mirror of
https://github.com/SabreTools/SabreTools.IO.git
synced 2026-02-07 21:30:59 +00:00
Compare commits
108 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7f7bd4d0d | ||
|
|
b3e410180a | ||
|
|
6bd77c7377 | ||
|
|
4dc1378d36 | ||
|
|
ae87869bb9 | ||
|
|
46ad576668 | ||
|
|
37b09b07a6 | ||
|
|
448e43dd05 | ||
|
|
e29b8ab4db | ||
|
|
6075aa25a2 | ||
|
|
c53fb33278 | ||
|
|
fb1fc5d85d | ||
|
|
2763d3915b | ||
|
|
16b238539b | ||
|
|
68f49eeb48 | ||
|
|
c5ecd41a8f | ||
|
|
9ab9dd4ff8 | ||
|
|
867c8d11da | ||
|
|
65dbb7a31a | ||
|
|
1eaf7954fe | ||
|
|
a602a07514 | ||
|
|
466b0e90e7 | ||
|
|
abdf50c9e0 | ||
|
|
12341ba6aa | ||
|
|
70b78f861c | ||
|
|
5b306ce9e8 | ||
|
|
2b6fc200e2 | ||
|
|
7c63f44c75 | ||
|
|
edd3e6eef2 | ||
|
|
244b7411d4 | ||
|
|
fb60f1fed5 | ||
|
|
8f06bf5859 | ||
|
|
2c5d7ad56b | ||
|
|
46996c10e5 | ||
|
|
7491821679 | ||
|
|
8fe404e732 | ||
|
|
793168fbe5 | ||
|
|
67b6118cc1 | ||
|
|
b12d122721 | ||
|
|
20f1679557 | ||
|
|
7ccedbeac5 | ||
|
|
72910cc1c0 | ||
|
|
8f4ea0da16 | ||
|
|
eb4975b261 | ||
|
|
995c19d903 | ||
|
|
f0fe9af467 | ||
|
|
d33b47d15a | ||
|
|
e4a0a08d13 | ||
|
|
24a69166f0 | ||
|
|
6c13cdcf31 | ||
|
|
4138c271e5 | ||
|
|
f80d31597b | ||
|
|
5054aeb077 | ||
|
|
d2e9b8d6e5 | ||
|
|
2c29aee834 | ||
|
|
576bafcb87 | ||
|
|
2b310ac528 | ||
|
|
4f6b6d7b59 | ||
|
|
17e55ee233 | ||
|
|
8b78906d1d | ||
|
|
cff2dcf4cc | ||
|
|
a56942cb73 | ||
|
|
5ed661b77c | ||
|
|
a0a0cd0386 | ||
|
|
bcc0fca4ad | ||
|
|
843e821e5f | ||
|
|
630b01283e | ||
|
|
22abb96013 | ||
|
|
314de12661 | ||
|
|
a0b24031b5 | ||
|
|
b4628485c3 | ||
|
|
4610ddc9b9 | ||
|
|
e392ddc8d7 | ||
|
|
1908d1b32e | ||
|
|
9d73195f86 | ||
|
|
335a486f17 | ||
|
|
d3e41ac187 | ||
|
|
8ddd9f3f78 | ||
|
|
54ad538c08 | ||
|
|
e6bc9ab3e3 | ||
|
|
94934b00a9 | ||
|
|
e49f56fccc | ||
|
|
79c64ddfa8 | ||
|
|
b22384d5f3 | ||
|
|
955c1b5641 | ||
|
|
535f9f928d | ||
|
|
f0cb15c2e4 | ||
|
|
ec99304c51 | ||
|
|
aefc931055 | ||
|
|
e7fe342379 | ||
|
|
f372999b1b | ||
|
|
2679975945 | ||
|
|
54dd7f2f8f | ||
|
|
aee5891c50 | ||
|
|
b81d3314ea | ||
|
|
4a3ffa5f90 | ||
|
|
a20c7529d6 | ||
|
|
baea5cb0d7 | ||
|
|
659674dd4a | ||
|
|
5c199a143b | ||
|
|
99ec814808 | ||
|
|
ea1f02798c | ||
|
|
e3d4cc5e45 | ||
|
|
c98eb5c42a | ||
|
|
d0392be2d8 | ||
|
|
8761629828 | ||
|
|
a3b258dfeb | ||
|
|
f7505effa1 |
167
.editorconfig
Normal file
167
.editorconfig
Normal file
@@ -0,0 +1,167 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
|
||||
# Indentation and spacing
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# New line preferences
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
max_line_length = unset
|
||||
|
||||
# using directive preferences
|
||||
csharp_using_directive_placement = outside_namespace
|
||||
dotnet_diagnostic.IDE0005.severity = error
|
||||
|
||||
# Code-block preferences
|
||||
csharp_style_namespace_declarations = block_scoped
|
||||
csharp_style_prefer_method_group_conversion = true
|
||||
csharp_style_prefer_top_level_statements = false
|
||||
|
||||
# Expression-level preferences
|
||||
csharp_prefer_simple_default_expression = true
|
||||
csharp_style_inlined_variable_declaration = true
|
||||
csharp_style_unused_value_assignment_preference = discard_variable
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable
|
||||
dotnet_diagnostic.IDE0001.severity = warning
|
||||
dotnet_diagnostic.IDE0002.severity = warning
|
||||
dotnet_diagnostic.IDE0004.severity = warning
|
||||
dotnet_diagnostic.IDE0010.severity = error
|
||||
dotnet_diagnostic.IDE0051.severity = warning
|
||||
dotnet_diagnostic.IDE0052.severity = warning
|
||||
dotnet_diagnostic.IDE0072.severity = warning
|
||||
dotnet_diagnostic.IDE0080.severity = warning
|
||||
dotnet_diagnostic.IDE0100.severity = error
|
||||
dotnet_diagnostic.IDE0110.severity = error
|
||||
dotnet_diagnostic.IDE0120.severity = warning
|
||||
dotnet_diagnostic.IDE0121.severity = warning
|
||||
dotnet_diagnostic.IDE0240.severity = error
|
||||
dotnet_diagnostic.IDE0241.severity = error
|
||||
dotnet_style_coalesce_expression = true
|
||||
dotnet_style_namespace_match_folder = false
|
||||
dotnet_style_null_propagation = true
|
||||
dotnet_style_prefer_auto_properties = true
|
||||
dotnet_style_prefer_collection_expression = when_types_loosely_match
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
||||
dotnet_style_prefer_compound_assignment = true
|
||||
csharp_style_prefer_simple_property_accessors = true
|
||||
dotnet_style_prefer_simplified_interpolation = true
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true
|
||||
csharp_style_prefer_unbound_generic_type_in_nameof = true
|
||||
|
||||
# Field preferences
|
||||
dotnet_diagnostic.IDE0044.severity = warning
|
||||
dotnet_style_readonly_field = true
|
||||
|
||||
# Language keyword vs. framework types preferences
|
||||
dotnet_diagnostic.IDE0049.severity = error
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||
dotnet_style_predefined_type_for_member_access = true
|
||||
|
||||
# Modifier preferences
|
||||
csharp_prefer_static_local_function = true
|
||||
csharp_style_prefer_readonly_struct = true
|
||||
dotnet_diagnostic.IDE0036.severity = warning
|
||||
dotnet_diagnostic.IDE0040.severity = error
|
||||
dotnet_diagnostic.IDE0380.severity = error
|
||||
dotnet_style_require_accessibility_modifiers = always
|
||||
|
||||
# New-line preferences
|
||||
dotnet_diagnostic.IDE2000.severity = warning
|
||||
dotnet_diagnostic.IDE2002.severity = warning
|
||||
dotnet_diagnostic.IDE2003.severity = warning
|
||||
dotnet_diagnostic.IDE2004.severity = warning
|
||||
dotnet_diagnostic.IDE2005.severity = warning
|
||||
dotnet_diagnostic.IDE2006.severity = warning
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false
|
||||
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = false
|
||||
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = false
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = false
|
||||
|
||||
# Null-checking preferences
|
||||
csharp_style_conditional_delegate_call = true
|
||||
|
||||
# Parameter preferences
|
||||
dotnet_code_quality_unused_parameters = all
|
||||
dotnet_diagnostic.IDE0280.severity = error
|
||||
|
||||
# Parentheses preferences
|
||||
dotnet_diagnostic.IDE0047.severity = warning
|
||||
dotnet_diagnostic.IDE0048.severity = warning
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_other_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
|
||||
|
||||
# Pattern-matching preferences
|
||||
dotnet_diagnostic.IDE0019.severity = warning
|
||||
dotnet_diagnostic.IDE0020.severity = warning
|
||||
dotnet_diagnostic.IDE0038.severity = warning
|
||||
dotnet_diagnostic.IDE0066.severity = none
|
||||
dotnet_diagnostic.IDE0083.severity = warning
|
||||
dotnet_diagnostic.IDE0260.severity = warning
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true
|
||||
csharp_style_prefer_not_pattern = true
|
||||
csharp_style_prefer_pattern_matching = true
|
||||
|
||||
# this. and Me. preferences
|
||||
dotnet_style_qualification_for_event = false
|
||||
dotnet_style_qualification_for_field = false
|
||||
dotnet_style_qualification_for_method = false
|
||||
dotnet_style_qualification_for_property = false
|
||||
|
||||
# var preferences
|
||||
csharp_style_var_for_built_in_types = false
|
||||
csharp_style_var_when_type_is_apparent = true
|
||||
|
||||
# .NET formatting options
|
||||
dotnet_separate_import_directive_groups = false
|
||||
dotnet_sort_system_directives_first = true
|
||||
|
||||
# C# formatting options
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = false
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
74
.github/workflows/build_and_test.yml
vendored
74
.github/workflows/build_and_test.yml
vendored
@@ -1,40 +1,48 @@
|
||||
name: Build and Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
8.0.x
|
||||
9.0.x
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
- name: Run publish script
|
||||
run: ./publish-nix.sh
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: "*.nupkg,*.snupkg"
|
||||
body: 'Last built commit: ${{ github.sha }}'
|
||||
name: 'Rolling Release'
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: |
|
||||
8.0.x
|
||||
9.0.x
|
||||
10.0.x
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
- name: Run publish script
|
||||
run: ./publish-nix.sh
|
||||
|
||||
- name: Update rolling tag
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git tag -f rolling
|
||||
git push origin :refs/tags/rolling || true
|
||||
git push origin rolling --force
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.20.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: "*.nupkg,*.snupkg"
|
||||
body: "Last built commit: ${{ github.sha }}"
|
||||
name: "Rolling Release"
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
|
||||
34
.github/workflows/check_pr.yml
vendored
34
.github/workflows/check_pr.yml
vendored
@@ -3,21 +3,21 @@ name: Build PR
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
8.0.x
|
||||
9.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: |
|
||||
8.0.x
|
||||
9.0.x
|
||||
10.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
7
LICENSE
Normal file
7
LICENSE
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright (c) 2018-2025 Matt Nadareski
|
||||
|
||||
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 (including the next paragraph) 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.
|
||||
57
README.MD
57
README.MD
@@ -39,16 +39,40 @@ Various compression implementations that are used across multiple projects. Most
|
||||
| [DotNetZip](https://github.com/DinoChiesa/DotNetZip) | BZip2 and DEFLATE implementations; minor edits have been made |
|
||||
| [ZLibPort](https://github.com/Nanook/zlib-C-To-CSharp-Port) | Adds zlib code for internal and external use; minor edits have been made |
|
||||
|
||||
### `SabreTools.IO.Encryption`
|
||||
|
||||
Various encryption implementations that are used across multiple projects. Most of the implementations are be ports of existing C and C++ code.
|
||||
|
||||
#### Supported Encryption Schemes
|
||||
|
||||
| Encryption Scheme | Encrypt | Decrypt | Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| AES/CTR | Yes | Yes | Subset of functionality exposed from [The Bouncy Castle Cryptography Library For .NET](https://github.com/bcgit/bc-csharp) |
|
||||
| MoPaQ | No | Yes | Used to encrypt and decrypt MoPaQ tables for processing |
|
||||
|
||||
### `SabreTools.IO.Extensions`
|
||||
|
||||
Extensions for `BinaryReader`, `byte[]`, and `Stream` to help with reading and writing various data types. Some data types are locked behind .NET version support.
|
||||
|
||||
This namespace also contains other various extensions that help with common functionality and safe access.
|
||||
|
||||
### `SabreTools.IO.Interfaces`
|
||||
|
||||
Common interfaces used mainly internal to the library.
|
||||
|
||||
| Interface | Notes |
|
||||
| --- | --- |
|
||||
| `IMatch<T>` | Represents a matcher for a generic type |
|
||||
| `IMatchSet<T, U>` | Represents a set of `IMatch<T>` types |
|
||||
|
||||
### `SabreTools.IO.Logging`
|
||||
|
||||
Logic for a logging system, including writing to console and textfile outputs. There are 4 possible log levels for logging statements to be invoked with. There is also a stopwatch implementation included for logging statements with automatic timespan tracking.
|
||||
|
||||
### `SabreTools.IO.Matching`
|
||||
|
||||
Classes designed to make matching contents and paths easier. These classes allow for both grouped and single matching as well as post-processing of matched information.
|
||||
|
||||
### `SabreTools.IO.Readers` and `SabreTools.IO.Writers`
|
||||
|
||||
Reading and writing support for the following file types:
|
||||
@@ -63,8 +87,41 @@ For a generic INI implementation, see `SabreTools.IO.IniFile`.
|
||||
|
||||
Custom `Stream` implementations that are required for specialized use:
|
||||
|
||||
- `BufferedStream`: A format that is not a true stream implementation used for buffered, single-byte reads
|
||||
- `ReadOnlyBitStream`: A readonly stream implementation allowing bitwise reading
|
||||
- `ReadOnlyCompositeStream`: A readonly stream implementation that wraps multiple source streams in a set order
|
||||
- `ViewStream`: A readonly stream implementation representing a view into source data
|
||||
|
||||
### `SabreTools.IO.Transform`
|
||||
|
||||
File and stream implementations of common data transformations:
|
||||
|
||||
- Combine using either ordered concatenation or interleaving
|
||||
- Split by even/odd chunks or based on block size
|
||||
- Convert data either by bit-swapping, byte-swapping, word-swapping, or word/byte-swapping
|
||||
|
||||
### `SabreTools.Numerics`
|
||||
|
||||
Custom numeric types and related functionality.
|
||||
|
||||
#### Supported Numeric Types
|
||||
|
||||
| Type Name | Description |
|
||||
| --- | --- |
|
||||
| `BothInt8` | Both-endian `Int8` value |
|
||||
| `BothUInt8` | Both-endian `UInt8` value |
|
||||
| `BothInt16` | Both-endian `Int16` value |
|
||||
| `BothUInt16` | Both-endian `UInt16` value |
|
||||
| `BothInt32` | Both-endian `Int32` value |
|
||||
| `BothUInt32` | Both-endian `UInt32` value |
|
||||
| `BothInt64` | Both-endian `Int64` value |
|
||||
| `BothUInt64` | Both-endian `UInt64` value |
|
||||
|
||||
**Both-endian** or **bi-endian** numbers are represented by a little-endian value followed by a big-endian value, where both values are the same number.
|
||||
|
||||
### `SabreTools.Text.Compare`
|
||||
|
||||
Classes focused on string comparison by natural sorting. For example, "5" would be sorted before "100".
|
||||
|
||||
## Releases
|
||||
|
||||
|
||||
38
SabreTools.IO.Test/Compare/NaturalComparerTests.cs
Normal file
38
SabreTools.IO.Test/Compare/NaturalComparerTests.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using SabreTools.Text.Compare;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Compare
|
||||
{
|
||||
public class NaturalComparerTests
|
||||
{
|
||||
[Fact]
|
||||
public void ListSort_Numeric()
|
||||
{
|
||||
// Setup arrays
|
||||
string[] sortable = ["0", "100", "5", "2", "1000"];
|
||||
string[] expected = ["0", "2", "5", "100", "1000"];
|
||||
|
||||
// Run sorting on array
|
||||
Array.Sort(sortable, new NaturalComparer());
|
||||
|
||||
// Check the output
|
||||
Assert.True(sortable.SequenceEqual(expected));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ListSort_Mixed()
|
||||
{
|
||||
// Setup arrays
|
||||
string[] sortable = ["b3b", "c", "b", "a", "a1"];
|
||||
string[] expected = ["a", "a1", "b", "b3b", "c"];
|
||||
|
||||
// Run sorting on array
|
||||
Array.Sort(sortable, new NaturalComparer());
|
||||
|
||||
// Check the output
|
||||
Assert.True(sortable.SequenceEqual(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
66
SabreTools.IO.Test/Compare/NaturalComparerUtilTests.cs
Normal file
66
SabreTools.IO.Test/Compare/NaturalComparerUtilTests.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using SabreTools.Text.Compare;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Compare
|
||||
{
|
||||
public class NaturalComparerUtilTests
|
||||
{
|
||||
[Fact]
|
||||
public void CompareNumeric_BothNull_Equal()
|
||||
{
|
||||
int actual = NaturalComparerUtil.ComparePaths(null, null);
|
||||
Assert.Equal(0, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareNumeric_SingleNull_Ordered()
|
||||
{
|
||||
int actual = NaturalComparerUtil.ComparePaths(null, "notnull");
|
||||
Assert.Equal(-1, actual);
|
||||
|
||||
actual = NaturalComparerUtil.ComparePaths("notnull", null);
|
||||
Assert.Equal(1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareNumeric_BothEqual_Equal()
|
||||
{
|
||||
int actual = NaturalComparerUtil.ComparePaths("notnull", "notnull");
|
||||
Assert.Equal(0, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareNumeric_BothEqualWithPath_Equal()
|
||||
{
|
||||
int actual = NaturalComparerUtil.ComparePaths("notnull/file.ext", "notnull/file.ext");
|
||||
Assert.Equal(0, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareNumeric_BothEqualWithAltPath_Equal()
|
||||
{
|
||||
int actual = NaturalComparerUtil.ComparePaths("notnull/file.ext", "notnull\\file.ext");
|
||||
Assert.Equal(0, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareNumeric_NumericNonDecimalString_Ordered()
|
||||
{
|
||||
int actual = NaturalComparerUtil.ComparePaths("100", "10");
|
||||
Assert.Equal(1, actual);
|
||||
|
||||
actual = NaturalComparerUtil.ComparePaths("10", "100");
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompareNumeric_NumericDecimalString_Ordered()
|
||||
{
|
||||
int actual = NaturalComparerUtil.ComparePaths("100.100", "100.10");
|
||||
Assert.Equal(1, actual);
|
||||
|
||||
actual = NaturalComparerUtil.ComparePaths("100.10", "100.100");
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
SabreTools.IO.Test/Compare/NaturalReversedComparerTests.cs
Normal file
38
SabreTools.IO.Test/Compare/NaturalReversedComparerTests.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using SabreTools.Text.Compare;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Compare
|
||||
{
|
||||
public class NaturalReversedComparerTests
|
||||
{
|
||||
[Fact]
|
||||
public void ListSort_Numeric()
|
||||
{
|
||||
// Setup arrays
|
||||
string[] sortable = ["0", "100", "5", "2", "1000"];
|
||||
string[] expected = ["1000", "100", "5", "2", "0"];
|
||||
|
||||
// Run sorting on array
|
||||
Array.Sort(sortable, new NaturalReversedComparer());
|
||||
|
||||
// Check the output
|
||||
Assert.True(sortable.SequenceEqual(expected));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ListSort_Mixed()
|
||||
{
|
||||
// Setup arrays
|
||||
string[] sortable = ["b3b", "c", "b", "a", "a1"];
|
||||
string[] expected = ["c", "b3b", "b", "a1", "a"];
|
||||
|
||||
// Run sorting on array
|
||||
Array.Sort(sortable, new NaturalReversedComparer());
|
||||
|
||||
// Check the output
|
||||
Assert.True(sortable.SequenceEqual(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ namespace SabreTools.IO.Test.Compression
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-compress.bin");
|
||||
byte[] input = File.ReadAllBytes(path);
|
||||
MemoryStream output = new MemoryStream();
|
||||
var output = new MemoryStream();
|
||||
|
||||
var bzip = new BZip2OutputStream(output, leaveOpen: true);
|
||||
bzip.Write(input, 0, input.Length);
|
||||
@@ -38,4 +38,4 @@ namespace SabreTools.IO.Test.Compression
|
||||
Assert.Equal(122, output.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,4 @@ namespace SabreTools.IO.Test.Compression
|
||||
Assert.Equal("AIAIAIAIAIAIA", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace SabreTools.IO.Test.Compression
|
||||
// CFDATA blocks.
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "test-archive.msz");
|
||||
byte[] inputBytes = File.ReadAllBytes(path);
|
||||
MemoryStream input = new MemoryStream(inputBytes);
|
||||
MemoryStream output = new MemoryStream();
|
||||
var input = new MemoryStream(inputBytes);
|
||||
var output = new MemoryStream();
|
||||
|
||||
var decompressor = Decompressor.Create();
|
||||
input.SeekIfPossible(0x0000);
|
||||
@@ -25,7 +25,7 @@ namespace SabreTools.IO.Test.Compression
|
||||
input.SeekIfPossible(0x3969);
|
||||
decompressor.CopyTo(input, output);
|
||||
|
||||
Assert.Equal(38470, output.Length);
|
||||
Assert.Equal(65536, output.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using SabreTools.IO.Compression.Quantum;
|
||||
using Xunit;
|
||||
|
||||
#pragma warning disable CA1822 // Mark members as static
|
||||
namespace SabreTools.IO.Test.Compression
|
||||
{
|
||||
public class QuantumTests
|
||||
@@ -26,4 +27,4 @@ namespace SabreTools.IO.Test.Compression
|
||||
Assert.Equal(38470, output.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
@@ -35,17 +33,29 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(1)];
|
||||
bw.Write((byte)0x00);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteByteBothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
|
||||
int offset = 0;
|
||||
bw.WriteBothEndian(_bytes.ReadByteBothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteBytesTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bw.Write([0x00, 0x01, 0x02, 0x03]);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -55,7 +65,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bw.WriteBigEndian([0x03, 0x02, 0x01, 0x00]);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -65,17 +75,29 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(1)];
|
||||
bw.Write((sbyte)0x00);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSByteBothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
|
||||
int offset = 0;
|
||||
bw.WriteBothEndian(_bytes.ReadSByteBothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteCharTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(1)];
|
||||
bw.Write('\0');
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -95,7 +117,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bw.Write((short)0x0100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -105,18 +127,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = bw.WriteBigEndian((short)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
|
||||
int offset = 0;
|
||||
bw.WriteBothEndian(_bytes.ReadInt16BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bw.Write((ushort)0x0100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -126,19 +160,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = bw.WriteBigEndian((ushort)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteUInt16BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
|
||||
int offset = 0;
|
||||
bw.WriteBothEndian(_bytes.ReadUInt16BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteHalfTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bw.Write(BitConverter.Int16BitsToHalf(0x0100));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -148,19 +193,18 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = bw.WriteBigEndian(BitConverter.Int16BitsToHalf(0x0001));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bw.WriteAsInt24(0x020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -170,7 +214,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = bw.WriteAsInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -181,7 +225,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bw.WriteAsUInt24(0x020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -191,7 +235,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = bw.WriteAsUInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -202,7 +246,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bw.Write(0x03020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -212,18 +256,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = bw.WriteBigEndian(0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
|
||||
int offset = 0;
|
||||
bw.WriteBothEndian(_bytes.ReadInt32BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bw.Write((uint)0x03020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -233,18 +289,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = bw.WriteBigEndian((uint)0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
|
||||
int offset = 0;
|
||||
bw.WriteBothEndian(_bytes.ReadUInt32BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bw.Write(BitConverter.Int32BitsToSingle(0x03020100));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -254,7 +322,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = bw.WriteBigEndian(BitConverter.Int32BitsToSingle(0x00010203));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -265,7 +333,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bw.WriteAsInt48(0x050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -275,7 +343,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = bw.WriteAsInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -286,7 +354,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bw.WriteAsUInt48(0x050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -296,7 +364,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = bw.WriteAsUInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -307,7 +375,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bw.Write(0x0706050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -317,18 +385,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = bw.WriteBigEndian(0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
|
||||
int offset = 0;
|
||||
bw.WriteBothEndian(_bytes.ReadInt64BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bw.Write((ulong)0x0706050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -338,18 +418,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = bw.WriteBigEndian((ulong)0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
|
||||
int offset = 0;
|
||||
bw.WriteBothEndian(_bytes.ReadUInt64BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDoubleTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bw.Write(BitConverter.Int64BitsToDouble(0x0706050403020100));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -359,7 +451,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = bw.WriteBigEndian(BitConverter.Int64BitsToDouble(0x0001020304050607));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -370,7 +462,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _decimalBytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _decimalBytes.Take(16)];
|
||||
bw.Write(0.0123456789M);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -380,7 +472,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _decimalBytes.Take(16).Reverse().ToArray();
|
||||
byte[] expected = [.. _decimalBytes.Take(16).Reverse()];
|
||||
bool write = bw.WriteBigEndian(0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -391,7 +483,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = bw.Write(new Guid(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -402,19 +494,18 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = bw.WriteBigEndian(new Guid(_bytes.Reverse().ToArray()));
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = bw.WriteBigEndian(new Guid([.. Enumerable.Reverse(_bytes)]));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = bw.Write((Int128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -425,8 +516,8 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = bw.WriteBigEndian((Int128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = bw.WriteBigEndian((Int128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -436,7 +527,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = bw.Write((UInt128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -447,12 +538,11 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = bw.WriteBigEndian((UInt128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = bw.WriteBigEndian((UInt128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedAnsiStringTest()
|
||||
@@ -532,39 +622,35 @@ namespace SabreTools.IO.Test.Extensions
|
||||
// Guid
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
bool actual = bw.WriteType<Guid>(new Guid(_bytes));
|
||||
bool actual = bw.WriteType(new Guid(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, stream.GetBuffer());
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
// Half
|
||||
stream = new MemoryStream(new byte[2], 0, 2, true, true);
|
||||
bw = new BinaryWriter(stream);
|
||||
actual = bw.WriteType<Half>(BitConverter.Int16BitsToHalf(0x0100));
|
||||
actual = bw.WriteType(BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(2)], stream.GetBuffer());
|
||||
#endif
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
// Int128
|
||||
stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
bw = new BinaryWriter(stream);
|
||||
actual = bw.WriteType<Int128>((Int128)new BigInteger(_bytes));
|
||||
actual = bw.WriteType((Int128)new BigInteger(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, stream.GetBuffer());
|
||||
|
||||
// UInt128
|
||||
stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
bw = new BinaryWriter(stream);
|
||||
actual = bw.WriteType<UInt128>((UInt128)new BigInteger(_bytes));
|
||||
actual = bw.WriteType((UInt128)new BigInteger(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, stream.GetBuffer());
|
||||
#endif
|
||||
|
||||
// Enum
|
||||
stream = new MemoryStream(new byte[4], 0, 4, true, true);
|
||||
bw = new BinaryWriter(stream);
|
||||
actual = bw.WriteType<TestEnum>((TestEnum)0x03020100);
|
||||
actual = bw.WriteType((TestEnum)0x03020100);
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(4)], stream.GetBuffer());
|
||||
}
|
||||
@@ -586,7 +672,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
SecondValue = 0x07060504,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = bytesWithString.Take(12).ToArray();
|
||||
byte[] expected = [.. bytesWithString.Take(12)];
|
||||
bool write = bw.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -611,7 +697,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
FourthValue = 0x0B0A,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = bytesWithString.Take(16).ToArray();
|
||||
byte[] expected = [.. bytesWithString.Take(16)];
|
||||
bool write = bw.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
@@ -7,7 +8,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class ByteArrayExtensionsTests
|
||||
{
|
||||
#region Is Null or Empty
|
||||
#region IsNullOrEmpty
|
||||
|
||||
[Fact]
|
||||
public void IsNullOrEmpty_Null_True()
|
||||
@@ -35,7 +36,511 @@ namespace SabreTools.IO.Test.Extensions
|
||||
|
||||
#endregion
|
||||
|
||||
#region To Hex String
|
||||
#region IsNumericArray
|
||||
|
||||
[Fact]
|
||||
public void IsNumericArray_Empty_False()
|
||||
{
|
||||
byte[] arr = [];
|
||||
bool actual = arr.IsNumericArray();
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsNumericArray_NonNumeric_False()
|
||||
{
|
||||
byte[] arr = Encoding.ASCII.GetBytes("ABCDEF");
|
||||
bool actual = arr.IsNumericArray();
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsNumericArray_MixedNumeric_False()
|
||||
{
|
||||
byte[] arr = Encoding.ASCII.GetBytes("ABC123");
|
||||
bool actual = arr.IsNumericArray();
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsNumericArray_Numeric_True()
|
||||
{
|
||||
byte[] arr = Encoding.ASCII.GetBytes("0123456789");
|
||||
bool actual = arr.IsNumericArray();
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FindAllPositions
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
var positions = stack.FindAllPositions([0x01]);
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_EmptyNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
var positions = stack.FindAllPositions(Array.Empty<byte>());
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_LongerNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
var positions = stack.FindAllPositions([0x01, 0x02]);
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_InvalidStart_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
var positions = stack.FindAllPositions([0x01, 0x02], start: -1);
|
||||
Assert.Empty(positions);
|
||||
|
||||
positions = stack.FindAllPositions([0x01, 0x02], start: 2);
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_InvalidEnd_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
var positions = stack.FindAllPositions([0x01, 0x02], end: -2);
|
||||
Assert.Empty(positions);
|
||||
|
||||
positions = stack.FindAllPositions([0x01, 0x02], end: 0);
|
||||
Assert.Empty(positions);
|
||||
|
||||
positions = stack.FindAllPositions([0x01, 0x02], end: 2);
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
var positions = stack.FindAllPositions([0x01, 0x02]);
|
||||
int position = Assert.Single(positions);
|
||||
Assert.Equal(0, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_Mismatch_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x03];
|
||||
var positions = stack.FindAllPositions([0x01, 0x02]);
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_Multiple_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x01];
|
||||
var positions = stack.FindAllPositions([0x01]);
|
||||
Assert.Equal(2, positions.Count);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FirstPosition
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
int position = stack.FirstPosition([0x01]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_EmptyNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.FirstPosition(Array.Empty<byte>());
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_LongerNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.FirstPosition([0x01, 0x02]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_InvalidStart_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.FirstPosition([0x01, 0x02], start: -1);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.FirstPosition([0x01, 0x02], start: 2);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_InvalidEnd_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.FirstPosition([0x01, 0x02], end: -2);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.FirstPosition([0x01, 0x02], end: 0);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.FirstPosition([0x01, 0x02], end: 2);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
int position = stack.FirstPosition([0x01, 0x02]);
|
||||
Assert.Equal(0, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_Mismatch_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x03];
|
||||
int position = stack.FirstPosition([0x01, 0x02]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_Multiple_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x01];
|
||||
int position = stack.FirstPosition([0x01]);
|
||||
Assert.Equal(0, position);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LastPosition
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
int position = stack.LastPosition([0x01]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_EmptyNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.LastPosition(Array.Empty<byte>());
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_LongerNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.LastPosition([0x01, 0x02]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_InvalidStart_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.LastPosition([0x01, 0x02], start: -1);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.LastPosition([0x01, 0x02], start: 2);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_InvalidEnd_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.LastPosition([0x01, 0x02], end: -2);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.LastPosition([0x01, 0x02], end: 0);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.LastPosition([0x01, 0x02], end: 2);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
int position = stack.LastPosition([0x01, 0x02]);
|
||||
Assert.Equal(0, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_Mismatch_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x03];
|
||||
int position = stack.LastPosition([0x01, 0x02]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_Multiple_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x01];
|
||||
int position = stack.LastPosition([0x01]);
|
||||
Assert.Equal(1, position);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region EqualsExactly
|
||||
|
||||
[Fact]
|
||||
public void EqualsExactly_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
bool found = stack.EqualsExactly([0x01]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualsExactly_EmptyNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
bool found = stack.EqualsExactly(Array.Empty<byte>());
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualsExactly_ShorterNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
bool found = stack.EqualsExactly([0x01]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualsExactly_LongerNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
bool found = stack.EqualsExactly([0x01, 0x02]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualsExactly_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
bool found = stack.EqualsExactly([0x01, 0x02]);
|
||||
Assert.True(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualsExactly_Mismatch_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x03];
|
||||
bool found = stack.EqualsExactly([0x01, 0x02]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region StartsWith
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
bool found = stack.StartsWith([0x01]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_EmptyNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
bool found = stack.StartsWith(Array.Empty<byte>());
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_LongerNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
bool found = stack.StartsWith([0x01, 0x02]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
bool found = stack.StartsWith([0x01, 0x02]);
|
||||
Assert.True(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_Mismatch_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x03];
|
||||
bool found = stack.StartsWith([0x01, 0x02]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_Multiple_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x01];
|
||||
bool found = stack.StartsWith([0x01]);
|
||||
Assert.True(found);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region EndsWith
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
bool found = stack.EndsWith([0x01]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_EmptyNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
bool found = stack.EndsWith(Array.Empty<byte>());
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_LongerNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
bool found = stack.StartsWith([0x01, 0x02]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
bool found = stack.EndsWith([0x01, 0x02]);
|
||||
Assert.True(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_Mismatch_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x03];
|
||||
bool found = stack.EndsWith([0x01, 0x02]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_Multiple_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x01];
|
||||
bool found = stack.EndsWith([0x01]);
|
||||
Assert.True(found);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Add
|
||||
|
||||
[Theory]
|
||||
[InlineData(new byte[0], 0, new byte[0])]
|
||||
[InlineData(new byte[0], 1234, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 })]
|
||||
[InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 }, 0, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 })]
|
||||
[InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 }, 1234, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xA4 })]
|
||||
public void Add_NumericInput(byte[] self, uint add, byte[] expected)
|
||||
{
|
||||
byte[] actual = self.Add(add);
|
||||
|
||||
Assert.Equal(expected.Length, actual.Length);
|
||||
if (actual.Length > 0)
|
||||
Assert.True(actual.EqualsExactly(expected));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new byte[0], new byte[0], new byte[0])]
|
||||
[InlineData(new byte[0], new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })]
|
||||
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[0], new byte[] { 0x04, 0xD2 })]
|
||||
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 })]
|
||||
[InlineData(new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })]
|
||||
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x09, 0xA4 })]
|
||||
[InlineData(new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x09, 0xA4 })]
|
||||
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0xAB, 0x09, 0xA4 })]
|
||||
public void Add_ArrayInput(byte[] self, byte[] add, byte[] expected)
|
||||
{
|
||||
byte[] actual = self.Add(add);
|
||||
|
||||
Assert.Equal(expected.Length, actual.Length);
|
||||
if (actual.Length > 0)
|
||||
Assert.True(actual.EqualsExactly(expected));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RotateLeft
|
||||
|
||||
[Theory]
|
||||
[InlineData(new byte[0], 0, new byte[0])]
|
||||
[InlineData(new byte[] { 0x01 }, 0, new byte[] { 0x01 })]
|
||||
[InlineData(new byte[] { 0x01 }, 1, new byte[] { 0x02 })]
|
||||
[InlineData(new byte[] { 0x80 }, 1, new byte[] { 0x01 })]
|
||||
[InlineData(new byte[] { 0x00, 0x01 }, 0, new byte[] { 0x00, 0x01 })]
|
||||
[InlineData(new byte[] { 0x00, 0x01 }, 1, new byte[] { 0x00, 0x02 })]
|
||||
[InlineData(new byte[] { 0x00, 0x80 }, 1, new byte[] { 0x01, 0x00 })]
|
||||
[InlineData(new byte[] { 0x80, 0x00 }, 1, new byte[] { 0x00, 0x01 })]
|
||||
public void RotateLeftTest(byte[] self, int numBits, byte[] expected)
|
||||
{
|
||||
byte[] actual = self.RotateLeft(numBits);
|
||||
|
||||
Assert.Equal(expected.Length, actual.Length);
|
||||
if (actual.Length > 0)
|
||||
Assert.True(actual.EqualsExactly(expected));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Xor
|
||||
|
||||
[Theory]
|
||||
[InlineData(new byte[0], new byte[0], new byte[0])]
|
||||
[InlineData(new byte[0], new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })]
|
||||
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[0], new byte[] { 0x04, 0xD2 })]
|
||||
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 })]
|
||||
[InlineData(new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })]
|
||||
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 })]
|
||||
[InlineData(new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x00, 0x00 })]
|
||||
[InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0xAB, 0x00, 0x00 })]
|
||||
public void XorTest(byte[] self, byte[] add, byte[] expected)
|
||||
{
|
||||
byte[] actual = self.Xor(add);
|
||||
|
||||
Assert.Equal(expected.Length, actual.Length);
|
||||
if (actual.Length > 0)
|
||||
Assert.True(actual.EqualsExactly(expected));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ToHexString
|
||||
|
||||
[Fact]
|
||||
public void ToHexString_Null()
|
||||
@@ -58,7 +563,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
|
||||
#endregion
|
||||
|
||||
#region From Hex String
|
||||
#region FromHexString
|
||||
|
||||
[Fact]
|
||||
public void FromHexString_Null()
|
||||
@@ -88,5 +593,385 @@ namespace SabreTools.IO.Test.Extensions
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ReadStringsFrom
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_Null_Null()
|
||||
{
|
||||
byte[]? arr = null;
|
||||
var actual = arr.ReadStringsFrom(3);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_Empty_Null()
|
||||
{
|
||||
byte[]? arr = [];
|
||||
var actual = arr.ReadStringsFrom(3);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1)]
|
||||
[InlineData(0)]
|
||||
[InlineData(2048)]
|
||||
public void ReadStringsFrom_InvalidLimit_Empty(int charLimit)
|
||||
{
|
||||
byte[]? arr = new byte[1024];
|
||||
var actual = arr.ReadStringsFrom(charLimit);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_NoValidStrings_Empty()
|
||||
{
|
||||
byte[]? arr = new byte[1024];
|
||||
var actual = arr.ReadStringsFrom(4);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_AsciiStrings_Filled()
|
||||
{
|
||||
byte[]? arr =
|
||||
[
|
||||
.. Encoding.ASCII.GetBytes("TEST"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.ASCII.GetBytes("TWO"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.ASCII.GetBytes("DATA"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
var actual = arr.ReadStringsFrom(4);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(2, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_Latin1Strings_Filled()
|
||||
{
|
||||
byte[]? arr =
|
||||
[
|
||||
.. Encoding.Latin1.GetBytes("TEST"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("TWO"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("DATA"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
var actual = arr.ReadStringsFrom(4);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(2, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_UTF16_Filled()
|
||||
{
|
||||
byte[]? arr =
|
||||
[
|
||||
.. Encoding.Unicode.GetBytes("TEST"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("TWO"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("DATA"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
var actual = arr.ReadStringsFrom(4);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(2, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_Mixed_Filled()
|
||||
{
|
||||
byte[]? arr =
|
||||
[
|
||||
.. Encoding.ASCII.GetBytes("TEST1"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.ASCII.GetBytes("TWO1"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.ASCII.GetBytes("DATA1"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("TEST2"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("TWO2"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("DATA2"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("TEST3"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("TWO3"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("DATA3"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
var actual = arr.ReadStringsFrom(5);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(6, actual.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This test is here mainly for performance testing
|
||||
/// and should not be enabled unless there are changes
|
||||
/// to the core reading methods that need comparison.
|
||||
/// </summary>
|
||||
// [Fact]
|
||||
// public void ReadStringsFrom_Mixed_MASSIVE()
|
||||
// {
|
||||
// byte[]? arr =
|
||||
// [
|
||||
// .. Encoding.ASCII.GetBytes("TEST1"),
|
||||
// .. new byte[] { 0x00 },
|
||||
// .. Encoding.ASCII.GetBytes("TWO1"),
|
||||
// .. new byte[] { 0x00 },
|
||||
// .. Encoding.ASCII.GetBytes("DATA1"),
|
||||
// .. new byte[] { 0x00 },
|
||||
// .. Encoding.UTF8.GetBytes("TEST2"),
|
||||
// .. new byte[] { 0x00 },
|
||||
// .. Encoding.UTF8.GetBytes("TWO2"),
|
||||
// .. new byte[] { 0x00 },
|
||||
// .. Encoding.UTF8.GetBytes("DATA2"),
|
||||
// .. new byte[] { 0x00 },
|
||||
// .. Encoding.Unicode.GetBytes("TEST3"),
|
||||
// .. new byte[] { 0x00 },
|
||||
// .. Encoding.Unicode.GetBytes("TWO3"),
|
||||
// .. new byte[] { 0x00 },
|
||||
// .. Encoding.Unicode.GetBytes("DATA3"),
|
||||
// .. new byte[] { 0x00 },
|
||||
// ];
|
||||
// arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
// arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
// arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
// arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
// arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
// arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
// arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
// arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
// arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
// arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
// // arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
// // arr = [.. arr, .. arr, .. arr, .. arr];
|
||||
|
||||
// var actual = arr.ReadStringsFrom(5);
|
||||
// Assert.NotNull(actual);
|
||||
// Assert.NotEmpty(actual);
|
||||
// }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ReadStringsWithEncoding
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_Null_Empty()
|
||||
{
|
||||
byte[]? bytes = null;
|
||||
var actual = bytes.ReadStringsWithEncoding(1, Encoding.ASCII);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_Empty_Empty()
|
||||
{
|
||||
byte[]? bytes = [];
|
||||
var actual = bytes.ReadStringsWithEncoding(1, Encoding.ASCII);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1)]
|
||||
[InlineData(0)]
|
||||
[InlineData(2048)]
|
||||
public void ReadStringsWithEncoding_InvalidLimit_Empty(int charLimit)
|
||||
{
|
||||
byte[]? bytes = new byte[1024];
|
||||
var actual = bytes.ReadStringsWithEncoding(charLimit, Encoding.ASCII);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_NoValidStrings_Empty()
|
||||
{
|
||||
byte[]? bytes = new byte[1024];
|
||||
var actual = bytes.ReadStringsWithEncoding(5, Encoding.ASCII);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_AsciiStrings_Filled()
|
||||
{
|
||||
byte[]? bytes =
|
||||
[
|
||||
.. Encoding.ASCII.GetBytes("TEST"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.ASCII.GetBytes("ONE"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.ASCII.GetBytes("TWO"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.ASCII.GetBytes("DATA"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
var actual = bytes.ReadStringsWithEncoding(4, Encoding.ASCII);
|
||||
Assert.Equal(2, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_InvalidAsciiChars_Empty()
|
||||
{
|
||||
byte[]? arr =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
.. Enumerable.Range(0x80, 0x80).Select(i => (byte)i),
|
||||
];
|
||||
var actual = arr.ReadStringsWithEncoding(1, Encoding.ASCII);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_Latin1_Filled()
|
||||
{
|
||||
byte[]? bytes =
|
||||
[
|
||||
.. Encoding.Latin1.GetBytes("TEST"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("ONE"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("TWO"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("DATA"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
var actual = bytes.ReadStringsWithEncoding(4, Encoding.Latin1);
|
||||
Assert.Equal(2, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_InvalidLatin1Chars_Empty()
|
||||
{
|
||||
byte[]? arr =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
];
|
||||
var actual = arr.ReadStringsWithEncoding(1, Encoding.Latin1);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_UTF8_Filled()
|
||||
{
|
||||
byte[]? bytes =
|
||||
[
|
||||
.. Encoding.UTF8.GetBytes("TEST"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.UTF8.GetBytes("ONE"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.UTF8.GetBytes("TWO"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.UTF8.GetBytes("DATA"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
var actual = bytes.ReadStringsWithEncoding(4, Encoding.UTF8);
|
||||
Assert.Equal(2, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_InvalidUTF8Chars_Empty()
|
||||
{
|
||||
byte[]? arr =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
.. Enumerable.Range(0x80, 0x42).Select(i => (byte)i),
|
||||
0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC,
|
||||
0xFD, 0xFE, 0xFF,
|
||||
];
|
||||
var actual = arr.ReadStringsWithEncoding(1, Encoding.UTF8);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_UTF16_Filled()
|
||||
{
|
||||
byte[]? bytes =
|
||||
[
|
||||
.. Encoding.Unicode.GetBytes("TEST"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("ONE"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("TWO"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("DATA"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
var actual = bytes.ReadStringsWithEncoding(4, Encoding.Unicode);
|
||||
Assert.Equal(2, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_InvalidUTF16Chars_Empty()
|
||||
{
|
||||
byte[]? arr =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
];
|
||||
var actual = arr.ReadStringsWithEncoding(1, Encoding.Unicode);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_UTF32_Filled()
|
||||
{
|
||||
byte[]? bytes =
|
||||
[
|
||||
.. Encoding.UTF32.GetBytes("TEST"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.UTF32.GetBytes("ONE"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.UTF32.GetBytes("TWO"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.UTF32.GetBytes("DATA"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
var actual = bytes.ReadStringsWithEncoding(4, Encoding.UTF32);
|
||||
Assert.Equal(2, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsWithEncoding_InvalidUTF32Chars_Empty()
|
||||
{
|
||||
byte[]? arr =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
];
|
||||
var actual = arr.ReadStringsWithEncoding(1, Encoding.UTF32);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
@@ -34,18 +32,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(1)];
|
||||
bool write = buffer.Write(ref offset, (byte)0x00);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteByteBothEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
|
||||
int readOffset = 0;
|
||||
buffer.WriteBothEndian(ref offset, _bytes.ReadByteBothEndian(ref readOffset));
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteBytesTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = buffer.Write(ref offset, [0x00, 0x01, 0x02, 0x03]);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -56,7 +66,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, [0x03, 0x02, 0x01, 0x00]);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -67,18 +77,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(1)];
|
||||
bool write = buffer.Write(ref offset, (sbyte)0x00);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSByteBothEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
|
||||
int readOffset = 0;
|
||||
buffer.WriteBothEndian(ref offset, _bytes.ReadSByteBothEndian(ref readOffset));
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteCharTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(1)];
|
||||
bool write = buffer.Write(ref offset, '\0');
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -100,7 +122,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = buffer.Write(ref offset, (short)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -111,18 +133,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, (short)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16BothEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
|
||||
int readOffset = 0;
|
||||
buffer.WriteBothEndian(ref offset, _bytes.ReadInt16BothEndian(ref readOffset));
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = buffer.Write(ref offset, (ushort)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -133,19 +167,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, (ushort)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteUInt16BothEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
|
||||
int readOffset = 0;
|
||||
buffer.WriteBothEndian(ref offset, _bytes.ReadUInt16BothEndian(ref readOffset));
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteHalfTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = buffer.Write(ref offset, BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -156,19 +201,18 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, BitConverter.Int16BitsToHalf(0x0001));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = buffer.WriteAsInt24(ref offset, 0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -179,7 +223,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = buffer.WriteAsInt24BigEndian(ref offset, 0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -190,7 +234,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = buffer.WriteAsUInt24(ref offset, 0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -201,7 +245,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = buffer.WriteAsUInt24BigEndian(ref offset, 0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -212,7 +256,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = buffer.Write(ref offset, 0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -223,18 +267,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, 0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32BothEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
|
||||
int readOffset = 0;
|
||||
buffer.WriteBothEndian(ref offset, _bytes.ReadInt32BothEndian(ref readOffset));
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = buffer.Write(ref offset, (uint)0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -245,18 +301,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, (uint)0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32BothEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
|
||||
int readOffset = 0;
|
||||
buffer.WriteBothEndian(ref offset, _bytes.ReadUInt32BothEndian(ref readOffset));
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = buffer.Write(ref offset, BitConverter.Int32BitsToSingle(0x03020100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -267,7 +335,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, BitConverter.Int32BitsToSingle(0x00010203));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -278,7 +346,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = buffer.WriteAsInt48(ref offset, 0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -289,7 +357,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = buffer.WriteAsInt48BigEndian(ref offset, 0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -300,7 +368,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = buffer.WriteAsUInt48(ref offset, 0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -311,7 +379,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = buffer.WriteAsUInt48BigEndian(ref offset, 0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -322,7 +390,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = buffer.Write(ref offset, 0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -333,18 +401,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, 0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64BothEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
|
||||
int readOffset = 0;
|
||||
buffer.WriteBothEndian(ref offset, _bytes.ReadInt64BothEndian(ref readOffset));
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = buffer.Write(ref offset, (ulong)0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -355,18 +435,30 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, (ulong)0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64BothEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
|
||||
int readOffset = 0;
|
||||
buffer.WriteBothEndian(ref offset, _bytes.ReadUInt64BothEndian(ref readOffset));
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDoubleTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = buffer.Write(ref offset, BitConverter.Int64BitsToDouble(0x0706050403020100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -377,7 +469,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, BitConverter.Int64BitsToDouble(0x0001020304050607));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -388,7 +480,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _decimalBytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _decimalBytes.Take(16)];
|
||||
bool write = buffer.Write(ref offset, 0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -399,7 +491,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _decimalBytes.Take(16).Reverse().ToArray();
|
||||
byte[] expected = [.. _decimalBytes.Take(16).Reverse()];
|
||||
bool write = buffer.WriteBigEndian(ref offset, 0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -410,7 +502,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.Write(ref offset, new Guid(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -421,19 +513,18 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, new Guid(_bytes.Reverse().ToArray()));
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, new Guid([.. Enumerable.Reverse(_bytes)]));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteInt128Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.Write(ref offset, (Int128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -444,8 +535,8 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, (Int128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, (Int128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
@@ -455,7 +546,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.Write(ref offset, (UInt128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -466,12 +557,11 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = buffer.WriteBigEndian(ref offset, (UInt128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, (UInt128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedAnsiStringTest()
|
||||
@@ -551,39 +641,35 @@ namespace SabreTools.IO.Test.Extensions
|
||||
// Guid
|
||||
int offset = 0;
|
||||
byte[] buffer = new byte[16];
|
||||
bool actual = buffer.WriteType<Guid>(ref offset, new Guid(_bytes));
|
||||
bool actual = buffer.WriteType(ref offset, new Guid(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, buffer);
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
// Half
|
||||
offset = 0;
|
||||
buffer = new byte[2];
|
||||
actual = buffer.WriteType<Half>(ref offset, BitConverter.Int16BitsToHalf(0x0100));
|
||||
actual = buffer.WriteType(ref offset, BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(2)], buffer);
|
||||
#endif
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
// Int128
|
||||
offset = 0;
|
||||
buffer = new byte[16];
|
||||
actual = buffer.WriteType<Int128>(ref offset, (Int128)new BigInteger(_bytes));
|
||||
actual = buffer.WriteType(ref offset, (Int128)new BigInteger(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, buffer);
|
||||
|
||||
// UInt128
|
||||
offset = 0;
|
||||
buffer = new byte[16];
|
||||
actual = buffer.WriteType<UInt128>(ref offset, (UInt128)new BigInteger(_bytes));
|
||||
actual = buffer.WriteType(ref offset, (UInt128)new BigInteger(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, buffer);
|
||||
#endif
|
||||
|
||||
// Enum
|
||||
offset = 0;
|
||||
buffer = new byte[4];
|
||||
actual = buffer.WriteType<TestEnum>(ref offset, (TestEnum)0x03020100);
|
||||
actual = buffer.WriteType(ref offset, (TestEnum)0x03020100);
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(4)], buffer);
|
||||
}
|
||||
@@ -605,7 +691,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
SecondValue = 0x07060504,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = bytesWithString.Take(12).ToArray();
|
||||
byte[] expected = [.. bytesWithString.Take(12)];
|
||||
bool write = buffer.WriteType(ref offset, obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
@@ -630,7 +716,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
FourthValue = 0x0B0A,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = bytesWithString.Take(16).ToArray();
|
||||
byte[] expected = [.. bytesWithString.Take(16)];
|
||||
bool write = buffer.WriteType(ref offset, obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
|
||||
86
SabreTools.IO.Test/Extensions/DictionaryExtensionsTests.cs
Normal file
86
SabreTools.IO.Test/Extensions/DictionaryExtensionsTests.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System.Collections.Generic;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class DictionaryExtensionsTests
|
||||
{
|
||||
#region MergeWith
|
||||
|
||||
[Fact]
|
||||
public void MergeWith_EmptySource_EmptyOther_Empty()
|
||||
{
|
||||
Dictionary<string, List<string>> source = [];
|
||||
Dictionary<string, List<string>> other = [];
|
||||
|
||||
source.MergeWith(other);
|
||||
Assert.Empty(source);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergeWith_EmptySource_EmptyKeyOther_Empty()
|
||||
{
|
||||
Dictionary<string, List<string>> source = [];
|
||||
Dictionary<string, List<string>> other = [];
|
||||
other.Add("key", []);
|
||||
|
||||
source.MergeWith(other);
|
||||
Assert.Empty(source);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergeWith_EmptySource_FilledOther_Filled()
|
||||
{
|
||||
Dictionary<string, List<string>> source = [];
|
||||
Dictionary<string, List<string>> other = [];
|
||||
other.Add("key", ["value"]);
|
||||
|
||||
source.MergeWith(other);
|
||||
string key = Assert.Single(source.Keys);
|
||||
Assert.Equal("key", key);
|
||||
List<string> actual = source[key];
|
||||
string value = Assert.Single(actual);
|
||||
Assert.Equal("value", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergeWith_FilledSource_EmptyOther_Filled()
|
||||
{
|
||||
Dictionary<string, List<string>> source = [];
|
||||
source.Add("key", ["value"]);
|
||||
Dictionary<string, List<string>> other = [];
|
||||
|
||||
source.MergeWith(other);
|
||||
string key = Assert.Single(source.Keys);
|
||||
Assert.Equal("key", key);
|
||||
List<string> actual = source[key];
|
||||
string value = Assert.Single(actual);
|
||||
Assert.Equal("value", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergeWith_FilledSource_FilledOther_Filled()
|
||||
{
|
||||
Dictionary<string, List<string>> source = [];
|
||||
source.Add("key1", ["value1"]);
|
||||
Dictionary<string, List<string>> other = [];
|
||||
other.Add("key2", ["value2"]);
|
||||
|
||||
source.MergeWith(other);
|
||||
Assert.Equal(2, source.Keys.Count);
|
||||
|
||||
Assert.Contains("key1", source.Keys);
|
||||
List<string> actualKey1 = source["key1"];
|
||||
string value1 = Assert.Single(actualKey1);
|
||||
Assert.Equal("value1", value1);
|
||||
|
||||
Assert.Contains("key2", source.Keys);
|
||||
List<string> actualKey2 = source["key2"];
|
||||
string value2 = Assert.Single(actualKey2);
|
||||
Assert.Equal("value2", value2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,32 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
#pragma warning disable IDE0060 // Remove unused parameter
|
||||
#pragma warning disable IDE0290 // Use primary constructor
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class EnumerableExtensionsTests
|
||||
{
|
||||
#region IterateWithAction
|
||||
|
||||
[Fact]
|
||||
public void IterateWithActionTest()
|
||||
{
|
||||
List<int> source = [1, 2, 3, 4];
|
||||
int actual = 0;
|
||||
|
||||
source.IterateWithAction(i => Interlocked.Add(ref actual, i));
|
||||
Assert.Equal(10, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SafeEnumerate
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerate_Empty()
|
||||
{
|
||||
@@ -60,8 +79,10 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(2, list.Count);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Fake enumerable that uses <see cref="ErrorEnumerator"/>
|
||||
/// Fake enumerable that uses <see cref="ErrorEnumerator"/>
|
||||
/// </summary>
|
||||
private class ErrorEnumerable : IEnumerable<string>
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
// Handle test setup
|
||||
expected ??= PathTool.GetRuntimeDirectory();
|
||||
if (expected != null)
|
||||
if (expected is not null)
|
||||
expected = Path.GetFullPath(expected);
|
||||
|
||||
string actual = dir.Ensure(create: false);
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
#pragma warning disable IDE0017 // Object initialization can be simplified
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class StreamExtensionsTests
|
||||
{
|
||||
#region Align to Boundary
|
||||
#region AlignToBoundary
|
||||
|
||||
[Fact]
|
||||
public void AlignToBoundary_Null_False()
|
||||
@@ -62,7 +64,215 @@ namespace SabreTools.IO.Test.Extensions
|
||||
|
||||
#endregion
|
||||
|
||||
#region Seek If Possible
|
||||
#region ReadFrom
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ReadFrom_Null_Null(bool retainPosition)
|
||||
{
|
||||
Stream? stream = null;
|
||||
byte[]? actual = stream.ReadFrom(0, 1, retainPosition);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ReadFrom_NonSeekable_Null(bool retainPosition)
|
||||
{
|
||||
Stream? stream = new NonSeekableStream();
|
||||
byte[]? actual = stream.ReadFrom(0, 1, retainPosition);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ReadFrom_Empty_Null(bool retainPosition)
|
||||
{
|
||||
Stream? stream = new MemoryStream([]);
|
||||
byte[]? actual = stream.ReadFrom(0, 1, retainPosition);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1, true)]
|
||||
[InlineData(2048, true)]
|
||||
[InlineData(-1, false)]
|
||||
[InlineData(2048, false)]
|
||||
public void ReadFrom_InvalidOffset_Null(long offset, bool retainPosition)
|
||||
{
|
||||
Stream? stream = new MemoryStream(new byte[1024]);
|
||||
byte[]? actual = stream.ReadFrom(offset, 1, retainPosition);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1, true)]
|
||||
[InlineData(2048, true)]
|
||||
[InlineData(-1, false)]
|
||||
[InlineData(2048, false)]
|
||||
public void ReadFrom_InvalidLength_Null(int length, bool retainPosition)
|
||||
{
|
||||
Stream? stream = new MemoryStream(new byte[1024]);
|
||||
byte[]? actual = stream.ReadFrom(0, length, retainPosition);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ReadFrom_Valid_Filled(bool retainPosition)
|
||||
{
|
||||
Stream? stream = new MemoryStream(new byte[1024]);
|
||||
byte[]? actual = stream.ReadFrom(0, 512, retainPosition);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(512, actual.Length);
|
||||
|
||||
if (retainPosition)
|
||||
Assert.Equal(0, stream.Position);
|
||||
else
|
||||
Assert.Equal(512, stream.Position);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ReadStringsFrom
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_Null_Null()
|
||||
{
|
||||
Stream? stream = null;
|
||||
var actual = stream.ReadStringsFrom(0, 1, 3);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_NonSeekable_Null()
|
||||
{
|
||||
Stream? stream = new NonSeekableStream();
|
||||
var actual = stream.ReadStringsFrom(0, 1, 3);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_Empty_Null()
|
||||
{
|
||||
Stream? stream = new MemoryStream([]);
|
||||
var actual = stream.ReadStringsFrom(0, 1, 3);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1)]
|
||||
[InlineData(0)]
|
||||
[InlineData(2048)]
|
||||
public void ReadStringsFrom_InvalidLimit_Empty(int charLimit)
|
||||
{
|
||||
Stream? stream = new MemoryStream(new byte[1024]);
|
||||
var actual = stream.ReadStringsFrom(0, 1024, charLimit);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_NoValidStrings_Empty()
|
||||
{
|
||||
Stream? stream = new MemoryStream(new byte[1024]);
|
||||
var actual = stream.ReadStringsFrom(0, 1024, 4);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_AsciiStrings_Filled()
|
||||
{
|
||||
byte[]? bytes =
|
||||
[
|
||||
.. Encoding.ASCII.GetBytes("TEST"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.ASCII.GetBytes("TWO"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.ASCII.GetBytes("DATA"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
Stream? stream = new MemoryStream(bytes);
|
||||
var actual = stream.ReadStringsFrom(0, bytes.Length, 4);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(2, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_Latin1Strings_Filled()
|
||||
{
|
||||
byte[]? bytes =
|
||||
[
|
||||
.. Encoding.Latin1.GetBytes("TEST"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("TWO"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("DATA"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
Stream? stream = new MemoryStream(bytes);
|
||||
var actual = stream.ReadStringsFrom(0, bytes.Length, 4);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(2, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_UTF16_Filled()
|
||||
{
|
||||
byte[]? bytes =
|
||||
[
|
||||
.. Encoding.Unicode.GetBytes("TEST"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("TWO"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("DATA"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
Stream? stream = new MemoryStream(bytes);
|
||||
var actual = stream.ReadStringsFrom(0, bytes.Length, 4);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(2, actual.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadStringsFrom_Mixed_Filled()
|
||||
{
|
||||
byte[]? bytes =
|
||||
[
|
||||
.. Encoding.ASCII.GetBytes("TEST1"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.ASCII.GetBytes("TWO1"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.ASCII.GetBytes("DATA1"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("TEST2"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("TWO2"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Latin1.GetBytes("DATA2"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("TEST3"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("TWO3"),
|
||||
.. new byte[] { 0x00 },
|
||||
.. Encoding.Unicode.GetBytes("DATA3"),
|
||||
.. new byte[] { 0x00 },
|
||||
];
|
||||
Stream? stream = new MemoryStream(bytes);
|
||||
var actual = stream.ReadStringsFrom(0, bytes.Length, 5);
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(6, actual.Count);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SeekIfPossible
|
||||
|
||||
[Fact]
|
||||
public void SeekIfPossible_NonSeekable_CurrentPosition()
|
||||
@@ -104,6 +314,92 @@ namespace SabreTools.IO.Test.Extensions
|
||||
Assert.Equal(13, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(SeekOrigin.Begin)]
|
||||
[InlineData(SeekOrigin.Current)]
|
||||
[InlineData(SeekOrigin.End)]
|
||||
public void SeekIfPossible_NonSeekable_OriginTest(SeekOrigin origin)
|
||||
{
|
||||
var stream = new NonSeekableStream();
|
||||
long actual = stream.SeekIfPossible(0, origin);
|
||||
Assert.Equal(8, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(SeekOrigin.Begin)]
|
||||
[InlineData(SeekOrigin.Current)]
|
||||
[InlineData(SeekOrigin.End)]
|
||||
public void SeekIfPossible_NonPositionable_OriginTest(SeekOrigin origin)
|
||||
{
|
||||
var stream = new NonPositionableStream();
|
||||
long actual = stream.SeekIfPossible(0, origin);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(SeekOrigin.Begin)]
|
||||
[InlineData(SeekOrigin.Current)]
|
||||
[InlineData(SeekOrigin.End)]
|
||||
public void SeekIfPossible_HiddenNonSeekable_OriginTest(SeekOrigin origin)
|
||||
{
|
||||
var stream = new HiddenNonSeekableStream();
|
||||
long actual = stream.SeekIfPossible(0, origin);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(SeekOrigin.Begin, 5, 5)]
|
||||
[InlineData(SeekOrigin.Current, 5, 7)]
|
||||
[InlineData(SeekOrigin.End, -5, 11)]
|
||||
public void SeekIfPossible_Seekable_OriginTest(SeekOrigin origin, long offset, long expected)
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, false, true);
|
||||
stream.Position = 2;
|
||||
|
||||
long actual = stream.SeekIfPossible(offset, origin);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SegmentValid
|
||||
|
||||
[Fact]
|
||||
public void SegmentValid_Null_False()
|
||||
{
|
||||
Stream? stream = null;
|
||||
bool actual = stream.SegmentValid(0, 1);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1)]
|
||||
[InlineData(2048)]
|
||||
public void SegmentValid_InvalidOffset_False(long offset)
|
||||
{
|
||||
Stream? stream = new MemoryStream(new byte[1024]);
|
||||
bool actual = stream.SegmentValid(offset, 1);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1)]
|
||||
[InlineData(2048)]
|
||||
public void SegmentValid_InvalidLength_False(int length)
|
||||
{
|
||||
Stream? stream = new MemoryStream(new byte[1024]);
|
||||
bool actual = stream.SegmentValid(0, length);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SegmentValid_ValidSegment_True()
|
||||
{
|
||||
Stream? stream = new MemoryStream(new byte[1024]);
|
||||
bool actual = stream.SegmentValid(0, 1024);
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
@@ -34,17 +32,28 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteByteValueTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(1)];
|
||||
bool write = stream.Write((byte)0x00);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteByteBothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
|
||||
int offset = 0;
|
||||
stream.WriteBothEndian(_bytes.ReadByteBothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteBytesTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = StreamWriterExtensions.Write(stream, [0x00, 0x01, 0x02, 0x03]);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -54,7 +63,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteBytesBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
stream.WriteBigEndian([0x03, 0x02, 0x01, 0x00]);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -63,17 +72,28 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteSByteTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(1)];
|
||||
bool write = stream.Write((sbyte)0x00);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSByteBothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
|
||||
int offset = 0;
|
||||
stream.WriteBothEndian(_bytes.ReadSByteBothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteCharTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(1).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(1)];
|
||||
bool write = stream.Write('\0');
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -92,7 +112,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteInt16Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = stream.Write((short)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -102,17 +122,28 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = stream.WriteBigEndian((short)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
|
||||
int offset = 0;
|
||||
stream.WriteBothEndian(_bytes.ReadInt16BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = stream.Write((ushort)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -122,18 +153,28 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteUInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = stream.WriteBigEndian((ushort)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteUInt16BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
|
||||
int offset = 0;
|
||||
stream.WriteBothEndian(_bytes.ReadUInt16BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteHalfTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = stream.Write(BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -143,18 +184,17 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteHalfBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(2).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = stream.WriteBigEndian(BitConverter.Int16BitsToHalf(0x0001));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = stream.WriteAsInt24(0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -164,7 +204,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = stream.WriteAsInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -174,7 +214,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteUInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = stream.WriteAsUInt24(0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -184,7 +224,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteUInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(3).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = stream.WriteAsUInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -194,7 +234,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteInt32Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = stream.Write(0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -204,17 +244,28 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = stream.WriteBigEndian(0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
|
||||
int offset = 0;
|
||||
stream.WriteBothEndian(_bytes.ReadInt32BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = stream.Write((uint)0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -224,17 +275,28 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteUInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = stream.WriteBigEndian((uint)0x00010203);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
|
||||
int offset = 0;
|
||||
stream.WriteBothEndian(_bytes.ReadUInt32BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = stream.Write(BitConverter.Int32BitsToSingle(0x03020100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -244,7 +306,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteSingleBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(4).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = stream.WriteBigEndian(BitConverter.Int32BitsToSingle(0x00010203));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -254,7 +316,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = stream.WriteAsInt48(0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -264,7 +326,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = stream.WriteAsInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -274,7 +336,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteUInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = stream.WriteAsUInt48(0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -284,7 +346,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteUInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(6).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = stream.WriteAsUInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -294,7 +356,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteInt64Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = stream.Write(0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -304,17 +366,28 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = stream.WriteBigEndian(0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
|
||||
int offset = 0;
|
||||
stream.WriteBothEndian(_bytes.ReadInt64BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = stream.Write((ulong)0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -324,17 +397,28 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteUInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = stream.WriteBigEndian((ulong)0x0001020304050607);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64BothEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
|
||||
int offset = 0;
|
||||
stream.WriteBothEndian(_bytes.ReadUInt64BothEndian(ref offset));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDoubleTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = stream.Write(BitConverter.Int64BitsToDouble(0x0706050403020100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -344,7 +428,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteDoubleBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(8).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = stream.WriteBigEndian(BitConverter.Int64BitsToDouble(0x0001020304050607));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -354,7 +438,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteDecimalTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _decimalBytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _decimalBytes.Take(16)];
|
||||
bool write = stream.Write(0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -364,7 +448,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteDecimalBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _decimalBytes.Take(16).Reverse().ToArray();
|
||||
byte[] expected = [.. _decimalBytes.Take(16).Reverse()];
|
||||
bool write = stream.WriteBigEndian(0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -374,7 +458,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteGuidTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.Write(new Guid(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -384,18 +468,17 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteGuidBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = stream.WriteBigEndian(new Guid(_bytes.Reverse().ToArray()));
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.WriteBigEndian(new Guid([.. Enumerable.Reverse(_bytes)]));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[Fact]
|
||||
public void WriteInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.Write((Int128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -405,8 +488,8 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = stream.WriteBigEndian((Int128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.WriteBigEndian((Int128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
@@ -415,7 +498,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteUInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.Write((UInt128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -425,12 +508,11 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public void WriteUInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = _bytes.Take(16).ToArray();
|
||||
bool write = stream.WriteBigEndian((UInt128)new BigInteger(_bytes.Reverse().ToArray()));
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.WriteBigEndian((UInt128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedAnsiStringTest()
|
||||
@@ -503,35 +585,31 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
// Guid
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
bool actual = stream.WriteType<Guid>(new Guid(_bytes));
|
||||
bool actual = stream.WriteType(new Guid(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, stream.GetBuffer());
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
// Half
|
||||
stream = new MemoryStream(new byte[2], 0, 2, true, true);
|
||||
actual = stream.WriteType<Half>(BitConverter.Int16BitsToHalf(0x0100));
|
||||
actual = stream.WriteType(BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(2)], stream.GetBuffer());
|
||||
#endif
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
// Int128
|
||||
stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
actual = stream.WriteType<Int128>((Int128)new BigInteger(_bytes));
|
||||
actual = stream.WriteType((Int128)new BigInteger(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, stream.GetBuffer());
|
||||
|
||||
// UInt128
|
||||
stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
actual = stream.WriteType<UInt128>((UInt128)new BigInteger(_bytes));
|
||||
actual = stream.WriteType((UInt128)new BigInteger(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, stream.GetBuffer());
|
||||
#endif
|
||||
|
||||
// Enum
|
||||
stream = new MemoryStream(new byte[4], 0, 4, true, true);
|
||||
actual = stream.WriteType<TestEnum>((TestEnum)0x03020100);
|
||||
actual = stream.WriteType((TestEnum)0x03020100);
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(4)], stream.GetBuffer());
|
||||
}
|
||||
@@ -552,7 +630,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
SecondValue = 0x07060504,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = bytesWithString.Take(12).ToArray();
|
||||
byte[] expected = [.. bytesWithString.Take(12)];
|
||||
bool write = stream.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
@@ -576,7 +654,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
FourthValue = 0x0B0A,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = bytesWithString.Take(16).ToArray();
|
||||
byte[] expected = [.. bytesWithString.Take(16)];
|
||||
bool write = stream.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
|
||||
76
SabreTools.IO.Test/Extensions/StringExtensionsTests.cs
Normal file
76
SabreTools.IO.Test/Extensions/StringExtensionsTests.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class StringExtensionsTests
|
||||
{
|
||||
#region OptionalContains
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "ANY", false)]
|
||||
[InlineData("", "ANY", false)]
|
||||
[InlineData("ANY", "ANY", true)]
|
||||
[InlineData("ANYTHING", "ANY", true)]
|
||||
[InlineData("THING", "ANY", false)]
|
||||
[InlineData("THINGANY", "ANY", true)]
|
||||
public void OptionalContainsTest(string? haystack, string needle, bool expected)
|
||||
{
|
||||
bool actual = haystack.OptionalContains(needle);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region OptionalEndsWith
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "ANY", false)]
|
||||
[InlineData("", "ANY", false)]
|
||||
[InlineData("ANY", "ANY", true)]
|
||||
[InlineData("ANYTHING", "ANY", false)]
|
||||
[InlineData("THING", "ANY", false)]
|
||||
[InlineData("THINGANY", "ANY", true)]
|
||||
public void OptionalEndsWithTest(string? haystack, string needle, bool expected)
|
||||
{
|
||||
bool actual = haystack.OptionalEndsWith(needle);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region OptionalEquals
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "ANY", false)]
|
||||
[InlineData("", "ANY", false)]
|
||||
[InlineData("ANY", "ANY", true)]
|
||||
[InlineData("ANYTHING", "ANY", false)]
|
||||
[InlineData("THING", "ANY", false)]
|
||||
[InlineData("THINGANY", "ANY", false)]
|
||||
public void OptionalEqualsTest(string? haystack, string needle, bool expected)
|
||||
{
|
||||
bool actual = haystack.OptionalEquals(needle);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region OptionalStartsWith
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "ANY", false)]
|
||||
[InlineData("", "ANY", false)]
|
||||
[InlineData("ANY", "ANY", true)]
|
||||
[InlineData("ANYTHING", "ANY", true)]
|
||||
[InlineData("THING", "ANY", false)]
|
||||
[InlineData("THINGANY", "ANY", false)]
|
||||
public void OptionalStartsWithTest(string? haystack, string needle, bool expected)
|
||||
{
|
||||
bool actual = haystack.OptionalStartsWith(needle);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public TestStructPoint[]? StructArray;
|
||||
|
||||
/// <summary>
|
||||
/// Length of <see cref="LPByteArray"/>
|
||||
/// Length of <see cref="LPByteArray"/>
|
||||
/// </summary>
|
||||
public ushort LPByteArrayLength;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)]
|
||||
public byte[]? LPByteArray;
|
||||
|
||||
|
||||
// /// <summary>
|
||||
// /// 4 entry nested byte array
|
||||
// /// </summary>
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
|
||||
public uint FieldB;
|
||||
}
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal class TestStructInheritanceChild2 : TestStructInheritanceParent
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public int SecondValue;
|
||||
|
||||
public ushort ThirdValue;
|
||||
|
||||
|
||||
public short FourthValue;
|
||||
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
|
||||
324
SabreTools.IO.Test/MatchUtilTests.cs
Normal file
324
SabreTools.IO.Test/MatchUtilTests.cs
Normal file
@@ -0,0 +1,324 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Matching;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test
|
||||
{
|
||||
public class MatchUtilTests
|
||||
{
|
||||
#region Array
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetAllMatches_NullStack_NoMatches()
|
||||
{
|
||||
byte[]? stack = null;
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[1], "name")];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets);
|
||||
Assert.Empty(matches);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetAllMatches_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[1], "name")];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets);
|
||||
Assert.Empty(matches);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetAllMatches_EmptyMatchSets_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
List<ContentMatchSet> matchSets = [];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets);
|
||||
Assert.Empty(matches);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetAllMatches_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[] { 0x01 }, "name")];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets);
|
||||
string setName = Assert.Single(matches);
|
||||
Assert.Equal("name", setName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetAllMatches_PartialMatchingAny_Matches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
List<ContentMatchSet> matchSets =
|
||||
[
|
||||
new ContentMatchSet([
|
||||
new byte[] { 0x00 },
|
||||
new ContentMatch([0x01]),
|
||||
], "name")
|
||||
];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets, any: true);
|
||||
string setName = Assert.Single(matches);
|
||||
Assert.Equal("name", setName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetAllMatches_PartialMatchingAll_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
List<ContentMatchSet> matchSets =
|
||||
[
|
||||
new ContentMatchSet([
|
||||
new byte[] { 0x00 },
|
||||
new ContentMatch([0x01]),
|
||||
], "name")
|
||||
];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets, any: false);
|
||||
Assert.Empty(matches);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetFirstMatch_NullStack_NoMatches()
|
||||
{
|
||||
byte[]? stack = null;
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[1], "name")];
|
||||
string? match = MatchUtil.GetFirstMatch("file", stack, matchSets);
|
||||
Assert.Null(match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetFirstMatch_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[1], "name")];
|
||||
string? match = MatchUtil.GetFirstMatch("file", stack, matchSets);
|
||||
Assert.Null(match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetFirstMatch_EmptyMatchSets_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
List<ContentMatchSet> matchSets = [];
|
||||
string? match = MatchUtil.GetFirstMatch("file", stack, matchSets);
|
||||
Assert.Null(match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetFirstMatch_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[] { 0x01 }, "name")];
|
||||
string? setName = MatchUtil.GetFirstMatch("file", stack, matchSets);
|
||||
Assert.Equal("name", setName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetFirstMatch_PartialMatchingAny_Matches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
List<ContentMatchSet> matchSets =
|
||||
[
|
||||
new ContentMatchSet([
|
||||
new byte[] { 0x00 },
|
||||
new ContentMatch([0x01]),
|
||||
], "name")
|
||||
];
|
||||
string? setName = MatchUtil.GetFirstMatch("file", stack, matchSets, any: true);
|
||||
Assert.Equal("name", setName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayGetFirstMatch_PartialMatchingAll_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
List<ContentMatchSet> matchSets =
|
||||
[
|
||||
new ContentMatchSet([
|
||||
new byte[] { 0x00 },
|
||||
new ContentMatch([0x01]),
|
||||
], "name")
|
||||
];
|
||||
string? setName = MatchUtil.GetFirstMatch("file", stack, matchSets, any: false);
|
||||
Assert.Null(setName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExactSizeArrayMatch()
|
||||
{
|
||||
byte[] source = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
|
||||
byte?[] check = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
|
||||
string expected = "match";
|
||||
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
new(check, expected),
|
||||
};
|
||||
|
||||
string? actual = MatchUtil.GetFirstMatch("testfile", source, matchers, any: false);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream
|
||||
|
||||
[Fact]
|
||||
public void StreamGetAllMatches_NullStack_NoMatches()
|
||||
{
|
||||
Stream? stack = null;
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[1], "name")];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets);
|
||||
Assert.Empty(matches);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamGetAllMatches_EmptyStack_NoMatches()
|
||||
{
|
||||
Stream stack = new MemoryStream();
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[1], "name")];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets);
|
||||
Assert.Empty(matches);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamGetAllMatches_EmptyMatchSets_NoMatches()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01]);
|
||||
List<ContentMatchSet> matchSets = [];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets);
|
||||
Assert.Empty(matches);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamGetAllMatches_Matching_Matches()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01]);
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[] { 0x01 }, "name")];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets);
|
||||
string setName = Assert.Single(matches);
|
||||
Assert.Equal("name", setName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamGetAllMatches_PartialMatchingAny_Matches()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01]);
|
||||
List<ContentMatchSet> matchSets =
|
||||
[
|
||||
new ContentMatchSet([
|
||||
new byte[] { 0x00 },
|
||||
new ContentMatch([0x01]),
|
||||
], "name")
|
||||
];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets, any: true);
|
||||
string setName = Assert.Single(matches);
|
||||
Assert.Equal("name", setName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamGetAllMatches_PartialMatchingAll_NoMatches()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01]);
|
||||
List<ContentMatchSet> matchSets =
|
||||
[
|
||||
new ContentMatchSet([
|
||||
new byte[] { 0x00 },
|
||||
new ContentMatch([0x01]),
|
||||
], "name")
|
||||
];
|
||||
var matches = MatchUtil.GetAllMatches("file", stack, matchSets, any: false);
|
||||
Assert.Empty(matches);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamGetFirstMatch_NullStack_NoMatches()
|
||||
{
|
||||
Stream? stack = null;
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[1], "name")];
|
||||
string? match = MatchUtil.GetFirstMatch("file", stack, matchSets);
|
||||
Assert.Null(match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamGetFirstMatch_EmptyStack_NoMatches()
|
||||
{
|
||||
Stream stack = new MemoryStream();
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[1], "name")];
|
||||
string? match = MatchUtil.GetFirstMatch("file", stack, matchSets);
|
||||
Assert.Null(match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamGetFirstMatch_EmptyMatchSets_NoMatches()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01]);
|
||||
List<ContentMatchSet> matchSets = [];
|
||||
string? match = MatchUtil.GetFirstMatch("file", stack, matchSets);
|
||||
Assert.Null(match);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamGetFirstMatch_Matching_Matches()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01]);
|
||||
List<ContentMatchSet> matchSets = [new ContentMatchSet(new byte[] { 0x01 }, "name")];
|
||||
string? setName = MatchUtil.GetFirstMatch("file", stack, matchSets);
|
||||
Assert.Equal("name", setName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamGetFirstMatch_PartialMatchingAny_Matches()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01]);
|
||||
List<ContentMatchSet> matchSets =
|
||||
[
|
||||
new ContentMatchSet([
|
||||
new byte[] { 0x00 },
|
||||
new ContentMatch([0x01]),
|
||||
], "name")
|
||||
];
|
||||
string? setName = MatchUtil.GetFirstMatch("file", stack, matchSets, any: true);
|
||||
Assert.Equal("name", setName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamGetFirstMatch_PartialMatchingAll_NoMatches()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01]);
|
||||
List<ContentMatchSet> matchSets =
|
||||
[
|
||||
new ContentMatchSet([
|
||||
new byte[] { 0x00 },
|
||||
new ContentMatch([0x01]),
|
||||
], "name")
|
||||
];
|
||||
string? setName = MatchUtil.GetFirstMatch("file", stack, matchSets, any: false);
|
||||
Assert.Null(setName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExactSizeStreamMatch()
|
||||
{
|
||||
byte[] source = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
|
||||
var stream = new MemoryStream(source);
|
||||
|
||||
byte?[] check = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
|
||||
string expected = "match";
|
||||
|
||||
var matchers = new List<ContentMatchSet>
|
||||
{
|
||||
new(check, expected),
|
||||
};
|
||||
|
||||
string? actual = MatchUtil.GetFirstMatch("testfile", stream, matchers, any: false);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Path
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
202
SabreTools.IO.Test/Matching/ContentMatchSetTests.cs
Normal file
202
SabreTools.IO.Test/Matching/ContentMatchSetTests.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Matching;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Matching
|
||||
{
|
||||
public class ContentMatchSetTests
|
||||
{
|
||||
[Fact]
|
||||
public void InvalidNeedle_ThrowsException()
|
||||
{
|
||||
Assert.Throws<InvalidDataException>(() => new ContentMatchSet(Array.Empty<byte>(), "name"));
|
||||
Assert.Throws<InvalidDataException>(() => new ContentMatchSet(Array.Empty<byte>(), ArrayVersionMock, "name"));
|
||||
Assert.Throws<InvalidDataException>(() => new ContentMatchSet(Array.Empty<byte>(), StreamVersionMock, "name"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidNeedles_ThrowsException()
|
||||
{
|
||||
Assert.Throws<InvalidDataException>(() => new ContentMatchSet([], "name"));
|
||||
Assert.Throws<InvalidDataException>(() => new ContentMatchSet([], ArrayVersionMock, "name"));
|
||||
Assert.Throws<InvalidDataException>(() => new ContentMatchSet([], StreamVersionMock, "name"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenericConstructor_NoDelegates()
|
||||
{
|
||||
var needles = new List<ContentMatch> { new byte[] { 0x01, 0x02, 0x03, 0x04 } };
|
||||
var cms = new ContentMatchSet(needles, "name");
|
||||
Assert.Null(cms.GetArrayVersion);
|
||||
Assert.Null(cms.GetStreamVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayConstructor_SingleDelegate()
|
||||
{
|
||||
var needles = new List<ContentMatch> { new byte[] { 0x01, 0x02, 0x03, 0x04 } };
|
||||
var cms = new ContentMatchSet(needles, ArrayVersionMock, "name");
|
||||
Assert.NotNull(cms.GetArrayVersion);
|
||||
Assert.Null(cms.GetStreamVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamConstructor_SingleDelegate()
|
||||
{
|
||||
var needles = new List<ContentMatch> { new byte[] { 0x01, 0x02, 0x03, 0x04 } };
|
||||
var cms = new ContentMatchSet(needles, StreamVersionMock, "name");
|
||||
Assert.Null(cms.GetArrayVersion);
|
||||
Assert.NotNull(cms.GetStreamVersion);
|
||||
}
|
||||
|
||||
#region Array
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_NullArray_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
var actual = cms.MatchesAll((byte[]?)null);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_EmptyArray_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
var actual = cms.MatchesAll([]);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_MatchingArray_Matches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
var actual = cms.MatchesAll([0x01, 0x02, 0x03, 0x04]);
|
||||
int position = Assert.Single(actual);
|
||||
Assert.Equal(0, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_MismatchedArray_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
var actual = cms.MatchesAll([0x01, 0x03]);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_NullArray_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
int actual = cms.MatchesAny((byte[]?)null);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_EmptyArray_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
int actual = cms.MatchesAny([]);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_MatchingArray_Matches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
int actual = cms.MatchesAny([0x01, 0x02, 0x03, 0x04]);
|
||||
Assert.Equal(0, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_MismatchedArray_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
int actual = cms.MatchesAny([0x01, 0x03]);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_NullStream_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
var actual = cms.MatchesAll((Stream?)null);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_EmptyStream_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
var actual = cms.MatchesAll(new MemoryStream());
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_MatchingStream_Matches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
var actual = cms.MatchesAll(new MemoryStream([0x01, 0x02, 0x03, 0x04]));
|
||||
int position = Assert.Single(actual);
|
||||
Assert.Equal(0, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_MismatchedStream_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
var actual = cms.MatchesAll([0x01, 0x03]);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_NullStream_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
int actual = cms.MatchesAny((Stream?)null);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_EmptyStream_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
int actual = cms.MatchesAny(new MemoryStream());
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_MatchingStream_Matches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
int actual = cms.MatchesAny(new MemoryStream([0x01, 0x02, 0x03, 0x04]));
|
||||
Assert.Equal(0, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_MismatchedStream_NoMatches()
|
||||
{
|
||||
var cms = new ContentMatchSet(new byte[] { 0x01, 0x02, 0x03, 0x04 }, "name");
|
||||
int actual = cms.MatchesAny([0x01, 0x03]);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mock Delegates
|
||||
|
||||
/// <inheritdoc cref="GetArrayVersion"/>
|
||||
private static string? ArrayVersionMock(string path, byte[]? content, List<int> positions) => null;
|
||||
|
||||
/// <inheritdoc cref="GetStreamVersion"/>
|
||||
private static string? StreamVersionMock(string path, Stream? content, List<int> positions) => null;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
271
SabreTools.IO.Test/Matching/ContentMatchTests.cs
Normal file
271
SabreTools.IO.Test/Matching/ContentMatchTests.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Matching;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Matching
|
||||
{
|
||||
public class ContentMatchTests
|
||||
{
|
||||
[Fact]
|
||||
public void InvalidNeedle_ThrowsException()
|
||||
{
|
||||
Assert.Throws<InvalidDataException>(() => new ContentMatch(Array.Empty<byte>()));
|
||||
Assert.Throws<InvalidDataException>(() => new ContentMatch(Array.Empty<byte?>()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidStart_ThrowsException()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new ContentMatch(new byte[1], start: -1));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new ContentMatch(new byte?[1], start: -1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidEnd_ThrowsException()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new ContentMatch(new byte[1], end: -2));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new ContentMatch(new byte?[1], end: -2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImplicitOperatorArray_Success()
|
||||
{
|
||||
byte[] needle = [0x01, 0x02, 0x03, 0x04];
|
||||
var cm = (ContentMatch)needle;
|
||||
Assert.NotNull(cm);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImplicitOperatorNullableArray_Success()
|
||||
{
|
||||
byte?[] needle = [0x01, 0x02, 0x03, 0x04];
|
||||
var cm = (ContentMatch)needle;
|
||||
Assert.NotNull(cm);
|
||||
}
|
||||
|
||||
#region Byte Array
|
||||
|
||||
[Fact]
|
||||
public void NullArray_NoMatch()
|
||||
{
|
||||
var cm = new ContentMatch(new byte?[1]);
|
||||
int actual = cm.Match((byte[]?)null);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyArray_NoMatch()
|
||||
{
|
||||
var cm = new ContentMatch(new byte?[1]);
|
||||
int actual = cm.Match([]);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LargerNeedleArray_NoMatch()
|
||||
{
|
||||
var cm = new ContentMatch(new byte?[2]);
|
||||
int actual = cm.Match(new byte[1]);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualLengthMatchingArray_Match()
|
||||
{
|
||||
byte[] needle = [0x01, 0x02, 0x03, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(needle);
|
||||
Assert.Equal(0, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualLengthMatchingArrayReverse_Match()
|
||||
{
|
||||
byte[] needle = [0x01, 0x02, 0x03, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(needle, reverse: true);
|
||||
Assert.Equal(0, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualLengthMismatchedArray_NoMatch()
|
||||
{
|
||||
byte[] needle = [0x01, 0x02, 0x03, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(new byte[4]);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualLengthMismatchedArrayReverse_NoMatch()
|
||||
{
|
||||
byte[] needle = [0x01, 0x02, 0x03, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(new byte[4], reverse: true);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InequalLengthMatchingArray_Match()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02, 0x03, 0x04];
|
||||
byte[] needle = [0x02, 0x03];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(stack);
|
||||
Assert.Equal(1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InequalLengthMatchingArrayReverse_Match()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02, 0x03, 0x04];
|
||||
byte[] needle = [0x02, 0x03];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(stack, reverse: true);
|
||||
Assert.Equal(1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InequalLengthMismatchedArray_NoMatch()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02, 0x03, 0x04];
|
||||
byte[] needle = [0x02, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(stack);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InequalLengthMismatchedArrayReverse_NoMatch()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02, 0x03, 0x04];
|
||||
byte[] needle = [0x02, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(stack, reverse: true);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream
|
||||
|
||||
[Fact]
|
||||
public void NullStream_NoMatch()
|
||||
{
|
||||
var cm = new ContentMatch(new byte?[1]);
|
||||
int actual = cm.Match((Stream?)null);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyStream_NoMatch()
|
||||
{
|
||||
var cm = new ContentMatch(new byte?[1]);
|
||||
int actual = cm.Match(new MemoryStream());
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LargerNeedleStream_NoMatch()
|
||||
{
|
||||
var cm = new ContentMatch(new byte?[2]);
|
||||
int actual = cm.Match(new MemoryStream(new byte[1]));
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualLengthMatchingStream_Match()
|
||||
{
|
||||
byte[] needle = [0x01, 0x02, 0x03, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(new MemoryStream(needle));
|
||||
Assert.Equal(0, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualLengthMatchingStreamReverse_Match()
|
||||
{
|
||||
byte[] needle = [0x01, 0x02, 0x03, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(new MemoryStream(needle), reverse: true);
|
||||
Assert.Equal(0, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualLengthMismatchedStream_NoMatch()
|
||||
{
|
||||
byte[] needle = [0x01, 0x02, 0x03, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(new MemoryStream(new byte[4]));
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EqualLengthMismatchedStreamReverse_NoMatch()
|
||||
{
|
||||
byte[] needle = [0x01, 0x02, 0x03, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(new MemoryStream(new byte[4]), reverse: true);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InequalLengthMatchingStream_Match()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01, 0x02, 0x03, 0x04]);
|
||||
byte[] needle = [0x02, 0x03];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(stack);
|
||||
Assert.Equal(1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InequalLengthMatchingStreamReverse_Match()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01, 0x02, 0x03, 0x04]);
|
||||
byte[] needle = [0x02, 0x03];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(stack, reverse: true);
|
||||
Assert.Equal(1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InequalLengthMismatchedStream_NoMatch()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01, 0x02, 0x03, 0x04]);
|
||||
byte[] needle = [0x02, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(stack);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InequalLengthMismatchedStreamReverse_NoMatch()
|
||||
{
|
||||
Stream stack = new MemoryStream([0x01, 0x02, 0x03, 0x04]);
|
||||
byte[] needle = [0x02, 0x04];
|
||||
var cm = new ContentMatch(needle);
|
||||
|
||||
int actual = cm.Match(stack, reverse: true);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
22
SabreTools.IO.Test/Matching/FilePathMatchTests.cs
Normal file
22
SabreTools.IO.Test/Matching/FilePathMatchTests.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.IO;
|
||||
using SabreTools.IO.Matching;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Matching
|
||||
{
|
||||
/// <remarks>
|
||||
/// All other test cases are covered by <see cref="PathMatchTests"/>
|
||||
/// </remarks>
|
||||
public class FilePathMatchTests
|
||||
{
|
||||
[Fact]
|
||||
public void ConstructorFormatsNeedle()
|
||||
{
|
||||
string needle = "test";
|
||||
string expected = $"{Path.DirectorySeparatorChar}{needle}";
|
||||
|
||||
var fpm = new FilePathMatch(needle);
|
||||
Assert.Equal(expected, fpm.Needle);
|
||||
}
|
||||
}
|
||||
}
|
||||
187
SabreTools.IO.Test/Matching/PathMatchSetTests.cs
Normal file
187
SabreTools.IO.Test/Matching/PathMatchSetTests.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Matching;
|
||||
using Xunit;
|
||||
|
||||
#pragma warning disable CA1861 // Prefer 'static readonly' fields
|
||||
namespace SabreTools.IO.Test.Matching
|
||||
{
|
||||
public class PathMatchSetTests
|
||||
{
|
||||
[Fact]
|
||||
public void InvalidNeedle_ThrowsException()
|
||||
{
|
||||
Assert.Throws<InvalidDataException>(() => new PathMatchSet(string.Empty, "name"));
|
||||
Assert.Throws<InvalidDataException>(() => new PathMatchSet(string.Empty, PathVersionMock, "name"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvalidNeedles_ThrowsException()
|
||||
{
|
||||
Assert.Throws<InvalidDataException>(() => new PathMatchSet([], "name"));
|
||||
Assert.Throws<InvalidDataException>(() => new PathMatchSet([], PathVersionMock, "name"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenericConstructor_NoDelegates()
|
||||
{
|
||||
var needles = new List<PathMatch> { "test" };
|
||||
var cms = new PathMatchSet(needles, "name");
|
||||
Assert.Null(cms.GetVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VersionConstructor_SingleDelegate()
|
||||
{
|
||||
var needles = new List<PathMatch> { "test" };
|
||||
var cms = new PathMatchSet(needles, PathVersionMock, "name");
|
||||
Assert.NotNull(cms.GetVersion);
|
||||
}
|
||||
|
||||
#region Array
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_NullArray_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
var actual = cms.MatchesAll((string[]?)null);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_EmptyArray_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
var actual = cms.MatchesAll(Array.Empty<string>());
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_MatchingArray_Matches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
var actual = cms.MatchesAll(new string[] { "test" });
|
||||
string path = Assert.Single(actual);
|
||||
Assert.Equal("test", path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_MismatchedArray_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
var actual = cms.MatchesAll(new string[] { "not" });
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_NullArray_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
string? actual = cms.MatchesAny((string[]?)null);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_EmptyArray_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
string? actual = cms.MatchesAny(Array.Empty<string>());
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_MatchingArray_Matches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
string? actual = cms.MatchesAny(new string[] { "test" });
|
||||
Assert.Equal("test", actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_MismatchedArray_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
string? actual = cms.MatchesAny(new string[] { "not" });
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region List
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_NullList_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
var actual = cms.MatchesAll((List<string>?)null);
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_EmptyList_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
var actual = cms.MatchesAll(new List<string>());
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_MatchingList_Matches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
var actual = cms.MatchesAll(new List<string> { "test" });
|
||||
string path = Assert.Single(actual);
|
||||
Assert.Equal("test", path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAll_MismatchedList_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
var actual = cms.MatchesAll(new List<string> { "not" });
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_NullList_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
string? actual = cms.MatchesAny((List<string>?)null);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_EmptyList_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
string? actual = cms.MatchesAny(new List<string>());
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_MatchingList_Matches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
string? actual = cms.MatchesAny(new List<string> { "test" });
|
||||
Assert.Equal("test", actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchesAny_MismatchedList_NoMatches()
|
||||
{
|
||||
var cms = new PathMatchSet("test", "name");
|
||||
string? actual = cms.MatchesAny(new List<string> { "not" });
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mock Delegates
|
||||
|
||||
/// <inheritdoc cref="GetPathVersion"/>
|
||||
private static string? PathVersionMock(string path, List<string>? files) => null;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
293
SabreTools.IO.Test/Matching/PathMatchTests.cs
Normal file
293
SabreTools.IO.Test/Matching/PathMatchTests.cs
Normal file
@@ -0,0 +1,293 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Matching;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Matching
|
||||
{
|
||||
public class PathMatchTests
|
||||
{
|
||||
[Fact]
|
||||
public void InvalidNeedle_ThrowsException()
|
||||
{
|
||||
Assert.Throws<InvalidDataException>(() => new PathMatch(string.Empty));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImplicitOperatorArray_Success()
|
||||
{
|
||||
string needle = "test";
|
||||
var pm = (PathMatch)needle;
|
||||
Assert.NotNull(pm);
|
||||
}
|
||||
|
||||
#region Array
|
||||
|
||||
[Fact]
|
||||
public void NullArray_NoMatch()
|
||||
{
|
||||
var pm = new PathMatch("test");
|
||||
string? actual = pm.Match((string[]?)null);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyArray_NoMatch()
|
||||
{
|
||||
var pm = new PathMatch("test");
|
||||
string? actual = pm.Match(Array.Empty<string>());
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SingleItemArrayMatching_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
string[] stack = [needle];
|
||||
var pm = new PathMatch(needle);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal(needle, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SingleItemArrayMismatched_NoMatch()
|
||||
{
|
||||
string needle = "test";
|
||||
string[] stack = ["not"];
|
||||
var pm = new PathMatch(needle);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultiItemArrayMatching_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
string[] stack = ["not", needle, "far"];
|
||||
var pm = new PathMatch(needle);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal(needle, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultiItemArrayMismatched_NoMatch()
|
||||
{
|
||||
string needle = "test";
|
||||
string[] stack = ["not", "too", "far"];
|
||||
var pm = new PathMatch(needle);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region List
|
||||
|
||||
[Fact]
|
||||
public void NullList_NoMatch()
|
||||
{
|
||||
var pm = new PathMatch("test");
|
||||
string? actual = pm.Match((List<string>?)null);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyList_NoMatch()
|
||||
{
|
||||
var pm = new PathMatch("test");
|
||||
string? actual = pm.Match(new List<string>());
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SingleItemListMatching_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [needle];
|
||||
var pm = new PathMatch(needle);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal(needle, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SingleItemListMismatched_NoMatch()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = ["not"];
|
||||
var pm = new PathMatch(needle);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultiItemListMatching_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = ["not", needle, "far"];
|
||||
var pm = new PathMatch(needle);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal(needle, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultiItemListMismatched_NoMatch()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = ["not", "too", "far"];
|
||||
var pm = new PathMatch(needle);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Match Case
|
||||
|
||||
[Fact]
|
||||
public void MatchCaseEqual_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [needle];
|
||||
var pm = new PathMatch(needle, matchCase: true);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal(needle, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoMatchCaseEqual_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [needle];
|
||||
var pm = new PathMatch(needle, matchCase: false);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal(needle, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchCaseInequal_NoMatch()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [needle.ToUpperInvariant()];
|
||||
var pm = new PathMatch(needle, matchCase: true);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoMatchCaseInequal_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [needle.ToUpperInvariant()];
|
||||
var pm = new PathMatch(needle, matchCase: false);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal(needle.ToUpperInvariant(), actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MatchCaseContains_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [$"prefix_{needle}_postfix"];
|
||||
var pm = new PathMatch(needle, matchCase: true);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal($"prefix_{needle}_postfix", actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoMatchCaseContains_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [$"prefix_{needle}_postfix"];
|
||||
var pm = new PathMatch(needle, matchCase: false);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal($"prefix_{needle}_postfix", actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Use Ends With
|
||||
|
||||
[Fact]
|
||||
public void EndsWithEqual_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [needle];
|
||||
var pm = new PathMatch(needle, useEndsWith: true);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal(needle, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoEndsWithEqual_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [needle];
|
||||
var pm = new PathMatch(needle, useEndsWith: false);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal(needle, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWithInequal_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [needle.ToUpperInvariant()];
|
||||
var pm = new PathMatch(needle, useEndsWith: true);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal(needle.ToUpperInvariant(), actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoEndsWithInequal_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [needle.ToUpperInvariant()];
|
||||
var pm = new PathMatch(needle, useEndsWith: false);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal(needle.ToUpperInvariant(), actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWithContains_NoMatch()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [$"prefix_{needle}_postfix"];
|
||||
var pm = new PathMatch(needle, useEndsWith: true);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoEndsWithContains_Match()
|
||||
{
|
||||
string needle = "test";
|
||||
List<string> stack = [$"prefix_{needle}_postfix"];
|
||||
var pm = new PathMatch(needle, useEndsWith: false);
|
||||
|
||||
string? actual = pm.Match(stack);
|
||||
Assert.Equal($"prefix_{needle}_postfix", actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
249
SabreTools.IO.Test/Numerics/BothInt16Tests.cs
Normal file
249
SabreTools.IO.Test/Numerics/BothInt16Tests.cs
Normal file
@@ -0,0 +1,249 @@
|
||||
using System;
|
||||
using SabreTools.Numerics;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Numerics
|
||||
{
|
||||
public class BothInt16Tests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0, 0, true)]
|
||||
[InlineData(0, 1, false)]
|
||||
public void IsValidTest(short le, short be, bool expected)
|
||||
{
|
||||
var val = new BothInt16(le, be);
|
||||
|
||||
Assert.Equal(le, val.LittleEndian);
|
||||
Assert.Equal(be, val.BigEndian);
|
||||
Assert.Equal(expected, val.IsValid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImplicitConversionTest()
|
||||
{
|
||||
short expected = 1;
|
||||
var val = new BothInt16(expected, expected);
|
||||
|
||||
short to = (short)val;
|
||||
Assert.Equal(expected, to);
|
||||
|
||||
BothInt16 back = (BothInt16)to;
|
||||
Assert.Equal(expected, back.LittleEndian);
|
||||
Assert.Equal(expected, back.BigEndian);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, -1)]
|
||||
[InlineData(1, 0)]
|
||||
[InlineData(2, 1)]
|
||||
public void CompareToTest(short le, int expected)
|
||||
{
|
||||
short compare = 1;
|
||||
var val = new BothInt16(le, le);
|
||||
|
||||
int actual = val.CompareTo(compare);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTypeCodeTest()
|
||||
{
|
||||
TypeCode expected = ((short)1).GetTypeCode();
|
||||
|
||||
var val = new BothInt16(1, 1);
|
||||
Assert.Equal(expected, val.GetTypeCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTypesTest()
|
||||
{
|
||||
var val = new BothInt16(1, 1);
|
||||
|
||||
bool expectedBool = Convert.ToBoolean((short)1);
|
||||
Assert.Equal(expectedBool, val.ToBoolean(null));
|
||||
|
||||
char expectedChar = Convert.ToChar((short)1);
|
||||
Assert.Equal(expectedChar, val.ToChar(null));
|
||||
|
||||
sbyte expectedSByte = Convert.ToSByte((short)1);
|
||||
Assert.Equal(expectedSByte, val.ToSByte(null));
|
||||
|
||||
byte expectedByte = Convert.ToByte((short)1);
|
||||
Assert.Equal(expectedByte, val.ToByte(null));
|
||||
|
||||
short expectedInt16 = Convert.ToInt16((short)1);
|
||||
Assert.Equal(expectedInt16, val.ToInt16(null));
|
||||
|
||||
ushort expectedUInt16 = Convert.ToUInt16((short)1);
|
||||
Assert.Equal(expectedUInt16, val.ToUInt16(null));
|
||||
|
||||
int expectedInt32 = Convert.ToInt32((short)1);
|
||||
Assert.Equal(expectedInt32, val.ToInt32(null));
|
||||
|
||||
uint expectedUInt32 = Convert.ToUInt32((short)1);
|
||||
Assert.Equal(expectedUInt32, val.ToUInt32(null));
|
||||
|
||||
long expectedInt64 = Convert.ToInt64((short)1);
|
||||
Assert.Equal(expectedInt64, val.ToInt64(null));
|
||||
|
||||
ulong expectedUInt64 = Convert.ToUInt64((short)1);
|
||||
Assert.Equal(expectedUInt64, val.ToUInt64(null));
|
||||
|
||||
float expectedSingle = Convert.ToSingle((short)1);
|
||||
Assert.Equal(expectedSingle, val.ToSingle(null));
|
||||
|
||||
double expectedDouble = Convert.ToDouble((short)1);
|
||||
Assert.Equal(expectedDouble, val.ToDouble(null));
|
||||
|
||||
decimal expectedDecimal = Convert.ToDecimal((short)1);
|
||||
Assert.Equal(expectedDecimal, val.ToDecimal(null));
|
||||
|
||||
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
|
||||
|
||||
string expectedString = Convert.ToString((short)1);
|
||||
Assert.Equal(expectedString, val.ToString(null));
|
||||
|
||||
ulong expectedObject = Convert.ToUInt64((short)1);
|
||||
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(0, 1, false)]
|
||||
[InlineData(1, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BothEndian(short le, short be, bool expected)
|
||||
{
|
||||
var val = new BothInt16(le, be);
|
||||
var equalTo = new BothInt16(1, 1);
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BaseType(short le, short be, bool expected)
|
||||
{
|
||||
var val = new BothInt16(le, be);
|
||||
short equalTo = 1;
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt16(2, 2);
|
||||
short expected = 3;
|
||||
valA++;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothInt16(2, 2);
|
||||
expected = 1;
|
||||
valA--;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothInt16(2, 2);
|
||||
expected = 2;
|
||||
BothInt16 actual = +valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = -2;
|
||||
actual = -valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt16(3, 3);
|
||||
var valB = new BothInt16(2, 2);
|
||||
|
||||
short expected = 6;
|
||||
BothInt16 actual = valA * valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA / valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA % valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 5;
|
||||
actual = valA + valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA - valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt16(2, 2);
|
||||
short expected = ~2;
|
||||
BothInt16 actual = ~valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShiftBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt16(2, 2);
|
||||
var valB = new BothInt16(1, 1);
|
||||
|
||||
short expected = 2 << 1;
|
||||
BothInt16 actual = valA << valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >> 1;
|
||||
actual = valA >> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >>> 1;
|
||||
actual = valA >>> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt16(3, 3);
|
||||
var valB = new BothInt16(2, 2);
|
||||
|
||||
short expected = 3 & 2;
|
||||
BothInt16 actual = valA & valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 | 2;
|
||||
actual = valA | valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 ^ 2;
|
||||
actual = valA ^ valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
}
|
||||
}
|
||||
249
SabreTools.IO.Test/Numerics/BothInt32Tests.cs
Normal file
249
SabreTools.IO.Test/Numerics/BothInt32Tests.cs
Normal file
@@ -0,0 +1,249 @@
|
||||
using System;
|
||||
using SabreTools.Numerics;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Numerics
|
||||
{
|
||||
public class BothInt32Tests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0, 0, true)]
|
||||
[InlineData(0, 1, false)]
|
||||
public void IsValidTest(int le, int be, bool expected)
|
||||
{
|
||||
var val = new BothInt32(le, be);
|
||||
|
||||
Assert.Equal(le, val.LittleEndian);
|
||||
Assert.Equal(be, val.BigEndian);
|
||||
Assert.Equal(expected, val.IsValid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImplicitConversionTest()
|
||||
{
|
||||
int expected = 1;
|
||||
var val = new BothInt32(expected, expected);
|
||||
|
||||
int to = (int)val;
|
||||
Assert.Equal(expected, to);
|
||||
|
||||
BothInt32 back = (BothInt32)to;
|
||||
Assert.Equal(expected, back.LittleEndian);
|
||||
Assert.Equal(expected, back.BigEndian);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, -1)]
|
||||
[InlineData(1, 0)]
|
||||
[InlineData(2, 1)]
|
||||
public void CompareToTest(int le, int expected)
|
||||
{
|
||||
int compare = 1;
|
||||
var val = new BothInt32(le, le);
|
||||
|
||||
int actual = val.CompareTo(compare);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTypeCodeTest()
|
||||
{
|
||||
TypeCode expected = 1.GetTypeCode();
|
||||
|
||||
var val = new BothInt32(1, 1);
|
||||
Assert.Equal(expected, val.GetTypeCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTypesTest()
|
||||
{
|
||||
var val = new BothInt32(1, 1);
|
||||
|
||||
bool expectedBool = Convert.ToBoolean(1);
|
||||
Assert.Equal(expectedBool, val.ToBoolean(null));
|
||||
|
||||
char expectedChar = Convert.ToChar(1);
|
||||
Assert.Equal(expectedChar, val.ToChar(null));
|
||||
|
||||
sbyte expectedSByte = Convert.ToSByte(1);
|
||||
Assert.Equal(expectedSByte, val.ToSByte(null));
|
||||
|
||||
byte expectedByte = Convert.ToByte(1);
|
||||
Assert.Equal(expectedByte, val.ToByte(null));
|
||||
|
||||
short expectedInt16 = Convert.ToInt16(1);
|
||||
Assert.Equal(expectedInt16, val.ToInt16(null));
|
||||
|
||||
ushort expectedUInt16 = Convert.ToUInt16(1);
|
||||
Assert.Equal(expectedUInt16, val.ToUInt16(null));
|
||||
|
||||
int expectedInt32 = Convert.ToInt32(1);
|
||||
Assert.Equal(expectedInt32, val.ToInt32(null));
|
||||
|
||||
uint expectedUInt32 = Convert.ToUInt32(1);
|
||||
Assert.Equal(expectedUInt32, val.ToUInt32(null));
|
||||
|
||||
long expectedInt64 = Convert.ToInt64(1);
|
||||
Assert.Equal(expectedInt64, val.ToInt64(null));
|
||||
|
||||
ulong expectedUInt64 = Convert.ToUInt64(1);
|
||||
Assert.Equal(expectedUInt64, val.ToUInt64(null));
|
||||
|
||||
float expectedSingle = Convert.ToSingle(1);
|
||||
Assert.Equal(expectedSingle, val.ToSingle(null));
|
||||
|
||||
double expectedDouble = Convert.ToDouble(1);
|
||||
Assert.Equal(expectedDouble, val.ToDouble(null));
|
||||
|
||||
decimal expectedDecimal = Convert.ToDecimal(1);
|
||||
Assert.Equal(expectedDecimal, val.ToDecimal(null));
|
||||
|
||||
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
|
||||
|
||||
string expectedString = Convert.ToString(1);
|
||||
Assert.Equal(expectedString, val.ToString(null));
|
||||
|
||||
ulong expectedObject = Convert.ToUInt64(1);
|
||||
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(0, 1, false)]
|
||||
[InlineData(1, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BothEndian(int le, int be, bool expected)
|
||||
{
|
||||
var val = new BothInt32(le, be);
|
||||
var equalTo = new BothInt32(1, 1);
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BaseType(int le, int be, bool expected)
|
||||
{
|
||||
var val = new BothInt32(le, be);
|
||||
int equalTo = 1;
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt32(2, 2);
|
||||
int expected = 3;
|
||||
valA++;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothInt32(2, 2);
|
||||
expected = 1;
|
||||
valA--;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothInt32(2, 2);
|
||||
expected = 2;
|
||||
BothInt32 actual = +valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = -2;
|
||||
actual = -valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt32(3, 3);
|
||||
var valB = new BothInt32(2, 2);
|
||||
|
||||
int expected = 6;
|
||||
BothInt32 actual = valA * valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA / valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA % valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 5;
|
||||
actual = valA + valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA - valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt32(2, 2);
|
||||
int expected = ~2;
|
||||
BothInt32 actual = ~valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShiftBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt32(2, 2);
|
||||
var valB = new BothInt32(1, 1);
|
||||
|
||||
int expected = 2 << 1;
|
||||
BothInt32 actual = valA << valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >> 1;
|
||||
actual = valA >> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >>> 1;
|
||||
actual = valA >>> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt32(3, 3);
|
||||
var valB = new BothInt32(2, 2);
|
||||
|
||||
int expected = 3 & 2;
|
||||
BothInt32 actual = valA & valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 | 2;
|
||||
actual = valA | valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 ^ 2;
|
||||
actual = valA ^ valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
}
|
||||
}
|
||||
249
SabreTools.IO.Test/Numerics/BothInt64Tests.cs
Normal file
249
SabreTools.IO.Test/Numerics/BothInt64Tests.cs
Normal file
@@ -0,0 +1,249 @@
|
||||
using System;
|
||||
using SabreTools.Numerics;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Numerics
|
||||
{
|
||||
public class BothInt64Tests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0, 0, true)]
|
||||
[InlineData(0, 1, false)]
|
||||
public void IsValidTest(long le, long be, bool expected)
|
||||
{
|
||||
var val = new BothInt64(le, be);
|
||||
|
||||
Assert.Equal(le, val.LittleEndian);
|
||||
Assert.Equal(be, val.BigEndian);
|
||||
Assert.Equal(expected, val.IsValid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImplicitConversionTest()
|
||||
{
|
||||
long expected = 1;
|
||||
var val = new BothInt64(expected, expected);
|
||||
|
||||
long to = (long)val;
|
||||
Assert.Equal(expected, to);
|
||||
|
||||
BothInt64 back = (BothInt64)to;
|
||||
Assert.Equal(expected, back.LittleEndian);
|
||||
Assert.Equal(expected, back.BigEndian);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, -1)]
|
||||
[InlineData(1, 0)]
|
||||
[InlineData(2, 1)]
|
||||
public void CompareToTest(long le, int expected)
|
||||
{
|
||||
long compare = 1;
|
||||
var val = new BothInt64(le, le);
|
||||
|
||||
int actual = val.CompareTo(compare);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTypeCodeTest()
|
||||
{
|
||||
TypeCode expected = ((long)1).GetTypeCode();
|
||||
|
||||
var val = new BothInt64(1, 1);
|
||||
Assert.Equal(expected, val.GetTypeCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTypesTest()
|
||||
{
|
||||
var val = new BothInt64(1, 1);
|
||||
|
||||
bool expectedBool = Convert.ToBoolean((long)1);
|
||||
Assert.Equal(expectedBool, val.ToBoolean(null));
|
||||
|
||||
char expectedChar = Convert.ToChar((long)1);
|
||||
Assert.Equal(expectedChar, val.ToChar(null));
|
||||
|
||||
sbyte expectedSByte = Convert.ToSByte((long)1);
|
||||
Assert.Equal(expectedSByte, val.ToSByte(null));
|
||||
|
||||
byte expectedByte = Convert.ToByte((long)1);
|
||||
Assert.Equal(expectedByte, val.ToByte(null));
|
||||
|
||||
short expectedInt16 = Convert.ToInt16((long)1);
|
||||
Assert.Equal(expectedInt16, val.ToInt16(null));
|
||||
|
||||
ushort expectedUInt16 = Convert.ToUInt16((long)1);
|
||||
Assert.Equal(expectedUInt16, val.ToUInt16(null));
|
||||
|
||||
int expectedInt32 = Convert.ToInt32((long)1);
|
||||
Assert.Equal(expectedInt32, val.ToInt32(null));
|
||||
|
||||
uint expectedUInt32 = Convert.ToUInt32((long)1);
|
||||
Assert.Equal(expectedUInt32, val.ToUInt32(null));
|
||||
|
||||
long expectedInt64 = Convert.ToInt64((long)1);
|
||||
Assert.Equal(expectedInt64, val.ToInt64(null));
|
||||
|
||||
ulong expectedUInt64 = Convert.ToUInt64((long)1);
|
||||
Assert.Equal(expectedUInt64, val.ToUInt64(null));
|
||||
|
||||
float expectedSingle = Convert.ToSingle((long)1);
|
||||
Assert.Equal(expectedSingle, val.ToSingle(null));
|
||||
|
||||
double expectedDouble = Convert.ToDouble((long)1);
|
||||
Assert.Equal(expectedDouble, val.ToDouble(null));
|
||||
|
||||
decimal expectedDecimal = Convert.ToDecimal((long)1);
|
||||
Assert.Equal(expectedDecimal, val.ToDecimal(null));
|
||||
|
||||
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
|
||||
|
||||
string expectedString = Convert.ToString((long)1);
|
||||
Assert.Equal(expectedString, val.ToString(null));
|
||||
|
||||
ulong expectedObject = Convert.ToUInt64((long)1);
|
||||
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(0, 1, false)]
|
||||
[InlineData(1, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BothEndian(long le, long be, bool expected)
|
||||
{
|
||||
var val = new BothInt64(le, be);
|
||||
var equalTo = new BothInt64(1, 1);
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BaseType(long le, long be, bool expected)
|
||||
{
|
||||
var val = new BothInt64(le, be);
|
||||
long equalTo = 1;
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt64(2, 2);
|
||||
long expected = 3;
|
||||
valA++;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothInt64(2, 2);
|
||||
expected = 1;
|
||||
valA--;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothInt64(2, 2);
|
||||
expected = 2;
|
||||
BothInt64 actual = +valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = -2;
|
||||
actual = -valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt64(3, 3);
|
||||
var valB = new BothInt64(2, 2);
|
||||
|
||||
long expected = 6;
|
||||
BothInt64 actual = valA * valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA / valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA % valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 5;
|
||||
actual = valA + valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA - valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt64(2, 2);
|
||||
long expected = ~2;
|
||||
BothInt64 actual = ~valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShiftBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt64(2, 2);
|
||||
var valB = new BothInt32(1, 1);
|
||||
|
||||
long expected = 2 << 1;
|
||||
BothInt64 actual = valA << valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >> 1;
|
||||
actual = valA >> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >>> 1;
|
||||
actual = valA >>> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt64(3, 3);
|
||||
var valB = new BothInt64(2, 2);
|
||||
|
||||
long expected = 3 & 2;
|
||||
BothInt64 actual = valA & valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 | 2;
|
||||
actual = valA | valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 ^ 2;
|
||||
actual = valA ^ valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
}
|
||||
}
|
||||
249
SabreTools.IO.Test/Numerics/BothInt8Tests.cs
Normal file
249
SabreTools.IO.Test/Numerics/BothInt8Tests.cs
Normal file
@@ -0,0 +1,249 @@
|
||||
using System;
|
||||
using SabreTools.Numerics;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Numerics
|
||||
{
|
||||
public class BothInt8Tests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0, 0, true)]
|
||||
[InlineData(0, 1, false)]
|
||||
public void IsValidTest(sbyte le, sbyte be, bool expected)
|
||||
{
|
||||
var val = new BothInt8(le, be);
|
||||
|
||||
Assert.Equal(le, val.LittleEndian);
|
||||
Assert.Equal(be, val.BigEndian);
|
||||
Assert.Equal(expected, val.IsValid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImplicitConversionTest()
|
||||
{
|
||||
sbyte expected = 1;
|
||||
var val = new BothInt8(expected, expected);
|
||||
|
||||
sbyte to = (sbyte)val;
|
||||
Assert.Equal(expected, to);
|
||||
|
||||
BothInt8 back = (BothInt8)to;
|
||||
Assert.Equal(expected, back.LittleEndian);
|
||||
Assert.Equal(expected, back.BigEndian);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, -1)]
|
||||
[InlineData(1, 0)]
|
||||
[InlineData(2, 1)]
|
||||
public void CompareToTest(sbyte le, int expected)
|
||||
{
|
||||
sbyte compare = 1;
|
||||
var val = new BothInt8(le, le);
|
||||
|
||||
int actual = val.CompareTo(compare);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTypeCodeTest()
|
||||
{
|
||||
TypeCode expected = ((sbyte)1).GetTypeCode();
|
||||
|
||||
var val = new BothInt8(1, 1);
|
||||
Assert.Equal(expected, val.GetTypeCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTypesTest()
|
||||
{
|
||||
var val = new BothInt8(1, 1);
|
||||
|
||||
bool expectedBool = Convert.ToBoolean((sbyte)1);
|
||||
Assert.Equal(expectedBool, val.ToBoolean(null));
|
||||
|
||||
char expectedChar = Convert.ToChar((sbyte)1);
|
||||
Assert.Equal(expectedChar, val.ToChar(null));
|
||||
|
||||
sbyte expectedSByte = Convert.ToSByte((sbyte)1);
|
||||
Assert.Equal(expectedSByte, val.ToSByte(null));
|
||||
|
||||
byte expectedByte = Convert.ToByte((sbyte)1);
|
||||
Assert.Equal(expectedByte, val.ToByte(null));
|
||||
|
||||
short expectedInt16 = Convert.ToInt16((sbyte)1);
|
||||
Assert.Equal(expectedInt16, val.ToInt16(null));
|
||||
|
||||
ushort expectedUInt16 = Convert.ToUInt16((sbyte)1);
|
||||
Assert.Equal(expectedUInt16, val.ToUInt16(null));
|
||||
|
||||
int expectedInt32 = Convert.ToInt32((sbyte)1);
|
||||
Assert.Equal(expectedInt32, val.ToInt32(null));
|
||||
|
||||
uint expectedUInt32 = Convert.ToUInt32((sbyte)1);
|
||||
Assert.Equal(expectedUInt32, val.ToUInt32(null));
|
||||
|
||||
long expectedInt64 = Convert.ToInt64((sbyte)1);
|
||||
Assert.Equal(expectedInt64, val.ToInt64(null));
|
||||
|
||||
ulong expectedUInt64 = Convert.ToUInt64((sbyte)1);
|
||||
Assert.Equal(expectedUInt64, val.ToUInt64(null));
|
||||
|
||||
float expectedSingle = Convert.ToSingle((sbyte)1);
|
||||
Assert.Equal(expectedSingle, val.ToSingle(null));
|
||||
|
||||
double expectedDouble = Convert.ToDouble((sbyte)1);
|
||||
Assert.Equal(expectedDouble, val.ToDouble(null));
|
||||
|
||||
decimal expectedDecimal = Convert.ToDecimal((sbyte)1);
|
||||
Assert.Equal(expectedDecimal, val.ToDecimal(null));
|
||||
|
||||
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
|
||||
|
||||
string expectedString = Convert.ToString((sbyte)1);
|
||||
Assert.Equal(expectedString, val.ToString(null));
|
||||
|
||||
ulong expectedObject = Convert.ToUInt64((sbyte)1);
|
||||
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(0, 1, false)]
|
||||
[InlineData(1, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BothEndian(sbyte le, sbyte be, bool expected)
|
||||
{
|
||||
var val = new BothInt8(le, be);
|
||||
var equalTo = new BothInt8(1, 1);
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BaseType(sbyte le, sbyte be, bool expected)
|
||||
{
|
||||
var val = new BothInt8(le, be);
|
||||
sbyte equalTo = 1;
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt8(2, 2);
|
||||
sbyte expected = 3;
|
||||
valA++;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothInt8(2, 2);
|
||||
expected = 1;
|
||||
valA--;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothInt8(2, 2);
|
||||
expected = 2;
|
||||
BothInt8 actual = +valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = -2;
|
||||
actual = -valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt8(3, 3);
|
||||
var valB = new BothInt8(2, 2);
|
||||
|
||||
sbyte expected = 6;
|
||||
BothInt8 actual = valA * valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA / valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA % valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 5;
|
||||
actual = valA + valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA - valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt8(2, 2);
|
||||
sbyte expected = ~2;
|
||||
BothInt8 actual = ~valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShiftBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt8(2, 2);
|
||||
var valB = new BothInt8(1, 1);
|
||||
|
||||
sbyte expected = 2 << 1;
|
||||
BothInt8 actual = valA << valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >> 1;
|
||||
actual = valA >> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >>> 1;
|
||||
actual = valA >>> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothInt8(3, 3);
|
||||
var valB = new BothInt8(2, 2);
|
||||
|
||||
sbyte expected = 3 & 2;
|
||||
BothInt8 actual = valA & valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 | 2;
|
||||
actual = valA | valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 ^ 2;
|
||||
actual = valA ^ valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
}
|
||||
}
|
||||
238
SabreTools.IO.Test/Numerics/BothUInt16Tests.cs
Normal file
238
SabreTools.IO.Test/Numerics/BothUInt16Tests.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
using System;
|
||||
using SabreTools.Numerics;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Numerics
|
||||
{
|
||||
public class BothUInt16Tests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0, 0, true)]
|
||||
[InlineData(0, 1, false)]
|
||||
public void IsValidTest(ushort le, ushort be, bool expected)
|
||||
{
|
||||
var val = new BothUInt16(le, be);
|
||||
|
||||
Assert.Equal(le, val.LittleEndian);
|
||||
Assert.Equal(be, val.BigEndian);
|
||||
Assert.Equal(expected, val.IsValid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImplicitConversionTest()
|
||||
{
|
||||
ushort expected = 1;
|
||||
var val = new BothUInt16(expected, expected);
|
||||
|
||||
ushort to = (ushort)val;
|
||||
Assert.Equal(expected, to);
|
||||
|
||||
BothUInt16 back = (BothUInt16)to;
|
||||
Assert.Equal(expected, back.LittleEndian);
|
||||
Assert.Equal(expected, back.BigEndian);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, -1)]
|
||||
[InlineData(1, 0)]
|
||||
[InlineData(2, 1)]
|
||||
public void CompareToTest(ushort le, int expected)
|
||||
{
|
||||
ushort compare = 1;
|
||||
var val = new BothUInt16(le, le);
|
||||
|
||||
int actual = val.CompareTo(compare);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTypeCodeTest()
|
||||
{
|
||||
TypeCode expected = ((ushort)1).GetTypeCode();
|
||||
|
||||
var val = new BothUInt16(1, 1);
|
||||
Assert.Equal(expected, val.GetTypeCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTypesTest()
|
||||
{
|
||||
var val = new BothUInt16(1, 1);
|
||||
|
||||
bool expectedBool = Convert.ToBoolean((ushort)1);
|
||||
Assert.Equal(expectedBool, val.ToBoolean(null));
|
||||
|
||||
char expectedChar = Convert.ToChar((ushort)1);
|
||||
Assert.Equal(expectedChar, val.ToChar(null));
|
||||
|
||||
sbyte expectedSByte = Convert.ToSByte((ushort)1);
|
||||
Assert.Equal(expectedSByte, val.ToSByte(null));
|
||||
|
||||
byte expectedByte = Convert.ToByte((ushort)1);
|
||||
Assert.Equal(expectedByte, val.ToByte(null));
|
||||
|
||||
short expectedInt16 = Convert.ToInt16((ushort)1);
|
||||
Assert.Equal(expectedInt16, val.ToInt16(null));
|
||||
|
||||
ushort expectedUInt16 = Convert.ToUInt16((ushort)1);
|
||||
Assert.Equal(expectedUInt16, val.ToUInt16(null));
|
||||
|
||||
int expectedInt32 = Convert.ToInt32((ushort)1);
|
||||
Assert.Equal(expectedInt32, val.ToInt32(null));
|
||||
|
||||
uint expectedUInt32 = Convert.ToUInt32((ushort)1);
|
||||
Assert.Equal(expectedUInt32, val.ToUInt32(null));
|
||||
|
||||
long expectedInt64 = Convert.ToInt64((ushort)1);
|
||||
Assert.Equal(expectedInt64, val.ToInt64(null));
|
||||
|
||||
ulong expectedUInt64 = Convert.ToUInt64((ushort)1);
|
||||
Assert.Equal(expectedUInt64, val.ToUInt64(null));
|
||||
|
||||
float expectedSingle = Convert.ToSingle((ushort)1);
|
||||
Assert.Equal(expectedSingle, val.ToSingle(null));
|
||||
|
||||
double expectedDouble = Convert.ToDouble((ushort)1);
|
||||
Assert.Equal(expectedDouble, val.ToDouble(null));
|
||||
|
||||
decimal expectedDecimal = Convert.ToDecimal((ushort)1);
|
||||
Assert.Equal(expectedDecimal, val.ToDecimal(null));
|
||||
|
||||
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
|
||||
|
||||
string expectedString = Convert.ToString((ushort)1);
|
||||
Assert.Equal(expectedString, val.ToString(null));
|
||||
|
||||
ulong expectedObject = Convert.ToUInt64((ushort)1);
|
||||
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(0, 1, false)]
|
||||
[InlineData(1, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BothEndian(ushort le, ushort be, bool expected)
|
||||
{
|
||||
var val = new BothUInt16(le, be);
|
||||
var equalTo = new BothUInt16(1, 1);
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BaseType(ushort le, ushort be, bool expected)
|
||||
{
|
||||
var val = new BothUInt16(le, be);
|
||||
ushort equalTo = 1;
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt16(2, 2);
|
||||
ushort expected = 3;
|
||||
valA++;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothUInt16(2, 2);
|
||||
expected = 1;
|
||||
valA--;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt16(3, 3);
|
||||
var valB = new BothUInt16(2, 2);
|
||||
|
||||
ushort expected = 6;
|
||||
BothUInt16 actual = valA * valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA / valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA % valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 5;
|
||||
actual = valA + valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA - valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt16(2, 2);
|
||||
ushort expected = 65533;
|
||||
BothUInt16 actual = ~valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShiftBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt16(2, 2);
|
||||
var valB = new BothUInt16(1, 1);
|
||||
|
||||
ushort expected = 2 << 1;
|
||||
BothUInt16 actual = valA << valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >> 1;
|
||||
actual = valA >> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >>> 1;
|
||||
actual = valA >>> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt16(3, 3);
|
||||
var valB = new BothUInt16(2, 2);
|
||||
|
||||
ushort expected = 3 & 2;
|
||||
BothUInt16 actual = valA & valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 | 2;
|
||||
actual = valA | valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 ^ 2;
|
||||
actual = valA ^ valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
}
|
||||
}
|
||||
238
SabreTools.IO.Test/Numerics/BothUInt32Tests.cs
Normal file
238
SabreTools.IO.Test/Numerics/BothUInt32Tests.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
using System;
|
||||
using SabreTools.Numerics;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Numerics
|
||||
{
|
||||
public class BothUInt32Tests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0, 0, true)]
|
||||
[InlineData(0, 1, false)]
|
||||
public void IsValidTest(uint le, uint be, bool expected)
|
||||
{
|
||||
var val = new BothUInt32(le, be);
|
||||
|
||||
Assert.Equal(le, val.LittleEndian);
|
||||
Assert.Equal(be, val.BigEndian);
|
||||
Assert.Equal(expected, val.IsValid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImplicitConversionTest()
|
||||
{
|
||||
uint expected = 1;
|
||||
var val = new BothUInt32(expected, expected);
|
||||
|
||||
uint to = (uint)val;
|
||||
Assert.Equal(expected, to);
|
||||
|
||||
BothUInt32 back = (BothUInt32)to;
|
||||
Assert.Equal(expected, back.LittleEndian);
|
||||
Assert.Equal(expected, back.BigEndian);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, -1)]
|
||||
[InlineData(1, 0)]
|
||||
[InlineData(2, 1)]
|
||||
public void CompareToTest(uint le, int expected)
|
||||
{
|
||||
uint compare = 1;
|
||||
var val = new BothUInt32(le, le);
|
||||
|
||||
int actual = val.CompareTo(compare);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTypeCodeTest()
|
||||
{
|
||||
TypeCode expected = ((uint)1).GetTypeCode();
|
||||
|
||||
var val = new BothUInt32(1, 1);
|
||||
Assert.Equal(expected, val.GetTypeCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTypesTest()
|
||||
{
|
||||
var val = new BothUInt32(1, 1);
|
||||
|
||||
bool expectedBool = Convert.ToBoolean((uint)1);
|
||||
Assert.Equal(expectedBool, val.ToBoolean(null));
|
||||
|
||||
char expectedChar = Convert.ToChar((uint)1);
|
||||
Assert.Equal(expectedChar, val.ToChar(null));
|
||||
|
||||
sbyte expectedSByte = Convert.ToSByte((uint)1);
|
||||
Assert.Equal(expectedSByte, val.ToSByte(null));
|
||||
|
||||
byte expectedByte = Convert.ToByte((uint)1);
|
||||
Assert.Equal(expectedByte, val.ToByte(null));
|
||||
|
||||
short expectedInt16 = Convert.ToInt16((uint)1);
|
||||
Assert.Equal(expectedInt16, val.ToInt16(null));
|
||||
|
||||
ushort expectedUInt16 = Convert.ToUInt16((uint)1);
|
||||
Assert.Equal(expectedUInt16, val.ToUInt16(null));
|
||||
|
||||
int expectedInt32 = Convert.ToInt32((uint)1);
|
||||
Assert.Equal(expectedInt32, val.ToInt32(null));
|
||||
|
||||
uint expectedUInt32 = Convert.ToUInt32((uint)1);
|
||||
Assert.Equal(expectedUInt32, val.ToUInt32(null));
|
||||
|
||||
long expectedInt64 = Convert.ToInt64((uint)1);
|
||||
Assert.Equal(expectedInt64, val.ToInt64(null));
|
||||
|
||||
ulong expectedUInt64 = Convert.ToUInt64((uint)1);
|
||||
Assert.Equal(expectedUInt64, val.ToUInt64(null));
|
||||
|
||||
float expectedSingle = Convert.ToSingle((uint)1);
|
||||
Assert.Equal(expectedSingle, val.ToSingle(null));
|
||||
|
||||
double expectedDouble = Convert.ToDouble((uint)1);
|
||||
Assert.Equal(expectedDouble, val.ToDouble(null));
|
||||
|
||||
decimal expectedDecimal = Convert.ToDecimal((uint)1);
|
||||
Assert.Equal(expectedDecimal, val.ToDecimal(null));
|
||||
|
||||
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
|
||||
|
||||
string expectedString = Convert.ToString((uint)1);
|
||||
Assert.Equal(expectedString, val.ToString(null));
|
||||
|
||||
ulong expectedObject = Convert.ToUInt64((uint)1);
|
||||
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(0, 1, false)]
|
||||
[InlineData(1, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BothEndian(uint le, uint be, bool expected)
|
||||
{
|
||||
var val = new BothUInt32(le, be);
|
||||
var equalTo = new BothUInt32(1, 1);
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BaseType(uint le, uint be, bool expected)
|
||||
{
|
||||
var val = new BothUInt32(le, be);
|
||||
uint equalTo = 1;
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt32(2, 2);
|
||||
uint expected = 3;
|
||||
valA++;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothUInt32(2, 2);
|
||||
expected = 1;
|
||||
valA--;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt32(3, 3);
|
||||
var valB = new BothUInt32(2, 2);
|
||||
|
||||
uint expected = 6;
|
||||
BothUInt32 actual = valA * valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA / valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA % valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 5;
|
||||
actual = valA + valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA - valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt32(2, 2);
|
||||
uint expected = ~(uint)2;
|
||||
BothUInt32 actual = ~valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShiftBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt32(2, 2);
|
||||
var valB = new BothInt32(1, 1);
|
||||
|
||||
uint expected = 2 << 1;
|
||||
BothUInt32 actual = valA << valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >> 1;
|
||||
actual = valA >> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >>> 1;
|
||||
actual = valA >>> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt32(3, 3);
|
||||
var valB = new BothUInt32(2, 2);
|
||||
|
||||
uint expected = 3 & 2;
|
||||
BothUInt32 actual = valA & valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 | 2;
|
||||
actual = valA | valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 ^ 2;
|
||||
actual = valA ^ valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
}
|
||||
}
|
||||
238
SabreTools.IO.Test/Numerics/BothUInt64Tests.cs
Normal file
238
SabreTools.IO.Test/Numerics/BothUInt64Tests.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
using System;
|
||||
using SabreTools.Numerics;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Numerics
|
||||
{
|
||||
public class BothUInt64Tests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0, 0, true)]
|
||||
[InlineData(0, 1, false)]
|
||||
public void IsValidTest(ulong le, ulong be, bool expected)
|
||||
{
|
||||
var val = new BothUInt64(le, be);
|
||||
|
||||
Assert.Equal(le, val.LittleEndian);
|
||||
Assert.Equal(be, val.BigEndian);
|
||||
Assert.Equal(expected, val.IsValid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImplicitConversionTest()
|
||||
{
|
||||
ulong expected = 1;
|
||||
var val = new BothUInt64(expected, expected);
|
||||
|
||||
ulong to = (ulong)val;
|
||||
Assert.Equal(expected, to);
|
||||
|
||||
BothUInt64 back = (BothUInt64)to;
|
||||
Assert.Equal(expected, back.LittleEndian);
|
||||
Assert.Equal(expected, back.BigEndian);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, -1)]
|
||||
[InlineData(1, 0)]
|
||||
[InlineData(2, 1)]
|
||||
public void CompareToTest(ulong le, int expected)
|
||||
{
|
||||
ulong compare = 1;
|
||||
var val = new BothUInt64(le, le);
|
||||
|
||||
int actual = val.CompareTo(compare);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTypeCodeTest()
|
||||
{
|
||||
TypeCode expected = ((ulong)1).GetTypeCode();
|
||||
|
||||
var val = new BothUInt64(1, 1);
|
||||
Assert.Equal(expected, val.GetTypeCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTypesTest()
|
||||
{
|
||||
var val = new BothUInt64(1, 1);
|
||||
|
||||
bool expectedBool = Convert.ToBoolean((ulong)1);
|
||||
Assert.Equal(expectedBool, val.ToBoolean(null));
|
||||
|
||||
char expectedChar = Convert.ToChar((ulong)1);
|
||||
Assert.Equal(expectedChar, val.ToChar(null));
|
||||
|
||||
sbyte expectedSByte = Convert.ToSByte((ulong)1);
|
||||
Assert.Equal(expectedSByte, val.ToSByte(null));
|
||||
|
||||
byte expectedByte = Convert.ToByte((ulong)1);
|
||||
Assert.Equal(expectedByte, val.ToByte(null));
|
||||
|
||||
short expectedInt16 = Convert.ToInt16((ulong)1);
|
||||
Assert.Equal(expectedInt16, val.ToInt16(null));
|
||||
|
||||
ushort expectedUInt16 = Convert.ToUInt16((ulong)1);
|
||||
Assert.Equal(expectedUInt16, val.ToUInt16(null));
|
||||
|
||||
int expectedInt32 = Convert.ToInt32((ulong)1);
|
||||
Assert.Equal(expectedInt32, val.ToInt32(null));
|
||||
|
||||
uint expectedUInt32 = Convert.ToUInt32((ulong)1);
|
||||
Assert.Equal(expectedUInt32, val.ToUInt32(null));
|
||||
|
||||
long expectedInt64 = Convert.ToInt64((ulong)1);
|
||||
Assert.Equal(expectedInt64, val.ToInt64(null));
|
||||
|
||||
ulong expectedUInt64 = Convert.ToUInt64((ulong)1);
|
||||
Assert.Equal(expectedUInt64, val.ToUInt64(null));
|
||||
|
||||
float expectedSingle = Convert.ToSingle((ulong)1);
|
||||
Assert.Equal(expectedSingle, val.ToSingle(null));
|
||||
|
||||
double expectedDouble = Convert.ToDouble((ulong)1);
|
||||
Assert.Equal(expectedDouble, val.ToDouble(null));
|
||||
|
||||
decimal expectedDecimal = Convert.ToDecimal((ulong)1);
|
||||
Assert.Equal(expectedDecimal, val.ToDecimal(null));
|
||||
|
||||
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
|
||||
|
||||
string expectedString = Convert.ToString((ulong)1);
|
||||
Assert.Equal(expectedString, val.ToString(null));
|
||||
|
||||
ulong expectedObject = Convert.ToUInt64((ulong)1);
|
||||
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(0, 1, false)]
|
||||
[InlineData(1, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BothEndian(ulong le, ulong be, bool expected)
|
||||
{
|
||||
var val = new BothUInt64(le, be);
|
||||
var equalTo = new BothUInt64(1, 1);
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BaseType(ulong le, ulong be, bool expected)
|
||||
{
|
||||
var val = new BothUInt64(le, be);
|
||||
ulong equalTo = 1;
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt64(2, 2);
|
||||
ulong expected = 3;
|
||||
valA++;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothUInt64(2, 2);
|
||||
expected = 1;
|
||||
valA--;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt64(3, 3);
|
||||
var valB = new BothUInt64(2, 2);
|
||||
|
||||
ulong expected = 6;
|
||||
BothUInt64 actual = valA * valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA / valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA % valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 5;
|
||||
actual = valA + valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA - valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt64(2, 2);
|
||||
ulong expected = ~(ulong)2;
|
||||
BothUInt64 actual = ~valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShiftBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt64(2, 2);
|
||||
var valB = new BothInt32(1, 1);
|
||||
|
||||
ulong expected = 2 << 1;
|
||||
BothUInt64 actual = valA << valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >> 1;
|
||||
actual = valA >> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >>> 1;
|
||||
actual = valA >>> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt64(3, 3);
|
||||
var valB = new BothUInt64(2, 2);
|
||||
|
||||
ulong expected = 3 & 2;
|
||||
BothUInt64 actual = valA & valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 | 2;
|
||||
actual = valA | valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 ^ 2;
|
||||
actual = valA ^ valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
}
|
||||
}
|
||||
238
SabreTools.IO.Test/Numerics/BothUInt8Tests.cs
Normal file
238
SabreTools.IO.Test/Numerics/BothUInt8Tests.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
using System;
|
||||
using SabreTools.Numerics;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Numerics
|
||||
{
|
||||
public class BothUInt8Tests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0, 0, true)]
|
||||
[InlineData(0, 1, false)]
|
||||
public void IsValidTest(byte le, byte be, bool expected)
|
||||
{
|
||||
var val = new BothUInt8(le, be);
|
||||
|
||||
Assert.Equal(le, val.LittleEndian);
|
||||
Assert.Equal(be, val.BigEndian);
|
||||
Assert.Equal(expected, val.IsValid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImplicitConversionTest()
|
||||
{
|
||||
byte expected = 1;
|
||||
var val = new BothUInt8(expected, expected);
|
||||
|
||||
byte to = (byte)val;
|
||||
Assert.Equal(expected, to);
|
||||
|
||||
BothUInt8 back = (BothUInt8)to;
|
||||
Assert.Equal(expected, back.LittleEndian);
|
||||
Assert.Equal(expected, back.BigEndian);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, -1)]
|
||||
[InlineData(1, 0)]
|
||||
[InlineData(2, 1)]
|
||||
public void CompareToTest(byte le, int expected)
|
||||
{
|
||||
byte compare = 1;
|
||||
var val = new BothUInt8(le, le);
|
||||
|
||||
int actual = val.CompareTo(compare);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTypeCodeTest()
|
||||
{
|
||||
TypeCode expected = ((byte)1).GetTypeCode();
|
||||
|
||||
var val = new BothUInt8(1, 1);
|
||||
Assert.Equal(expected, val.GetTypeCode());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToTypesTest()
|
||||
{
|
||||
var val = new BothUInt8(1, 1);
|
||||
|
||||
bool expectedBool = Convert.ToBoolean((byte)1);
|
||||
Assert.Equal(expectedBool, val.ToBoolean(null));
|
||||
|
||||
char expectedChar = Convert.ToChar((byte)1);
|
||||
Assert.Equal(expectedChar, val.ToChar(null));
|
||||
|
||||
sbyte expectedSByte = Convert.ToSByte((byte)1);
|
||||
Assert.Equal(expectedSByte, val.ToSByte(null));
|
||||
|
||||
byte expectedByte = Convert.ToByte((byte)1);
|
||||
Assert.Equal(expectedByte, val.ToByte(null));
|
||||
|
||||
short expectedInt16 = Convert.ToInt16((byte)1);
|
||||
Assert.Equal(expectedInt16, val.ToInt16(null));
|
||||
|
||||
ushort expectedUInt16 = Convert.ToUInt16((byte)1);
|
||||
Assert.Equal(expectedUInt16, val.ToUInt16(null));
|
||||
|
||||
int expectedInt32 = Convert.ToInt32((byte)1);
|
||||
Assert.Equal(expectedInt32, val.ToInt32(null));
|
||||
|
||||
uint expectedUInt32 = Convert.ToUInt32((byte)1);
|
||||
Assert.Equal(expectedUInt32, val.ToUInt32(null));
|
||||
|
||||
long expectedInt64 = Convert.ToInt64((byte)1);
|
||||
Assert.Equal(expectedInt64, val.ToInt64(null));
|
||||
|
||||
ulong expectedUInt64 = Convert.ToUInt64((byte)1);
|
||||
Assert.Equal(expectedUInt64, val.ToUInt64(null));
|
||||
|
||||
float expectedSingle = Convert.ToSingle((byte)1);
|
||||
Assert.Equal(expectedSingle, val.ToSingle(null));
|
||||
|
||||
double expectedDouble = Convert.ToDouble((byte)1);
|
||||
Assert.Equal(expectedDouble, val.ToDouble(null));
|
||||
|
||||
decimal expectedDecimal = Convert.ToDecimal((byte)1);
|
||||
Assert.Equal(expectedDecimal, val.ToDecimal(null));
|
||||
|
||||
Assert.Throws<InvalidCastException>(() => val.ToDateTime(null));
|
||||
|
||||
string expectedString = Convert.ToString((byte)1);
|
||||
Assert.Equal(expectedString, val.ToString(null));
|
||||
|
||||
ulong expectedObject = Convert.ToUInt64((byte)1);
|
||||
Assert.Equal(expectedObject, val.ToType(typeof(ulong), null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(0, 1, false)]
|
||||
[InlineData(1, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BothEndian(byte le, byte be, bool expected)
|
||||
{
|
||||
var val = new BothUInt8(le, be);
|
||||
var equalTo = new BothUInt8(1, 1);
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, false)]
|
||||
[InlineData(1, 1, true)]
|
||||
public void Equals_BaseType(byte le, byte be, bool expected)
|
||||
{
|
||||
var val = new BothUInt8(le, be);
|
||||
byte equalTo = 1;
|
||||
|
||||
bool actual = val.Equals(equalTo);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt8(2, 2);
|
||||
byte expected = 3;
|
||||
valA++;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
|
||||
valA = new BothUInt8(2, 2);
|
||||
expected = 1;
|
||||
valA--;
|
||||
Assert.Equal(expected, valA.LittleEndian);
|
||||
Assert.Equal(expected, valA.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArithmeticBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt8(3, 3);
|
||||
var valB = new BothUInt8(2, 2);
|
||||
|
||||
byte expected = 6;
|
||||
BothUInt8 actual = valA * valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA / valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA % valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 5;
|
||||
actual = valA + valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 1;
|
||||
actual = valA - valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseUnaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt8(2, 2);
|
||||
byte expected = 253;
|
||||
BothUInt8 actual = ~valA;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShiftBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt8(2, 2);
|
||||
var valB = new BothUInt8(1, 1);
|
||||
|
||||
byte expected = 2 << 1;
|
||||
BothUInt8 actual = valA << valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >> 1;
|
||||
actual = valA >> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 2 >>> 1;
|
||||
actual = valA >>> valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BitwiseBinaryOperatorsTest()
|
||||
{
|
||||
var valA = new BothUInt8(3, 3);
|
||||
var valB = new BothUInt8(2, 2);
|
||||
|
||||
byte expected = 3 & 2;
|
||||
BothUInt8 actual = valA & valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 | 2;
|
||||
actual = valA | valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
|
||||
expected = 3 ^ 2;
|
||||
actual = valA ^ valB;
|
||||
Assert.Equal(expected, actual.LittleEndian);
|
||||
Assert.Equal(expected, actual.BigEndian);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -24,9 +24,9 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.3">
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
40
SabreTools.IO.Test/Streams/BufferedStreamTests.cs
Normal file
40
SabreTools.IO.Test/Streams/BufferedStreamTests.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Streams
|
||||
{
|
||||
public class BufferedStreamTests
|
||||
{
|
||||
#region ReadNextByte
|
||||
|
||||
[Fact]
|
||||
public void ReadNextByte_Empty_Null()
|
||||
{
|
||||
var source = new MemoryStream();
|
||||
var stream = new IO.Streams.BufferedStream(source);
|
||||
byte? actual = stream.ReadNextByte();
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadNextByte_Filled_ValidPosition_Byte()
|
||||
{
|
||||
var source = new MemoryStream(new byte[1024]);
|
||||
var stream = new IO.Streams.BufferedStream(source);
|
||||
byte? actual = stream.ReadNextByte();
|
||||
Assert.Equal((byte)0x00, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadNextByte_Filled_InvalidPosition_Null()
|
||||
{
|
||||
var source = new MemoryStream(new byte[1024]);
|
||||
source.Seek(0, SeekOrigin.End);
|
||||
var stream = new IO.Streams.BufferedStream(source);
|
||||
byte? actual = stream.ReadNextByte();
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Streams;
|
||||
@@ -7,8 +8,10 @@ namespace SabreTools.IO.Test.Streams
|
||||
{
|
||||
public class ReadOnlyCompositeStreamTests
|
||||
{
|
||||
#region Constructor
|
||||
|
||||
[Fact]
|
||||
public void DefaultConstructorTest()
|
||||
public void Constructor_Default()
|
||||
{
|
||||
var stream = new ReadOnlyCompositeStream();
|
||||
Assert.Equal(0, stream.Length);
|
||||
@@ -16,7 +19,7 @@ namespace SabreTools.IO.Test.Streams
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyArrayConstructorTest()
|
||||
public void Constructor_EmptyArray()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream()];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
@@ -25,9 +28,8 @@ namespace SabreTools.IO.Test.Streams
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptyEnumerableConstructorTest()
|
||||
public void Constructor_EmptyEnumerable()
|
||||
{
|
||||
// Empty enumerable constructor
|
||||
List<Stream> list = [new MemoryStream()];
|
||||
var stream = new ReadOnlyCompositeStream(list);
|
||||
Assert.Equal(0, stream.Length);
|
||||
@@ -35,7 +37,7 @@ namespace SabreTools.IO.Test.Streams
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SingleStreamConstructorTest()
|
||||
public void Constructor_SingleStream()
|
||||
{
|
||||
var stream = new ReadOnlyCompositeStream(new MemoryStream(new byte[1024]));
|
||||
Assert.Equal(1024, stream.Length);
|
||||
@@ -43,7 +45,7 @@ namespace SabreTools.IO.Test.Streams
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FilledArrayConstructorTest()
|
||||
public void Constructor_FilledArray()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[1024]), new MemoryStream(new byte[1024])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
@@ -52,7 +54,7 @@ namespace SabreTools.IO.Test.Streams
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FilledEnumerableConstructorTest()
|
||||
public void Constructor_FilledEnumerable()
|
||||
{
|
||||
List<Stream> list = [new MemoryStream(new byte[1024]), new MemoryStream(new byte[1024])];
|
||||
var stream = new ReadOnlyCompositeStream(list);
|
||||
@@ -60,6 +62,10 @@ namespace SabreTools.IO.Test.Streams
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region AddStream
|
||||
|
||||
[Fact]
|
||||
public void AddStreamTest()
|
||||
{
|
||||
@@ -70,10 +76,18 @@ namespace SabreTools.IO.Test.Streams
|
||||
stream.AddStream(new MemoryStream(new byte[1024]));
|
||||
Assert.Equal(1024, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
|
||||
stream.AddStream(new MemoryStream([]));
|
||||
Assert.Equal(1024, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Read
|
||||
|
||||
[Fact]
|
||||
public void EmptyStreamReadTest()
|
||||
public void Read_EmptyStream()
|
||||
{
|
||||
var stream = new ReadOnlyCompositeStream();
|
||||
|
||||
@@ -84,7 +98,7 @@ namespace SabreTools.IO.Test.Streams
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SingleStreamReadTest()
|
||||
public void Read_SingleStream()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[1024])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
@@ -96,7 +110,7 @@ namespace SabreTools.IO.Test.Streams
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultipleStreamSingleContainedReadTest()
|
||||
public void Read_MultipleStream_SingleContained()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[1024]), new MemoryStream(new byte[1024])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
@@ -108,7 +122,7 @@ namespace SabreTools.IO.Test.Streams
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultipleStreamMultipleContainedReadTest()
|
||||
public void Read_MultipleStream_MultipleContained()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[256]), new MemoryStream(new byte[256])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
@@ -120,7 +134,7 @@ namespace SabreTools.IO.Test.Streams
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SingleStreamExtraReadTest()
|
||||
public void Read_SingleStream_Extra()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[256])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
@@ -132,7 +146,7 @@ namespace SabreTools.IO.Test.Streams
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultipleStreamExtraReadTest()
|
||||
public void Read_MultipleStream_Extra()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[128]), new MemoryStream(new byte[128])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
@@ -142,5 +156,32 @@ namespace SabreTools.IO.Test.Streams
|
||||
|
||||
Assert.Equal(256, read);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unimplemented
|
||||
|
||||
[Fact]
|
||||
public void Flush_Throws()
|
||||
{
|
||||
var stream = new ReadOnlyCompositeStream();
|
||||
Assert.Throws<NotImplementedException>(() => stream.Flush());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetLength_Throws()
|
||||
{
|
||||
var stream = new ReadOnlyCompositeStream();
|
||||
Assert.Throws<NotImplementedException>(() => stream.SetLength(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_Throws()
|
||||
{
|
||||
var stream = new ReadOnlyCompositeStream();
|
||||
Assert.Throws<NotImplementedException>(() => stream.Write([], 0, 0));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
419
SabreTools.IO.Test/Streams/ViewStreamTests.cs
Normal file
419
SabreTools.IO.Test/Streams/ViewStreamTests.cs
Normal file
@@ -0,0 +1,419 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Streams;
|
||||
using Xunit;
|
||||
|
||||
#pragma warning disable IDE0017 // Object initialization can be simplified
|
||||
namespace SabreTools.IO.Test.Streams
|
||||
{
|
||||
public class ViewStreamTests
|
||||
{
|
||||
#region Constructor
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0)]
|
||||
[InlineData(1024, 0, 1024)]
|
||||
[InlineData(1024, 256, 768)]
|
||||
public void Constructor_Array(int size, long offset, long expectedLength)
|
||||
{
|
||||
byte[] data = new byte[size];
|
||||
var stream = new ViewStream(data, offset);
|
||||
Assert.Equal(expectedLength, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0, 0)]
|
||||
[InlineData(1024, 0, 1024, 1024)]
|
||||
[InlineData(1024, 256, 512, 512)]
|
||||
public void Constructor_Array_Length(int size, long offset, long length, long expectedLength)
|
||||
{
|
||||
byte[] data = new byte[size];
|
||||
var stream = new ViewStream(data, offset, length);
|
||||
Assert.Equal(expectedLength, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, -1, 0)]
|
||||
[InlineData(0, 2048, 0)]
|
||||
[InlineData(1024, -1, 1024)]
|
||||
[InlineData(1024, 2048, 1024)]
|
||||
[InlineData(1024, -1, 512)]
|
||||
[InlineData(1024, 2048, 512)]
|
||||
public void Constructor_Array_InvalidOffset(int size, long offset, long length)
|
||||
{
|
||||
byte[] data = new byte[size];
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => _ = new ViewStream(data, offset, length));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, -1)]
|
||||
[InlineData(0, 0, 2048)]
|
||||
[InlineData(1024, 0, -1)]
|
||||
[InlineData(1024, 0, 2048)]
|
||||
[InlineData(1024, 256, -1)]
|
||||
[InlineData(1024, 256, 2048)]
|
||||
public void Constructor_Array_InvalidLength(int size, long offset, long length)
|
||||
{
|
||||
byte[] data = new byte[size];
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => _ = new ViewStream(data, offset, length));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0)]
|
||||
[InlineData(1024, 0, 1024)]
|
||||
[InlineData(1024, 256, 768)]
|
||||
public void Constructor_Stream(int size, long offset, long expectedLength)
|
||||
{
|
||||
Stream data = new MemoryStream(new byte[size]);
|
||||
var stream = new ViewStream(data, offset);
|
||||
Assert.Equal(expectedLength, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0, 0)]
|
||||
[InlineData(1024, 0, 1024, 1024)]
|
||||
[InlineData(1024, 256, 512, 512)]
|
||||
public void Constructor_Stream_Length(int size, long offset, long length, long expectedLength)
|
||||
{
|
||||
Stream data = new MemoryStream(new byte[size]);
|
||||
var stream = new ViewStream(data, offset, length);
|
||||
Assert.Equal(expectedLength, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, -1, 0)]
|
||||
[InlineData(0, 2048, 0)]
|
||||
[InlineData(1024, -1, 1024)]
|
||||
[InlineData(1024, 2048, 1024)]
|
||||
[InlineData(1024, -1, 512)]
|
||||
[InlineData(1024, 2048, 512)]
|
||||
public void Constructor_Stream_InvalidOffset(int size, long offset, long length)
|
||||
{
|
||||
Stream data = new MemoryStream(new byte[size]);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => _ = new ViewStream(data, offset, length));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, -1)]
|
||||
[InlineData(0, 0, 2048)]
|
||||
[InlineData(1024, 0, -1)]
|
||||
[InlineData(1024, 0, 2048)]
|
||||
[InlineData(1024, 256, -1)]
|
||||
[InlineData(1024, 256, 2048)]
|
||||
public void Constructor_Stream_InvalidLength(int size, long offset, long length)
|
||||
{
|
||||
Stream data = new MemoryStream(new byte[size]);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => _ = new ViewStream(data, offset, length));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Position
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0, -1, 0)]
|
||||
[InlineData(0, 0, 0, 0, 0)]
|
||||
[InlineData(0, 0, 0, 256, 0)]
|
||||
[InlineData(0, 0, 0, 2048, 0)]
|
||||
[InlineData(1024, 0, 1024, -1, 0)]
|
||||
[InlineData(1024, 0, 1024, 0, 0)]
|
||||
[InlineData(1024, 0, 1024, 256, 256)]
|
||||
[InlineData(1024, 0, 1024, 2048, 1023)]
|
||||
[InlineData(1024, 256, 512, -1, 0)]
|
||||
[InlineData(1024, 256, 512, 0, 0)]
|
||||
[InlineData(1024, 256, 512, 256, 256)]
|
||||
[InlineData(1024, 256, 512, 2048, 511)]
|
||||
public void Position_Array(int size, long offset, long length, long position, long expectedPosition)
|
||||
{
|
||||
byte[] data = new byte[size];
|
||||
var stream = new ViewStream(data, offset, length);
|
||||
stream.Position = position;
|
||||
Assert.Equal(expectedPosition, stream.Position);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0, -1, 0)]
|
||||
[InlineData(0, 0, 0, 0, 0)]
|
||||
[InlineData(0, 0, 0, 256, 0)]
|
||||
[InlineData(0, 0, 0, 2048, 0)]
|
||||
[InlineData(1024, 0, 1024, -1, 0)]
|
||||
[InlineData(1024, 0, 1024, 0, 0)]
|
||||
[InlineData(1024, 0, 1024, 256, 256)]
|
||||
[InlineData(1024, 0, 1024, 2048, 1023)]
|
||||
[InlineData(1024, 256, 512, -1, 0)]
|
||||
[InlineData(1024, 256, 512, 0, 0)]
|
||||
[InlineData(1024, 256, 512, 256, 256)]
|
||||
[InlineData(1024, 256, 512, 2048, 511)]
|
||||
public void Position_Stream(int size, long offset, long length, long position, long expectedPosition)
|
||||
{
|
||||
Stream data = new MemoryStream(new byte[size]);
|
||||
var stream = new ViewStream(data, offset, length);
|
||||
stream.Position = position;
|
||||
Assert.Equal(expectedPosition, stream.Position);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SegmentValid
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0, -1, 0, false)]
|
||||
[InlineData(0, 0, 0, 2048, 0, false)]
|
||||
[InlineData(0, 0, 0, 0, 0, true)]
|
||||
[InlineData(0, 0, 0, 0, -1, false)]
|
||||
[InlineData(0, 0, 0, 0, 2048, false)]
|
||||
[InlineData(1024, 0, 1024, -1, 0, false)]
|
||||
[InlineData(1024, 0, 1024, 2048, 0, false)]
|
||||
[InlineData(1024, 0, 1024, 0, 0, true)]
|
||||
[InlineData(1024, 0, 1024, 256, 0, true)]
|
||||
[InlineData(1024, 0, 1024, 256, 256, true)]
|
||||
[InlineData(1024, 0, 1024, 0, -1, false)]
|
||||
[InlineData(1024, 0, 1024, 0, 2048, false)]
|
||||
[InlineData(1024, 256, 512, -1, 0, false)]
|
||||
[InlineData(1024, 256, 512, 2048, 0, false)]
|
||||
[InlineData(1024, 256, 512, 0, 0, true)]
|
||||
[InlineData(1024, 256, 512, 256, 0, true)]
|
||||
[InlineData(1024, 256, 512, 256, 256, true)]
|
||||
[InlineData(1024, 256, 512, 0, -1, false)]
|
||||
[InlineData(1024, 256, 512, 0, 2048, false)]
|
||||
public void SegmentValid_Array(int size, long offset, long length, int segmentStart, int segmentLength, bool expected)
|
||||
{
|
||||
byte[] data = new byte[size];
|
||||
var stream = new ViewStream(data, offset, length);
|
||||
bool actual = stream.SegmentValid(segmentStart, segmentLength);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0, -1, 0, false)]
|
||||
[InlineData(0, 0, 0, 2048, 0, false)]
|
||||
[InlineData(0, 0, 0, 0, 0, true)]
|
||||
[InlineData(0, 0, 0, 0, -1, false)]
|
||||
[InlineData(0, 0, 0, 0, 2048, false)]
|
||||
[InlineData(1024, 0, 1024, -1, 0, false)]
|
||||
[InlineData(1024, 0, 1024, 2048, 0, false)]
|
||||
[InlineData(1024, 0, 1024, 0, 0, true)]
|
||||
[InlineData(1024, 0, 1024, 256, 0, true)]
|
||||
[InlineData(1024, 0, 1024, 256, 256, true)]
|
||||
[InlineData(1024, 0, 1024, 0, -1, false)]
|
||||
[InlineData(1024, 0, 1024, 0, 2048, false)]
|
||||
[InlineData(1024, 256, 512, -1, 0, false)]
|
||||
[InlineData(1024, 256, 512, 2048, 0, false)]
|
||||
[InlineData(1024, 256, 512, 0, 0, true)]
|
||||
[InlineData(1024, 256, 512, 256, 0, true)]
|
||||
[InlineData(1024, 256, 512, 256, 256, true)]
|
||||
[InlineData(1024, 256, 512, 0, -1, false)]
|
||||
[InlineData(1024, 256, 512, 0, 2048, false)]
|
||||
public void SegmentValid_Stream(int size, long offset, long length, int segmentStart, int segmentLength, bool expected)
|
||||
{
|
||||
Stream data = new MemoryStream(new byte[size]);
|
||||
var stream = new ViewStream(data, offset, length);
|
||||
bool actual = stream.SegmentValid(segmentStart, segmentLength);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Read
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0, -1, 0)]
|
||||
[InlineData(0, 0, 0, 0, 0)]
|
||||
[InlineData(0, 0, 0, 2048, 0)]
|
||||
[InlineData(1024, 0, 1024, -1, 0)]
|
||||
[InlineData(1024, 0, 1024, 0, 0)]
|
||||
[InlineData(1024, 0, 1024, 256, 256)]
|
||||
[InlineData(1024, 0, 1024, 1024, 1024)]
|
||||
[InlineData(1024, 0, 1024, 2048, 0)]
|
||||
[InlineData(1024, 256, 512, -1, 0)]
|
||||
[InlineData(1024, 256, 512, 0, 0)]
|
||||
[InlineData(1024, 256, 512, 256, 256)]
|
||||
[InlineData(1024, 256, 512, 512, 512)]
|
||||
[InlineData(1024, 256, 512, 2048, 0)]
|
||||
public void Read_Array(int size, long offset, long length, int count, int expectedRead)
|
||||
{
|
||||
byte[] data = new byte[size];
|
||||
var stream = new ViewStream(data, offset, length);
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int actual = stream.Read(buffer, 0, count);
|
||||
Assert.Equal(expectedRead, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0, -1, 0)]
|
||||
[InlineData(0, 0, 0, 0, 0)]
|
||||
[InlineData(0, 0, 0, 2048, 0)]
|
||||
[InlineData(1024, 0, 1024, -1, 0)]
|
||||
[InlineData(1024, 0, 1024, 0, 0)]
|
||||
[InlineData(1024, 0, 1024, 256, 256)]
|
||||
[InlineData(1024, 0, 1024, 1024, 1024)]
|
||||
[InlineData(1024, 0, 1024, 2048, 0)]
|
||||
[InlineData(1024, 256, 512, -1, 0)]
|
||||
[InlineData(1024, 256, 512, 0, 0)]
|
||||
[InlineData(1024, 256, 512, 256, 256)]
|
||||
[InlineData(1024, 256, 512, 512, 512)]
|
||||
[InlineData(1024, 256, 512, 2048, 0)]
|
||||
public void Read_Stream(int size, long offset, long length, int count, int expectedRead)
|
||||
{
|
||||
Stream data = new MemoryStream(new byte[size]);
|
||||
var stream = new ViewStream(data, offset, length);
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int actual = stream.Read(buffer, 0, count);
|
||||
Assert.Equal(expectedRead, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Seek
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0, -1, SeekOrigin.Begin, 0)]
|
||||
[InlineData(0, 0, 0, -1, SeekOrigin.End, 0)]
|
||||
[InlineData(0, 0, 0, -1, SeekOrigin.Current, 0)]
|
||||
[InlineData(0, 0, 0, 0, SeekOrigin.Begin, 0)]
|
||||
[InlineData(0, 0, 0, 0, SeekOrigin.End, 0)]
|
||||
[InlineData(0, 0, 0, 0, SeekOrigin.Current, 0)]
|
||||
[InlineData(0, 0, 0, 256, SeekOrigin.Begin, 0)]
|
||||
[InlineData(0, 0, 0, 256, SeekOrigin.End, 0)]
|
||||
[InlineData(0, 0, 0, 256, SeekOrigin.Current, 0)]
|
||||
[InlineData(0, 0, 0, 2048, SeekOrigin.Begin, 0)]
|
||||
[InlineData(0, 0, 0, 2048, SeekOrigin.End, 0)]
|
||||
[InlineData(0, 0, 0, 2048, SeekOrigin.Current, 0)]
|
||||
[InlineData(1024, 0, 1024, -1, SeekOrigin.Begin, 0)]
|
||||
[InlineData(1024, 0, 1024, -1, SeekOrigin.End, 1022)]
|
||||
[InlineData(1024, 0, 1024, -1, SeekOrigin.Current, 0)]
|
||||
[InlineData(1024, 0, 1024, 0, SeekOrigin.Begin, 0)]
|
||||
[InlineData(1024, 0, 1024, 0, SeekOrigin.End, 1023)]
|
||||
[InlineData(1024, 0, 1024, 0, SeekOrigin.Current, 0)]
|
||||
[InlineData(1024, 0, 1024, 256, SeekOrigin.Begin, 256)]
|
||||
[InlineData(1024, 0, 1024, 256, SeekOrigin.End, 1023)]
|
||||
[InlineData(1024, 0, 1024, 256, SeekOrigin.Current, 256)]
|
||||
[InlineData(1024, 0, 1024, 2048, SeekOrigin.Begin, 1023)]
|
||||
[InlineData(1024, 0, 1024, 2048, SeekOrigin.End, 1023)]
|
||||
[InlineData(1024, 0, 1024, 2048, SeekOrigin.Current, 1023)]
|
||||
[InlineData(1024, 256, 512, -1, SeekOrigin.Begin, 0)]
|
||||
[InlineData(1024, 256, 512, -1, SeekOrigin.End, 510)]
|
||||
[InlineData(1024, 256, 512, -1, SeekOrigin.Current, 0)]
|
||||
[InlineData(1024, 256, 512, 0, SeekOrigin.Begin, 0)]
|
||||
[InlineData(1024, 256, 512, 0, SeekOrigin.End, 511)]
|
||||
[InlineData(1024, 256, 512, 0, SeekOrigin.Current, 0)]
|
||||
[InlineData(1024, 256, 512, 256, SeekOrigin.Begin, 256)]
|
||||
[InlineData(1024, 256, 512, 256, SeekOrigin.End, 511)]
|
||||
[InlineData(1024, 256, 512, 256, SeekOrigin.Current, 256)]
|
||||
[InlineData(1024, 256, 512, 2048, SeekOrigin.Begin, 511)]
|
||||
[InlineData(1024, 256, 512, 2048, SeekOrigin.End, 511)]
|
||||
[InlineData(1024, 256, 512, 2048, SeekOrigin.Current, 511)]
|
||||
public void Seek_Array(int size, long offset, long length, long position, SeekOrigin seekOrigin, long expectedPosition)
|
||||
{
|
||||
byte[] data = new byte[size];
|
||||
var stream = new ViewStream(data, offset, length);
|
||||
stream.Seek(position, seekOrigin);
|
||||
Assert.Equal(expectedPosition, stream.Position);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0, 0, -1, SeekOrigin.Begin, 0)]
|
||||
[InlineData(0, 0, 0, -1, SeekOrigin.End, 0)]
|
||||
[InlineData(0, 0, 0, -1, SeekOrigin.Current, 0)]
|
||||
[InlineData(0, 0, 0, 0, SeekOrigin.Begin, 0)]
|
||||
[InlineData(0, 0, 0, 0, SeekOrigin.End, 0)]
|
||||
[InlineData(0, 0, 0, 0, SeekOrigin.Current, 0)]
|
||||
[InlineData(0, 0, 0, 256, SeekOrigin.Begin, 0)]
|
||||
[InlineData(0, 0, 0, 256, SeekOrigin.End, 0)]
|
||||
[InlineData(0, 0, 0, 256, SeekOrigin.Current, 0)]
|
||||
[InlineData(0, 0, 0, 2048, SeekOrigin.Begin, 0)]
|
||||
[InlineData(0, 0, 0, 2048, SeekOrigin.End, 0)]
|
||||
[InlineData(0, 0, 0, 2048, SeekOrigin.Current, 0)]
|
||||
[InlineData(1024, 0, 1024, -1, SeekOrigin.Begin, 0)]
|
||||
[InlineData(1024, 0, 1024, -1, SeekOrigin.End, 1022)]
|
||||
[InlineData(1024, 0, 1024, -1, SeekOrigin.Current, 0)]
|
||||
[InlineData(1024, 0, 1024, 0, SeekOrigin.Begin, 0)]
|
||||
[InlineData(1024, 0, 1024, 0, SeekOrigin.End, 1023)]
|
||||
[InlineData(1024, 0, 1024, 0, SeekOrigin.Current, 0)]
|
||||
[InlineData(1024, 0, 1024, 256, SeekOrigin.Begin, 256)]
|
||||
[InlineData(1024, 0, 1024, 256, SeekOrigin.End, 1023)]
|
||||
[InlineData(1024, 0, 1024, 256, SeekOrigin.Current, 256)]
|
||||
[InlineData(1024, 0, 1024, 2048, SeekOrigin.Begin, 1023)]
|
||||
[InlineData(1024, 0, 1024, 2048, SeekOrigin.End, 1023)]
|
||||
[InlineData(1024, 0, 1024, 2048, SeekOrigin.Current, 1023)]
|
||||
[InlineData(1024, 256, 512, -1, SeekOrigin.Begin, 0)]
|
||||
[InlineData(1024, 256, 512, -1, SeekOrigin.End, 510)]
|
||||
[InlineData(1024, 256, 512, -1, SeekOrigin.Current, 0)]
|
||||
[InlineData(1024, 256, 512, 0, SeekOrigin.Begin, 0)]
|
||||
[InlineData(1024, 256, 512, 0, SeekOrigin.End, 511)]
|
||||
[InlineData(1024, 256, 512, 0, SeekOrigin.Current, 0)]
|
||||
[InlineData(1024, 256, 512, 256, SeekOrigin.Begin, 256)]
|
||||
[InlineData(1024, 256, 512, 256, SeekOrigin.End, 511)]
|
||||
[InlineData(1024, 256, 512, 256, SeekOrigin.Current, 256)]
|
||||
[InlineData(1024, 256, 512, 2048, SeekOrigin.Begin, 511)]
|
||||
[InlineData(1024, 256, 512, 2048, SeekOrigin.End, 511)]
|
||||
[InlineData(1024, 256, 512, 2048, SeekOrigin.Current, 511)]
|
||||
public void Seek_Stream(int size, long offset, long length, long position, SeekOrigin seekOrigin, long expectedPosition)
|
||||
{
|
||||
Stream data = new MemoryStream(new byte[size]);
|
||||
var stream = new ViewStream(data, offset, length);
|
||||
stream.Seek(position, seekOrigin);
|
||||
Assert.Equal(expectedPosition, stream.Position);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unimplemented
|
||||
|
||||
[Fact]
|
||||
public void Flush_Array_Throws()
|
||||
{
|
||||
byte[] data = new byte[1024];
|
||||
var stream = new ViewStream(data, 0, 1024);
|
||||
Assert.Throws<NotImplementedException>(() => stream.Flush());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Flush_Stream_Throws()
|
||||
{
|
||||
Stream data = new MemoryStream(new byte[1024]);
|
||||
var stream = new ViewStream(data, 0, 1024);
|
||||
Assert.Throws<NotImplementedException>(() => stream.Flush());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetLength_Array_Throws()
|
||||
{
|
||||
byte[] data = new byte[1024];
|
||||
var stream = new ViewStream(data, 0, 1024);
|
||||
Assert.Throws<NotImplementedException>(() => stream.SetLength(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetLength_Stream_Throws()
|
||||
{
|
||||
Stream data = new MemoryStream(new byte[1024]);
|
||||
var stream = new ViewStream(data, 0, 1024);
|
||||
Assert.Throws<NotImplementedException>(() => stream.SetLength(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_Array_Throws()
|
||||
{
|
||||
byte[] data = new byte[1024];
|
||||
var stream = new ViewStream(data, 0, 1024);
|
||||
Assert.Throws<NotImplementedException>(() => stream.Write([], 0, 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_Stream_Throws()
|
||||
{
|
||||
Stream data = new MemoryStream(new byte[1024]);
|
||||
var stream = new ViewStream(data, 0, 1024);
|
||||
Assert.Throws<NotImplementedException>(() => stream.Write([], 0, 0));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
124
SabreTools.IO.Test/Transform/CombineTests.cs
Normal file
124
SabreTools.IO.Test/Transform/CombineTests.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Transform;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Transform
|
||||
{
|
||||
public class CombineTests
|
||||
{
|
||||
#region Concatenate
|
||||
|
||||
[Fact]
|
||||
public void Concatenate_EmptyList_False()
|
||||
{
|
||||
List<string> paths = [];
|
||||
string output = string.Empty;
|
||||
bool actual = Combine.Concatenate(paths, output);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Concatenate_InvalidOutput_False()
|
||||
{
|
||||
List<string> paths = ["a"];
|
||||
string output = string.Empty;
|
||||
bool actual = Combine.Concatenate(paths, output);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Concatenate_FilledList_True()
|
||||
{
|
||||
List<string> paths = [
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt"),
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-compress.bin"),
|
||||
];
|
||||
string output = Guid.NewGuid().ToString();
|
||||
bool actual = Combine.Concatenate(paths, output);
|
||||
Assert.True(actual);
|
||||
|
||||
string text = File.ReadAllText(output);
|
||||
Assert.Equal("This doesn't match anythingThis is just a file that has a known set of hashes to make sure that everything with hashing is still working as anticipated.", text);
|
||||
|
||||
File.Delete(output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Interleave
|
||||
|
||||
[Fact]
|
||||
public void Interleave_EvenNotExists_False()
|
||||
{
|
||||
string even = "NOT A REAL PATH";
|
||||
string odd = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string output = Guid.NewGuid().ToString();
|
||||
|
||||
bool actual = Combine.Interleave(even, odd, output, BlockSize.Byte);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Interleave_OddNotExists_False()
|
||||
{
|
||||
string even = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string odd = "NOT A REAL PATH";
|
||||
string output = Guid.NewGuid().ToString();
|
||||
|
||||
bool actual = Combine.Interleave(even, odd, output, BlockSize.Byte);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Interleave_InvalidType_False()
|
||||
{
|
||||
string even = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string odd = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string output = Guid.NewGuid().ToString();
|
||||
|
||||
bool actual = Combine.Interleave(even, odd, output, (BlockSize)int.MaxValue);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(BlockSize.Byte, "TThhiiss ddooeessnn''tt mmaattcchh aannyytthhiinngg")]
|
||||
[InlineData(BlockSize.Word, "ThThisis d doeoesnsn't't m matatchch a anynyththiningg")]
|
||||
[InlineData(BlockSize.Dword, "ThisThis doe doesn'tsn't mat match ach anythnythinging")]
|
||||
[InlineData(BlockSize.Qword, "This doeThis doesn't matsn't match anythch anythinging")]
|
||||
public void Interleave_SameLength_True(BlockSize type, string expected)
|
||||
{
|
||||
string even = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string odd = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string output = Guid.NewGuid().ToString();
|
||||
|
||||
bool actual = Combine.Interleave(even, odd, output, type);
|
||||
Assert.True(actual);
|
||||
|
||||
string text = File.ReadAllText(output);
|
||||
Assert.Equal(expected, text);
|
||||
|
||||
File.Delete(output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Interleave_DifferentLength_True()
|
||||
{
|
||||
string even = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string odd = Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-compress.bin");
|
||||
|
||||
string output = Guid.NewGuid().ToString();
|
||||
|
||||
bool actual = Combine.Interleave(even, odd, output, BlockSize.Byte);
|
||||
Assert.True(actual);
|
||||
|
||||
string text = File.ReadAllText(output);
|
||||
Assert.Equal("TThhiiss diose sjnu'stt maa tfcihl ea ntyhtahti nhgas a known set of hashes to make sure that everything with hashing is still working as anticipated.", text);
|
||||
|
||||
File.Delete(output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
124
SabreTools.IO.Test/Transform/SplitTests.cs
Normal file
124
SabreTools.IO.Test/Transform/SplitTests.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Transform;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Transform
|
||||
{
|
||||
public class SplitTests
|
||||
{
|
||||
#region BlockSplit
|
||||
|
||||
[Fact]
|
||||
public void BlockSplit_EmptyFileName_False()
|
||||
{
|
||||
string input = string.Empty;
|
||||
string outputDir = string.Empty;
|
||||
bool actual = Split.BlockSplit(input, outputDir, BlockSize.Byte);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BlockSplit_InvalidFile_False()
|
||||
{
|
||||
string input = "INVALID";
|
||||
string outputDir = string.Empty;
|
||||
bool actual = Split.BlockSplit(input, outputDir, BlockSize.Byte);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BlockSplit_InvalidType_False()
|
||||
{
|
||||
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string outputDir = Guid.NewGuid().ToString();
|
||||
|
||||
bool actual = Split.BlockSplit(input, outputDir, (BlockSize)int.MaxValue);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(BlockSize.Byte, "Ti os' ac ntig", "hsdentmthayhn")]
|
||||
[InlineData(BlockSize.Word, "Th dsn mchnyin", "isoe'tat athg")]
|
||||
[InlineData(BlockSize.Dword, "Thissn'tch aing", " doe matnyth")]
|
||||
[InlineData(BlockSize.Qword, "This doech anyth", "sn't mating")]
|
||||
public void BlockSplit_ValidFile_True(BlockSize type, string expectedEven, string expectedOdd)
|
||||
{
|
||||
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string outputDir = Guid.NewGuid().ToString();
|
||||
|
||||
bool actual = Split.BlockSplit(input, outputDir, type);
|
||||
Assert.True(actual);
|
||||
|
||||
string baseFilename = Path.GetFileName(input);
|
||||
string text = File.ReadAllText(Path.Combine(outputDir, $"{baseFilename}.even"));
|
||||
Assert.Equal(expectedEven, text);
|
||||
text = File.ReadAllText(Path.Combine(outputDir, $"{baseFilename}.odd"));
|
||||
Assert.Equal(expectedOdd, text);
|
||||
|
||||
File.Delete($"{baseFilename}.even");
|
||||
File.Delete($"{baseFilename}.odd");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SizeSplit
|
||||
|
||||
[Fact]
|
||||
public void SizeSplit_EmptyFileName_False()
|
||||
{
|
||||
string input = string.Empty;
|
||||
string outputDir = string.Empty;
|
||||
int size = 1;
|
||||
|
||||
bool actual = Split.SizeSplit(input, outputDir, size);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SizeSplit_InvalidFile_False()
|
||||
{
|
||||
string input = "INVALID";
|
||||
string outputDir = string.Empty;
|
||||
int size = 1;
|
||||
|
||||
bool actual = Split.SizeSplit(input, outputDir, size);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SizeSplit_InvalidSize_False()
|
||||
{
|
||||
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string outputDir = string.Empty;
|
||||
int size = 0;
|
||||
|
||||
bool actual = Split.SizeSplit(input, outputDir, size);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SizeSplit_Valid_True()
|
||||
{
|
||||
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string outputDir = Guid.NewGuid().ToString();
|
||||
int size = 16;
|
||||
|
||||
bool actual = Split.SizeSplit(input, outputDir, size);
|
||||
Assert.True(actual);
|
||||
|
||||
Assert.Equal(2, Directory.GetFiles(outputDir).Length);
|
||||
|
||||
string baseFilename = Path.GetFileName(input);
|
||||
string text = File.ReadAllText(Path.Combine(outputDir, $"{baseFilename}.0"));
|
||||
Assert.Equal("This doesn't mat", text);
|
||||
text = File.ReadAllText(Path.Combine(outputDir, $"{baseFilename}.1"));
|
||||
Assert.Equal("ch anything", text);
|
||||
|
||||
File.Delete($"{baseFilename}.0");
|
||||
File.Delete($"{baseFilename}.1");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
77
SabreTools.IO.Test/Transform/SwapTests.cs
Normal file
77
SabreTools.IO.Test/Transform/SwapTests.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.IO.Transform;
|
||||
using Xunit;
|
||||
|
||||
#pragma warning disable IDE0230 // Use UTF-8 string literal
|
||||
namespace SabreTools.IO.Test.Transform
|
||||
{
|
||||
public class SwapTests
|
||||
{
|
||||
#region Process
|
||||
|
||||
[Fact]
|
||||
public void Process_EmptyFileName_False()
|
||||
{
|
||||
string input = string.Empty;
|
||||
string output = string.Empty;
|
||||
bool actual = Swap.Process(input, output, Operation.Byteswap);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Process_InvalidFile_False()
|
||||
{
|
||||
string input = "INVALID";
|
||||
string output = string.Empty;
|
||||
bool actual = Swap.Process(input, output, Operation.Byteswap);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Process_InvalidType_False()
|
||||
{
|
||||
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string output = Guid.NewGuid().ToString();
|
||||
|
||||
bool actual = Swap.Process(input, output, (Operation)int.MaxValue);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Process_Valid_True()
|
||||
{
|
||||
string input = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
string output = Guid.NewGuid().ToString();
|
||||
|
||||
// Bitswap
|
||||
bool actual = Swap.Process(input, output, Operation.Bitswap);
|
||||
Assert.True(actual);
|
||||
byte[] actualBytes = File.ReadAllBytes(output);
|
||||
Assert.True(new byte[] { 0x2A, 0x16, 0x96, 0xCE, 0x04, 0x26, 0xF6, 0xA6, 0xCE, 0x76, 0xE4, 0x2E, 0x04, 0xB6, 0x86, 0x2E, 0xC6, 0x16, 0x04, 0x86, 0x76, 0x9E, 0x2E, 0x16, 0x96, 0x76, 0xE6 }.EqualsExactly(actualBytes));
|
||||
|
||||
// Byteswap
|
||||
actual = Swap.Process(input, output, Operation.Byteswap);
|
||||
Assert.True(actual);
|
||||
actualBytes = File.ReadAllBytes(output);
|
||||
Assert.True(new byte[] { 0x68, 0x54, 0x73, 0x69, 0x64, 0x20, 0x65, 0x6F, 0x6E, 0x73, 0x74, 0x27, 0x6D, 0x20, 0x74, 0x61, 0x68, 0x63, 0x61, 0x20, 0x79, 0x6E, 0x68, 0x74, 0x6E, 0x69, 0x67 }.EqualsExactly(actualBytes));
|
||||
|
||||
// Wordswap
|
||||
actual = Swap.Process(input, output, Operation.Wordswap);
|
||||
Assert.True(actual);
|
||||
actualBytes = File.ReadAllBytes(output);
|
||||
Assert.True(new byte[] { 0x69, 0x73, 0x54, 0x68, 0x6F, 0x65, 0x20, 0x64, 0x27, 0x74, 0x73, 0x6E, 0x61, 0x74, 0x20, 0x6D, 0x20, 0x61, 0x63, 0x68, 0x74, 0x68, 0x6E, 0x79, 0x69, 0x6E, 0x67 }.EqualsExactly(actualBytes));
|
||||
|
||||
// WordByteswap
|
||||
actual = Swap.Process(input, output, Operation.WordByteswap);
|
||||
Assert.True(actual);
|
||||
actualBytes = File.ReadAllBytes(output);
|
||||
Assert.True(new byte[] { 0x73, 0x69, 0x68, 0x54, 0x65, 0x6F, 0x64, 0x20, 0x74, 0x27, 0x6E, 0x73, 0x74, 0x61, 0x6D, 0x20, 0x61, 0x20, 0x68, 0x63, 0x68, 0x74, 0x79, 0x6E, 0x69, 0x6E, 0x67 }.EqualsExactly(actualBytes));
|
||||
|
||||
File.Delete(output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
92
SabreTools.IO/Compare/NaturalComparer.cs
Normal file
92
SabreTools.IO/Compare/NaturalComparer.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
*
|
||||
* Links for info and original source code:
|
||||
*
|
||||
* https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
|
||||
* http://www.codeproject.com/Articles/22517/Natural-Sort-Comparer
|
||||
*
|
||||
* Exact code implementation used with permission, originally by motoschifo
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SabreTools.Text.Compare
|
||||
{
|
||||
public class NaturalComparer : Comparer<string>, IDisposable
|
||||
{
|
||||
private readonly Dictionary<string, string[]> _table;
|
||||
|
||||
public NaturalComparer()
|
||||
{
|
||||
_table = [];
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_table.Clear();
|
||||
}
|
||||
|
||||
public override int Compare(string? x, string? y)
|
||||
{
|
||||
if (x is null || y is null)
|
||||
{
|
||||
if (x is null && y is not null)
|
||||
return -1;
|
||||
else if (x is not null && y is null)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (x.ToLowerInvariant() == y.ToLowerInvariant())
|
||||
return x.CompareTo(y);
|
||||
|
||||
if (!_table.TryGetValue(x, out string[]? x1))
|
||||
{
|
||||
//x1 = Regex.Split(x.Replace(" ", string.Empty), "([0-9]+)");
|
||||
x1 = Regex.Split(x.ToLowerInvariant(), "([0-9]+)");
|
||||
x1 = Array.FindAll(x1, s => !string.IsNullOrEmpty(s));
|
||||
_table.Add(x, x1);
|
||||
}
|
||||
|
||||
if (!_table.TryGetValue(y, out string[]? y1))
|
||||
{
|
||||
//y1 = Regex.Split(y.Replace(" ", string.Empty), "([0-9]+)");
|
||||
y1 = Regex.Split(y.ToLowerInvariant(), "([0-9]+)");
|
||||
y1 = Array.FindAll(y1, s => !string.IsNullOrEmpty(s));
|
||||
_table.Add(y, y1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < x1.Length && i < y1.Length; i++)
|
||||
{
|
||||
if (x1[i] != y1[i])
|
||||
return PartCompare(x1[i], y1[i]);
|
||||
}
|
||||
|
||||
if (x1.Length > y1.Length)
|
||||
return 1;
|
||||
else if (y1.Length > x1.Length)
|
||||
return -1;
|
||||
else
|
||||
return x.CompareTo(y);
|
||||
}
|
||||
|
||||
private static int PartCompare(string left, string right)
|
||||
{
|
||||
if (!long.TryParse(left, out long x))
|
||||
return NaturalComparerUtil.ComparePaths(left, right);
|
||||
|
||||
if (!long.TryParse(right, out long y))
|
||||
return NaturalComparerUtil.ComparePaths(left, right);
|
||||
|
||||
// If we have an equal part, then make sure that "longer" ones are taken into account
|
||||
if (x.CompareTo(y) == 0)
|
||||
return left.Length - right.Length;
|
||||
|
||||
return x.CompareTo(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
96
SabreTools.IO/Compare/NaturalComparerUtil.cs
Normal file
96
SabreTools.IO/Compare/NaturalComparerUtil.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
namespace SabreTools.Text.Compare
|
||||
{
|
||||
internal static class NaturalComparerUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Compare two strings by path parts
|
||||
/// </summary>
|
||||
public static int ComparePaths(string? left, string? right)
|
||||
{
|
||||
// If both strings are null, return
|
||||
if (left is null && right is null)
|
||||
return 0;
|
||||
|
||||
// If one is null, then say that's less than
|
||||
if (left is null)
|
||||
return -1;
|
||||
if (right is null)
|
||||
return 1;
|
||||
|
||||
// Normalize the path seperators
|
||||
left = left.Replace('\\', '/');
|
||||
right = right.Replace('\\', '/');
|
||||
|
||||
// Save the orginal adjusted strings
|
||||
string leftOrig = left;
|
||||
string rightOrig = right;
|
||||
|
||||
// Normalize strings by lower-case
|
||||
left = leftOrig.ToLowerInvariant();
|
||||
right = rightOrig.ToLowerInvariant();
|
||||
|
||||
// If the strings are the same exactly, return
|
||||
if (left == right)
|
||||
return leftOrig.CompareTo(rightOrig);
|
||||
|
||||
// Now split into path parts
|
||||
string[] leftParts = left.Split('/');
|
||||
string[] rightParts = right.Split('/');
|
||||
|
||||
// Then compare each part in turn
|
||||
for (int i = 0; i < leftParts.Length && i < rightParts.Length; i++)
|
||||
{
|
||||
int partCompare = ComparePathSegment(leftParts[i], rightParts[i]);
|
||||
if (partCompare != 0)
|
||||
return partCompare;
|
||||
}
|
||||
|
||||
// If we got out here, then it looped through at least one of the strings
|
||||
if (leftParts.Length > rightParts.Length)
|
||||
return 1;
|
||||
if (leftParts.Length < rightParts.Length)
|
||||
return -1;
|
||||
|
||||
return leftOrig.CompareTo(rightOrig);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two path segments deterministically
|
||||
/// </summary>
|
||||
private static int ComparePathSegment(string left, string right)
|
||||
{
|
||||
// If the lengths are both zero, they're equal
|
||||
if (left.Length == 0 && right.Length == 0)
|
||||
return 0;
|
||||
|
||||
// Shorter strings are sorted before
|
||||
if (left.Length == 0)
|
||||
return -1;
|
||||
if (right.Length == 0)
|
||||
return 1;
|
||||
|
||||
// Otherwise, loop through until we have an answer
|
||||
for (int i = 0; i < left.Length && i < right.Length; i++)
|
||||
{
|
||||
// Get the next characters from the inputs as integers
|
||||
int leftChar = left[i];
|
||||
int rightChar = right[i];
|
||||
|
||||
// If the characters are the same, continue
|
||||
if (leftChar == rightChar)
|
||||
continue;
|
||||
|
||||
// If they're different, check which one was larger
|
||||
return leftChar > rightChar ? 1 : -1;
|
||||
}
|
||||
|
||||
// If we got out here, then it looped through at least one of the strings
|
||||
if (left.Length > right.Length)
|
||||
return 1;
|
||||
if (left.Length < right.Length)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
92
SabreTools.IO/Compare/NaturalReversedComparer.cs
Normal file
92
SabreTools.IO/Compare/NaturalReversedComparer.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
*
|
||||
* Links for info and original source code:
|
||||
*
|
||||
* https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
|
||||
* http://www.codeproject.com/Articles/22517/Natural-Sort-Comparer
|
||||
*
|
||||
* Exact code implementation used with permission, originally by motoschifo
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SabreTools.Text.Compare
|
||||
{
|
||||
public class NaturalReversedComparer : Comparer<string>, IDisposable
|
||||
{
|
||||
private readonly Dictionary<string, string[]> _table;
|
||||
|
||||
public NaturalReversedComparer()
|
||||
{
|
||||
_table = [];
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_table.Clear();
|
||||
}
|
||||
|
||||
public override int Compare(string? x, string? y)
|
||||
{
|
||||
if (x is null || y is null)
|
||||
{
|
||||
if (x is null && y is not null)
|
||||
return -1;
|
||||
else if (x is not null && y is null)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (y.ToLowerInvariant() == x.ToLowerInvariant())
|
||||
return y.CompareTo(x);
|
||||
|
||||
if (!_table.TryGetValue(x, out string[]? x1))
|
||||
{
|
||||
//x1 = Regex.Split(x.Replace(" ", string.Empty), "([0-9]+)");
|
||||
x1 = Regex.Split(x.ToLowerInvariant(), "([0-9]+)");
|
||||
x1 = Array.FindAll(x1, s => !string.IsNullOrEmpty(s));
|
||||
_table.Add(x, x1);
|
||||
}
|
||||
|
||||
if (!_table.TryGetValue(y, out string[]? y1))
|
||||
{
|
||||
//y1 = Regex.Split(y.Replace(" ", string.Empty), "([0-9]+)");
|
||||
y1 = Regex.Split(y.ToLowerInvariant(), "([0-9]+)");
|
||||
y1 = Array.FindAll(y1, s => !string.IsNullOrEmpty(s));
|
||||
_table.Add(y, y1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < x1.Length && i < y1.Length; i++)
|
||||
{
|
||||
if (x1[i] != y1[i])
|
||||
return PartCompare(x1[i], y1[i]);
|
||||
}
|
||||
|
||||
if (y1.Length > x1.Length)
|
||||
return 1;
|
||||
else if (x1.Length > y1.Length)
|
||||
return -1;
|
||||
else
|
||||
return y.CompareTo(x);
|
||||
}
|
||||
|
||||
private static int PartCompare(string left, string right)
|
||||
{
|
||||
if (!long.TryParse(left, out long x))
|
||||
return NaturalComparerUtil.ComparePaths(right, left);
|
||||
|
||||
if (!long.TryParse(right, out long y))
|
||||
return NaturalComparerUtil.ComparePaths(right, left);
|
||||
|
||||
// If we have an equal part, then make sure that "longer" ones are taken into account
|
||||
if (y.CompareTo(x) == 0)
|
||||
return right.Length - left.Length;
|
||||
|
||||
return y.CompareTo(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,10 @@
|
||||
|
||||
namespace SabreTools.IO.Compression.BZip2
|
||||
{
|
||||
#pragma warning disable IDE0047
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2002
|
||||
#pragma warning disable IDE2003
|
||||
// /**
|
||||
// * Checks if the signature matches what is expected for a bzip2 file.
|
||||
// *
|
||||
@@ -111,4 +115,4 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -58,13 +58,24 @@ using System.IO;
|
||||
#nullable disable
|
||||
namespace SabreTools.IO.Compression.BZip2
|
||||
{
|
||||
#pragma warning disable IDE0001
|
||||
#pragma warning disable IDE0002
|
||||
#pragma warning disable IDE0004
|
||||
#pragma warning disable IDE0036
|
||||
#pragma warning disable IDE0040
|
||||
#pragma warning disable IDE0047
|
||||
#pragma warning disable IDE0048
|
||||
#pragma warning disable IDE0049
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2002
|
||||
#pragma warning disable IDE2003
|
||||
/// <summary>
|
||||
/// A read-only decorator stream that performs BZip2 decompression on Read.
|
||||
/// </summary>
|
||||
public class BZip2InputStream : System.IO.Stream
|
||||
{
|
||||
bool _disposed;
|
||||
bool _leaveOpen;
|
||||
readonly bool _leaveOpen;
|
||||
Int64 totalBytesRead;
|
||||
private int last;
|
||||
|
||||
@@ -79,7 +90,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
private bool blockRandomised;
|
||||
private int bsBuff;
|
||||
private int bsLive;
|
||||
private readonly CRC32 crc = new CRC32(true);
|
||||
private readonly CRC32 crc = new(true);
|
||||
private int nInUse;
|
||||
private Stream input;
|
||||
private int currentChar = -1;
|
||||
@@ -208,7 +219,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
throw new IndexOutOfRangeException(String.Format("offset({0}) count({1}) bLength({2})",
|
||||
offset, count, buffer.Length));
|
||||
|
||||
if (this.input == null)
|
||||
if (this.input is null)
|
||||
throw new IOException("the stream is not open");
|
||||
|
||||
|
||||
@@ -408,7 +419,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing && (this.input != null))
|
||||
if (disposing && (this.input is not null))
|
||||
this.input.Close();
|
||||
_disposed = true;
|
||||
}
|
||||
@@ -491,8 +502,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
this.blockRandomised = (GetBits(1) == 1);
|
||||
|
||||
// Lazily allocate data
|
||||
if (this.data == null)
|
||||
this.data = new DecompressionState(this.blockSize100k);
|
||||
this.data ??= new DecompressionState(this.blockSize100k);
|
||||
|
||||
// currBlockNo++;
|
||||
getAndMoveToFrontDecode();
|
||||
@@ -552,7 +562,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
public override void Close()
|
||||
{
|
||||
Stream inShadow = this.input;
|
||||
if (inShadow != null)
|
||||
if (inShadow is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1094,7 +1104,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
|
||||
private void SetupBlock()
|
||||
{
|
||||
if (this.data == null)
|
||||
if (this.data is null)
|
||||
return;
|
||||
|
||||
int i;
|
||||
@@ -1372,7 +1382,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
// it can happen, if the compressor mixed small and large
|
||||
// blocks. Normally only the last block will be smaller
|
||||
// than others.
|
||||
if ((ttShadow == null) || (ttShadow.Length < length))
|
||||
if ((ttShadow is null) || (ttShadow.Length < length))
|
||||
{
|
||||
this.tt = ttShadow = new int[length];
|
||||
}
|
||||
@@ -1383,4 +1393,4 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
// Design Notes:
|
||||
//
|
||||
// This class follows the classic Decorator pattern: it is a Stream that
|
||||
@@ -85,6 +84,14 @@ using System.IO;
|
||||
#nullable disable
|
||||
namespace SabreTools.IO.Compression.BZip2
|
||||
{
|
||||
#pragma warning disable IDE0001
|
||||
#pragma warning disable IDE0004
|
||||
#pragma warning disable IDE0040
|
||||
#pragma warning disable IDE0048
|
||||
#pragma warning disable IDE0049
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2002
|
||||
#pragma warning disable IDE2003
|
||||
/// <summary>
|
||||
/// A write-only decorator stream that compresses data as it is
|
||||
/// written using the BZip2 algorithm.
|
||||
@@ -92,14 +99,14 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
public class BZip2OutputStream : System.IO.Stream
|
||||
{
|
||||
int totalBytesWrittenIn;
|
||||
bool leaveOpen;
|
||||
readonly bool leaveOpen;
|
||||
BZip2Compressor compressor;
|
||||
uint combinedCRC;
|
||||
Stream output;
|
||||
BitWriter bw;
|
||||
int blockSize100k; // 0...9
|
||||
readonly int blockSize100k; // 0...9
|
||||
|
||||
private TraceBits desiredTrace = TraceBits.Crc | TraceBits.Write;
|
||||
private readonly TraceBits desiredTrace = TraceBits.Crc | TraceBits.Write;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new <c>BZip2OutputStream</c>, that sends its
|
||||
@@ -218,7 +225,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
/// </remarks>
|
||||
public override void Close()
|
||||
{
|
||||
if (output != null)
|
||||
if (output is not null)
|
||||
{
|
||||
Stream o = this.output;
|
||||
Finish();
|
||||
@@ -233,7 +240,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
if (this.output != null)
|
||||
if (this.output is not null)
|
||||
{
|
||||
this.bw.Flush();
|
||||
this.output.Flush();
|
||||
@@ -348,7 +355,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
if (offset + count > buffer.Length)
|
||||
throw new IndexOutOfRangeException(String.Format("offset({0}) count({1}) bLength({2})",
|
||||
offset, count, buffer.Length));
|
||||
if (this.output == null)
|
||||
if (this.output is null)
|
||||
throw new IOException("the stream is not open");
|
||||
|
||||
if (count == 0) return; // nothing to do
|
||||
@@ -429,7 +436,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.output == null) throw new ObjectDisposedException("BZip2Stream");
|
||||
if (this.output is null) throw new ObjectDisposedException("BZip2Stream");
|
||||
return this.output.CanWrite;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,246 +1,249 @@
|
||||
// BitWriter.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2011 Dino Chiesa.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Last Saved: <2011-July-25 18:57:31>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines the BitWriter class, which writes bits at a time
|
||||
// to an output stream. It's used by the BZip2Compressor class, and by
|
||||
// the BZip2OutputStream class and its parallel variant,
|
||||
// ParallelBZip2OutputStream.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// Design notes:
|
||||
//
|
||||
// BZip2 employs byte-shredding in its data format - rather than
|
||||
// aligning all data items in a compressed .bz2 file on byte barriers,
|
||||
// the BZip2 format uses portions of bytes to represent independent
|
||||
// pieces of information. This "shredding" starts with the first
|
||||
// "randomised" bit - just 12 bytes or so into a bz2 file or stream. But
|
||||
// the approach is used extensively in bzip2 files - sometimes 5 bits
|
||||
// are used, sometimes 24 or 3 bits, sometimes just 1 bit, and so on.
|
||||
// It's not possible to send this information directly to a stream in
|
||||
// this form; Streams in .NET accept byte-oriented input. Therefore,
|
||||
// when actually writing a bz2 file, the output data must be organized
|
||||
// into a byte-aligned format before being written to the output stream.
|
||||
//
|
||||
// This BitWriter class provides the byte-shredding necessary for BZip2
|
||||
// output. Think of this class as an Adapter that enables Bit-oriented
|
||||
// output to a standard byte-oriented .NET stream. This class writes
|
||||
// data out to the captive output stream only after the data bits have
|
||||
// been accumulated and aligned. For example, suppose that during
|
||||
// operation, the BZip2 compressor emits 5 bits, then 24 bits, then 32
|
||||
// bits. When the first 5 bits are sent to the BitWriter, nothing is
|
||||
// written to the output stream; instead these 5 bits are simply stored
|
||||
// in the internal accumulator. When the next 24 bits are written, the
|
||||
// first 3 bits are gathered with the accumulated bits. The resulting
|
||||
// 5+3 constitutes an entire byte; the BitWriter then actually writes
|
||||
// that byte to the output stream. This leaves 21 bits. BitWriter writes
|
||||
// 2 more whole bytes (16 more bits), in 8-bit chunks, leaving 5 in the
|
||||
// accumulator. BitWriter then follows the same procedure with the 32
|
||||
// new bits. And so on.
|
||||
//
|
||||
// A quick tour of the implementation:
|
||||
//
|
||||
// The accumulator is a uint - so it can accumulate at most 4 bytes of
|
||||
// information. In practice because of the design of this class, it
|
||||
// never accumulates more than 3 bytes.
|
||||
//
|
||||
// The Flush() method emits all whole bytes available. After calling
|
||||
// Flush(), there may be between 0-7 bits yet to be emitted into the
|
||||
// output stream.
|
||||
//
|
||||
// FinishAndPad() emits all data, including the last partial byte and
|
||||
// any necessary padding. In effect, it establishes a byte-alignment
|
||||
// barrier. To support bzip2, FinishAndPad() should be called only once
|
||||
// for a bz2 file, after the last bit of data has been written through
|
||||
// this adapter. Other binary file formats may use byte-alignment at
|
||||
// various points within the file, and FinishAndPad() would support that
|
||||
// scenario.
|
||||
//
|
||||
// The internal fn Reset() is used to reset the state of the adapter;
|
||||
// this class is used by BZip2Compressor, instances of which get re-used
|
||||
// by multiple distinct threads, for different blocks of data.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SabreTools.IO.Compression.BZip2
|
||||
{
|
||||
internal class BitWriter
|
||||
{
|
||||
uint accumulator;
|
||||
int nAccumulatedBits;
|
||||
Stream output;
|
||||
int totalBytesWrittenOut;
|
||||
|
||||
public BitWriter(Stream s)
|
||||
{
|
||||
this.output = s;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delivers the remaining bits, left-aligned, in a byte.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is valid only if NumRemainingBits is less than 8;
|
||||
/// in other words it is valid only after a call to Flush().
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public byte RemainingBits
|
||||
{
|
||||
get
|
||||
{
|
||||
return (byte)(this.accumulator >> (32 - this.nAccumulatedBits) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
public int NumRemainingBits
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.nAccumulatedBits;
|
||||
}
|
||||
}
|
||||
|
||||
public int TotalBytesWrittenOut
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.totalBytesWrittenOut;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the BitWriter.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is useful when the BitWriter writes into a MemoryStream, and
|
||||
/// is used by a BZip2Compressor, which itself is re-used for multiple
|
||||
/// distinct data blocks.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void Reset()
|
||||
{
|
||||
this.accumulator = 0;
|
||||
this.nAccumulatedBits = 0;
|
||||
this.totalBytesWrittenOut = 0;
|
||||
this.output.Seek(0, SeekOrigin.Begin);
|
||||
this.output.SetLength(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write some number of bits from the given value, into the output.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The nbits value should be a max of 25, for safety. For performance
|
||||
/// reasons, this method does not check!
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void WriteBits(int nbits, uint value)
|
||||
{
|
||||
int nAccumulated = this.nAccumulatedBits;
|
||||
uint u = this.accumulator;
|
||||
|
||||
while (nAccumulated >= 8)
|
||||
{
|
||||
this.output.WriteByte((byte)(u >> 24 & 0xff));
|
||||
this.totalBytesWrittenOut++;
|
||||
u <<= 8;
|
||||
nAccumulated -= 8;
|
||||
}
|
||||
|
||||
this.accumulator = u | (value << (32 - nAccumulated - nbits));
|
||||
this.nAccumulatedBits = nAccumulated + nbits;
|
||||
|
||||
// Console.WriteLine("WriteBits({0}, 0x{1:X2}) => {2:X8} n({3})",
|
||||
// nbits, value, accumulator, nAccumulatedBits);
|
||||
// Console.ReadLine();
|
||||
|
||||
// At this point the accumulator may contain up to 31 bits waiting for
|
||||
// output.
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Write a full 8-bit byte into the output.
|
||||
/// </summary>
|
||||
public void WriteByte(byte b)
|
||||
{
|
||||
WriteBits(8, b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write four 8-bit bytes into the output.
|
||||
/// </summary>
|
||||
public void WriteInt(uint u)
|
||||
{
|
||||
WriteBits(8, (u >> 24) & 0xff);
|
||||
WriteBits(8, (u >> 16) & 0xff);
|
||||
WriteBits(8, (u >> 8) & 0xff);
|
||||
WriteBits(8, u & 0xff);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write all available byte-aligned bytes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method writes no new output, but flushes any accumulated
|
||||
/// bits. At completion, the accumulator may contain up to 7
|
||||
/// bits.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This is necessary when re-assembling output from N independent
|
||||
/// compressors, one for each of N blocks. The output of any
|
||||
/// particular compressor will in general have some fragment of a byte
|
||||
/// remaining. This fragment needs to be accumulated into the
|
||||
/// parent BZip2OutputStream.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void Flush()
|
||||
{
|
||||
WriteBits(0, 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Writes all available bytes, and emits padding for the final byte as
|
||||
/// necessary. This must be the last method invoked on an instance of
|
||||
/// BitWriter.
|
||||
/// </summary>
|
||||
public void FinishAndPad()
|
||||
{
|
||||
Flush();
|
||||
|
||||
if (this.NumRemainingBits > 0)
|
||||
{
|
||||
byte b = (byte)((this.accumulator >> 24) & 0xff);
|
||||
this.output.WriteByte(b);
|
||||
this.totalBytesWrittenOut++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// BitWriter.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2011 Dino Chiesa.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Last Saved: <2011-July-25 18:57:31>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines the BitWriter class, which writes bits at a time
|
||||
// to an output stream. It's used by the BZip2Compressor class, and by
|
||||
// the BZip2OutputStream class and its parallel variant,
|
||||
// ParallelBZip2OutputStream.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// Design notes:
|
||||
//
|
||||
// BZip2 employs byte-shredding in its data format - rather than
|
||||
// aligning all data items in a compressed .bz2 file on byte barriers,
|
||||
// the BZip2 format uses portions of bytes to represent independent
|
||||
// pieces of information. This "shredding" starts with the first
|
||||
// "randomised" bit - just 12 bytes or so into a bz2 file or stream. But
|
||||
// the approach is used extensively in bzip2 files - sometimes 5 bits
|
||||
// are used, sometimes 24 or 3 bits, sometimes just 1 bit, and so on.
|
||||
// It's not possible to send this information directly to a stream in
|
||||
// this form; Streams in .NET accept byte-oriented input. Therefore,
|
||||
// when actually writing a bz2 file, the output data must be organized
|
||||
// into a byte-aligned format before being written to the output stream.
|
||||
//
|
||||
// This BitWriter class provides the byte-shredding necessary for BZip2
|
||||
// output. Think of this class as an Adapter that enables Bit-oriented
|
||||
// output to a standard byte-oriented .NET stream. This class writes
|
||||
// data out to the captive output stream only after the data bits have
|
||||
// been accumulated and aligned. For example, suppose that during
|
||||
// operation, the BZip2 compressor emits 5 bits, then 24 bits, then 32
|
||||
// bits. When the first 5 bits are sent to the BitWriter, nothing is
|
||||
// written to the output stream; instead these 5 bits are simply stored
|
||||
// in the internal accumulator. When the next 24 bits are written, the
|
||||
// first 3 bits are gathered with the accumulated bits. The resulting
|
||||
// 5+3 constitutes an entire byte; the BitWriter then actually writes
|
||||
// that byte to the output stream. This leaves 21 bits. BitWriter writes
|
||||
// 2 more whole bytes (16 more bits), in 8-bit chunks, leaving 5 in the
|
||||
// accumulator. BitWriter then follows the same procedure with the 32
|
||||
// new bits. And so on.
|
||||
//
|
||||
// A quick tour of the implementation:
|
||||
//
|
||||
// The accumulator is a uint - so it can accumulate at most 4 bytes of
|
||||
// information. In practice because of the design of this class, it
|
||||
// never accumulates more than 3 bytes.
|
||||
//
|
||||
// The Flush() method emits all whole bytes available. After calling
|
||||
// Flush(), there may be between 0-7 bits yet to be emitted into the
|
||||
// output stream.
|
||||
//
|
||||
// FinishAndPad() emits all data, including the last partial byte and
|
||||
// any necessary padding. In effect, it establishes a byte-alignment
|
||||
// barrier. To support bzip2, FinishAndPad() should be called only once
|
||||
// for a bz2 file, after the last bit of data has been written through
|
||||
// this adapter. Other binary file formats may use byte-alignment at
|
||||
// various points within the file, and FinishAndPad() would support that
|
||||
// scenario.
|
||||
//
|
||||
// The internal fn Reset() is used to reset the state of the adapter;
|
||||
// this class is used by BZip2Compressor, instances of which get re-used
|
||||
// by multiple distinct threads, for different blocks of data.
|
||||
//
|
||||
|
||||
using System.IO;
|
||||
|
||||
#pragma warning disable IDE0040
|
||||
#pragma warning disable IDE0048
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2002
|
||||
namespace SabreTools.IO.Compression.BZip2
|
||||
{
|
||||
internal class BitWriter
|
||||
{
|
||||
uint accumulator;
|
||||
int nAccumulatedBits;
|
||||
readonly Stream output;
|
||||
int totalBytesWrittenOut;
|
||||
|
||||
public BitWriter(Stream s)
|
||||
{
|
||||
this.output = s;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delivers the remaining bits, left-aligned, in a byte.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is valid only if NumRemainingBits is less than 8;
|
||||
/// in other words it is valid only after a call to Flush().
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public byte RemainingBits
|
||||
{
|
||||
get
|
||||
{
|
||||
return (byte)(this.accumulator >> (32 - this.nAccumulatedBits) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
public int NumRemainingBits
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.nAccumulatedBits;
|
||||
}
|
||||
}
|
||||
|
||||
public int TotalBytesWrittenOut
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.totalBytesWrittenOut;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the BitWriter.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is useful when the BitWriter writes into a MemoryStream, and
|
||||
/// is used by a BZip2Compressor, which itself is re-used for multiple
|
||||
/// distinct data blocks.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void Reset()
|
||||
{
|
||||
this.accumulator = 0;
|
||||
this.nAccumulatedBits = 0;
|
||||
this.totalBytesWrittenOut = 0;
|
||||
this.output.Seek(0, SeekOrigin.Begin);
|
||||
this.output.SetLength(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write some number of bits from the given value, into the output.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The nbits value should be a max of 25, for safety. For performance
|
||||
/// reasons, this method does not check!
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void WriteBits(int nbits, uint value)
|
||||
{
|
||||
int nAccumulated = this.nAccumulatedBits;
|
||||
uint u = this.accumulator;
|
||||
|
||||
while (nAccumulated >= 8)
|
||||
{
|
||||
this.output.WriteByte((byte)(u >> 24 & 0xff));
|
||||
this.totalBytesWrittenOut++;
|
||||
u <<= 8;
|
||||
nAccumulated -= 8;
|
||||
}
|
||||
|
||||
this.accumulator = u | (value << (32 - nAccumulated - nbits));
|
||||
this.nAccumulatedBits = nAccumulated + nbits;
|
||||
|
||||
// Console.WriteLine("WriteBits({0}, 0x{1:X2}) => {2:X8} n({3})",
|
||||
// nbits, value, accumulator, nAccumulatedBits);
|
||||
// Console.ReadLine();
|
||||
|
||||
// At this point the accumulator may contain up to 31 bits waiting for
|
||||
// output.
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Write a full 8-bit byte into the output.
|
||||
/// </summary>
|
||||
public void WriteByte(byte b)
|
||||
{
|
||||
WriteBits(8, b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write four 8-bit bytes into the output.
|
||||
/// </summary>
|
||||
public void WriteInt(uint u)
|
||||
{
|
||||
WriteBits(8, (u >> 24) & 0xff);
|
||||
WriteBits(8, (u >> 16) & 0xff);
|
||||
WriteBits(8, (u >> 8) & 0xff);
|
||||
WriteBits(8, u & 0xff);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write all available byte-aligned bytes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method writes no new output, but flushes any accumulated
|
||||
/// bits. At completion, the accumulator may contain up to 7
|
||||
/// bits.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This is necessary when re-assembling output from N independent
|
||||
/// compressors, one for each of N blocks. The output of any
|
||||
/// particular compressor will in general have some fragment of a byte
|
||||
/// remaining. This fragment needs to be accumulated into the
|
||||
/// parent BZip2OutputStream.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void Flush()
|
||||
{
|
||||
WriteBits(0, 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Writes all available bytes, and emits padding for the final byte as
|
||||
/// necessary. This must be the last method invoked on an instance of
|
||||
/// BitWriter.
|
||||
/// </summary>
|
||||
public void FinishAndPad()
|
||||
{
|
||||
Flush();
|
||||
|
||||
if (this.NumRemainingBits > 0)
|
||||
{
|
||||
byte b = (byte)((this.accumulator >> 24) & 0xff);
|
||||
this.output.WriteByte(b);
|
||||
this.totalBytesWrittenOut++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,9 +29,17 @@ using System;
|
||||
using Interop = System.Runtime.InteropServices;
|
||||
|
||||
#nullable disable
|
||||
#pragma warning disable CS0618
|
||||
namespace SabreTools.IO.Compression.BZip2
|
||||
{
|
||||
#pragma warning disable IDE0001
|
||||
#pragma warning disable IDE0002
|
||||
#pragma warning disable IDE0047
|
||||
#pragma warning disable IDE0048
|
||||
#pragma warning disable IDE0049
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2002
|
||||
#pragma warning disable IDE2003
|
||||
#pragma warning disable IDE2004
|
||||
/// <summary>
|
||||
/// Computes a CRC-32. The CRC-32 algorithm is parameterized - you
|
||||
/// can set the polynomial and enable or disable bit
|
||||
@@ -91,7 +99,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
/// <returns>the CRC32 calculation</returns>
|
||||
public Int32 GetCrc32AndCopy(System.IO.Stream input, System.IO.Stream output)
|
||||
{
|
||||
if (input == null)
|
||||
if (input is null)
|
||||
throw new Exception("The input stream must not be null.");
|
||||
|
||||
unchecked
|
||||
@@ -101,13 +109,13 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
|
||||
_TotalBytesRead = 0;
|
||||
int count = input.Read(buffer, 0, readSize);
|
||||
if (output != null) output.Write(buffer, 0, count);
|
||||
output?.Write(buffer, 0, count);
|
||||
_TotalBytesRead += count;
|
||||
while (count > 0)
|
||||
{
|
||||
SlurpBlock(buffer, 0, count);
|
||||
count = input.Read(buffer, 0, readSize);
|
||||
if (output != null) output.Write(buffer, 0, count);
|
||||
output?.Write(buffer, 0, count);
|
||||
_TotalBytesRead += count;
|
||||
}
|
||||
|
||||
@@ -143,7 +151,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
/// <param name="count">how many bytes within the block to slurp</param>
|
||||
public void SlurpBlock(byte[] block, int offset, int count)
|
||||
{
|
||||
if (block == null)
|
||||
if (block is null)
|
||||
throw new Exception("The data buffer must not be null.");
|
||||
|
||||
// bzip algorithm
|
||||
@@ -279,7 +287,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
crc32Table[i] = dwCrc;
|
||||
}
|
||||
i++;
|
||||
} while (i!=0);
|
||||
} while (i != 0);
|
||||
}
|
||||
|
||||
#if VERBOSE
|
||||
@@ -303,10 +311,10 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
private uint gf2_matrix_times(uint[] matrix, uint vec)
|
||||
{
|
||||
uint sum = 0;
|
||||
int i=0;
|
||||
int i = 0;
|
||||
while (vec != 0)
|
||||
{
|
||||
if ((vec & 0x01)== 0x01)
|
||||
if ((vec & 0x01) == 0x01)
|
||||
sum ^= matrix[i];
|
||||
vec >>= 1;
|
||||
i++;
|
||||
@@ -341,8 +349,8 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
uint crc1= ~_register;
|
||||
uint crc2= (uint) crc;
|
||||
uint crc1 = ~_register;
|
||||
uint crc2 = (uint)crc;
|
||||
|
||||
// put operator for one zero bit in odd
|
||||
odd[0] = this.dwPolynomial; // the CRC-32 polynomial
|
||||
@@ -359,15 +367,16 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
// put operator for four zero bits in odd
|
||||
gf2_matrix_square(odd, even);
|
||||
|
||||
uint len2 = (uint) length;
|
||||
uint len2 = (uint)length;
|
||||
|
||||
// apply len2 zeros to crc1 (first square will put the operator for one
|
||||
// zero byte, eight zero bits, in even)
|
||||
do {
|
||||
do
|
||||
{
|
||||
// apply zeros operator for this bit of len2
|
||||
gf2_matrix_square(even, odd);
|
||||
|
||||
if ((len2 & 1)== 1)
|
||||
if ((len2 & 1) == 1)
|
||||
crc1 = gf2_matrix_times(even, crc1);
|
||||
len2 >>= 1;
|
||||
|
||||
@@ -376,7 +385,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
|
||||
// another iteration of the loop with odd and even swapped
|
||||
gf2_matrix_square(odd, even);
|
||||
if ((len2 & 1)==1)
|
||||
if ((len2 & 1) == 1)
|
||||
crc1 = gf2_matrix_times(odd, crc1);
|
||||
len2 >>= 1;
|
||||
|
||||
@@ -385,7 +394,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
|
||||
crc1 ^= crc2;
|
||||
|
||||
_register= ~crc1;
|
||||
_register = ~crc1;
|
||||
|
||||
//return (int) crc1;
|
||||
return;
|
||||
@@ -417,7 +426,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public CRC32(bool reverseBits) :
|
||||
this( unchecked((int)0xEDB88320), reverseBits)
|
||||
this(unchecked((int)0xEDB88320), reverseBits)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -450,7 +459,7 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
public CRC32(int polynomial, bool reverseBits)
|
||||
{
|
||||
this.reverseBits = reverseBits;
|
||||
this.dwPolynomial = (uint) polynomial;
|
||||
this.dwPolynomial = (uint)polynomial;
|
||||
this.GenerateLookupTable();
|
||||
}
|
||||
|
||||
@@ -469,9 +478,9 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
}
|
||||
|
||||
// private member vars
|
||||
private UInt32 dwPolynomial;
|
||||
private readonly UInt32 dwPolynomial;
|
||||
private Int64 _TotalBytesRead;
|
||||
private bool reverseBits;
|
||||
private readonly bool reverseBits;
|
||||
private UInt32[] crc32Table;
|
||||
private const int BUFFER_SIZE = 8192;
|
||||
private UInt32 _register = 0xFFFFFFFFU;
|
||||
@@ -502,8 +511,8 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
private static readonly Int64 UnsetLengthLimit = -99;
|
||||
|
||||
internal System.IO.Stream _innerStream;
|
||||
private CRC32 _Crc32;
|
||||
private Int64 _lengthLimit = -99;
|
||||
private readonly CRC32 _Crc32;
|
||||
private readonly Int64 _lengthLimit = -99;
|
||||
private bool _leaveOpen;
|
||||
|
||||
/// <summary>
|
||||
@@ -812,4 +821,4 @@ namespace SabreTools.IO.Compression.BZip2
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,99 +1,96 @@
|
||||
// Rand.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2011 Dino Chiesa.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Last Saved: <2011-July-31 15:09:16>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines a helper class for the BZip2 classes. This code
|
||||
// is derived from the original BZip2 source code.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace SabreTools.IO.Compression.BZip2
|
||||
{
|
||||
internal static class Rand
|
||||
{
|
||||
private static int[] RNUMS =
|
||||
{
|
||||
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
|
||||
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
|
||||
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
|
||||
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
|
||||
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
|
||||
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
|
||||
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
|
||||
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
|
||||
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
|
||||
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
|
||||
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
|
||||
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
|
||||
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
|
||||
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
|
||||
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
|
||||
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
|
||||
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
|
||||
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
|
||||
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
|
||||
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
|
||||
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
|
||||
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
|
||||
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
|
||||
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
|
||||
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
|
||||
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
|
||||
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
|
||||
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
|
||||
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
|
||||
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
|
||||
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
|
||||
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
|
||||
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
|
||||
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
|
||||
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
|
||||
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
|
||||
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
|
||||
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
|
||||
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
|
||||
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
|
||||
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
|
||||
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
|
||||
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
|
||||
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
|
||||
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
|
||||
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
|
||||
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
|
||||
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
|
||||
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
|
||||
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
|
||||
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
|
||||
936, 638
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the "random" number at a specific index.
|
||||
/// </summary>
|
||||
/// <param name='i'>the index</param>
|
||||
/// <returns>the random number</returns>
|
||||
internal static int Rnums(int i)
|
||||
{
|
||||
return RNUMS[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Rand.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2011 Dino Chiesa.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Last Saved: <2011-July-31 15:09:16>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines a helper class for the BZip2 classes. This code
|
||||
// is derived from the original BZip2 source code.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
namespace SabreTools.IO.Compression.BZip2
|
||||
{
|
||||
internal static class Rand
|
||||
{
|
||||
private static readonly int[] RNUMS =
|
||||
[
|
||||
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
|
||||
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
|
||||
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
|
||||
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
|
||||
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
|
||||
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
|
||||
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
|
||||
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
|
||||
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
|
||||
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
|
||||
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
|
||||
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
|
||||
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
|
||||
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
|
||||
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
|
||||
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
|
||||
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
|
||||
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
|
||||
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
|
||||
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
|
||||
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
|
||||
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
|
||||
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
|
||||
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
|
||||
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
|
||||
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
|
||||
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
|
||||
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
|
||||
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
|
||||
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
|
||||
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
|
||||
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
|
||||
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
|
||||
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
|
||||
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
|
||||
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
|
||||
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
|
||||
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
|
||||
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
|
||||
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
|
||||
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
|
||||
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
|
||||
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
|
||||
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
|
||||
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
|
||||
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
|
||||
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
|
||||
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
|
||||
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
|
||||
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
|
||||
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
|
||||
936, 638
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Returns the "random" number at a specific index.
|
||||
/// </summary>
|
||||
/// <param name='i'>the index</param>
|
||||
/// <returns>the random number</returns>
|
||||
internal static int Rnums(int i)
|
||||
{
|
||||
return RNUMS[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,12 +41,12 @@ namespace SabreTools.IO.Compression.Blast
|
||||
/// that library. (Note: PKWare overused the "implode" verb, and the format
|
||||
/// used by their library implode() function is completely different and
|
||||
/// incompatible with the implode compression method supported by PKZIP.)
|
||||
///
|
||||
///
|
||||
/// The binary mode for stdio functions should be used to assure that the
|
||||
/// compressed data is not corrupted when read or written. For example:
|
||||
/// fopen(..., "rb") and fopen(..., "wb").
|
||||
/// </summary>
|
||||
public unsafe class Decompressor
|
||||
public class Decompressor
|
||||
{
|
||||
#region Huffman Encoding
|
||||
|
||||
@@ -168,29 +168,29 @@ namespace SabreTools.IO.Compression.Blast
|
||||
/// First byte is 0 if literals are uncoded or 1 if they are coded. Second
|
||||
/// byte is 4, 5, or 6 for the number of extra bits in the distance code.
|
||||
/// This is the base-2 logarithm of the dictionary size minus six.
|
||||
///
|
||||
///
|
||||
/// Compressed data is a combination of literals and length/distance pairs
|
||||
/// terminated by an end code. Literals are either Huffman coded or
|
||||
/// uncoded bytes. A length/distance pair is a coded length followed by a
|
||||
/// coded distance to represent a string that occurs earlier in the
|
||||
/// uncompressed data that occurs again at the current location.
|
||||
///
|
||||
///
|
||||
/// A bit preceding a literal or length/distance pair indicates which comes
|
||||
/// next, 0 for literals, 1 for length/distance.
|
||||
///
|
||||
///
|
||||
/// If literals are uncoded, then the next eight bits are the literal, in the
|
||||
/// normal bit order in the stream, i.e. no bit-reversal is needed. Similarly,
|
||||
/// no bit reversal is needed for either the length extra bits or the distance
|
||||
/// extra bits.
|
||||
///
|
||||
///
|
||||
/// Literal bytes are simply written to the output. A length/distance pair is
|
||||
/// an instruction to copy previously uncompressed bytes to the output. The
|
||||
/// copy is from distance bytes back in the output stream, copying for length
|
||||
/// bytes.
|
||||
///
|
||||
///
|
||||
/// Distances pointing before the beginning of the output data are not
|
||||
/// permitted.
|
||||
///
|
||||
///
|
||||
/// Overlapped copies, where the length is greater than the distance, are
|
||||
/// allowed and common. For example, a distance of one and a length of 518
|
||||
/// simply copies the last byte 518 times. A distance of four and a length of
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace SabreTools.IO.Compression.Blast
|
||||
// Assumes lengths are within bounds
|
||||
for (symbol = 0; symbol < n; symbol++)
|
||||
{
|
||||
(Count[length[symbol]])++;
|
||||
Count[length[symbol]]++;
|
||||
}
|
||||
|
||||
// No codes! Complete, but decode() will fail
|
||||
@@ -138,7 +138,7 @@ namespace SabreTools.IO.Compression.Blast
|
||||
/// bits are pulled from the compressed data one at a time and used to
|
||||
/// build the code value reversed from what is in the stream in order to
|
||||
/// permit simple integer comparisons for decoding.
|
||||
///
|
||||
///
|
||||
/// The first code for the shortest length is all ones. Subsequent codes of
|
||||
/// the same length are simply integer decrements of the previous code. When
|
||||
/// moving up a length, a one bit is appended to the code. For a complete
|
||||
@@ -182,7 +182,7 @@ namespace SabreTools.IO.Compression.Blast
|
||||
len++;
|
||||
}
|
||||
|
||||
left = (MAXBITS + 1) - len;
|
||||
left = MAXBITS + 1 - len;
|
||||
if (left == 0)
|
||||
break;
|
||||
|
||||
|
||||
@@ -1,180 +1,177 @@
|
||||
// Zlib.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009-2011 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Last Saved: <2011-August-03 19:52:28>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines classes for ZLIB compression and
|
||||
// decompression. This code is derived from the jzlib implementation of
|
||||
// zlib, but significantly modified. The object model is not the same,
|
||||
// and many of the behaviors are new or different. Nonetheless, in
|
||||
// keeping with the license for jzlib, the copyright to that code is
|
||||
// included below.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// The following notice applies to jzlib:
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// jzlib is based on zlib-1.1.3.
|
||||
//
|
||||
// The following notice applies to zlib:
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler
|
||||
//
|
||||
// The ZLIB software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
// Jean-loup Gailly jloup@gzip.org
|
||||
// Mark Adler madler@alumni.caltech.edu
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
/// <summary>
|
||||
/// Computes an Adler-32 checksum.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Adler checksum is similar to a CRC checksum, but faster to compute, though less
|
||||
/// reliable. It is used in producing RFC1950 compressed streams. The Adler checksum
|
||||
/// is a required part of the "ZLIB" standard. Applications will almost never need to
|
||||
/// use this class directly.
|
||||
/// </remarks>
|
||||
///
|
||||
/// <exclude/>
|
||||
public sealed class Adler
|
||||
{
|
||||
// largest prime smaller than 65536
|
||||
private static readonly uint BASE = 65521;
|
||||
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
|
||||
private static readonly int NMAX = 5552;
|
||||
|
||||
|
||||
#pragma warning disable 3001
|
||||
#pragma warning disable 3002
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the Adler32 checksum.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is used within ZLIB. You probably don't need to use this directly.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// To compute an Adler32 checksum on a byte array:
|
||||
/// <code>
|
||||
/// var adler = Adler.Adler32(0, null, 0, 0);
|
||||
/// adler = Adler.Adler32(adler, buffer, index, length);
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static uint Adler32(uint adler, byte[] buf, int index, int len)
|
||||
{
|
||||
if (buf == null)
|
||||
return 1;
|
||||
|
||||
uint s1 = (uint)(adler & 0xffff);
|
||||
uint s2 = (uint)((adler >> 16) & 0xffff);
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
int k = len < NMAX ? len : NMAX;
|
||||
len -= k;
|
||||
while (k >= 16)
|
||||
{
|
||||
//s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
k -= 16;
|
||||
}
|
||||
if (k != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
s1 += buf[index++];
|
||||
s2 += s1;
|
||||
}
|
||||
while (--k != 0);
|
||||
}
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
return (uint)((s2 << 16) | s1);
|
||||
}
|
||||
#pragma warning restore 3001
|
||||
#pragma warning restore 3002
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// Zlib.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009-2011 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Last Saved: <2011-August-03 19:52:28>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines classes for ZLIB compression and
|
||||
// decompression. This code is derived from the jzlib implementation of
|
||||
// zlib, but significantly modified. The object model is not the same,
|
||||
// and many of the behaviors are new or different. Nonetheless, in
|
||||
// keeping with the license for jzlib, the copyright to that code is
|
||||
// included below.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// The following notice applies to jzlib:
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// jzlib is based on zlib-1.1.3.
|
||||
//
|
||||
// The following notice applies to zlib:
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler
|
||||
//
|
||||
// The ZLIB software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
// Jean-loup Gailly jloup@gzip.org
|
||||
// Mark Adler madler@alumni.caltech.edu
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0004
|
||||
#pragma warning disable IDE2002
|
||||
#pragma warning disable IDE2003
|
||||
/// <summary>
|
||||
/// Computes an Adler-32 checksum.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Adler checksum is similar to a CRC checksum, but faster to compute, though less
|
||||
/// reliable. It is used in producing RFC1950 compressed streams. The Adler checksum
|
||||
/// is a required part of the "ZLIB" standard. Applications will almost never need to
|
||||
/// use this class directly.
|
||||
/// </remarks>
|
||||
///
|
||||
/// <exclude/>
|
||||
public sealed class Adler
|
||||
{
|
||||
// largest prime smaller than 65536
|
||||
private static readonly uint BASE = 65521;
|
||||
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
|
||||
private static readonly int NMAX = 5552;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the Adler32 checksum.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is used within ZLIB. You probably don't need to use this directly.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// To compute an Adler32 checksum on a byte array:
|
||||
/// <code>
|
||||
/// var adler = Adler.Adler32(0, null, 0, 0);
|
||||
/// adler = Adler.Adler32(adler, buffer, index, length);
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static uint Adler32(uint adler, byte[] buf, int index, int len)
|
||||
{
|
||||
if (buf is null)
|
||||
return 1;
|
||||
|
||||
uint s1 = (uint)(adler & 0xffff);
|
||||
uint s2 = (uint)((adler >> 16) & 0xffff);
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
int k = len < NMAX ? len : NMAX;
|
||||
len -= k;
|
||||
while (k >= 16)
|
||||
{
|
||||
//s1 += (buf[index++] & 0xff); s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
s1 += buf[index++]; s2 += s1;
|
||||
k -= 16;
|
||||
}
|
||||
if (k != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
s1 += buf[index++];
|
||||
s2 += s1;
|
||||
}
|
||||
while (--k != 0);
|
||||
}
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
return (uint)((s2 << 16) | s1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,4 +75,4 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
FinishStarted, // finish started, need only more output at next deflate
|
||||
FinishDone // finish done, accept no more input or output
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,17 @@ using System;
|
||||
using Interop = System.Runtime.InteropServices;
|
||||
|
||||
#nullable disable
|
||||
#pragma warning disable CS0618
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0001
|
||||
#pragma warning disable IDE0002
|
||||
#pragma warning disable IDE0047
|
||||
#pragma warning disable IDE0048
|
||||
#pragma warning disable IDE0049
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2002
|
||||
#pragma warning disable IDE2003
|
||||
#pragma warning disable IDE2004
|
||||
/// <summary>
|
||||
/// Computes a CRC-32. The CRC-32 algorithm is parameterized - you
|
||||
/// can set the polynomial and enable or disable bit
|
||||
@@ -91,7 +99,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
/// <returns>the CRC32 calculation</returns>
|
||||
public Int32 GetCrc32AndCopy(System.IO.Stream input, System.IO.Stream output)
|
||||
{
|
||||
if (input == null)
|
||||
if (input is null)
|
||||
throw new Exception("The input stream must not be null.");
|
||||
|
||||
unchecked
|
||||
@@ -101,13 +109,13 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
|
||||
_TotalBytesRead = 0;
|
||||
int count = input.Read(buffer, 0, readSize);
|
||||
if (output != null) output.Write(buffer, 0, count);
|
||||
output?.Write(buffer, 0, count);
|
||||
_TotalBytesRead += count;
|
||||
while (count > 0)
|
||||
{
|
||||
SlurpBlock(buffer, 0, count);
|
||||
count = input.Read(buffer, 0, readSize);
|
||||
if (output != null) output.Write(buffer, 0, count);
|
||||
output?.Write(buffer, 0, count);
|
||||
_TotalBytesRead += count;
|
||||
}
|
||||
|
||||
@@ -143,7 +151,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
/// <param name="count">how many bytes within the block to slurp</param>
|
||||
public void SlurpBlock(byte[] block, int offset, int count)
|
||||
{
|
||||
if (block == null)
|
||||
if (block is null)
|
||||
throw new Exception("The data buffer must not be null.");
|
||||
|
||||
// bzip algorithm
|
||||
@@ -279,7 +287,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
crc32Table[i] = dwCrc;
|
||||
}
|
||||
i++;
|
||||
} while (i!=0);
|
||||
} while (i != 0);
|
||||
}
|
||||
|
||||
#if VERBOSE
|
||||
@@ -303,10 +311,10 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
private uint gf2_matrix_times(uint[] matrix, uint vec)
|
||||
{
|
||||
uint sum = 0;
|
||||
int i=0;
|
||||
int i = 0;
|
||||
while (vec != 0)
|
||||
{
|
||||
if ((vec & 0x01)== 0x01)
|
||||
if ((vec & 0x01) == 0x01)
|
||||
sum ^= matrix[i];
|
||||
vec >>= 1;
|
||||
i++;
|
||||
@@ -341,8 +349,8 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
uint crc1= ~_register;
|
||||
uint crc2= (uint) crc;
|
||||
uint crc1 = ~_register;
|
||||
uint crc2 = (uint)crc;
|
||||
|
||||
// put operator for one zero bit in odd
|
||||
odd[0] = this.dwPolynomial; // the CRC-32 polynomial
|
||||
@@ -359,15 +367,16 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
// put operator for four zero bits in odd
|
||||
gf2_matrix_square(odd, even);
|
||||
|
||||
uint len2 = (uint) length;
|
||||
uint len2 = (uint)length;
|
||||
|
||||
// apply len2 zeros to crc1 (first square will put the operator for one
|
||||
// zero byte, eight zero bits, in even)
|
||||
do {
|
||||
do
|
||||
{
|
||||
// apply zeros operator for this bit of len2
|
||||
gf2_matrix_square(even, odd);
|
||||
|
||||
if ((len2 & 1)== 1)
|
||||
if ((len2 & 1) == 1)
|
||||
crc1 = gf2_matrix_times(even, crc1);
|
||||
len2 >>= 1;
|
||||
|
||||
@@ -376,7 +385,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
|
||||
// another iteration of the loop with odd and even swapped
|
||||
gf2_matrix_square(odd, even);
|
||||
if ((len2 & 1)==1)
|
||||
if ((len2 & 1) == 1)
|
||||
crc1 = gf2_matrix_times(odd, crc1);
|
||||
len2 >>= 1;
|
||||
|
||||
@@ -385,7 +394,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
|
||||
crc1 ^= crc2;
|
||||
|
||||
_register= ~crc1;
|
||||
_register = ~crc1;
|
||||
|
||||
//return (int) crc1;
|
||||
return;
|
||||
@@ -417,7 +426,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public CRC32(bool reverseBits) :
|
||||
this( unchecked((int)0xEDB88320), reverseBits)
|
||||
this(unchecked((int)0xEDB88320), reverseBits)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -450,7 +459,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
public CRC32(int polynomial, bool reverseBits)
|
||||
{
|
||||
this.reverseBits = reverseBits;
|
||||
this.dwPolynomial = (uint) polynomial;
|
||||
this.dwPolynomial = (uint)polynomial;
|
||||
this.GenerateLookupTable();
|
||||
}
|
||||
|
||||
@@ -469,9 +478,9 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
}
|
||||
|
||||
// private member vars
|
||||
private UInt32 dwPolynomial;
|
||||
private readonly UInt32 dwPolynomial;
|
||||
private Int64 _TotalBytesRead;
|
||||
private bool reverseBits;
|
||||
private readonly bool reverseBits;
|
||||
private UInt32[] crc32Table;
|
||||
private const int BUFFER_SIZE = 8192;
|
||||
private UInt32 _register = 0xFFFFFFFFU;
|
||||
@@ -502,8 +511,8 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
private static readonly Int64 UnsetLengthLimit = -99;
|
||||
|
||||
internal System.IO.Stream _innerStream;
|
||||
private CRC32 _Crc32;
|
||||
private Int64 _lengthLimit = -99;
|
||||
private readonly CRC32 _Crc32;
|
||||
private readonly Int64 _lengthLimit = -99;
|
||||
private bool _leaveOpen;
|
||||
|
||||
/// <summary>
|
||||
@@ -812,4 +821,4 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,5 +164,4 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
/// </summary>
|
||||
Level9 = 9,
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,5 +102,4 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
/// </summary>
|
||||
Decompress = 1,
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,5 +115,4 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
/// </summary>
|
||||
HuffmanOnly = 2,
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
26
SabreTools.IO/Compression/Deflate/DeflateInfo.cs
Normal file
26
SabreTools.IO/Compression/Deflate/DeflateInfo.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents information about a DEFLATE stream
|
||||
/// </summary>
|
||||
public class DeflateInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Size of the deflated data
|
||||
/// </summary>
|
||||
/// <remarks>Set to a value less than 0 to ignore</remarks>
|
||||
public long InputSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the inflated data
|
||||
/// </summary>
|
||||
/// <remarks>Set to a value less than 0 to ignore</remarks>
|
||||
public long OutputSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// CRC-32 of the inflated data
|
||||
/// </summary>
|
||||
/// <remarks>Set to a value of 0 to ignore</remarks>
|
||||
public uint Crc32 { get; set; }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
34
SabreTools.IO/Compression/Deflate/Enums.cs
Normal file
34
SabreTools.IO/Compression/Deflate/Enums.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the status returned from extracting
|
||||
/// </summary>
|
||||
public enum ExtractionStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Extraction wasn't performed because the inputs were invalid
|
||||
/// </summary>
|
||||
INVALID,
|
||||
|
||||
/// <summary>
|
||||
/// No issues with the extraction
|
||||
/// </summary>
|
||||
GOOD,
|
||||
|
||||
/// <summary>
|
||||
/// File extracted but was the wrong size
|
||||
/// </summary>
|
||||
/// <remarks>Rewinds the stream and deletes the bad file</remarks>
|
||||
WRONG_SIZE,
|
||||
|
||||
/// <summary>
|
||||
/// File extracted but had the wrong CRC-32 value
|
||||
/// </summary>
|
||||
BAD_CRC,
|
||||
|
||||
/// <summary>
|
||||
/// Extraction failed entirely
|
||||
/// </summary>
|
||||
FAIL,
|
||||
}
|
||||
}
|
||||
@@ -129,5 +129,4 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
/// <summary>Signals the end of the compression/decompression stream.</summary>
|
||||
Finish,
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,435 +1,440 @@
|
||||
// Inftree.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2009-October-28 12:43:54>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines classes used in decompression. This code is derived
|
||||
// from the jzlib implementation of zlib. In keeping with the license for jzlib,
|
||||
// the copyright to that code is below.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
|
||||
#nullable disable
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
sealed class InfTree
|
||||
{
|
||||
|
||||
private const int MANY = 1440;
|
||||
|
||||
private const int Z_OK = 0;
|
||||
private const int Z_STREAM_END = 1;
|
||||
private const int Z_NEED_DICT = 2;
|
||||
private const int Z_ERRNO = -1;
|
||||
private const int Z_STREAM_ERROR = -2;
|
||||
private const int Z_DATA_ERROR = -3;
|
||||
private const int Z_MEM_ERROR = -4;
|
||||
private const int Z_BUF_ERROR = -5;
|
||||
private const int Z_VERSION_ERROR = -6;
|
||||
|
||||
internal const int fixed_bl = 9;
|
||||
internal const int fixed_bd = 5;
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'fixed_tl'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] fixed_tl = new int[]{96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186,
|
||||
0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8,
|
||||
14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255};
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'fixed_td'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] fixed_td = new int[] { 80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577 };
|
||||
|
||||
// Tables for deflate from PKZIP's appnote.txt.
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cplens'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cplens = new int[] { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 };
|
||||
|
||||
// see note #13 above about 258
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cplext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cplext = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 };
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cpdist'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cpdist = new int[] { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cpdext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cpdext = new int[] { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 };
|
||||
|
||||
// If BMAX needs to be larger than 16, then h and x[] should be uLong.
|
||||
internal const int BMAX = 15; // maximum bit length of any code
|
||||
|
||||
internal int[] hn = null; // hufts used in space
|
||||
internal int[] v = null; // work area for huft_build
|
||||
internal int[] c = null; // bit length count table
|
||||
internal int[] r = null; // table entry for structure assignment
|
||||
internal int[] u = null; // table stack
|
||||
internal int[] x = null; // bit offsets, then code stack
|
||||
|
||||
private int huft_build(int[] b, int bindex, int n, int s, int[] d, int[] e, int[] t, int[] m, int[] hp, int[] hn, int[] v)
|
||||
{
|
||||
// Given a list of code lengths and a maximum table size, make a set of
|
||||
// tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
|
||||
// if the given code set is incomplete (the tables are still built in this
|
||||
// case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
|
||||
// lengths), or Z_MEM_ERROR if not enough memory.
|
||||
|
||||
int a; // counter for codes of length k
|
||||
int f; // i repeats in table every f entries
|
||||
int g; // maximum code length
|
||||
int h; // table level
|
||||
int i; // counter, current code
|
||||
int j; // counter
|
||||
int k; // number of bits in current code
|
||||
int l; // bits per table (returned in m)
|
||||
int mask; // (1 << w) - 1, to avoid cc -O bug on HP
|
||||
int p; // pointer into c[], b[], or v[]
|
||||
int q; // points to current table
|
||||
int w; // bits before this table == (l * h)
|
||||
int xp; // pointer into x
|
||||
int y; // number of dummy codes added
|
||||
int z; // number of entries in current table
|
||||
|
||||
// Generate counts for each bit length
|
||||
|
||||
p = 0; i = n;
|
||||
do
|
||||
{
|
||||
c[b[bindex + p]]++; p++; i--; // assume all entries <= BMAX
|
||||
}
|
||||
while (i != 0);
|
||||
|
||||
if (c[0] == n)
|
||||
{
|
||||
// null input--all zero length codes
|
||||
t[0] = -1;
|
||||
m[0] = 0;
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
// Find minimum and maximum length, bound *m by those
|
||||
l = m[0];
|
||||
for (j = 1; j <= BMAX; j++)
|
||||
if (c[j] != 0)
|
||||
break;
|
||||
k = j; // minimum code length
|
||||
if (l < j)
|
||||
{
|
||||
l = j;
|
||||
}
|
||||
for (i = BMAX; i != 0; i--)
|
||||
{
|
||||
if (c[i] != 0)
|
||||
break;
|
||||
}
|
||||
g = i; // maximum code length
|
||||
if (l > i)
|
||||
{
|
||||
l = i;
|
||||
}
|
||||
m[0] = l;
|
||||
|
||||
// Adjust last length count to fill out codes, if needed
|
||||
for (y = 1 << j; j < i; j++, y <<= 1)
|
||||
{
|
||||
if ((y -= c[j]) < 0)
|
||||
{
|
||||
return Z_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
if ((y -= c[i]) < 0)
|
||||
{
|
||||
return Z_DATA_ERROR;
|
||||
}
|
||||
c[i] += y;
|
||||
|
||||
// Generate starting offsets into the value table for each length
|
||||
x[1] = j = 0;
|
||||
p = 1; xp = 2;
|
||||
while (--i != 0)
|
||||
{
|
||||
// note that i == g from above
|
||||
x[xp] = (j += c[p]);
|
||||
xp++;
|
||||
p++;
|
||||
}
|
||||
|
||||
// Make a table of values in order of bit lengths
|
||||
i = 0; p = 0;
|
||||
do
|
||||
{
|
||||
if ((j = b[bindex + p]) != 0)
|
||||
{
|
||||
v[x[j]++] = i;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
while (++i < n);
|
||||
n = x[g]; // set n to length of v
|
||||
|
||||
// Generate the Huffman codes and for each, make the table entries
|
||||
x[0] = i = 0; // first Huffman code is zero
|
||||
p = 0; // grab values in bit order
|
||||
h = -1; // no tables yet--level -1
|
||||
w = -l; // bits decoded == (l * h)
|
||||
u[0] = 0; // just to keep compilers happy
|
||||
q = 0; // ditto
|
||||
z = 0; // ditto
|
||||
|
||||
// go through the bit lengths (k already is bits in shortest code)
|
||||
for (; k <= g; k++)
|
||||
{
|
||||
a = c[k];
|
||||
while (a-- != 0)
|
||||
{
|
||||
// here i is the Huffman code of length k bits for value *p
|
||||
// make tables up to required level
|
||||
while (k > w + l)
|
||||
{
|
||||
h++;
|
||||
w += l; // previous table always l bits
|
||||
// compute minimum size table less than or equal to l bits
|
||||
z = g - w;
|
||||
z = (z > l) ? l : z; // table size upper limit
|
||||
if ((f = 1 << (j = k - w)) > a + 1)
|
||||
{
|
||||
// try a k-w bit table
|
||||
// too few codes for k-w bit table
|
||||
f -= (a + 1); // deduct codes from patterns left
|
||||
xp = k;
|
||||
if (j < z)
|
||||
{
|
||||
while (++j < z)
|
||||
{
|
||||
// try smaller tables up to z bits
|
||||
if ((f <<= 1) <= c[++xp])
|
||||
break; // enough codes to use up j bits
|
||||
f -= c[xp]; // else deduct codes from patterns
|
||||
}
|
||||
}
|
||||
}
|
||||
z = 1 << j; // table entries for j-bit table
|
||||
|
||||
// allocate new table
|
||||
if (hn[0] + z > MANY)
|
||||
{
|
||||
// (note: doesn't matter for fixed)
|
||||
return Z_DATA_ERROR; // overflow of MANY
|
||||
}
|
||||
u[h] = q = hn[0]; // DEBUG
|
||||
hn[0] += z;
|
||||
|
||||
// connect to last table, if there is one
|
||||
if (h != 0)
|
||||
{
|
||||
x[h] = i; // save pattern for backing up
|
||||
r[0] = (sbyte)j; // bits in this table
|
||||
r[1] = (sbyte)l; // bits to dump before this table
|
||||
j = SharedUtils.URShift(i, (w - l));
|
||||
r[2] = (int)(q - u[h - 1] - j); // offset to this table
|
||||
Array.Copy(r, 0, hp, (u[h - 1] + j) * 3, 3); // connect to last table
|
||||
}
|
||||
else
|
||||
{
|
||||
t[0] = q; // first table is returned result
|
||||
}
|
||||
}
|
||||
|
||||
// set up table entry in r
|
||||
r[1] = (sbyte)(k - w);
|
||||
if (p >= n)
|
||||
{
|
||||
r[0] = 128 + 64; // out of values--invalid code
|
||||
}
|
||||
else if (v[p] < s)
|
||||
{
|
||||
r[0] = (sbyte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block
|
||||
r[2] = v[p++]; // simple code is just the value
|
||||
}
|
||||
else
|
||||
{
|
||||
r[0] = (sbyte)(e[v[p] - s] + 16 + 64); // non-simple--look up in lists
|
||||
r[2] = d[v[p++] - s];
|
||||
}
|
||||
|
||||
// fill code-like entries with r
|
||||
f = 1 << (k - w);
|
||||
for (j = SharedUtils.URShift(i, w); j < z; j += f)
|
||||
{
|
||||
Array.Copy(r, 0, hp, (q + j) * 3, 3);
|
||||
}
|
||||
|
||||
// backwards increment the k-bit code i
|
||||
for (j = 1 << (k - 1); (i & j) != 0; j = SharedUtils.URShift(j, 1))
|
||||
{
|
||||
i ^= j;
|
||||
}
|
||||
i ^= j;
|
||||
|
||||
// backup over finished tables
|
||||
mask = (1 << w) - 1; // needed on HP, cc -O bug
|
||||
while ((i & mask) != x[h])
|
||||
{
|
||||
h--; // don't need to update q
|
||||
w -= l;
|
||||
mask = (1 << w) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return Z_BUF_ERROR if we were given an incomplete table
|
||||
return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
|
||||
}
|
||||
|
||||
internal int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZlibCodec z)
|
||||
{
|
||||
int result;
|
||||
initWorkArea(19);
|
||||
hn[0] = 0;
|
||||
result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
|
||||
|
||||
if (result == Z_DATA_ERROR)
|
||||
{
|
||||
z.Message = "oversubscribed dynamic bit lengths tree";
|
||||
}
|
||||
else if (result == Z_BUF_ERROR || bb[0] == 0)
|
||||
{
|
||||
z.Message = "incomplete dynamic bit lengths tree";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, ZlibCodec z)
|
||||
{
|
||||
int result;
|
||||
|
||||
// build literal/length tree
|
||||
initWorkArea(288);
|
||||
hn[0] = 0;
|
||||
result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
|
||||
if (result != Z_OK || bl[0] == 0)
|
||||
{
|
||||
if (result == Z_DATA_ERROR)
|
||||
{
|
||||
z.Message = "oversubscribed literal/length tree";
|
||||
}
|
||||
else if (result != Z_MEM_ERROR)
|
||||
{
|
||||
z.Message = "incomplete literal/length tree";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// build distance tree
|
||||
initWorkArea(288);
|
||||
result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
|
||||
|
||||
if (result != Z_OK || (bd[0] == 0 && nl > 257))
|
||||
{
|
||||
if (result == Z_DATA_ERROR)
|
||||
{
|
||||
z.Message = "oversubscribed distance tree";
|
||||
}
|
||||
else if (result == Z_BUF_ERROR)
|
||||
{
|
||||
z.Message = "incomplete distance tree";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
else if (result != Z_MEM_ERROR)
|
||||
{
|
||||
z.Message = "empty distance tree with lengths";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z)
|
||||
{
|
||||
bl[0] = fixed_bl;
|
||||
bd[0] = fixed_bd;
|
||||
tl[0] = fixed_tl;
|
||||
td[0] = fixed_td;
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
private void initWorkArea(int vsize)
|
||||
{
|
||||
if (hn == null)
|
||||
{
|
||||
hn = new int[1];
|
||||
v = new int[vsize];
|
||||
c = new int[BMAX + 1];
|
||||
r = new int[3];
|
||||
u = new int[BMAX];
|
||||
x = new int[BMAX + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v.Length < vsize)
|
||||
{
|
||||
v = new int[vsize];
|
||||
}
|
||||
Array.Clear(v, 0, vsize);
|
||||
Array.Clear(c, 0, BMAX + 1);
|
||||
r[0] = 0; r[1] = 0; r[2] = 0;
|
||||
// for(int i=0; i<BMAX; i++){u[i]=0;}
|
||||
//Array.Copy(c, 0, u, 0, BMAX);
|
||||
Array.Clear(u, 0, BMAX);
|
||||
// for(int i=0; i<BMAX+1; i++){x[i]=0;}
|
||||
//Array.Copy(c, 0, x, 0, BMAX + 1);
|
||||
Array.Clear(x, 0, BMAX + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Inftree.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2009-October-28 12:43:54>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines classes used in decompression. This code is derived
|
||||
// from the jzlib implementation of zlib. In keeping with the license for jzlib,
|
||||
// the copyright to that code is below.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
|
||||
#nullable disable
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0004
|
||||
#pragma warning disable IDE0040
|
||||
#pragma warning disable IDE0047
|
||||
#pragma warning disable IDE0051
|
||||
#pragma warning disable IDE2003
|
||||
sealed class InfTree
|
||||
{
|
||||
|
||||
private const int MANY = 1440;
|
||||
|
||||
private const int Z_OK = 0;
|
||||
private const int Z_STREAM_END = 1;
|
||||
private const int Z_NEED_DICT = 2;
|
||||
private const int Z_ERRNO = -1;
|
||||
private const int Z_STREAM_ERROR = -2;
|
||||
private const int Z_DATA_ERROR = -3;
|
||||
private const int Z_MEM_ERROR = -4;
|
||||
private const int Z_BUF_ERROR = -5;
|
||||
private const int Z_VERSION_ERROR = -6;
|
||||
|
||||
internal const int fixed_bl = 9;
|
||||
internal const int fixed_bd = 5;
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'fixed_tl'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] fixed_tl = [96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 192, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 160, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 224, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 144, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 208, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 176, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 240, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 200, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 168, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 232, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 152, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 216, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 184, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 248, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 196, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 164, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 228, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 148, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 212, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 180, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 244, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 204, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 172, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 236, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 156, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 220, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 188, 0, 8, 14, 0, 8, 142, 0, 8, 78, 0, 9, 252, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 194, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 162, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 226, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 146, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 210, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 178, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 242, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 202, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 170, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 234, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 154, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 218, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 186,
|
||||
0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 250, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 198, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 166, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 230, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 150, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 214, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 182, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 246, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 206, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 174, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 238, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 158, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 222, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 190, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 254, 96, 7, 256, 0, 8, 80, 0, 8, 16, 84, 8, 115, 82, 7, 31, 0, 8, 112, 0, 8, 48, 0, 9, 193, 80, 7, 10, 0, 8, 96, 0, 8, 32, 0, 9, 161, 0, 8, 0, 0, 8, 128, 0, 8, 64, 0, 9, 225, 80, 7, 6, 0, 8, 88, 0, 8, 24, 0, 9, 145, 83, 7, 59, 0, 8, 120, 0, 8, 56, 0, 9, 209, 81, 7, 17, 0, 8, 104, 0, 8, 40, 0, 9, 177, 0, 8, 8, 0, 8, 136, 0, 8, 72, 0, 9, 241, 80, 7, 4, 0, 8, 84, 0, 8, 20, 85, 8, 227, 83, 7, 43, 0, 8, 116, 0, 8, 52, 0, 9, 201, 81, 7, 13, 0, 8, 100, 0, 8, 36, 0, 9, 169, 0, 8, 4, 0, 8, 132, 0, 8, 68, 0, 9, 233, 80, 7, 8, 0, 8, 92, 0, 8, 28, 0, 9, 153, 84, 7, 83, 0, 8, 124, 0, 8, 60, 0, 9, 217, 82, 7, 23, 0, 8, 108, 0, 8, 44, 0, 9, 185, 0, 8, 12, 0, 8, 140, 0, 8, 76, 0, 9, 249, 80, 7, 3, 0, 8, 82, 0, 8, 18, 85, 8, 163, 83, 7, 35, 0, 8, 114, 0, 8, 50, 0, 9, 197, 81, 7, 11, 0, 8, 98, 0, 8, 34, 0, 9, 165, 0, 8, 2, 0, 8, 130, 0, 8, 66, 0, 9, 229, 80, 7, 7, 0, 8, 90, 0, 8, 26, 0, 9, 149, 84, 7, 67, 0, 8, 122, 0, 8, 58, 0, 9, 213, 82, 7, 19, 0, 8, 106, 0, 8, 42, 0, 9, 181, 0, 8, 10, 0, 8, 138, 0, 8, 74, 0, 9, 245, 80, 7, 5, 0, 8, 86, 0, 8, 22, 192, 8, 0, 83, 7, 51, 0, 8, 118, 0, 8, 54, 0, 9, 205, 81, 7, 15, 0, 8, 102, 0, 8, 38, 0, 9, 173, 0, 8, 6, 0, 8, 134, 0, 8, 70, 0, 9, 237, 80, 7, 9, 0, 8, 94, 0, 8, 30, 0, 9, 157, 84, 7, 99, 0, 8, 126, 0, 8, 62, 0, 9, 221, 82, 7, 27, 0, 8, 110, 0, 8, 46, 0, 9, 189, 0, 8,
|
||||
14, 0, 8, 142, 0, 8, 78, 0, 9, 253, 96, 7, 256, 0, 8, 81, 0, 8, 17, 85, 8, 131, 82, 7, 31, 0, 8, 113, 0, 8, 49, 0, 9, 195, 80, 7, 10, 0, 8, 97, 0, 8, 33, 0, 9, 163, 0, 8, 1, 0, 8, 129, 0, 8, 65, 0, 9, 227, 80, 7, 6, 0, 8, 89, 0, 8, 25, 0, 9, 147, 83, 7, 59, 0, 8, 121, 0, 8, 57, 0, 9, 211, 81, 7, 17, 0, 8, 105, 0, 8, 41, 0, 9, 179, 0, 8, 9, 0, 8, 137, 0, 8, 73, 0, 9, 243, 80, 7, 4, 0, 8, 85, 0, 8, 21, 80, 8, 258, 83, 7, 43, 0, 8, 117, 0, 8, 53, 0, 9, 203, 81, 7, 13, 0, 8, 101, 0, 8, 37, 0, 9, 171, 0, 8, 5, 0, 8, 133, 0, 8, 69, 0, 9, 235, 80, 7, 8, 0, 8, 93, 0, 8, 29, 0, 9, 155, 84, 7, 83, 0, 8, 125, 0, 8, 61, 0, 9, 219, 82, 7, 23, 0, 8, 109, 0, 8, 45, 0, 9, 187, 0, 8, 13, 0, 8, 141, 0, 8, 77, 0, 9, 251, 80, 7, 3, 0, 8, 83, 0, 8, 19, 85, 8, 195, 83, 7, 35, 0, 8, 115, 0, 8, 51, 0, 9, 199, 81, 7, 11, 0, 8, 99, 0, 8, 35, 0, 9, 167, 0, 8, 3, 0, 8, 131, 0, 8, 67, 0, 9, 231, 80, 7, 7, 0, 8, 91, 0, 8, 27, 0, 9, 151, 84, 7, 67, 0, 8, 123, 0, 8, 59, 0, 9, 215, 82, 7, 19, 0, 8, 107, 0, 8, 43, 0, 9, 183, 0, 8, 11, 0, 8, 139, 0, 8, 75, 0, 9, 247, 80, 7, 5, 0, 8, 87, 0, 8, 23, 192, 8, 0, 83, 7, 51, 0, 8, 119, 0, 8, 55, 0, 9, 207, 81, 7, 15, 0, 8, 103, 0, 8, 39, 0, 9, 175, 0, 8, 7, 0, 8, 135, 0, 8, 71, 0, 9, 239, 80, 7, 9, 0, 8, 95, 0, 8, 31, 0, 9, 159, 84, 7, 99, 0, 8, 127, 0, 8, 63, 0, 9, 223, 82, 7, 27, 0, 8, 111, 0, 8, 47, 0, 9, 191, 0, 8, 15, 0, 8, 143, 0, 8, 79, 0, 9, 255];
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'fixed_td'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] fixed_td = [80, 5, 1, 87, 5, 257, 83, 5, 17, 91, 5, 4097, 81, 5, 5, 89, 5, 1025, 85, 5, 65, 93, 5, 16385, 80, 5, 3, 88, 5, 513, 84, 5, 33, 92, 5, 8193, 82, 5, 9, 90, 5, 2049, 86, 5, 129, 192, 5, 24577, 80, 5, 2, 87, 5, 385, 83, 5, 25, 91, 5, 6145, 81, 5, 7, 89, 5, 1537, 85, 5, 97, 93, 5, 24577, 80, 5, 4, 88, 5, 769, 84, 5, 49, 92, 5, 12289, 82, 5, 13, 90, 5, 3073, 86, 5, 193, 192, 5, 24577];
|
||||
|
||||
// Tables for deflate from PKZIP's appnote.txt.
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cplens'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cplens = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0];
|
||||
|
||||
// see note #13 above about 258
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cplext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cplext = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112];
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cpdist'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cpdist = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577];
|
||||
|
||||
//UPGRADE_NOTE: Final was removed from the declaration of 'cpdext'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
|
||||
internal static readonly int[] cpdext = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13];
|
||||
|
||||
// If BMAX needs to be larger than 16, then h and x[] should be uLong.
|
||||
internal const int BMAX = 15; // maximum bit length of any code
|
||||
|
||||
internal int[] hn = null; // hufts used in space
|
||||
internal int[] v = null; // work area for huft_build
|
||||
internal int[] c = null; // bit length count table
|
||||
internal int[] r = null; // table entry for structure assignment
|
||||
internal int[] u = null; // table stack
|
||||
internal int[] x = null; // bit offsets, then code stack
|
||||
|
||||
private int huft_build(int[] b, int bindex, int n, int s, int[] d, int[] e, int[] t, int[] m, int[] hp, int[] hn, int[] v)
|
||||
{
|
||||
// Given a list of code lengths and a maximum table size, make a set of
|
||||
// tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
|
||||
// if the given code set is incomplete (the tables are still built in this
|
||||
// case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
|
||||
// lengths), or Z_MEM_ERROR if not enough memory.
|
||||
|
||||
int a; // counter for codes of length k
|
||||
int f; // i repeats in table every f entries
|
||||
int g; // maximum code length
|
||||
int h; // table level
|
||||
int i; // counter, current code
|
||||
int j; // counter
|
||||
int k; // number of bits in current code
|
||||
int l; // bits per table (returned in m)
|
||||
int mask; // (1 << w) - 1, to avoid cc -O bug on HP
|
||||
int p; // pointer into c[], b[], or v[]
|
||||
int q; // points to current table
|
||||
int w; // bits before this table == (l * h)
|
||||
int xp; // pointer into x
|
||||
int y; // number of dummy codes added
|
||||
int z; // number of entries in current table
|
||||
|
||||
// Generate counts for each bit length
|
||||
|
||||
p = 0; i = n;
|
||||
do
|
||||
{
|
||||
c[b[bindex + p]]++; p++; i--; // assume all entries <= BMAX
|
||||
}
|
||||
while (i != 0);
|
||||
|
||||
if (c[0] == n)
|
||||
{
|
||||
// null input--all zero length codes
|
||||
t[0] = -1;
|
||||
m[0] = 0;
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
// Find minimum and maximum length, bound *m by those
|
||||
l = m[0];
|
||||
for (j = 1; j <= BMAX; j++)
|
||||
if (c[j] != 0)
|
||||
break;
|
||||
k = j; // minimum code length
|
||||
if (l < j)
|
||||
{
|
||||
l = j;
|
||||
}
|
||||
for (i = BMAX; i != 0; i--)
|
||||
{
|
||||
if (c[i] != 0)
|
||||
break;
|
||||
}
|
||||
g = i; // maximum code length
|
||||
if (l > i)
|
||||
{
|
||||
l = i;
|
||||
}
|
||||
m[0] = l;
|
||||
|
||||
// Adjust last length count to fill out codes, if needed
|
||||
for (y = 1 << j; j < i; j++, y <<= 1)
|
||||
{
|
||||
if ((y -= c[j]) < 0)
|
||||
{
|
||||
return Z_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
if ((y -= c[i]) < 0)
|
||||
{
|
||||
return Z_DATA_ERROR;
|
||||
}
|
||||
c[i] += y;
|
||||
|
||||
// Generate starting offsets into the value table for each length
|
||||
x[1] = j = 0;
|
||||
p = 1; xp = 2;
|
||||
while (--i != 0)
|
||||
{
|
||||
// note that i == g from above
|
||||
x[xp] = (j += c[p]);
|
||||
xp++;
|
||||
p++;
|
||||
}
|
||||
|
||||
// Make a table of values in order of bit lengths
|
||||
i = 0; p = 0;
|
||||
do
|
||||
{
|
||||
if ((j = b[bindex + p]) != 0)
|
||||
{
|
||||
v[x[j]++] = i;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
while (++i < n);
|
||||
n = x[g]; // set n to length of v
|
||||
|
||||
// Generate the Huffman codes and for each, make the table entries
|
||||
x[0] = i = 0; // first Huffman code is zero
|
||||
p = 0; // grab values in bit order
|
||||
h = -1; // no tables yet--level -1
|
||||
w = -l; // bits decoded == (l * h)
|
||||
u[0] = 0; // just to keep compilers happy
|
||||
q = 0; // ditto
|
||||
z = 0; // ditto
|
||||
|
||||
// go through the bit lengths (k already is bits in shortest code)
|
||||
for (; k <= g; k++)
|
||||
{
|
||||
a = c[k];
|
||||
while (a-- != 0)
|
||||
{
|
||||
// here i is the Huffman code of length k bits for value *p
|
||||
// make tables up to required level
|
||||
while (k > w + l)
|
||||
{
|
||||
h++;
|
||||
w += l; // previous table always l bits
|
||||
// compute minimum size table less than or equal to l bits
|
||||
z = g - w;
|
||||
z = (z > l) ? l : z; // table size upper limit
|
||||
if ((f = 1 << (j = k - w)) > a + 1)
|
||||
{
|
||||
// try a k-w bit table
|
||||
// too few codes for k-w bit table
|
||||
f -= (a + 1); // deduct codes from patterns left
|
||||
xp = k;
|
||||
if (j < z)
|
||||
{
|
||||
while (++j < z)
|
||||
{
|
||||
// try smaller tables up to z bits
|
||||
if ((f <<= 1) <= c[++xp])
|
||||
break; // enough codes to use up j bits
|
||||
f -= c[xp]; // else deduct codes from patterns
|
||||
}
|
||||
}
|
||||
}
|
||||
z = 1 << j; // table entries for j-bit table
|
||||
|
||||
// allocate new table
|
||||
if (hn[0] + z > MANY)
|
||||
{
|
||||
// (note: doesn't matter for fixed)
|
||||
return Z_DATA_ERROR; // overflow of MANY
|
||||
}
|
||||
u[h] = q = hn[0]; // DEBUG
|
||||
hn[0] += z;
|
||||
|
||||
// connect to last table, if there is one
|
||||
if (h != 0)
|
||||
{
|
||||
x[h] = i; // save pattern for backing up
|
||||
r[0] = (sbyte)j; // bits in this table
|
||||
r[1] = (sbyte)l; // bits to dump before this table
|
||||
j = SharedUtils.URShift(i, (w - l));
|
||||
r[2] = (int)(q - u[h - 1] - j); // offset to this table
|
||||
Array.Copy(r, 0, hp, (u[h - 1] + j) * 3, 3); // connect to last table
|
||||
}
|
||||
else
|
||||
{
|
||||
t[0] = q; // first table is returned result
|
||||
}
|
||||
}
|
||||
|
||||
// set up table entry in r
|
||||
r[1] = (sbyte)(k - w);
|
||||
if (p >= n)
|
||||
{
|
||||
r[0] = 128 + 64; // out of values--invalid code
|
||||
}
|
||||
else if (v[p] < s)
|
||||
{
|
||||
r[0] = (sbyte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block
|
||||
r[2] = v[p++]; // simple code is just the value
|
||||
}
|
||||
else
|
||||
{
|
||||
r[0] = (sbyte)(e[v[p] - s] + 16 + 64); // non-simple--look up in lists
|
||||
r[2] = d[v[p++] - s];
|
||||
}
|
||||
|
||||
// fill code-like entries with r
|
||||
f = 1 << (k - w);
|
||||
for (j = SharedUtils.URShift(i, w); j < z; j += f)
|
||||
{
|
||||
Array.Copy(r, 0, hp, (q + j) * 3, 3);
|
||||
}
|
||||
|
||||
// backwards increment the k-bit code i
|
||||
for (j = 1 << (k - 1); (i & j) != 0; j = SharedUtils.URShift(j, 1))
|
||||
{
|
||||
i ^= j;
|
||||
}
|
||||
i ^= j;
|
||||
|
||||
// backup over finished tables
|
||||
mask = (1 << w) - 1; // needed on HP, cc -O bug
|
||||
while ((i & mask) != x[h])
|
||||
{
|
||||
h--; // don't need to update q
|
||||
w -= l;
|
||||
mask = (1 << w) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return Z_BUF_ERROR if we were given an incomplete table
|
||||
return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
|
||||
}
|
||||
|
||||
internal int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZlibCodec z)
|
||||
{
|
||||
int result;
|
||||
initWorkArea(19);
|
||||
hn[0] = 0;
|
||||
result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
|
||||
|
||||
if (result == Z_DATA_ERROR)
|
||||
{
|
||||
z.Message = "oversubscribed dynamic bit lengths tree";
|
||||
}
|
||||
else if (result == Z_BUF_ERROR || bb[0] == 0)
|
||||
{
|
||||
z.Message = "incomplete dynamic bit lengths tree";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, ZlibCodec z)
|
||||
{
|
||||
int result;
|
||||
|
||||
// build literal/length tree
|
||||
initWorkArea(288);
|
||||
hn[0] = 0;
|
||||
result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
|
||||
if (result != Z_OK || bl[0] == 0)
|
||||
{
|
||||
if (result == Z_DATA_ERROR)
|
||||
{
|
||||
z.Message = "oversubscribed literal/length tree";
|
||||
}
|
||||
else if (result != Z_MEM_ERROR)
|
||||
{
|
||||
z.Message = "incomplete literal/length tree";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// build distance tree
|
||||
initWorkArea(288);
|
||||
result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
|
||||
|
||||
if (result != Z_OK || (bd[0] == 0 && nl > 257))
|
||||
{
|
||||
if (result == Z_DATA_ERROR)
|
||||
{
|
||||
z.Message = "oversubscribed distance tree";
|
||||
}
|
||||
else if (result == Z_BUF_ERROR)
|
||||
{
|
||||
z.Message = "incomplete distance tree";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
else if (result != Z_MEM_ERROR)
|
||||
{
|
||||
z.Message = "empty distance tree with lengths";
|
||||
result = Z_DATA_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z)
|
||||
{
|
||||
bl[0] = fixed_bl;
|
||||
bd[0] = fixed_bd;
|
||||
tl[0] = fixed_tl;
|
||||
td[0] = fixed_td;
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
private void initWorkArea(int vsize)
|
||||
{
|
||||
if (hn is null)
|
||||
{
|
||||
hn = new int[1];
|
||||
v = new int[vsize];
|
||||
c = new int[BMAX + 1];
|
||||
r = new int[3];
|
||||
u = new int[BMAX];
|
||||
x = new int[BMAX + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v.Length < vsize)
|
||||
{
|
||||
v = new int[vsize];
|
||||
}
|
||||
Array.Clear(v, 0, vsize);
|
||||
Array.Clear(c, 0, BMAX + 1);
|
||||
r[0] = 0; r[1] = 0; r[2] = 0;
|
||||
// for(int i=0; i<BMAX; i++){u[i]=0;}
|
||||
//Array.Copy(c, 0, u, 0, BMAX);
|
||||
Array.Clear(u, 0, BMAX);
|
||||
// for(int i=0; i<BMAX+1; i++){x[i]=0;}
|
||||
//Array.Copy(c, 0, x, 0, BMAX + 1);
|
||||
Array.Clear(x, 0, BMAX + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,13 +66,20 @@ using System;
|
||||
#nullable disable
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0004
|
||||
#pragma warning disable IDE0010
|
||||
#pragma warning disable IDE0040
|
||||
#pragma warning disable IDE0047
|
||||
#pragma warning disable IDE0048
|
||||
#pragma warning disable IDE0049
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2003
|
||||
sealed class InflateBlocks
|
||||
{
|
||||
private const int MANY = 1440;
|
||||
|
||||
// Table for deflate from PKZIP's appnote.txt.
|
||||
internal static readonly int[] border = new int[]
|
||||
{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
|
||||
internal static readonly int[] border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
|
||||
|
||||
private enum InflateBlockMode
|
||||
{
|
||||
@@ -98,7 +105,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
internal int[] bb = new int[1]; // bit length tree depth
|
||||
internal int[] tb = new int[1]; // bit length decoding tree
|
||||
|
||||
internal InflateCodes codes = new InflateCodes(); // if CODES, current state
|
||||
internal InflateCodes codes = new(); // if CODES, current state
|
||||
|
||||
internal int last; // true if this block is the last block
|
||||
|
||||
@@ -115,7 +122,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
internal System.Object checkfn; // check function
|
||||
internal uint check; // check on output
|
||||
|
||||
internal InfTree inftree = new InfTree();
|
||||
internal InfTree inftree = new();
|
||||
|
||||
internal InflateBlocks(ZlibCodec codec, System.Object checkfn, int w)
|
||||
{
|
||||
@@ -136,7 +143,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
bitb = 0;
|
||||
readAt = writeAt = 0;
|
||||
|
||||
if (checkfn != null)
|
||||
if (checkfn is not null)
|
||||
_codec._Adler32 = check = Adler.Adler32(0, null, 0, 0);
|
||||
return oldCheck;
|
||||
}
|
||||
@@ -363,7 +370,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
return Flush(r);
|
||||
}
|
||||
t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
|
||||
if (blens == null || blens.Length < t)
|
||||
if (blens is null || blens.Length < t)
|
||||
{
|
||||
blens = new int[t];
|
||||
}
|
||||
@@ -545,8 +552,8 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
|
||||
tb[0] = -1;
|
||||
{
|
||||
int[] bl = new int[] { 9 }; // must be <= 9 for lookahead assumptions
|
||||
int[] bd = new int[] { 6 }; // must be <= 9 for lookahead assumptions
|
||||
int[] bl = [9]; // must be <= 9 for lookahead assumptions
|
||||
int[] bd = [6]; // must be <= 9 for lookahead assumptions
|
||||
int[] tl = new int[1];
|
||||
int[] td = new int[1];
|
||||
|
||||
@@ -711,7 +718,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
_codec.TotalBytesOut += nBytes;
|
||||
|
||||
// update check information
|
||||
if (checkfn != null)
|
||||
if (checkfn is not null)
|
||||
_codec._Adler32 = check = Adler.Adler32(check, window, readAt, nBytes);
|
||||
|
||||
// copy as far as end of window
|
||||
@@ -734,4 +741,4 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,12 @@ using System;
|
||||
#nullable disable
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0004
|
||||
#pragma warning disable IDE0040
|
||||
#pragma warning disable IDE0047
|
||||
#pragma warning disable IDE0048
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2003
|
||||
sealed class InflateCodes
|
||||
{
|
||||
// waiting for "i:"=input,
|
||||
@@ -720,4 +726,4 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
return ZlibConstants.Z_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,465 +1,467 @@
|
||||
// Inflate.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2010-January-08 18:32:12>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines classes for decompression. This code is derived
|
||||
// from the jzlib implementation of zlib, but significantly modified.
|
||||
// The object model is not the same, and many of the behaviors are
|
||||
// different. Nonetheless, in keeping with the license for jzlib, I am
|
||||
// reproducing the copyright to that code here.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
using System;
|
||||
|
||||
#nullable disable
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
internal sealed class InflateManager
|
||||
{
|
||||
// preset dictionary flag in zlib header
|
||||
private const int PRESET_DICT = 0x20;
|
||||
|
||||
private const int Z_DEFLATED = 8;
|
||||
|
||||
private enum InflateManagerMode
|
||||
{
|
||||
METHOD = 0, // waiting for method byte
|
||||
FLAG = 1, // waiting for flag byte
|
||||
DICT4 = 2, // four dictionary check bytes to go
|
||||
DICT3 = 3, // three dictionary check bytes to go
|
||||
DICT2 = 4, // two dictionary check bytes to go
|
||||
DICT1 = 5, // one dictionary check byte to go
|
||||
DICT0 = 6, // waiting for inflateSetDictionary
|
||||
BLOCKS = 7, // decompressing blocks
|
||||
CHECK4 = 8, // four check bytes to go
|
||||
CHECK3 = 9, // three check bytes to go
|
||||
CHECK2 = 10, // two check bytes to go
|
||||
CHECK1 = 11, // one check byte to go
|
||||
DONE = 12, // finished check, done
|
||||
BAD = 13, // got an error--stay here
|
||||
}
|
||||
|
||||
private InflateManagerMode mode; // current inflate mode
|
||||
internal ZlibCodec _codec; // pointer back to this zlib stream
|
||||
|
||||
// mode dependent information
|
||||
internal int method; // if FLAGS, method byte
|
||||
|
||||
// if CHECK, check values to compare
|
||||
internal uint computedCheck; // computed check value
|
||||
internal uint expectedCheck; // stream check value
|
||||
|
||||
// if BAD, inflateSync's marker bytes count
|
||||
internal int marker;
|
||||
|
||||
// mode independent information
|
||||
//internal int nowrap; // flag for no wrapper
|
||||
private bool _handleRfc1950HeaderBytes = true;
|
||||
internal bool HandleRfc1950HeaderBytes
|
||||
{
|
||||
get { return _handleRfc1950HeaderBytes; }
|
||||
set { _handleRfc1950HeaderBytes = value; }
|
||||
}
|
||||
internal int wbits; // log2(window size) (8..15, defaults to 15)
|
||||
|
||||
internal InflateBlocks blocks; // current inflate_blocks state
|
||||
|
||||
public InflateManager() { }
|
||||
|
||||
public InflateManager(bool expectRfc1950HeaderBytes)
|
||||
{
|
||||
_handleRfc1950HeaderBytes = expectRfc1950HeaderBytes;
|
||||
}
|
||||
|
||||
internal int Reset()
|
||||
{
|
||||
_codec.TotalBytesIn = _codec.TotalBytesOut = 0;
|
||||
_codec.Message = null;
|
||||
mode = HandleRfc1950HeaderBytes ? InflateManagerMode.METHOD : InflateManagerMode.BLOCKS;
|
||||
blocks.Reset();
|
||||
return ZlibConstants.Z_OK;
|
||||
}
|
||||
|
||||
internal int End()
|
||||
{
|
||||
if (blocks != null)
|
||||
blocks.Free();
|
||||
blocks = null;
|
||||
return ZlibConstants.Z_OK;
|
||||
}
|
||||
|
||||
internal int Initialize(ZlibCodec codec, int w)
|
||||
{
|
||||
_codec = codec;
|
||||
_codec.Message = null;
|
||||
blocks = null;
|
||||
|
||||
// handle undocumented nowrap option (no zlib header or check)
|
||||
//nowrap = 0;
|
||||
//if (w < 0)
|
||||
//{
|
||||
// w = - w;
|
||||
// nowrap = 1;
|
||||
//}
|
||||
|
||||
// set window size
|
||||
if (w < 8 || w > 15)
|
||||
{
|
||||
End();
|
||||
throw new ZlibException("Bad window size.");
|
||||
|
||||
//return ZlibConstants.Z_STREAM_ERROR;
|
||||
}
|
||||
wbits = w;
|
||||
|
||||
blocks = new InflateBlocks(codec,
|
||||
HandleRfc1950HeaderBytes ? this : null,
|
||||
1 << w);
|
||||
|
||||
// reset state
|
||||
Reset();
|
||||
return ZlibConstants.Z_OK;
|
||||
}
|
||||
|
||||
|
||||
internal int Inflate(FlushType flush)
|
||||
{
|
||||
int b;
|
||||
|
||||
if (_codec.InputBuffer == null)
|
||||
throw new ZlibException("InputBuffer is null. ");
|
||||
|
||||
// int f = (flush == FlushType.Finish)
|
||||
// ? ZlibConstants.Z_BUF_ERROR
|
||||
// : ZlibConstants.Z_OK;
|
||||
|
||||
// workitem 8870
|
||||
int f = ZlibConstants.Z_OK;
|
||||
int r = ZlibConstants.Z_BUF_ERROR;
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case InflateManagerMode.METHOD:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
if (((method = _codec.InputBuffer[_codec.NextIn++]) & 0xf) != Z_DEFLATED)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
_codec.Message = String.Format("unknown compression method (0x{0:X2})", method);
|
||||
marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
if ((method >> 4) + 8 > wbits)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
_codec.Message = String.Format("invalid window size ({0})", (method >> 4) + 8);
|
||||
marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
mode = InflateManagerMode.FLAG;
|
||||
break;
|
||||
|
||||
|
||||
case InflateManagerMode.FLAG:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
b = (_codec.InputBuffer[_codec.NextIn++]) & 0xff;
|
||||
|
||||
if ((((method << 8) + b) % 31) != 0)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
_codec.Message = "incorrect header check";
|
||||
marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
|
||||
mode = ((b & PRESET_DICT) == 0)
|
||||
? InflateManagerMode.BLOCKS
|
||||
: InflateManagerMode.DICT4;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.DICT4:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
expectedCheck = (uint)((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000);
|
||||
mode = InflateManagerMode.DICT3;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.DICT3:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000);
|
||||
mode = InflateManagerMode.DICT2;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.DICT2:
|
||||
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00);
|
||||
mode = InflateManagerMode.DICT1;
|
||||
break;
|
||||
|
||||
|
||||
case InflateManagerMode.DICT1:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--; _codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0x000000ff);
|
||||
_codec._Adler32 = expectedCheck;
|
||||
mode = InflateManagerMode.DICT0;
|
||||
return ZlibConstants.Z_NEED_DICT;
|
||||
|
||||
|
||||
case InflateManagerMode.DICT0:
|
||||
mode = InflateManagerMode.BAD;
|
||||
_codec.Message = "need dictionary";
|
||||
marker = 0; // can try inflateSync
|
||||
return ZlibConstants.Z_STREAM_ERROR;
|
||||
|
||||
|
||||
case InflateManagerMode.BLOCKS:
|
||||
r = blocks.Process(r);
|
||||
if (r == ZlibConstants.Z_DATA_ERROR)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
marker = 0; // can try inflateSync
|
||||
break;
|
||||
}
|
||||
|
||||
if (r == ZlibConstants.Z_OK) r = f;
|
||||
|
||||
if (r != ZlibConstants.Z_STREAM_END)
|
||||
return r;
|
||||
|
||||
r = f;
|
||||
computedCheck = blocks.Reset();
|
||||
if (!HandleRfc1950HeaderBytes)
|
||||
{
|
||||
mode = InflateManagerMode.DONE;
|
||||
return ZlibConstants.Z_STREAM_END;
|
||||
}
|
||||
mode = InflateManagerMode.CHECK4;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.CHECK4:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
expectedCheck = (uint)((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000);
|
||||
mode = InflateManagerMode.CHECK3;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.CHECK3:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--; _codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000);
|
||||
mode = InflateManagerMode.CHECK2;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.CHECK2:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00);
|
||||
mode = InflateManagerMode.CHECK1;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.CHECK1:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--; _codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0x000000ff);
|
||||
if (computedCheck != expectedCheck)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
_codec.Message = "incorrect data check";
|
||||
marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
mode = InflateManagerMode.DONE;
|
||||
return ZlibConstants.Z_STREAM_END;
|
||||
|
||||
case InflateManagerMode.DONE:
|
||||
return ZlibConstants.Z_STREAM_END;
|
||||
|
||||
case InflateManagerMode.BAD:
|
||||
throw new ZlibException(String.Format("Bad state ({0})", _codec.Message));
|
||||
|
||||
default:
|
||||
throw new ZlibException("Stream error.");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal int SetDictionary(byte[] dictionary, bool check = true)
|
||||
{
|
||||
int index = 0;
|
||||
int length = dictionary.Length;
|
||||
|
||||
if (check)
|
||||
{
|
||||
if (mode != InflateManagerMode.DICT0)
|
||||
throw new ZlibException("Stream error.");
|
||||
|
||||
if (Adler.Adler32(1, dictionary, 0, dictionary.Length) != _codec._Adler32)
|
||||
{
|
||||
return ZlibConstants.Z_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
_codec._Adler32 = Adler.Adler32(0, null, 0, 0);
|
||||
|
||||
if (length >= (1 << wbits))
|
||||
{
|
||||
length = (1 << wbits) - 1;
|
||||
index = dictionary.Length - length;
|
||||
}
|
||||
blocks.SetDictionary(dictionary, index, length);
|
||||
mode = InflateManagerMode.BLOCKS;
|
||||
return ZlibConstants.Z_OK;
|
||||
}
|
||||
|
||||
|
||||
private static readonly byte[] mark = new byte[] { 0, 0, 0xff, 0xff };
|
||||
|
||||
internal int Sync()
|
||||
{
|
||||
int n; // number of bytes to look at
|
||||
int p; // pointer to bytes
|
||||
int m; // number of marker bytes found in a row
|
||||
long r, w; // temporaries to save total_in and total_out
|
||||
|
||||
// set up
|
||||
if (mode != InflateManagerMode.BAD)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
marker = 0;
|
||||
}
|
||||
if ((n = _codec.AvailableBytesIn) == 0)
|
||||
return ZlibConstants.Z_BUF_ERROR;
|
||||
p = _codec.NextIn;
|
||||
m = marker;
|
||||
|
||||
// search
|
||||
while (n != 0 && m < 4)
|
||||
{
|
||||
if (_codec.InputBuffer[p] == mark[m])
|
||||
{
|
||||
m++;
|
||||
}
|
||||
else if (_codec.InputBuffer[p] != 0)
|
||||
{
|
||||
m = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = 4 - m;
|
||||
}
|
||||
p++; n--;
|
||||
}
|
||||
|
||||
// restore
|
||||
_codec.TotalBytesIn += p - _codec.NextIn;
|
||||
_codec.NextIn = p;
|
||||
_codec.AvailableBytesIn = n;
|
||||
marker = m;
|
||||
|
||||
// return no joy or set up to restart on a new block
|
||||
if (m != 4)
|
||||
{
|
||||
return ZlibConstants.Z_DATA_ERROR;
|
||||
}
|
||||
r = _codec.TotalBytesIn;
|
||||
w = _codec.TotalBytesOut;
|
||||
Reset();
|
||||
_codec.TotalBytesIn = r;
|
||||
_codec.TotalBytesOut = w;
|
||||
mode = InflateManagerMode.BLOCKS;
|
||||
return ZlibConstants.Z_OK;
|
||||
}
|
||||
|
||||
|
||||
// Returns true if inflate is currently at the end of a block generated
|
||||
// by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
|
||||
// implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
|
||||
// but removes the length bytes of the resulting empty stored block. When
|
||||
// decompressing, PPP checks that at the end of input packet, inflate is
|
||||
// waiting for these length bytes.
|
||||
internal int SyncPoint(ZlibCodec z)
|
||||
{
|
||||
return blocks.SyncPoint();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Inflate.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2010-January-08 18:32:12>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines classes for decompression. This code is derived
|
||||
// from the jzlib implementation of zlib, but significantly modified.
|
||||
// The object model is not the same, and many of the behaviors are
|
||||
// different. Nonetheless, in keeping with the license for jzlib, I am
|
||||
// reproducing the copyright to that code here.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
|
||||
#nullable disable
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0047
|
||||
#pragma warning disable IDE0049
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2003
|
||||
internal sealed class InflateManager
|
||||
{
|
||||
// preset dictionary flag in zlib header
|
||||
private const int PRESET_DICT = 0x20;
|
||||
|
||||
private const int Z_DEFLATED = 8;
|
||||
|
||||
private enum InflateManagerMode
|
||||
{
|
||||
METHOD = 0, // waiting for method byte
|
||||
FLAG = 1, // waiting for flag byte
|
||||
DICT4 = 2, // four dictionary check bytes to go
|
||||
DICT3 = 3, // three dictionary check bytes to go
|
||||
DICT2 = 4, // two dictionary check bytes to go
|
||||
DICT1 = 5, // one dictionary check byte to go
|
||||
DICT0 = 6, // waiting for inflateSetDictionary
|
||||
BLOCKS = 7, // decompressing blocks
|
||||
CHECK4 = 8, // four check bytes to go
|
||||
CHECK3 = 9, // three check bytes to go
|
||||
CHECK2 = 10, // two check bytes to go
|
||||
CHECK1 = 11, // one check byte to go
|
||||
DONE = 12, // finished check, done
|
||||
BAD = 13, // got an error--stay here
|
||||
}
|
||||
|
||||
private InflateManagerMode mode; // current inflate mode
|
||||
internal ZlibCodec _codec; // pointer back to this zlib stream
|
||||
|
||||
// mode dependent information
|
||||
internal int method; // if FLAGS, method byte
|
||||
|
||||
// if CHECK, check values to compare
|
||||
internal uint computedCheck; // computed check value
|
||||
internal uint expectedCheck; // stream check value
|
||||
|
||||
// if BAD, inflateSync's marker bytes count
|
||||
internal int marker;
|
||||
|
||||
// mode independent information
|
||||
//internal int nowrap; // flag for no wrapper
|
||||
private bool _handleRfc1950HeaderBytes = true;
|
||||
internal bool HandleRfc1950HeaderBytes
|
||||
{
|
||||
get { return _handleRfc1950HeaderBytes; }
|
||||
set { _handleRfc1950HeaderBytes = value; }
|
||||
}
|
||||
internal int wbits; // log2(window size) (8..15, defaults to 15)
|
||||
|
||||
internal InflateBlocks blocks; // current inflate_blocks state
|
||||
|
||||
public InflateManager() { }
|
||||
|
||||
public InflateManager(bool expectRfc1950HeaderBytes)
|
||||
{
|
||||
_handleRfc1950HeaderBytes = expectRfc1950HeaderBytes;
|
||||
}
|
||||
|
||||
internal int Reset()
|
||||
{
|
||||
_codec.TotalBytesIn = _codec.TotalBytesOut = 0;
|
||||
_codec.Message = null;
|
||||
mode = HandleRfc1950HeaderBytes ? InflateManagerMode.METHOD : InflateManagerMode.BLOCKS;
|
||||
blocks.Reset();
|
||||
return ZlibConstants.Z_OK;
|
||||
}
|
||||
|
||||
internal int End()
|
||||
{
|
||||
blocks?.Free();
|
||||
blocks = null;
|
||||
return ZlibConstants.Z_OK;
|
||||
}
|
||||
|
||||
internal int Initialize(ZlibCodec codec, int w)
|
||||
{
|
||||
_codec = codec;
|
||||
_codec.Message = null;
|
||||
blocks = null;
|
||||
|
||||
// handle undocumented nowrap option (no zlib header or check)
|
||||
//nowrap = 0;
|
||||
//if (w < 0)
|
||||
//{
|
||||
// w = - w;
|
||||
// nowrap = 1;
|
||||
//}
|
||||
|
||||
// set window size
|
||||
if (w < 8 || w > 15)
|
||||
{
|
||||
End();
|
||||
throw new ZlibException("Bad window size.");
|
||||
|
||||
//return ZlibConstants.Z_STREAM_ERROR;
|
||||
}
|
||||
wbits = w;
|
||||
|
||||
blocks = new InflateBlocks(codec,
|
||||
HandleRfc1950HeaderBytes ? this : null,
|
||||
1 << w);
|
||||
|
||||
// reset state
|
||||
Reset();
|
||||
return ZlibConstants.Z_OK;
|
||||
}
|
||||
|
||||
|
||||
internal int Inflate(FlushType flush)
|
||||
{
|
||||
int b;
|
||||
|
||||
if (_codec.InputBuffer is null)
|
||||
throw new ZlibException("InputBuffer is null. ");
|
||||
|
||||
// int f = (flush == FlushType.Finish)
|
||||
// ? ZlibConstants.Z_BUF_ERROR
|
||||
// : ZlibConstants.Z_OK;
|
||||
|
||||
// workitem 8870
|
||||
int f = ZlibConstants.Z_OK;
|
||||
int r = ZlibConstants.Z_BUF_ERROR;
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case InflateManagerMode.METHOD:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
if (((method = _codec.InputBuffer[_codec.NextIn++]) & 0xf) != Z_DEFLATED)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
_codec.Message = String.Format("unknown compression method (0x{0:X2})", method);
|
||||
marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
if ((method >> 4) + 8 > wbits)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
_codec.Message = String.Format("invalid window size ({0})", (method >> 4) + 8);
|
||||
marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
mode = InflateManagerMode.FLAG;
|
||||
break;
|
||||
|
||||
|
||||
case InflateManagerMode.FLAG:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
b = (_codec.InputBuffer[_codec.NextIn++]) & 0xff;
|
||||
|
||||
if ((((method << 8) + b) % 31) != 0)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
_codec.Message = "incorrect header check";
|
||||
marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
|
||||
mode = ((b & PRESET_DICT) == 0)
|
||||
? InflateManagerMode.BLOCKS
|
||||
: InflateManagerMode.DICT4;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.DICT4:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
expectedCheck = (uint)((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000);
|
||||
mode = InflateManagerMode.DICT3;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.DICT3:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000);
|
||||
mode = InflateManagerMode.DICT2;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.DICT2:
|
||||
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00);
|
||||
mode = InflateManagerMode.DICT1;
|
||||
break;
|
||||
|
||||
|
||||
case InflateManagerMode.DICT1:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--; _codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0x000000ff);
|
||||
_codec._Adler32 = expectedCheck;
|
||||
mode = InflateManagerMode.DICT0;
|
||||
return ZlibConstants.Z_NEED_DICT;
|
||||
|
||||
|
||||
case InflateManagerMode.DICT0:
|
||||
mode = InflateManagerMode.BAD;
|
||||
_codec.Message = "need dictionary";
|
||||
marker = 0; // can try inflateSync
|
||||
return ZlibConstants.Z_STREAM_ERROR;
|
||||
|
||||
|
||||
case InflateManagerMode.BLOCKS:
|
||||
r = blocks.Process(r);
|
||||
if (r == ZlibConstants.Z_DATA_ERROR)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
marker = 0; // can try inflateSync
|
||||
break;
|
||||
}
|
||||
|
||||
if (r == ZlibConstants.Z_OK) r = f;
|
||||
|
||||
if (r != ZlibConstants.Z_STREAM_END)
|
||||
return r;
|
||||
|
||||
r = f;
|
||||
computedCheck = blocks.Reset();
|
||||
if (!HandleRfc1950HeaderBytes)
|
||||
{
|
||||
mode = InflateManagerMode.DONE;
|
||||
return ZlibConstants.Z_STREAM_END;
|
||||
}
|
||||
mode = InflateManagerMode.CHECK4;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.CHECK4:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
expectedCheck = (uint)((_codec.InputBuffer[_codec.NextIn++] << 24) & 0xff000000);
|
||||
mode = InflateManagerMode.CHECK3;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.CHECK3:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--; _codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 16) & 0x00ff0000);
|
||||
mode = InflateManagerMode.CHECK2;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.CHECK2:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--;
|
||||
_codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)((_codec.InputBuffer[_codec.NextIn++] << 8) & 0x0000ff00);
|
||||
mode = InflateManagerMode.CHECK1;
|
||||
break;
|
||||
|
||||
case InflateManagerMode.CHECK1:
|
||||
if (_codec.AvailableBytesIn == 0) return r;
|
||||
r = f;
|
||||
_codec.AvailableBytesIn--; _codec.TotalBytesIn++;
|
||||
expectedCheck += (uint)(_codec.InputBuffer[_codec.NextIn++] & 0x000000ff);
|
||||
if (computedCheck != expectedCheck)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
_codec.Message = "incorrect data check";
|
||||
marker = 5; // can't try inflateSync
|
||||
break;
|
||||
}
|
||||
mode = InflateManagerMode.DONE;
|
||||
return ZlibConstants.Z_STREAM_END;
|
||||
|
||||
case InflateManagerMode.DONE:
|
||||
return ZlibConstants.Z_STREAM_END;
|
||||
|
||||
case InflateManagerMode.BAD:
|
||||
throw new ZlibException(String.Format("Bad state ({0})", _codec.Message));
|
||||
|
||||
default:
|
||||
throw new ZlibException("Stream error.");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal int SetDictionary(byte[] dictionary, bool check = true)
|
||||
{
|
||||
int index = 0;
|
||||
int length = dictionary.Length;
|
||||
|
||||
if (check)
|
||||
{
|
||||
if (mode != InflateManagerMode.DICT0)
|
||||
throw new ZlibException("Stream error.");
|
||||
|
||||
if (Adler.Adler32(1, dictionary, 0, dictionary.Length) != _codec._Adler32)
|
||||
{
|
||||
return ZlibConstants.Z_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
_codec._Adler32 = Adler.Adler32(0, null, 0, 0);
|
||||
|
||||
if (length >= (1 << wbits))
|
||||
{
|
||||
length = (1 << wbits) - 1;
|
||||
index = dictionary.Length - length;
|
||||
}
|
||||
blocks.SetDictionary(dictionary, index, length);
|
||||
mode = InflateManagerMode.BLOCKS;
|
||||
return ZlibConstants.Z_OK;
|
||||
}
|
||||
|
||||
|
||||
private static readonly byte[] mark = [0, 0, 0xff, 0xff];
|
||||
|
||||
internal int Sync()
|
||||
{
|
||||
int n; // number of bytes to look at
|
||||
int p; // pointer to bytes
|
||||
int m; // number of marker bytes found in a row
|
||||
long r, w; // temporaries to save total_in and total_out
|
||||
|
||||
// set up
|
||||
if (mode != InflateManagerMode.BAD)
|
||||
{
|
||||
mode = InflateManagerMode.BAD;
|
||||
marker = 0;
|
||||
}
|
||||
if ((n = _codec.AvailableBytesIn) == 0)
|
||||
return ZlibConstants.Z_BUF_ERROR;
|
||||
p = _codec.NextIn;
|
||||
m = marker;
|
||||
|
||||
// search
|
||||
while (n != 0 && m < 4)
|
||||
{
|
||||
if (_codec.InputBuffer[p] == mark[m])
|
||||
{
|
||||
m++;
|
||||
}
|
||||
else if (_codec.InputBuffer[p] != 0)
|
||||
{
|
||||
m = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = 4 - m;
|
||||
}
|
||||
p++; n--;
|
||||
}
|
||||
|
||||
// restore
|
||||
_codec.TotalBytesIn += p - _codec.NextIn;
|
||||
_codec.NextIn = p;
|
||||
_codec.AvailableBytesIn = n;
|
||||
marker = m;
|
||||
|
||||
// return no joy or set up to restart on a new block
|
||||
if (m != 4)
|
||||
{
|
||||
return ZlibConstants.Z_DATA_ERROR;
|
||||
}
|
||||
r = _codec.TotalBytesIn;
|
||||
w = _codec.TotalBytesOut;
|
||||
Reset();
|
||||
_codec.TotalBytesIn = r;
|
||||
_codec.TotalBytesOut = w;
|
||||
mode = InflateManagerMode.BLOCKS;
|
||||
return ZlibConstants.Z_OK;
|
||||
}
|
||||
|
||||
|
||||
// Returns true if inflate is currently at the end of a block generated
|
||||
// by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
|
||||
// implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
|
||||
// but removes the length bytes of the resulting empty stored block. When
|
||||
// decompressing, PPP checks that at the end of input packet, inflate is
|
||||
// waiting for these length bytes.
|
||||
internal int SyncPoint(ZlibCodec z)
|
||||
{
|
||||
return blocks.SyncPoint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
470
SabreTools.IO/Compression/Deflate/InflateWrapper.cs
Normal file
470
SabreTools.IO/Compression/Deflate/InflateWrapper.cs
Normal file
@@ -0,0 +1,470 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Hashing;
|
||||
using SabreTools.IO.Extensions;
|
||||
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper to handle DEFLATE decompression with data verification
|
||||
/// </summary>
|
||||
public class InflateWrapper
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary>
|
||||
/// Buffer size for decompression
|
||||
/// </summary>
|
||||
private const int BufferSize = 1024 * 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Local file header signature
|
||||
/// </summary>
|
||||
private const uint LocalFileHeaderSignature = 0x04034B50;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Classes
|
||||
|
||||
/// <summary>
|
||||
/// Minimal PKZIP local file header information
|
||||
/// </summary>
|
||||
private class MinLocalFileHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Signature (0x04034B50)
|
||||
/// </summary>
|
||||
public uint Signature { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// CRC-32
|
||||
/// </summary>
|
||||
public uint CRC32 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compressed size
|
||||
/// </summary>
|
||||
public uint CompressedSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed size
|
||||
/// </summary>
|
||||
public uint UncompressedSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// File name (variable size)
|
||||
/// </summary>
|
||||
public string? FileName { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extraction
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to extract a file defined by a filename
|
||||
/// </summary>
|
||||
/// <param name="source">Stream representing the deflated data</param>
|
||||
/// <param name="filename">Output filename, null to auto-generate</param>
|
||||
/// <param name="outputDirectory">Output directory to write to</param>
|
||||
/// <param name="expected">Expected DEFLATE stream information</param>
|
||||
/// <param name="pkzip">Indicates if PKZIP containers are used</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Extraction status representing the final state</returns>
|
||||
/// <remarks>Assumes that the current stream position is where the compressed data lives</remarks>
|
||||
public static ExtractionStatus ExtractFile(Stream source,
|
||||
string? filename,
|
||||
string outputDirectory,
|
||||
DeflateInfo expected,
|
||||
bool pkzip,
|
||||
bool includeDebug)
|
||||
{
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"Attempting to extract {filename}");
|
||||
|
||||
// Extract the file
|
||||
var destination = new MemoryStream();
|
||||
ExtractionStatus status = ExtractStream(source,
|
||||
destination,
|
||||
expected,
|
||||
pkzip,
|
||||
includeDebug,
|
||||
out var foundFilename);
|
||||
|
||||
// If the extracted data is invalid
|
||||
if (status != ExtractionStatus.GOOD || destination is null)
|
||||
return status;
|
||||
|
||||
// Ensure directory separators are consistent
|
||||
filename ??= foundFilename ?? $"FILE_[{expected.InputSize}, {expected.OutputSize}, {expected.Crc32}]";
|
||||
if (Path.DirectorySeparatorChar == '\\')
|
||||
filename = filename.Replace('/', '\\');
|
||||
else if (Path.DirectorySeparatorChar == '/')
|
||||
filename = filename.Replace('\\', '/');
|
||||
|
||||
// Ensure the full output directory exists
|
||||
filename = Path.Combine(outputDirectory, filename);
|
||||
var directoryName = Path.GetDirectoryName(filename);
|
||||
if (directoryName is not null && !Directory.Exists(directoryName))
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
// Write the output file
|
||||
File.WriteAllBytes(filename, destination.ToArray());
|
||||
return status;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to extract a file to a stream
|
||||
/// </summary>
|
||||
/// <param name="source">Stream representing the deflated data</param>
|
||||
/// <param name="destination">Stream where the inflated data will be written</param>
|
||||
/// <param name="expected">Expected DEFLATE stream information</param>
|
||||
/// <param name="pkzip">Indicates if PKZIP containers are used</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <param name="filename">Output filename if extracted from the data, null otherwise</param>
|
||||
/// <returns>Extraction status representing the final state</returns>
|
||||
/// <remarks>Assumes that the current stream position is where the compressed data lives</remarks>
|
||||
public static ExtractionStatus ExtractStream(Stream source,
|
||||
Stream destination,
|
||||
DeflateInfo expected,
|
||||
bool pkzip,
|
||||
bool includeDebug,
|
||||
out string? filename)
|
||||
{
|
||||
// If PKZIP containers are used
|
||||
if (pkzip)
|
||||
return ExtractStreamWithContainer(source, destination, expected, includeDebug, out filename);
|
||||
|
||||
// If post-data checksums are used
|
||||
filename = null;
|
||||
return ExtractStreamWithChecksum(source, destination, expected, includeDebug);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract source data in a PKZIP container
|
||||
/// </summary>
|
||||
/// <param name="source">Stream representing the deflated data</param>
|
||||
/// <param name="destination">Stream where the inflated data will be written</param>
|
||||
/// <param name="expected">Expected DEFLATE stream information</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <param name="filename">Filename from the PKZIP header, if it exists</param>
|
||||
/// <returns></returns>
|
||||
public static ExtractionStatus ExtractStreamWithContainer(Stream source,
|
||||
Stream destination,
|
||||
DeflateInfo expected,
|
||||
bool includeDebug,
|
||||
out string? filename)
|
||||
{
|
||||
// Set default values
|
||||
filename = null;
|
||||
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"Offset: {source.Position:X8}, Expected Read: {expected.InputSize}, Expected Write: {expected.OutputSize}, Expected CRC-32: {expected.Crc32:X8}");
|
||||
|
||||
// Check the validity of the inputs
|
||||
if (expected.InputSize == 0)
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine($"Not attempting to extract, expected to read 0 bytes");
|
||||
return ExtractionStatus.INVALID;
|
||||
}
|
||||
else if (expected.InputSize > (source.Length - source.Position))
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine($"Not attempting to extract, expected to read {expected.InputSize} bytes but only {source.Length - source.Position} bytes remain");
|
||||
return ExtractionStatus.INVALID;
|
||||
}
|
||||
|
||||
// Cache the current offset
|
||||
long current = source.Position;
|
||||
|
||||
// Parse the PKZIP header, if it exists
|
||||
MinLocalFileHeader? zipHeader = ParseLocalFileHeader(source);
|
||||
long zipHeaderBytes = source.Position - current;
|
||||
|
||||
// Always trust the PKZIP CRC-32 value over what is supplied
|
||||
if (zipHeader is not null)
|
||||
expected.Crc32 = zipHeader.CRC32;
|
||||
|
||||
// If the filename is [NULL], replace with the zip filename
|
||||
if (zipHeader?.FileName is not null)
|
||||
{
|
||||
filename = zipHeader.FileName;
|
||||
if (includeDebug) Console.WriteLine($"Filename from PKZIP header: {filename}");
|
||||
}
|
||||
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"PKZIP Filename: {zipHeader?.FileName}, PKZIP Expected Read: {zipHeader?.CompressedSize}, PKZIP Expected Write: {zipHeader?.UncompressedSize}, PKZIP Expected CRC-32: {zipHeader?.CRC32:X4}");
|
||||
|
||||
// Extract the file
|
||||
var actual = Inflate(source, destination);
|
||||
if (actual is null)
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine($"Could not extract {filename}");
|
||||
return ExtractionStatus.FAIL;
|
||||
}
|
||||
|
||||
// Account for the header bytes read
|
||||
actual.InputSize += zipHeaderBytes;
|
||||
source.Seek(current + actual.InputSize, SeekOrigin.Begin);
|
||||
|
||||
// Verify the extracted data
|
||||
return VerifyExtractedData(source, current, expected, actual, includeDebug);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract source data with a trailing CRC-32 checksum
|
||||
/// </summary>
|
||||
/// <param name="source">Stream representing the deflated data</param>
|
||||
/// <param name="destination">Stream where the inflated data will be written</param>
|
||||
/// <param name="expected">Expected DEFLATE stream information</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns></returns>
|
||||
public static ExtractionStatus ExtractStreamWithChecksum(Stream source,
|
||||
Stream destination,
|
||||
DeflateInfo expected,
|
||||
bool includeDebug)
|
||||
{
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"Offset: {source.Position:X8}, Expected Read: {expected.InputSize}, Expected Write: {expected.OutputSize}, Expected CRC-32: {expected.Crc32:X8}");
|
||||
|
||||
// Check the validity of the inputs
|
||||
if (expected.InputSize == 0)
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine($"Not attempting to extract, expected to read 0 bytes");
|
||||
return ExtractionStatus.INVALID;
|
||||
}
|
||||
else if (expected.InputSize > (source.Length - source.Position))
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine($"Not attempting to extract, expected to read {expected.InputSize} bytes but only {source.Length - source.Position} bytes remain");
|
||||
return ExtractionStatus.INVALID;
|
||||
}
|
||||
|
||||
// Cache the current offset
|
||||
long current = source.Position;
|
||||
|
||||
// Extract the file
|
||||
var actual = Inflate(source, destination);
|
||||
if (actual is null)
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine($"Could not extract");
|
||||
return ExtractionStatus.FAIL;
|
||||
}
|
||||
|
||||
// Seek to the true end of the data
|
||||
source.Seek(current + actual.InputSize, SeekOrigin.Begin);
|
||||
|
||||
// If the read value is off-by-one after checksum
|
||||
if (actual.InputSize == expected.InputSize - 5)
|
||||
{
|
||||
// If not at the end of the file, get the corrected offset
|
||||
if (source.Position + 5 < source.Length)
|
||||
{
|
||||
// TODO: What does this byte represent?
|
||||
byte padding = source.ReadByteValue();
|
||||
actual.InputSize += 1;
|
||||
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"Off-by-one padding byte detected: 0x{padding:X2}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"Not enough data to adjust offset");
|
||||
}
|
||||
}
|
||||
|
||||
// If there is enough data to read the full CRC
|
||||
uint deflateCrc;
|
||||
if (source.Position + 4 < source.Length)
|
||||
{
|
||||
deflateCrc = source.ReadUInt32LittleEndian();
|
||||
actual.InputSize += 4;
|
||||
}
|
||||
// Otherwise, read what is possible and pad with 0x00
|
||||
else
|
||||
{
|
||||
byte[] deflateCrcBytes = new byte[4];
|
||||
int realCrcLength = source.Read(deflateCrcBytes, 0, (int)(source.Length - source.Position));
|
||||
|
||||
// Parse as a little-endian 32-bit value
|
||||
deflateCrc = (uint)(deflateCrcBytes[0]
|
||||
| (deflateCrcBytes[1] << 8)
|
||||
| (deflateCrcBytes[2] << 16)
|
||||
| (deflateCrcBytes[3] << 24));
|
||||
|
||||
actual.InputSize += realCrcLength;
|
||||
}
|
||||
|
||||
// If the CRC to check isn't set
|
||||
if (expected.Crc32 == 0)
|
||||
expected.Crc32 = deflateCrc;
|
||||
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"DeflateStream CRC-32: {deflateCrc:X8}");
|
||||
|
||||
// Verify the extracted data
|
||||
return VerifyExtractedData(source, current, expected, actual, includeDebug);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a minimal local file header
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled minimal local file header on success, null on error</returns>
|
||||
/// <remarks>Partial mirror of method in Serialization</remarks>
|
||||
private static MinLocalFileHeader? ParseLocalFileHeader(Stream data)
|
||||
{
|
||||
var header = new MinLocalFileHeader();
|
||||
|
||||
header.Signature = data.ReadUInt32LittleEndian();
|
||||
if (header.Signature != LocalFileHeaderSignature)
|
||||
return null;
|
||||
|
||||
_ = data.ReadUInt16LittleEndian(); // Version
|
||||
_ = data.ReadUInt16LittleEndian(); // Flags
|
||||
_ = data.ReadUInt16LittleEndian(); // CompressionMethod
|
||||
_ = data.ReadUInt16LittleEndian(); // LastModifedFileTime
|
||||
_ = data.ReadUInt16LittleEndian(); // LastModifiedFileDate
|
||||
header.CRC32 = data.ReadUInt32LittleEndian();
|
||||
header.CompressedSize = data.ReadUInt32LittleEndian();
|
||||
header.UncompressedSize = data.ReadUInt32LittleEndian();
|
||||
ushort fileNameLength = data.ReadUInt16LittleEndian();
|
||||
ushort extraFieldLength = data.ReadUInt16LittleEndian();
|
||||
|
||||
if (fileNameLength > 0 && data.Position + fileNameLength <= data.Length)
|
||||
{
|
||||
byte[] filenameBytes = data.ReadBytes(fileNameLength);
|
||||
header.FileName = Encoding.ASCII.GetString(filenameBytes);
|
||||
}
|
||||
|
||||
// Parsing extras is skipped here, unlike in Serialization
|
||||
if (extraFieldLength > 0 && data.Position + extraFieldLength <= data.Length)
|
||||
_ = data.ReadBytes(extraFieldLength);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify the extracted stream data, seeking to the original location on failure
|
||||
/// </summary>
|
||||
/// <param name="source">Stream representing the deflated data</param>
|
||||
/// <param name="start">Position representing the start of the deflated data</param>
|
||||
/// <param name="expected">Expected deflation info</param>
|
||||
/// <param name="actual">Actual deflation info</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Extraction status representing the final state</returns>
|
||||
private static ExtractionStatus VerifyExtractedData(Stream source,
|
||||
long start,
|
||||
DeflateInfo expected,
|
||||
DeflateInfo actual,
|
||||
bool includeDebug)
|
||||
{
|
||||
// Debug output
|
||||
if (includeDebug) Console.WriteLine($"Actual Read: {actual.InputSize}, Actual Write: {actual.OutputSize}, Actual CRC-32: {actual.Crc32:X8}");
|
||||
|
||||
// If there's a mismatch during both reading and writing
|
||||
if (expected.InputSize >= 0 && expected.InputSize != actual.InputSize)
|
||||
{
|
||||
// This in/out check helps catch false positives, such as
|
||||
// files that have an off-by-one mismatch for read values
|
||||
// but properly match the output written values.
|
||||
|
||||
// If the written bytes not correct as well
|
||||
if (expected.OutputSize >= 0 && expected.OutputSize != actual.OutputSize)
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine($"Mismatched read/write values!");
|
||||
source.Seek(start, SeekOrigin.Begin);
|
||||
return ExtractionStatus.WRONG_SIZE;
|
||||
}
|
||||
|
||||
// If the written bytes are not being verified
|
||||
else if (expected.OutputSize < 0)
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine($"Mismatched read/write values!");
|
||||
source.Seek(start, SeekOrigin.Begin);
|
||||
return ExtractionStatus.WRONG_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// If there's just a mismatch during only writing
|
||||
if (expected.InputSize >= 0 && expected.InputSize == actual.InputSize)
|
||||
{
|
||||
// We want to log this but ignore the error
|
||||
if (expected.OutputSize >= 0 && expected.OutputSize != actual.OutputSize)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine($"Ignoring mismatched write values because read values match!");
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, the write size should be checked normally
|
||||
else if (expected.InputSize == 0 && expected.OutputSize >= 0 && expected.OutputSize != actual.OutputSize)
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine($"Mismatched write values!");
|
||||
source.Seek(start, SeekOrigin.Begin);
|
||||
return ExtractionStatus.WRONG_SIZE;
|
||||
}
|
||||
|
||||
// If there's a mismatch with the CRC-32
|
||||
if (expected.Crc32 != 0 && expected.Crc32 != actual.Crc32)
|
||||
{
|
||||
if (includeDebug) Console.Error.WriteLine($"Mismatched CRC-32 values!");
|
||||
source.Seek(start, SeekOrigin.Begin);
|
||||
return ExtractionStatus.BAD_CRC;
|
||||
}
|
||||
|
||||
return ExtractionStatus.GOOD;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Inflation
|
||||
|
||||
/// <summary>
|
||||
/// Inflate an input stream to an output stream
|
||||
/// </summary>
|
||||
/// <param name="source">Stream representing the deflated data</param>
|
||||
/// <param name="destination">Stream where the inflated data will be written</param>
|
||||
/// <returns>Deflate information representing the processed data on success, null on error</returns>
|
||||
public static DeflateInfo? Inflate(Stream source, Stream destination)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Setup the hasher for CRC-32 calculation
|
||||
using var hasher = new HashWrapper(HashType.CRC32);
|
||||
|
||||
// Create a DeflateStream from the input
|
||||
using var ds = new DeflateStream(source, CompressionMode.Decompress, leaveOpen: true);
|
||||
|
||||
// Decompress in blocks
|
||||
while (true)
|
||||
{
|
||||
byte[] buf = new byte[BufferSize];
|
||||
int read = ds.Read(buf, 0, buf.Length);
|
||||
if (read == 0)
|
||||
break;
|
||||
|
||||
hasher.Process(buf, 0, read);
|
||||
destination.Write(buf, 0, read);
|
||||
}
|
||||
|
||||
// Finalize the hash
|
||||
hasher.Terminate();
|
||||
byte[] hashBytes = hasher.CurrentHashBytes!;
|
||||
|
||||
// Save the deflate values
|
||||
return new DeflateInfo
|
||||
{
|
||||
InputSize = ds.TotalIn,
|
||||
OutputSize = ds.TotalOut,
|
||||
Crc32 = BitConverter.ToUInt32(hashBytes, 0),
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -88,27 +88,29 @@
|
||||
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0047
|
||||
#pragma warning disable IDE2002
|
||||
internal static class InternalConstants
|
||||
{
|
||||
internal static readonly int MAX_BITS = 15;
|
||||
internal static readonly int BL_CODES = 19;
|
||||
internal static readonly int D_CODES = 30;
|
||||
internal static readonly int LITERALS = 256;
|
||||
internal static readonly int MAX_BITS = 15;
|
||||
internal static readonly int BL_CODES = 19;
|
||||
internal static readonly int D_CODES = 30;
|
||||
internal static readonly int LITERALS = 256;
|
||||
internal static readonly int LENGTH_CODES = 29;
|
||||
internal static readonly int L_CODES = (LITERALS + 1 + LENGTH_CODES);
|
||||
internal static readonly int L_CODES = (LITERALS + 1 + LENGTH_CODES);
|
||||
|
||||
// Bit length codes must not exceed MAX_BL_BITS bits
|
||||
internal static readonly int MAX_BL_BITS = 7;
|
||||
internal static readonly int MAX_BL_BITS = 7;
|
||||
|
||||
// repeat previous bit length 3-6 times (2 bits of repeat count)
|
||||
internal static readonly int REP_3_6 = 16;
|
||||
internal static readonly int REP_3_6 = 16;
|
||||
|
||||
// repeat a zero length 3-10 times (3 bits of repeat count)
|
||||
internal static readonly int REPZ_3_10 = 17;
|
||||
internal static readonly int REPZ_3_10 = 17;
|
||||
|
||||
// repeat a zero length 11-138 times (7 bits of repeat count)
|
||||
internal static readonly int REPZ_11_138 = 18;
|
||||
internal static readonly int REPZ_11_138 = 18;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,10 +66,10 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
internal static class InternalInflateConstants
|
||||
{
|
||||
// And'ing with mask[n] masks the lower n bits
|
||||
internal static readonly int[] InflateMask = new int[] {
|
||||
internal static readonly int[] InflateMask = [
|
||||
0x00000000, 0x00000001, 0x00000003, 0x00000007,
|
||||
0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
|
||||
0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
|
||||
0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff };
|
||||
0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,10 @@
|
||||
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0002
|
||||
#pragma warning disable IDE0049
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2002
|
||||
internal class SharedUtils
|
||||
{
|
||||
/// <summary>
|
||||
@@ -159,4 +163,4 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
internal sealed class StaticTree
|
||||
{
|
||||
internal static readonly short[] lengthAndLiteralsTreeCodes = new short[] {
|
||||
internal static readonly short[] lengthAndLiteralsTreeCodes = [
|
||||
12, 8, 140, 8, 76, 8, 204, 8, 44, 8, 172, 8, 108, 8, 236, 8,
|
||||
28, 8, 156, 8, 92, 8, 220, 8, 60, 8, 188, 8, 124, 8, 252, 8,
|
||||
2, 8, 130, 8, 66, 8, 194, 8, 34, 8, 162, 8, 98, 8, 226, 8,
|
||||
@@ -127,13 +127,13 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
8, 7, 72, 7, 40, 7, 104, 7, 24, 7, 88, 7, 56, 7, 120, 7,
|
||||
4, 7, 68, 7, 36, 7, 100, 7, 20, 7, 84, 7, 52, 7, 116, 7,
|
||||
3, 8, 131, 8, 67, 8, 195, 8, 35, 8, 163, 8, 99, 8, 227, 8
|
||||
};
|
||||
];
|
||||
|
||||
internal static readonly short[] distTreeCodes = new short[] {
|
||||
internal static readonly short[] distTreeCodes = [
|
||||
0, 5, 16, 5, 8, 5, 24, 5, 4, 5, 20, 5, 12, 5, 28, 5,
|
||||
2, 5, 18, 5, 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, 30, 5,
|
||||
1, 5, 17, 5, 9, 5, 25, 5, 5, 5, 21, 5, 13, 5, 29, 5,
|
||||
3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 };
|
||||
3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 ];
|
||||
|
||||
internal static readonly StaticTree Literals;
|
||||
internal static readonly StaticTree Distances;
|
||||
@@ -160,5 +160,4 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
BitLengths = new StaticTree(null, Tree.extra_blbits, 0, InternalConstants.BL_CODES, InternalConstants.MAX_BL_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,421 +1,428 @@
|
||||
// Tree.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2009-October-28 13:29:50>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines classes for zlib compression and
|
||||
// decompression. This code is derived from the jzlib implementation of
|
||||
// zlib. In keeping with the license for jzlib, the copyright to that
|
||||
// code is below.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
#nullable disable
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
sealed class Tree
|
||||
{
|
||||
private static readonly int HEAP_SIZE = (2 * InternalConstants.L_CODES + 1);
|
||||
|
||||
// extra bits for each length code
|
||||
internal static readonly int[] ExtraLengthBits = new int[]
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
};
|
||||
|
||||
// extra bits for each distance code
|
||||
internal static readonly int[] ExtraDistanceBits = new int[]
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
|
||||
7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
|
||||
};
|
||||
|
||||
// extra bits for each bit length code
|
||||
internal static readonly int[] extra_blbits = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7};
|
||||
|
||||
internal static readonly sbyte[] bl_order = new sbyte[]{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
|
||||
|
||||
|
||||
// The lengths of the bit length codes are sent in order of decreasing
|
||||
// probability, to avoid transmitting the lengths for unused bit
|
||||
// length codes.
|
||||
|
||||
internal const int Buf_size = 8 * 2;
|
||||
|
||||
// see definition of array dist_code below
|
||||
//internal const int DIST_CODE_LEN = 512;
|
||||
|
||||
private static readonly sbyte[] _dist_code = new sbyte[]
|
||||
{
|
||||
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
|
||||
};
|
||||
|
||||
internal static readonly sbyte[] LengthCode = new sbyte[]
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11,
|
||||
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
|
||||
};
|
||||
|
||||
|
||||
internal static readonly int[] LengthBase = new int[]
|
||||
{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28,
|
||||
32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0
|
||||
};
|
||||
|
||||
|
||||
internal static readonly int[] DistanceBase = new int[]
|
||||
{
|
||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
|
||||
256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Map from a distance to a distance code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// No side effects. _dist_code[256] and _dist_code[257] are never used.
|
||||
/// </remarks>
|
||||
internal static int DistanceCode(int dist)
|
||||
{
|
||||
return (dist < 256)
|
||||
? _dist_code[dist]
|
||||
: _dist_code[256 + SharedUtils.URShift(dist, 7)];
|
||||
}
|
||||
|
||||
internal short[] dyn_tree; // the dynamic tree
|
||||
internal int max_code; // largest code with non zero frequency
|
||||
internal StaticTree staticTree; // the corresponding static tree
|
||||
|
||||
// Compute the optimal bit lengths for a tree and update the total bit length
|
||||
// for the current block.
|
||||
// IN assertion: the fields freq and dad are set, heap[heap_max] and
|
||||
// above are the tree nodes sorted by increasing frequency.
|
||||
// OUT assertions: the field len is set to the optimal bit length, the
|
||||
// array bl_count contains the frequencies for each bit length.
|
||||
// The length opt_len is updated; static_len is also updated if stree is
|
||||
// not null.
|
||||
internal void gen_bitlen(DeflateManager s)
|
||||
{
|
||||
short[] tree = dyn_tree;
|
||||
short[] stree = staticTree.treeCodes;
|
||||
int[] extra = staticTree.extraBits;
|
||||
int base_Renamed = staticTree.extraBase;
|
||||
int max_length = staticTree.maxLength;
|
||||
int h; // heap index
|
||||
int n, m; // iterate over the tree elements
|
||||
int bits; // bit length
|
||||
int xbits; // extra bits
|
||||
short f; // frequency
|
||||
int overflow = 0; // number of elements with bit length too large
|
||||
|
||||
for (bits = 0; bits <= InternalConstants.MAX_BITS; bits++)
|
||||
s.bl_count[bits] = 0;
|
||||
|
||||
// In a first pass, compute the optimal bit lengths (which may
|
||||
// overflow in the case of the bit length tree).
|
||||
tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
|
||||
|
||||
for (h = s.heap_max + 1; h < HEAP_SIZE; h++)
|
||||
{
|
||||
n = s.heap[h];
|
||||
bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
|
||||
if (bits > max_length)
|
||||
{
|
||||
bits = max_length; overflow++;
|
||||
}
|
||||
tree[n * 2 + 1] = (short) bits;
|
||||
// We overwrite tree[n*2+1] which is no longer needed
|
||||
|
||||
if (n > max_code)
|
||||
continue; // not a leaf node
|
||||
|
||||
s.bl_count[bits]++;
|
||||
xbits = 0;
|
||||
if (n >= base_Renamed)
|
||||
xbits = extra[n - base_Renamed];
|
||||
f = tree[n * 2];
|
||||
s.opt_len += f * (bits + xbits);
|
||||
if (stree != null)
|
||||
s.static_len += f * (stree[n * 2 + 1] + xbits);
|
||||
}
|
||||
if (overflow == 0)
|
||||
return ;
|
||||
|
||||
// This happens for example on obj2 and pic of the Calgary corpus
|
||||
// Find the first bit length which could increase:
|
||||
do
|
||||
{
|
||||
bits = max_length - 1;
|
||||
while (s.bl_count[bits] == 0)
|
||||
bits--;
|
||||
s.bl_count[bits]--; // move one leaf down the tree
|
||||
s.bl_count[bits + 1] = (short) (s.bl_count[bits + 1] + 2); // move one overflow item as its brother
|
||||
s.bl_count[max_length]--;
|
||||
// The brother of the overflow item also moves one step up,
|
||||
// but this does not affect bl_count[max_length]
|
||||
overflow -= 2;
|
||||
}
|
||||
while (overflow > 0);
|
||||
|
||||
for (bits = max_length; bits != 0; bits--)
|
||||
{
|
||||
n = s.bl_count[bits];
|
||||
while (n != 0)
|
||||
{
|
||||
m = s.heap[--h];
|
||||
if (m > max_code)
|
||||
continue;
|
||||
if (tree[m * 2 + 1] != bits)
|
||||
{
|
||||
s.opt_len = (int) (s.opt_len + ((long) bits - (long) tree[m * 2 + 1]) * (long) tree[m * 2]);
|
||||
tree[m * 2 + 1] = (short) bits;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct one Huffman tree and assigns the code bit strings and lengths.
|
||||
// Update the total bit length for the current block.
|
||||
// IN assertion: the field freq is set for all tree elements.
|
||||
// OUT assertions: the fields len and code are set to the optimal bit length
|
||||
// and corresponding code. The length opt_len is updated; static_len is
|
||||
// also updated if stree is not null. The field max_code is set.
|
||||
internal void build_tree(DeflateManager s)
|
||||
{
|
||||
short[] tree = dyn_tree;
|
||||
short[] stree = staticTree.treeCodes;
|
||||
int elems = staticTree.elems;
|
||||
int n, m; // iterate over heap elements
|
||||
int max_code = -1; // largest code with non zero frequency
|
||||
int node; // new node being created
|
||||
|
||||
// Construct the initial heap, with least frequent element in
|
||||
// heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
|
||||
// heap[0] is not used.
|
||||
s.heap_len = 0;
|
||||
s.heap_max = HEAP_SIZE;
|
||||
|
||||
for (n = 0; n < elems; n++)
|
||||
{
|
||||
if (tree[n * 2] != 0)
|
||||
{
|
||||
s.heap[++s.heap_len] = max_code = n;
|
||||
s.depth[n] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree[n * 2 + 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// The pkzip format requires that at least one distance code exists,
|
||||
// and that at least one bit should be sent even if there is only one
|
||||
// possible code. So to avoid special checks later on we force at least
|
||||
// two codes of non zero frequency.
|
||||
while (s.heap_len < 2)
|
||||
{
|
||||
node = s.heap[++s.heap_len] = (max_code < 2?++max_code:0);
|
||||
tree[node * 2] = 1;
|
||||
s.depth[node] = 0;
|
||||
s.opt_len--;
|
||||
if (stree != null)
|
||||
s.static_len -= stree[node * 2 + 1];
|
||||
// node is 0 or 1 so it does not have extra bits
|
||||
}
|
||||
this.max_code = max_code;
|
||||
|
||||
// The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
|
||||
// establish sub-heaps of increasing lengths:
|
||||
|
||||
for (n = s.heap_len / 2; n >= 1; n--)
|
||||
s.pqdownheap(tree, n);
|
||||
|
||||
// Construct the Huffman tree by repeatedly combining the least two
|
||||
// frequent nodes.
|
||||
|
||||
node = elems; // next internal node of the tree
|
||||
do
|
||||
{
|
||||
// n = node of least frequency
|
||||
n = s.heap[1];
|
||||
s.heap[1] = s.heap[s.heap_len--];
|
||||
s.pqdownheap(tree, 1);
|
||||
m = s.heap[1]; // m = node of next least frequency
|
||||
|
||||
s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
|
||||
s.heap[--s.heap_max] = m;
|
||||
|
||||
// Create a new node father of n and m
|
||||
tree[node * 2] = unchecked((short) (tree[n * 2] + tree[m * 2]));
|
||||
s.depth[node] = (sbyte) (System.Math.Max((byte) s.depth[n], (byte) s.depth[m]) + 1);
|
||||
tree[n * 2 + 1] = tree[m * 2 + 1] = (short) node;
|
||||
|
||||
// and insert the new node in the heap
|
||||
s.heap[1] = node++;
|
||||
s.pqdownheap(tree, 1);
|
||||
}
|
||||
while (s.heap_len >= 2);
|
||||
|
||||
s.heap[--s.heap_max] = s.heap[1];
|
||||
|
||||
// At this point, the fields freq and dad are set. We can now
|
||||
// generate the bit lengths.
|
||||
|
||||
gen_bitlen(s);
|
||||
|
||||
// The field len is now set, we can generate the bit codes
|
||||
gen_codes(tree, max_code, s.bl_count);
|
||||
}
|
||||
|
||||
// Generate the codes for a given tree and bit counts (which need not be
|
||||
// optimal).
|
||||
// IN assertion: the array bl_count contains the bit length statistics for
|
||||
// the given tree and the field len is set for all tree elements.
|
||||
// OUT assertion: the field code is set for all tree elements of non
|
||||
// zero code length.
|
||||
internal static void gen_codes(short[] tree, int max_code, short[] bl_count)
|
||||
{
|
||||
short[] next_code = new short[InternalConstants.MAX_BITS + 1]; // next code value for each bit length
|
||||
short code = 0; // running code value
|
||||
int bits; // bit index
|
||||
int n; // code index
|
||||
|
||||
// The distribution counts are first used to generate the code values
|
||||
// without bit reversal.
|
||||
for (bits = 1; bits <= InternalConstants.MAX_BITS; bits++)
|
||||
unchecked {
|
||||
next_code[bits] = code = (short) ((code + bl_count[bits - 1]) << 1);
|
||||
}
|
||||
|
||||
// Check that the bit counts in bl_count are consistent. The last code
|
||||
// must be all ones.
|
||||
//Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
|
||||
// "inconsistent bit counts");
|
||||
//Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
|
||||
|
||||
for (n = 0; n <= max_code; n++)
|
||||
{
|
||||
int len = tree[n * 2 + 1];
|
||||
if (len == 0)
|
||||
continue;
|
||||
// Now reverse the bits
|
||||
tree[n * 2] = unchecked((short) (bi_reverse(next_code[len]++, len)));
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse the first len bits of a code, using straightforward code (a faster
|
||||
// method would use a table)
|
||||
// IN assertion: 1 <= len <= 15
|
||||
internal static int bi_reverse(int code, int len)
|
||||
{
|
||||
int res = 0;
|
||||
do
|
||||
{
|
||||
res |= code & 1;
|
||||
code >>= 1; //SharedUtils.URShift(code, 1);
|
||||
res <<= 1;
|
||||
}
|
||||
while (--len > 0);
|
||||
return res >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Tree.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2009-October-28 13:29:50>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines classes for zlib compression and
|
||||
// decompression. This code is derived from the jzlib implementation of
|
||||
// zlib. In keeping with the license for jzlib, the copyright to that
|
||||
// code is below.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
#nullable disable
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0004
|
||||
#pragma warning disable IDE0040
|
||||
#pragma warning disable IDE0047
|
||||
#pragma warning disable IDE0048
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2003
|
||||
sealed class Tree
|
||||
{
|
||||
private static readonly int HEAP_SIZE = (2 * InternalConstants.L_CODES + 1);
|
||||
|
||||
// extra bits for each length code
|
||||
internal static readonly int[] ExtraLengthBits =
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
|
||||
];
|
||||
|
||||
// extra bits for each distance code
|
||||
internal static readonly int[] ExtraDistanceBits =
|
||||
[
|
||||
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
|
||||
7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
|
||||
];
|
||||
|
||||
// extra bits for each bit length code
|
||||
internal static readonly int[] extra_blbits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7];
|
||||
|
||||
internal static readonly sbyte[] bl_order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
|
||||
|
||||
|
||||
// The lengths of the bit length codes are sent in order of decreasing
|
||||
// probability, to avoid transmitting the lengths for unused bit
|
||||
// length codes.
|
||||
|
||||
internal const int Buf_size = 8 * 2;
|
||||
|
||||
// see definition of array dist_code below
|
||||
//internal const int DIST_CODE_LEN = 512;
|
||||
|
||||
private static readonly sbyte[] _dist_code =
|
||||
[
|
||||
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||||
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
|
||||
];
|
||||
|
||||
internal static readonly sbyte[] LengthCode =
|
||||
[
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11,
|
||||
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
|
||||
];
|
||||
|
||||
|
||||
internal static readonly int[] LengthBase =
|
||||
[
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28,
|
||||
32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0
|
||||
];
|
||||
|
||||
|
||||
internal static readonly int[] DistanceBase =
|
||||
[
|
||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
|
||||
256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
|
||||
];
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Map from a distance to a distance code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// No side effects. _dist_code[256] and _dist_code[257] are never used.
|
||||
/// </remarks>
|
||||
internal static int DistanceCode(int dist)
|
||||
{
|
||||
return (dist < 256)
|
||||
? _dist_code[dist]
|
||||
: _dist_code[256 + SharedUtils.URShift(dist, 7)];
|
||||
}
|
||||
|
||||
internal short[] dyn_tree; // the dynamic tree
|
||||
internal int max_code; // largest code with non zero frequency
|
||||
internal StaticTree staticTree; // the corresponding static tree
|
||||
|
||||
// Compute the optimal bit lengths for a tree and update the total bit length
|
||||
// for the current block.
|
||||
// IN assertion: the fields freq and dad are set, heap[heap_max] and
|
||||
// above are the tree nodes sorted by increasing frequency.
|
||||
// OUT assertions: the field len is set to the optimal bit length, the
|
||||
// array bl_count contains the frequencies for each bit length.
|
||||
// The length opt_len is updated; static_len is also updated if stree is
|
||||
// not null.
|
||||
internal void gen_bitlen(DeflateManager s)
|
||||
{
|
||||
short[] tree = dyn_tree;
|
||||
short[] stree = staticTree.treeCodes;
|
||||
int[] extra = staticTree.extraBits;
|
||||
int base_Renamed = staticTree.extraBase;
|
||||
int max_length = staticTree.maxLength;
|
||||
int h; // heap index
|
||||
int n, m; // iterate over the tree elements
|
||||
int bits; // bit length
|
||||
int xbits; // extra bits
|
||||
short f; // frequency
|
||||
int overflow = 0; // number of elements with bit length too large
|
||||
|
||||
for (bits = 0; bits <= InternalConstants.MAX_BITS; bits++)
|
||||
s.bl_count[bits] = 0;
|
||||
|
||||
// In a first pass, compute the optimal bit lengths (which may
|
||||
// overflow in the case of the bit length tree).
|
||||
tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
|
||||
|
||||
for (h = s.heap_max + 1; h < HEAP_SIZE; h++)
|
||||
{
|
||||
n = s.heap[h];
|
||||
bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
|
||||
if (bits > max_length)
|
||||
{
|
||||
bits = max_length; overflow++;
|
||||
}
|
||||
tree[n * 2 + 1] = (short)bits;
|
||||
// We overwrite tree[n*2+1] which is no longer needed
|
||||
|
||||
if (n > max_code)
|
||||
continue; // not a leaf node
|
||||
|
||||
s.bl_count[bits]++;
|
||||
xbits = 0;
|
||||
if (n >= base_Renamed)
|
||||
xbits = extra[n - base_Renamed];
|
||||
f = tree[n * 2];
|
||||
s.opt_len += f * (bits + xbits);
|
||||
if (stree is not null)
|
||||
s.static_len += f * (stree[n * 2 + 1] + xbits);
|
||||
}
|
||||
if (overflow == 0)
|
||||
return;
|
||||
|
||||
// This happens for example on obj2 and pic of the Calgary corpus
|
||||
// Find the first bit length which could increase:
|
||||
do
|
||||
{
|
||||
bits = max_length - 1;
|
||||
while (s.bl_count[bits] == 0)
|
||||
bits--;
|
||||
s.bl_count[bits]--; // move one leaf down the tree
|
||||
s.bl_count[bits + 1] = (short)(s.bl_count[bits + 1] + 2); // move one overflow item as its brother
|
||||
s.bl_count[max_length]--;
|
||||
// The brother of the overflow item also moves one step up,
|
||||
// but this does not affect bl_count[max_length]
|
||||
overflow -= 2;
|
||||
}
|
||||
while (overflow > 0);
|
||||
|
||||
for (bits = max_length; bits != 0; bits--)
|
||||
{
|
||||
n = s.bl_count[bits];
|
||||
while (n != 0)
|
||||
{
|
||||
m = s.heap[--h];
|
||||
if (m > max_code)
|
||||
continue;
|
||||
if (tree[m * 2 + 1] != bits)
|
||||
{
|
||||
s.opt_len = (int)(s.opt_len + ((long)bits - (long)tree[m * 2 + 1]) * (long)tree[m * 2]);
|
||||
tree[m * 2 + 1] = (short)bits;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct one Huffman tree and assigns the code bit strings and lengths.
|
||||
// Update the total bit length for the current block.
|
||||
// IN assertion: the field freq is set for all tree elements.
|
||||
// OUT assertions: the fields len and code are set to the optimal bit length
|
||||
// and corresponding code. The length opt_len is updated; static_len is
|
||||
// also updated if stree is not null. The field max_code is set.
|
||||
internal void build_tree(DeflateManager s)
|
||||
{
|
||||
short[] tree = dyn_tree;
|
||||
short[] stree = staticTree.treeCodes;
|
||||
int elems = staticTree.elems;
|
||||
int n, m; // iterate over heap elements
|
||||
int max_code = -1; // largest code with non zero frequency
|
||||
int node; // new node being created
|
||||
|
||||
// Construct the initial heap, with least frequent element in
|
||||
// heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
|
||||
// heap[0] is not used.
|
||||
s.heap_len = 0;
|
||||
s.heap_max = HEAP_SIZE;
|
||||
|
||||
for (n = 0; n < elems; n++)
|
||||
{
|
||||
if (tree[n * 2] != 0)
|
||||
{
|
||||
s.heap[++s.heap_len] = max_code = n;
|
||||
s.depth[n] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree[n * 2 + 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// The pkzip format requires that at least one distance code exists,
|
||||
// and that at least one bit should be sent even if there is only one
|
||||
// possible code. So to avoid special checks later on we force at least
|
||||
// two codes of non zero frequency.
|
||||
while (s.heap_len < 2)
|
||||
{
|
||||
node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
|
||||
tree[node * 2] = 1;
|
||||
s.depth[node] = 0;
|
||||
s.opt_len--;
|
||||
if (stree is not null)
|
||||
s.static_len -= stree[node * 2 + 1];
|
||||
// node is 0 or 1 so it does not have extra bits
|
||||
}
|
||||
this.max_code = max_code;
|
||||
|
||||
// The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
|
||||
// establish sub-heaps of increasing lengths:
|
||||
|
||||
for (n = s.heap_len / 2; n >= 1; n--)
|
||||
s.pqdownheap(tree, n);
|
||||
|
||||
// Construct the Huffman tree by repeatedly combining the least two
|
||||
// frequent nodes.
|
||||
|
||||
node = elems; // next internal node of the tree
|
||||
do
|
||||
{
|
||||
// n = node of least frequency
|
||||
n = s.heap[1];
|
||||
s.heap[1] = s.heap[s.heap_len--];
|
||||
s.pqdownheap(tree, 1);
|
||||
m = s.heap[1]; // m = node of next least frequency
|
||||
|
||||
s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
|
||||
s.heap[--s.heap_max] = m;
|
||||
|
||||
// Create a new node father of n and m
|
||||
tree[node * 2] = unchecked((short)(tree[n * 2] + tree[m * 2]));
|
||||
s.depth[node] = (sbyte)(System.Math.Max((byte)s.depth[n], (byte)s.depth[m]) + 1);
|
||||
tree[n * 2 + 1] = tree[m * 2 + 1] = (short)node;
|
||||
|
||||
// and insert the new node in the heap
|
||||
s.heap[1] = node++;
|
||||
s.pqdownheap(tree, 1);
|
||||
}
|
||||
while (s.heap_len >= 2);
|
||||
|
||||
s.heap[--s.heap_max] = s.heap[1];
|
||||
|
||||
// At this point, the fields freq and dad are set. We can now
|
||||
// generate the bit lengths.
|
||||
|
||||
gen_bitlen(s);
|
||||
|
||||
// The field len is now set, we can generate the bit codes
|
||||
gen_codes(tree, max_code, s.bl_count);
|
||||
}
|
||||
|
||||
// Generate the codes for a given tree and bit counts (which need not be
|
||||
// optimal).
|
||||
// IN assertion: the array bl_count contains the bit length statistics for
|
||||
// the given tree and the field len is set for all tree elements.
|
||||
// OUT assertion: the field code is set for all tree elements of non
|
||||
// zero code length.
|
||||
internal static void gen_codes(short[] tree, int max_code, short[] bl_count)
|
||||
{
|
||||
short[] next_code = new short[InternalConstants.MAX_BITS + 1]; // next code value for each bit length
|
||||
short code = 0; // running code value
|
||||
int bits; // bit index
|
||||
int n; // code index
|
||||
|
||||
// The distribution counts are first used to generate the code values
|
||||
// without bit reversal.
|
||||
for (bits = 1; bits <= InternalConstants.MAX_BITS; bits++)
|
||||
unchecked
|
||||
{
|
||||
next_code[bits] = code = (short)((code + bl_count[bits - 1]) << 1);
|
||||
}
|
||||
|
||||
// Check that the bit counts in bl_count are consistent. The last code
|
||||
// must be all ones.
|
||||
//Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
|
||||
// "inconsistent bit counts");
|
||||
//Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
|
||||
|
||||
for (n = 0; n <= max_code; n++)
|
||||
{
|
||||
int len = tree[n * 2 + 1];
|
||||
if (len == 0)
|
||||
continue;
|
||||
// Now reverse the bits
|
||||
tree[n * 2] = unchecked((short)(bi_reverse(next_code[len]++, len)));
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse the first len bits of a code, using straightforward code (a faster
|
||||
// method would use a table)
|
||||
// IN assertion: 1 <= len <= 15
|
||||
internal static int bi_reverse(int code, int len)
|
||||
{
|
||||
int res = 0;
|
||||
do
|
||||
{
|
||||
res |= code & 1;
|
||||
code >>= 1; //SharedUtils.URShift(code, 1);
|
||||
res <<= 1;
|
||||
}
|
||||
while (--len > 0);
|
||||
return res >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
#pragma warning disable CS0649
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0001
|
||||
#pragma warning disable IDE0048
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2002
|
||||
internal class WorkItem
|
||||
{
|
||||
public byte[] buffer;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,128 +1,126 @@
|
||||
// ZlibConstants.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2009-November-03 18:50:19>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines constants used by the zlib class library. This
|
||||
// code is derived from the jzlib implementation of zlib, but
|
||||
// significantly modified. In keeping with the license for jzlib, the
|
||||
// copyright to that code is included here.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
using System;
|
||||
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
/// <summary>
|
||||
/// A bunch of constants used in the Zlib interface.
|
||||
/// </summary>
|
||||
public static class ZlibConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum number of window bits for the Deflate algorithm.
|
||||
/// </summary>
|
||||
public const int WindowBitsMax = 15; // 32K LZ77 window
|
||||
|
||||
/// <summary>
|
||||
/// The default number of window bits for the Deflate algorithm.
|
||||
/// </summary>
|
||||
public const int WindowBitsDefault = WindowBitsMax;
|
||||
|
||||
/// <summary>
|
||||
/// indicates everything is A-OK
|
||||
/// </summary>
|
||||
public const int Z_OK = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the last operation reached the end of the stream.
|
||||
/// </summary>
|
||||
public const int Z_STREAM_END = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The operation ended in need of a dictionary.
|
||||
/// </summary>
|
||||
public const int Z_NEED_DICT = 2;
|
||||
|
||||
/// <summary>
|
||||
/// There was an error with the stream - not enough data, not open and readable, etc.
|
||||
/// </summary>
|
||||
public const int Z_STREAM_ERROR = -2;
|
||||
|
||||
/// <summary>
|
||||
/// There was an error with the data - not enough data, bad data, etc.
|
||||
/// </summary>
|
||||
public const int Z_DATA_ERROR = -3;
|
||||
|
||||
/// <summary>
|
||||
/// There was an error with the working buffer.
|
||||
/// </summary>
|
||||
public const int Z_BUF_ERROR = -5;
|
||||
|
||||
/// <summary>
|
||||
/// The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes.
|
||||
/// </summary>
|
||||
#if NETCF
|
||||
public const int WorkingBufferSizeDefault = 8192;
|
||||
#else
|
||||
public const int WorkingBufferSizeDefault = 16384;
|
||||
#endif
|
||||
/// <summary>
|
||||
/// The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes.
|
||||
/// </summary>
|
||||
public const int WorkingBufferSizeMin = 1024;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ZlibConstants.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code module is part of DotNetZip, a zipfile class library.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file License.txt for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// last saved (in emacs):
|
||||
// Time-stamp: <2009-November-03 18:50:19>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines constants used by the zlib class library. This
|
||||
// code is derived from the jzlib implementation of zlib, but
|
||||
// significantly modified. In keeping with the license for jzlib, the
|
||||
// copyright to that code is included here.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The names of the authors may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
||||
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
||||
// INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// This program is based on zlib-1.1.3; credit to authors
|
||||
// Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
|
||||
// and contributors of zlib.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE2002
|
||||
/// <summary>
|
||||
/// A bunch of constants used in the Zlib interface.
|
||||
/// </summary>
|
||||
public static class ZlibConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum number of window bits for the Deflate algorithm.
|
||||
/// </summary>
|
||||
public const int WindowBitsMax = 15; // 32K LZ77 window
|
||||
|
||||
/// <summary>
|
||||
/// The default number of window bits for the Deflate algorithm.
|
||||
/// </summary>
|
||||
public const int WindowBitsDefault = WindowBitsMax;
|
||||
|
||||
/// <summary>
|
||||
/// indicates everything is A-OK
|
||||
/// </summary>
|
||||
public const int Z_OK = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the last operation reached the end of the stream.
|
||||
/// </summary>
|
||||
public const int Z_STREAM_END = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The operation ended in need of a dictionary.
|
||||
/// </summary>
|
||||
public const int Z_NEED_DICT = 2;
|
||||
|
||||
/// <summary>
|
||||
/// There was an error with the stream - not enough data, not open and readable, etc.
|
||||
/// </summary>
|
||||
public const int Z_STREAM_ERROR = -2;
|
||||
|
||||
/// <summary>
|
||||
/// There was an error with the data - not enough data, bad data, etc.
|
||||
/// </summary>
|
||||
public const int Z_DATA_ERROR = -3;
|
||||
|
||||
/// <summary>
|
||||
/// There was an error with the working buffer.
|
||||
/// </summary>
|
||||
public const int Z_BUF_ERROR = -5;
|
||||
|
||||
/// <summary>
|
||||
/// The size of the working buffer used in the ZlibCodec class. Defaults to 8192 bytes.
|
||||
/// </summary>
|
||||
#if NETCF
|
||||
public const int WorkingBufferSizeDefault = 8192;
|
||||
#else
|
||||
public const int WorkingBufferSizeDefault = 16384;
|
||||
#endif
|
||||
/// <summary>
|
||||
/// The minimum size of the working buffer used in the ZlibCodec class. Currently it is 128 bytes.
|
||||
/// </summary>
|
||||
public const int WorkingBufferSizeMin = 1024;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -86,12 +86,13 @@
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
using Interop = System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0001
|
||||
#pragma warning disable IDE0049
|
||||
#pragma warning disable IDE2002
|
||||
/// <summary>
|
||||
/// A general purpose exception class for exceptions in the Zlib library.
|
||||
/// </summary>
|
||||
@@ -117,4 +118,4 @@ namespace SabreTools.IO.Compression.Deflate
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
58
SabreTools.IO/Compression/LZX/AlignedOffsetBlockData.cs
Normal file
58
SabreTools.IO/Compression/LZX/AlignedOffsetBlockData.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
namespace SabreTools.IO.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// An aligned offset block is identical to the verbatim block except for the presence of the aligned offset
|
||||
/// tree preceding the other trees.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
internal class AlignedOffsetBlockData : BlockData
|
||||
{
|
||||
/// <summary>
|
||||
/// Aligned offset tree
|
||||
/// </summary>
|
||||
/// <remarks>8 elements, 3 bits each</remarks>
|
||||
public byte[]? AlignedOffsetTree { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pretree for first 256 elements of main tree
|
||||
/// </summary>
|
||||
/// <remarks>20 elements, 4 bits each</remarks>
|
||||
public byte[]? PretreeFirst256 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path lengths of first 256 elements of main tree
|
||||
/// </summary>
|
||||
/// <remarks>Encoded using pretree</remarks>
|
||||
public int[]? PathLengthsFirst256 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pretree for remainder of main tree
|
||||
/// </summary>
|
||||
/// <remarks>20 elements, 4 bits each</remarks>
|
||||
public byte[]? PretreeRemainder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path lengths of remaining elements of main tree
|
||||
/// </summary>
|
||||
/// <remarks>Encoded using pretree</remarks>
|
||||
public int[]? PathLengthsRemainder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pretree for length tree
|
||||
/// </summary>
|
||||
/// <remarks>20 elements, 4 bits each</remarks>
|
||||
public byte[]? PretreeLengthTree { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path lengths of elements in length tree
|
||||
/// </summary>
|
||||
/// <remarks>Encoded using pretree</remarks>
|
||||
public int[]? PathLengthsLengthTree { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Token sequence (matches and literals)
|
||||
/// </summary>
|
||||
/// <remarks>Variable</remarks>
|
||||
public byte[]? TokenSequence { get; set; }
|
||||
}
|
||||
}
|
||||
24
SabreTools.IO/Compression/LZX/Block.cs
Normal file
24
SabreTools.IO/Compression/LZX/Block.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace SabreTools.IO.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// An LZXD block represents a sequence of compressed data that is encoded with the same set of
|
||||
/// Huffman trees, or a sequence of uncompressed data. There can be one or more LZXD blocks in a
|
||||
/// compressed stream, each with its own set of Huffman trees. Blocks do not have to start or end on a
|
||||
/// chunk boundary; blocks can span multiple chunks, or a single chunk can contain multiple blocks. The
|
||||
/// number of chunks is related to the size of the data being compressed, while the number of blocks is
|
||||
/// related to how well the data is compressed.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
internal class Block
|
||||
{
|
||||
/// <summary>
|
||||
/// Block header
|
||||
/// </summary>
|
||||
public BlockHeader? Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block data
|
||||
/// </summary>
|
||||
public BlockData? BlockData { get; set; }
|
||||
}
|
||||
}
|
||||
8
SabreTools.IO/Compression/LZX/BlockData.cs
Normal file
8
SabreTools.IO/Compression/LZX/BlockData.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace SabreTools.IO.Compression.LZX
|
||||
{
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
internal abstract class BlockData
|
||||
{
|
||||
// No common fields between all block data
|
||||
}
|
||||
}
|
||||
33
SabreTools.IO/Compression/LZX/BlockHeader.cs
Normal file
33
SabreTools.IO/Compression/LZX/BlockHeader.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace SabreTools.IO.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// The Block Type field, as specified in section 2.3.1.1, indicates which type of block follows,
|
||||
/// and the Block Size field, as specified in section 2.3.1.2, indicates the number of
|
||||
/// uncompressed bytes represented by the block. Following the generic block
|
||||
/// header is a type-specific header that describes the remainder of the block.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
internal class BlockHeader
|
||||
{
|
||||
/// <remarks>3 bits</remarks>
|
||||
public BlockType BlockType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block size is the high 8 bits of 24
|
||||
/// </summary>
|
||||
/// <remarks>8 bits</remarks>
|
||||
public byte BlockSizeMSB { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block size is the middle 8 bits of 24
|
||||
/// </summary>
|
||||
/// <remarks>8 bits</remarks>
|
||||
public byte BlockSizeByte2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block size is the low 8 bits of 24
|
||||
/// </summary>
|
||||
/// <remarks>8 bits</remarks>
|
||||
public byte BlocksizeLSB { get; set; }
|
||||
}
|
||||
}
|
||||
25
SabreTools.IO/Compression/LZX/Chunk.cs
Normal file
25
SabreTools.IO/Compression/LZX/Chunk.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace SabreTools.IO.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// The LZXD compressor emits chunks of compressed data. A chunk represents exactly 32 KB of
|
||||
/// uncompressed data until the last chunk in the stream, which can represent less than 32 KB. To
|
||||
/// ensure that an exact number of input bytes represent an exact number of output bytes for each
|
||||
/// chunk, after each 32 KB of uncompressed data is represented in the output compressed bitstream, the
|
||||
/// output bitstream is padded with up to 15 bits of zeros to realign the bitstream on a 16-bit boundary
|
||||
/// (even byte boundary) for the next 32 KB of data. This results in a compressed chunk of a byte-aligned
|
||||
/// size. The compressed chunk could be smaller than 32 KB or larger than 32 KB if the data is
|
||||
/// incompressible when the chunk is not the last one.
|
||||
/// </summary>
|
||||
internal class Chunk
|
||||
{
|
||||
/// <summary>
|
||||
/// Chunk header
|
||||
/// </summary>
|
||||
public ChunkHeader? Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Block headers and data
|
||||
/// </summary>
|
||||
public Block[]? Blocks { get; set; }
|
||||
}
|
||||
}
|
||||
46
SabreTools.IO/Compression/LZX/ChunkHeader.cs
Normal file
46
SabreTools.IO/Compression/LZX/ChunkHeader.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
namespace SabreTools.IO.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// The LZXD compressor emits chunks of compressed data. A chunk represents exactly 32 KB of
|
||||
/// uncompressed data until the last chunk in the stream, which can represent less than 32 KB. To
|
||||
/// ensure that an exact number of input bytes represent an exact number of output bytes for each
|
||||
/// chunk, after each 32 KB of uncompressed data is represented in the output compressed bitstream, the
|
||||
/// output bitstream is padded with up to 15 bits of zeros to realign the bitstream on a 16-bit boundary
|
||||
/// (even byte boundary) for the next 32 KB of data. This results in a compressed chunk of a byte-aligned
|
||||
/// size. The compressed chunk could be smaller than 32 KB or larger than 32 KB if the data is
|
||||
/// incompressible when the chunk is not the last one.
|
||||
/// </summary>
|
||||
internal class ChunkHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// The LZXD engine encodes a compressed, chunk-size prefix field preceding each compressed chunk in
|
||||
/// the compressed byte stream. The compressed, chunk-size prefix field is a byte aligned, little-endian,
|
||||
/// 16-bit field. The chunk prefix chain could be followed in the compressed stream without
|
||||
/// decompressing any data. The next chunk prefix is at a location computed by the absolute byte offset
|
||||
/// location of this chunk prefix plus 2 (for the size of the chunk-size prefix field) plus the current chunk
|
||||
/// size.
|
||||
/// </summary>
|
||||
public ushort ChunkSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The first bit in the first chunk in the LZXD bitstream (following the 2-byte, chunk-size prefix described
|
||||
/// in section 2.2.1) indicates the presence or absence of two 16-bit fields immediately following the
|
||||
/// single bit. If the bit is set, E8 translation is enabled for all the following chunks in the stream using the
|
||||
/// 32-bit value derived from the two 16-bit fields as the E8_file_size provided to the compressor when E8
|
||||
/// translation was enabled. Note that E8_file_size is completely independent of the length of the
|
||||
/// uncompressed data. E8 call translation is disabled after the 32,768th chunk (after 1 gigabyte (GB) of
|
||||
/// uncompressed data).
|
||||
/// </summary>
|
||||
public byte E8Translation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// E8 translation size, high WORD
|
||||
/// </summary>
|
||||
public ushort? TranslationSizeHighWord { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// E8 translation size, low WORD
|
||||
/// </summary>
|
||||
public ushort? TranslationSizeLowWord { get; set; }
|
||||
}
|
||||
}
|
||||
38
SabreTools.IO/Compression/LZX/Constants.cs
Normal file
38
SabreTools.IO/Compression/LZX/Constants.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace SabreTools.IO.Compression.LZX
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
||||
/* some constants defined by the LZX specification */
|
||||
public const int LZX_MIN_MATCH = 2;
|
||||
public const int LZX_MAX_MATCH = 257;
|
||||
public const int LZX_NUM_CHARS = 256;
|
||||
public const int LZX_PRETREE_NUM_ELEMENTS = 20;
|
||||
|
||||
/// <summary>
|
||||
/// aligned offset tree #elements
|
||||
/// </summary>
|
||||
public const int LZX_ALIGNED_NUM_ELEMENTS = 8;
|
||||
|
||||
/// <summary>
|
||||
/// this one missing from spec!
|
||||
/// </summary>
|
||||
public const int LZX_NUM_PRIMARY_LENGTHS = 7;
|
||||
|
||||
/// <summary>
|
||||
/// length tree #elements
|
||||
/// </summary>
|
||||
public const int LZX_NUM_SECONDARY_LENGTHS = 249;
|
||||
|
||||
/* LZX huffman defines: tweak tablebits as desired */
|
||||
public const int LZX_PRETREE_MAXSYMBOLS = LZX_PRETREE_NUM_ELEMENTS;
|
||||
public const int LZX_PRETREE_TABLEBITS = 6;
|
||||
public const int LZX_MAINTREE_MAXSYMBOLS = (LZX_NUM_CHARS + 50) * 8;
|
||||
public const int LZX_MAINTREE_TABLEBITS = 12;
|
||||
public const int LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS + 1;
|
||||
public const int LZX_LENGTH_TABLEBITS = 12;
|
||||
public const int LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS;
|
||||
public const int LZX_ALIGNED_TABLEBITS = 7;
|
||||
|
||||
public const int LZX_LENTABLE_SAFETY = 64; /* we allow length table decoding overruns */
|
||||
}
|
||||
}
|
||||
48
SabreTools.IO/Compression/LZX/Enums.cs
Normal file
48
SabreTools.IO/Compression/LZX/Enums.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace SabreTools.IO.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-bit block type
|
||||
/// </summary>
|
||||
internal enum BlockType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Not valid
|
||||
/// </summary>
|
||||
INVALID_0 = 0b000,
|
||||
|
||||
/// <summary>
|
||||
/// Verbatim block
|
||||
/// </summary>
|
||||
Verbatim = 0b001,
|
||||
|
||||
/// <summary>
|
||||
/// Aligned offset block
|
||||
/// </summary>
|
||||
AlignedOffset = 0b010,
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed block
|
||||
/// </summary>
|
||||
Uncompressed = 0b011,
|
||||
|
||||
/// <summary>
|
||||
/// Not valid
|
||||
/// </summary>
|
||||
INVALID_4 = 0b100,
|
||||
|
||||
/// <summary>
|
||||
/// Not valid
|
||||
/// </summary>
|
||||
INVALID_5 = 0b101,
|
||||
|
||||
/// <summary>
|
||||
/// Not valid
|
||||
/// </summary>
|
||||
INVALID_6 = 0b110,
|
||||
|
||||
/// <summary>
|
||||
/// Not valid
|
||||
/// </summary>
|
||||
INVALID_7 = 0b111,
|
||||
}
|
||||
}
|
||||
54
SabreTools.IO/Compression/LZX/UncompressedBlockData.cs
Normal file
54
SabreTools.IO/Compression/LZX/UncompressedBlockData.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
namespace SabreTools.IO.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// Following the generic block header, an uncompressed block begins with 1 to 16 bits of zero padding
|
||||
/// to align the bit buffer on a 16-bit boundary. At this point, the bitstream ends and a byte stream
|
||||
/// begins. Following the zero padding, new 32-bit values for R0, R1, and R2 are output in little-endian
|
||||
/// form, followed by the uncompressed data bytes themselves. Finally, if the uncompressed data length
|
||||
/// is odd, one extra byte of zero padding is encoded to realign the following bitstream.
|
||||
///
|
||||
/// Then the bitstream of byte-swapped 16-bit integers resumes for the next Block Type field (if there
|
||||
/// are subsequent blocks).
|
||||
///
|
||||
/// The decoded R0, R1, and R2 values are used as initial repeated offset values to decode the
|
||||
/// subsequent compressed block if present.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
internal class UncompressedBlockData : BlockData
|
||||
{
|
||||
/// <summary>
|
||||
/// Padding to align following field on 16-bit boundary
|
||||
/// </summary>
|
||||
/// <remarks>Bits have a value of zero</remarks>
|
||||
public ushort PaddingBits { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Least significant to most significant byte (little-endian DWORD ([MS-DTYP]))
|
||||
/// </summary>
|
||||
/// <remarks>Encoded directly in the byte stream, not in the bitstream of byte-swapped 16-bit words</remarks>
|
||||
public uint R0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Least significant to most significant byte (little-endian DWORD)
|
||||
/// </summary>
|
||||
/// <remarks>Encoded directly in the byte stream, not in the bitstream of byte-swapped 16-bit words</remarks>
|
||||
public uint R1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Least significant to most significant byte (little-endian DWORD)
|
||||
/// </summary>
|
||||
/// <remarks>Encoded directly in the byte stream, not in the bitstream of byte-swapped 16-bit words</remarks>
|
||||
public uint R2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Can use the direct memcpy function, as specified in [IEEE1003.1]
|
||||
/// </summary>
|
||||
/// <remarks>Encoded directly in the byte stream, not in the bitstream of byte-swapped 16-bit words</remarks>
|
||||
public byte[]? RawDataBytes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Only if uncompressed size is odd
|
||||
/// </summary>
|
||||
public byte AlignmentByte { get; set; }
|
||||
}
|
||||
}
|
||||
51
SabreTools.IO/Compression/LZX/VerbatimBlockData.cs
Normal file
51
SabreTools.IO/Compression/LZX/VerbatimBlockData.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
namespace SabreTools.IO.Compression.LZX
|
||||
{
|
||||
/// <summary>
|
||||
/// The fields of a verbatim block that follow the generic block header
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-PATCH/%5bMS-PATCH%5d.pdf"/>
|
||||
internal class VerbatimBlockData : BlockData
|
||||
{
|
||||
/// <summary>
|
||||
/// Pretree for first 256 elements of main tree
|
||||
/// </summary>
|
||||
/// <remarks>20 elements, 4 bits each</remarks>
|
||||
public byte[]? PretreeFirst256 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path lengths of first 256 elements of main tree
|
||||
/// </summary>
|
||||
/// <remarks>Encoded using pretree</remarks>
|
||||
public int[]? PathLengthsFirst256 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pretree for remainder of main tree
|
||||
/// </summary>
|
||||
/// <remarks>20 elements, 4 bits each</remarks>
|
||||
public byte[]? PretreeRemainder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path lengths of remaining elements of main tree
|
||||
/// </summary>
|
||||
/// <remarks>Encoded using pretree</remarks>
|
||||
public int[]? PathLengthsRemainder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pretree for length tree
|
||||
/// </summary>
|
||||
/// <remarks>20 elements, 4 bits each</remarks>
|
||||
public byte[]? PretreeLengthTree { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Path lengths of elements in length tree
|
||||
/// </summary>
|
||||
/// <remarks>Encoded using pretree</remarks>
|
||||
public int[]? PathLengthsLengthTree { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Token sequence (matches and literals)
|
||||
/// </summary>
|
||||
/// <remarks>Variable</remarks>
|
||||
public byte[]? TokenSequence { get; set; }
|
||||
}
|
||||
}
|
||||
28
SabreTools.IO/Compression/MSZIP/BlockHeader.cs
Normal file
28
SabreTools.IO/Compression/MSZIP/BlockHeader.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace SabreTools.IO.Compression.MSZIP
|
||||
{
|
||||
/// <summary>
|
||||
/// Each MSZIP block MUST consist of a 2-byte MSZIP signature and one or more RFC 1951 blocks. The
|
||||
/// 2-byte MSZIP signature MUST consist of the bytes 0x43 and 0x4B. The MSZIP signature MUST be
|
||||
/// the first 2 bytes in the MSZIP block. The MSZIP signature is shown in the following packet diagram.
|
||||
///
|
||||
/// Each MSZIP block is the result of a single deflate compression operation, as defined in [RFC1951].
|
||||
/// The compressor that performs the compression operation MUST generate one or more RFC 1951
|
||||
/// blocks, as defined in [RFC1951]. The number, deflation mode, and type of RFC 1951 blocks in each
|
||||
/// MSZIP block is determined by the compressor, as defined in [RFC1951]. The last RFC 1951 block in
|
||||
/// each MSZIP block MUST be marked as the "end" of the stream(1), as defined by [RFC1951]
|
||||
/// section 3.2.3. Decoding trees MUST be discarded after each RFC 1951 block, but the history buffer
|
||||
/// MUST be maintained.Each MSZIP block MUST represent no more than 32 KB of uncompressed data.
|
||||
///
|
||||
/// The maximum compressed size of each MSZIP block is 32 KB + 12 bytes. This enables the MSZIP
|
||||
/// block to contain 32 KB of data split between two noncompressed RFC 1951 blocks, each of which
|
||||
/// has a value of BTYPE = 00.
|
||||
/// </summary>
|
||||
/// <see href="https://interoperability.blob.core.windows.net/files/MS-MCI/%5bMS-MCI%5d.pdf"/>
|
||||
internal class BlockHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// 'CK'
|
||||
/// </summary>
|
||||
public ushort Signature { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Extensions;
|
||||
using SabreTools.Models.Compression.MSZIP;
|
||||
|
||||
namespace SabreTools.IO.Compression.MSZIP
|
||||
{
|
||||
/// <see href="https://msopenspecs.azureedge.net/files/MS-MCI/%5bMS-MCI%5d.pdf"/>
|
||||
/// <see href="https://officeprotocoldoc.z19.web.core.windows.net/files/MS-MCI/%5bMS-MCI%5d.pdf"/>
|
||||
public class Decompressor
|
||||
{
|
||||
/// <summary>
|
||||
@@ -13,6 +12,11 @@ namespace SabreTools.IO.Compression.MSZIP
|
||||
/// </summary>
|
||||
private byte[]? _history = null;
|
||||
|
||||
/// <summary>
|
||||
/// Required output buffer size (32KiB)
|
||||
/// </summary>
|
||||
private const int _bufferSize = 0x8000;
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
@@ -52,20 +56,20 @@ namespace SabreTools.IO.Compression.MSZIP
|
||||
if (header.Signature != 0x4B43)
|
||||
throw new InvalidDataException(nameof(source));
|
||||
|
||||
byte[] buffer = new byte[32 * 1024];
|
||||
byte[] buffer = new byte[_bufferSize];
|
||||
var blockStream = new Deflate.DeflateStream(source, Deflate.CompressionMode.Decompress, leaveOpen: true);
|
||||
if (_history != null)
|
||||
if (_history is not null)
|
||||
blockStream.SetDictionary(_history, check: false);
|
||||
|
||||
int read = blockStream.Read(buffer, 0, buffer.Length);
|
||||
int read = blockStream.Read(buffer, 0, _bufferSize);
|
||||
if (read > 0)
|
||||
{
|
||||
// Write to output
|
||||
dest.Write(buffer, 0, read);
|
||||
dest.Write(buffer, 0, _bufferSize);
|
||||
|
||||
// Save the history for rollover
|
||||
_history = new byte[read];
|
||||
Array.Copy(buffer, _history, read);
|
||||
_history = new byte[_bufferSize];
|
||||
Array.Copy(buffer, _history, _bufferSize);
|
||||
}
|
||||
|
||||
// Flush and return
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user