Compare commits

..

1 Commits

Author SHA1 Message Date
Adam Hathcock
cbc58c4d8f First WinRT project 2013-05-04 16:58:50 +01:00
1185 changed files with 46525 additions and 140857 deletions

View File

@@ -1,13 +0,0 @@
{
"version": 1,
"isRoot": true,
"tools": {
"csharpier": {
"version": "1.1.2",
"commands": [
"csharpier"
],
"rollForward": false
}
}
}

View File

@@ -1,7 +0,0 @@
enabled: true
agent:
name: copilot-coding-agent
allow:
- paths: ["src/**/*", "tests/**/*", "README.md", "AGENTS.md"]
actions: ["create", "modify"]
require_review_before_merge: true

View File

@@ -1,568 +0,0 @@
# Version: 2.0.1 (Using https://semver.org/)
# Updated: 2020-12-11
# See https://github.com/RehanSaeed/EditorConfig/releases for release notes.
# See https://github.com/RehanSaeed/EditorConfig for updates to this file.
# See http://EditorConfig.org for more information about .editorconfig files.
##########################################
# Common Settings
##########################################
# This file is the top-most EditorConfig file
root = true
# All Files
[*]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
##########################################
# File Extension Settings
##########################################
# Visual Studio Solution Files
[*.sln]
indent_style = tab
# Visual Studio XML Project Files
[*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# XML Configuration Files
[*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}]
indent_size = 2
# JSON Files
[*.{json,json5,webmanifest}]
indent_size = 2
# YAML Files
[*.{yml,yaml}]
indent_size = 2
# Markdown Files
[*.md]
trim_trailing_whitespace = false
# Web Files
[*.{htm,html,js,jsm,ts,tsx,css,sass,scss,less,svg,vue}]
indent_size = 2
# Batch Files
[*.{cmd,bat}]
end_of_line = crlf
# Bash Files
[*.sh]
end_of_line = lf
# Makefiles
[Makefile]
indent_style = tab
##########################################
# Default .NET Code Style Severities
# https://docs.microsoft.com/dotnet/fundamentals/code-analysis/configuration-options#scope
##########################################
[*.{cs,csx,cake,vb,vbx}]
# Default Severity for all .NET Code Style rules below
dotnet_analyzer_diagnostic.severity = silent
##########################################
# File Header (Uncomment to support file headers)
# https://docs.microsoft.com/visualstudio/ide/reference/add-file-header
##########################################
# [*.{cs,csx,cake,vb,vbx}]
# file_header_template = <copyright file="{fileName}" company="PROJECT-AUTHOR">\n© PROJECT-AUTHOR\n</copyright>
# SA1636: File header copyright text should match
# Justification: .editorconfig supports file headers. If this is changed to a value other than "none", a stylecop.json file will need to added to the project.
# dotnet_diagnostic.SA1636.severity = none
##########################################
# .NET Language Conventions
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions
##########################################
# .NET Code Style Settings
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#net-code-style-settings
[*.{cs,csx,cake,vb,vbx}]
# "this." and "Me." qualifiers
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#this-and-me
#dotnet_style_qualification_for_field = true:warning
#dotnet_style_qualification_for_property = true:warning
#dotnet_style_qualification_for_method = true:warning
#dotnet_style_qualification_for_event = true:warning
# Language keywords instead of framework type names for type references
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#language-keywords
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
# Modifier preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#normalize-modifiers
dotnet_style_require_accessibility_modifiers = always:warning
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:warning
dotnet_style_readonly_field = true:warning
# Parentheses preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parentheses-preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_operators = always_for_clarity:suggestion
# Expression-level preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
dotnet_style_object_initializer = true:warning
dotnet_style_collection_initializer = true:warning
dotnet_style_explicit_tuple_names = true:warning
dotnet_style_prefer_inferred_tuple_names = true:warning
dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
dotnet_style_prefer_auto_properties = true:warning
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
dotnet_style_prefer_conditional_expression_over_assignment = false:suggestion
dotnet_diagnostic.IDE0045.severity = suggestion
dotnet_style_prefer_conditional_expression_over_return = false:suggestion
dotnet_diagnostic.IDE0046.severity = suggestion
dotnet_style_prefer_compound_assignment = true:warning
# Null-checking preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#null-checking-preferences
dotnet_style_coalesce_expression = true:warning
dotnet_style_null_propagation = true:warning
# Parameter preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parameter-preferences
dotnet_code_quality_unused_parameters = all:warning
# More style options (Undocumented)
# https://github.com/MicrosoftDocs/visualstudio-docs/issues/3641
dotnet_style_operator_placement_when_wrapping = end_of_line
# https://github.com/dotnet/roslyn/pull/40070
dotnet_style_prefer_simplified_interpolation = true:warning
# C# Code Style Settings
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-code-style-settings
[*.{cs,csx,cake}]
# Implicit and explicit types
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#implicit-and-explicit-types
csharp_style_var_for_built_in_types = true:warning
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_var_elsewhere = true:warning
# Expression-bodied members
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-bodied-members
csharp_style_expression_bodied_methods = true:warning
csharp_style_expression_bodied_constructors = true:warning
csharp_style_expression_bodied_operators = true:warning
csharp_style_expression_bodied_properties = true:warning
csharp_style_expression_bodied_indexers = true:warning
csharp_style_expression_bodied_accessors = true:warning
csharp_style_expression_bodied_lambdas = true:warning
csharp_style_expression_bodied_local_functions = true:warning
# Pattern matching
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#pattern-matching
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
csharp_style_pattern_matching_over_as_with_null_check = true:warning
# Inlined variable declarations
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#inlined-variable-declarations
csharp_style_inlined_variable_declaration = true:warning
# Expression-level preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
csharp_prefer_simple_default_expression = true:warning
# "Null" checking preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-null-checking-preferences
csharp_style_throw_expression = true:warning
csharp_style_conditional_delegate_call = true:warning
# Code block preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#code-block-preferences
csharp_prefer_braces = true:warning
# Unused value preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#unused-value-preferences
csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
dotnet_diagnostic.IDE0058.severity = suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
dotnet_diagnostic.IDE0059.severity = suggestion
# Index and range preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#index-and-range-preferences
csharp_style_prefer_index_operator = true:warning
csharp_style_prefer_range_operator = true:warning
# Miscellaneous preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#miscellaneous-preferences
csharp_style_deconstructed_variable_declaration = true:warning
csharp_style_pattern_local_over_anonymous_function = true:warning
csharp_using_directive_placement = outside_namespace:warning
csharp_prefer_static_local_function = true:warning
csharp_prefer_simple_using_statement = true:suggestion
dotnet_diagnostic.IDE0063.severity = suggestion
##########################################
# .NET Formatting Conventions
# https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference#formatting-conventions
##########################################
# Organize usings
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#organize-using-directives
dotnet_sort_system_directives_first = true
# Newline options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#new-line-options
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#indentation-options
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = no_change
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents_when_block = false
# Spacing options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#spacing-options
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_after_comma = true
csharp_space_before_comma = false
csharp_space_after_dot = false
csharp_space_before_dot = false
csharp_space_after_semicolon_in_for_statement = true
csharp_space_before_semicolon_in_for_statement = false
csharp_space_around_declaration_statements = false
csharp_space_before_open_square_brackets = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_square_brackets = false
# Wrapping options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#wrap-options
csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true
csharp_style_namespace_declarations = file_scoped
##########################################
# .NET Naming Conventions
# https://docs.microsoft.com/visualstudio/ide/editorconfig-naming-conventions
##########################################
[*.{cs,csx,cake,vb,vbx}]
dotnet_diagnostic.CA1000.severity = suggestion
dotnet_diagnostic.CA1001.severity = error
dotnet_diagnostic.CA1018.severity = error
dotnet_diagnostic.CA1036.severity = silent
dotnet_diagnostic.CA1051.severity = suggestion
dotnet_diagnostic.CA1068.severity = error
dotnet_diagnostic.CA1069.severity = error
dotnet_diagnostic.CA1304.severity = error
dotnet_diagnostic.CA1305.severity = suggestion
dotnet_diagnostic.CA1307.severity = suggestion
dotnet_diagnostic.CA1309.severity = suggestion
dotnet_diagnostic.CA1310.severity = error
dotnet_diagnostic.CA1507.severity = suggestion
dotnet_diagnostic.CA1513.severity = suggestion
dotnet_diagnostic.CA1707.severity = suggestion
dotnet_diagnostic.CA1708.severity = suggestion
dotnet_diagnostic.CA1711.severity = suggestion
dotnet_diagnostic.CA1716.severity = suggestion
dotnet_diagnostic.CA1720.severity = suggestion
dotnet_diagnostic.CA1725.severity = suggestion
dotnet_diagnostic.CA1805.severity = suggestion
dotnet_diagnostic.CA1816.severity = suggestion
dotnet_diagnostic.CA1822.severity = suggestion
dotnet_diagnostic.CA1825.severity = error
dotnet_diagnostic.CA1826.severity = silent
dotnet_diagnostic.CA1827.severity = error
dotnet_diagnostic.CA1829.severity = suggestion
dotnet_diagnostic.CA1834.severity = error
dotnet_diagnostic.CA1845.severity = suggestion
dotnet_diagnostic.CA1848.severity = suggestion
dotnet_diagnostic.CA1852.severity = suggestion
dotnet_diagnostic.CA1860.severity = silent
dotnet_diagnostic.CA2016.severity = suggestion
dotnet_diagnostic.CA2201.severity = error
dotnet_diagnostic.CA2206.severity = error
dotnet_diagnostic.CA2208.severity = error
dotnet_diagnostic.CA2211.severity = error
dotnet_diagnostic.CA2249.severity = error
dotnet_diagnostic.CA2251.severity = error
dotnet_diagnostic.CA2252.severity = none
dotnet_diagnostic.CA2254.severity = suggestion
dotnet_diagnostic.CS0169.severity = error
dotnet_diagnostic.CS0219.severity = error
dotnet_diagnostic.CS0649.severity = suggestion
dotnet_diagnostic.CS1998.severity = error
dotnet_diagnostic.CS8602.severity = error
dotnet_diagnostic.CS8604.severity = error
dotnet_diagnostic.CS8618.severity = error
dotnet_diagnostic.CS0618.severity = suggestion
dotnet_diagnostic.CS1998.severity = error
dotnet_diagnostic.CS4014.severity = error
dotnet_diagnostic.CS8600.severity = error
dotnet_diagnostic.CS8603.severity = error
dotnet_diagnostic.CS8625.severity = error
dotnet_diagnostic.BL0005.severity = suggestion
dotnet_diagnostic.MVC1000.severity = suggestion
dotnet_diagnostic.RZ10012.severity = error
dotnet_diagnostic.IDE0004.severity = error # redundant cast
dotnet_diagnostic.IDE0005.severity = suggestion
dotnet_diagnostic.IDE0007.severity = error # Use var
dotnet_diagnostic.IDE0011.severity = error # Use braces on if statements
dotnet_diagnostic.IDE0010.severity = silent # populate switch
dotnet_diagnostic.IDE0017.severity = suggestion # initialization can be simplified
dotnet_diagnostic.IDE0021.severity = silent # expression body for constructors
dotnet_diagnostic.IDE0022.severity = silent # expression body for methods
dotnet_diagnostic.IDE0023.severity = suggestion # use expression body for operators
dotnet_diagnostic.IDE0024.severity = silent # expression body for operators
dotnet_diagnostic.IDE0025.severity = suggestion # use expression body for properties
dotnet_diagnostic.IDE0027.severity = suggestion # Use expression body for accessors
dotnet_diagnostic.IDE0028.severity = silent # expression body for accessors
dotnet_diagnostic.IDE0032.severity = suggestion # Use auto property
dotnet_diagnostic.IDE0033.severity = error # prefer tuple name
dotnet_diagnostic.IDE0037.severity = suggestion # simplify anonymous type
dotnet_diagnostic.IDE0040.severity = error # modifiers required
dotnet_diagnostic.IDE0041.severity = error # simplify null
dotnet_diagnostic.IDE0042.severity = error # deconstruct variable
dotnet_diagnostic.IDE0044.severity = suggestion # make field only when possible
dotnet_diagnostic.IDE0047.severity = suggestion # parameter name
dotnet_diagnostic.IDE0051.severity = error # unused field
dotnet_diagnostic.IDE0052.severity = error # unused member
dotnet_diagnostic.IDE0053.severity = suggestion # lambda not needed
dotnet_diagnostic.IDE0055.severity = suggestion # Fix formatting
dotnet_diagnostic.IDE0057.severity = suggestion # substring can be simplified
dotnet_diagnostic.IDE0060.severity = suggestion # unused parameters
dotnet_diagnostic.IDE0061.severity = suggestion # local expression body
dotnet_diagnostic.IDE0062.severity = suggestion # local to static
dotnet_diagnostic.IDE0063.severity = error # simplify using
dotnet_diagnostic.IDE0066.severity = suggestion # switch expression
dotnet_diagnostic.IDE0072.severity = suggestion # Populate switch - forces population of all cases even when default specified
dotnet_diagnostic.IDE0078.severity = suggestion # use pattern matching
dotnet_diagnostic.IDE0090.severity = suggestion # new can be simplified
dotnet_diagnostic.IDE0130.severity = suggestion # namespace folder structure
dotnet_diagnostic.IDE0160.severity = silent # Use block namespaces ARE NOT required
dotnet_diagnostic.IDE0161.severity = error # Please use file namespaces
dotnet_diagnostic.IDE0200.severity = suggestion # lambda not needed
dotnet_diagnostic.IDE1006.severity = suggestion # Naming rule violation: These words cannot contain lower case characters
dotnet_diagnostic.IDE0260.severity = suggestion # Use pattern matching
dotnet_diagnostic.IDE0270.severity = suggestion # Null check simplifcation
dotnet_diagnostic.IDE0290.severity = error # Primary Constructor
dotnet_diagnostic.IDE0300.severity = suggestion # Collection
dotnet_diagnostic.IDE0305.severity = suggestion # Collection ToList
dotnet_diagnostic.NX0001.severity = error
dotnet_diagnostic.NX0002.severity = silent
dotnet_diagnostic.NX0003.severity = silent
##########################################
# Styles
##########################################
# camel_case_style - Define the camelCase style
dotnet_naming_style.camel_case_style.capitalization = camel_case
# pascal_case_style - Define the PascalCase style
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# constant_case - Define the CONSTANT_CASE style
dotnet_naming_style.constant_case.capitalization = all_upper
dotnet_naming_style.constant_case.word_separator = _
# first_upper_style - The first character must start with an upper-case character
dotnet_naming_style.first_upper_style.capitalization = first_word_upper
# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I'
dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case
dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I
# prefix_type_parameters_with_t_style - Generic Type Parameters must be PascalCase and the first character must be a 'T'
dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case
dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T
# disallowed_style - Anything that has this style applied is marked as disallowed
dotnet_naming_style.disallowed_style.capitalization = pascal_case
dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____
dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____
# internal_error_style - This style should never occur... if it does, it indicates a bug in file or in the parser using the file
dotnet_naming_style.internal_error_style.capitalization = pascal_case
dotnet_naming_style.internal_error_style.required_prefix = ____INTERNAL_ERROR____
dotnet_naming_style.internal_error_style.required_suffix = ____INTERNAL_ERROR____
# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I'
dotnet_naming_style.underscore_camel_case_style.capitalization = camel_case
dotnet_naming_style.underscore_camel_case_style.required_prefix = _
##########################################
# .NET Design Guideline Field Naming Rules
# Naming rules for fields follow the .NET Framework design guidelines
# https://docs.microsoft.com/dotnet/standard/design-guidelines/index
##########################################
# All public/protected/protected_internal constant fields must be constant_case
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal
dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const
dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = constant_case
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning
# All public/protected/protected_internal static readonly fields must be constant_case
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected, protected_internal
dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly
dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = constant_case
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning
# No other public/protected/protected_internal fields are allowed
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected, protected_internal
dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error
##########################################
# StyleCop Field Naming Rules
# Naming rules for fields follow the StyleCop analyzers
# This does not override any rules using disallowed_style above
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers
##########################################
# All constant fields must be constant_case
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1303.md
dotnet_naming_symbols.stylecop_constant_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private
dotnet_naming_symbols.stylecop_constant_fields_group.required_modifiers = const
dotnet_naming_symbols.stylecop_constant_fields_group.applicable_kinds = field
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.symbols = stylecop_constant_fields_group
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.style = constant_case
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.severity = warning
# All static readonly fields must be constant_case
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1311.md
dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private
dotnet_naming_symbols.stylecop_static_readonly_fields_group.required_modifiers = static, readonly
dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_kinds = field
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.symbols = stylecop_static_readonly_fields_group
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.style = constant_case
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.severity = warning
# No non-private instance fields are allowed
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md
dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected
dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.severity = error
# Private fields must be camelCase
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md
dotnet_naming_symbols.stylecop_private_fields_group.applicable_accessibilities = private
dotnet_naming_symbols.stylecop_private_fields_group.applicable_kinds = field
dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.symbols = stylecop_private_fields_group
dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.style = underscore_camel_case_style
dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.severity = warning
# Local variables must be camelCase
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md
dotnet_naming_symbols.stylecop_local_fields_group.applicable_accessibilities = local
dotnet_naming_symbols.stylecop_local_fields_group.applicable_kinds = local
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.symbols = stylecop_local_fields_group
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.style = camel_case_style
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.severity = warning
# This rule should never fire. However, it's included for at least two purposes:
# First, it helps to understand, reason about, and root-case certain types of issues, such as bugs in .editorconfig parsers.
# Second, it helps to raise immediate awareness if a new field type is added (as occurred recently in C#).
dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_accessibilities = *
dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_kinds = field
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_check_uncovered_field_case_group
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error
##########################################
# Other Naming Rules
##########################################
# All of the following must be PascalCase:
# - Namespaces
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-namespaces
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
# - Classes and Enumerations
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
# - Delegates
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces#names-of-common-types
# - Constructors, Properties, Events, Methods
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-type-members
dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property
dotnet_naming_rule.element_rule.symbols = element_group
dotnet_naming_rule.element_rule.style = pascal_case_style
dotnet_naming_rule.element_rule.severity = warning
# Interfaces use PascalCase and are prefixed with uppercase 'I'
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
dotnet_naming_symbols.interface_group.applicable_kinds = interface
dotnet_naming_rule.interface_rule.symbols = interface_group
dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style
dotnet_naming_rule.interface_rule.severity = warning
# Generics Type Parameters use PascalCase and are prefixed with uppercase 'T'
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter
dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group
dotnet_naming_rule.type_parameter_rule.style = prefix_type_parameters_with_t_style
dotnet_naming_rule.type_parameter_rule.severity = warning
# Function parameters use camelCase
# https://docs.microsoft.com/dotnet/standard/design-guidelines/naming-parameters
dotnet_naming_symbols.parameters_group.applicable_kinds = parameter
dotnet_naming_rule.parameters_rule.symbols = parameters_group
dotnet_naming_rule.parameters_rule.style = camel_case_style
dotnet_naming_rule.parameters_rule.severity = warning
##########################################
# License
##########################################
# The following applies as to the .editorconfig file ONLY, and is
# included below for reference, per the requirements of the license
# corresponding to this .editorconfig file.
# See: https://github.com/RehanSaeed/EditorConfig
#
# MIT License
#
# Copyright (c) 2017-2019 Muhammad Rehan Saeed
# Copyright (c) 2019 Henry Gabryjelski
#
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject
# to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
##########################################

5
.gitattributes vendored
View File

@@ -1,5 +0,0 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# need original files to be windows
*.txt text eol=crlf

View File

@@ -1,15 +0,0 @@
# Copilot Coding Agent Configuration
This repository includes a minimal opt-in configuration and CI workflow to allow the GitHub Copilot coding agent to open and validate PRs.
- .copilot-agent.yml: opt-in config for automated agents
- .github/agents/copilot-agent.yml: detailed agent policy configuration
- .github/workflows/dotnetcore.yml: CI runs on PRs touching the solution, source, or tests to validate changes
- AGENTS.md: general instructions for Copilot coding agent with project-specific guidelines
Maintainers can adjust the allowed paths or disable the agent by editing or removing .copilot-agent.yml.
Notes:
- The agent can create, modify, and delete files within the allowed paths (src, tests, README.md, AGENTS.md)
- All changes require review before merge
- If build/test paths are different, update the workflow accordingly; this workflow targets SharpCompress.sln and the SharpCompress.Test test project.

View File

@@ -1,192 +0,0 @@
---
name: C# Expert
description: An agent designed to assist with software development tasks for .NET projects.
# version: 2025-10-27a
---
You are an expert C#/.NET developer. You help with .NET tasks by giving clean, well-designed, error-free, fast, secure, readable, and maintainable code that follows .NET conventions. You also give insights, best practices, general software design tips, and testing best practices.
When invoked:
- Understand the user's .NET task and context
- Propose clean, organized solutions that follow .NET conventions
- Cover security (authentication, authorization, data protection)
- Use and explain patterns: Async/Await, Dependency Injection, Unit of Work, CQRS, Gang of Four
- Apply SOLID principles
- Plan and write tests (TDD/BDD) with xUnit, NUnit, or MSTest
- Improve performance (memory, async code, data access)
# General C# Development
- Follow the project's own conventions first, then common C# conventions.
- Keep naming, formatting, and project structure consistent.
## Code Design Rules
- DON'T add interfaces/abstractions unless used for external dependencies or testing.
- Don't wrap existing abstractions.
- Don't default to `public`. Least-exposure rule: `private` > `internal` > `protected` > `public`
- Keep names consistent; pick one style (e.g., `WithHostPort` or `WithBrowserPort`) and stick to it.
- Don't edit auto-generated code (`/api/*.cs`, `*.g.cs`, `// <auto-generated>`).
- Comments explain **why**, not what.
- Don't add unused methods/params.
- When fixing one method, check siblings for the same issue.
- Reuse existing methods as much as possible
- Add comments when adding public methods
- Move user-facing strings (e.g., AnalyzeAndConfirmNuGetConfigChanges) into resource files. Keep error/help text localizable.
## Error Handling & Edge Cases
- **Null checks**: use `ArgumentNullException.ThrowIfNull(x)`; for strings use `string.IsNullOrWhiteSpace(x)`; guard early. Avoid blanket `!`.
- **Exceptions**: choose precise types (e.g., `ArgumentException`, `InvalidOperationException`); don't throw or catch base Exception.
- **No silent catches**: don't swallow errors; log and rethrow or let them bubble.
## Goals for .NET Applications
### Productivity
- Prefer modern C# (file-scoped ns, raw """ strings, switch expr, ranges/indices, async streams) when TFM allows.
- Keep diffs small; reuse code; avoid new layers unless needed.
- Be IDE-friendly (go-to-def, rename, quick fixes work).
### Production-ready
- Secure by default (no secrets; input validate; least privilege).
- Resilient I/O (timeouts; retry with backoff when it fits).
- Structured logging with scopes; useful context; no log spam.
- Use precise exceptions; dont swallow; keep cause/context.
### Performance
- Simple first; optimize hot paths when measured.
- Stream large payloads; avoid extra allocs.
- Use Span/Memory/pooling when it matters.
- Async end-to-end; no sync-over-async.
### Cloud-native / cloud-ready
- Cross-platform; guard OS-specific APIs.
- Diagnostics: health/ready when it fits; metrics + traces.
- Observability: ILogger + OpenTelemetry hooks.
- 12-factor: config from env; avoid stateful singletons.
# .NET quick checklist
## Do first
* Read TFM + C# version.
* Check `global.json` SDK.
## Initial check
* App type: web / desktop / console / lib.
* Packages (and multi-targeting).
* Nullable on? (`<Nullable>enable</Nullable>` / `#nullable enable`)
* Repo config: `Directory.Build.*`, `Directory.Packages.props`.
## C# version
* **Don't** set C# newer than TFM default.
* C# 14 (NET 10+): extension members; `field` accessor; implicit `Span<T>` conv; `?.=`; `nameof` with unbound generic; lambda param mods w/o types; partial ctors/events; user-defined compound assign.
## Build
* .NET 5+: `dotnet build`, `dotnet publish`.
* .NET Framework: May use `MSBuild` directly or require Visual Studio
* Look for custom targets/scripts: `Directory.Build.targets`, `build.cmd/.sh`, `Build.ps1`.
## Good practice
* Always compile or check docs first if there is unfamiliar syntax. Don't try to correct the syntax if code can compile.
* Don't change TFM, SDK, or `<LangVersion>` unless asked.
# Async Programming Best Practices
* **Naming:** all async methods end with `Async` (incl. CLI handlers).
* **Always await:** no fire-and-forget; if timing out, **cancel the work**.
* **Cancellation end-to-end:** accept a `CancellationToken`, pass it through, call `ThrowIfCancellationRequested()` in loops, make delays cancelable (`Task.Delay(ms, ct)`).
* **Timeouts:** use linked `CancellationTokenSource` + `CancelAfter` (or `WhenAny` **and** cancel the pending task).
* **Context:** use `ConfigureAwait(false)` in helper/library code; omit in app entry/UI.
* **Stream JSON:** `GetAsync(..., ResponseHeadersRead)``ReadAsStreamAsync``JsonDocument.ParseAsync`; avoid `ReadAsStringAsync` when large.
* **Exit code on cancel:** return non-zero (e.g., `130`).
* **`ValueTask`:** use only when measured to help; default to `Task`.
* **Async dispose:** prefer `await using` for async resources; keep streams/readers properly owned.
* **No pointless wrappers:** dont add `async/await` if you just return the task.
## Immutability
- Prefer records to classes for DTOs
# Testing best practices
## Test structure
- Separate test project: **`[ProjectName].Tests`**.
- Mirror classes: `CatDoor` -> `CatDoorTests`.
- Name tests by behavior: `WhenCatMeowsThenCatDoorOpens`.
- Follow existing naming conventions.
- Use **public instance** classes; avoid **static** fields.
- No branching/conditionals inside tests.
## Unit Tests
- One behavior per test;
- Avoid Unicode symbols.
- Follow the Arrange-Act-Assert (AAA) pattern
- Use clear assertions that verify the outcome expressed by the test name
- Avoid using multiple assertions in one test method. In this case, prefer multiple tests.
- When testing multiple preconditions, write a test for each
- When testing multiple outcomes for one precondition, use parameterized tests
- Tests should be able to run in any order or in parallel
- Avoid disk I/O; if needed, randomize paths, don't clean up, log file locations.
- Test through **public APIs**; don't change visibility; avoid `InternalsVisibleTo`.
- Require tests for new/changed **public APIs**.
- Assert specific values and edge cases, not vague outcomes.
## Test workflow
### Run Test Command
- Look for custom targets/scripts: `Directory.Build.targets`, `test.ps1/.cmd/.sh`
- .NET Framework: May use `vstest.console.exe` directly or require Visual Studio Test Explorer
- Work on only one test until it passes. Then run other tests to ensure nothing has been broken.
### Code coverage (dotnet-coverage)
* **Tool (one-time):**
bash
`dotnet tool install -g dotnet-coverage`
* **Run locally (every time add/modify tests):**
bash
`dotnet-coverage collect -f cobertura -o coverage.cobertura.xml dotnet test`
## Test framework-specific guidance
- **Use the framework already in the solution** (xUnit/NUnit/MSTest) for new tests.
### xUnit
* Packages: `Microsoft.NET.Test.Sdk`, `xunit`, `xunit.runner.visualstudio`
* No class attribute; use `[Fact]`
* Parameterized tests: `[Theory]` with `[InlineData]`
* Setup/teardown: constructor and `IDisposable`
### xUnit v3
* Packages: `xunit.v3`, `xunit.runner.visualstudio` 3.x, `Microsoft.NET.Test.Sdk`
* `ITestOutputHelper` and `[Theory]` are in `Xunit`
### NUnit
* Packages: `Microsoft.NET.Test.Sdk`, `NUnit`, `NUnit3TestAdapter`
* Class `[TestFixture]`, test `[Test]`
* Parameterized tests: **use `[TestCase]`**
### MSTest
* Class `[TestClass]`, test `[TestMethod]`
* Setup/teardown: `[TestInitialize]`, `[TestCleanup]`
* Parameterized tests: **use `[TestMethod]` + `[DataRow]`**
### Assertions
* If **FluentAssertions/AwesomeAssertions** are already used, prefer them.
* Otherwise, use the frameworks asserts.
* Use `Throws/ThrowsAsync` (or MSTest `Assert.ThrowsException`) for exceptions.
## Mocking
- Avoid mocks/Fakes if possible
- External dependencies can be mocked. Never mock code whose implementation is part of the solution under test.
- Try to verify that the outputs (e.g. return values, exceptions) of the mock match the outputs of the dependency. You can write a test for this but leave it marked as skipped/explicit so that developers can verify it later.

View File

@@ -1,13 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "nuget"
directory: "/" # change to "/src/YourProject" if .csproj files are in subfolders
schedule:
interval: "weekly"
open-pull-requests-limit: 5
# optional: target-branch: "master"

View File

@@ -1,114 +0,0 @@
---
description: 'Guidelines for building C# applications'
applyTo: '**/*.cs'
---
# C# Development
## C# Instructions
- Always use the latest version C#, currently C# 14 features.
- Write clear and concise comments for each function.
## General Instructions
- Make only high confidence suggestions when reviewing code changes.
- Write code with good maintainability practices, including comments on why certain design decisions were made.
- Handle edge cases and write clear exception handling.
- For libraries or external dependencies, mention their usage and purpose in comments.
## Naming Conventions
- Follow PascalCase for component names, method names, and public members.
- Use camelCase for private fields and local variables.
- Prefix interface names with "I" (e.g., IUserService).
## Formatting
- Apply code-formatting style defined in `.editorconfig`.
- Prefer file-scoped namespace declarations and single-line using directives.
- Insert a newline before the opening curly brace of any code block (e.g., after `if`, `for`, `while`, `foreach`, `using`, `try`, etc.).
- Ensure that the final return statement of a method is on its own line.
- Use pattern matching and switch expressions wherever possible.
- Use `nameof` instead of string literals when referring to member names.
- Ensure that XML doc comments are created for any public APIs. When applicable, include `<example>` and `<code>` documentation in the comments.
## Project Setup and Structure
- Guide users through creating a new .NET project with the appropriate templates.
- Explain the purpose of each generated file and folder to build understanding of the project structure.
- Demonstrate how to organize code using feature folders or domain-driven design principles.
- Show proper separation of concerns with models, services, and data access layers.
- Explain the Program.cs and configuration system in ASP.NET Core 10 including environment-specific settings.
## Nullable Reference Types
- Declare variables non-nullable, and check for `null` at entry points.
- Always use `is null` or `is not null` instead of `== null` or `!= null`.
- Trust the C# null annotations and don't add null checks when the type system says a value cannot be null.
## Data Access Patterns
- Guide the implementation of a data access layer using Entity Framework Core.
- Explain different options (SQL Server, SQLite, In-Memory) for development and production.
- Demonstrate repository pattern implementation and when it's beneficial.
- Show how to implement database migrations and data seeding.
- Explain efficient query patterns to avoid common performance issues.
## Authentication and Authorization
- Guide users through implementing authentication using JWT Bearer tokens.
- Explain OAuth 2.0 and OpenID Connect concepts as they relate to ASP.NET Core.
- Show how to implement role-based and policy-based authorization.
- Demonstrate integration with Microsoft Entra ID (formerly Azure AD).
- Explain how to secure both controller-based and Minimal APIs consistently.
## Validation and Error Handling
- Guide the implementation of model validation using data annotations and FluentValidation.
- Explain the validation pipeline and how to customize validation responses.
- Demonstrate a global exception handling strategy using middleware.
- Show how to create consistent error responses across the API.
- Explain problem details (RFC 7807) implementation for standardized error responses.
## API Versioning and Documentation
- Guide users through implementing and explaining API versioning strategies.
- Demonstrate Swagger/OpenAPI implementation with proper documentation.
- Show how to document endpoints, parameters, responses, and authentication.
- Explain versioning in both controller-based and Minimal APIs.
- Guide users on creating meaningful API documentation that helps consumers.
## Logging and Monitoring
- Guide the implementation of structured logging using Serilog or other providers.
- Explain the logging levels and when to use each.
- Demonstrate integration with Application Insights for telemetry collection.
- Show how to implement custom telemetry and correlation IDs for request tracking.
- Explain how to monitor API performance, errors, and usage patterns.
## Testing
- Always include test cases for critical paths of the application.
- Guide users through creating unit tests.
- Do not emit "Act", "Arrange" or "Assert" comments.
- Copy existing style in nearby files for test method names and capitalization.
- Explain integration testing approaches for API endpoints.
- Demonstrate how to mock dependencies for effective testing.
- Show how to test authentication and authorization logic.
- Explain test-driven development principles as applied to API development.
## Performance Optimization
- Guide users on implementing caching strategies (in-memory, distributed, response caching).
- Explain asynchronous programming patterns and why they matter for API performance.
- Demonstrate pagination, filtering, and sorting for large data sets.
- Show how to implement compression and other performance optimizations.
- Explain how to measure and benchmark API performance.
## Deployment and DevOps
- Guide users through containerizing their API using .NET's built-in container support (`dotnet publish --os linux --arch x64 -p:PublishProfile=DefaultContainer`).
- Explain the differences between manual Dockerfile creation and .NET's container publishing features.
- Explain CI/CD pipelines for NET applications.
- Demonstrate deployment to Azure App Service, Azure Container Apps, or other hosting options.
- Show how to implement health checks and readiness probes.
- Explain environment-specific configurations for different deployment stages.

View File

@@ -1,21 +0,0 @@
---
mode: 'agent'
description: 'Create a README.md file for the project'
---
## Role
You're a senior expert software engineer with extensive experience in open source projects. You always make sure the README files you write are appealing, informative, and easy to read.
## Task
1. Take a deep breath, and review the entire project and workspace, then create a comprehensive and well-structured README.md file for the project.
2. Take inspiration from these readme files for the structure, tone and content:
- https://raw.githubusercontent.com/Azure-Samples/serverless-chat-langchainjs/refs/heads/main/README.md
- https://raw.githubusercontent.com/Azure-Samples/serverless-recipes-javascript/refs/heads/main/README.md
- https://raw.githubusercontent.com/sinedied/run-on-output/refs/heads/main/README.md
- https://raw.githubusercontent.com/sinedied/smoke/refs/heads/main/README.md
3. Do not overuse emojis, and keep the readme concise and to the point.
4. Do not include sections like "LICENSE", "CONTRIBUTING", "CHANGELOG", etc. There are dedicated files for those sections.
5. Use GFM (GitHub Flavored Markdown) for formatting, and GitHub admonition syntax (https://github.com/orgs/community/discussions/16925) where appropriate.
6. If you find a logo or icon for the project, use it in the readme's header.

View File

@@ -1,127 +0,0 @@
---
mode: 'agent'
description: 'Create a new specification file for the solution, optimized for Generative AI consumption.'
tools: ['changes', 'search/codebase', 'edit/editFiles', 'extensions', 'fetch', 'githubRepo', 'openSimpleBrowser', 'problems', 'runTasks', 'search', 'search/searchResults', 'runCommands/terminalLastCommand', 'runCommands/terminalSelection', 'testFailure', 'usages', 'vscodeAPI']
---
# Create Specification
Your goal is to create a new specification file for `${input:SpecPurpose}`.
The specification file must define the requirements, constraints, and interfaces for the solution components in a manner that is clear, unambiguous, and structured for effective use by Generative AIs. Follow established documentation standards and ensure the content is machine-readable and self-contained.
## Best Practices for AI-Ready Specifications
- Use precise, explicit, and unambiguous language.
- Clearly distinguish between requirements, constraints, and recommendations.
- Use structured formatting (headings, lists, tables) for easy parsing.
- Avoid idioms, metaphors, or context-dependent references.
- Define all acronyms and domain-specific terms.
- Include examples and edge cases where applicable.
- Ensure the document is self-contained and does not rely on external context.
The specification should be saved in the [/spec/](/spec/) directory and named according to the following convention: `spec-[a-z0-9-]+.md`, where the name should be descriptive of the specification's content and starting with the highlevel purpose, which is one of [schema, tool, data, infrastructure, process, architecture, or design].
The specification file must be formatted in well formed Markdown.
Specification files must follow the template below, ensuring that all sections are filled out appropriately. The front matter for the markdown should be structured correctly as per the example following:
```md
---
title: [Concise Title Describing the Specification's Focus]
version: [Optional: e.g., 1.0, Date]
date_created: [YYYY-MM-DD]
last_updated: [Optional: YYYY-MM-DD]
owner: [Optional: Team/Individual responsible for this spec]
tags: [Optional: List of relevant tags or categories, e.g., `infrastructure`, `process`, `design`, `app` etc]
---
# Introduction
[A short concise introduction to the specification and the goal it is intended to achieve.]
## 1. Purpose & Scope
[Provide a clear, concise description of the specification's purpose and the scope of its application. State the intended audience and any assumptions.]
## 2. Definitions
[List and define all acronyms, abbreviations, and domain-specific terms used in this specification.]
## 3. Requirements, Constraints & Guidelines
[Explicitly list all requirements, constraints, rules, and guidelines. Use bullet points or tables for clarity.]
- **REQ-001**: Requirement 1
- **SEC-001**: Security Requirement 1
- **[3 LETTERS]-001**: Other Requirement 1
- **CON-001**: Constraint 1
- **GUD-001**: Guideline 1
- **PAT-001**: Pattern to follow 1
## 4. Interfaces & Data Contracts
[Describe the interfaces, APIs, data contracts, or integration points. Use tables or code blocks for schemas and examples.]
## 5. Acceptance Criteria
[Define clear, testable acceptance criteria for each requirement using Given-When-Then format where appropriate.]
- **AC-001**: Given [context], When [action], Then [expected outcome]
- **AC-002**: The system shall [specific behavior] when [condition]
- **AC-003**: [Additional acceptance criteria as needed]
## 6. Test Automation Strategy
[Define the testing approach, frameworks, and automation requirements.]
- **Test Levels**: Unit, Integration, End-to-End
- **Frameworks**: MSTest, FluentAssertions, Moq (for .NET applications)
- **Test Data Management**: [approach for test data creation and cleanup]
- **CI/CD Integration**: [automated testing in GitHub Actions pipelines]
- **Coverage Requirements**: [minimum code coverage thresholds]
- **Performance Testing**: [approach for load and performance testing]
## 7. Rationale & Context
[Explain the reasoning behind the requirements, constraints, and guidelines. Provide context for design decisions.]
## 8. Dependencies & External Integrations
[Define the external systems, services, and architectural dependencies required for this specification. Focus on **what** is needed rather than **how** it's implemented. Avoid specific package or library versions unless they represent architectural constraints.]
### External Systems
- **EXT-001**: [External system name] - [Purpose and integration type]
### Third-Party Services
- **SVC-001**: [Service name] - [Required capabilities and SLA requirements]
### Infrastructure Dependencies
- **INF-001**: [Infrastructure component] - [Requirements and constraints]
### Data Dependencies
- **DAT-001**: [External data source] - [Format, frequency, and access requirements]
### Technology Platform Dependencies
- **PLT-001**: [Platform/runtime requirement] - [Version constraints and rationale]
### Compliance Dependencies
- **COM-001**: [Regulatory or compliance requirement] - [Impact on implementation]
**Note**: This section should focus on architectural and business dependencies, not specific package implementations. For example, specify "OAuth 2.0 authentication library" rather than "Microsoft.AspNetCore.Authentication.JwtBearer v6.0.1".
## 9. Examples & Edge Cases
```code
// Code snippet or data example demonstrating the correct application of the guidelines, including edge cases
```
## 10. Validation Criteria
[List the criteria or tests that must be satisfied for compliance with this specification.]
## 11. Related Specifications / Further Reading
[Link to related spec 1]
[Link to relevant external documentation]
```

View File

@@ -1,50 +0,0 @@
---
mode: 'agent'
tools: ['changes', 'search/codebase', 'edit/editFiles', 'problems']
description: 'Get best practices for C# async programming'
---
# C# Async Programming Best Practices
Your goal is to help me follow best practices for asynchronous programming in C#.
## Naming Conventions
- Use the 'Async' suffix for all async methods
- Match method names with their synchronous counterparts when applicable (e.g., `GetDataAsync()` for `GetData()`)
## Return Types
- Return `Task<T>` when the method returns a value
- Return `Task` when the method doesn't return a value
- Consider `ValueTask<T>` for high-performance scenarios to reduce allocations
- Avoid returning `void` for async methods except for event handlers
## Exception Handling
- Use try/catch blocks around await expressions
- Avoid swallowing exceptions in async methods
- Use `ConfigureAwait(false)` when appropriate to prevent deadlocks in library code
- Propagate exceptions with `Task.FromException()` instead of throwing in async Task returning methods
## Performance
- Use `Task.WhenAll()` for parallel execution of multiple tasks
- Use `Task.WhenAny()` for implementing timeouts or taking the first completed task
- Avoid unnecessary async/await when simply passing through task results
- Consider cancellation tokens for long-running operations
## Common Pitfalls
- Never use `.Wait()`, `.Result`, or `.GetAwaiter().GetResult()` in async code
- Avoid mixing blocking and async code
- Don't create async void methods (except for event handlers)
- Always await Task-returning methods
## Implementation Patterns
- Implement the async command pattern for long-running operations
- Use async streams (IAsyncEnumerable<T>) for processing sequences asynchronously
- Consider the task-based asynchronous pattern (TAP) for public APIs
When reviewing my C# code, identify these issues and suggest improvements that follow these best practices.

View File

@@ -1,69 +0,0 @@
---
mode: 'agent'
tools: ['changes', 'search/codebase', 'edit/editFiles', 'problems', 'search']
description: 'Get best practices for XUnit unit testing, including data-driven tests'
---
# XUnit Best Practices
Your goal is to help me write effective unit tests with XUnit, covering both standard and data-driven testing approaches.
## Project Setup
- Use a separate test project with naming convention `[ProjectName].Tests`
- Reference Microsoft.NET.Test.Sdk, xunit, and xunit.runner.visualstudio packages
- Create test classes that match the classes being tested (e.g., `CalculatorTests` for `Calculator`)
- Use .NET SDK test commands: `dotnet test` for running tests
## Test Structure
- No test class attributes required (unlike MSTest/NUnit)
- Use fact-based tests with `[Fact]` attribute for simple tests
- Follow the Arrange-Act-Assert (AAA) pattern
- Name tests using the pattern `MethodName_Scenario_ExpectedBehavior`
- Use constructor for setup and `IDisposable.Dispose()` for teardown
- Use `IClassFixture<T>` for shared context between tests in a class
- Use `ICollectionFixture<T>` for shared context between multiple test classes
## Standard Tests
- Keep tests focused on a single behavior
- Avoid testing multiple behaviors in one test method
- Use clear assertions that express intent
- Include only the assertions needed to verify the test case
- Make tests independent and idempotent (can run in any order)
- Avoid test interdependencies
## Data-Driven Tests
- Use `[Theory]` combined with data source attributes
- Use `[InlineData]` for inline test data
- Use `[MemberData]` for method-based test data
- Use `[ClassData]` for class-based test data
- Create custom data attributes by implementing `DataAttribute`
- Use meaningful parameter names in data-driven tests
## Assertions
- Use `Assert.Equal` for value equality
- Use `Assert.Same` for reference equality
- Use `Assert.True`/`Assert.False` for boolean conditions
- Use `Assert.Contains`/`Assert.DoesNotContain` for collections
- Use `Assert.Matches`/`Assert.DoesNotMatch` for regex pattern matching
- Use `Assert.Throws<T>` or `await Assert.ThrowsAsync<T>` to test exceptions
- Use fluent assertions library for more readable assertions
## Mocking and Isolation
- Consider using Moq or NSubstitute alongside XUnit
- Mock dependencies to isolate units under test
- Use interfaces to facilitate mocking
- Consider using a DI container for complex test setups
## Test Organization
- Group tests by feature or component
- Use `[Trait("Category", "CategoryName")]` for categorization
- Use collection fixtures to group tests with shared dependencies
- Consider output helpers (`ITestOutputHelper`) for test diagnostics
- Skip tests conditionally with `Skip = "reason"` in fact/theory attributes

View File

@@ -1,84 +0,0 @@
---
mode: 'agent'
description: 'Ensure .NET/C# code meets best practices for the solution/project.'
---
# .NET/C# Best Practices
Your task is to ensure .NET/C# code in ${selection} meets the best practices specific to this solution/project. This includes:
## Documentation & Structure
- Create comprehensive XML documentation comments for all public classes, interfaces, methods, and properties
- Include parameter descriptions and return value descriptions in XML comments
- Follow the established namespace structure: {Core|Console|App|Service}.{Feature}
## Design Patterns & Architecture
- Use primary constructor syntax for dependency injection (e.g., `public class MyClass(IDependency dependency)`)
- Implement the Command Handler pattern with generic base classes (e.g., `CommandHandler<TOptions>`)
- Use interface segregation with clear naming conventions (prefix interfaces with 'I')
- Follow the Factory pattern for complex object creation.
## Dependency Injection & Services
- Use constructor dependency injection with null checks via ArgumentNullException
- Register services with appropriate lifetimes (Singleton, Scoped, Transient)
- Use Microsoft.Extensions.DependencyInjection patterns
- Implement service interfaces for testability
## Resource Management & Localization
- Use ResourceManager for localized messages and error strings
- Separate LogMessages and ErrorMessages resource files
- Access resources via `_resourceManager.GetString("MessageKey")`
## Async/Await Patterns
- Use async/await for all I/O operations and long-running tasks
- Return Task or Task<T> from async methods
- Use ConfigureAwait(false) where appropriate
- Handle async exceptions properly
## Testing Standards
- Use MSTest framework with FluentAssertions for assertions
- Follow AAA pattern (Arrange, Act, Assert)
- Use Moq for mocking dependencies
- Test both success and failure scenarios
- Include null parameter validation tests
## Configuration & Settings
- Use strongly-typed configuration classes with data annotations
- Implement validation attributes (Required, NotEmptyOrWhitespace)
- Use IConfiguration binding for settings
- Support appsettings.json configuration files
## Semantic Kernel & AI Integration
- Use Microsoft.SemanticKernel for AI operations
- Implement proper kernel configuration and service registration
- Handle AI model settings (ChatCompletion, Embedding, etc.)
- Use structured output patterns for reliable AI responses
## Error Handling & Logging
- Use structured logging with Microsoft.Extensions.Logging
- Include scoped logging with meaningful context
- Throw specific exceptions with descriptive messages
- Use try-catch blocks for expected failure scenarios
## Performance & Security
- Use C# 12+ features and .NET 8 optimizations where applicable
- Implement proper input validation and sanitization
- Use parameterized queries for database operations
- Follow secure coding practices for AI/ML operations
## Code Quality
- Ensure SOLID principles compliance
- Avoid code duplication through base classes and utilities
- Use meaningful names that reflect domain concepts
- Keep methods focused and cohesive
- Implement proper disposal patterns for resources

View File

@@ -1,41 +0,0 @@
---
mode: 'agent'
description: 'Review the C#/.NET code for design pattern implementation and suggest improvements.'
---
# .NET/C# Design Pattern Review
Review the C#/.NET code in ${selection} for design pattern implementation and suggest improvements for the solution/project. Do not make any changes to the code, just provide a review.
## Required Design Patterns
- **Command Pattern**: Generic base classes (`CommandHandler<TOptions>`), `ICommandHandler<TOptions>` interface, `CommandHandlerOptions` inheritance, static `SetupCommand(IHost host)` methods
- **Factory Pattern**: Complex object creation service provider integration
- **Dependency Injection**: Primary constructor syntax, `ArgumentNullException` null checks, interface abstractions, proper service lifetimes
- **Repository Pattern**: Async data access interfaces provider abstractions for connections
- **Provider Pattern**: External service abstractions (database, AI), clear contracts, configuration handling
- **Resource Pattern**: ResourceManager for localized messages, separate .resx files (LogMessages, ErrorMessages)
## Review Checklist
- **Design Patterns**: Identify patterns used. Are Command Handler, Factory, Provider, and Repository patterns correctly implemented? Missing beneficial patterns?
- **Architecture**: Follow namespace conventions (`{Core|Console|App|Service}.{Feature}`)? Proper separation between Core/Console projects? Modular and readable?
- **.NET Best Practices**: Primary constructors, async/await with Task returns, ResourceManager usage, structured logging, strongly-typed configuration?
- **GoF Patterns**: Command, Factory, Template Method, Strategy patterns correctly implemented?
- **SOLID Principles**: Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion violations?
- **Performance**: Proper async/await, resource disposal, ConfigureAwait(false), parallel processing opportunities?
- **Maintainability**: Clear separation of concerns, consistent error handling, proper configuration usage?
- **Testability**: Dependencies abstracted via interfaces, mockable components, async testability, AAA pattern compatibility?
- **Security**: Input validation, secure credential handling, parameterized queries, safe exception handling?
- **Documentation**: XML docs for public APIs, parameter/return descriptions, resource file organization?
- **Code Clarity**: Meaningful names reflecting domain concepts, clear intent through patterns, self-explanatory structure?
- **Clean Code**: Consistent style, appropriate method/class size, minimal complexity, eliminated duplication?
## Improvement Focus Areas
- **Command Handlers**: Validation in base class, consistent error handling, proper resource management
- **Factories**: Dependency configuration, service provider integration, disposal patterns
- **Providers**: Connection management, async patterns, exception handling and logging
- **Configuration**: Data annotations, validation attributes, secure sensitive value handling
- **AI/ML Integration**: Semantic Kernel patterns, structured output handling, model configuration
Provide specific, actionable recommendations for improvements aligned with the project's architecture and .NET best practices.

View File

@@ -1,25 +0,0 @@
name: SharpCompress
on:
push:
branches:
- 'master'
pull_request:
types: [ opened, synchronize, reopened, ready_for_review ]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, ubuntu-latest]
steps:
- uses: actions/checkout@v5
- uses: actions/setup-dotnet@v5
with:
dotnet-version: 8.0.x
- run: dotnet run --project build/build.csproj
- uses: actions/upload-artifact@v5
with:
name: ${{ matrix.os }}-sharpcompress.nupkg
path: artifacts/*

30
.gitignore vendored
View File

@@ -1,22 +1,8 @@
**/bin/*
**/obj/*
_ReSharper.SharpCompress/
bin/
*.suo
*.user
TestArchives/Scratch/
TestArchives/Scratch2/
TestResults/
*.nupkg
packages/*/
project.lock.json
tests/TestArchives/Scratch
tests/TestArchives/*/Scratch
tests/TestArchives/*/Scratch2
.vs
tools
.vscode
.idea/
.DS_Store
*.snupkg
**/bin/*
**/obj/*
_ReSharper.SharpCompress/
bin/
*.suo
*.user
TestArchives/Scratch/
TestArchives/Scratch2/

118
AGENTS.md
View File

@@ -1,118 +0,0 @@
---
description: 'Guidelines for building SharpCompress - A C# compression library'
applyTo: '**/*.cs'
---
# SharpCompress Development
## About SharpCompress
SharpCompress is a pure C# compression library supporting multiple archive formats (Zip, Tar, GZip, BZip2, 7Zip, Rar, LZip, XZ, ZStandard) for .NET Framework 4.62, .NET Standard 2.1, .NET 6.0, and .NET 8.0. The library provides both seekable Archive APIs and forward-only Reader/Writer APIs for streaming scenarios.
## C# Instructions
- Always use the latest version C#, currently C# 13 features.
- Write clear and concise comments for each function.
- Follow the existing code style and patterns in the codebase.
## General Instructions
- Make only high confidence suggestions when reviewing code changes.
- Write code with good maintainability practices, including comments on why certain design decisions were made.
- Handle edge cases and write clear exception handling.
- For libraries or external dependencies, mention their usage and purpose in comments.
- Preserve backward compatibility when making changes to public APIs.
## Naming Conventions
- Follow PascalCase for component names, method names, and public members.
- Use camelCase for private fields and local variables.
- Prefix interface names with "I" (e.g., IUserService).
## Code Formatting
- Use CSharpier for code formatting to ensure consistent style across the project
- CSharpier is configured as a local tool in `.config/dotnet-tools.json`
- Restore tools with: `dotnet tool restore`
- Format files from the project root with: `dotnet csharpier .`
- **Run `dotnet csharpier .` from the project root after making code changes before committing**
- Configure your IDE to format on save using CSharpier for the best experience
- The project also uses `.editorconfig` for editor settings (indentation, encoding, etc.)
- Let CSharpier handle code style while `.editorconfig` handles editor behavior
## Project Setup and Structure
- The project targets multiple frameworks: .NET Framework 4.62, .NET Standard 2.1, .NET 6.0, and .NET 8.0
- Main library is in `src/SharpCompress/`
- Tests are in `tests/SharpCompress.Test/`
- Performance tests are in `tests/SharpCompress.Performance/`
- Test archives are in `tests/TestArchives/`
- Build project is in `build/`
- Use `dotnet build` to build the solution
- Use `dotnet test` to run tests
- Solution file: `SharpCompress.sln`
## Nullable Reference Types
- Declare variables non-nullable, and check for `null` at entry points.
- Always use `is null` or `is not null` instead of `== null` or `!= null`.
- Trust the C# null annotations and don't add null checks when the type system says a value cannot be null.
## SharpCompress-Specific Guidelines
### Supported Formats
SharpCompress supports multiple archive and compression formats:
- **Archive Formats**: Zip, Tar, 7Zip, Rar (read-only)
- **Compression**: DEFLATE, BZip2, LZMA/LZMA2, PPMd, ZStandard (decompress only), Deflate64 (decompress only)
- **Combined Formats**: Tar.GZip, Tar.BZip2, Tar.LZip, Tar.XZ, Tar.ZStandard
- See FORMATS.md for complete format support matrix
### Stream Handling Rules
- **Disposal**: As of version 0.21, SharpCompress closes wrapped streams by default
- Use `ReaderOptions` or `WriterOptions` with `LeaveStreamOpen = true` to control stream disposal
- Use `NonDisposingStream` wrapper when working with compression streams directly to prevent disposal
- Always dispose of readers, writers, and archives in `using` blocks
- For forward-only operations, use Reader/Writer APIs; for random access, use Archive APIs
### Async/Await Patterns
- All I/O operations support async/await with `CancellationToken`
- Async methods follow the naming convention: `MethodNameAsync`
- Key async methods:
- `WriteEntryToAsync` - Extract entry asynchronously
- `WriteAllToDirectoryAsync` - Extract all entries asynchronously
- `WriteAsync` - Write entry asynchronously
- `WriteAllAsync` - Write directory asynchronously
- `OpenEntryStreamAsync` - Open entry stream asynchronously
- Always provide `CancellationToken` parameter in async methods
### Archive APIs vs Reader/Writer APIs
- **Archive API**: Use for random access with seekable streams (e.g., `ZipArchive`, `TarArchive`)
- **Reader API**: Use for forward-only reading on non-seekable streams (e.g., `ZipReader`, `TarReader`)
- **Writer API**: Use for forward-only writing on streams (e.g., `ZipWriter`, `TarWriter`)
- 7Zip only supports Archive API due to format limitations
### Tar-Specific Considerations
- Tar format requires file size in the header
- If no size is specified to TarWriter and the stream is not seekable, an exception will be thrown
- Tar combined with compression (GZip, BZip2, LZip, XZ) is supported
### Zip-Specific Considerations
- Supports Zip64 for large files (seekable streams only)
- Supports PKWare and WinZip AES encryption
- Multiple compression methods: None, Shrink, Reduce, Implode, DEFLATE, Deflate64, BZip2, LZMA, PPMd
- Encrypted LZMA is not supported
### Performance Considerations
- For large files, use Reader/Writer APIs with non-seekable streams to avoid loading entire file in memory
- Leverage async I/O for better scalability
- Consider compression level trade-offs (speed vs. size)
- Use appropriate buffer sizes for stream operations
## Testing
- Always include test cases for critical paths of the application.
- Test with multiple archive formats when making changes to core functionality.
- Include tests for both Archive and Reader/Writer APIs when applicable.
- Test async operations with cancellation tokens.
- Do not emit "Act", "Arrange" or "Assert" comments.
- Copy existing style in nearby files for test method names and capitalization.
- Use test archives from `tests/TestArchives` directory for consistency.
- Test stream disposal and `LeaveStreamOpen` behavior.
- Test edge cases: empty archives, large files, corrupted archives, encrypted archives.

View File

@@ -1,16 +0,0 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<AnalysisMode>Recommended</AnalysisMode>
<WarningsAsErrors>true</WarningsAsErrors>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RunAnalyzersDuringLiveAnalysis>False</RunAnalyzersDuringLiveAnalysis>
<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
</Project>

View File

@@ -1,21 +0,0 @@
<Project>
<ItemGroup>
<PackageVersion Include="Bullseye" Version="6.0.0" />
<PackageVersion Include="AwesomeAssertions" Version="9.2.1" />
<PackageVersion Include="Glob" Version="1.1.9" />
<PackageVersion Include="JetBrains.Profiler.SelfApi" Version="2.5.14" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
<PackageVersion Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageVersion Include="SimpleExec" Version="12.0.0" />
<PackageVersion Include="System.Buffers" Version="4.6.1" />
<PackageVersion Include="System.Memory" Version="4.6.3" />
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="ZstdSharp.Port" Version="0.8.6" />
<PackageVersion Include="Microsoft.NET.ILLink.Tasks" Version="8.0.21" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" />
</ItemGroup>
</Project>

View File

@@ -1,61 +0,0 @@
# Formats
## Accessing Archives
* Archive classes allow random access to a seekable stream.
* Reader classes allow forward-only reading on a stream.
* Writer classes allow forward-only Writing on a stream.
## Supported Format Table
| Archive Format | Compression Format(s) | Compress/Decompress | Archive API | Reader API | Writer API |
| ---------------------- | ------------------------------------------------- | ------------------- | --------------- | ---------- | ------------- |
| Rar | Rar | Decompress (1) | RarArchive | RarReader | N/A |
| Zip (2) | None, Shrink, Reduce, Implode, DEFLATE, Deflate64, BZip2, LZMA/LZMA2, PPMd | Both | ZipArchive | ZipReader | ZipWriter |
| Tar | None | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.GZip | DEFLATE | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.BZip2 | BZip2 | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.Zstandard | ZStandard | Decompress | TarArchive | TarReader | N/A |
| Tar.LZip | LZMA | Both | TarArchive | TarReader | TarWriter (3) |
| Tar.XZ | LZMA2 | Decompress | TarArchive | TarReader | TarWriter (3) |
| GZip (single file) | DEFLATE | Both | GZipArchive | GZipReader | GZipWriter |
| 7Zip (4) | LZMA, LZMA2, BZip2, PPMd, BCJ, BCJ2, Deflate | Decompress | SevenZipArchive | N/A | N/A |
1. SOLID Rars are only supported in the RarReader API.
2. Zip format supports pkware and WinzipAES encryption. However, encrypted LZMA is not supported. Zip64 reading/writing is supported but only with seekable streams as the Zip spec doesn't support Zip64 data in post data descriptors. Deflate64 is only supported for reading.
3. The Tar format requires a file size in the header. If no size is specified to the TarWriter and the stream is not seekable, then an exception will be thrown.
4. The 7Zip format doesn't allow for reading as a forward-only stream so 7Zip is only supported through the Archive API
5. LZip has no support for extra data like the file name or timestamp. There is a default filename used when looking at the entry Key on the archive.
## Compression Streams
For those who want to directly compress/decompress bits. The single file formats are represented here as well. However, BZip2, LZip and XZ have no metadata (GZip has a little) so using them without something like a Tar file makes little sense.
| Compressor | Compress/Decompress |
| --------------- | ------------------- |
| BZip2Stream | Both |
| GZipStream | Both |
| DeflateStream | Both |
| Deflate64Stream | Decompress |
| LZMAStream | Both |
| PPMdStream | Both |
| ADCStream | Decompress |
| LZipStream | Both |
| XZStream | Decompress |
| ZStandardStream | Decompress |
## Archive Formats vs Compression
Sometimes the terminology gets mixed.
### Compression
DEFLATE, LZMA are pure compression algorithms
### Formats
Formats like Zip, 7Zip, Rar are archive formats only. They use other compression methods (e.g. DEFLATE, LZMA, etc.) or propriatory (e.g RAR)
### Overlap
GZip, BZip2 and LZip are single file archival formats. The overlap in the API happens because Tar uses the single file formats as "compression" methods and the API tries to hide this a bit.

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014 Adam Hathcock
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSourceMapping>
<!-- key value for <packageSource> should match key values from <packageSources> element -->
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
</packageSourceMapping>
</configuration>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<version>0.8.2</version>
<authors>Adam Hathcock</authors>
<owners>Adam Hathcock</owners>
<licenseUrl>http://sharpcompress.codeplex.com/license</licenseUrl>
<projectUrl>http://sharpcompress.codeplex.com/</projectUrl>
<id>sharpcompress</id>
<title>SharpCompress - Pure C# Decompression/Compression</title>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>SharpCompress is a compression library for .NET/Mono/Silverlight/WP7 that can unrar, decompress 7zip, zip/unzip, tar/untar bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.</description>
<releaseNotes />
<language>en-US</language>
<tags>rar unrar zip unzip bzip2 gzip tar 7zip .net40 .net35 sl4</tags>
</metadata>
<files>
<file src="..\bin\SharpCompress.3.5.dll" target="lib\net35\SharpCompress.3.5.dll" />
<file src="..\bin\SharpCompress.dll" target="lib\net40\SharpCompress.dll" />
<file src="..\bin\SharpCompress.WP7.dll" target="lib\sl3-wp\SharpCompress.WP7.dll" />
<file src="..\bin\SharpCompress.Silverlight.dll" target="lib\sl50\SharpCompress.Silverlight.dll" />
</files>
</package>

278
README.md
View File

@@ -1,280 +1,24 @@
# SharpCompress
SharpCompress
=============
SharpCompress is a compression library in pure C# for .NET Framework 4.62, .NET Standard 2.1, .NET 6.0 and NET 8.0 that can unrar, un7zip, unzip, untar unbzip2, ungzip, unlzip, unzstd, unarc and unarj with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip/lzip are implemented.
Github mirror of http://sharpcompress.codeplex.com
The major feature is support for non-seekable streams so large files can be processed on the fly (i.e. download stream).
SharpCompress is a compression library for .NET/Mono/Silverlight/WP7 that can unrar, un7zip, unzip, untar unbzip2 and ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.
**NEW:** All I/O operations now support async/await for improved performance and scalability. See the [Async Usage](#async-usage) section below.
The major feature is support for non-seekable streams so large files can be processed on the fly (i.e. download stream).
GitHub Actions Build -
[![SharpCompress](https://github.com/adamhathcock/sharpcompress/actions/workflows/dotnetcore.yml/badge.svg)](https://github.com/adamhathcock/sharpcompress/actions/workflows/dotnetcore.yml)
[![Static Badge](https://img.shields.io/badge/API%20Docs-DNDocs-190088?logo=readme&logoColor=white)](https://dndocs.com/d/sharpcompress/api/index.html)
## Need Help?
Post Issues on Github!
Check the [Supported Formats](FORMATS.md) and [Basic Usage.](USAGE.md)
## Recommended Formats
In general, I recommend GZip (Deflate)/BZip2 (BZip)/LZip (LZMA) as the simplicity of the formats lend to better long term archival as well as the streamability. Tar is often used in conjunction for multiple files in a single archive (e.g. `.tar.gz`)
Zip is okay, but it's a very hap-hazard format and the variation in headers and implementations makes it hard to get correct. Uses Deflate by default but supports a lot of compression methods.
RAR is not recommended as it's a proprietary format and the compression is closed source. Use Tar/LZip for LZMA
7Zip and XZ both are overly complicated. 7Zip does not support streamable formats. XZ has known holes explained here: (http://www.nongnu.org/lzip/xz_inadequate.html) Use Tar/LZip for LZMA compression instead.
ZStandard is an efficient format that works well for streaming with a flexible compression level to tweak the speed/performance trade off you are looking for. We currently only implement decompression for ZStandard but as we leverage the [ZstdSharp](https://github.com/oleg-st/ZstdSharp) library one could likely add compression support without much trouble (PRs are welcome!).
## A Simple Request
A Simple Request
Hi everyone. I hope you're using SharpCompress and finding it useful. Please give me feedback on what you'd like to see changed especially as far as usability goes. New feature suggestions are always welcome as well. I would also like to know what projects SharpCompress is being used in. I like seeing how it is used to give me ideas for future versions. Thanks!
Please do not email me directly to ask for help. If you think there is a real issue, please report it here.
## Async Usage
SharpCompress now provides full async/await support for all I/O operations, allowing for better performance and scalability in modern applications.
### Async Reading Examples
Extract entries asynchronously:
```csharp
using (Stream stream = File.OpenRead("archive.zip"))
using (var reader = ReaderFactory.Open(stream))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
// Async extraction
await reader.WriteEntryToDirectoryAsync(
@"C:\temp",
new ExtractionOptions() { ExtractFullPath = true, Overwrite = true },
cancellationToken
);
}
}
}
```
Extract all entries to directory asynchronously:
```csharp
using (Stream stream = File.OpenRead("archive.tar.gz"))
using (var reader = ReaderFactory.Open(stream))
{
await reader.WriteAllToDirectoryAsync(
@"C:\temp",
new ExtractionOptions() { ExtractFullPath = true, Overwrite = true },
cancellationToken
);
}
```
Open entry stream asynchronously:
```csharp
using (var archive = ZipArchive.Open("archive.zip"))
{
foreach (var entry in archive.Entries.Where(e => !e.IsDirectory))
{
using (var entryStream = await entry.OpenEntryStreamAsync(cancellationToken))
{
// Process stream asynchronously
await entryStream.CopyToAsync(outputStream, cancellationToken);
}
}
}
```
### Async Writing Examples
Write files asynchronously:
```csharp
using (Stream stream = File.OpenWrite("output.zip"))
using (var writer = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate))
{
await writer.WriteAsync("file1.txt", fileStream, DateTime.Now, cancellationToken);
}
```
Write all files from directory asynchronously:
```csharp
using (Stream stream = File.OpenWrite("output.tar.gz"))
using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, new WriterOptions(CompressionType.GZip)))
{
await writer.WriteAllAsync(@"D:\files", "*", SearchOption.AllDirectories, cancellationToken);
}
```
All async methods support `CancellationToken` for graceful cancellation of long-running operations.
## Want to contribute?
Want to contribute?
I'm always looking for help or ideas. Please submit code or email with ideas. Unfortunately, just letting me know you'd like to help is not enough because I really have no overall plan of what needs to be done. I'll definitely accept code submissions and add you as a member of the project!
## TODOs (always lots)
* RAR 5 decryption crc check support
TODOs (always lots):
* 7Zip writing
* Zip64 (Need writing and extend Reading)
* RAR Decryption
* Zip64
* Multi-volume Zip support.
* ZStandard writing
## Version Log
* [Releases](https://github.com/adamhathcock/sharpcompress/releases)
### Version 0.18
* [Now on Github releases](https://github.com/adamhathcock/sharpcompress/releases/tag/0.18)
### Version 0.17.1
* Fix - [Bug Fix for .NET Core on Windows](https://github.com/adamhathcock/sharpcompress/pull/257)
### Version 0.17.0
* New - Full LZip support! Can read and write LZip files and Tars inside LZip files. [Make LZip a first class citizen. #241](https://github.com/adamhathcock/sharpcompress/issues/241)
* New - XZ read support! Can read XZ files and Tars inside XZ files. [XZ in SharpCompress #91](https://github.com/adamhathcock/sharpcompress/issues/94)
* Fix - [Regression - zip file writing on seekable streams always assumed stream start was 0. Introduced with Zip64 writing.](https://github.com/adamhathcock/sharpcompress/issues/244)
* Fix - [Zip files with post-data descriptors can be properly skipped via decompression](https://github.com/adamhathcock/sharpcompress/issues/162)
### Version 0.16.2
* Fix [.NET 3.5 should support files and cryptography (was a regression from 0.16.0)](https://github.com/adamhathcock/sharpcompress/pull/251)
* Fix [Zip per entry compression customization wrote the wrong method into the zip archive](https://github.com/adamhathcock/sharpcompress/pull/249)
### Version 0.16.1
* Fix [Preserve compression method when getting a compressed stream](https://github.com/adamhathcock/sharpcompress/pull/235)
* Fix [RAR entry key normalization fix](https://github.com/adamhathcock/sharpcompress/issues/201)
### Version 0.16.0
* Breaking - [Progress Event Tracking rethink](https://github.com/adamhathcock/sharpcompress/pull/226)
* Update to VS2017 - [VS2017](https://github.com/adamhathcock/sharpcompress/pull/231) - Framework targets have been changed.
* New - [Add Zip64 writing](https://github.com/adamhathcock/sharpcompress/pull/211)
* [Fix invalid/mismatching Zip version flags.](https://github.com/adamhathcock/sharpcompress/issues/164) - This allows nuget/System.IO.Packaging to read zip files generated by SharpCompress
* [Fix 7Zip directory hiding](https://github.com/adamhathcock/sharpcompress/pull/215/files)
* [Verify RAR CRC headers](https://github.com/adamhathcock/sharpcompress/pull/220)
### Version 0.15.2
* [Fix invalid headers](https://github.com/adamhathcock/sharpcompress/pull/210) - fixes an issue creating large-ish zip archives that was introduced with zip64 reading.
### Version 0.15.1
* [Zip64 extending information and ZipReader](https://github.com/adamhathcock/sharpcompress/pull/206)
### Version 0.15.0
* [Add zip64 support for ZipArchive extraction](https://github.com/adamhathcock/sharpcompress/pull/205)
### Version 0.14.1
* [.NET Assemblies aren't strong named](https://github.com/adamhathcock/sharpcompress/issues/158)
* [Pkware encryption for Zip files didn't allow for multiple reads of an entry](https://github.com/adamhathcock/sharpcompress/issues/197)
* [GZip Entry couldn't be read multiple times](https://github.com/adamhathcock/sharpcompress/issues/198)
### Version 0.14.0
* [Support for LZip reading in for Tars](https://github.com/adamhathcock/sharpcompress/pull/191)
### Version 0.13.1
* [Fix null password on ReaderFactory. Fix null options on SevenZipArchive](https://github.com/adamhathcock/sharpcompress/pull/188)
* [Make PpmdProperties lazy to avoid unnecessary allocations.](https://github.com/adamhathcock/sharpcompress/pull/185)
### Version 0.13.0
* Breaking change: Big refactor of Options on API.
* 7Zip supports Deflate
### Version 0.12.4
* Forward only zip issue fix https://github.com/adamhathcock/sharpcompress/issues/160
* Try to fix frameworks again by copying targets from JSON.NET
### Version 0.12.3
* 7Zip fixes https://github.com/adamhathcock/sharpcompress/issues/73
* Maybe all profiles will work with project.json now
### Version 0.12.2
* Support Profile 259 again
### Version 0.12.1
* Support Silverlight 5
### Version 0.12.0
* .NET Core RTM!
* Bug fix for Tar long paths
### Version 0.11.6
* Bug fix for global header in Tar
* Writers now have a leaveOpen `bool` overload. They won't close streams if not-requested to.
### Version 0.11.5
* Bug fix in Skip method
### Version 0.11.4
* SharpCompress is now endian neutral (matters for Mono platforms)
* Fix for Inflate (need to change implementation)
* Fixes for RAR detection
### Version 0.11.1
* Added Cancel on IReader
* Removed .NET 2.0 support and LinqBridge dependency
### Version 0.11
* Been over a year, contains mainly fixes from contributors!
* Possible breaking change: ArchiveEncoding is UTF8 by default now.
* TAR supports writing long names using longlink
* RAR Protect Header added
### Version 0.10.3
* Finally fixed Disposal issue when creating a new archive with the Archive API
### Version 0.10.2
* Fixed Rar Header reading for invalid extended time headers.
* Windows Store assembly is now strong named
* Known issues with Long Tar names being worked on
* Updated to VS2013
* Portable targets SL5 and Windows Phone 8 (up from SL4 and WP7)
### Version 0.10.1
* Fixed 7Zip extraction performance problem
### Version 0.10:
* Added support for RAR Decryption (thanks to https://github.com/hrasyid)
* Embedded some BouncyCastle crypto classes to allow RAR Decryption and Winzip AES Decryption in Portable and Windows Store DLLs
* Built in Release (I think)
XZ implementation based on: https://github.com/sambott/XZ.NET by @sambott
XZ BCJ filters support contributed by Louis-Michel Bergeron, on behalf of aDolus Technology Inc. - 2022
7Zip implementation based on: https://code.google.com/p/managed-lzma/
LICENSE
Copyright (c) 2000 - 2011 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7Zip implementation based on: https://code.google.com/p/managed-lzma/

View File

@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Archive;
using SharpCompress.Common;
namespace SharpCompress.Test
{
public class ArchiveTests : TestBase
{
protected void ArchiveStreamReadExtractAll(string testArchive, CompressionType compression)
{
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
ArchiveStreamReadExtractAll(testArchive.AsEnumerable(), compression);
}
protected void ArchiveStreamReadExtractAll(IEnumerable<string> testArchives, CompressionType compression)
{
foreach (var path in testArchives)
{
ResetScratch();
using (Stream stream = File.OpenRead(path))
using (var archive = ArchiveFactory.Open(stream))
{
Assert.IsTrue(archive.IsSolid);
using (var reader = archive.ExtractAllEntries())
{
ReaderTests.UseReader(this, reader, compression);
}
VerifyFiles();
if (archive.Entries.First().CompressionType == CompressionType.Rar)
{
return;
}
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH,
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
}
protected void ArchiveStreamRead(string testArchive)
{
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
ArchiveStreamRead(testArchive.AsEnumerable());
}
protected void ArchiveStreamRead(params string[] testArchives)
{
ArchiveStreamRead(testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)));
}
protected void ArchiveStreamRead(IEnumerable<string> testArchives)
{
foreach (var path in testArchives)
{
ResetScratch();
using (Stream stream = File.OpenRead(path))
using (var archive = ArchiveFactory.Open(stream))
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
}
protected void ArchiveFileRead(string testArchive)
{
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
ArchiveFileRead(testArchive.AsEnumerable());
}
protected void ArchiveFileRead(IEnumerable<string> testArchives)
{
foreach (var path in testArchives)
{
ResetScratch();
using (var archive = ArchiveFactory.Open(path))
{
archive.EntryExtractionBegin += archive_EntryExtractionBegin;
archive.FilePartExtractionBegin += archive_FilePartExtractionBegin;
archive.CompressedBytesRead += archive_CompressedBytesRead;
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH,
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
}
void archive_CompressedBytesRead(object sender, CompressedBytesReadEventArgs e)
{
Console.WriteLine("Read Compressed File Part Bytes: {0} Percentage: {1}%",
e.CurrentFilePartCompressedBytesRead, CreatePercentage(e.CurrentFilePartCompressedBytesRead, partTotal));
string percentage = entryTotal.HasValue ? CreatePercentage(e.CompressedBytesRead,
entryTotal.Value).ToString() : "Unknown";
Console.WriteLine("Read Compressed File Entry Bytes: {0} Percentage: {1}%",
e.CompressedBytesRead, percentage);
}
void archive_FilePartExtractionBegin(object sender, FilePartExtractionBeginEventArgs e)
{
this.partTotal = e.Size;
Console.WriteLine("Initializing File Part Extraction: " + e.Name);
}
void archive_EntryExtractionBegin(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
{
this.entryTotal = e.Item.Size;
Console.WriteLine("Initializing File Entry Extraction: " + e.Item.FilePath);
}
private long? entryTotal;
private long partTotal;
private int CreatePercentage(long n, long d)
{
return (int)(((double)n / (double)d) * 100);
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Archive;
using SharpCompress.Archive.GZip;
namespace SharpCompress.Test
{
[TestClass]
public class GZipArchiveTests : ArchiveTests
{
public GZipArchiveTests()
{
UseExtensionInsteadOfNameToVerify = true;
}
[TestMethod]
public void GZip_Archive_Generic()
{
ResetScratch();
using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
using (var archive = ArchiveFactory.Open(stream))
{
var entry = archive.Entries.First();
entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.FilePath));
}
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"),
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
}
[TestMethod]
public void GZip_Archive()
{
ResetScratch();
using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
using (var archive = GZipArchive.Open(stream))
{
var entry = archive.Entries.First();
entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.FilePath));
}
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"),
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void GZip_Archive_NoAdd()
{
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg");
ResetScratch();
using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
using (var archive = GZipArchive.Open(stream))
{
archive.AddEntry("jpg\\test.jpg", jpg);
archive.SaveTo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"));
}
}
}
}

View File

@@ -0,0 +1,58 @@
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
using SharpCompress.Writer;
using SharpCompress.Writer.GZip;
namespace SharpCompress.Test
{
[TestClass]
public class GZipWriterTests : WriterTests
{
public GZipWriterTests()
: base(ArchiveType.GZip)
{
UseExtensionInsteadOfNameToVerify = true;
}
[TestMethod]
public void GZip_Writer_Generic()
{
ResetScratch();
using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write))
using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.GZip))
{
writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
}
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"),
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
}
[TestMethod]
public void GZip_Writer()
{
ResetScratch();
using (Stream stream = File.Open(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"), FileMode.OpenOrCreate, FileAccess.Write))
using (var writer = new GZipWriter(stream))
{
writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
}
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"),
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
}
[TestMethod]
[ExpectedException(typeof(InvalidFormatException))]
public void GZip_Writer_Generic_Bad_Compression()
{
ResetScratch();
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")))
using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2))
{
writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
}
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"),
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SharpCompress.Test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("SharpCompress.Test")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f01fddfb-445f-4548-9f69-88b69a8b71b0")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.269
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace SharpCompress.Test.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SharpCompress.Test.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.269
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace SharpCompress.Test.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,170 @@
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Archive;
using SharpCompress.Archive.Rar;
using SharpCompress.Common;
namespace SharpCompress.Test
{
[TestClass]
public class RarArchiveTests : ArchiveTests
{
[TestMethod]
public void Rar_None_ArchiveStreamRead()
{
ArchiveStreamRead("Rar.none.rar");
}
[TestMethod]
public void Rar_ArchiveStreamRead()
{
ArchiveStreamRead("Rar.rar");
}
[TestMethod]
public void Rar_Jpg_ArchiveStreamRead()
{
ResetScratch();
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "RarJpeg.jpg")))
{
using (var archive = RarArchive.Open(stream, Options.LookForHeader))
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH,
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
}
[TestMethod]
public void Rar_IsSolidArchiveCheck()
{
ResetScratch();
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar")))
{
using (var archive = RarArchive.Open(stream))
{
Assert.IsFalse(archive.IsSolidArchive());
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH,
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
}
VerifyFiles();
}
[TestMethod]
[ExpectedException(typeof(InvalidFormatException))]
public void Rar_Solid_ArchiveStreamRead()
{
ArchiveStreamRead("Rar.solid.rar");
}
[TestMethod]
public void Rar_Solid_StreamRead_Extract_All()
{
ArchiveStreamReadExtractAll("Rar.solid.rar", CompressionType.Rar);
}
[TestMethod]
public void Rar_Multi_ArchiveStreamRead()
{
var testArchives = new string[] { "Rar.multi.part01.rar",
"Rar.multi.part02.rar",
"Rar.multi.part03.rar",
"Rar.multi.part04.rar",
"Rar.multi.part05.rar",
"Rar.multi.part06.rar"};
ResetScratch();
using (var archive = RarArchive.Open(testArchives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s))
.Select(p => File.OpenRead(p))))
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
[TestMethod]
public void RarNoneArchiveFileRead()
{
ArchiveFileRead("Rar.none.rar");
}
[TestMethod]
public void Rar_ArchiveFileRead()
{
ArchiveFileRead("Rar.rar");
}
[TestMethod]
public void Rar_ArchiveFileRead_HasDirectories()
{
ResetScratch();
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar")))
{
using (var archive = RarArchive.Open(stream))
{
Assert.IsFalse(archive.IsSolidArchive());
Assert.IsTrue(archive.Entries.Any(entry => entry.IsDirectory));
}
}
}
[TestMethod]
public void Rar_Jpg_ArchiveFileRead()
{
ResetScratch();
using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "RarJpeg.jpg"), Options.LookForHeader))
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
[TestMethod]
[ExpectedException(typeof(InvalidFormatException))]
public void Rar_Solid_ArchiveFileRead()
{
ArchiveFileRead("Rar.solid.rar");
}
[TestMethod]
public void Rar_Multi_ArchiveFileRead()
{
ArchiveFileRead("Rar.multi.part01.rar");
}
[TestMethod]
public void Rar_IsFirstVolume_True()
{
using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Rar.multi.part01.rar")))
{
Assert.IsTrue(archive.IsMultipartVolume());
Assert.IsTrue(archive.IsFirstVolume());
}
}
[TestMethod]
public void Rar_IsFirstVolume_False()
{
using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Rar.multi.part03.rar")))
{
Assert.IsTrue(archive.IsMultipartVolume());
Assert.IsFalse(archive.IsFirstVolume());
}
}
}
}

View File

@@ -0,0 +1,191 @@
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
using SharpCompress.Reader;
using SharpCompress.Reader.Rar;
namespace SharpCompress.Test
{
[TestClass]
public class RarReaderTests : ReaderTests
{
[TestMethod]
public void Rar_Multi_Reader()
{
var testArchives = new string[] { "Rar.multi.part01.rar",
"Rar.multi.part02.rar",
"Rar.multi.part03.rar",
"Rar.multi.part04.rar",
"Rar.multi.part05.rar",
"Rar.multi.part06.rar"};
ResetScratch();
using (var reader = RarReader.Open(testArchives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s))
.Select(p => File.OpenRead(p))))
{
while (reader.MoveToNextEntry())
{
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
[TestMethod]
public void Rar_Multi_Reader_Delete_Files()
{
var testArchives = new string[] { "Rar.multi.part01.rar",
"Rar.multi.part02.rar",
"Rar.multi.part03.rar",
"Rar.multi.part04.rar",
"Rar.multi.part05.rar",
"Rar.multi.part06.rar"};
ResetScratch();
foreach (var file in testArchives)
{
File.Copy(Path.Combine(TEST_ARCHIVES_PATH, file), Path.Combine(SCRATCH2_FILES_PATH, file));
}
using (var reader = RarReader.Open(testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s))
.Select(p => File.OpenRead(p)), Options.None))
{
while (reader.MoveToNextEntry())
{
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
foreach (var file in testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)))
{
File.Delete(file);
}
}
[TestMethod]
public void Rar_None_Reader()
{
Read("Rar.none.rar", CompressionType.Rar);
}
[TestMethod]
public void Rar_Reader()
{
Read("Rar.rar", CompressionType.Rar);
}
[TestMethod]
public void Rar_Entry_Stream()
{
ResetScratch();
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar")))
using (var reader = RarReader.Open(stream))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
using (var entryStream = reader.OpenEntryStream())
{
string file = Path.GetFileName(reader.Entry.FilePath);
string folder = Path.GetDirectoryName(reader.Entry.FilePath);
string destdir = Path.Combine(SCRATCH_FILES_PATH, folder);
if (!Directory.Exists(destdir))
{
Directory.CreateDirectory(destdir);
}
string destinationFileName = Path.Combine(destdir, file);
using (FileStream fs = File.OpenWrite(destinationFileName))
{
entryStream.TransferTo(fs);
}
}
}
}
}
VerifyFiles();
}
[TestMethod]
public void Rar_Reader_Audio_program()
{
ResetScratch();
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Audio_program.rar")))
using (var reader = RarReader.Open(stream, Options.LookForHeader))
{
while (reader.MoveToNextEntry())
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
CompareFilesByPath(Path.Combine(SCRATCH_FILES_PATH, "test.dat"),
Path.Combine(MISC_TEST_FILES_PATH, "test.dat"));
}
[TestMethod]
public void Rar_Jpg_Reader()
{
ResetScratch();
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "RarJpeg.jpg")))
using (var reader = RarReader.Open(stream, Options.LookForHeader))
{
while (reader.MoveToNextEntry())
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
[TestMethod]
public void Rar_Solid_Reader()
{
Read("Rar.solid.rar", CompressionType.Rar);
}
[TestMethod]
public void Rar_Solid_Skip_Reader()
{
ResetScratch();
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.solid.rar")))
using (var reader = RarReader.Open(stream, Options.LookForHeader))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.FilePath.Contains("jpg"))
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
}
}
[TestMethod]
public void Rar_Reader_Skip()
{
ResetScratch();
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar")))
using (var reader = RarReader.Open(stream, Options.LookForHeader))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.FilePath.Contains("jpg"))
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
}
}
}
}

View File

@@ -0,0 +1,43 @@
using System.Collections.Generic;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
using SharpCompress.Reader;
namespace SharpCompress.Test
{
public class ReaderTests : TestBase
{
protected void Read(string testArchive, CompressionType expectedCompression)
{
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
Read(testArchive.AsEnumerable(), expectedCompression);
}
protected void Read(IEnumerable<string> testArchives, CompressionType expectedCompression)
{
foreach (var path in testArchives)
{
using (Stream stream = File.OpenRead(path))
using (IReader reader = ReaderFactory.Open(stream))
{
UseReader(this, reader, expectedCompression);
}
}
}
public static void UseReader(TestBase test, IReader reader, CompressionType expectedCompression)
{
test.ResetScratch();
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
Assert.AreEqual(reader.Entry.CompressionType, expectedCompression);
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
test.VerifyFiles();
}
}
}

View File

@@ -0,0 +1,84 @@
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.IO;
namespace SharpCompress.Test
{
[TestClass]
public class RewindableStreamTest
{
[TestMethod]
public void TestRewind()
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
bw.Write(1);
bw.Write(2);
bw.Write(3);
bw.Write(4);
bw.Write(5);
bw.Write(6);
bw.Write(7);
bw.Flush();
ms.Position = 0;
RewindableStream stream = new RewindableStream(ms);
stream.StartRecording();
BinaryReader br = new BinaryReader(stream);
Assert.AreEqual(br.ReadInt32(), 1);
Assert.AreEqual(br.ReadInt32(), 2);
Assert.AreEqual(br.ReadInt32(), 3);
Assert.AreEqual(br.ReadInt32(), 4);
stream.Rewind(true);
stream.StartRecording();
Assert.AreEqual(br.ReadInt32(), 1);
Assert.AreEqual(br.ReadInt32(), 2);
Assert.AreEqual(br.ReadInt32(), 3);
Assert.AreEqual(br.ReadInt32(), 4);
Assert.AreEqual(br.ReadInt32(), 5);
Assert.AreEqual(br.ReadInt32(), 6);
Assert.AreEqual(br.ReadInt32(), 7);
stream.Rewind(true);
stream.StartRecording();
Assert.AreEqual(br.ReadInt32(), 1);
Assert.AreEqual(br.ReadInt32(), 2);
Assert.AreEqual(br.ReadInt32(), 3);
Assert.AreEqual(br.ReadInt32(), 4);
}
[TestMethod]
public void TestIncompleteRewind()
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
bw.Write(1);
bw.Write(2);
bw.Write(3);
bw.Write(4);
bw.Write(5);
bw.Write(6);
bw.Write(7);
bw.Flush();
ms.Position = 0;
RewindableStream stream = new RewindableStream(ms);
stream.StartRecording();
BinaryReader br = new BinaryReader(stream);
Assert.AreEqual(br.ReadInt32(), 1);
Assert.AreEqual(br.ReadInt32(), 2);
Assert.AreEqual(br.ReadInt32(), 3);
Assert.AreEqual(br.ReadInt32(), 4);
stream.Rewind(true);
Assert.AreEqual(br.ReadInt32(), 1);
Assert.AreEqual(br.ReadInt32(), 2);
stream.StartRecording();
Assert.AreEqual(br.ReadInt32(), 3);
Assert.AreEqual(br.ReadInt32(), 4);
Assert.AreEqual(br.ReadInt32(), 5);
stream.Rewind(true);
Assert.AreEqual(br.ReadInt32(), 3);
Assert.AreEqual(br.ReadInt32(), 4);
Assert.AreEqual(br.ReadInt32(), 5);
Assert.AreEqual(br.ReadInt32(), 6);
Assert.AreEqual(br.ReadInt32(), 7);
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
namespace SharpCompress.Test
{
[TestClass]
public class SevenZipArchiveTests : ArchiveTests
{
[TestMethod]
public void SevenZipArchive_LZMA_StreamRead()
{
ArchiveStreamRead("7Zip.LZMA.7z");
}
[TestMethod]
public void SevenZipArchive_LZMA_PathRead()
{
ArchiveFileRead("7Zip.LZMA.7z");
}
[TestMethod]
public void SevenZipArchive_PPMd_StreamRead()
{
ArchiveStreamRead("7Zip.PPMd.7z");
}
[TestMethod]
public void SevenZipArchive_PPMd_StreamRead_Extract_All()
{
ArchiveStreamReadExtractAll("7Zip.PPMd.7z", CompressionType.PPMd);
}
[TestMethod]
public void SevenZipArchive_PPMd_PathRead()
{
ArchiveFileRead("7Zip.PPMd.7z");
}
[TestMethod]
public void SevenZipArchive_LZMA2_StreamRead()
{
ArchiveStreamRead("7Zip.LZMA2.7z");
}
[TestMethod]
public void SevenZipArchive_LZMA2_PathRead()
{
ArchiveFileRead("7Zip.LZMA2.7z");
}
[TestMethod]
public void SevenZipArchive_BZip2_StreamRead()
{
ArchiveStreamRead("7Zip.BZip2.7z");
}
[TestMethod]
public void SevenZipArchive_BZip2_PathRead()
{
ArchiveFileRead("7Zip.BZip2.7z");
}
[TestMethod]
[ExpectedException(typeof(IndexOutOfRangeException))]
public void SevenZipArchive_BZip2_Split()
{
ArchiveStreamRead("Original.7z.001", "Original.7z.002",
"Original.7z.003", "Original.7z.004", "Original.7z.005",
"Original.7z.006", "Original.7z.007");
}
}
}

View File

@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SharpCompress.Test</RootNamespace>
<AssemblyName>SharpCompress.Test</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\sharpcompress\</SolutionDir>
<RestorePackages>true</RestorePackages>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject>
</StartupObject>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\SharpCompress\SharpCompress.pfx</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="ArchiveTests.cs" />
<Compile Include="GZip\GZipWriterTests.cs" />
<Compile Include="GZip\GZipArchiveTests.cs" />
<Compile Include="SevenZip\SevenZipArchiveTests.cs" />
<Compile Include="Streams\StreamTests.cs" />
<Compile Include="Tar\TarWriterTests.cs" />
<Compile Include="Tar\TarReaderTests.cs" />
<Compile Include="Zip\ZipWriterTests.cs" />
<Compile Include="WriterTests.cs" />
<Compile Include="Rar\RarReaderTests.cs" />
<Compile Include="ReaderTests.cs" />
<Compile Include="Tar\TarArchiveTests.cs" />
<Compile Include="Zip\ZipArchiveTests.cs" />
<Compile Include="Rar\RarArchiveTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RewindableStreamTest.cs" />
<Compile Include="TestBase.cs" />
<Compile Include="TestStream.cs" />
<Compile Include="Zip\ZipReaderTests.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="..\SharpCompress\SharpCompress.pfx">
<Link>SharpCompress.pfx</Link>
</None>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SharpCompress\SharpCompress.csproj">
<Project>{10A689CF-76A2-4A4F-96E4-553C33398438}</Project>
<Name>SharpCompress</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,21 @@
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Compressor.LZMA;
namespace SharpCompress.Test.Streams
{
[TestClass]
public class StreamTests
{
[TestMethod]
public void TestLzma2Decompress1Byte()
{
byte[] properties = new byte[] { 0x01 };
byte[] compressedData = new byte[] { 0x01, 0x00, 0x00, 0x58, 0x00 };
MemoryStream lzma2Stream = new MemoryStream(compressedData);
LzmaStream decompressor = new LzmaStream(properties, lzma2Stream, 5, 1);
Assert.AreEqual('X', decompressor.ReadByte());
}
}
}

View File

@@ -0,0 +1,91 @@
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Archive;
using SharpCompress.Archive.Tar;
using SharpCompress.Common;
namespace SharpCompress.Test
{
[TestClass]
public class TarArchiveTests : ArchiveTests
{
public TarArchiveTests()
{
UseExtensionInsteadOfNameToVerify = true;
}
[TestMethod]
public void TarArchiveStreamRead()
{
ArchiveStreamRead("Tar.tar");
}
[TestMethod]
public void TarArchivePathRead()
{
ArchiveFileRead("Tar.tar");
}
[TestMethod]
public void TarArchivePathReadLongName()
{
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "very long filename.tar");
using (var archive = TarArchive.Open(unmodified))
{
Assert.AreEqual(2, archive.Entries.Count);
Assert.AreEqual(archive.Entries.Last().FilePath, @"very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg");
}
}
[TestMethod]
public void Tar_Create_New()
{
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.tar");
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
base.ResetScratch();
using (var archive = TarArchive.Create())
{
archive.AddAllFromDirectory(ORIGINAL_FILES_PATH);
archive.SaveTo(scratchPath, CompressionType.None);
}
CompareArchivesByPath(unmodified, scratchPath);
}
[TestMethod]
public void Tar_Random_Write_Add()
{
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg");
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar");
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar");
string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
base.ResetScratch();
using (var archive = TarArchive.Open(unmodified))
{
archive.AddEntry("jpg\\test.jpg", jpg);
archive.SaveTo(scratchPath, CompressionType.None);
}
CompareArchivesByPath(modified, scratchPath);
}
[TestMethod]
public void Tar_Random_Write_Remove()
{
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar");
string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar");
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
base.ResetScratch();
using (var archive = TarArchive.Open(unmodified))
{
var entry = archive.Entries.Where(x => x.FilePath.EndsWith("jpg")).Single();
archive.RemoveEntry(entry);
archive.SaveTo(scratchPath, CompressionType.None);
}
CompareArchivesByPath(modified, scratchPath);
}
}
}

View File

@@ -0,0 +1,92 @@
using System.Collections.Generic;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
using SharpCompress.Reader.Tar;
namespace SharpCompress.Test
{
[TestClass]
public class TarReaderTests : ReaderTests
{
public TarReaderTests()
{
UseExtensionInsteadOfNameToVerify = true;
}
[TestMethod]
public void Tar_Reader()
{
Read("Tar.tar", CompressionType.None);
}
[TestMethod]
public void Tar_BZip2_Reader()
{
Read("Tar.tar.bz2", CompressionType.BZip2);
}
[TestMethod]
public void Tar_GZip_Reader()
{
Read("Tar.tar.gz", CompressionType.GZip);
}
[TestMethod]
public void Tar_BZip2_Entry_Stream()
{
ResetScratch();
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2")))
using (var reader = TarReader.Open(stream))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.BZip2);
using (var entryStream = reader.OpenEntryStream())
{
string file = Path.GetFileName(reader.Entry.FilePath);
string folder = Path.GetDirectoryName(reader.Entry.FilePath);
string destdir = Path.Combine(SCRATCH_FILES_PATH, folder);
if (!Directory.Exists(destdir))
{
Directory.CreateDirectory(destdir);
}
string destinationFileName = Path.Combine(destdir, file);
using (FileStream fs = File.OpenWrite(destinationFileName))
{
entryStream.TransferTo(fs);
}
}
}
}
}
VerifyFiles();
}
[TestMethod]
public void Tar_BZip2_Skip_Entry_Stream()
{
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2")))
using (var reader = TarReader.Open(stream))
{
List<string> names = new List<string>();
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.BZip2);
using (var entryStream = reader.OpenEntryStream())
{
entryStream.SkipEntry();
names.Add(reader.Entry.FilePath);
}
}
}
Assert.AreEqual(names.Count, 3);
}
}
}
}

View File

@@ -0,0 +1,34 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
namespace SharpCompress.Test
{
[TestClass]
public class TarWriterTests : WriterTests
{
public TarWriterTests()
: base(ArchiveType.Tar)
{
UseExtensionInsteadOfNameToVerify = true;
}
[TestMethod]
public void Tar_Writer()
{
Write(CompressionType.None, "Tar.noEmptyDirs.tar", "Tar.noEmptyDirs.tar");
}
[TestMethod]
public void Tar_BZip2_Writer()
{
Write(CompressionType.BZip2, "Tar.noEmptyDirs.tar.bz2", "Tar.noEmptyDirs.tar.bz2");
}
[TestMethod]
[ExpectedException(typeof(InvalidFormatException))]
public void Tar_Rar_Write()
{
Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip");
}
}
}

View File

@@ -0,0 +1,151 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
using SharpCompress.Reader;
namespace SharpCompress.Test
{
public class TestBase
{
protected const string TEST_BASE_PATH = @"C:\Git\sharpcompress";
protected static readonly string TEST_ARCHIVES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Archives");
protected static readonly string ORIGINAL_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Original");
protected static readonly string MISC_TEST_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "MiscTest");
protected static readonly string SCRATCH_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Scratch");
protected static readonly string SCRATCH2_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Scratch2");
protected static IEnumerable<string> GetRarArchives()
{
yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.none.rar");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.rar");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.solid.rar");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.multi.part01.rar");
}
protected static IEnumerable<string> GetZipArchives()
{
yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.dd.zip");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.zip");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd-.zip");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.dd.zip");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.zip");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.none.zip");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.ppmd.dd.zip");
yield return Path.Combine(TEST_ARCHIVES_PATH, "Zip.ppmd.zip");
}
protected static IEnumerable<string> GetTarArchives()
{
yield return Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar");
}
protected static IEnumerable<string> GetTarBz2Archives()
{
yield return Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2");
}
protected static IEnumerable<string> GetTarGzArchives()
{
yield return Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz");
}
public void ResetScratch()
{
if (Directory.Exists(SCRATCH_FILES_PATH))
{
Directory.Delete(SCRATCH_FILES_PATH, true);
}
Directory.CreateDirectory(SCRATCH_FILES_PATH);
if (Directory.Exists(SCRATCH2_FILES_PATH))
{
Directory.Delete(SCRATCH2_FILES_PATH, true);
}
Directory.CreateDirectory(SCRATCH2_FILES_PATH);
}
public void VerifyFiles()
{
if (UseExtensionInsteadOfNameToVerify)
{
VerifyFilesByExtension();
}
else
{
VerifyFilesByName();
}
}
protected void VerifyFilesByName()
{
var extracted =
Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories)
.ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length));
var original =
Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)
.ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length));
Assert.AreEqual(extracted.Count, original.Count);
foreach (var orig in original)
{
Assert.IsTrue(extracted.Contains(orig.Key));
CompareFilesByPath(orig.Single(), extracted[orig.Key].Single());
}
}
protected bool UseExtensionInsteadOfNameToVerify { get; set; }
protected void VerifyFilesByExtension()
{
var extracted =
Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories)
.ToLookup(path => Path.GetExtension(path));
var original =
Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)
.ToLookup(path => Path.GetExtension(path));
Assert.AreEqual(extracted.Count, original.Count);
foreach (var orig in original)
{
Assert.IsTrue(extracted.Contains(orig.Key));
CompareFilesByPath(orig.Single(), extracted[orig.Key].Single());
}
}
protected void CompareFilesByPath(string file1, string file2)
{
using (var file1Stream = File.OpenRead(file1))
using (var file2Stream = File.OpenRead(file2))
{
Assert.AreEqual(file1Stream.Length, file2Stream.Length);
int byte1 = 0;
int byte2 = 0;
while (byte1 != -1)
{
byte1 = file1Stream.ReadByte();
byte2 = file2Stream.ReadByte();
Assert.AreEqual(byte1, byte2);
}
}
}
protected void CompareArchivesByPath(string file1, string file2)
{
using (var archive1 = ReaderFactory.Open(File.OpenRead(file1), Options.None))
using (var archive2 = ReaderFactory.Open(File.OpenRead(file2), Options.None))
{
while (archive1.MoveToNextEntry())
{
Assert.IsTrue(archive2.MoveToNextEntry());
Assert.AreEqual(archive1.Entry.FilePath, archive2.Entry.FilePath);
}
Assert.IsFalse(archive2.MoveToNextEntry());
}
}
}
}

View File

@@ -0,0 +1,85 @@
using System.IO;
namespace SharpCompress.Test
{
public class TestStream : Stream
{
private Stream stream;
private bool read;
private bool write;
private bool seek;
public TestStream(Stream stream)
: this(stream, true, true, true)
{
}
public bool IsDisposed { get; private set; }
public TestStream(Stream stream, bool read, bool write, bool seek)
{
this.stream = stream;
this.read = read;
this.write = write;
this.seek = seek;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
stream.Dispose();
IsDisposed = true;
}
public override bool CanRead
{
get { return read; }
}
public override bool CanSeek
{
get { return seek; }
}
public override bool CanWrite
{
get { return write; }
}
public override void Flush()
{
stream.Flush();
}
public override long Length
{
get { return stream.Length; }
}
public override long Position
{
get { return stream.Position; }
set { stream.Position = value; }
}
public override int Read(byte[] buffer, int offset, int count)
{
return stream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset, origin);
}
public override void SetLength(long value)
{
stream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
stream.Write(buffer, offset, count);
}
}
}

View File

@@ -0,0 +1,36 @@
using System.IO;
using SharpCompress.Common;
using SharpCompress.Reader;
using SharpCompress.Writer;
namespace SharpCompress.Test
{
public class WriterTests : TestBase
{
private ArchiveType type;
protected WriterTests(ArchiveType type)
{
this.type = type;
}
protected void Write(CompressionType compressionType, string archive, string archiveToVerifyAgainst)
{
ResetScratch();
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
using (var writer = WriterFactory.Open(stream, type, compressionType))
{
writer.WriteAll(ORIGINAL_FILES_PATH, "*", SearchOption.AllDirectories);
}
CompareArchivesByPath(Path.Combine(SCRATCH2_FILES_PATH, archive),
Path.Combine(TEST_ARCHIVES_PATH, archiveToVerifyAgainst));
using (Stream stream = File.OpenRead(Path.Combine(SCRATCH2_FILES_PATH, archive)))
using (var reader = ReaderFactory.Open(stream))
{
reader.WriteAllToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath);
}
VerifyFiles();
}
}
}

View File

@@ -0,0 +1,310 @@
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Archive;
using SharpCompress.Archive.Zip;
using SharpCompress.Common;
using SharpCompress.Writer;
namespace SharpCompress.Test
{
[TestClass]
public class ZipArchiveTests : ArchiveTests
{
public ZipArchiveTests()
{
UseExtensionInsteadOfNameToVerify = true;
}
[TestMethod]
public void Zip_ZipX_ArchiveStreamRead()
{
ArchiveStreamRead("Zip.zipx");
}
[TestMethod]
public void Zip_BZip2_Streamed_ArchiveStreamRead()
{
ArchiveStreamRead("Zip.bzip2.dd.zip");
}
[TestMethod]
public void Zip_BZip2_ArchiveStreamRead()
{
ArchiveStreamRead("Zip.bzip2.zip");
}
[TestMethod]
public void Zip_Deflate_Streamed2_ArchiveStreamRead()
{
ArchiveStreamRead("Zip.deflate.dd-.zip");
}
[TestMethod]
public void Zip_Deflate_Streamed_ArchiveStreamRead()
{
ArchiveStreamRead("Zip.deflate.dd.zip");
}
[TestMethod]
public void Zip_Deflate_ArchiveStreamRead()
{
ArchiveStreamRead("Zip.deflate.zip");
}
[TestMethod]
public void Zip_LZMA_Streamed_ArchiveStreamRead()
{
ArchiveStreamRead("Zip.lzma.dd.zip");
}
[TestMethod]
public void Zip_LZMA_ArchiveStreamRead()
{
ArchiveStreamRead("Zip.lzma.zip");
}
[TestMethod]
public void Zip_PPMd_Streamed_ArchiveStreamRead()
{
ArchiveStreamRead("Zip.ppmd.dd.zip");
}
[TestMethod]
public void Zip_PPMd_ArchiveStreamRead()
{
ArchiveStreamRead("Zip.ppmd.zip");
}
[TestMethod]
public void Zip_None_ArchiveStreamRead()
{
ArchiveStreamRead("Zip.none.zip");
}
[TestMethod]
public void Zip_BZip2_Streamed_ArchiveFileRead()
{
ArchiveFileRead("Zip.bzip2.dd.zip");
}
[TestMethod]
public void Zip_BZip2_ArchiveFileRead()
{
ArchiveFileRead("Zip.bzip2.zip");
}
[TestMethod]
public void Zip_Deflate_Streamed2_ArchiveFileRead()
{
ArchiveFileRead("Zip.deflate.dd-.zip");
}
[TestMethod]
public void Zip_Deflate_Streamed_ArchiveFileRead()
{
ArchiveFileRead("Zip.deflate.dd.zip");
}
[TestMethod]
public void Zip_Deflate_ArchiveFileRead()
{
ArchiveFileRead("Zip.deflate.zip");
}
[TestMethod]
public void Zip_LZMA_Streamed_ArchiveFileRead()
{
ArchiveFileRead("Zip.lzma.dd.zip");
}
[TestMethod]
public void Zip_LZMA_ArchiveFileRead()
{
ArchiveFileRead("Zip.lzma.zip");
}
[TestMethod]
public void Zip_PPMd_Streamed_ArchiveFileRead()
{
ArchiveFileRead("Zip.ppmd.dd.zip");
}
[TestMethod]
public void Zip_PPMd_ArchiveFileRead()
{
ArchiveFileRead("Zip.ppmd.zip");
}
[TestMethod]
public void Zip_None_ArchiveFileRead()
{
ArchiveFileRead("Zip.none.zip");
}
[TestMethod]
public void Zip_Random_Write_Remove()
{
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip");
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip");
base.ResetScratch();
using (var archive = ZipArchive.Open(unmodified))
{
var entry = archive.Entries.Where(x => x.FilePath.EndsWith("jpg")).Single();
archive.RemoveEntry(entry);
archive.SaveTo(scratchPath, CompressionType.Deflate);
}
CompareArchivesByPath(modified, scratchPath);
}
[TestMethod]
[ExpectedException(typeof(ArchiveException))]
public void Zip_Random_Write_Remove_Fail()
{
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip");
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip");
base.ResetScratch();
using (var stream = File.OpenRead(unmodified))
using (var archive = ZipArchive.Open(stream))
{
var entry = archive.Entries.Where(x => x.FilePath.EndsWith("jpg")).Single();
archive.RemoveEntry(entry);
archive.SaveTo(scratchPath, CompressionType.Deflate);
}
CompareArchivesByPath(modified, scratchPath);
}
[TestMethod]
public void Zip_Random_Write_Add()
{
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg");
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip");
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip");
string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod2.zip");
base.ResetScratch();
using (var archive = ZipArchive.Open(unmodified))
{
archive.AddEntry("jpg\\test.jpg", jpg);
archive.SaveTo(scratchPath, CompressionType.Deflate);
}
CompareArchivesByPath(modified, scratchPath);
}
[TestMethod]
public void Zip_Create_New()
{
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.noEmptyDirs.zip");
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
base.ResetScratch();
using (var archive = ZipArchive.Create())
{
archive.AddAllFromDirectory(ORIGINAL_FILES_PATH);
archive.SaveTo(scratchPath, CompressionType.Deflate);
}
CompareArchivesByPath(unmodified, scratchPath);
}
[TestMethod]
public void Zip_Deflate_WinzipAES_Read()
{
ResetScratch();
using (var reader = ZipArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip"), "test"))
{
foreach (var entry in reader.Entries.Where(x => !x.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
[TestMethod]
public void Zip_BZip2_Pkware_Read()
{
ResetScratch();
using (var reader = ZipArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip"), "test"))
{
foreach (var entry in reader.Entries.Where(x => !x.IsDirectory))
{
entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
VerifyFiles();
}
[TestMethod]
public void Zip_Random_Entry_Access()
{
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
base.ResetScratch();
ZipArchive a = ZipArchive.Open(unmodified);
int count = 0;
foreach (var e in a.Entries)
count++;
//Prints 3
Assert.AreEqual(count, 3);
a.Dispose();
a = ZipArchive.Open(unmodified);
int count2 = 0;
foreach (var e in a.Entries)
{
count2++;
//Stop at last file
if (count2 == count)
{
var s = e.OpenEntryStream();
s.ReadByte(); //Actually access stream
s.Dispose();
break;
}
}
int count3 = 0;
foreach (var e in a.Entries)
count3++;
Assert.AreEqual(count3, 3);
}
class NonSeekableMemoryStream : MemoryStream
{
public override bool CanSeek
{
get
{
return false;
}
}
}
[TestMethod]
public void TestSharpCompressWithEmptyStream()
{
MemoryStream stream = new NonSeekableMemoryStream();
using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate))
{
zipWriter.Write("foo.txt", new MemoryStream(new byte[0]));
zipWriter.Write("foo2.txt", new MemoryStream(new byte[10]));
}
stream = new MemoryStream(stream.ToArray());
File.WriteAllBytes("foo.zip", stream.ToArray());
using (var zipArchive = ZipArchive.Open(stream))
{
foreach(var entry in zipArchive.Entries)
{
using (var entryStream = entry.OpenEntryStream())
{
MemoryStream tempStream = new MemoryStream();
const int bufSize = 0x1000;
byte[] buf = new byte[bufSize];
int bytesRead = 0;
while ((bytesRead = entryStream.Read(buf, 0, bufSize)) > 0)
tempStream.Write(buf, 0, bytesRead);
}
}
}
}
}
}

View File

@@ -0,0 +1,224 @@
using System;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
using SharpCompress.Reader;
using SharpCompress.Reader.Zip;
using SharpCompress.Writer;
namespace SharpCompress.Test
{
[TestClass]
public class ZipReaderTests : ReaderTests
{
public ZipReaderTests()
{
UseExtensionInsteadOfNameToVerify = true;
}
[TestMethod]
public void Zip_ZipX_Streamed_Read()
{
Read("Zip.Zipx", CompressionType.LZMA);
}
[TestMethod]
public void Zip_BZip2_Streamed_Read()
{
Read("Zip.bzip2.dd.zip", CompressionType.BZip2);
}
[TestMethod]
public void Zip_BZip2_Read()
{
Read("Zip.bzip2.zip", CompressionType.BZip2);
}
[TestMethod]
public void Zip_Deflate_Streamed2_Read()
{
Read("Zip.deflate.dd-.zip", CompressionType.Deflate);
}
[TestMethod]
public void Zip_Deflate_Streamed_Read()
{
Read("Zip.deflate.dd.zip", CompressionType.Deflate);
}
[TestMethod]
public void Zip_Deflate_Read()
{
Read("Zip.deflate.zip", CompressionType.Deflate);
}
[TestMethod]
public void Zip_LZMA_Streamed_Read()
{
Read("Zip.lzma.dd.zip", CompressionType.LZMA);
}
[TestMethod]
public void Zip_LZMA_Read()
{
Read("Zip.lzma.zip", CompressionType.LZMA);
}
[TestMethod]
public void Zip_PPMd_Streamed_Read()
{
Read("Zip.ppmd.dd.zip", CompressionType.PPMd);
}
[TestMethod]
public void Zip_PPMd_Read()
{
Read("Zip.ppmd.zip", CompressionType.PPMd);
}
[TestMethod]
public void Zip_None_Read()
{
Read("Zip.none.zip", CompressionType.None);
}
[TestMethod]
public void Zip_Deflate_NoEmptyDirs_Read()
{
Read("Zip.deflate.noEmptyDirs.zip", CompressionType.Deflate);
}
[TestMethod]
public void Zip_BZip2_PkwareEncryption_Read()
{
ResetScratch();
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.pkware.zip")))
using (var reader = ZipReader.Open(stream, "test"))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.BZip2);
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
}
VerifyFiles();
}
[TestMethod]
public void Zip_Reader_Disposal_Test()
{
ResetScratch();
using (TestStream stream = new TestStream(File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip"))))
{
using (var reader = ReaderFactory.Open(stream, Options.None))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH,
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
}
Assert.IsTrue(stream.IsDisposed);
}
}
[TestMethod]
public void Zip_Reader_Disposal_Test2()
{
ResetScratch();
using (TestStream stream = new TestStream(File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.dd.zip"))))
{
var reader = ReaderFactory.Open(stream, Options.None);
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH,
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
Assert.IsFalse(stream.IsDisposed);
}
}
[TestMethod]
[ExpectedException(typeof(NotSupportedException))]
public void Zip_LZMA_WinzipAES_Read()
{
ResetScratch();
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.winzipaes.zip")))
using (var reader = ZipReader.Open(stream, "test"))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Unknown);
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
}
VerifyFiles();
}
[TestMethod]
public void Zip_Deflate_WinzipAES_Read()
{
ResetScratch();
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.WinzipAES.zip")))
using (var reader = ZipReader.Open(stream, "test"))
{
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Unknown);
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH,
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
}
}
}
VerifyFiles();
}
class NonSeekableMemoryStream : MemoryStream
{
public override bool CanSeek
{
get
{
return false;
}
}
}
[TestMethod]
public void TestSharpCompressWithEmptyStream()
{
MemoryStream stream = new NonSeekableMemoryStream();
using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate))
{
zipWriter.Write("foo.txt", new MemoryStream(new byte[0]));
zipWriter.Write("foo2.txt", new MemoryStream(new byte[10]));
}
stream = new MemoryStream(stream.ToArray());
File.WriteAllBytes("foo.zip", stream.ToArray());
using (IReader zipReader = ZipReader.Open(stream))
{
while (zipReader.MoveToNextEntry())
{
using (EntryStream entry = zipReader.OpenEntryStream())
{
MemoryStream tempStream = new MemoryStream();
const int bufSize = 0x1000;
byte[] buf = new byte[bufSize];
int bytesRead = 0;
while ((bytesRead = entry.Read(buf, 0, bufSize)) > 0)
tempStream.Write(buf, 0, bytesRead);
}
}
}
}
}
}

View File

@@ -0,0 +1,54 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpCompress.Common;
namespace SharpCompress.Test
{
[TestClass]
public class ZipWriterTests : WriterTests
{
public ZipWriterTests()
: base(ArchiveType.Zip)
{
}
[TestMethod]
public void Zip_Deflate_Write()
{
Write(CompressionType.Deflate, "Zip.deflate.noEmptyDirs.zip", "Zip.deflate.noEmptyDirs.zip");
}
[TestMethod]
public void Zip_BZip2_Write()
{
Write(CompressionType.BZip2, "Zip.bzip2.noEmptyDirs.zip", "Zip.bzip2.noEmptyDirs.zip");
}
[TestMethod]
public void Zip_None_Write()
{
Write(CompressionType.None, "Zip.none.noEmptyDirs.zip", "Zip.none.noEmptyDirs.zip");
}
[TestMethod]
public void Zip_LZMA_Write()
{
Write(CompressionType.LZMA, "Zip.lzma.noEmptyDirs.zip", "Zip.lzma.noEmptyDirs.zip");
}
[TestMethod]
public void Zip_PPMd_Write()
{
Write(CompressionType.PPMd, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip");
}
[TestMethod]
[ExpectedException(typeof(InvalidFormatException))]
public void Zip_Rar_Write()
{
Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip");
}
}
}

53
SharpCompress.shfbproj Normal file
View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<!-- The configuration and platform will be used to determine which
assemblies to include from solution and project documentation
sources -->
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{a226cac9-f2c4-4cc2-94f9-163b3e221817}</ProjectGuid>
<SHFBSchemaVersion>1.9.3.0</SHFBSchemaVersion>
<!-- AssemblyName, Name, and RootNamespace are not used by SHFB but Visual
Studio adds them anyway -->
<AssemblyName>Documentation</AssemblyName>
<RootNamespace>Documentation</RootNamespace>
<Name>Documentation</Name>
<!-- SHFB properties -->
<OutputPath>.\Help\</OutputPath>
<HtmlHelpName>sharpcompress</HtmlHelpName>
<Language>en-US</Language>
<RootNamespaceTitle>SharpCompress</RootNamespaceTitle>
<SandcastlePath>..\..\Program Files (x86)\Sandcastle\</SandcastlePath>
<DocumentationSources>
<DocumentationSource sourceFile="bin\SharpCompress.dll" />
<DocumentationSource sourceFile="bin\SharpCompress.xml" />
</DocumentationSources>
<HelpTitle>SharpCompress</HelpTitle>
<PresentationStyle>Prototype</PresentationStyle>
<HelpFileFormat>HtmlHelp1, Website</HelpFileFormat>
<MissingTags>AutoDocumentCtors, AutoDocumentDispose</MissingTags>
</PropertyGroup>
<!-- There are no properties for these groups. AnyCPU needs to appear in
order for Visual Studio to perform the build. The others are optional
common platform types that may appear. -->
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|Win32' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|Win32' ">
</PropertyGroup>
<!-- Import the SHFB build targets -->
<Import Project="$(SHFBROOT)\SandcastleHelpFileBuilder.targets" />
</Project>

Binary file not shown.

View File

@@ -1,63 +1,92 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.6
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C5BE746-03E5-4895-9988-0B57F162F86C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0F0901FF-E8D9-426A-B5A2-17C7F47C1529}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpCompress", "src\SharpCompress\SharpCompress.csproj", "{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpCompress.Test", "tests\SharpCompress.Test\SharpCompress.Test.csproj", "{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "build", "build\build.csproj", "{D4D613CB-5E94-47FB-85BE-B8423D20C545}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{CDB42573-7D22-4490-BA12-1B7FB99CE7FB}"
ProjectSection(SolutionItems) = preProject
Directory.Build.props = Directory.Build.props
global.json = global.json
.editorconfig = .editorconfig
Directory.Packages.props = Directory.Packages.props
NuGet.config = NuGet.config
.github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml
USAGE.md = USAGE.md
README.md = README.md
FORMATS.md = FORMATS.md
AGENTS.md = AGENTS.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.Performance", "tests\SharpCompress.Performance\SharpCompress.Performance.csproj", "{5BDE6DBC-9E5F-4E21-AB71-F138A3E72B17}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.Build.0 = Release|Any CPU
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F}.Release|Any CPU.Build.0 = Release|Any CPU
{D4D613CB-5E94-47FB-85BE-B8423D20C545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4D613CB-5E94-47FB-85BE-B8423D20C545}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4D613CB-5E94-47FB-85BE-B8423D20C545}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4D613CB-5E94-47FB-85BE-B8423D20C545}.Release|Any CPU.Build.0 = Release|Any CPU
{5BDE6DBC-9E5F-4E21-AB71-F138A3E72B17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5BDE6DBC-9E5F-4E21-AB71-F138A3E72B17}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5BDE6DBC-9E5F-4E21-AB71-F138A3E72B17}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5BDE6DBC-9E5F-4E21-AB71-F138A3E72B17}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {3C5BE746-03E5-4895-9988-0B57F162F86C}
{F2B1A1EB-0FA6-40D0-8908-E13247C7226F} = {0F0901FF-E8D9-426A-B5A2-17C7F47C1529}
{5BDE6DBC-9E5F-4E21-AB71-F138A3E72B17} = {0F0901FF-E8D9-426A-B5A2-17C7F47C1529}
EndGlobalSection
EndGlobal
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress", "SharpCompress\SharpCompress.csproj", "{10A689CF-76A2-4A4F-96E4-553C33398438}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.Test", "SharpCompress.Test\SharpCompress.Test.csproj", "{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.Portable", "SharpCompress\SharpCompress.Portable.csproj", "{7FA7D133-1417-4F85-9998-4C618AC8FEDA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.WindowsStore", "SharpCompress\SharpCompress.WindowsStore.csproj", "{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.WinRT", "SharpCompress\SharpCompress.WinRT.csproj", "{90F0D086-689E-470D-A72C-2FA01779FF90}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{10A689CF-76A2-4A4F-96E4-553C33398438}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{10A689CF-76A2-4A4F-96E4-553C33398438}.Debug|Any CPU.Build.0 = Debug|Any CPU
{10A689CF-76A2-4A4F-96E4-553C33398438}.Debug|ARM.ActiveCfg = Debug|Any CPU
{10A689CF-76A2-4A4F-96E4-553C33398438}.Debug|x64.ActiveCfg = Debug|Any CPU
{10A689CF-76A2-4A4F-96E4-553C33398438}.Debug|x86.ActiveCfg = Debug|Any CPU
{10A689CF-76A2-4A4F-96E4-553C33398438}.Release|Any CPU.ActiveCfg = Release|Any CPU
{10A689CF-76A2-4A4F-96E4-553C33398438}.Release|Any CPU.Build.0 = Release|Any CPU
{10A689CF-76A2-4A4F-96E4-553C33398438}.Release|ARM.ActiveCfg = Release|Any CPU
{10A689CF-76A2-4A4F-96E4-553C33398438}.Release|x64.ActiveCfg = Release|Any CPU
{10A689CF-76A2-4A4F-96E4-553C33398438}.Release|x86.ActiveCfg = Release|Any CPU
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Debug|ARM.ActiveCfg = Debug|Any CPU
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Debug|x64.ActiveCfg = Debug|Any CPU
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Debug|x86.ActiveCfg = Debug|Any CPU
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Release|Any CPU.Build.0 = Release|Any CPU
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Release|ARM.ActiveCfg = Release|Any CPU
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Release|x64.ActiveCfg = Release|Any CPU
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Release|x86.ActiveCfg = Release|Any CPU
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Debug|ARM.ActiveCfg = Debug|Any CPU
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Debug|x64.ActiveCfg = Debug|Any CPU
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Debug|x86.ActiveCfg = Debug|Any CPU
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Release|Any CPU.Build.0 = Release|Any CPU
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Release|ARM.ActiveCfg = Release|Any CPU
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Release|x64.ActiveCfg = Release|Any CPU
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Release|x86.ActiveCfg = Release|Any CPU
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|ARM.ActiveCfg = Debug|ARM
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|ARM.Build.0 = Debug|ARM
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|x64.ActiveCfg = Debug|x64
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|x64.Build.0 = Debug|x64
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|x86.ActiveCfg = Debug|x86
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|x86.Build.0 = Debug|x86
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|Any CPU.Build.0 = Release|Any CPU
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|ARM.ActiveCfg = Release|ARM
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|ARM.Build.0 = Release|ARM
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|x64.ActiveCfg = Release|x64
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|x64.Build.0 = Release|x64
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|x86.ActiveCfg = Release|x86
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|x86.Build.0 = Release|x86
{90F0D086-689E-470D-A72C-2FA01779FF90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{90F0D086-689E-470D-A72C-2FA01779FF90}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90F0D086-689E-470D-A72C-2FA01779FF90}.Debug|ARM.ActiveCfg = Debug|ARM
{90F0D086-689E-470D-A72C-2FA01779FF90}.Debug|ARM.Build.0 = Debug|ARM
{90F0D086-689E-470D-A72C-2FA01779FF90}.Debug|x64.ActiveCfg = Debug|x64
{90F0D086-689E-470D-A72C-2FA01779FF90}.Debug|x64.Build.0 = Debug|x64
{90F0D086-689E-470D-A72C-2FA01779FF90}.Debug|x86.ActiveCfg = Debug|x86
{90F0D086-689E-470D-A72C-2FA01779FF90}.Debug|x86.Build.0 = Debug|x86
{90F0D086-689E-470D-A72C-2FA01779FF90}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90F0D086-689E-470D-A72C-2FA01779FF90}.Release|Any CPU.Build.0 = Release|Any CPU
{90F0D086-689E-470D-A72C-2FA01779FF90}.Release|ARM.ActiveCfg = Release|ARM
{90F0D086-689E-470D-A72C-2FA01779FF90}.Release|ARM.Build.0 = Release|ARM
{90F0D086-689E-470D-A72C-2FA01779FF90}.Release|x64.ActiveCfg = Release|x64
{90F0D086-689E-470D-A72C-2FA01779FF90}.Release|x64.Build.0 = Release|x64
{90F0D086-689E-470D-A72C-2FA01779FF90}.Release|x86.ActiveCfg = Release|x86
{90F0D086-689E-470D-A72C-2FA01779FF90}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -1,138 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArgumentsStyleNamedExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fdowhile/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Ffixed/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Ffor/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fforeach/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fifelse/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Flock/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fusing/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeBraces_005Fwhile/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MethodSupportsCancellation/@EntryIndexedValue">ERROR</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantExplicitParamsArrayCreation/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Basic_0020Clean/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Basic Clean"&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSShortenReferences&gt;True&lt;/CSShortenReferences&gt;&lt;CSRemoveCodeRedundancies&gt;True&lt;/CSRemoveCodeRedundancies&gt;&lt;CSMakeFieldReadonly&gt;True&lt;/CSMakeFieldReadonly&gt;&lt;CSCodeStyleAttributes ArrangeTypeAccessModifier="False" ArrangeTypeMemberAccessModifier="False" SortModifiers="False" RemoveRedundantParentheses="False" AddMissingParentheses="False" ArrangeBraces="True" ArrangeAttributes="False" ArrangeArgumentsStyle="False" /&gt;&lt;RemoveCodeRedundancies&gt;True&lt;/RemoveCodeRedundancies&gt;&lt;CSUseAutoProperty&gt;True&lt;/CSUseAutoProperty&gt;&lt;CSMakeAutoPropertyGetOnly&gt;True&lt;/CSMakeAutoPropertyGetOnly&gt;&lt;CSReformatCode&gt;True&lt;/CSReformatCode&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/SilentCleanupProfile/@EntryValue">Basic Clean</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/APPLY_ON_COMPLETION/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ARGUMENTS_NAMED/@EntryValue">Positional</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_FIRST_ARG_BY_PAREN/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_LINQ_QUERY/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_ARGUMENT/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_ARRAY_AND_OBJECT_INITIALIZER/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_EXPRESSION/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_FOR_STMT/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_PARAMETER/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTIPLE_DECLARATION/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_CONSTRAINS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_LIST/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AFTER_START_COMMENT/@EntryValue">0</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BEFORE_SINGLE_LINE_COMMENT/@EntryValue">1</s:Int64>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_ATTRIBUTE_STYLE/@EntryValue">SEPARATE</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FIXED_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOR_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOREACH_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_IFELSE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_USING_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_WHILE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_ANONYMOUS_METHOD_BLOCK/@EntryValue">False</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_CONSTRUCTOR_INITIALIZER_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSORHOLDER_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_INITIALIZER_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_WHILE_ON_NEW_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_ARROW_OP/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_MULTIPLICATIVE_OP/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_SIZEOF_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_TYPEOF_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/STICK_COMMENT/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARGUMENTS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARRAY_INITIALIZER_STYLE/@EntryValue">CHOP_ALWAYS</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_EXTENDS_LIST_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LINES/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_PARAMETERS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForBuiltInTypes/@EntryValue">UseVar</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseVar</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseVar</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=15b5b1f1_002D457c_002D4ca6_002Db278_002D5615aedc07d3/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=4a98fdf6_002D7d98_002D4f5a_002Dafeb_002Dea44ad98c70c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=c873eafb_002Dd57f_002D481d_002D8c93_002D77f6863c2f88/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static readonly fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=f9fce829_002De6f4_002D4cb2_002D80f1_002D5497c44f51df/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FCONSTANT/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCLASS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCONSTRUCTOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FGLOBAL_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLABEL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLOCAL_005FCONSTRUCTOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLOCAL_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FOBJECT_005FPROPERTY_005FOF_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FPARAMETER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FCLASS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM_005FMEMBER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FINTERFACE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE_005FEXPORTED/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE_005FLOCAL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FTYPE_005FPARAMETER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FHTML_005FCONTROL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FTAG_005FNAME/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FTAG_005FPREFIX/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=NAMESPACE_005FALIAS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FRESOURCE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CustomTools/CustomToolsData/@EntryValue"></s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=6af8f80e_002D9fdd_002D4223_002D8e02_002D473db916f9b2/@EntryIndexedValue">&lt;SessionState ContinuousTestingIsOn="False" ContinuousTestingMode="0" FrameworkVersion="{x:Null}" IsLocked="False" Name="All tests from Solution" PlatformMonoPreference="{x:Null}" PlatformType="{x:Null}" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
&lt;Solution /&gt;
&lt;/SessionState&gt;</s:String></wpf:ResourceDictionary>

Binary file not shown.

View File

@@ -0,0 +1,205 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Reader;
namespace SharpCompress.Archive
{
public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IStreamListener
where TEntry : IArchiveEntry
where TVolume : IVolume
{
private readonly LazyReadOnlyCollection<TVolume> lazyVolumes;
private readonly LazyReadOnlyCollection<TEntry> lazyEntries;
public event EventHandler<ArchiveExtractionEventArgs<IArchiveEntry>> EntryExtractionBegin;
public event EventHandler<ArchiveExtractionEventArgs<IArchiveEntry>> EntryExtractionEnd;
public event EventHandler<CompressedBytesReadEventArgs> CompressedBytesRead;
public event EventHandler<FilePartExtractionBeginEventArgs> FilePartExtractionBegin;
#if !PORTABLE && !NETFX_CORE
internal AbstractArchive(ArchiveType type, FileInfo fileInfo, Options options)
{
this.Type = type;
if (!fileInfo.Exists)
{
throw new ArgumentException("File does not exist: " + fileInfo.FullName);
}
options = (Options) FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(fileInfo, options));
lazyEntries = new LazyReadOnlyCollection<TEntry>(LoadEntries(Volumes));
}
protected abstract IEnumerable<TVolume> LoadVolumes(FileInfo file, Options options);
#endif
internal AbstractArchive(ArchiveType type, IEnumerable<Stream> streams, Options options)
{
this.Type = type;
lazyVolumes =
new LazyReadOnlyCollection<TVolume>(LoadVolumes(streams.Select<Stream, Stream>(CheckStreams), options));
lazyEntries = new LazyReadOnlyCollection<TEntry>(LoadEntries(Volumes));
}
internal AbstractArchive(ArchiveType type)
{
this.Type = type;
lazyVolumes = new LazyReadOnlyCollection<TVolume>(Enumerable.Empty<TVolume>());
lazyEntries = new LazyReadOnlyCollection<TEntry>(Enumerable.Empty<TEntry>());
}
internal void FireEntryExtractionBegin(IArchiveEntry entry)
{
if (EntryExtractionBegin != null)
{
EntryExtractionBegin(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
}
}
internal void FireEntryExtractionEnd(IArchiveEntry entry)
{
if (EntryExtractionEnd != null)
{
EntryExtractionEnd(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
}
}
private static Stream CheckStreams(Stream stream)
{
if (!stream.CanSeek || !stream.CanRead)
{
throw new ArgumentException("Archive streams must be Readable and Seekable");
}
return stream;
}
/// <summary>
/// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive.
/// </summary>
/// <returns></returns>
public virtual ICollection<TEntry> Entries
{
get { return lazyEntries; }
}
/// <summary>
/// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive.
/// </summary>
/// <returns></returns>
public ICollection<TVolume> Volumes
{
get { return lazyVolumes; }
}
/// <summary>
/// The total size of the files compressed in the archive.
/// </summary>
public long TotalSize
{
get { return Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); }
}
protected abstract IEnumerable<TVolume> LoadVolumes(IEnumerable<Stream> streams, Options options);
protected abstract IEnumerable<TEntry> LoadEntries(IEnumerable<TVolume> volumes);
IEnumerable<IArchiveEntry> IArchive.Entries
{
get { return lazyEntries.Cast<IArchiveEntry>(); }
}
IEnumerable<IVolume> IArchive.Volumes
{
get { return lazyVolumes.Cast<IVolume>(); }
}
private bool disposed;
public void Dispose()
{
if (!disposed)
{
lazyVolumes.ForEach(v => v.Dispose());
lazyEntries.GetLoaded().Cast<Entry>().ForEach(x => x.Close());
disposed = true;
}
}
internal void EnsureEntriesLoaded()
{
lazyEntries.EnsureFullyLoaded();
lazyVolumes.EnsureFullyLoaded();
}
public ArchiveType Type { get; private set; }
void IStreamListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes)
{
if (CompressedBytesRead != null)
{
CompressedBytesRead(this, new CompressedBytesReadEventArgs()
{
CurrentFilePartCompressedBytesRead = currentPartCompressedBytes,
CompressedBytesRead = compressedReadBytes
});
}
}
void IStreamListener.FireFilePartExtractionBegin(string name, long size, long compressedSize)
{
if (FilePartExtractionBegin != null)
{
FilePartExtractionBegin(this, new FilePartExtractionBeginEventArgs()
{
CompressedSize = compressedSize,
Size = size,
Name = name,
});
}
}
/// <summary>
/// Use this method to extract all entries in an archive in order.
/// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be
/// extracted sequentially for the best performance.
///
/// This method will load all entry information from the archive.
///
/// WARNING: this will reuse the underlying stream for the archive. Errors may
/// occur if this is used at the same time as other extraction methods on this instance.
/// </summary>
/// <returns></returns>
public IReader ExtractAllEntries()
{
EnsureEntriesLoaded();
return CreateReaderForSolidExtraction();
}
protected abstract IReader CreateReaderForSolidExtraction();
/// <summary>
/// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files).
/// </summary>
public virtual bool IsSolid
{
get { return false; }
}
/// <summary>
/// The archive can find all the parts of the archive needed to fully extract the archive. This forces the parsing of the entire archive.
/// </summary>
public bool IsComplete
{
get
{
EnsureEntriesLoaded();
return Entries.All(x => x.IsComplete);
}
}
}
}

View File

@@ -0,0 +1,85 @@
using System.IO;
using SharpCompress.Common;
namespace SharpCompress.Archive
{
public static class AbstractWritableArchiveExtensions
{
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
Stream stream, CompressionType compressionType)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
}
#if !PORTABLE && !NETFX_CORE
public static void AddEntry<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
string entryPath, string filePath)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
var fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists)
{
throw new FileNotFoundException("Could not AddEntry: " + filePath);
}
writableArchive.AddEntry(entryPath, new FileInfo(filePath).OpenRead(), true, fileInfo.Length,
fileInfo.LastWriteTime);
}
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
string filePath, CompressionType compressionType)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
writableArchive.SaveTo(new FileInfo(filePath), new CompressionInfo {Type = compressionType});
}
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
FileInfo fileInfo, CompressionType compressionType)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
}
}
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
string filePath, CompressionInfo compressionInfo)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
writableArchive.SaveTo(new FileInfo(filePath), compressionInfo);
}
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
FileInfo fileInfo, CompressionInfo compressionInfo)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
writableArchive.SaveTo(stream, compressionInfo);
}
}
public static void AddAllFromDirectory<TEntry, TVolume>(
this AbstractWritableArchive<TEntry, TVolume> writableArchive,
string filePath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.AllDirectories)
where TEntry : IArchiveEntry
where TVolume : IVolume
{
foreach (var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption))
{
var fileInfo = new FileInfo(path);
writableArchive.AddEntry(path.Substring(filePath.Length), fileInfo.OpenRead(), true, fileInfo.Length,
fileInfo.LastWriteTime);
}
}
#endif
}
}

View File

@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
namespace SharpCompress.Archive
{
public abstract class AbstractWritableArchive<TEntry, TVolume> : AbstractArchive<TEntry, TVolume>
where TEntry : IArchiveEntry
where TVolume : IVolume
{
private readonly List<TEntry> newEntries = new List<TEntry>();
private readonly List<TEntry> removedEntries = new List<TEntry>();
private readonly List<TEntry> modifiedEntries = new List<TEntry>();
private bool hasModifications;
private readonly bool anyNotWritable;
internal AbstractWritableArchive(ArchiveType type)
: base(type)
{
}
internal AbstractWritableArchive(ArchiveType type, IEnumerable<Stream> streams, Options options)
: base(type, streams, options)
{
if (streams.Any(x => !x.CanWrite))
{
anyNotWritable = true;
}
}
#if !PORTABLE && !NETFX_CORE
internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, Options options)
: base(type, fileInfo, options)
{
}
#endif
private void CheckWritable()
{
if (anyNotWritable)
{
throw new ArchiveException("All Archive streams must be Writable to use Archive writing functionality.");
}
}
public override ICollection<TEntry> Entries
{
get
{
if (hasModifications)
{
return modifiedEntries;
}
return base.Entries;
}
}
private void RebuildModifiedCollection()
{
hasModifications = true;
modifiedEntries.Clear();
modifiedEntries.AddRange(OldEntries.Concat(newEntries));
}
private IEnumerable<TEntry> OldEntries
{
get { return base.Entries.Where(x => !removedEntries.Contains(x)); }
}
public void RemoveEntry(TEntry entry)
{
CheckWritable();
if (!removedEntries.Contains(entry))
{
removedEntries.Add(entry);
RebuildModifiedCollection();
}
}
public void AddEntry(string filePath, Stream source,
long size = 0, DateTime? modified = null)
{
CheckWritable();
newEntries.Add(CreateEntry(filePath, source, size, modified, false));
RebuildModifiedCollection();
}
public void AddEntry(string filePath, Stream source, bool closeStream,
long size = 0, DateTime? modified = null)
{
CheckWritable();
newEntries.Add(CreateEntry(filePath, source, size, modified, closeStream));
RebuildModifiedCollection();
}
#if !PORTABLE && !NETFX_CORE
public void AddEntry(string filePath, FileInfo fileInfo)
{
if (!fileInfo.Exists)
{
throw new ArgumentException("FileInfo does not exist.");
}
AddEntry(filePath, fileInfo.OpenRead(), true, fileInfo.Length, fileInfo.LastWriteTime);
}
#endif
public void SaveTo(Stream stream, CompressionInfo compressionType)
{
SaveTo(stream, compressionType, OldEntries, newEntries);
}
protected abstract TEntry CreateEntry(string filePath, Stream source, long size, DateTime? modified,
bool closeStream);
protected abstract void SaveTo(Stream stream, CompressionInfo compressionType,
IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
}
}

View File

@@ -0,0 +1,168 @@
using System;
using System.IO;
using SharpCompress.Archive.GZip;
using SharpCompress.Archive.Rar;
using SharpCompress.Archive.SevenZip;
using SharpCompress.Archive.Tar;
using SharpCompress.Archive.Zip;
using SharpCompress.Common;
namespace SharpCompress.Archive
{
public class ArchiveFactory
{
/// <summary>
/// Opens an Archive for random access
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
/// <returns></returns>
public static IArchive Open(Stream stream, Options options = Options.KeepStreamsOpen)
{
stream.CheckNotNull("stream");
if (!stream.CanRead || !stream.CanSeek)
{
throw new ArgumentException("Stream should be readable and seekable");
}
if (ZipArchive.IsZipFile(stream, null))
{
stream.Seek(0, SeekOrigin.Begin);
return ZipArchive.Open(stream, options, null);
}
stream.Seek(0, SeekOrigin.Begin);
if (RarArchive.IsRarFile(stream))
{
stream.Seek(0, SeekOrigin.Begin);
return RarArchive.Open(stream, options);
}
stream.Seek(0, SeekOrigin.Begin);
if (TarArchive.IsTarFile(stream))
{
stream.Seek(0, SeekOrigin.Begin);
return TarArchive.Open(stream, options);
}
stream.Seek(0, SeekOrigin.Begin);
if (SevenZipArchive.IsSevenZipFile(stream))
{
stream.Seek(0, SeekOrigin.Begin);
return SevenZipArchive.Open(stream, options);
}
stream.Seek(0, SeekOrigin.Begin);
if (GZipArchive.IsGZipFile(stream))
{
stream.Seek(0, SeekOrigin.Begin);
return GZipArchive.Open(stream, options);
}
throw new InvalidOperationException("Cannot determine compressed stream type.");
}
public static IArchive Create(ArchiveType type)
{
switch (type)
{
case ArchiveType.Zip:
{
return ZipArchive.Create();
}
case ArchiveType.Tar:
{
return TarArchive.Create();
}
default:
{
throw new NotSupportedException("Cannot create Archives of type: " + type);
}
}
}
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
public static IArchive Open(string filePath)
{
return Open(filePath, Options.None);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
public static IArchive Open(FileInfo fileInfo)
{
return Open(fileInfo, Options.None);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
public static IArchive Open(string filePath, Options options)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
public static IArchive Open(FileInfo fileInfo, Options options)
{
fileInfo.CheckNotNull("fileInfo");
using (var stream = fileInfo.OpenRead())
{
if (ZipArchive.IsZipFile(stream, null))
{
stream.Dispose();
return ZipArchive.Open(fileInfo, options, null);
}
stream.Seek(0, SeekOrigin.Begin);
if (RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen))
{
stream.Dispose();
return RarArchive.Open(fileInfo, options);
}
stream.Seek(0, SeekOrigin.Begin);
if (TarArchive.IsTarFile(stream))
{
stream.Dispose();
return TarArchive.Open(fileInfo, options);
}
stream.Seek(0, SeekOrigin.Begin);
if (SevenZipArchive.IsSevenZipFile(stream))
{
stream.Dispose();
return SevenZipArchive.Open(fileInfo, options);
}
stream.Seek(0, SeekOrigin.Begin);
if (GZipArchive.IsGZipFile(stream))
{
stream.Dispose();
return GZipArchive.Open(fileInfo, options);
}
throw new InvalidOperationException("Cannot determine compressed stream type.");
}
}
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public static void WriteToDirectory(string sourceArchive, string destinationDirectory,
ExtractOptions options = ExtractOptions.Overwrite)
{
using (IArchive archive = Open(sourceArchive))
{
foreach (IArchiveEntry entry in archive.Entries)
{
entry.WriteToDirectory(destinationDirectory, options);
}
}
}
#endif
}
}

View File

@@ -0,0 +1,213 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.GZip;
using SharpCompress.Reader;
using SharpCompress.Reader.GZip;
using SharpCompress.Writer.GZip;
namespace SharpCompress.Archive.GZip
{
public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
{
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
public static GZipArchive Open(string filePath)
{
return Open(filePath, Options.None);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
public static GZipArchive Open(FileInfo fileInfo)
{
return Open(fileInfo, Options.None);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
public static GZipArchive Open(string filePath, Options options)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
public static GZipArchive Open(FileInfo fileInfo, Options options)
{
fileInfo.CheckNotNull("fileInfo");
return new GZipArchive(fileInfo, options);
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
public static GZipArchive Open(Stream stream)
{
stream.CheckNotNull("stream");
return Open(stream, Options.None);
}
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
public static GZipArchive Open(Stream stream, Options options)
{
stream.CheckNotNull("stream");
return new GZipArchive(stream, options);
}
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
internal GZipArchive(FileInfo fileInfo, Options options)
: base(ArchiveType.GZip, fileInfo, options)
{
}
protected override IEnumerable<GZipVolume> LoadVolumes(FileInfo file, Options options)
{
return new GZipVolume(file, options).AsEnumerable();
}
public static bool IsGZipFile(string filePath)
{
return IsGZipFile(new FileInfo(filePath));
}
public static bool IsGZipFile(FileInfo fileInfo)
{
if (!fileInfo.Exists)
{
return false;
}
using (Stream stream = fileInfo.OpenRead())
{
return IsGZipFile(stream);
}
}
public void SaveTo(string filePath)
{
SaveTo(new FileInfo(filePath));
}
public void SaveTo(FileInfo fileInfo)
{
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
{
SaveTo(stream);
}
}
#endif
public static bool IsGZipFile(Stream stream)
{
// read the header on the first read
byte[] header = new byte[10];
int n = stream.Read(header, 0, header.Length);
// workitem 8501: handle edge case (decompress empty stream)
if (n == 0)
return false;
if (n != 10)
return false;
if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8)
return false;
return true;
}
/// <summary>
/// Takes multiple seekable Streams for a multi-part archive
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
internal GZipArchive(Stream stream, Options options)
: base(ArchiveType.GZip, stream.AsEnumerable(), options)
{
}
internal GZipArchive()
: base(ArchiveType.GZip)
{
}
public void SaveTo(Stream stream)
{
this.SaveTo(stream, CompressionType.GZip);
}
protected override GZipArchiveEntry CreateEntry(string filePath, Stream source, long size, DateTime? modified,
bool closeStream)
{
if (Entries.Any())
{
throw new InvalidOperationException("Only one entry is allowed in a GZip Archive");
}
return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
}
protected override void SaveTo(Stream stream, CompressionInfo compressionInfo,
IEnumerable<GZipArchiveEntry> oldEntries,
IEnumerable<GZipArchiveEntry> newEntries)
{
if (Entries.Count > 1)
{
throw new InvalidOperationException("Only one entry is allowed in a GZip Archive");
}
using (var writer = new GZipWriter(stream))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
{
using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.FilePath, entryStream, entry.LastModifiedTime);
}
}
}
}
protected override IEnumerable<GZipVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
{
return new GZipVolume(streams.First(), options).AsEnumerable();
}
protected override IEnumerable<GZipArchiveEntry> LoadEntries(IEnumerable<GZipVolume> volumes)
{
Stream stream = volumes.Single().Stream;
yield return new GZipArchiveEntry(this, new GZipFilePart(stream));
}
protected override IReader CreateReaderForSolidExtraction()
{
var stream = Volumes.Single().Stream;
stream.Position = 0;
return GZipReader.Open(stream);
}
}
}

View File

@@ -0,0 +1,41 @@
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.GZip;
namespace SharpCompress.Archive.GZip
{
public class GZipArchiveEntry : GZipEntry, IArchiveEntry
{
private GZipArchive archive;
internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part)
: base(part)
{
this.archive = archive;
}
public virtual Stream OpenEntryStream()
{
return Parts.Single().GetCompressedStream();
}
#region IArchiveEntry Members
public void WriteTo(Stream streamToWriteTo)
{
if (IsEncrypted)
{
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
}
this.Extract(archive, streamToWriteTo);
}
public bool IsComplete
{
get { return true; }
}
#endregion
}
}

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
namespace SharpCompress.Archive.GZip
{
internal class GZipWritableArchiveEntry : GZipArchiveEntry
{
private string path;
private long size;
private DateTime? lastModified;
private bool closeStream;
internal GZipWritableArchiveEntry(GZipArchive archive, Stream stream,
string path, long size, DateTime? lastModified, bool closeStream)
: base(archive, null)
{
this.Stream = stream;
this.path = path;
this.size = size;
this.lastModified = lastModified;
this.closeStream = closeStream;
}
public override uint Crc
{
get { return 0; }
}
public override string FilePath
{
get { return path; }
}
public override long CompressedSize
{
get { return 0; }
}
public override long Size
{
get { return size; }
}
public override DateTime? LastModifiedTime
{
get { return lastModified; }
}
public override DateTime? CreatedTime
{
get { return null; }
}
public override DateTime? LastAccessedTime
{
get { return null; }
}
public override DateTime? ArchivedTime
{
get { return null; }
}
public override bool IsEncrypted
{
get { return false; }
}
public override bool IsDirectory
{
get { return false; }
}
public override bool IsSplit
{
get { return false; }
}
internal override IEnumerable<FilePart> Parts
{
get { throw new NotImplementedException(); }
}
internal Stream Stream { get; private set; }
public override Stream OpenEntryStream()
{
return new NonDisposingStream(Stream);
}
internal override void Close()
{
if (closeStream)
{
Stream.Dispose();
}
}
}
}

View File

@@ -0,0 +1,22 @@
using System.Linq;
using SharpCompress.Common;
namespace SharpCompress.Archive
{
public static class IArchiveExtensions
{
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public static void WriteToDirectory(this IArchive archive, string destinationDirectory,
ExtractOptions options = ExtractOptions.Overwrite)
{
foreach (IArchiveEntry entry in archive.Entries.Where(x => !x.IsDirectory))
{
entry.WriteToDirectory(destinationDirectory, options);
}
}
#endif
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using SharpCompress.Common;
using SharpCompress.Reader;
namespace SharpCompress.Archive
{
public interface IArchive : IDisposable
{
event EventHandler<ArchiveExtractionEventArgs<IArchiveEntry>> EntryExtractionBegin;
event EventHandler<ArchiveExtractionEventArgs<IArchiveEntry>> EntryExtractionEnd;
event EventHandler<CompressedBytesReadEventArgs> CompressedBytesRead;
event EventHandler<FilePartExtractionBeginEventArgs> FilePartExtractionBegin;
IEnumerable<IArchiveEntry> Entries { get; }
long TotalSize { get; }
IEnumerable<IVolume> Volumes { get; }
ArchiveType Type { get; }
/// <summary>
/// Use this method to extract all entries in an archive in order.
/// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be
/// extracted sequentially for the best performance.
/// </summary>
/// <returns></returns>
IReader ExtractAllEntries();
/// <summary>
/// Archive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files).
/// Rar Archives can be SOLID while all 7Zip archives are considered SOLID.
/// </summary>
bool IsSolid { get; }
/// <summary>
/// This checks to see if all the known entries have IsComplete = true
/// </summary>
bool IsComplete { get; }
}
}

View File

@@ -0,0 +1,61 @@
using System.IO;
using SharpCompress.Common;
namespace SharpCompress.Archive
{
public static class IArchiveEntryExtensions
{
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory,
ExtractOptions options = ExtractOptions.Overwrite)
{
string destinationFileName = string.Empty;
string file = Path.GetFileName(entry.FilePath);
if (options.HasFlag(ExtractOptions.ExtractFullPath))
{
string folder = Path.GetDirectoryName(entry.FilePath);
string destdir = Path.Combine(destinationDirectory, folder);
if (!Directory.Exists(destdir))
{
Directory.CreateDirectory(destdir);
}
destinationFileName = Path.Combine(destdir, file);
}
else
{
destinationFileName = Path.Combine(destinationDirectory, file);
}
entry.WriteToFile(destinationFileName, options);
}
/// <summary>
/// Extract to specific file
/// </summary>
public static void WriteToFile(this IArchiveEntry entry, string destinationFileName,
ExtractOptions options = ExtractOptions.Overwrite)
{
if (entry.IsDirectory)
{
return;
}
FileMode fm = FileMode.Create;
if (!options.HasFlag(ExtractOptions.Overwrite))
{
fm = FileMode.CreateNew;
}
using (FileStream fs = File.Open(destinationFileName, fm))
// using (Stream entryStream = entry.OpenEntryStream())
{
//entryStream.TransferTo(fs);
entry.WriteTo(fs);
}
}
#endif
}
}

View File

@@ -0,0 +1,21 @@
using System.IO;
using SharpCompress.Common;
namespace SharpCompress.Archive
{
public interface IArchiveEntry : IEntry
{
/// <summary>
/// Opens the current entry as a stream that will decompress as it is read.
/// Read the entire stream or use SkipEntry on EntryStream.
/// </summary>
Stream OpenEntryStream();
void WriteTo(Stream stream);
/// <summary>
/// The archive can find all the parts of the archive needed to extract this entry.
/// </summary>
bool IsComplete { get; }
}
}

View File

@@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.IO;
namespace SharpCompress.Archive.Rar
{
/// <summary>
/// A rar part based on a FileInfo object
/// </summary>
internal class FileInfoRarArchiveVolume : RarVolume
{
internal FileInfoRarArchiveVolume(FileInfo fileInfo, Options options)
: base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options))
{
FileInfo = fileInfo;
FileParts = base.GetVolumeFileParts().ToReadOnly();
}
private static Options FixOptions(Options options)
{
//make sure we're closing streams with fileinfo
if (options.HasFlag(Options.KeepStreamsOpen))
{
options = (Options) FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
}
return options;
}
internal ReadOnlyCollection<RarFilePart> FileParts { get; private set; }
internal FileInfo FileInfo { get; private set; }
internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader)
{
return new FileInfoRarFilePart(this, markHeader, fileHeader, FileInfo);
}
internal override IEnumerable<RarFilePart> ReadFileParts()
{
return FileParts;
}
public override FileInfo VolumeFile
{
get { return FileInfo; }
}
}
}

View File

@@ -0,0 +1,36 @@
using System.IO;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Archive.Rar
{
internal class FileInfoRarFilePart : RarFilePart
{
private FileInfoRarArchiveVolume volume;
internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, MarkHeader mh, FileHeader fh, FileInfo fi)
: base(mh, fh)
{
this.volume = volume;
FileInfo = fi;
}
internal FileInfo FileInfo { get; private set; }
internal override Stream GetCompressedStream()
{
var stream = volume.Stream;
stream.Position = FileHeader.DataStartPosition;
return stream;
}
internal override string FilePartName
{
get
{
return "Rar File: " + FileInfo.FullName
+ " File Entry: " + FileHeader.FileName;
}
}
}
}

View File

@@ -0,0 +1,31 @@
using System.Linq;
namespace SharpCompress.Archive.Rar
{
public static class RarArchiveExtensions
{
/// <summary>
/// RarArchive is the first volume of a multi-part archive. If MultipartVolume is true and IsFirstVolume is false then the first volume file must be missing.
/// </summary>
public static bool IsFirstVolume(this RarArchive archive)
{
return archive.Volumes.First().IsFirstVolume;
}
/// <summary>
/// RarArchive is part of a multi-part archive.
/// </summary>
public static bool IsMultipartVolume(this RarArchive archive)
{
return archive.Volumes.First().IsMultiVolume;
}
/// <summary>
/// RarArchive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files).
/// </summary>
public static bool IsSolidArchive(this RarArchive archive)
{
return archive.IsSolid;
}
}
}

View File

@@ -0,0 +1,203 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.Compressor.Rar;
using SharpCompress.IO;
using SharpCompress.Reader;
using SharpCompress.Reader.Rar;
namespace SharpCompress.Archive.Rar
{
public class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
{
private readonly Unpack unpack = new Unpack();
internal Unpack Unpack
{
get { return unpack; }
}
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
internal RarArchive(FileInfo fileInfo, Options options)
: base(ArchiveType.Rar, fileInfo, options)
{
}
protected override IEnumerable<RarVolume> LoadVolumes(FileInfo file, Options options)
{
return RarArchiveVolumeFactory.GetParts(file, options);
}
#endif
/// <summary>
/// Takes multiple seekable Streams for a multi-part archive
/// </summary>
/// <param name="streams"></param>
/// <param name="options"></param>
internal RarArchive(IEnumerable<Stream> streams, Options options)
: base(ArchiveType.Rar, streams, options)
{
}
protected override IEnumerable<RarArchiveEntry> LoadEntries(IEnumerable<RarVolume> volumes)
{
return RarArchiveEntryFactory.GetEntries(this, volumes);
}
protected override IEnumerable<RarVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
{
return RarArchiveVolumeFactory.GetParts(streams, options);
}
protected override IReader CreateReaderForSolidExtraction()
{
var stream = Volumes.First().Stream;
stream.Position = 0;
return RarReader.Open(stream);
}
public override bool IsSolid
{
get { return Volumes.First().IsSolidArchive; }
}
#region Creation
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
public static RarArchive Open(string filePath)
{
return Open(filePath, Options.None);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
public static RarArchive Open(FileInfo fileInfo)
{
return Open(fileInfo, Options.None);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
public static RarArchive Open(string filePath, Options options)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
public static RarArchive Open(FileInfo fileInfo, Options options)
{
fileInfo.CheckNotNull("fileInfo");
return new RarArchive(fileInfo, options);
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
public static RarArchive Open(Stream stream)
{
stream.CheckNotNull("stream");
return Open(stream.AsEnumerable());
}
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
public static RarArchive Open(Stream stream, Options options)
{
stream.CheckNotNull("stream");
return Open(stream.AsEnumerable(), options);
}
/// <summary>
/// Takes multiple seekable Streams for a multi-part archive
/// </summary>
/// <param name="streams"></param>
public static RarArchive Open(IEnumerable<Stream> streams)
{
streams.CheckNotNull("streams");
return new RarArchive(streams, Options.KeepStreamsOpen);
}
/// <summary>
/// Takes multiple seekable Streams for a multi-part archive
/// </summary>
/// <param name="streams"></param>
/// <param name="options"></param>
public static RarArchive Open(IEnumerable<Stream> streams, Options options)
{
streams.CheckNotNull("streams");
return new RarArchive(streams, options);
}
#if !PORTABLE && !NETFX_CORE
public static bool IsRarFile(string filePath)
{
return IsRarFile(new FileInfo(filePath));
}
public static bool IsRarFile(FileInfo fileInfo)
{
if (!fileInfo.Exists)
{
return false;
}
using (Stream stream = fileInfo.OpenRead())
{
return IsRarFile(stream);
}
}
#endif
public static bool IsRarFile(Stream stream)
{
return IsRarFile(stream, Options.None);
}
public static bool IsRarFile(Stream stream, Options options)
{
try
{
var headerFactory = new RarHeaderFactory(StreamingMode.Seekable, options);
RarHeader header = headerFactory.ReadHeaders(stream).FirstOrDefault();
if (header == null)
{
return false;
}
return Enum.IsDefined(typeof (HeaderType), header.HeaderType);
}
catch
{
return false;
}
}
#endregion
}
}

View File

@@ -0,0 +1,105 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.Compressor.Rar;
namespace SharpCompress.Archive.Rar
{
public class RarArchiveEntry : RarEntry, IArchiveEntry
{
private readonly ICollection<RarFilePart> parts;
internal RarArchiveEntry(RarArchive archive, IEnumerable<RarFilePart> parts)
{
this.parts = parts.ToList();
Archive = archive;
}
public override CompressionType CompressionType
{
get { return CompressionType.Rar; }
}
private RarArchive Archive { get; set; }
internal override IEnumerable<FilePart> Parts
{
get { return parts.Cast<FilePart>(); }
}
internal override FileHeader FileHeader
{
get { return parts.First().FileHeader; }
}
public override uint Crc
{
get
{
CheckIncomplete();
return parts.Select(fp => fp.FileHeader)
.Where(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER))
.Single().FileCRC;
}
}
public override long Size
{
get
{
CheckIncomplete();
return parts.First().FileHeader.UncompressedSize;
}
}
public override long CompressedSize
{
get
{
CheckIncomplete();
return parts.Aggregate(0L, (total, fp) => { return total + fp.FileHeader.CompressedSize; });
}
}
public Stream OpenEntryStream()
{
return new RarStream(Archive.Unpack, FileHeader,
new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>(), Archive));
}
public void WriteTo(Stream streamToWriteTo)
{
CheckIncomplete();
if (Archive.IsSolidArchive())
{
throw new InvalidFormatException("Cannot use Archive random access on SOLID Rar files.");
}
if (IsEncrypted)
{
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
}
this.Extract(Archive, streamToWriteTo);
}
public bool IsComplete
{
get { return parts.Select(fp => fp.FileHeader).Any(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)); }
}
private void CheckIncomplete()
{
if (!IsComplete)
{
throw new IncompleteArchiveException("ArchiveEntry is incomplete and cannot perform this operation.");
}
}
internal override void Close()
{
}
}
}

View File

@@ -0,0 +1,49 @@
using System.Collections.Generic;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Archive.Rar
{
internal static class RarArchiveEntryFactory
{
private static IEnumerable<RarFilePart> GetFileParts(IEnumerable<RarVolume> parts)
{
foreach (RarVolume rarPart in parts)
{
foreach (RarFilePart fp in rarPart.ReadFileParts())
{
yield return fp;
}
}
}
private static IEnumerable<IEnumerable<RarFilePart>> GetMatchedFileParts(IEnumerable<RarVolume> parts)
{
var groupedParts = new List<RarFilePart>();
foreach (RarFilePart fp in GetFileParts(parts))
{
groupedParts.Add(fp);
if (!FlagUtility.HasFlag((long) fp.FileHeader.FileFlags, (long) FileFlags.SPLIT_AFTER))
{
yield return groupedParts;
groupedParts = new List<RarFilePart>();
}
}
if (groupedParts.Count > 0)
{
yield return groupedParts;
}
}
internal static IEnumerable<RarArchiveEntry> GetEntries(RarArchive archive,
IEnumerable<RarVolume> rarParts)
{
foreach (var groupedParts in GetMatchedFileParts(rarParts))
{
yield return new RarArchiveEntry(archive, groupedParts);
}
}
}
}

View File

@@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.IO;
#if !PORTABLE
using System.Linq;
using System.Text;
using SharpCompress.Common.Rar.Headers;
#endif
using SharpCompress.Common;
using SharpCompress.Common.Rar;
namespace SharpCompress.Archive.Rar
{
internal static class RarArchiveVolumeFactory
{
internal static IEnumerable<RarVolume> GetParts(IEnumerable<Stream> streams, Options options)
{
foreach (Stream s in streams)
{
if (!s.CanRead || !s.CanSeek)
{
throw new ArgumentException("Stream is not readable and seekable");
}
StreamRarArchiveVolume part = new StreamRarArchiveVolume(s, options);
yield return part;
}
}
#if !PORTABLE && !NETFX_CORE
internal static IEnumerable<RarVolume> GetParts(FileInfo fileInfo, Options options)
{
FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, options);
yield return part;
if (!part.ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.VOLUME))
{
yield break; //if file isn't volume then there is no reason to look
}
ArchiveHeader ah = part.ArchiveHeader;
fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart);
//we use fileinfo because rar is dumb and looks at file names rather than archive info for another volume
while (fileInfo != null && fileInfo.Exists)
{
part = new FileInfoRarArchiveVolume(fileInfo, options);
fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart);
yield return part;
}
}
private static FileInfo GetNextFileInfo(ArchiveHeader ah, FileInfoRarFilePart currentFilePart)
{
if (currentFilePart == null)
{
return null;
}
bool oldNumbering = !ah.ArchiveHeaderFlags.HasFlag(ArchiveFlags.NEWNUMBERING)
|| currentFilePart.MarkHeader.OldFormat;
if (oldNumbering)
{
return FindNextFileWithOldNumbering(currentFilePart.FileInfo);
}
else
{
return FindNextFileWithNewNumbering(currentFilePart.FileInfo);
}
}
private static FileInfo FindNextFileWithOldNumbering(FileInfo currentFileInfo)
{
// .rar, .r00, .r01, ...
string extension = currentFileInfo.Extension;
StringBuilder buffer = new StringBuilder(currentFileInfo.FullName.Length);
buffer.Append(currentFileInfo.FullName.Substring(0,
currentFileInfo.FullName.Length - extension.Length));
if (string.Compare(extension, ".rar", StringComparison.InvariantCultureIgnoreCase) == 0)
{
buffer.Append(".r00");
}
else
{
int num = 0;
if (int.TryParse(extension.Substring(2, 2), out num))
{
num++;
buffer.Append(".r");
if (num < 10)
{
buffer.Append('0');
}
buffer.Append(num);
}
else
{
ThrowInvalidFileName(currentFileInfo);
}
}
return new FileInfo(buffer.ToString());
}
private static FileInfo FindNextFileWithNewNumbering(FileInfo currentFileInfo)
{
// part1.rar, part2.rar, ...
string extension = currentFileInfo.Extension;
if (string.Compare(extension, ".rar", StringComparison.InvariantCultureIgnoreCase) != 0)
{
throw new ArgumentException("Invalid extension, expected 'rar': " + currentFileInfo.FullName);
}
int startIndex = currentFileInfo.FullName.LastIndexOf(".part");
if (startIndex < 0)
{
ThrowInvalidFileName(currentFileInfo);
}
StringBuilder buffer = new StringBuilder(currentFileInfo.FullName.Length);
buffer.Append(currentFileInfo.FullName, 0, startIndex);
int num = 0;
string numString = currentFileInfo.FullName.Substring(startIndex + 5,
currentFileInfo.FullName.IndexOf('.', startIndex + 5) -
startIndex - 5);
buffer.Append(".part");
if (int.TryParse(numString, out num))
{
num++;
for (int i = 0; i < numString.Length - num.ToString().Length; i++)
{
buffer.Append('0');
}
buffer.Append(num);
}
else
{
ThrowInvalidFileName(currentFileInfo);
}
buffer.Append(".rar");
return new FileInfo(buffer.ToString());
}
private static void ThrowInvalidFileName(FileInfo fileInfo)
{
throw new ArgumentException("Filename invalid or next archive could not be found:"
+ fileInfo.FullName);
}
#endif
}
}

View File

@@ -0,0 +1,28 @@
using System.IO;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Archive.Rar
{
internal class SeekableStreamFilePart : RarFilePart
{
internal SeekableStreamFilePart(MarkHeader mh, FileHeader fh, Stream stream)
: base(mh, fh)
{
Stream = stream;
}
internal Stream Stream { get; private set; }
internal override Stream GetCompressedStream()
{
Stream.Position = FileHeader.DataStartPosition;
return Stream;
}
internal override string FilePartName
{
get { return "Unknown Stream - File Entry: " + base.FileHeader.FileName; }
}
}
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
using SharpCompress.IO;
namespace SharpCompress.Archive.Rar
{
internal class StreamRarArchiveVolume : RarVolume
{
internal StreamRarArchiveVolume(Stream stream, Options options)
: base(StreamingMode.Seekable, stream, options)
{
}
#if !PORTABLE && !NETFX_CORE
public override FileInfo VolumeFile
{
get { return null; }
}
#endif
internal override IEnumerable<RarFilePart> ReadFileParts()
{
return GetVolumeFileParts();
}
internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader)
{
return new SeekableStreamFilePart(markHeader, fileHeader, Stream);
}
}
}

View File

@@ -0,0 +1,239 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.SevenZip;
using SharpCompress.IO;
using SharpCompress.Reader;
namespace SharpCompress.Archive.SevenZip
{
public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVolume>
{
private ArchiveDatabase database;
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
public static SevenZipArchive Open(string filePath)
{
return Open(filePath, Options.None);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
public static SevenZipArchive Open(FileInfo fileInfo)
{
return Open(fileInfo, Options.None);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
public static SevenZipArchive Open(string filePath, Options options)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
public static SevenZipArchive Open(FileInfo fileInfo, Options options)
{
fileInfo.CheckNotNull("fileInfo");
return new SevenZipArchive(fileInfo, options);
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
public static SevenZipArchive Open(Stream stream)
{
stream.CheckNotNull("stream");
return Open(stream, Options.None);
}
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
public static SevenZipArchive Open(Stream stream, Options options)
{
stream.CheckNotNull("stream");
return new SevenZipArchive(stream, options);
}
#if !PORTABLE && !NETFX_CORE
internal SevenZipArchive(FileInfo fileInfo, Options options)
: base(ArchiveType.SevenZip, fileInfo, options)
{
}
protected override IEnumerable<SevenZipVolume> LoadVolumes(FileInfo file, Options options)
{
return new SevenZipVolume(file, options).AsEnumerable();
}
public static bool IsSevenZipFile(string filePath)
{
return IsSevenZipFile(new FileInfo(filePath));
}
public static bool IsSevenZipFile(FileInfo fileInfo)
{
if (!fileInfo.Exists)
{
return false;
}
using (Stream stream = fileInfo.OpenRead())
{
return IsSevenZipFile(stream);
}
}
#endif
internal SevenZipArchive(Stream stream, Options options)
: base(ArchiveType.SevenZip, stream.AsEnumerable(), options)
{
}
internal SevenZipArchive()
: base(ArchiveType.SevenZip)
{
}
protected override IEnumerable<SevenZipVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
{
foreach (Stream s in streams)
{
if (!s.CanRead || !s.CanSeek)
{
throw new ArgumentException("Stream is not readable and seekable");
}
SevenZipVolume volume = new SevenZipVolume(s, options);
yield return volume;
}
}
protected override IEnumerable<SevenZipArchiveEntry> LoadEntries(IEnumerable<SevenZipVolume> volumes)
{
var stream = volumes.Single().Stream;
LoadFactory(stream);
for (int i = 0; i < database.Files.Count; i++)
{
var file = database.Files[i];
if (!file.IsDir)
{
yield return new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file));
}
}
}
private void LoadFactory(Stream stream)
{
if (database == null)
{
stream.Position = 0;
var reader = new ArchiveReader();
reader.Open(stream);
database = reader.ReadDatabase(null);
}
}
public static bool IsSevenZipFile(Stream stream)
{
try
{
return SignatureMatch(stream);
}
catch
{
return false;
}
}
private static readonly byte[] SIGNATURE = new byte[] {(byte) '7', (byte) 'z', 0xBC, 0xAF, 0x27, 0x1C};
private static bool SignatureMatch(Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
byte[] signatureBytes = reader.ReadBytes(6);
return signatureBytes.BinaryEquals(SIGNATURE);
}
protected override IReader CreateReaderForSolidExtraction()
{
return new SevenZipReader(this);
}
public override bool IsSolid
{
get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; }
}
private class SevenZipReader : AbstractReader<SevenZipEntry, SevenZipVolume>
{
private readonly SevenZipArchive archive;
private CFolder currentFolder;
private Stream currentStream;
private CFileItem currentItem;
internal SevenZipReader(SevenZipArchive archive)
: base(Options.KeepStreamsOpen, ArchiveType.SevenZip)
{
this.archive = archive;
}
public override SevenZipVolume Volume
{
get { return archive.Volumes.Single(); }
}
internal override IEnumerable<SevenZipEntry> GetEntries(Stream stream)
{
List<SevenZipArchiveEntry> entries = archive.Entries.ToList();
stream.Position = 0;
foreach (var dir in entries.Where(x => x.IsDirectory))
{
yield return dir;
}
foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder))
{
currentFolder = group.Key;
if (group.Key == null)
{
currentStream = Stream.Null;
}
else
{
currentStream = archive.database.GetFolderStream(stream, currentFolder, null);
}
foreach (var entry in group)
{
currentItem = entry.FilePart.Header;
yield return entry;
}
}
}
protected override EntryStream GetEntryStream()
{
return new EntryStream(new ReadOnlySubStream(currentStream, currentItem.Size));
}
}
}
}

View File

@@ -0,0 +1,44 @@
using System.IO;
using SharpCompress.Common;
using SharpCompress.Common.SevenZip;
namespace SharpCompress.Archive.SevenZip
{
public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry
{
private SevenZipArchive archive;
internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part)
: base(part)
{
this.archive = archive;
}
public Stream OpenEntryStream()
{
return FilePart.GetCompressedStream();
}
public void WriteTo(Stream stream)
{
if (IsEncrypted)
{
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
}
this.Extract(archive, stream);
}
public bool IsComplete
{
get { return true; }
}
/// <summary>
/// This is a 7Zip Anti item
/// </summary>
public bool IsAnti
{
get { return FilePart.Header.IsAnti; }
}
}
}

View File

@@ -0,0 +1,217 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Tar;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
using SharpCompress.Reader;
using SharpCompress.Reader.Tar;
using SharpCompress.Writer.Tar;
namespace SharpCompress.Archive.Tar
{
public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
{
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
public static TarArchive Open(string filePath)
{
return Open(filePath, Options.None);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
public static TarArchive Open(FileInfo fileInfo)
{
return Open(fileInfo, Options.None);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
public static TarArchive Open(string filePath, Options options)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
public static TarArchive Open(FileInfo fileInfo, Options options)
{
fileInfo.CheckNotNull("fileInfo");
return new TarArchive(fileInfo, options);
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
public static TarArchive Open(Stream stream)
{
stream.CheckNotNull("stream");
return Open(stream, Options.None);
}
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
public static TarArchive Open(Stream stream, Options options)
{
stream.CheckNotNull("stream");
return new TarArchive(stream, options);
}
#if !PORTABLE && !NETFX_CORE
public static bool IsTarFile(string filePath)
{
return IsTarFile(new FileInfo(filePath));
}
public static bool IsTarFile(FileInfo fileInfo)
{
if (!fileInfo.Exists)
{
return false;
}
using (Stream stream = fileInfo.OpenRead())
{
return IsTarFile(stream);
}
}
#endif
public static bool IsTarFile(Stream stream)
{
try
{
TarHeader tar = new TarHeader();
tar.Read(new BinaryReader(stream));
return tar.Name.Length > 0 && Enum.IsDefined(typeof (EntryType), tar.EntryType);
}
catch
{
}
return false;
}
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
internal TarArchive(FileInfo fileInfo, Options options)
: base(ArchiveType.Tar, fileInfo, options)
{
}
protected override IEnumerable<TarVolume> LoadVolumes(FileInfo file, Options options)
{
return new TarVolume(file, options).AsEnumerable();
}
#endif
/// <summary>
/// Takes multiple seekable Streams for a multi-part archive
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
internal TarArchive(Stream stream, Options options)
: base(ArchiveType.Tar, stream.AsEnumerable(), options)
{
}
internal TarArchive()
: base(ArchiveType.Tar)
{
}
protected override IEnumerable<TarVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
{
return new TarVolume(streams.First(), options).AsEnumerable();
}
protected override IEnumerable<TarArchiveEntry> LoadEntries(IEnumerable<TarVolume> volumes)
{
Stream stream = volumes.Single().Stream;
TarHeader previousHeader = null;
foreach (TarHeader header in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream))
{
if (header != null)
{
if (header.EntryType == EntryType.LongName)
{
previousHeader = header;
}
else
{
if (previousHeader != null)
{
var entry = new TarArchiveEntry(this, new TarFilePart(previousHeader, stream),
CompressionType.None);
var memoryStream = new MemoryStream();
entry.WriteTo(memoryStream);
memoryStream.Position = 0;
var bytes = memoryStream.ToArray();
header.Name = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length).TrimNulls();
previousHeader = null;
}
yield return new TarArchiveEntry(this, new TarFilePart(header, stream), CompressionType.None);
}
}
}
}
public static TarArchive Create()
{
return new TarArchive();
}
protected override TarArchiveEntry CreateEntry(string filePath, Stream source,
long size, DateTime? modified, bool closeStream)
{
return new TarWritableArchiveEntry(this, source, CompressionType.Unknown, filePath, size, modified,
closeStream);
}
protected override void SaveTo(Stream stream, CompressionInfo compressionInfo,
IEnumerable<TarArchiveEntry> oldEntries,
IEnumerable<TarArchiveEntry> newEntries)
{
using (var writer = new TarWriter(stream, compressionInfo))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
{
using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.FilePath, entryStream, entry.LastModifiedTime, entry.Size);
}
}
}
}
protected override IReader CreateReaderForSolidExtraction()
{
var stream = Volumes.Single().Stream;
stream.Position = 0;
return TarReader.Open(stream);
}
}
}

View File

@@ -0,0 +1,41 @@
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Tar;
namespace SharpCompress.Archive.Tar
{
public class TarArchiveEntry : TarEntry, IArchiveEntry
{
private TarArchive archive;
internal TarArchiveEntry(TarArchive archive, TarFilePart part, CompressionType compressionType)
: base(part, compressionType)
{
this.archive = archive;
}
public virtual Stream OpenEntryStream()
{
return Parts.Single().GetCompressedStream();
}
#region IArchiveEntry Members
public void WriteTo(Stream streamToWriteTo)
{
if (IsEncrypted)
{
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
}
this.Extract(archive, streamToWriteTo);
}
public bool IsComplete
{
get { return true; }
}
#endregion
}
}

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
namespace SharpCompress.Archive.Tar
{
internal class TarWritableArchiveEntry : TarArchiveEntry
{
private string path;
private long size;
private DateTime? lastModified;
private bool closeStream;
internal TarWritableArchiveEntry(TarArchive archive, Stream stream, CompressionType compressionType,
string path, long size, DateTime? lastModified, bool closeStream)
: base(archive, null, compressionType)
{
this.Stream = stream;
this.path = path;
this.size = size;
this.lastModified = lastModified;
this.closeStream = closeStream;
}
public override uint Crc
{
get { return 0; }
}
public override string FilePath
{
get { return path; }
}
public override long CompressedSize
{
get { return 0; }
}
public override long Size
{
get { return size; }
}
public override DateTime? LastModifiedTime
{
get { return lastModified; }
}
public override DateTime? CreatedTime
{
get { return null; }
}
public override DateTime? LastAccessedTime
{
get { return null; }
}
public override DateTime? ArchivedTime
{
get { return null; }
}
public override bool IsEncrypted
{
get { return false; }
}
public override bool IsDirectory
{
get { return false; }
}
public override bool IsSplit
{
get { return false; }
}
internal override IEnumerable<FilePart> Parts
{
get { throw new NotImplementedException(); }
}
internal Stream Stream { get; private set; }
public override Stream OpenEntryStream()
{
return new NonDisposingStream(Stream);
}
internal override void Close()
{
if (closeStream)
{
Stream.Dispose();
}
}
}
}

View File

@@ -0,0 +1,241 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common;
using SharpCompress.Common.Zip;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.Compressor.Deflate;
using SharpCompress.Reader;
using SharpCompress.Reader.Zip;
using SharpCompress.Writer.Zip;
namespace SharpCompress.Archive.Zip
{
public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
{
private SeekableZipHeaderFactory headerFactory;
/// <summary>
/// Gets or sets the compression level applied to files added to the archive,
/// if the compression method is set to deflate
/// </summary>
public CompressionLevel DeflateCompressionLevel { get; set; }
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="password"></param>
public static ZipArchive Open(string filePath, string password = null)
{
return Open(filePath, Options.None, password);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="password"></param>
public static ZipArchive Open(FileInfo fileInfo, string password = null)
{
return Open(fileInfo, Options.None, password);
}
/// <summary>
/// Constructor expects a filepath to an existing file.
/// </summary>
/// <param name="filePath"></param>
/// <param name="options"></param>
/// <param name="password"></param>
public static ZipArchive Open(string filePath, Options options, string password = null)
{
filePath.CheckNotNullOrEmpty("filePath");
return Open(new FileInfo(filePath), options, password);
}
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
/// <param name="password"></param>
public static ZipArchive Open(FileInfo fileInfo, Options options, string password = null)
{
fileInfo.CheckNotNull("fileInfo");
return new ZipArchive(fileInfo, options, password);
}
#endif
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="password"></param>
public static ZipArchive Open(Stream stream, string password = null)
{
stream.CheckNotNull("stream");
return Open(stream, Options.None, password);
}
/// <summary>
/// Takes a seekable Stream as a source
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
/// <param name="password"></param>
public static ZipArchive Open(Stream stream, Options options, string password = null)
{
stream.CheckNotNull("stream");
return new ZipArchive(stream, options, password);
}
#if !PORTABLE && !NETFX_CORE
public static bool IsZipFile(string filePath, string password = null)
{
return IsZipFile(new FileInfo(filePath), password);
}
public static bool IsZipFile(FileInfo fileInfo, string password = null)
{
if (!fileInfo.Exists)
{
return false;
}
using (Stream stream = fileInfo.OpenRead())
{
return IsZipFile(stream, password);
}
}
#endif
public static bool IsZipFile(Stream stream, string password = null)
{
StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password);
try
{
ZipHeader header =
headerFactory.ReadStreamHeader(stream).FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split);
if (header == null)
{
return false;
}
return Enum.IsDefined(typeof (ZipHeaderType), header.ZipHeaderType);
}
catch (CryptographicException)
{
return true;
}
catch
{
return false;
}
}
#if !PORTABLE && !NETFX_CORE
/// <summary>
/// Constructor with a FileInfo object to an existing file.
/// </summary>
/// <param name="fileInfo"></param>
/// <param name="options"></param>
/// <param name="password"></param>
internal ZipArchive(FileInfo fileInfo, Options options, string password = null)
: base(ArchiveType.Zip, fileInfo, options)
{
headerFactory = new SeekableZipHeaderFactory(password);
}
protected override IEnumerable<ZipVolume> LoadVolumes(FileInfo file, Options options)
{
return new ZipVolume(file, options).AsEnumerable();
}
#endif
internal ZipArchive()
: base(ArchiveType.Zip)
{
}
/// <summary>
/// Takes multiple seekable Streams for a multi-part archive
/// </summary>
/// <param name="stream"></param>
/// <param name="options"></param>
/// <param name="password"></param>
internal ZipArchive(Stream stream, Options options, string password = null)
: base(ArchiveType.Zip, stream.AsEnumerable(), options)
{
headerFactory = new SeekableZipHeaderFactory(password);
}
protected override IEnumerable<ZipVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
{
return new ZipVolume(streams.First(), options).AsEnumerable();
}
protected override IEnumerable<ZipArchiveEntry> LoadEntries(IEnumerable<ZipVolume> volumes)
{
var volume = volumes.Single();
Stream stream = volumes.Single().Stream;
foreach (ZipHeader h in headerFactory.ReadSeekableHeader(stream))
{
if (h != null)
{
switch (h.ZipHeaderType)
{
case ZipHeaderType.DirectoryEntry:
{
yield return new ZipArchiveEntry(this,
new SeekableZipFilePart(headerFactory,
h as DirectoryEntryHeader,
stream));
}
break;
case ZipHeaderType.DirectoryEnd:
{
byte[] bytes = (h as DirectoryEndHeader).Comment;
volume.Comment = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length);
yield break;
}
}
}
}
}
protected override void SaveTo(Stream stream, CompressionInfo compressionInfo,
IEnumerable<ZipArchiveEntry> oldEntries,
IEnumerable<ZipArchiveEntry> newEntries)
{
using (var writer = new ZipWriter(stream, compressionInfo, string.Empty))
{
foreach (var entry in oldEntries.Concat(newEntries)
.Where(x => !x.IsDirectory))
{
using (var entryStream = entry.OpenEntryStream())
{
writer.Write(entry.FilePath, entryStream, entry.LastModifiedTime, string.Empty);
}
}
}
}
protected override ZipArchiveEntry CreateEntry(string filePath, Stream source, long size, DateTime? modified,
bool closeStream)
{
return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
}
public static ZipArchive Create()
{
return new ZipArchive();
}
protected override IReader CreateReaderForSolidExtraction()
{
var stream = Volumes.Single().Stream;
stream.Position = 0;
return ZipReader.Open(stream);
}
}
}

View File

@@ -0,0 +1,41 @@
using System.IO;
using System.Linq;
using SharpCompress.Common.Zip;
namespace SharpCompress.Archive.Zip
{
public class ZipArchiveEntry : ZipEntry, IArchiveEntry
{
private ZipArchive archive;
internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart part)
: base(part)
{
this.archive = archive;
}
public virtual Stream OpenEntryStream()
{
return Parts.Single().GetCompressedStream();
}
#region IArchiveEntry Members
public void WriteTo(Stream streamToWriteTo)
{
this.Extract(archive, streamToWriteTo);
}
public bool IsComplete
{
get { return true; }
}
#endregion
public string Comment
{
get { return (Parts.Single() as SeekableZipFilePart).Comment; }
}
}
}

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
namespace SharpCompress.Archive.Zip
{
internal class ZipWritableArchiveEntry : ZipArchiveEntry
{
private string path;
private long size;
private DateTime? lastModified;
private bool closeStream;
internal ZipWritableArchiveEntry(ZipArchive archive, Stream stream, string path, long size,
DateTime? lastModified, bool closeStream)
: base(archive, null)
{
this.Stream = stream;
this.path = path;
this.size = size;
this.lastModified = lastModified;
this.closeStream = closeStream;
}
public override uint Crc
{
get { return 0; }
}
public override string FilePath
{
get { return path; }
}
public override long CompressedSize
{
get { return 0; }
}
public override long Size
{
get { return size; }
}
public override DateTime? LastModifiedTime
{
get { return lastModified; }
}
public override DateTime? CreatedTime
{
get { return null; }
}
public override DateTime? LastAccessedTime
{
get { return null; }
}
public override DateTime? ArchivedTime
{
get { return null; }
}
public override bool IsEncrypted
{
get { return false; }
}
public override bool IsDirectory
{
get { return false; }
}
public override bool IsSplit
{
get { return false; }
}
internal override IEnumerable<FilePart> Parts
{
get { throw new NotImplementedException(); }
}
internal Stream Stream { get; private set; }
public override Stream OpenEntryStream()
{
return new NonDisposingStream(Stream);
}
internal override void Close()
{
if (closeStream)
{
Stream.Dispose();
}
}
}
}

View File

@@ -0,0 +1,11 @@
namespace SharpCompress
{
public enum ArchiveType
{
Rar,
Zip,
Tar,
SevenZip,
GZip,
}
}

View File

@@ -0,0 +1,20 @@
using System.Reflection;
using System.Runtime.CompilerServices;
#if SILVERLIGHT
[assembly: AssemblyTitle("SharpCompress.Silverlight")]
[assembly: AssemblyProduct("SharpCompress.Silverlight")]
#else
#if PORTABLE
[assembly: AssemblyTitle("SharpCompress.Silverlight")]
[assembly: AssemblyProduct("SharpCompress.Silverlight")]
#else
[assembly: AssemblyTitle("SharpCompress")]
[assembly: AssemblyProduct("SharpCompress")]
[assembly:
InternalsVisibleTo(
"SharpCompress.Test, PublicKey=002400000480000094000000060200000024000052534131000400000100010005d6ae1b0f6875393da83c920a5b9408f5191aaf4e8b3c2c476ad2a11f5041ecae84ce9298bc4c203637e2fd3a80ad5378a9fa8da1363e98cea45c73969198a4b64510927c910001491cebbadf597b22448ad103b0a4007e339faf8fe8665dcdb70d65b27ac05b1977c0655fad06b372b820ecbdccf10a0f214fee0986dfeded"
)]
#endif
#endif

View File

@@ -0,0 +1,29 @@
using System.Globalization;
using System.Text;
namespace SharpCompress.Common
{
public class ArchiveEncoding
{
/// <summary>
/// Default encoding to use when archive format doesn't specify one.
/// </summary>
public static Encoding Default;
/// <summary>
/// Encoding used by encryption schemes which don't comply with RFC 2898.
/// </summary>
public static Encoding Password;
static ArchiveEncoding()
{
#if PORTABLE || NETFX_CORE
Default = Encoding.UTF8;
Password = Encoding.UTF8;
#else
Default = Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage);
Password = Encoding.Default;
#endif
}
}
}

View File

@@ -0,0 +1,12 @@
using System;
namespace SharpCompress.Common
{
public class ArchiveException : Exception
{
public ArchiveException(string message)
: base(message)
{
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
namespace SharpCompress.Common
{
public class ArchiveExtractionEventArgs<T> : EventArgs
{
internal ArchiveExtractionEventArgs(T entry)
{
Item = entry;
}
public T Item { get; private set; }
}
}

View File

@@ -0,0 +1,11 @@
namespace SharpCompress.Common
{
public enum ArchiveType
{
Rar,
Zip,
Tar,
SevenZip,
GZip,
}
}

View File

@@ -0,0 +1,17 @@
using System;
namespace SharpCompress.Common
{
public class CompressedBytesReadEventArgs : EventArgs
{
/// <summary>
/// Compressed bytes read for the current entry
/// </summary>
public long CompressedBytesRead { get; internal set; }
/// <summary>
/// Current file part read for Multipart files (e.g. Rar)
/// </summary>
public long CurrentFilePartCompressedBytesRead { get; internal set; }
}
}

View File

@@ -0,0 +1,30 @@
using SharpCompress.Compressor.Deflate;
namespace SharpCompress.Common
{
/// <summary>
/// Detailed compression properties when saving.
/// </summary>
public class CompressionInfo
{
public CompressionInfo()
{
DeflateCompressionLevel = CompressionLevel.Default;
}
/// <summary>
/// The algorthm to use. Must be valid for the format type.
/// </summary>
public CompressionType Type { get; set; }
/// <summary>
/// When CompressionType.Deflate is used, this property is referenced. Defaults to CompressionLevel.Default.
/// </summary>
public CompressionLevel DeflateCompressionLevel { get; set; }
public static implicit operator CompressionInfo(CompressionType compressionType)
{
return new CompressionInfo() {Type = compressionType};
}
}
}

View File

@@ -0,0 +1,16 @@
namespace SharpCompress.Common
{
public enum CompressionType
{
None,
GZip,
BZip2,
PPMd,
Deflate,
Rar,
LZMA,
BCJ,
BCJ2,
Unknown,
}
}

View File

@@ -0,0 +1,12 @@
using System;
namespace SharpCompress.Common
{
public class CryptographicException : Exception
{
public CryptographicException(string message)
: base(message)
{
}
}
}

View File

@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
namespace SharpCompress.Common
{
public abstract class Entry : SharpCompress.Common.IEntry
{
internal bool IsSolid { get; set; }
/// <summary>
/// The File's 32 bit CRC Hash
/// </summary>
public abstract uint Crc { get; }
/// <summary>
/// The path of the file internal to the Rar Archive.
/// </summary>
public abstract string FilePath { get; }
/// <summary>
/// The compressed file size
/// </summary>
public abstract long CompressedSize { get; }
/// <summary>
/// The compression type
/// </summary>
public abstract CompressionType CompressionType { get; }
/// <summary>
/// The uncompressed file size
/// </summary>
public abstract long Size { get; }
/// <summary>
/// The entry last modified time in the archive, if recorded
/// </summary>
public abstract DateTime? LastModifiedTime { get; }
/// <summary>
/// The entry create time in the archive, if recorded
/// </summary>
public abstract DateTime? CreatedTime { get; }
/// <summary>
/// The entry last accessed time in the archive, if recorded
/// </summary>
public abstract DateTime? LastAccessedTime { get; }
/// <summary>
/// The entry time whend archived, if recorded
/// </summary>
public abstract DateTime? ArchivedTime { get; }
/// <summary>
/// Entry is password protected and encrypted and cannot be extracted.
/// </summary>
public abstract bool IsEncrypted { get; }
/// <summary>
/// Entry is password protected and encrypted and cannot be extracted.
/// </summary>
public abstract bool IsDirectory { get; }
public abstract bool IsSplit { get; }
internal abstract IEnumerable<FilePart> Parts { get; }
internal abstract void Close();
}
}

View File

@@ -0,0 +1,95 @@
using System;
using System.IO;
namespace SharpCompress.Common
{
public class EntryStream : Stream
{
private Stream stream;
private bool completed;
internal EntryStream(Stream stream)
{
this.stream = stream;
}
/// <summary>
/// When reading a stream from OpenEntryStream, the stream must be completed so use this to finish reading the entire entry.
/// </summary>
public void SkipEntry()
{
var buffer = new byte[4096];
while (Read(buffer, 0, buffer.Length) > 0)
{
}
completed = true;
}
protected override void Dispose(bool disposing)
{
if (!completed)
{
throw new InvalidOperationException(
"EntryStream has not been fully consumed. Read the entire stream or use SkipEntry.");
}
base.Dispose(disposing);
stream.Dispose();
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override void Flush()
{
throw new System.NotImplementedException();
}
public override long Length
{
get { throw new System.NotImplementedException(); }
}
public override long Position
{
get { throw new System.NotImplementedException(); }
set { throw new System.NotImplementedException(); }
}
public override int Read(byte[] buffer, int offset, int count)
{
int read = stream.Read(buffer, offset, count);
if (read <= 0)
{
completed = true;
}
return read;
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new System.NotImplementedException();
}
public override void SetLength(long value)
{
throw new System.NotImplementedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new System.NotImplementedException();
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
namespace SharpCompress.Common
{
[Flags]
public enum ExtractOptions
{
None,
/// <summary>
/// overwrite target if it exists
/// </summary>
Overwrite,
/// <summary>
/// extract with internal directory structure
/// </summary>
ExtractFullPath,
}
}

View File

@@ -0,0 +1,17 @@
using System;
namespace SharpCompress.Common
{
public class ExtractionException : Exception
{
public ExtractionException(string message)
: base(message)
{
}
public ExtractionException(string message, Exception inner)
: base(message, inner)
{
}
}
}

View File

@@ -0,0 +1,12 @@
using System.IO;
namespace SharpCompress.Common
{
public abstract class FilePart
{
internal abstract string FilePartName { get; }
internal abstract Stream GetCompressedStream();
internal abstract Stream GetRawStream();
}
}

View File

@@ -0,0 +1,22 @@
using System;
namespace SharpCompress.Common
{
public class FilePartExtractionBeginEventArgs : EventArgs
{
/// <summary>
/// File name for the part for the current entry
/// </summary>
public string Name { get; internal set; }
/// <summary>
/// Uncompressed size of the current entry in the part
/// </summary>
public long Size { get; internal set; }
/// <summary>
/// Compressed size of the current entry in the part
/// </summary>
public long CompressedSize { get; internal set; }
}
}

View File

@@ -0,0 +1,130 @@
using System;
namespace SharpCompress.Common
{
internal static class FlagUtility
{
/// <summary>
/// Returns true if the flag is set on the specified bit field.
/// Currently only works with 32-bit bitfields.
/// </summary>
/// <typeparam name="T">Enumeration with Flags attribute</typeparam>
/// <param name="bitField">Flagged variable</param>
/// <param name="flag">Flag to test</param>
/// <returns></returns>
public static bool HasFlag<T>(long bitField, T flag)
where T : struct
{
return HasFlag(bitField, flag);
}
/// <summary>
/// Returns true if the flag is set on the specified bit field.
/// Currently only works with 32-bit bitfields.
/// </summary>
/// <typeparam name="T">Enumeration with Flags attribute</typeparam>
/// <param name="bitField">Flagged variable</param>
/// <param name="flag">Flag to test</param>
/// <returns></returns>
public static bool HasFlag<T>(ulong bitField, T flag)
where T : struct
{
return HasFlag(bitField, flag);
}
/// <summary>
/// Returns true if the flag is set on the specified bit field.
/// Currently only works with 32-bit bitfields.
/// </summary>
/// <param name="bitField">Flagged variable</param>
/// <param name="flag">Flag to test</param>
/// <returns></returns>
public static bool HasFlag(ulong bitField, ulong flag)
{
return ((bitField & flag) == flag);
}
public static bool HasFlag(short bitField, short flag)
{
return ((bitField & flag) == flag);
}
#if PORTABLE
/// <summary>
/// Generically checks enums in a Windows Phone 7 enivronment
/// </summary>
/// <param name="enumVal"></param>
/// <param name="flag"></param>
/// <returns></returns>
public static bool HasFlag(this Enum enumVal, Enum flag)
{
if (enumVal.GetHashCode() > 0) //GetHashCode returns the enum value. But it's something very crazy if not set beforehand
{
ulong num = Convert.ToUInt64(flag.GetHashCode());
return ((Convert.ToUInt64(enumVal.GetHashCode()) & num) == num);
}
else
{
return false;
}
}
#endif
/// <summary>
/// Returns true if the flag is set on the specified bit field.
/// Currently only works with 32-bit bitfields.
/// </summary>
/// <typeparam name="T">Enumeration with Flags attribute</typeparam>
/// <param name="bitField">Flagged variable</param>
/// <param name="flag">Flag to test</param>
/// <returns></returns>
public static bool HasFlag<T>(T bitField, T flag)
where T : struct
{
return HasFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag));
}
/// <summary>
/// Returns true if the flag is set on the specified bit field.
/// Currently only works with 32-bit bitfields.
/// </summary>
/// <param name="bitField">Flagged variable</param>
/// <param name="flag">Flag to test</param>
/// <returns></returns>
public static bool HasFlag(long bitField, long flag)
{
return ((bitField & flag) == flag);
}
/// <summary>
/// Sets a bit-field to either on or off for the specified flag.
/// </summary>
/// <param name="bitField">Flagged variable</param>
/// <param name="flag">Flag to change</param>
/// <param name="on">bool</param>
/// <returns>The flagged variable with the flag changed</returns>
public static long SetFlag(long bitField, long flag, bool @on)
{
if (@on)
{
return bitField | flag;
}
return bitField & (~flag);
}
/// <summary>
/// Sets a bit-field to either on or off for the specified flag.
/// </summary>
/// <typeparam name="T">Enumeration with Flags attribute</typeparam>
/// <param name="bitField">Flagged variable</param>
/// <param name="flag">Flag to change</param>
/// <param name="on">bool</param>
/// <returns>The flagged variable with the flag changed</returns>
public static long SetFlag<T>(T bitField, T flag, bool @on)
where T : struct
{
return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), @on);
}
}
}

View File

@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace SharpCompress.Common.GZip
{
public class GZipEntry : Entry
{
private readonly GZipFilePart filePart;
internal GZipEntry(GZipFilePart filePart)
{
this.filePart = filePart;
}
public override CompressionType CompressionType
{
get { return CompressionType.GZip; }
}
public override uint Crc
{
get { return 0; }
}
public override string FilePath
{
get { return filePart.FilePartName; }
}
public override long CompressedSize
{
get { return 0; }
}
public override long Size
{
get { return 0; }
}
public override DateTime? LastModifiedTime
{
get { return filePart.DateModified; }
}
public override DateTime? CreatedTime
{
get { return null; }
}
public override DateTime? LastAccessedTime
{
get { return null; }
}
public override DateTime? ArchivedTime
{
get { return null; }
}
public override bool IsEncrypted
{
get { return false; }
}
public override bool IsDirectory
{
get { return false; }
}
public override bool IsSplit
{
get { return false; }
}
internal override IEnumerable<FilePart> Parts
{
get { return filePart.AsEnumerable<FilePart>(); }
}
internal static IEnumerable<GZipEntry> GetEntries(Stream stream)
{
yield return new GZipEntry(new GZipFilePart(stream));
}
internal override void Close()
{
}
}
}

View File

@@ -0,0 +1,103 @@
using System;
using System.IO;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.Compressor;
using SharpCompress.Compressor.Deflate;
namespace SharpCompress.Common.GZip
{
internal class GZipFilePart : FilePart
{
private string name;
private readonly Stream stream;
internal GZipFilePart(Stream stream)
{
ReadAndValidateGzipHeader(stream);
this.stream = stream;
}
internal DateTime? DateModified { get; private set; }
internal override string FilePartName
{
get { return name; }
}
internal override Stream GetCompressedStream()
{
return new DeflateStream(stream, CompressionMode.Decompress, CompressionLevel.Default, false);
}
internal override Stream GetRawStream()
{
return stream;
}
private void ReadAndValidateGzipHeader(Stream stream)
{
// read the header on the first read
byte[] header = new byte[10];
int n = stream.Read(header, 0, header.Length);
// workitem 8501: handle edge case (decompress empty stream)
if (n == 0)
return;
if (n != 10)
throw new ZlibException("Not a valid GZIP stream.");
if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8)
throw new ZlibException("Bad GZIP header.");
Int32 timet = BitConverter.ToInt32(header, 4);
DateModified = TarHeader.Epoch.AddSeconds(timet);
if ((header[3] & 0x04) == 0x04)
{
// read and discard extra field
n = stream.Read(header, 0, 2); // 2-byte length field
Int16 extraLength = (Int16) (header[0] + header[1]*256);
byte[] extra = new byte[extraLength];
n = stream.Read(extra, 0, extra.Length);
if (n != extraLength)
{
throw new ZlibException("Unexpected end-of-file reading GZIP header.");
}
}
if ((header[3] & 0x08) == 0x08)
name = ReadZeroTerminatedString(stream);
if ((header[3] & 0x10) == 0x010)
ReadZeroTerminatedString(stream);
if ((header[3] & 0x02) == 0x02)
stream.ReadByte(); // CRC16, ignore
}
private static string ReadZeroTerminatedString(Stream stream)
{
byte[] buf1 = new byte[1];
var list = new System.Collections.Generic.List<byte>();
bool done = false;
do
{
// workitem 7740
int n = stream.Read(buf1, 0, 1);
if (n != 1)
{
throw new ZlibException("Unexpected EOF reading GZIP header.");
}
if (buf1[0] == 0)
{
done = true;
}
else
{
list.Add(buf1[0]);
}
} while (!done);
byte[] a = list.ToArray();
return ArchiveEncoding.Default.GetString(a, 0, a.Length);
}
}
}

Some files were not shown because too many files have changed in this diff Show More