mirror of
https://github.com/SabreTools/SabreTools.IO.git
synced 2026-02-07 13:54:34 +00:00
Compare commits
192 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 | ||
|
|
40d6ccf804 | ||
|
|
31c41f8775 | ||
|
|
cf7daff040 | ||
|
|
8570b107da | ||
|
|
cf4f613a65 | ||
|
|
16248ef02f | ||
|
|
abeaa92112 | ||
|
|
4b9b4a22cc | ||
|
|
bd1ac0c01c | ||
|
|
670594d13f | ||
|
|
89441103b3 | ||
|
|
71021c61f7 | ||
|
|
d49c211882 | ||
|
|
f2bdc815b8 | ||
|
|
e89450c4c1 | ||
|
|
44d5227c14 | ||
|
|
a914b554d1 | ||
|
|
20382360ee | ||
|
|
ff26c0a4b9 | ||
|
|
6028032c89 | ||
|
|
8f3a9d0ede | ||
|
|
4400f0bb87 | ||
|
|
9f12ee642d | ||
|
|
b084b13ec3 | ||
|
|
93b3accbfd | ||
|
|
e96c3114d9 | ||
|
|
04f095018c | ||
|
|
ff18049832 | ||
|
|
5e7d2901c8 | ||
|
|
add7bc8ea5 | ||
|
|
f95853cc87 | ||
|
|
3f146d45a8 | ||
|
|
f3689087e6 | ||
|
|
d2d191d86f | ||
|
|
d6cc7faea8 | ||
|
|
3b56150cc9 | ||
|
|
a7b50dfdf2 | ||
|
|
0b7ab5b932 | ||
|
|
e43560cbbd | ||
|
|
861bfdc4f4 | ||
|
|
933dd70654 | ||
|
|
0d2a2a3b7d | ||
|
|
6ad4872bd4 | ||
|
|
8c0f54c059 | ||
|
|
ab1b0646c4 | ||
|
|
450d8aab11 | ||
|
|
ec8908aec0 | ||
|
|
fb7ca7cde0 | ||
|
|
67ca20f71b | ||
|
|
ae3a27eee1 | ||
|
|
3b7f910a98 | ||
|
|
244edc132f | ||
|
|
cec495d55a | ||
|
|
7656734bb2 | ||
|
|
fa9310de39 | ||
|
|
fe466dfe25 | ||
|
|
d2c59c565f | ||
|
|
4e221f33d5 | ||
|
|
c5c8ce67ba | ||
|
|
8e3d204329 | ||
|
|
200d947f30 | ||
|
|
dfccdcfb05 | ||
|
|
72ff3ead48 | ||
|
|
fb15aecb87 | ||
|
|
897e54ca61 | ||
|
|
3af6bc8365 | ||
|
|
de05bae3f8 | ||
|
|
97d603abb7 | ||
|
|
ed32302447 | ||
|
|
c125dc4ec0 | ||
|
|
f154ae47c0 | ||
|
|
0d0e960b98 | ||
|
|
4a9f84ab66 | ||
|
|
39277ee443 | ||
|
|
ed367ace6d | ||
|
|
80e72832a4 | ||
|
|
8924a50432 | ||
|
|
97f00a2565 | ||
|
|
f35231d95b | ||
|
|
96c6bba93e | ||
|
|
b0d81f225b | ||
|
|
ef699ee1fb | ||
|
|
0910b716ba | ||
|
|
584feb33e6 |
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
|
||||
48
.github/workflows/build_and_test.yml
vendored
Normal file
48
.github/workflows/build_and_test.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Build and Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- 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
|
||||
49
.github/workflows/build_nupkg.yml
vendored
49
.github/workflows/build_nupkg.yml
vendored
@@ -1,49 +0,0 @@
|
||||
name: Nuget Pack
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build library
|
||||
run: dotnet build
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
- name: Pack
|
||||
run: dotnet pack
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'Nuget Package'
|
||||
path: 'SabreTools.IO/bin/Release/*.nupkg'
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: 'SabreTools.IO/bin/Release/*.nupkg'
|
||||
body: 'Last built commit: ${{ github.sha }}'
|
||||
name: 'Rolling Release'
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
31
.github/workflows/check_pr.yml
vendored
31
.github/workflows/check_pr.yml
vendored
@@ -3,18 +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: 8.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.
|
||||
125
README.MD
125
README.MD
@@ -1,11 +1,130 @@
|
||||
# SabreTools.IO
|
||||
|
||||
This library comprises I/O functionality for the following file types:
|
||||
[](https://github.com/SabreTools/SabreTools.IO/actions/workflows/build_and_test.yml)
|
||||
|
||||
This library compries of I/O functionality used by other SabreTools projects.
|
||||
|
||||
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.IO).
|
||||
|
||||
## Namespaces
|
||||
|
||||
Below are a list of the included namespaces and their overall utility.
|
||||
|
||||
### `SabreTools.IO`
|
||||
|
||||
Generic helper classes that involve custom functionality and utility.
|
||||
|
||||
### `SabreTools.IO.Compression`
|
||||
|
||||
Various compression implementations that are used across multiple projects. Most of the implementations are be ports of existing C and C++ code.
|
||||
|
||||
#### Supported Compressions
|
||||
|
||||
| Compression Name | Decompress | Compress | Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| Blast | Yes | No | |
|
||||
| BZip2 | Yes | Yes | Sourced from DotNetZip |
|
||||
| Deflate | Yes | Yes | Sourced from DotNetZip |
|
||||
| LZ | Yes | No | KWAJ, QBasic 4.5, and SZDD variants; KWAJ incomplete |
|
||||
| LZX | No | No | |
|
||||
| MSZIP | Yes | No | |
|
||||
| Quantum | Yes* | No | Partial implementation based on standalone archives; not working |
|
||||
|
||||
**Note:** If something is marked with a `*` it means that it need testing.
|
||||
|
||||
#### External Libraries
|
||||
|
||||
| Library Name | Use |
|
||||
| --- | ---|
|
||||
| [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:
|
||||
|
||||
- ClrMamePro-derived Metadata files
|
||||
- Standard and non-standard INI files
|
||||
- Separated-Value files (e.g. CSV, SSV, TSV)
|
||||
|
||||
There are also some extensions that are useful for wrapping common functionality required by SabreTools.
|
||||
For a generic INI implementation, see `SabreTools.IO.IniFile`.
|
||||
|
||||
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.IO).
|
||||
### `SabreTools.IO.Streams`
|
||||
|
||||
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
|
||||
|
||||
For the most recent stable build, download the latest release here: [Releases Page](https://github.com/SabreTools/SabreTools.IO/releases)
|
||||
|
||||
For the latest WIP build here: [Rolling Release](https://github.com/SabreTools/SabreTools.IO/releases/rolling)
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
41
SabreTools.IO.Test/Compression/BZip2Tests.cs
Normal file
41
SabreTools.IO.Test/Compression/BZip2Tests.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Compression.BZip2;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Compression
|
||||
{
|
||||
public class BZip2Tests
|
||||
{
|
||||
[Fact]
|
||||
public void BZip2InputStreamTest()
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "test-archive.bz2");
|
||||
Stream input = File.OpenRead(path);
|
||||
byte[] output = new byte[1024];
|
||||
|
||||
var bzip = new BZip2InputStream(input);
|
||||
int actual = bzip.Read(output, 0, output.Length);
|
||||
bzip.Close();
|
||||
|
||||
Assert.Equal(125, actual);
|
||||
string str = Encoding.UTF8.GetString(output, 0, 125);
|
||||
Assert.Equal("This is just a file that has a known set of hashes to make sure that everything with hashing is still working as anticipated.", str);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BZip2OutputStreamTest()
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-compress.bin");
|
||||
byte[] input = File.ReadAllBytes(path);
|
||||
var output = new MemoryStream();
|
||||
|
||||
var bzip = new BZip2OutputStream(output, leaveOpen: true);
|
||||
bzip.Write(input, 0, input.Length);
|
||||
bzip.Close();
|
||||
|
||||
Assert.Equal(122, output.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
SabreTools.IO.Test/Compression/BlastTests.cs
Normal file
27
SabreTools.IO.Test/Compression/BlastTests.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Compression.Blast;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Compression
|
||||
{
|
||||
public class BlastTests
|
||||
{
|
||||
[Fact]
|
||||
public void DecompressorTest()
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "test-archive.pk");
|
||||
byte[] input = File.ReadAllBytes(path);
|
||||
MemoryStream output = new MemoryStream();
|
||||
|
||||
var decompressor = Decompressor.Create();
|
||||
decompressor.CopyTo(input, output);
|
||||
|
||||
Assert.Equal(13, output.Length);
|
||||
byte[] bytes = output.ToArray();
|
||||
string str = Encoding.ASCII.GetString(bytes);
|
||||
Assert.Equal("AIAIAIAIAIAIA", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
SabreTools.IO.Test/Compression/MSZIPTests.cs
Normal file
31
SabreTools.IO.Test/Compression/MSZIPTests.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Compression.MSZIP;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Compression
|
||||
{
|
||||
public class MSZIPTests
|
||||
{
|
||||
[Fact]
|
||||
public void DecompressorTest()
|
||||
{
|
||||
// Testing Note: This is a fake file that has multiple blocks
|
||||
// sequentially. In real cabinet files, these are embedded in
|
||||
// CFDATA blocks.
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "test-archive.msz");
|
||||
byte[] inputBytes = File.ReadAllBytes(path);
|
||||
var input = new MemoryStream(inputBytes);
|
||||
var output = new MemoryStream();
|
||||
|
||||
var decompressor = Decompressor.Create();
|
||||
input.SeekIfPossible(0x0000);
|
||||
decompressor.CopyTo(input, output);
|
||||
input.SeekIfPossible(0x3969);
|
||||
decompressor.CopyTo(input, output);
|
||||
|
||||
Assert.Equal(65536, output.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
30
SabreTools.IO.Test/Compression/QuantumTests.cs
Normal file
30
SabreTools.IO.Test/Compression/QuantumTests.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
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
|
||||
{
|
||||
// This test is disabled for the forseeable future. The current Quantum
|
||||
// processing code only handles standalone Quantum archives in theory.
|
||||
// There is additional work that needs to be done to support MS-CAB padding
|
||||
// before this test will pass properly.
|
||||
|
||||
//[Fact]
|
||||
public void DecompressorTest()
|
||||
{
|
||||
// Testing Note: This is a fake file that has been taken
|
||||
// from the CFDATA block of a cabinet file.
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "test-archive.qtm");
|
||||
byte[] inputBytes = File.ReadAllBytes(path);
|
||||
|
||||
var decompressor = Decompressor.Create(inputBytes, 19);
|
||||
byte[] output = decompressor.Process();
|
||||
|
||||
Assert.Equal(38470, output.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,13 @@
|
||||
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;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
// TODO: Add byte[], char[] tests
|
||||
// TODO: Add string writing tests
|
||||
public class BinaryWriterExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
@@ -37,37 +33,71 @@ 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());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteBytesBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bw.WriteBigEndian([0x03, 0x02, 0x01, 0x00]);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSByteTest()
|
||||
{
|
||||
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());
|
||||
}
|
||||
@@ -87,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());
|
||||
}
|
||||
@@ -97,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());
|
||||
}
|
||||
@@ -118,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());
|
||||
}
|
||||
@@ -140,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());
|
||||
}
|
||||
@@ -162,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());
|
||||
@@ -173,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());
|
||||
}
|
||||
@@ -183,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());
|
||||
@@ -194,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());
|
||||
}
|
||||
@@ -204,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());
|
||||
}
|
||||
@@ -225,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());
|
||||
}
|
||||
@@ -246,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());
|
||||
@@ -257,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());
|
||||
}
|
||||
@@ -267,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());
|
||||
@@ -278,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());
|
||||
}
|
||||
@@ -288,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());
|
||||
@@ -299,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());
|
||||
}
|
||||
@@ -309,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());
|
||||
}
|
||||
@@ -330,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());
|
||||
}
|
||||
@@ -351,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());
|
||||
@@ -362,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());
|
||||
}
|
||||
@@ -372,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());
|
||||
@@ -383,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());
|
||||
@@ -394,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());
|
||||
@@ -417,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());
|
||||
}
|
||||
@@ -428,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());
|
||||
@@ -439,12 +538,122 @@ 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()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[4], 0, 4, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [0x41, 0x42, 0x43, 0x00];
|
||||
|
||||
bool write = bw.WriteNullTerminatedAnsiString("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedUTF8StringTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[4], 0, 4, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [0x41, 0x42, 0x43, 0x00];
|
||||
|
||||
bool write = bw.WriteNullTerminatedUTF8String("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedUnicodeStringTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[8], 0, 8, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00];
|
||||
|
||||
bool write = bw.WriteNullTerminatedUnicodeString("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedUTF32StringTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
|
||||
|
||||
bool write = bw.WriteNullTerminatedUTF32String("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WritePrefixedAnsiStringTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[4], 0, 4, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [0x03, 0x41, 0x42, 0x43];
|
||||
|
||||
bool write = bw.WritePrefixedAnsiString("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WritePrefixedUnicodeStringTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[8], 0, 8, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [0x03, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00];
|
||||
|
||||
bool write = bw.WritePrefixedUnicodeString("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeTest()
|
||||
{
|
||||
// Guid
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
bool actual = bw.WriteType(new Guid(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, stream.GetBuffer());
|
||||
|
||||
// Half
|
||||
stream = new MemoryStream(new byte[2], 0, 2, true, true);
|
||||
bw = new BinaryWriter(stream);
|
||||
actual = bw.WriteType(BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(2)], stream.GetBuffer());
|
||||
|
||||
// Int128
|
||||
stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
bw = new BinaryWriter(stream);
|
||||
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)new BigInteger(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, stream.GetBuffer());
|
||||
|
||||
// Enum
|
||||
stream = new MemoryStream(new byte[4], 0, 4, true, true);
|
||||
bw = new BinaryWriter(stream);
|
||||
actual = bw.WriteType((TestEnum)0x03020100);
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(4)], stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeExplicitTest()
|
||||
@@ -463,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());
|
||||
@@ -488,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());
|
||||
@@ -505,4 +714,4 @@ namespace SabreTools.IO.Test.Extensions
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,547 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
// TODO: Add string reading tests
|
||||
public class ByteArrayExtensionsReadTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test pattern from 0x00-0x0F
|
||||
/// </summary>
|
||||
private static readonly byte[] _bytes =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Represents the decimal value 0.0123456789
|
||||
/// </summary>
|
||||
private static readonly byte[] _decimalBytes =
|
||||
[
|
||||
0x15, 0xCD, 0x5B, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void ReadByteTest()
|
||||
{
|
||||
int offset = 0;
|
||||
byte read = _bytes.ReadByte(ref offset);
|
||||
Assert.Equal(0x00, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadByteValueTest()
|
||||
{
|
||||
int offset = 0;
|
||||
byte read = _bytes.ReadByteValue(ref offset);
|
||||
Assert.Equal(0x00, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadBytesTest()
|
||||
{
|
||||
int offset = 0, length = 4;
|
||||
byte[] read = _bytes.ReadBytes(ref offset, length);
|
||||
Assert.Equal(length, read.Length);
|
||||
Assert.True(read.SequenceEqual(_bytes.Take(length)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadSByteTest()
|
||||
{
|
||||
int offset = 0;
|
||||
sbyte read = _bytes.ReadSByte(ref offset);
|
||||
Assert.Equal(0x00, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadCharTest()
|
||||
{
|
||||
int offset = 0;
|
||||
char read = _bytes.ReadChar(ref offset);
|
||||
Assert.Equal('\0', read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt16Test()
|
||||
{
|
||||
int offset = 0;
|
||||
short read = _bytes.ReadInt16(ref offset);
|
||||
Assert.Equal(0x0100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt16BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
short read = _bytes.ReadInt16BigEndian(ref offset);
|
||||
Assert.Equal(0x0001, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt16Test()
|
||||
{
|
||||
int offset = 0;
|
||||
ushort read = _bytes.ReadUInt16(ref offset);
|
||||
Assert.Equal(0x0100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt16BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
ushort read = _bytes.ReadUInt16BigEndian(ref offset);
|
||||
Assert.Equal(0x0001, read);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
[Fact]
|
||||
public void ReadHalfTest()
|
||||
{
|
||||
int offset = 0;
|
||||
Half expected = BitConverter.Int16BitsToHalf(0x0100);
|
||||
Half read = _bytes.ReadHalf(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadHalfBigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
Half expected = BitConverter.Int16BitsToHalf(0x0001);
|
||||
Half read = _bytes.ReadHalfBigEndian(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void ReadInt24Test()
|
||||
{
|
||||
int offset = 0;
|
||||
int read = _bytes.ReadInt24(ref offset);
|
||||
Assert.Equal(0x020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt24BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
int read = _bytes.ReadInt24BigEndian(ref offset);
|
||||
Assert.Equal(0x000102, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt24Test()
|
||||
{
|
||||
int offset = 0;
|
||||
uint read = _bytes.ReadUInt24(ref offset);
|
||||
Assert.Equal((uint)0x020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt24BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
uint read = _bytes.ReadUInt24BigEndian(ref offset);
|
||||
Assert.Equal((uint)0x000102, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt32Test()
|
||||
{
|
||||
int offset = 0;
|
||||
int read = _bytes.ReadInt32(ref offset);
|
||||
Assert.Equal(0x03020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt32BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
int read = _bytes.ReadInt32BigEndian(ref offset);
|
||||
Assert.Equal(0x00010203, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt32Test()
|
||||
{
|
||||
int offset = 0;
|
||||
uint read = _bytes.ReadUInt32(ref offset);
|
||||
Assert.Equal((uint)0x03020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt32BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
uint read = _bytes.ReadUInt32BigEndian(ref offset);
|
||||
Assert.Equal((uint)0x00010203, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadSingleTest()
|
||||
{
|
||||
int offset = 0;
|
||||
float expected = BitConverter.Int32BitsToSingle(0x03020100);
|
||||
float read = _bytes.ReadSingle(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadSingleBigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
float expected = BitConverter.Int32BitsToSingle(0x00010203);
|
||||
float read = _bytes.ReadSingleBigEndian(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt48Test()
|
||||
{
|
||||
int offset = 0;
|
||||
long read = _bytes.ReadInt48(ref offset);
|
||||
Assert.Equal(0x050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt48BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
long read = _bytes.ReadInt48BigEndian(ref offset);
|
||||
Assert.Equal(0x000102030405, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt48Test()
|
||||
{
|
||||
int offset = 0;
|
||||
ulong read = _bytes.ReadUInt48(ref offset);
|
||||
Assert.Equal((ulong)0x050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt48BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
ulong read = _bytes.ReadUInt48BigEndian(ref offset);
|
||||
Assert.Equal((ulong)0x000102030405, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt64Test()
|
||||
{
|
||||
int offset = 0;
|
||||
long read = _bytes.ReadInt64(ref offset);
|
||||
Assert.Equal(0x0706050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt64BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
long read = _bytes.ReadInt64BigEndian(ref offset);
|
||||
Assert.Equal(0x0001020304050607, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt64Test()
|
||||
{
|
||||
int offset = 0;
|
||||
ulong read = _bytes.ReadUInt64(ref offset);
|
||||
Assert.Equal((ulong)0x0706050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt64BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
ulong read = _bytes.ReadUInt64BigEndian(ref offset);
|
||||
Assert.Equal((ulong)0x0001020304050607, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDoubleTest()
|
||||
{
|
||||
int offset = 0;
|
||||
double expected = BitConverter.Int64BitsToDouble(0x0706050403020100);
|
||||
double read = _bytes.ReadDouble(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDoubleBigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
double expected = BitConverter.Int64BitsToDouble(0x0001020304050607);
|
||||
double read = _bytes.ReadDoubleBigEndian(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDecimalTest()
|
||||
{
|
||||
int offset = 0;
|
||||
decimal expected = 0.0123456789M;
|
||||
decimal read = _decimalBytes.ReadDecimal(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDecimalBigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
decimal expected = 0.0123456789M;
|
||||
decimal read = _decimalBytes.Reverse().ToArray().ReadDecimalBigEndian(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadGuidTest()
|
||||
{
|
||||
int offset = 0;
|
||||
var expected = new Guid(_bytes);
|
||||
Guid read = _bytes.ReadGuid(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadGuidBigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
var expected = new Guid(_bytes.Reverse().ToArray());
|
||||
Guid read = _bytes.ReadGuidBigEndian(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[Fact]
|
||||
public void ReadInt128Test()
|
||||
{
|
||||
int offset = 0;
|
||||
var expected = (Int128)new BigInteger(_bytes);
|
||||
Int128 read = _bytes.ReadInt128(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt128BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
var reversed = _bytes.Reverse().ToArray();
|
||||
var expected = (Int128)new BigInteger(reversed);
|
||||
Int128 read = _bytes.ReadInt128BigEndian(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt128Test()
|
||||
{
|
||||
int offset = 0;
|
||||
var expected = (UInt128)new BigInteger(_bytes);
|
||||
UInt128 read = _bytes.ReadUInt128(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt128BigEndianTest()
|
||||
{
|
||||
int offset = 0;
|
||||
var reversed = _bytes.Reverse().ToArray();
|
||||
var expected = (UInt128)new BigInteger(reversed);
|
||||
UInt128 read = _bytes.ReadUInt128BigEndian(ref offset);
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeExplicitTest()
|
||||
{
|
||||
byte[] bytesWithString =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x41, 0x42, 0x43, 0x00,
|
||||
];
|
||||
|
||||
int offset = 0;
|
||||
var expected = new TestStructExplicit
|
||||
{
|
||||
FirstValue = TestEnum.RecognizedTestValue,
|
||||
SecondValue = 0x07060504,
|
||||
ThirdValue = 0x0504,
|
||||
FourthValue = 0x0706,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
var read = bytesWithString.ReadType<TestStructExplicit>(ref offset);
|
||||
Assert.Equal(expected.FirstValue, read.FirstValue);
|
||||
Assert.Equal(expected.SecondValue, read.SecondValue);
|
||||
Assert.Equal(expected.ThirdValue, read.ThirdValue);
|
||||
Assert.Equal(expected.FourthValue, read.FourthValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeSequentialTest()
|
||||
{
|
||||
byte[] bytesWithString =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x41, 0x42, 0x43, 0x00,
|
||||
];
|
||||
|
||||
int offset = 0;
|
||||
var expected = new TestStructSequential
|
||||
{
|
||||
FirstValue = TestEnum.RecognizedTestValue,
|
||||
SecondValue = 0x07060504,
|
||||
ThirdValue = 0x0908,
|
||||
FourthValue = 0x0B0A,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
var read = bytesWithString.ReadType<TestStructSequential>(ref offset);
|
||||
Assert.Equal(expected.FirstValue, read.FirstValue);
|
||||
Assert.Equal(expected.SecondValue, read.SecondValue);
|
||||
Assert.Equal(expected.ThirdValue, read.ThirdValue);
|
||||
Assert.Equal(expected.FourthValue, read.FourthValue);
|
||||
Assert.Equal(expected.FifthValue, read.FifthValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeStringsTest()
|
||||
{
|
||||
byte[] structBytes =
|
||||
[
|
||||
0x03, 0x41, 0x42, 0x43, // AnsiBStr
|
||||
0x03, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, // BStr
|
||||
0x41, 0x42, 0x43, // ByValTStr
|
||||
0x41, 0x42, 0x43, 0x00, // LPStr
|
||||
0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00, 0x00, // LPWStr
|
||||
];
|
||||
|
||||
int offset = 0;
|
||||
var expected = new TestStructStrings
|
||||
{
|
||||
AnsiBStr = "ABC",
|
||||
BStr = "ABC",
|
||||
ByValTStr = "ABC",
|
||||
LPStr = "ABC",
|
||||
LPWStr = "ABC",
|
||||
};
|
||||
var read = structBytes.ReadType<TestStructStrings>(ref offset);
|
||||
Assert.Equal(expected.AnsiBStr, read.AnsiBStr);
|
||||
Assert.Equal(expected.BStr, read.BStr);
|
||||
Assert.Equal(expected.ByValTStr, read.ByValTStr);
|
||||
Assert.Equal(expected.LPStr, read.LPStr);
|
||||
Assert.Equal(expected.LPWStr, read.LPWStr);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeArraysTest()
|
||||
{
|
||||
byte[] structBytes =
|
||||
[
|
||||
// Byte Array
|
||||
0x00, 0x01, 0x02, 0x03,
|
||||
|
||||
// Int Array
|
||||
0x03, 0x02, 0x01, 0x00,
|
||||
0x04, 0x03, 0x02, 0x01,
|
||||
0x05, 0x04, 0x03, 0x02,
|
||||
0x06, 0x05, 0x04, 0x03,
|
||||
|
||||
// Struct Array (X, Y)
|
||||
0xFF, 0x00, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0xFF, 0x00,
|
||||
0xAA, 0x55, 0x55, 0xAA,
|
||||
0x55, 0xAA, 0xAA, 0x55,
|
||||
|
||||
// LPArray
|
||||
0x04, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03,
|
||||
];
|
||||
|
||||
int offset = 0;
|
||||
var expected = new TestStructArrays
|
||||
{
|
||||
ByteArray = [0x00, 0x01, 0x02, 0x03],
|
||||
IntArray = [0x00010203, 0x01020304, 0x02030405, 0x03040506],
|
||||
StructArray =
|
||||
[
|
||||
new TestStructPoint { X = 0x00FF, Y = 0xFF00 },
|
||||
new TestStructPoint { X = 0xFF00, Y = 0x00FF },
|
||||
new TestStructPoint { X = 0x55AA, Y = 0xAA55 },
|
||||
new TestStructPoint { X = 0xAA55, Y = 0x55AA },
|
||||
],
|
||||
LPByteArrayLength = 0x0004,
|
||||
LPByteArray = [0x00, 0x01, 0x02, 0x03],
|
||||
};
|
||||
var read = structBytes.ReadType<TestStructArrays>(ref offset);
|
||||
Assert.NotNull(read.ByteArray);
|
||||
Assert.True(expected.ByteArray.SequenceEqual(read.ByteArray));
|
||||
Assert.NotNull(read.IntArray);
|
||||
Assert.True(expected.IntArray.SequenceEqual(read.IntArray));
|
||||
Assert.NotNull(read.StructArray);
|
||||
Assert.True(expected.StructArray.SequenceEqual(read.StructArray));
|
||||
Assert.Equal(expected.LPByteArrayLength, read.LPByteArrayLength);
|
||||
Assert.NotNull(read.LPByteArray);
|
||||
Assert.True(expected.LPByteArray.SequenceEqual(read.LPByteArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeInheritanceTest()
|
||||
{
|
||||
byte[] structBytes1 =
|
||||
[
|
||||
0x41, 0x42, 0x43, 0x44, // Signature
|
||||
0x00, 0xFF, 0x00, 0xFF, // IdentifierType
|
||||
0xAA, 0x55, 0xAA, 0x55, // FieldA
|
||||
0x55, 0xAA, 0x55, 0xAA, // FieldB
|
||||
];
|
||||
|
||||
int offset1 = 0;
|
||||
var expected1 = new TestStructInheritanceChild1
|
||||
{
|
||||
Signature = [0x41, 0x42, 0x43, 0x44],
|
||||
IdentifierType = 0xFF00FF00,
|
||||
FieldA = 0x55AA55AA,
|
||||
FieldB = 0xAA55AA55,
|
||||
};
|
||||
var read1 = structBytes1.ReadType<TestStructInheritanceChild1>(ref offset1);
|
||||
Assert.NotNull(read1?.Signature);
|
||||
Assert.Equal(expected1.Signature, read1.Signature);
|
||||
Assert.Equal(expected1.IdentifierType, read1.IdentifierType);
|
||||
Assert.Equal(expected1.FieldA, read1.FieldA);
|
||||
Assert.Equal(expected1.FieldB, read1.FieldB);
|
||||
|
||||
byte[] structBytes2 =
|
||||
[
|
||||
0x41, 0x42, 0x43, 0x44, // Signature
|
||||
0x00, 0xFF, 0x00, 0xFF, // IdentifierType
|
||||
0xAA, 0x55, // FieldA
|
||||
0x55, 0xAA, // FieldB
|
||||
];
|
||||
|
||||
int offset2 = 0;
|
||||
var expected2 = new TestStructInheritanceChild2
|
||||
{
|
||||
Signature = [0x41, 0x42, 0x43, 0x44],
|
||||
IdentifierType = 0xFF00FF00,
|
||||
FieldA = 0x55AA,
|
||||
FieldB = 0xAA55,
|
||||
};
|
||||
var read2 = structBytes2.ReadType<TestStructInheritanceChild2>(ref offset2);
|
||||
Assert.NotNull(read2?.Signature);
|
||||
Assert.Equal(expected2.Signature, read2.Signature);
|
||||
Assert.Equal(expected2.IdentifierType, read2.IdentifierType);
|
||||
Assert.Equal(expected2.FieldA, read2.FieldA);
|
||||
Assert.Equal(expected2.FieldB, read2.FieldB);
|
||||
}
|
||||
}
|
||||
}
|
||||
977
SabreTools.IO.Test/Extensions/ByteArrayExtensionsTests.cs
Normal file
977
SabreTools.IO.Test/Extensions/ByteArrayExtensionsTests.cs
Normal file
@@ -0,0 +1,977 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class ByteArrayExtensionsTests
|
||||
{
|
||||
#region IsNullOrEmpty
|
||||
|
||||
[Fact]
|
||||
public void IsNullOrEmpty_Null_True()
|
||||
{
|
||||
byte[]? arr = null;
|
||||
bool actual = arr.IsNullOrEmpty();
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsNullOrEmpty_Empty_True()
|
||||
{
|
||||
byte[]? arr = [];
|
||||
bool actual = arr.IsNullOrEmpty();
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsNullOrEmpty_NonEmpty_False()
|
||||
{
|
||||
byte[]? arr = [0x01];
|
||||
bool actual = arr.IsNullOrEmpty();
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#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()
|
||||
{
|
||||
byte[]? arr = null;
|
||||
string? actual = arr.ToHexString();
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToHexString_Valid()
|
||||
{
|
||||
byte[]? arr = [0x01, 0x02, 0x03, 0x04];
|
||||
string expected = "01020304";
|
||||
|
||||
string? actual = arr.ToHexString();
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FromHexString
|
||||
|
||||
[Fact]
|
||||
public void FromHexString_Null()
|
||||
{
|
||||
string? str = null;
|
||||
byte[]? actual = str.FromHexString();
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FromHexString_Valid()
|
||||
{
|
||||
string str = "01020304";
|
||||
byte[]? expected = [0x01, 0x02, 0x03, 0x04];
|
||||
|
||||
byte[]? actual = str.FromHexString();
|
||||
Assert.NotNull(actual);
|
||||
Assert.True(expected.SequenceEqual(actual));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FromHexString_Invalid()
|
||||
{
|
||||
string str = "0102030G";
|
||||
byte[]? actual = str.FromHexString();
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
#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
|
||||
}
|
||||
}
|
||||
2181
SabreTools.IO.Test/Extensions/ByteArrayReaderExtensionsTests.cs
Normal file
2181
SabreTools.IO.Test/Extensions/ByteArrayReaderExtensionsTests.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
// TODO: Add string writing tests
|
||||
public class ByteArrayExtensionsWriteTests
|
||||
public class ByteArrayWriterExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test pattern from 0x00-0x0F
|
||||
@@ -34,51 +32,97 @@ 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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteBytesBigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, [0x03, 0x02, 0x01, 0x00]);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSByteTest()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteCharEncodingTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [0x00, 0x00];
|
||||
bool write = buffer.Write(ref offset, '\0', Encoding.Unicode);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16Test()
|
||||
{
|
||||
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);
|
||||
@@ -89,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);
|
||||
@@ -111,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);
|
||||
@@ -134,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);
|
||||
@@ -157,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);
|
||||
@@ -168,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);
|
||||
@@ -179,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);
|
||||
@@ -190,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);
|
||||
@@ -201,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);
|
||||
@@ -223,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);
|
||||
@@ -245,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);
|
||||
@@ -256,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);
|
||||
@@ -267,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);
|
||||
@@ -278,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);
|
||||
@@ -289,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);
|
||||
@@ -300,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);
|
||||
@@ -311,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);
|
||||
@@ -333,18 +435,52 @@ 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)];
|
||||
bool write = buffer.Write(ref offset, BitConverter.Int64BitsToDouble(0x0706050403020100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDoubleBigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, BitConverter.Int64BitsToDouble(0x0001020304050607));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDecimalTest()
|
||||
{
|
||||
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);
|
||||
@@ -355,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);
|
||||
@@ -366,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);
|
||||
@@ -377,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);
|
||||
@@ -400,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);
|
||||
}
|
||||
@@ -411,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);
|
||||
@@ -422,12 +557,122 @@ 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()
|
||||
{
|
||||
int offset = 0;
|
||||
byte[] buffer = new byte[4];
|
||||
byte[] expected = [0x41, 0x42, 0x43, 0x00];
|
||||
|
||||
bool write = buffer.WriteNullTerminatedAnsiString(ref offset, "ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedUTF8StringTest()
|
||||
{
|
||||
int offset = 0;
|
||||
byte[] buffer = new byte[4];
|
||||
byte[] expected = [0x41, 0x42, 0x43, 0x00];
|
||||
|
||||
bool write = buffer.WriteNullTerminatedUTF8String(ref offset, "ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedUnicodeStringTest()
|
||||
{
|
||||
int offset = 0;
|
||||
byte[] buffer = new byte[8];
|
||||
byte[] expected = [0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00];
|
||||
|
||||
bool write = buffer.WriteNullTerminatedUnicodeString(ref offset, "ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedUTF32StringTest()
|
||||
{
|
||||
int offset = 0;
|
||||
byte[] buffer = new byte[16];
|
||||
byte[] expected = [0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
|
||||
|
||||
bool write = buffer.WriteNullTerminatedUTF32String(ref offset, "ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WritePrefixedAnsiStringTest()
|
||||
{
|
||||
int offset = 0;
|
||||
byte[] buffer = new byte[4];
|
||||
byte[] expected = [0x03, 0x41, 0x42, 0x43];
|
||||
|
||||
bool write = buffer.WritePrefixedAnsiString(ref offset, "ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WritePrefixedUnicodeStringTest()
|
||||
{
|
||||
int offset = 0;
|
||||
byte[] buffer = new byte[8];
|
||||
byte[] expected = [0x03, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00];
|
||||
|
||||
bool write = buffer.WritePrefixedUnicodeString(ref offset, "ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeTest()
|
||||
{
|
||||
// Guid
|
||||
int offset = 0;
|
||||
byte[] buffer = new byte[16];
|
||||
bool actual = buffer.WriteType(ref offset, new Guid(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, buffer);
|
||||
|
||||
// Half
|
||||
offset = 0;
|
||||
buffer = new byte[2];
|
||||
actual = buffer.WriteType(ref offset, BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(2)], buffer);
|
||||
|
||||
// Int128
|
||||
offset = 0;
|
||||
buffer = new byte[16];
|
||||
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(ref offset, (UInt128)new BigInteger(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, buffer);
|
||||
|
||||
// Enum
|
||||
offset = 0;
|
||||
buffer = new byte[4];
|
||||
actual = buffer.WriteType(ref offset, (TestEnum)0x03020100);
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(4)], buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeExplicitTest()
|
||||
@@ -446,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);
|
||||
@@ -471,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);
|
||||
@@ -488,4 +733,4 @@ namespace SabreTools.IO.Test.Extensions
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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,15 +2,34 @@ 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 SafeEnumerateEmptyTest()
|
||||
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()
|
||||
{
|
||||
var source = Enumerable.Empty<string>();
|
||||
var safe = source.SafeEnumerate();
|
||||
@@ -19,7 +38,18 @@ namespace SabreTools.IO.Test.Extensions
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateNoErrorTest()
|
||||
public void SafeEnumerate_Throws()
|
||||
{
|
||||
var source = new List<string> { "a", "ab", "abc" };
|
||||
var wrapper = new ThrowsEnumerable(source);
|
||||
|
||||
var safe = wrapper.SafeEnumerate();
|
||||
var list = safe.ToList();
|
||||
Assert.Empty(list);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerate_NoError()
|
||||
{
|
||||
var source = new List<string> { "a", "ab", "abc" };
|
||||
var safe = source.SafeEnumerate();
|
||||
@@ -28,7 +58,7 @@ namespace SabreTools.IO.Test.Extensions
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateErrorMidTest()
|
||||
public void SafeEnumerate_ErrorMid()
|
||||
{
|
||||
var source = new List<string> { "a", "ab", "abc" };
|
||||
var wrapper = new ErrorEnumerable(source);
|
||||
@@ -39,18 +69,20 @@ namespace SabreTools.IO.Test.Extensions
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateErrorLastTest()
|
||||
public void SafeEnumerate_ErrorLast()
|
||||
{
|
||||
var source = new List<string> { "a", "ab", "abc", "abcd" };
|
||||
var wrapper = new ErrorEnumerable(source);
|
||||
|
||||
|
||||
var safe = wrapper.SafeEnumerate();
|
||||
var list = safe.ToList();
|
||||
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>
|
||||
{
|
||||
@@ -134,5 +166,19 @@ namespace SabreTools.IO.Test.Extensions
|
||||
_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fake enumerable that throws an exception for the enumerator
|
||||
/// </summary>
|
||||
private class ThrowsEnumerable : IEnumerable<string>
|
||||
{
|
||||
public ThrowsEnumerable(IEnumerable<string> source) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<string> GetEnumerator() => throw new Exception();
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
@@ -5,6 +8,116 @@ namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class IOExtensionsTests
|
||||
{
|
||||
#region Ensure
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData("", null)]
|
||||
[InlineData(" ", " ")] // TODO: This is a bad result
|
||||
[InlineData("dirname", "dirname")]
|
||||
[InlineData("\"dirname\"", "dirname")]
|
||||
public void EnsureTest(string? dir, string? expected)
|
||||
{
|
||||
// Handle test setup
|
||||
expected ??= PathTool.GetRuntimeDirectory();
|
||||
if (expected is not null)
|
||||
expected = Path.GetFullPath(expected);
|
||||
|
||||
string actual = dir.Ensure(create: false);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Encoding
|
||||
|
||||
[Fact]
|
||||
public void GetEncoding_EmptyPath()
|
||||
{
|
||||
string path = "";
|
||||
Encoding expected = Encoding.Default;
|
||||
|
||||
var actual = path.GetEncoding();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetEncoding_InvalidPath()
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "INVALID");
|
||||
Encoding expected = Encoding.Default;
|
||||
|
||||
var actual = path.GetEncoding();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
// Disable warning about UTF7 usage
|
||||
#pragma warning disable SYSLIB0001
|
||||
[Fact]
|
||||
public void GetEncoding_UTF7()
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "utf7bom.txt");
|
||||
Encoding expected = Encoding.UTF7;
|
||||
|
||||
var actual = path.GetEncoding();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
#pragma warning restore SYSLIB0001
|
||||
|
||||
[Fact]
|
||||
public void GetEncoding_UTF8()
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "utf8bom.txt");
|
||||
Encoding expected = Encoding.UTF8;
|
||||
|
||||
var actual = path.GetEncoding();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetEncoding_Unicode()
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "utf16lebom.txt");
|
||||
Encoding expected = Encoding.Unicode;
|
||||
|
||||
var actual = path.GetEncoding();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetEncoding_BigEndianUnicode()
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "utf16bebom.txt");
|
||||
Encoding expected = Encoding.BigEndianUnicode;
|
||||
|
||||
var actual = path.GetEncoding();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetEncoding_UTF32()
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "utf32bom.txt");
|
||||
Encoding expected = Encoding.UTF32;
|
||||
|
||||
var actual = path.GetEncoding();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetEncoding_ASCII()
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "TestData", "ascii.txt");
|
||||
Encoding expected = Encoding.Default;
|
||||
|
||||
var actual = path.GetEncoding();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Normalized Extension
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData("", null)]
|
||||
@@ -15,10 +128,185 @@ namespace SabreTools.IO.Test.Extensions
|
||||
[InlineData("NO-EXTENSION.", null)]
|
||||
[InlineData("filename.ext", "ext")]
|
||||
[InlineData("FILENAME.EXT", "ext")]
|
||||
public void NormalizedExtensionTest(string? path, string? expected)
|
||||
public void GetNormalizedExtensionTest(string? path, string? expected)
|
||||
{
|
||||
string? actual = path.GetNormalizedExtension();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Path
|
||||
|
||||
[Fact]
|
||||
public void ListEmpty_NullDirectory()
|
||||
{
|
||||
string? dir = null;
|
||||
var empty = dir.ListEmpty();
|
||||
Assert.Null(empty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ListEmpty_InvalidDirectory()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData", "INVALID");
|
||||
var empty = dir.ListEmpty();
|
||||
Assert.Null(empty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ListEmpty_ValidDirectory()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var empty = dir.ListEmpty();
|
||||
Assert.NotNull(empty);
|
||||
Assert.Empty(empty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeGetDirectories_ValidDirectory()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var dirs = dir.SafeGetDirectories();
|
||||
Assert.Single(dirs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeGetDirectories_ValidDirectory_Pattern()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var dirs = dir.SafeGetDirectories("*");
|
||||
Assert.Single(dirs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeGetDirectories_ValidDirectory_PatternOption()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var dirs = dir.SafeGetDirectories("*", SearchOption.AllDirectories);
|
||||
Assert.Single(dirs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeGetFiles_ValidDirectory()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var files = dir.SafeGetFiles();
|
||||
Assert.NotEmpty(files);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeGetFiles_ValidDirectory_Pattern()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var files = dir.SafeGetFiles("*");
|
||||
Assert.NotEmpty(files);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeGetFiles_ValidDirectory_PatternOption()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var files = dir.SafeGetFiles("*", SearchOption.AllDirectories);
|
||||
Assert.NotEmpty(files);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeGetFileSystemEntries_ValidDirectory()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var entries = dir.SafeGetFileSystemEntries();
|
||||
Assert.NotEmpty(entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeGetFileSystemEntries_ValidDirectory_Pattern()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var entries = dir.SafeGetFileSystemEntries("*");
|
||||
Assert.NotEmpty(entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeGetFileSystemEntries_ValidDirectory_PatternOption()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var entries = dir.SafeGetFileSystemEntries("*", SearchOption.AllDirectories);
|
||||
Assert.NotEmpty(entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateDirectories_ValidDirectory()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var dirs = dir.SafeEnumerateDirectories();
|
||||
Assert.Single(dirs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateDirectories_ValidDirectory_Pattern()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var dirs = dir.SafeEnumerateDirectories("*");
|
||||
Assert.Single(dirs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateDirectories_ValidDirectory_PatternOption()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var dirs = dir.SafeEnumerateDirectories("*", SearchOption.AllDirectories);
|
||||
Assert.Single(dirs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateFiles_ValidDirectory()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var files = dir.SafeEnumerateFiles();
|
||||
Assert.NotEmpty(files);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateFiles_ValidDirectory_Pattern()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var files = dir.SafeEnumerateFiles("*");
|
||||
Assert.NotEmpty(files);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateFiles_ValidDirectory_PatternOption()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var files = dir.SafeEnumerateFiles("*", SearchOption.AllDirectories);
|
||||
Assert.NotEmpty(files);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateFileSystemEntries_ValidDirectory()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var entries = dir.SafeEnumerateFileSystemEntries();
|
||||
Assert.NotEmpty(entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateFileSystemEntries_ValidDirectory_Pattern()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var entries = dir.SafeEnumerateFileSystemEntries("*");
|
||||
Assert.NotEmpty(entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerateFileSystemEntries_ValidDirectory_PatternOption()
|
||||
{
|
||||
string dir = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
var entries = dir.SafeEnumerateFileSystemEntries("*", SearchOption.AllDirectories);
|
||||
Assert.NotEmpty(entries);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,541 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#if NET7_0_OR_GREATER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
// TODO: Add string reading tests
|
||||
public class StreamExtensionsReadTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test pattern from 0x00-0x0F
|
||||
/// </summary>
|
||||
private static readonly byte[] _bytes =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Represents the decimal value 0.0123456789
|
||||
/// </summary>
|
||||
private static readonly byte[] _decimalBytes =
|
||||
[
|
||||
0x15, 0xCD, 0x5B, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void ReadByteValueTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
byte read = stream.ReadByteValue();
|
||||
Assert.Equal(0x00, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadBytesTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
int length = 4;
|
||||
byte[] read = stream.ReadBytes(length);
|
||||
Assert.Equal(length, read.Length);
|
||||
Assert.True(read.SequenceEqual(_bytes.Take(length)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadSByteTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
sbyte read = stream.ReadSByte();
|
||||
Assert.Equal(0x00, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadCharTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
char read = stream.ReadChar();
|
||||
Assert.Equal('\0', read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt16Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
short read = stream.ReadInt16();
|
||||
Assert.Equal(0x0100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
short read = stream.ReadInt16BigEndian();
|
||||
Assert.Equal(0x0001, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt16Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
ushort read = stream.ReadUInt16();
|
||||
Assert.Equal(0x0100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
ushort read = stream.ReadUInt16BigEndian();
|
||||
Assert.Equal(0x0001, read);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
[Fact]
|
||||
public void ReadHalfTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
Half expected = BitConverter.Int16BitsToHalf(0x0100);
|
||||
Half read = stream.ReadHalf();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadHalfBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
Half expected = BitConverter.Int16BitsToHalf(0x0001);
|
||||
Half read = stream.ReadHalfBigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void ReadInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
int read = stream.ReadInt24();
|
||||
Assert.Equal(0x020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
int read = stream.ReadInt24BigEndian();
|
||||
Assert.Equal(0x000102, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
uint read = stream.ReadUInt24();
|
||||
Assert.Equal((uint)0x020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
uint read = stream.ReadUInt24BigEndian();
|
||||
Assert.Equal((uint)0x000102, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt32Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
int read = stream.ReadInt32();
|
||||
Assert.Equal(0x03020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
int read = stream.ReadInt32BigEndian();
|
||||
Assert.Equal(0x00010203, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt32Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
uint read = stream.ReadUInt32();
|
||||
Assert.Equal((uint)0x03020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
uint read = stream.ReadUInt32BigEndian();
|
||||
Assert.Equal((uint)0x00010203, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadSingleTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
float expected = BitConverter.Int32BitsToSingle(0x03020100);
|
||||
float read = stream.ReadSingle();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadSingleBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
float expected = BitConverter.Int32BitsToSingle(0x00010203);
|
||||
float read = stream.ReadSingleBigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
long read = stream.ReadInt48();
|
||||
Assert.Equal(0x050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
long read = stream.ReadInt48BigEndian();
|
||||
Assert.Equal(0x000102030405, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
ulong read = stream.ReadUInt48();
|
||||
Assert.Equal((ulong)0x050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
ulong read = stream.ReadUInt48BigEndian();
|
||||
Assert.Equal((ulong)0x000102030405, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt64Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
long read = stream.ReadInt64();
|
||||
Assert.Equal(0x0706050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
long read = stream.ReadInt64BigEndian();
|
||||
Assert.Equal(0x0001020304050607, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt64Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
ulong read = stream.ReadUInt64();
|
||||
Assert.Equal((ulong)0x0706050403020100, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
ulong read = stream.ReadUInt64BigEndian();
|
||||
Assert.Equal((ulong)0x0001020304050607, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDoubleTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
double expected = BitConverter.Int64BitsToDouble(0x0706050403020100);
|
||||
double read = stream.ReadDouble();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDoubleBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
double expected = BitConverter.Int64BitsToDouble(0x0001020304050607);
|
||||
double read = stream.ReadDoubleBigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDecimalTest()
|
||||
{
|
||||
var stream = new MemoryStream(_decimalBytes);
|
||||
decimal expected = 0.0123456789M;
|
||||
decimal read = stream.ReadDecimal();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadDecimalBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_decimalBytes.Reverse().ToArray());
|
||||
decimal expected = 0.0123456789M;
|
||||
decimal read = stream.ReadDecimalBigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadGuidTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var expected = new Guid(_bytes);
|
||||
Guid read = stream.ReadGuid();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadGuidBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var expected = new Guid(_bytes.Reverse().ToArray());
|
||||
Guid read = stream.ReadGuidBigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
[Fact]
|
||||
public void ReadInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var expected = (Int128)new BigInteger(_bytes);
|
||||
Int128 read = stream.ReadInt128();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var reversed = _bytes.Reverse().ToArray();
|
||||
var expected = (Int128)new BigInteger(reversed);
|
||||
Int128 read = stream.ReadInt128BigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var expected = (UInt128)new BigInteger(_bytes);
|
||||
UInt128 read = stream.ReadUInt128();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(_bytes);
|
||||
var reversed = _bytes.Reverse().ToArray();
|
||||
var expected = (UInt128)new BigInteger(reversed);
|
||||
UInt128 read = stream.ReadUInt128BigEndian();
|
||||
Assert.Equal(expected, read);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeExplicitTest()
|
||||
{
|
||||
byte[] bytesWithString =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x41, 0x42, 0x43, 0x00,
|
||||
];
|
||||
|
||||
var stream = new MemoryStream(bytesWithString);
|
||||
var expected = new TestStructExplicit
|
||||
{
|
||||
FirstValue = TestEnum.RecognizedTestValue,
|
||||
SecondValue = 0x07060504,
|
||||
ThirdValue = 0x0504,
|
||||
FourthValue = 0x0706,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
var read = stream.ReadType<TestStructExplicit>();
|
||||
Assert.Equal(expected.FirstValue, read.FirstValue);
|
||||
Assert.Equal(expected.SecondValue, read.SecondValue);
|
||||
Assert.Equal(expected.ThirdValue, read.ThirdValue);
|
||||
Assert.Equal(expected.FourthValue, read.FourthValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeSequentialTest()
|
||||
{
|
||||
byte[] bytesWithString =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x41, 0x42, 0x43, 0x00,
|
||||
];
|
||||
|
||||
var stream = new MemoryStream(bytesWithString);
|
||||
var expected = new TestStructSequential
|
||||
{
|
||||
FirstValue = TestEnum.RecognizedTestValue,
|
||||
SecondValue = 0x07060504,
|
||||
ThirdValue = 0x0908,
|
||||
FourthValue = 0x0B0A,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
var read = stream.ReadType<TestStructSequential>();
|
||||
Assert.Equal(expected.FirstValue, read.FirstValue);
|
||||
Assert.Equal(expected.SecondValue, read.SecondValue);
|
||||
Assert.Equal(expected.ThirdValue, read.ThirdValue);
|
||||
Assert.Equal(expected.FourthValue, read.FourthValue);
|
||||
Assert.Equal(expected.FifthValue, read.FifthValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeStringsTest()
|
||||
{
|
||||
byte[] structBytes =
|
||||
[
|
||||
0x03, 0x41, 0x42, 0x43, // AnsiBStr
|
||||
0x03, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, // BStr
|
||||
0x41, 0x42, 0x43, // ByValTStr
|
||||
0x41, 0x42, 0x43, 0x00, // LPStr
|
||||
0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00, 0x00, // LPWStr
|
||||
];
|
||||
|
||||
var stream = new MemoryStream(structBytes);
|
||||
var expected = new TestStructStrings
|
||||
{
|
||||
AnsiBStr = "ABC",
|
||||
BStr = "ABC",
|
||||
ByValTStr = "ABC",
|
||||
LPStr = "ABC",
|
||||
LPWStr = "ABC",
|
||||
};
|
||||
var read = stream.ReadType<TestStructStrings>();
|
||||
Assert.Equal(expected.AnsiBStr, read.AnsiBStr);
|
||||
Assert.Equal(expected.BStr, read.BStr);
|
||||
Assert.Equal(expected.ByValTStr, read.ByValTStr);
|
||||
Assert.Equal(expected.LPStr, read.LPStr);
|
||||
Assert.Equal(expected.LPWStr, read.LPWStr);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeArraysTest()
|
||||
{
|
||||
byte[] structBytes =
|
||||
[
|
||||
// Byte Array
|
||||
0x00, 0x01, 0x02, 0x03,
|
||||
|
||||
// Int Array
|
||||
0x03, 0x02, 0x01, 0x00,
|
||||
0x04, 0x03, 0x02, 0x01,
|
||||
0x05, 0x04, 0x03, 0x02,
|
||||
0x06, 0x05, 0x04, 0x03,
|
||||
|
||||
// Struct Array (X, Y)
|
||||
0xFF, 0x00, 0x00, 0xFF,
|
||||
0x00, 0xFF, 0xFF, 0x00,
|
||||
0xAA, 0x55, 0x55, 0xAA,
|
||||
0x55, 0xAA, 0xAA, 0x55,
|
||||
|
||||
// LPArray
|
||||
0x04, 0x00,
|
||||
0x00, 0x01, 0x02, 0x03,
|
||||
];
|
||||
|
||||
var stream = new MemoryStream(structBytes);
|
||||
var expected = new TestStructArrays
|
||||
{
|
||||
ByteArray = [0x00, 0x01, 0x02, 0x03],
|
||||
IntArray = [0x00010203, 0x01020304, 0x02030405, 0x03040506],
|
||||
StructArray =
|
||||
[
|
||||
new TestStructPoint { X = 0x00FF, Y = 0xFF00 },
|
||||
new TestStructPoint { X = 0xFF00, Y = 0x00FF },
|
||||
new TestStructPoint { X = 0x55AA, Y = 0xAA55 },
|
||||
new TestStructPoint { X = 0xAA55, Y = 0x55AA },
|
||||
],
|
||||
LPByteArrayLength = 0x0004,
|
||||
LPByteArray = [0x00, 0x01, 0x02, 0x03],
|
||||
};
|
||||
var read = stream.ReadType<TestStructArrays>();
|
||||
Assert.NotNull(read.ByteArray);
|
||||
Assert.True(expected.ByteArray.SequenceEqual(read.ByteArray));
|
||||
Assert.NotNull(read.IntArray);
|
||||
Assert.True(expected.IntArray.SequenceEqual(read.IntArray));
|
||||
Assert.NotNull(read.StructArray);
|
||||
Assert.True(expected.StructArray.SequenceEqual(read.StructArray));
|
||||
Assert.Equal(expected.LPByteArrayLength, read.LPByteArrayLength);
|
||||
Assert.NotNull(read.LPByteArray);
|
||||
Assert.True(expected.LPByteArray.SequenceEqual(read.LPByteArray));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadTypeInheritanceTest()
|
||||
{
|
||||
byte[] structBytes1 =
|
||||
[
|
||||
0x41, 0x42, 0x43, 0x44, // Signature
|
||||
0x00, 0xFF, 0x00, 0xFF, // IdentifierType
|
||||
0xAA, 0x55, 0xAA, 0x55, // FieldA
|
||||
0x55, 0xAA, 0x55, 0xAA, // FieldB
|
||||
];
|
||||
|
||||
var stream1 = new MemoryStream(structBytes1);
|
||||
var expected1 = new TestStructInheritanceChild1
|
||||
{
|
||||
Signature = [0x41, 0x42, 0x43, 0x44],
|
||||
IdentifierType = 0xFF00FF00,
|
||||
FieldA = 0x55AA55AA,
|
||||
FieldB = 0xAA55AA55,
|
||||
};
|
||||
var read1 = stream1.ReadType<TestStructInheritanceChild1>();
|
||||
Assert.NotNull(read1?.Signature);
|
||||
Assert.Equal(expected1.Signature, read1.Signature);
|
||||
Assert.Equal(expected1.IdentifierType, read1.IdentifierType);
|
||||
Assert.Equal(expected1.FieldA, read1.FieldA);
|
||||
Assert.Equal(expected1.FieldB, read1.FieldB);
|
||||
|
||||
byte[] structBytes2 =
|
||||
[
|
||||
0x41, 0x42, 0x43, 0x44, // Signature
|
||||
0x00, 0xFF, 0x00, 0xFF, // IdentifierType
|
||||
0xAA, 0x55, // FieldA
|
||||
0x55, 0xAA, // FieldB
|
||||
];
|
||||
|
||||
var stream2 = new MemoryStream(structBytes2);
|
||||
var expected2 = new TestStructInheritanceChild2
|
||||
{
|
||||
Signature = [0x41, 0x42, 0x43, 0x44],
|
||||
IdentifierType = 0xFF00FF00,
|
||||
FieldA = 0x55AA,
|
||||
FieldB = 0xAA55,
|
||||
};
|
||||
var read2 = stream2.ReadType<TestStructInheritanceChild2>();
|
||||
Assert.NotNull(read2?.Signature);
|
||||
Assert.Equal(expected2.Signature, read2.Signature);
|
||||
Assert.Equal(expected2.IdentifierType, read2.IdentifierType);
|
||||
Assert.Equal(expected2.FieldA, read2.FieldA);
|
||||
Assert.Equal(expected2.FieldB, read2.FieldB);
|
||||
}
|
||||
}
|
||||
}
|
||||
528
SabreTools.IO.Test/Extensions/StreamExtensionsTests.cs
Normal file
528
SabreTools.IO.Test/Extensions/StreamExtensionsTests.cs
Normal file
@@ -0,0 +1,528 @@
|
||||
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 AlignToBoundary
|
||||
|
||||
[Fact]
|
||||
public void AlignToBoundary_Null_False()
|
||||
{
|
||||
Stream? stream = null;
|
||||
byte alignment = 4;
|
||||
bool actual = stream.AlignToBoundary(alignment);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AlignToBoundary_Empty_False()
|
||||
{
|
||||
Stream? stream = new MemoryStream([]);
|
||||
byte alignment = 4;
|
||||
bool actual = stream.AlignToBoundary(alignment);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AlignToBoundary_EOF_False()
|
||||
{
|
||||
Stream? stream = new MemoryStream([0x01, 0x02]);
|
||||
byte alignment = 4;
|
||||
|
||||
stream.Position = 1;
|
||||
bool actual = stream.AlignToBoundary(alignment);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AlignToBoundary_TooShort_False()
|
||||
{
|
||||
Stream? stream = new MemoryStream([0x01, 0x02]);
|
||||
byte alignment = 4;
|
||||
|
||||
stream.Position = 1;
|
||||
bool actual = stream.AlignToBoundary(alignment);
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AlignToBoundary_CanAlign_True()
|
||||
{
|
||||
Stream? stream = new MemoryStream([0x01, 0x02, 0x03, 0x04, 0x05]);
|
||||
byte alignment = 4;
|
||||
|
||||
stream.Position = 1;
|
||||
bool actual = stream.AlignToBoundary(alignment);
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#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()
|
||||
{
|
||||
var stream = new NonSeekableStream();
|
||||
long actual = stream.SeekIfPossible(0);
|
||||
Assert.Equal(8, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SeekIfPossible_NonPositionable_InvalidPosition()
|
||||
{
|
||||
var stream = new NonPositionableStream();
|
||||
long actual = stream.SeekIfPossible(0);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SeekIfPossible_HiddenNonSeekable_InvalidPosition()
|
||||
{
|
||||
var stream = new HiddenNonSeekableStream();
|
||||
long actual = stream.SeekIfPossible(0);
|
||||
Assert.Equal(-1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SeekIfPossible_NonNegative_ValidPosition()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, false, true);
|
||||
long actual = stream.SeekIfPossible(5);
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SeekIfPossible_Negative_ValidPosition()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, false, true);
|
||||
long actual = stream.SeekIfPossible(-3);
|
||||
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>
|
||||
/// Represents a hidden non-seekable stream
|
||||
/// </summary>
|
||||
private class HiddenNonSeekableStream : Stream
|
||||
{
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => true;
|
||||
|
||||
public override bool CanWrite => true;
|
||||
|
||||
public override long Length => 16;
|
||||
|
||||
public override long Position { get => 8; set => throw new NotSupportedException(); }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a non-seekable stream
|
||||
/// </summary>
|
||||
private class NonSeekableStream : Stream
|
||||
{
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => true;
|
||||
|
||||
public override long Length => 16;
|
||||
|
||||
public override long Position { get => 8; set => throw new NotSupportedException(); }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a non-seekable, non-positionable stream
|
||||
/// </summary>
|
||||
private class NonPositionableStream : Stream
|
||||
{
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => true;
|
||||
|
||||
public override long Length => 16;
|
||||
|
||||
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2169
SabreTools.IO.Test/Extensions/StreamReaderExtensionsTests.cs
Normal file
2169
SabreTools.IO.Test/Extensions/StreamReaderExtensionsTests.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,14 @@
|
||||
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;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
// TODO: Add string writing tests
|
||||
public class StreamExtensionsWriteTests
|
||||
public class StreamWriterExtensionsTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test pattern from 0x00-0x0F
|
||||
@@ -34,47 +32,87 @@ 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());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteBytesBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
stream.WriteBigEndian([0x03, 0x02, 0x01, 0x00]);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
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());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteCharEncodingTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [0x00, 0x00];
|
||||
stream.Write('\0', Encoding.Unicode);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
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());
|
||||
@@ -84,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());
|
||||
@@ -104,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());
|
||||
@@ -125,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());
|
||||
@@ -146,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());
|
||||
@@ -156,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());
|
||||
@@ -166,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());
|
||||
@@ -176,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());
|
||||
@@ -186,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());
|
||||
@@ -206,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());
|
||||
@@ -226,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());
|
||||
@@ -236,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());
|
||||
@@ -246,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());
|
||||
@@ -256,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());
|
||||
@@ -266,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());
|
||||
@@ -276,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());
|
||||
@@ -286,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());
|
||||
@@ -306,17 +397,48 @@ 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)];
|
||||
bool write = stream.Write(BitConverter.Int64BitsToDouble(0x0706050403020100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDoubleBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = stream.WriteBigEndian(BitConverter.Int64BitsToDouble(0x0001020304050607));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
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());
|
||||
@@ -326,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());
|
||||
@@ -336,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());
|
||||
@@ -346,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());
|
||||
@@ -367,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());
|
||||
}
|
||||
@@ -377,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());
|
||||
@@ -387,12 +508,111 @@ 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()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[4], 0, 4, true, true);
|
||||
byte[] expected = [0x41, 0x42, 0x43, 0x00];
|
||||
|
||||
bool write = stream.WriteNullTerminatedAnsiString("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedUTF8StringTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[4], 0, 4, true, true);
|
||||
byte[] expected = [0x41, 0x42, 0x43, 0x00];
|
||||
|
||||
bool write = stream.WriteNullTerminatedUTF8String("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedUnicodeStringTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[8], 0, 8, true, true);
|
||||
byte[] expected = [0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x00];
|
||||
|
||||
bool write = stream.WriteNullTerminatedUnicodeString("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteNullTerminatedUTF32StringTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
|
||||
|
||||
bool write = stream.WriteNullTerminatedUTF32String("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WritePrefixedAnsiStringTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[4], 0, 4, true, true);
|
||||
byte[] expected = [0x03, 0x41, 0x42, 0x43];
|
||||
|
||||
bool write = stream.WritePrefixedAnsiString("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WritePrefixedUnicodeStringTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[8], 0, 8, true, true);
|
||||
byte[] expected = [0x03, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00];
|
||||
|
||||
bool write = stream.WritePrefixedUnicodeString("ABC");
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeTest()
|
||||
{
|
||||
// Guid
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
bool actual = stream.WriteType(new Guid(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, stream.GetBuffer());
|
||||
|
||||
// Half
|
||||
stream = new MemoryStream(new byte[2], 0, 2, true, true);
|
||||
actual = stream.WriteType(BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(2)], stream.GetBuffer());
|
||||
|
||||
// Int128
|
||||
stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
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)new BigInteger(_bytes));
|
||||
Assert.True(actual);
|
||||
ValidateBytes(_bytes, stream.GetBuffer());
|
||||
|
||||
// Enum
|
||||
stream = new MemoryStream(new byte[4], 0, 4, true, true);
|
||||
actual = stream.WriteType((TestEnum)0x03020100);
|
||||
Assert.True(actual);
|
||||
ValidateBytes([.. _bytes.Take(4)], stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeExplicitTest()
|
||||
@@ -410,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());
|
||||
@@ -434,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());
|
||||
@@ -451,4 +671,4 @@ namespace SabreTools.IO.Test.Extensions
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -5,5 +5,5 @@ namespace SabreTools.IO.Test.Extensions
|
||||
None = 0x00000000,
|
||||
RecognizedTestValue = 0x03020100,
|
||||
UpperBoundaryValue = 0xFFFFFFFF,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,12 @@ namespace SabreTools.IO.Test.Extensions
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public int[]? IntArray;
|
||||
|
||||
/// <summary>
|
||||
/// 4 entry int array
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public TestEnum[]? EnumArray;
|
||||
|
||||
/// <summary>
|
||||
/// 4 entry struct array
|
||||
/// </summary>
|
||||
@@ -24,16 +30,16 @@ namespace SabreTools.IO.Test.Extensions
|
||||
public TestStructPoint[]? StructArray;
|
||||
|
||||
/// <summary>
|
||||
/// Length of <see cref="LPByteArray"/>
|
||||
/// Length of <see cref="LPByteArray"/>
|
||||
/// </summary>
|
||||
public ushort LPByteArrayLength;
|
||||
|
||||
/// <summary>
|
||||
/// 4 entry byte array whose length is defined by <see cref="LPByteArrayLength"/>
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]
|
||||
[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)]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable CS0618 // Obsolete unmanaged types
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
|
||||
242
SabreTools.IO.Test/Extensions/XmlTextWriterExtensionsTests.cs
Normal file
242
SabreTools.IO.Test/Extensions/XmlTextWriterExtensionsTests.cs
Normal file
@@ -0,0 +1,242 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class XmlTextWriterExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void WriteRequiredAttributeString_NullInputThrow_Throws()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><element />";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("element");
|
||||
Assert.Throws<ArgumentNullException>(()
|
||||
=> writer.WriteRequiredAttributeString("attr", null, throwOnError: true));
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(52, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteRequiredAttributeString_NullInputNoThrow_Writes()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><element attr=\"\" />";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("element");
|
||||
writer.WriteRequiredAttributeString("attr", null, throwOnError: false);
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(60, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteRequiredAttributeString_ValidInput_Writes()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><element attr=\"val\" />";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("element");
|
||||
writer.WriteRequiredAttributeString("attr", "val", throwOnError: false);
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(63, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteRequiredElementString_NullInputThrow_Throws()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
Assert.Throws<ArgumentNullException>(()
|
||||
=> writer.WriteRequiredElementString("element", null, throwOnError: true));
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(41, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteRequiredElementString_NullInputNoThrow_Writes()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><element></element>";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteRequiredElementString("element", null, throwOnError: false);
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(60, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteRequiredElementString_ValidInput_Writes()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><element>val</element>";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteRequiredElementString("element", "val", throwOnError: false);
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(63, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteOptionalAttributeString_NullInput_NoWrite()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><element />";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("element");
|
||||
writer.WriteOptionalAttributeString("attr", null);
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(52, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteOptionalAttributeString_EmptyInput_NoWrite()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><element />";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("element");
|
||||
writer.WriteOptionalAttributeString("attr", string.Empty);
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(52, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteOptionalAttributeString_ValidInput_Writes()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><element attr=\"val\" />";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteStartElement("element");
|
||||
writer.WriteOptionalAttributeString("attr", "val");
|
||||
writer.WriteEndElement();
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(63, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteOptionalElementString_NullInput_NoWrite()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteOptionalElementString("element", null);
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(41, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteOptionalElementString_EmptyInput_NoWrite()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteOptionalElementString("element", string.Empty);
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(41, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteOptionalElementString_ValidInput_Writes()
|
||||
{
|
||||
string expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><element>val</element>";
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var writer = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteStartDocument();
|
||||
writer.WriteOptionalElementString("element", "val");
|
||||
writer.Flush();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(63, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
67
SabreTools.IO.Test/IniFileTests.cs
Normal file
67
SabreTools.IO.Test/IniFileTests.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test
|
||||
{
|
||||
public class IniFileTests
|
||||
{
|
||||
[Fact]
|
||||
public void EndToEndTest()
|
||||
{
|
||||
string expected = "[section1]\nkey1=value1\nkey2=value2\n";
|
||||
|
||||
// Build the INI
|
||||
var iniFile = new IniFile();
|
||||
iniFile.AddOrUpdate("section1.key1", "value1");
|
||||
iniFile["section1.key2"] = "value2";
|
||||
iniFile["section2.key3"] = "REMOVEME";
|
||||
bool removed = iniFile.Remove("section2.key3");
|
||||
|
||||
Assert.True(removed);
|
||||
Assert.Equal("value1", iniFile["section1.key1"]);
|
||||
Assert.Equal("value2", iniFile["section1.key2"]);
|
||||
|
||||
// Write the INI
|
||||
var stream = new MemoryStream();
|
||||
bool write = iniFile.Write(stream);
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.True(write);
|
||||
Assert.Equal(38, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
|
||||
// Parse the INI
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
var secondIni = new IniFile(stream);
|
||||
Assert.Equal("value1", secondIni["section1.key1"]);
|
||||
Assert.Equal("value2", secondIni["section1.key2"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveInvalidKeyTest()
|
||||
{
|
||||
var iniFile = new IniFile();
|
||||
bool removed = iniFile.Remove("invalid.key");
|
||||
Assert.False(removed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadEmptyStreamTest()
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var iniFile = new IniFile(stream);
|
||||
Assert.Empty(iniFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteEmptyIniFileTest()
|
||||
{
|
||||
var iniFile = new IniFile();
|
||||
var stream = new MemoryStream();
|
||||
bool write = iniFile.Write(stream);
|
||||
Assert.False(write);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
SabreTools.IO.Test/Logging/ConvertersTests.cs
Normal file
38
SabreTools.IO.Test/Logging/ConvertersTests.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using SabreTools.IO.Logging;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Logging
|
||||
{
|
||||
public class ConvertersTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null, LogLevel.VERBOSE)]
|
||||
[InlineData("", LogLevel.VERBOSE)]
|
||||
[InlineData("INVALID", LogLevel.VERBOSE)]
|
||||
[InlineData("verbose", LogLevel.VERBOSE)]
|
||||
[InlineData("VERBOSE", LogLevel.VERBOSE)]
|
||||
[InlineData("user", LogLevel.USER)]
|
||||
[InlineData("USER", LogLevel.USER)]
|
||||
[InlineData("warning", LogLevel.WARNING)]
|
||||
[InlineData("WARNING", LogLevel.WARNING)]
|
||||
[InlineData("error", LogLevel.ERROR)]
|
||||
[InlineData("ERROR", LogLevel.ERROR)]
|
||||
public void AsLogLevelTest(string? level, LogLevel expected)
|
||||
{
|
||||
LogLevel actual = level.AsLogLevel();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(LogLevel.VERBOSE, "VERBOSE")]
|
||||
[InlineData(LogLevel.USER, "USER")]
|
||||
[InlineData(LogLevel.WARNING, "WARNING")]
|
||||
[InlineData(LogLevel.ERROR, "ERROR")]
|
||||
[InlineData((LogLevel)99, null)]
|
||||
public void FromLogLevelTest(LogLevel level, string? expected)
|
||||
{
|
||||
string? actual = level.FromLogLevel();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
SabreTools.IO.Test/Logging/InternalStopwatchTests.cs
Normal file
40
SabreTools.IO.Test/Logging/InternalStopwatchTests.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using SabreTools.IO.Logging;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Logging
|
||||
{
|
||||
public class InternalStopwatchTests
|
||||
{
|
||||
[Fact]
|
||||
public void Stopwatch_NoSubject_StartNoSubject()
|
||||
{
|
||||
var stopwatch = new InternalStopwatch();
|
||||
stopwatch.Start();
|
||||
stopwatch.Stop();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Stopwatch_NoSubject_StartSubject()
|
||||
{
|
||||
var stopwatch = new InternalStopwatch();
|
||||
stopwatch.Start("start");
|
||||
stopwatch.Stop();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Stopwatch_Subject_StartNoSubject()
|
||||
{
|
||||
var stopwatch = new InternalStopwatch("init");
|
||||
stopwatch.Start();
|
||||
stopwatch.Stop();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Stopwatch_Subject_StartSubject()
|
||||
{
|
||||
var stopwatch = new InternalStopwatch("init");
|
||||
stopwatch.Start("start");
|
||||
stopwatch.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
54
SabreTools.IO.Test/Logging/LoggerTests.cs
Normal file
54
SabreTools.IO.Test/Logging/LoggerTests.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using SabreTools.IO.Logging;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Logging
|
||||
{
|
||||
public class LoggerTests
|
||||
{
|
||||
[Fact]
|
||||
public void EndToEnd()
|
||||
{
|
||||
Assert.Null(LoggerImpl.Filename);
|
||||
Assert.False(LoggerImpl.LogToFile);
|
||||
Assert.Null(LoggerImpl.LogDirectory);
|
||||
Assert.True(LoggerImpl.AppendPrefix);
|
||||
Assert.False(LoggerImpl.ThrowOnError);
|
||||
|
||||
LoggerImpl.Start();
|
||||
|
||||
var logger = new Logger();
|
||||
|
||||
logger.Verbose("verbose");
|
||||
logger.Verbose(new Exception());
|
||||
logger.Verbose(new Exception(), "verbose");
|
||||
logger.Verbose(1, 1, "verbose");
|
||||
|
||||
logger.User("user");
|
||||
logger.User(new Exception());
|
||||
logger.User(new Exception(), "user");
|
||||
logger.User(1, 1, "user");
|
||||
|
||||
logger.Warning("warning");
|
||||
logger.Warning(new Exception());
|
||||
logger.Warning(new Exception(), "warning");
|
||||
logger.Warning(1, 1, "warning");
|
||||
|
||||
logger.Error("error");
|
||||
logger.Error(new Exception());
|
||||
logger.Error(new Exception(), "error");
|
||||
logger.Error(1, 1, "error");
|
||||
|
||||
LoggerImpl.ThrowOnError = true;
|
||||
Assert.Throws<Exception>(() => logger.Error(new Exception()));
|
||||
|
||||
Assert.True(LoggerImpl.StartTime < DateTime.Now);
|
||||
Assert.True(LoggerImpl.LoggedWarnings);
|
||||
Assert.True(LoggerImpl.LoggedErrors);
|
||||
|
||||
LoggerImpl.SetFilename("logfile.txt", addDate: true);
|
||||
|
||||
LoggerImpl.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,4 +84,4 @@ namespace SabreTools.IO.Test
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
121
SabreTools.IO.Test/PathToolTests.cs
Normal file
121
SabreTools.IO.Test/PathToolTests.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test
|
||||
{
|
||||
public class PathToolTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetDirectoriesOnly_NoAppendParent()
|
||||
{
|
||||
string expectedParent = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
string expectedCurrent = Path.Combine(expectedParent, "Subdirectory");
|
||||
|
||||
List<string> inputs =
|
||||
[
|
||||
string.Empty,
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData"),
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData", "Subdir*"),
|
||||
];
|
||||
var actual = PathTool.GetDirectoriesOnly(inputs, appendParent: true);
|
||||
Assert.NotEmpty(actual);
|
||||
|
||||
var first = actual[0];
|
||||
Assert.Equal(expectedCurrent, first.CurrentPath);
|
||||
Assert.Equal(expectedParent, first.ParentPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDirectoriesOnly_AppendParent()
|
||||
{
|
||||
string expectedParent = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
string expectedCurrent = Path.Combine(expectedParent, "Subdirectory");
|
||||
|
||||
List<string> inputs =
|
||||
[
|
||||
string.Empty,
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData"),
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData", "Subdir*"),
|
||||
];
|
||||
var actual = PathTool.GetDirectoriesOnly(inputs, appendParent: false);
|
||||
Assert.NotEmpty(actual);
|
||||
|
||||
var first = actual[0];
|
||||
Assert.Equal(expectedCurrent, first.CurrentPath);
|
||||
Assert.Equal(string.Empty, first.ParentPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFilesOnly_NoAppendParent()
|
||||
{
|
||||
string expectedParent = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
string expectedCurrent = Path.Combine(expectedParent, "ascii.txt");
|
||||
|
||||
List<string> inputs =
|
||||
[
|
||||
string.Empty,
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData"),
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData", "Subdir*"),
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData", "utf8bom.txt"),
|
||||
];
|
||||
var actual = PathTool.GetFilesOnly(inputs, appendParent: true);
|
||||
Assert.NotEmpty(actual);
|
||||
|
||||
var first = actual[0];
|
||||
Assert.Equal(expectedCurrent, first.CurrentPath);
|
||||
Assert.Equal(expectedParent, first.ParentPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFilesOnly_AppendParent()
|
||||
{
|
||||
string expectedParent = Path.Combine(Environment.CurrentDirectory, "TestData");
|
||||
string expectedCurrent = Path.Combine(expectedParent, "ascii.txt");
|
||||
|
||||
List<string> inputs =
|
||||
[
|
||||
string.Empty,
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData"),
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData", "Subdir*"),
|
||||
Path.Combine(Environment.CurrentDirectory, "TestData", "utf8bom.txt"),
|
||||
];
|
||||
var actual = PathTool.GetFilesOnly(inputs, appendParent: false);
|
||||
Assert.NotEmpty(actual);
|
||||
|
||||
var first = actual[0];
|
||||
Assert.Equal(expectedCurrent, first.CurrentPath);
|
||||
Assert.Equal(string.Empty, first.ParentPath);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, false, "")]
|
||||
[InlineData(null, true, "")]
|
||||
[InlineData("", false, "")]
|
||||
[InlineData("", true, "")]
|
||||
[InlineData("filename.bin", false, "filename.bin")]
|
||||
[InlineData("filename.bin", true, "filename.bin")]
|
||||
[InlineData("\"filename.bin\"", false, "filename.bin")]
|
||||
[InlineData("\"filename.bin\"", true, "filename.bin")]
|
||||
[InlineData("<filename.bin>", false, "filename.bin")]
|
||||
[InlineData("<filename.bin>", true, "filename.bin")]
|
||||
[InlineData("1.2.3.4..bin", false, "1.2.3.4..bin")]
|
||||
[InlineData("1.2.3.4..bin", true, "1.2.3.4..bin")]
|
||||
[InlineData("dir/filename.bin", false, "dir/filename.bin")]
|
||||
[InlineData("dir/filename.bin", true, "dir/filename.bin")]
|
||||
[InlineData(" dir / filename.bin", false, "dir/filename.bin")]
|
||||
[InlineData(" dir / filename.bin", true, "dir/filename.bin")]
|
||||
[InlineData("\0dir/\0filename.bin", false, "_dir/_filename.bin")]
|
||||
[InlineData("\0dir/\0filename.bin", true, "_dir/_filename.bin")]
|
||||
public void NormalizeOutputPathsTest(string? path, bool getFullPath, string expected)
|
||||
{
|
||||
// Modify expected to account for test data if necessary
|
||||
if (getFullPath && !string.IsNullOrEmpty(expected))
|
||||
expected = Path.GetFullPath(expected);
|
||||
|
||||
string actual = PathTool.NormalizeFilePath(path, getFullPath);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
SabreTools.IO.Test/ReadersWriters/ClrMameProTests.cs
Normal file
60
SabreTools.IO.Test/ReadersWriters/ClrMameProTests.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Readers;
|
||||
using SabreTools.IO.Writers;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.ReadersWriters
|
||||
{
|
||||
public class ClrMameProTests
|
||||
{
|
||||
[Fact]
|
||||
public void EndToEndTest()
|
||||
{
|
||||
string expected = "header (\n\tstandalone \"value\"\n)\n\n# Comment\n\ngame (\n\titem ( attr \"value\" )\n)";
|
||||
|
||||
// Build and write the CMP file
|
||||
var stream = new MemoryStream();
|
||||
var writer = new ClrMameProWriter(stream, Encoding.UTF8);
|
||||
Assert.True(writer.Quotes);
|
||||
|
||||
writer.WriteStartElement("header");
|
||||
writer.WriteRequiredStandalone("standalone", "value");
|
||||
writer.WriteOptionalStandalone("optstand", null);
|
||||
writer.WriteFullEndElement();
|
||||
|
||||
writer.WriteString("\n\n# Comment\n");
|
||||
|
||||
writer.WriteStartElement("game");
|
||||
writer.WriteStartElement("item");
|
||||
writer.WriteRequiredAttributeString("attr", "value");
|
||||
writer.WriteOptionalAttributeString("optional", null);
|
||||
writer.WriteEndElement();
|
||||
writer.WriteFullEndElement();
|
||||
|
||||
writer.Flush();
|
||||
writer.Dispose();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(77, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
|
||||
// Parse the CMP file
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
var reader = new ClrMameProReader(stream, Encoding.UTF8);
|
||||
Assert.False(reader.DosCenter);
|
||||
Assert.True(reader.Quotes);
|
||||
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
bool hasNext = reader.ReadNextLine();
|
||||
Assert.True(hasNext);
|
||||
Assert.NotNull(reader.CurrentLine);
|
||||
Assert.True(reader.LineNumber >= 0);
|
||||
}
|
||||
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
50
SabreTools.IO.Test/ReadersWriters/IniTests.cs
Normal file
50
SabreTools.IO.Test/ReadersWriters/IniTests.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Readers;
|
||||
using SabreTools.IO.Writers;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.ReadersWriters
|
||||
{
|
||||
public class IniTests
|
||||
{
|
||||
[Fact]
|
||||
public void EndToEndTest()
|
||||
{
|
||||
string expected = "[section1]\nkey1=value1\nkey2=value2\n\n;comment\n;string\n";
|
||||
|
||||
// Build and write the INI
|
||||
var stream = new MemoryStream();
|
||||
var writer = new IniWriter(stream, Encoding.UTF8);
|
||||
|
||||
writer.WriteSection("section1");
|
||||
writer.WriteKeyValuePair("key1", "value1");
|
||||
writer.WriteKeyValuePair("key2", "value2");
|
||||
writer.WriteLine();
|
||||
writer.WriteComment("comment");
|
||||
writer.WriteString(";string\n");
|
||||
|
||||
writer.Flush();
|
||||
writer.Dispose();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(56, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
|
||||
// Parse the INI
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
var reader = new IniReader(stream, Encoding.UTF8);
|
||||
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
bool hasNext = reader.ReadNextLine();
|
||||
Assert.True(hasNext);
|
||||
Assert.NotNull(reader.CurrentLine);
|
||||
Assert.True(reader.LineNumber >= 0);
|
||||
}
|
||||
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
60
SabreTools.IO.Test/ReadersWriters/SeparatedValueTests.cs
Normal file
60
SabreTools.IO.Test/ReadersWriters/SeparatedValueTests.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Readers;
|
||||
using SabreTools.IO.Writers;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.ReadersWriters
|
||||
{
|
||||
public class SeparatedValueTests
|
||||
{
|
||||
[Fact]
|
||||
public void EndToEndTest()
|
||||
{
|
||||
string expected = "\"col1\",\"col2\",\"col3\"\n\"value1\",\"value2\",\"value3\"\n\"value4\",\"value5\",\"value6\"\n";
|
||||
|
||||
// Build and write the CSV
|
||||
var stream = new MemoryStream();
|
||||
var writer = new SeparatedValueWriter(stream, Encoding.UTF8);
|
||||
Assert.True(writer.Quotes);
|
||||
Assert.Equal(',', writer.Separator);
|
||||
Assert.True(writer.VerifyFieldCount);
|
||||
|
||||
writer.WriteHeader(["col1", "col2", "col3"]);
|
||||
writer.WriteValues(["value1", "value2", "value3"]);
|
||||
writer.WriteString("\"value4\",\"value5\",\"value6\"\n");
|
||||
|
||||
writer.Flush();
|
||||
writer.Dispose();
|
||||
|
||||
// Length includes UTF-8 BOM
|
||||
Assert.Equal(78, stream.Length);
|
||||
string actual = Encoding.UTF8.GetString(stream.ToArray(), 3, (int)stream.Length - 3);
|
||||
Assert.Equal(expected, actual);
|
||||
|
||||
// Parse the CSV
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
var reader = new SeparatedValueReader(stream, Encoding.UTF8);
|
||||
Assert.True(reader.Header);
|
||||
Assert.True(reader.Quotes);
|
||||
Assert.Equal(',', reader.Separator);
|
||||
Assert.True(reader.VerifyFieldCount);
|
||||
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
bool hasNext = reader.ReadNextLine();
|
||||
Assert.True(hasNext);
|
||||
Assert.NotNull(reader.CurrentLine);
|
||||
Assert.True(reader.LineNumber >= 0);
|
||||
|
||||
if (reader.LineNumber > 0)
|
||||
{
|
||||
Assert.NotNull(reader.GetValue(0));
|
||||
Assert.NotNull(reader.GetValue("col2"));
|
||||
}
|
||||
}
|
||||
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,39 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningsNotAsErrors>CS0618</WarningsNotAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SabreTools.IO\SabreTools.IO.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningsNotAsErrors>CS0618</WarningsNotAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="TestData\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="TestData\**">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<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.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SabreTools.IO\SabreTools.IO.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
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,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SabreTools.IO.Streams;
|
||||
using Xunit;
|
||||
|
||||
@@ -24,31 +25,95 @@ namespace SabreTools.IO.Test.Streams
|
||||
byte[] data = [0b01010101];
|
||||
var stream = new ReadOnlyBitStream(new MemoryStream(data));
|
||||
byte? bit = stream.ReadBit();
|
||||
|
||||
Assert.NotNull(bit);
|
||||
Assert.Equal((byte)0b00000001, bit);
|
||||
Assert.Equal(1, stream.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadBitsLSBTest()
|
||||
[Theory]
|
||||
[InlineData(4, 0b00000101, 1)]
|
||||
[InlineData(9, 0b10101010_1, 2)]
|
||||
public void ReadBitsBETest(int bits, uint expected, int position)
|
||||
{
|
||||
byte[] data = [0b01010101, 0b01010101, 0b01010101, 0b01010101];
|
||||
var stream = new ReadOnlyBitStream(new MemoryStream(data));
|
||||
uint? bits = stream.ReadBitsLSB(4);
|
||||
Assert.NotNull(bits);
|
||||
Assert.Equal((byte)0b00000101, bits);
|
||||
Assert.Equal(1, stream.Position);
|
||||
uint? actual = stream.ReadBitsBE(bits);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.Equal(position, stream.Position);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(4, 0b00001010, 1)]
|
||||
[InlineData(9, 0b10101010_1, 2)]
|
||||
public void ReadBitsLETest(int bits, uint expected, int position)
|
||||
{
|
||||
byte[] data = [0b01010101, 0b01010101, 0b01010101, 0b01010101];
|
||||
var stream = new ReadOnlyBitStream(new MemoryStream(data));
|
||||
uint? actual = stream.ReadBitsLE(bits);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(expected, actual);
|
||||
Assert.Equal(position, stream.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadBitsMSBTest()
|
||||
public void ReadByteTest()
|
||||
{
|
||||
byte[] data = [0b01010101, 0b01010101, 0b01010101, 0b01010101];
|
||||
byte expected = 0b01010101;
|
||||
|
||||
var stream = new ReadOnlyBitStream(new MemoryStream(data));
|
||||
uint? bits = stream.ReadBitsMSB(4);
|
||||
Assert.NotNull(bits);
|
||||
Assert.Equal((byte)0b00001010, bits);
|
||||
Assert.Equal(1, stream.Position);
|
||||
byte? actual = stream.ReadByte();
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt16Test()
|
||||
{
|
||||
byte[] data = [0b01010101, 0b01010101, 0b01010101, 0b01010101];
|
||||
ushort expected = 0b0101010101010101;
|
||||
|
||||
var stream = new ReadOnlyBitStream(new MemoryStream(data));
|
||||
ushort? actual = stream.ReadUInt16();
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt32Test()
|
||||
{
|
||||
byte[] data = [0b01010101, 0b01010101, 0b01010101, 0b01010101];
|
||||
uint expected = 0b01010101010101010101010101010101;
|
||||
|
||||
var stream = new ReadOnlyBitStream(new MemoryStream(data));
|
||||
uint? actual = stream.ReadUInt32();
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt64Test()
|
||||
{
|
||||
byte[] data = [0b01010101, 0b01010101, 0b01010101, 0b01010101];
|
||||
|
||||
var stream = new ReadOnlyBitStream(new MemoryStream(data));
|
||||
ulong? actual = stream.ReadUInt64();
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadBytesTest()
|
||||
{
|
||||
byte[] data = [0b01010101, 0b01010101, 0b01010101, 0b01010101];
|
||||
|
||||
var stream = new ReadOnlyBitStream(new MemoryStream(data));
|
||||
byte[]? actual = stream.ReadBytes(4);
|
||||
Assert.NotNull(actual);
|
||||
Assert.True(data.SequenceEqual(actual));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,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);
|
||||
@@ -17,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);
|
||||
@@ -26,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);
|
||||
@@ -36,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);
|
||||
@@ -44,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);
|
||||
@@ -53,14 +54,18 @@ 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);
|
||||
Assert.Equal(2048, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region AddStream
|
||||
|
||||
[Fact]
|
||||
public void AddStreamTest()
|
||||
{
|
||||
@@ -71,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();
|
||||
|
||||
@@ -85,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);
|
||||
@@ -97,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);
|
||||
@@ -109,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);
|
||||
@@ -121,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);
|
||||
@@ -133,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);
|
||||
@@ -143,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
|
||||
}
|
||||
}
|
||||
1
SabreTools.IO.Test/TestData/Subdirectory/sample.txt
Normal file
1
SabreTools.IO.Test/TestData/Subdirectory/sample.txt
Normal file
@@ -0,0 +1 @@
|
||||
Sample file for subdirectories
|
||||
1
SabreTools.IO.Test/TestData/ascii.txt
Normal file
1
SabreTools.IO.Test/TestData/ascii.txt
Normal file
@@ -0,0 +1 @@
|
||||
This doesn't match anything
|
||||
1
SabreTools.IO.Test/TestData/file-to-compress.bin
Normal file
1
SabreTools.IO.Test/TestData/file-to-compress.bin
Normal file
@@ -0,0 +1 @@
|
||||
This is just a file that has a known set of hashes to make sure that everything with hashing is still working as anticipated.
|
||||
BIN
SabreTools.IO.Test/TestData/test-archive.bz2
Normal file
BIN
SabreTools.IO.Test/TestData/test-archive.bz2
Normal file
Binary file not shown.
BIN
SabreTools.IO.Test/TestData/test-archive.msz
Normal file
BIN
SabreTools.IO.Test/TestData/test-archive.msz
Normal file
Binary file not shown.
BIN
SabreTools.IO.Test/TestData/test-archive.pk
Normal file
BIN
SabreTools.IO.Test/TestData/test-archive.pk
Normal file
Binary file not shown.
BIN
SabreTools.IO.Test/TestData/test-archive.qtm
Normal file
BIN
SabreTools.IO.Test/TestData/test-archive.qtm
Normal file
Binary file not shown.
1
SabreTools.IO.Test/TestData/utf16bebom.txt
Normal file
1
SabreTools.IO.Test/TestData/utf16bebom.txt
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
SabreTools.IO.Test/TestData/utf16lebom.txt
Normal file
1
SabreTools.IO.Test/TestData/utf16lebom.txt
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
BIN
SabreTools.IO.Test/TestData/utf32bom.txt
Normal file
BIN
SabreTools.IO.Test/TestData/utf32bom.txt
Normal file
Binary file not shown.
1
SabreTools.IO.Test/TestData/utf7bom.txt
Normal file
1
SabreTools.IO.Test/TestData/utf7bom.txt
Normal file
@@ -0,0 +1 @@
|
||||
+/v
|
||||
1
SabreTools.IO.Test/TestData/utf8bom.txt
Normal file
1
SabreTools.IO.Test/TestData/utf8bom.txt
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
118
SabreTools.IO/Compression/BZip2/BZip2.cs
Normal file
118
SabreTools.IO/Compression/BZip2/BZip2.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
// BZip2InputStream.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 11:57:32>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines the BZip2InputStream class, which is a decompressing
|
||||
// stream that handles BZIP2. This code is derived from Apache commons source code.
|
||||
// The license below applies to the original Apache code.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This package is based on the work done by Keiron Liddle, Aftex Software
|
||||
* <keiron@aftexsw.com> to whom the Ant project is very grateful for his
|
||||
* great code.
|
||||
*/
|
||||
|
||||
// compile: msbuild
|
||||
// not: csc.exe /t:library /debug+ /out:SabreTools.IO.Compression.BZip2.dll BZip2InputStream.cs BCRC32.cs Rand.cs
|
||||
|
||||
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.
|
||||
// *
|
||||
// * @param signature
|
||||
// * the bytes to check
|
||||
// * @param length
|
||||
// * the number of bytes to check
|
||||
// * @return true, if this stream is a bzip2 compressed stream, false otherwise
|
||||
// *
|
||||
// * @since Apache Commons Compress 1.1
|
||||
// */
|
||||
// public static boolean MatchesSig(byte[] signature)
|
||||
// {
|
||||
// if ((signature.Length < 3) ||
|
||||
// (signature[0] != 'B') ||
|
||||
// (signature[1] != 'Z') ||
|
||||
// (signature[2] != 'h'))
|
||||
// return false;
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
|
||||
internal static class BZip2
|
||||
{
|
||||
internal static T[][] InitRectangularArray<T>(int d1, int d2)
|
||||
{
|
||||
var x = new T[d1][];
|
||||
for (int i = 0; i < d1; i++)
|
||||
{
|
||||
x[i] = new T[d2];
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
public static readonly int BlockSizeMultiple = 100000;
|
||||
public static readonly int MinBlockSize = 1;
|
||||
public static readonly int MaxBlockSize = 9;
|
||||
public static readonly int MaxAlphaSize = 258;
|
||||
public static readonly int MaxCodeLength = 23;
|
||||
public static readonly char RUNA = (char)0;
|
||||
public static readonly char RUNB = (char)1;
|
||||
public static readonly int NGroups = 6;
|
||||
public static readonly int G_SIZE = 50;
|
||||
public static readonly int N_ITERS = 4;
|
||||
public static readonly int MaxSelectors = (2 + (900000 / G_SIZE));
|
||||
public static readonly int NUM_OVERSHOOT_BYTES = 20;
|
||||
/*
|
||||
* <p> If you are ever unlucky/improbable enough to get a stack
|
||||
* overflow whilst sorting, increase the following constant and
|
||||
* try again. In practice I have never seen the stack go above 27
|
||||
* elems, so the following limit seems very generous. </p>
|
||||
*/
|
||||
internal static readonly int QSORT_STACK_SIZE = 1000;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
1954
SabreTools.IO/Compression/BZip2/BZip2Compressor.cs
Normal file
1954
SabreTools.IO/Compression/BZip2/BZip2Compressor.cs
Normal file
File diff suppressed because it is too large
Load Diff
1396
SabreTools.IO/Compression/BZip2/BZip2InputStream.cs
Normal file
1396
SabreTools.IO/Compression/BZip2/BZip2InputStream.cs
Normal file
File diff suppressed because it is too large
Load Diff
537
SabreTools.IO/Compression/BZip2/BZip2OutputStream.cs
Normal file
537
SabreTools.IO/Compression/BZip2/BZip2OutputStream.cs
Normal file
@@ -0,0 +1,537 @@
|
||||
//#define Trace
|
||||
|
||||
// BZip2OutputStream.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-August-02 16:44:11>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines the BZip2OutputStream class, which is a
|
||||
// compressing stream that handles BZIP2. This code may have been
|
||||
// derived in part from Apache commons source code. The license below
|
||||
// applies to the original Apache code.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
// flymake: csc.exe /t:module BZip2InputStream.cs BZip2Compressor.cs Rand.cs BCRC32.cs @@FILE@@
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
// Design Notes:
|
||||
//
|
||||
// This class follows the classic Decorator pattern: it is a Stream that
|
||||
// wraps itself around a Stream, and in doing so provides bzip2
|
||||
// compression as callers Write into it.
|
||||
//
|
||||
// BZip2 is a straightforward data format: there are 4 magic bytes at
|
||||
// the top of the file, followed by 1 or more compressed blocks. There
|
||||
// is a small "magic byte" trailer after all compressed blocks. This
|
||||
// class emits the magic bytes for the header and trailer, and relies on
|
||||
// a BZip2Compressor to generate each of the compressed data blocks.
|
||||
//
|
||||
// BZip2 does byte-shredding - it uses partial fractions of bytes to
|
||||
// represent independent pieces of information. This class relies on the
|
||||
// BitWriter to adapt the bit-oriented BZip2 output to the byte-oriented
|
||||
// model of the .NET Stream class.
|
||||
//
|
||||
// ----
|
||||
//
|
||||
// Regarding the Apache code base: Most of the code in this particular
|
||||
// class is related to stream operations, and is my own code. It largely
|
||||
// does not rely on any code obtained from Apache commons. If you
|
||||
// compare this code with the Apache commons BZip2OutputStream, you will
|
||||
// see very little code that is common, except for the
|
||||
// nearly-boilerplate structure that is common to all subtypes of
|
||||
// System.IO.Stream. There may be some small remnants of code in this
|
||||
// module derived from the Apache stuff, which is why I left the license
|
||||
// in here. Most of the Apache commons compressor magic has been ported
|
||||
// into the BZip2Compressor class.
|
||||
//
|
||||
|
||||
using System;
|
||||
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.
|
||||
/// </summary>
|
||||
public class BZip2OutputStream : System.IO.Stream
|
||||
{
|
||||
int totalBytesWrittenIn;
|
||||
readonly bool leaveOpen;
|
||||
BZip2Compressor compressor;
|
||||
uint combinedCRC;
|
||||
Stream output;
|
||||
BitWriter bw;
|
||||
readonly int blockSize100k; // 0...9
|
||||
|
||||
private readonly TraceBits desiredTrace = TraceBits.Crc | TraceBits.Write;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new <c>BZip2OutputStream</c>, that sends its
|
||||
/// compressed output to the given output stream.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name='output'>
|
||||
/// The destination stream, to which compressed output will be sent.
|
||||
/// </param>
|
||||
///
|
||||
/// <example>
|
||||
///
|
||||
/// This example reads a file, then compresses it with bzip2 file,
|
||||
/// and writes the compressed data into a newly created file.
|
||||
///
|
||||
/// <code>
|
||||
/// var fname = "logfile.log";
|
||||
/// using (var fs = File.OpenRead(fname))
|
||||
/// {
|
||||
/// var outFname = fname + ".bz2";
|
||||
/// using (var output = File.Create(outFname))
|
||||
/// {
|
||||
/// using (var compressor = new SabreTools.IO.Compression.BZip2.BZip2OutputStream(output))
|
||||
/// {
|
||||
/// byte[] buffer = new byte[2048];
|
||||
/// int n;
|
||||
/// while ((n = fs.Read(buffer, 0, buffer.Length)) > 0)
|
||||
/// {
|
||||
/// compressor.Write(buffer, 0, n);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public BZip2OutputStream(Stream output)
|
||||
: this(output, BZip2.MaxBlockSize, false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new <c>BZip2OutputStream</c> with specified blocksize.
|
||||
/// </summary>
|
||||
/// <param name = "output">the destination stream.</param>
|
||||
/// <param name = "blockSize">
|
||||
/// The blockSize in units of 100000 bytes.
|
||||
/// The valid range is 1..9.
|
||||
/// </param>
|
||||
public BZip2OutputStream(Stream output, int blockSize)
|
||||
: this(output, blockSize, false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new <c>BZip2OutputStream</c>.
|
||||
/// </summary>
|
||||
/// <param name = "output">the destination stream.</param>
|
||||
/// <param name = "leaveOpen">
|
||||
/// whether to leave the captive stream open upon closing this stream.
|
||||
/// </param>
|
||||
public BZip2OutputStream(Stream output, bool leaveOpen)
|
||||
: this(output, BZip2.MaxBlockSize, leaveOpen)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new <c>BZip2OutputStream</c> with specified blocksize,
|
||||
/// and explicitly specifies whether to leave the wrapped stream open.
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name = "output">the destination stream.</param>
|
||||
/// <param name = "blockSize">
|
||||
/// The blockSize in units of 100000 bytes.
|
||||
/// The valid range is 1..9.
|
||||
/// </param>
|
||||
/// <param name = "leaveOpen">
|
||||
/// whether to leave the captive stream open upon closing this stream.
|
||||
/// </param>
|
||||
public BZip2OutputStream(Stream output, int blockSize, bool leaveOpen)
|
||||
{
|
||||
if (blockSize < BZip2.MinBlockSize ||
|
||||
blockSize > BZip2.MaxBlockSize)
|
||||
{
|
||||
var msg = String.Format("blockSize={0} is out of range; must be between {1} and {2}",
|
||||
blockSize,
|
||||
BZip2.MinBlockSize, BZip2.MaxBlockSize);
|
||||
throw new ArgumentException(msg, "blockSize");
|
||||
}
|
||||
|
||||
this.output = output;
|
||||
if (!this.output.CanWrite)
|
||||
throw new ArgumentException("The stream is not writable.", "output");
|
||||
|
||||
this.bw = new BitWriter(this.output);
|
||||
this.blockSize100k = blockSize;
|
||||
this.compressor = new BZip2Compressor(this.bw, blockSize);
|
||||
this.leaveOpen = leaveOpen;
|
||||
this.combinedCRC = 0;
|
||||
EmitHeader();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Close the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This may or may not close the underlying stream. Check the
|
||||
/// constructors that accept a bool value.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public override void Close()
|
||||
{
|
||||
if (output is not null)
|
||||
{
|
||||
Stream o = this.output;
|
||||
Finish();
|
||||
if (!leaveOpen)
|
||||
o.Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Flush the stream.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
if (this.output is not null)
|
||||
{
|
||||
this.bw.Flush();
|
||||
this.output.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
private void EmitHeader()
|
||||
{
|
||||
var magic = new byte[] {
|
||||
(byte) 'B',
|
||||
(byte) 'Z',
|
||||
(byte) 'h',
|
||||
(byte) ('0' + this.blockSize100k)
|
||||
};
|
||||
|
||||
// not necessary to shred the initial magic bytes
|
||||
this.output.Write(magic, 0, magic.Length);
|
||||
}
|
||||
|
||||
private void EmitTrailer()
|
||||
{
|
||||
// A magic 48-bit number, 0x177245385090, to indicate the end
|
||||
// of the last block. (sqrt(pi), if you want to know)
|
||||
|
||||
TraceOutput(TraceBits.Write, "total written out: {0} (0x{0:X})",
|
||||
this.bw.TotalBytesWrittenOut);
|
||||
|
||||
// must shred
|
||||
this.bw.WriteByte(0x17);
|
||||
this.bw.WriteByte(0x72);
|
||||
this.bw.WriteByte(0x45);
|
||||
this.bw.WriteByte(0x38);
|
||||
this.bw.WriteByte(0x50);
|
||||
this.bw.WriteByte(0x90);
|
||||
|
||||
this.bw.WriteInt(this.combinedCRC);
|
||||
|
||||
this.bw.FinishAndPad();
|
||||
|
||||
TraceOutput(TraceBits.Write, "final total: {0} (0x{0:X})",
|
||||
this.bw.TotalBytesWrittenOut);
|
||||
}
|
||||
|
||||
void Finish()
|
||||
{
|
||||
// Console.WriteLine("BZip2:Finish");
|
||||
|
||||
try
|
||||
{
|
||||
var totalBefore = this.bw.TotalBytesWrittenOut;
|
||||
this.compressor.CompressAndWrite();
|
||||
TraceOutput(TraceBits.Write, "out block length (bytes): {0} (0x{0:X})",
|
||||
this.bw.TotalBytesWrittenOut - totalBefore);
|
||||
|
||||
TraceOutput(TraceBits.Crc, " combined CRC (before): {0:X8}",
|
||||
this.combinedCRC);
|
||||
this.combinedCRC = (this.combinedCRC << 1) | (this.combinedCRC >> 31);
|
||||
this.combinedCRC ^= (uint)compressor.Crc32;
|
||||
TraceOutput(TraceBits.Crc, " block CRC : {0:X8}",
|
||||
this.compressor.Crc32);
|
||||
TraceOutput(TraceBits.Crc, " combined CRC (final) : {0:X8}",
|
||||
this.combinedCRC);
|
||||
|
||||
EmitTrailer();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.output = null;
|
||||
this.compressor = null;
|
||||
this.bw = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The blocksize parameter specified at construction time.
|
||||
/// </summary>
|
||||
public int BlockSize
|
||||
{
|
||||
get { return this.blockSize100k; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Write data to the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// <para>
|
||||
/// Use the <c>BZip2OutputStream</c> to compress data while writing:
|
||||
/// create a <c>BZip2OutputStream</c> with a writable output stream.
|
||||
/// Then call <c>Write()</c> on that <c>BZip2OutputStream</c>, providing
|
||||
/// uncompressed data as input. The data sent to the output stream will
|
||||
/// be the compressed form of the input data.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// A <c>BZip2OutputStream</c> can be used only for <c>Write()</c> not for <c>Read()</c>.
|
||||
/// </para>
|
||||
///
|
||||
/// </remarks>
|
||||
///
|
||||
/// <param name="buffer">The buffer holding data to write to the stream.</param>
|
||||
/// <param name="offset">the offset within that data array to find the first byte to write.</param>
|
||||
/// <param name="count">the number of bytes to write.</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (offset < 0)
|
||||
throw new IndexOutOfRangeException(String.Format("offset ({0}) must be > 0", offset));
|
||||
if (count < 0)
|
||||
throw new IndexOutOfRangeException(String.Format("count ({0}) must be > 0", count));
|
||||
if (offset + count > buffer.Length)
|
||||
throw new IndexOutOfRangeException(String.Format("offset({0}) count({1}) bLength({2})",
|
||||
offset, count, buffer.Length));
|
||||
if (this.output is null)
|
||||
throw new IOException("the stream is not open");
|
||||
|
||||
if (count == 0) return; // nothing to do
|
||||
|
||||
int bytesWritten = 0;
|
||||
int bytesRemaining = count;
|
||||
|
||||
do
|
||||
{
|
||||
int n = compressor.Fill(buffer, offset, bytesRemaining);
|
||||
if (n != bytesRemaining)
|
||||
{
|
||||
// The compressor data block is full. Compress and
|
||||
// write out the compressed data, then reset the
|
||||
// compressor and continue.
|
||||
|
||||
var totalBefore = this.bw.TotalBytesWrittenOut;
|
||||
this.compressor.CompressAndWrite();
|
||||
TraceOutput(TraceBits.Write, "out block length (bytes): {0} (0x{0:X})",
|
||||
this.bw.TotalBytesWrittenOut - totalBefore);
|
||||
|
||||
// and now any remaining bits
|
||||
TraceOutput(TraceBits.Write,
|
||||
" remaining: {0} 0x{1:X}",
|
||||
this.bw.NumRemainingBits,
|
||||
this.bw.RemainingBits);
|
||||
|
||||
TraceOutput(TraceBits.Crc, " combined CRC (before): {0:X8}",
|
||||
this.combinedCRC);
|
||||
this.combinedCRC = (this.combinedCRC << 1) | (this.combinedCRC >> 31);
|
||||
this.combinedCRC ^= (uint)compressor.Crc32;
|
||||
TraceOutput(TraceBits.Crc, " block CRC : {0:X8}",
|
||||
compressor.Crc32);
|
||||
TraceOutput(TraceBits.Crc, " combined CRC (after) : {0:X8}",
|
||||
this.combinedCRC);
|
||||
offset += n;
|
||||
}
|
||||
bytesRemaining -= n;
|
||||
bytesWritten += n;
|
||||
} while (bytesRemaining > 0);
|
||||
|
||||
totalBytesWrittenIn += bytesWritten;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream can be read.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The return value is always false.
|
||||
/// </remarks>
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream supports Seek operations.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Always returns false.
|
||||
/// </remarks>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream can be written.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The return value should always be true, unless and until the
|
||||
/// object is disposed and closed.
|
||||
/// </remarks>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.output is null) throw new ObjectDisposedException("BZip2Stream");
|
||||
return this.output.CanWrite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reading this property always throws a <see cref="NotImplementedException"/>.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The position of the stream pointer.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Setting this property always throws a <see
|
||||
/// cref="NotImplementedException"/>. Reading will return the
|
||||
/// total number of uncompressed bytes written through.
|
||||
/// </remarks>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.totalBytesWrittenIn;
|
||||
}
|
||||
set { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calling this method always throws a <see cref="NotImplementedException"/>.
|
||||
/// </summary>
|
||||
/// <param name="offset">this is irrelevant, since it will always throw!</param>
|
||||
/// <param name="origin">this is irrelevant, since it will always throw!</param>
|
||||
/// <returns>irrelevant!</returns>
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calling this method always throws a <see cref="NotImplementedException"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">this is irrelevant, since it will always throw!</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calling this method always throws a <see cref="NotImplementedException"/>.
|
||||
/// </summary>
|
||||
/// <param name='buffer'>this parameter is never used</param>
|
||||
/// <param name='offset'>this parameter is never used</param>
|
||||
/// <param name='count'>this parameter is never used</param>
|
||||
/// <returns>never returns anything; always throws</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
// used only when Trace is defined
|
||||
[Flags]
|
||||
enum TraceBits : uint
|
||||
{
|
||||
None = 0,
|
||||
Crc = 1,
|
||||
Write = 2,
|
||||
All = 0xffffffff,
|
||||
}
|
||||
|
||||
|
||||
[System.Diagnostics.ConditionalAttribute("Trace")]
|
||||
private void TraceOutput(TraceBits bits, string format, params object[] varParams)
|
||||
{
|
||||
if ((bits & this.desiredTrace) != 0)
|
||||
{
|
||||
//lock(outputLock)
|
||||
{
|
||||
int tid = System.Threading.Thread.CurrentThread.GetHashCode();
|
||||
#if !SILVERLIGHT && !NETCF
|
||||
Console.ForegroundColor = (ConsoleColor)(tid % 8 + 10);
|
||||
#endif
|
||||
Console.Write("{0:000} PBOS ", tid);
|
||||
Console.WriteLine(format, varParams);
|
||||
#if !SILVERLIGHT && !NETCF
|
||||
Console.ResetColor();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
249
SabreTools.IO/Compression/BZip2/BitWriter.cs
Normal file
249
SabreTools.IO/Compression/BZip2/BitWriter.cs
Normal file
@@ -0,0 +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.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++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
824
SabreTools.IO/Compression/BZip2/CRC32.cs
Normal file
824
SabreTools.IO/Compression/BZip2/CRC32.cs
Normal file
@@ -0,0 +1,824 @@
|
||||
// CRC32.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-August-02 18:25:54>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines the CRC32 class, which can do the CRC32 algorithm, using
|
||||
// arbitrary starting polynomials, and bit reversal. The bit reversal is what
|
||||
// distinguishes this CRC-32 used in BZip2 from the CRC-32 that is used in PKZIP
|
||||
// files, or GZIP files. This class does both.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using Interop = System.Runtime.InteropServices;
|
||||
|
||||
#nullable disable
|
||||
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
|
||||
/// reversal. This can be used for GZIP, BZip2, or ZIP.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This type is used internally by DotNetZip; it is generally not used
|
||||
/// directly by applications wishing to create, read, or manipulate zip
|
||||
/// archive files.
|
||||
/// </remarks>
|
||||
|
||||
[Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000C")]
|
||||
[Interop.ComVisible(true)]
|
||||
#if !NETCF
|
||||
[Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
|
||||
#endif
|
||||
public class CRC32
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the total number of bytes applied to the CRC.
|
||||
/// </summary>
|
||||
public Int64 TotalBytesRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return _TotalBytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the current CRC for all blocks slurped in.
|
||||
/// </summary>
|
||||
public Int32 Crc32Result
|
||||
{
|
||||
get
|
||||
{
|
||||
return unchecked((Int32)(~_register));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the CRC32 for the specified stream.
|
||||
/// </summary>
|
||||
/// <param name="input">The stream over which to calculate the CRC32</param>
|
||||
/// <returns>the CRC32 calculation</returns>
|
||||
public Int32 GetCrc32(System.IO.Stream input)
|
||||
{
|
||||
return GetCrc32AndCopy(input, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the CRC32 for the specified stream, and writes the input into the
|
||||
/// output stream.
|
||||
/// </summary>
|
||||
/// <param name="input">The stream over which to calculate the CRC32</param>
|
||||
/// <param name="output">The stream into which to deflate the input</param>
|
||||
/// <returns>the CRC32 calculation</returns>
|
||||
public Int32 GetCrc32AndCopy(System.IO.Stream input, System.IO.Stream output)
|
||||
{
|
||||
if (input is null)
|
||||
throw new Exception("The input stream must not be null.");
|
||||
|
||||
unchecked
|
||||
{
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int readSize = BUFFER_SIZE;
|
||||
|
||||
_TotalBytesRead = 0;
|
||||
int count = input.Read(buffer, 0, readSize);
|
||||
output?.Write(buffer, 0, count);
|
||||
_TotalBytesRead += count;
|
||||
while (count > 0)
|
||||
{
|
||||
SlurpBlock(buffer, 0, count);
|
||||
count = input.Read(buffer, 0, readSize);
|
||||
output?.Write(buffer, 0, count);
|
||||
_TotalBytesRead += count;
|
||||
}
|
||||
|
||||
return (Int32)(~_register);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the CRC32 for the given (word,byte) combo. This is a
|
||||
/// computation defined by PKzip for PKZIP 2.0 (weak) encryption.
|
||||
/// </summary>
|
||||
/// <param name="W">The word to start with.</param>
|
||||
/// <param name="B">The byte to combine it with.</param>
|
||||
/// <returns>The CRC-ized result.</returns>
|
||||
public Int32 ComputeCrc32(Int32 W, byte B)
|
||||
{
|
||||
return _InternalComputeCrc32((UInt32)W, B);
|
||||
}
|
||||
|
||||
internal Int32 _InternalComputeCrc32(UInt32 W, byte B)
|
||||
{
|
||||
return (Int32)(crc32Table[(W ^ B) & 0xFF] ^ (W >> 8));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Update the value for the running CRC32 using the given block of bytes.
|
||||
/// This is useful when using the CRC32() class in a Stream.
|
||||
/// </summary>
|
||||
/// <param name="block">block of bytes to slurp</param>
|
||||
/// <param name="offset">starting point in the block</param>
|
||||
/// <param name="count">how many bytes within the block to slurp</param>
|
||||
public void SlurpBlock(byte[] block, int offset, int count)
|
||||
{
|
||||
if (block is null)
|
||||
throw new Exception("The data buffer must not be null.");
|
||||
|
||||
// bzip algorithm
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int x = offset + i;
|
||||
byte b = block[x];
|
||||
if (this.reverseBits)
|
||||
{
|
||||
UInt32 temp = (_register >> 24) ^ b;
|
||||
_register = (_register << 8) ^ crc32Table[temp];
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 temp = (_register & 0x000000FF) ^ b;
|
||||
_register = (_register >> 8) ^ crc32Table[temp];
|
||||
}
|
||||
}
|
||||
_TotalBytesRead += count;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Process one byte in the CRC.
|
||||
/// </summary>
|
||||
/// <param name = "b">the byte to include into the CRC . </param>
|
||||
public void UpdateCRC(byte b)
|
||||
{
|
||||
if (this.reverseBits)
|
||||
{
|
||||
UInt32 temp = (_register >> 24) ^ b;
|
||||
_register = (_register << 8) ^ crc32Table[temp];
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 temp = (_register & 0x000000FF) ^ b;
|
||||
_register = (_register >> 8) ^ crc32Table[temp];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a run of N identical bytes into the CRC.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method serves as an optimization for updating the CRC when a
|
||||
/// run of identical bytes is found. Rather than passing in a buffer of
|
||||
/// length n, containing all identical bytes b, this method accepts the
|
||||
/// byte value and the length of the (virtual) buffer - the length of
|
||||
/// the run.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name = "b">the byte to include into the CRC. </param>
|
||||
/// <param name = "n">the number of times that byte should be repeated. </param>
|
||||
public void UpdateCRC(byte b, int n)
|
||||
{
|
||||
while (n-- > 0)
|
||||
{
|
||||
if (this.reverseBits)
|
||||
{
|
||||
uint temp = (_register >> 24) ^ b;
|
||||
_register = (_register << 8) ^ crc32Table[(temp >= 0)
|
||||
? temp
|
||||
: (temp + 256)];
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 temp = (_register & 0x000000FF) ^ b;
|
||||
_register = (_register >> 8) ^ crc32Table[(temp >= 0)
|
||||
? temp
|
||||
: (temp + 256)];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static uint ReverseBits(uint data)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint ret = data;
|
||||
ret = (ret & 0x55555555) << 1 | (ret >> 1) & 0x55555555;
|
||||
ret = (ret & 0x33333333) << 2 | (ret >> 2) & 0x33333333;
|
||||
ret = (ret & 0x0F0F0F0F) << 4 | (ret >> 4) & 0x0F0F0F0F;
|
||||
ret = (ret << 24) | ((ret & 0xFF00) << 8) | ((ret >> 8) & 0xFF00) | (ret >> 24);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte ReverseBits(byte data)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint u = (uint)data * 0x00020202;
|
||||
uint m = 0x01044010;
|
||||
uint s = u & m;
|
||||
uint t = (u << 2) & (m << 1);
|
||||
return (byte)((0x01001001 * (s + t)) >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void GenerateLookupTable()
|
||||
{
|
||||
crc32Table = new UInt32[256];
|
||||
unchecked
|
||||
{
|
||||
UInt32 dwCrc;
|
||||
byte i = 0;
|
||||
do
|
||||
{
|
||||
dwCrc = i;
|
||||
for (byte j = 8; j > 0; j--)
|
||||
{
|
||||
if ((dwCrc & 1) == 1)
|
||||
{
|
||||
dwCrc = (dwCrc >> 1) ^ dwPolynomial;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwCrc >>= 1;
|
||||
}
|
||||
}
|
||||
if (reverseBits)
|
||||
{
|
||||
crc32Table[ReverseBits(i)] = ReverseBits(dwCrc);
|
||||
}
|
||||
else
|
||||
{
|
||||
crc32Table[i] = dwCrc;
|
||||
}
|
||||
i++;
|
||||
} while (i != 0);
|
||||
}
|
||||
|
||||
#if VERBOSE
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("private static readonly UInt32[] crc32Table = {");
|
||||
for (int i = 0; i < crc32Table.Length; i+=4)
|
||||
{
|
||||
Console.Write(" ");
|
||||
for (int j=0; j < 4; j++)
|
||||
{
|
||||
Console.Write(" 0x{0:X8}U,", crc32Table[i+j]);
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
Console.WriteLine("};");
|
||||
Console.WriteLine();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
private uint gf2_matrix_times(uint[] matrix, uint vec)
|
||||
{
|
||||
uint sum = 0;
|
||||
int i = 0;
|
||||
while (vec != 0)
|
||||
{
|
||||
if ((vec & 0x01) == 0x01)
|
||||
sum ^= matrix[i];
|
||||
vec >>= 1;
|
||||
i++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
private void gf2_matrix_square(uint[] square, uint[] mat)
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
square[i] = gf2_matrix_times(mat, mat[i]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Combines the given CRC32 value with the current running total.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is useful when using a divide-and-conquer approach to
|
||||
/// calculating a CRC. Multiple threads can each calculate a
|
||||
/// CRC32 on a segment of the data, and then combine the
|
||||
/// individual CRC32 values at the end.
|
||||
/// </remarks>
|
||||
/// <param name="crc">the crc value to be combined with this one</param>
|
||||
/// <param name="length">the length of data the CRC value was calculated on</param>
|
||||
public void Combine(int crc, int length)
|
||||
{
|
||||
uint[] even = new uint[32]; // even-power-of-two zeros operator
|
||||
uint[] odd = new uint[32]; // odd-power-of-two zeros operator
|
||||
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
uint crc1 = ~_register;
|
||||
uint crc2 = (uint)crc;
|
||||
|
||||
// put operator for one zero bit in odd
|
||||
odd[0] = this.dwPolynomial; // the CRC-32 polynomial
|
||||
uint row = 1;
|
||||
for (int i = 1; i < 32; i++)
|
||||
{
|
||||
odd[i] = row;
|
||||
row <<= 1;
|
||||
}
|
||||
|
||||
// put operator for two zero bits in even
|
||||
gf2_matrix_square(even, odd);
|
||||
|
||||
// put operator for four zero bits in odd
|
||||
gf2_matrix_square(odd, even);
|
||||
|
||||
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
|
||||
{
|
||||
// apply zeros operator for this bit of len2
|
||||
gf2_matrix_square(even, odd);
|
||||
|
||||
if ((len2 & 1) == 1)
|
||||
crc1 = gf2_matrix_times(even, crc1);
|
||||
len2 >>= 1;
|
||||
|
||||
if (len2 == 0)
|
||||
break;
|
||||
|
||||
// another iteration of the loop with odd and even swapped
|
||||
gf2_matrix_square(odd, even);
|
||||
if ((len2 & 1) == 1)
|
||||
crc1 = gf2_matrix_times(odd, crc1);
|
||||
len2 >>= 1;
|
||||
|
||||
|
||||
} while (len2 != 0);
|
||||
|
||||
crc1 ^= crc2;
|
||||
|
||||
_register = ~crc1;
|
||||
|
||||
//return (int) crc1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of the CRC32 class using the default settings: no
|
||||
/// bit reversal, and a polynomial of 0xEDB88320.
|
||||
/// </summary>
|
||||
public CRC32() : this(false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of the CRC32 class, specifying whether to reverse
|
||||
/// data bits or not.
|
||||
/// </summary>
|
||||
/// <param name='reverseBits'>
|
||||
/// specify true if the instance should reverse data bits.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
|
||||
/// want a CRC32 with compatibility with BZip2, you should pass true
|
||||
/// here. In the CRC-32 used by GZIP and PKZIP, the bits are not
|
||||
/// reversed; Therefore if you want a CRC32 with compatibility with
|
||||
/// those, you should pass false.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public CRC32(bool reverseBits) :
|
||||
this(unchecked((int)0xEDB88320), reverseBits)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of the CRC32 class, specifying the polynomial and
|
||||
/// whether to reverse data bits or not.
|
||||
/// </summary>
|
||||
/// <param name='polynomial'>
|
||||
/// The polynomial to use for the CRC, expressed in the reversed (LSB)
|
||||
/// format: the highest ordered bit in the polynomial value is the
|
||||
/// coefficient of the 0th power; the second-highest order bit is the
|
||||
/// coefficient of the 1 power, and so on. Expressed this way, the
|
||||
/// polynomial for the CRC-32C used in IEEE 802.3, is 0xEDB88320.
|
||||
/// </param>
|
||||
/// <param name='reverseBits'>
|
||||
/// specify true if the instance should reverse data bits.
|
||||
/// </param>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
|
||||
/// want a CRC32 with compatibility with BZip2, you should pass true
|
||||
/// here for the <c>reverseBits</c> parameter. In the CRC-32 used by
|
||||
/// GZIP and PKZIP, the bits are not reversed; Therefore if you want a
|
||||
/// CRC32 with compatibility with those, you should pass false for the
|
||||
/// <c>reverseBits</c> parameter.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public CRC32(int polynomial, bool reverseBits)
|
||||
{
|
||||
this.reverseBits = reverseBits;
|
||||
this.dwPolynomial = (uint)polynomial;
|
||||
this.GenerateLookupTable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the CRC-32 class - clear the CRC "remainder register."
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Use this when employing a single instance of this class to compute
|
||||
/// multiple, distinct CRCs on multiple, distinct data blocks.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void Reset()
|
||||
{
|
||||
_register = 0xFFFFFFFFU;
|
||||
}
|
||||
|
||||
// private member vars
|
||||
private readonly UInt32 dwPolynomial;
|
||||
private Int64 _TotalBytesRead;
|
||||
private readonly bool reverseBits;
|
||||
private UInt32[] crc32Table;
|
||||
private const int BUFFER_SIZE = 8192;
|
||||
private UInt32 _register = 0xFFFFFFFFU;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A Stream that calculates a CRC32 (a checksum) on all bytes read,
|
||||
/// or on all bytes written.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This class can be used to verify the CRC of a ZipEntry when
|
||||
/// reading from a stream, or to calculate a CRC when writing to a
|
||||
/// stream. The stream should be used to either read, or write, but
|
||||
/// not both. If you intermix reads and writes, the results are not
|
||||
/// defined.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// This class is intended primarily for use internally by the
|
||||
/// DotNetZip library.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class CrcCalculatorStream : System.IO.Stream, System.IDisposable
|
||||
{
|
||||
private static readonly Int64 UnsetLengthLimit = -99;
|
||||
|
||||
internal System.IO.Stream _innerStream;
|
||||
private readonly CRC32 _Crc32;
|
||||
private readonly Int64 _lengthLimit = -99;
|
||||
private bool _leaveOpen;
|
||||
|
||||
/// <summary>
|
||||
/// The default constructor.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Instances returned from this constructor will leave the underlying
|
||||
/// stream open upon Close(). The stream uses the default CRC32
|
||||
/// algorithm, which implies a polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream)
|
||||
: this(true, CrcCalculatorStream.UnsetLengthLimit, stream, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The constructor allows the caller to specify how to handle the
|
||||
/// underlying stream at close.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the default CRC32 algorithm, which implies a
|
||||
/// polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="leaveOpen">true to leave the underlying stream
|
||||
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, bool leaveOpen)
|
||||
: this(leaveOpen, CrcCalculatorStream.UnsetLengthLimit, stream, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A constructor allowing the specification of the length of the stream
|
||||
/// to read.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the default CRC32 algorithm, which implies a
|
||||
/// polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Instances returned from this constructor will leave the underlying
|
||||
/// stream open upon Close().
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="length">The length of the stream to slurp</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, Int64 length)
|
||||
: this(true, length, stream, null)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new ArgumentException("length");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A constructor allowing the specification of the length of the stream
|
||||
/// to read, as well as whether to keep the underlying stream open upon
|
||||
/// Close().
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the default CRC32 algorithm, which implies a
|
||||
/// polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="length">The length of the stream to slurp</param>
|
||||
/// <param name="leaveOpen">true to leave the underlying stream
|
||||
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen)
|
||||
: this(leaveOpen, length, stream, null)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new ArgumentException("length");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A constructor allowing the specification of the length of the stream
|
||||
/// to read, as well as whether to keep the underlying stream open upon
|
||||
/// Close(), and the CRC32 instance to use.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the specified CRC32 instance, which allows the
|
||||
/// application to specify how the CRC gets calculated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="length">The length of the stream to slurp</param>
|
||||
/// <param name="leaveOpen">true to leave the underlying stream
|
||||
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
|
||||
/// <param name="crc32">the CRC32 instance to use to calculate the CRC32</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen,
|
||||
CRC32 crc32)
|
||||
: this(leaveOpen, length, stream, crc32)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new ArgumentException("length");
|
||||
}
|
||||
|
||||
|
||||
// This ctor is private - no validation is done here. This is to allow the use
|
||||
// of a (specific) negative value for the _lengthLimit, to indicate that there
|
||||
// is no length set. So we validate the length limit in those ctors that use an
|
||||
// explicit param, otherwise we don't validate, because it could be our special
|
||||
// value.
|
||||
private CrcCalculatorStream
|
||||
(bool leaveOpen, Int64 length, System.IO.Stream stream, CRC32 crc32)
|
||||
: base()
|
||||
{
|
||||
_innerStream = stream;
|
||||
_Crc32 = crc32 ?? new CRC32();
|
||||
_lengthLimit = length;
|
||||
_leaveOpen = leaveOpen;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of bytes run through the CRC32 calculator.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// This is either the total number of bytes read, or the total number of
|
||||
/// bytes written, depending on the direction of this stream.
|
||||
/// </remarks>
|
||||
public Int64 TotalBytesSlurped
|
||||
{
|
||||
get { return _Crc32.TotalBytesRead; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides the current CRC for all blocks slurped in.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The running total of the CRC is kept as data is written or read
|
||||
/// through the stream. read this property after all reads or writes to
|
||||
/// get an accurate CRC for the entire stream.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public Int32 Crc
|
||||
{
|
||||
get { return _Crc32.Crc32Result; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the underlying stream will be left open when the
|
||||
/// <c>CrcCalculatorStream</c> is Closed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Set this at any point before calling <see cref="Close()"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool LeaveOpen
|
||||
{
|
||||
get { return _leaveOpen; }
|
||||
set { _leaveOpen = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from the stream
|
||||
/// </summary>
|
||||
/// <param name="buffer">the buffer to read</param>
|
||||
/// <param name="offset">the offset at which to start</param>
|
||||
/// <param name="count">the number of bytes to read</param>
|
||||
/// <returns>the number of bytes actually read</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int bytesToRead = count;
|
||||
|
||||
// Need to limit the # of bytes returned, if the stream is intended to have
|
||||
// a definite length. This is especially useful when returning a stream for
|
||||
// the uncompressed data directly to the application. The app won't
|
||||
// necessarily read only the UncompressedSize number of bytes. For example
|
||||
// wrapping the stream returned from OpenReader() into a StreadReader() and
|
||||
// calling ReadToEnd() on it, We can "over-read" the zip data and get a
|
||||
// corrupt string. The length limits that, prevents that problem.
|
||||
|
||||
if (_lengthLimit != CrcCalculatorStream.UnsetLengthLimit)
|
||||
{
|
||||
if (_Crc32.TotalBytesRead >= _lengthLimit) return 0; // EOF
|
||||
Int64 bytesRemaining = _lengthLimit - _Crc32.TotalBytesRead;
|
||||
if (bytesRemaining < count) bytesToRead = (int)bytesRemaining;
|
||||
}
|
||||
int n = _innerStream.Read(buffer, offset, bytesToRead);
|
||||
if (n > 0) _Crc32.SlurpBlock(buffer, offset, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write to the stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">the buffer from which to write</param>
|
||||
/// <param name="offset">the offset at which to start writing</param>
|
||||
/// <param name="count">the number of bytes to write</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (count > 0) _Crc32.SlurpBlock(buffer, offset, count);
|
||||
_innerStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream supports reading.
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return _innerStream.CanRead; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream supports seeking.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Always returns false.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream supports writing.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return _innerStream.CanWrite; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush the stream.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
_innerStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the length of the underlying stream.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_lengthLimit == CrcCalculatorStream.UnsetLengthLimit)
|
||||
return _innerStream.Length;
|
||||
else return _lengthLimit;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The getter for this property returns the total bytes read.
|
||||
/// If you use the setter, it will throw
|
||||
/// <see cref="NotSupportedException"/>.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get { return _Crc32.TotalBytesRead; }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seeking is not supported on this stream. This method always throws
|
||||
/// <see cref="NotSupportedException"/>
|
||||
/// </summary>
|
||||
/// <param name="offset">N/A</param>
|
||||
/// <param name="origin">N/A</param>
|
||||
/// <returns>N/A</returns>
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method always throws
|
||||
/// <see cref="NotSupportedException"/>
|
||||
/// </summary>
|
||||
/// <param name="value">N/A</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the stream.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
if (!_leaveOpen)
|
||||
_innerStream.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
96
SabreTools.IO/Compression/BZip2/Rand.cs
Normal file
96
SabreTools.IO/Compression/BZip2/Rand.cs
Normal file
@@ -0,0 +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 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
15
SabreTools.IO/Compression/Blast/Constants.cs
Normal file
15
SabreTools.IO/Compression/Blast/Constants.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace SabreTools.IO.Compression.Blast
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum code length
|
||||
/// </summary>
|
||||
public const int MAXBITS = 13;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum window size
|
||||
/// </summary>
|
||||
public const int MAXWIN = 4096;
|
||||
}
|
||||
}
|
||||
287
SabreTools.IO/Compression/Blast/Decompressor.cs
Normal file
287
SabreTools.IO/Compression/Blast/Decompressor.cs
Normal file
@@ -0,0 +1,287 @@
|
||||
/* blast.c
|
||||
* Copyright (C) 2003, 2012, 2013 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in blast.h
|
||||
* version 1.3, 24 Aug 2013
|
||||
*
|
||||
* blast.c decompresses data compressed by the PKWare Compression Library.
|
||||
* This function provides functionality similar to the explode() function of
|
||||
* the PKWare library, hence the name "blast".
|
||||
*
|
||||
* This decompressor is based on the excellent format description provided by
|
||||
* Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the
|
||||
* example Ben provided in the post is incorrect. The distance 110001 should
|
||||
* instead be 111000. When corrected, the example byte stream becomes:
|
||||
*
|
||||
* 00 04 82 24 25 8f 80 7f
|
||||
*
|
||||
* which decompresses to "AIAIAIAIAIAIA" (without the quotes).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Change history:
|
||||
*
|
||||
* 1.0 12 Feb 2003 - First version
|
||||
* 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data
|
||||
* 1.2 24 Oct 2012 - Add note about using binary mode in stdio
|
||||
* - Fix comparisons of differently signed integers
|
||||
* 1.3 24 Aug 2013 - Return unused input from blast()
|
||||
* - Fix test code to correctly report unused input
|
||||
* - Enable the provision of initial input to blast()
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using static SabreTools.IO.Compression.Blast.Constants;
|
||||
|
||||
namespace SabreTools.IO.Compression.Blast
|
||||
{
|
||||
/// <summary>
|
||||
/// blast() decompresses the PKWare Data Compression Library (DCL) compressed
|
||||
/// format. It provides the same functionality as the explode() function in
|
||||
/// 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 class Decompressor
|
||||
{
|
||||
#region Huffman Encoding
|
||||
|
||||
/// <summary>
|
||||
/// Literal code
|
||||
/// </summary>
|
||||
private readonly Huffman litcode = new(MAXBITS + 1, 256);
|
||||
|
||||
/// <summary>
|
||||
/// Length code
|
||||
/// </summary>
|
||||
private readonly Huffman lencode = new(MAXBITS + 1, 16);
|
||||
|
||||
/// <summary>
|
||||
/// Distance code
|
||||
/// </summary>
|
||||
private readonly Huffman distcode = new(MAXBITS + 1, 64);
|
||||
|
||||
/// <summary>
|
||||
/// Base for length codes
|
||||
/// </summary>
|
||||
private static readonly short[] baseLength =
|
||||
[
|
||||
3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Extra bits for length codes
|
||||
/// </summary>
|
||||
private static readonly byte[] extra =
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8
|
||||
];
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Create a Blast decompressor
|
||||
/// </summary>
|
||||
private Decompressor()
|
||||
{
|
||||
// Repeated code lengths of literal codes
|
||||
byte[] litlen =
|
||||
[
|
||||
11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8,
|
||||
9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5,
|
||||
7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12,
|
||||
8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27,
|
||||
44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45,
|
||||
44, 173
|
||||
];
|
||||
litcode.Initialize(litlen);
|
||||
|
||||
// Repeated code lengths of length codes 0..15
|
||||
byte[] lenlen =
|
||||
[
|
||||
2, 35, 36, 53, 38, 23
|
||||
];
|
||||
lencode.Initialize(lenlen);
|
||||
|
||||
// Repeated code lengths of distance codes 0..63
|
||||
byte[] distlen =
|
||||
[
|
||||
2, 20, 53, 230, 247, 151, 248
|
||||
];
|
||||
distcode.Initialize(distlen);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a Blast decompressor
|
||||
/// </summary>
|
||||
public static Decompressor Create() => new();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Decompress source data to an output stream
|
||||
/// </summary>
|
||||
public bool CopyTo(byte[] source, Stream dest)
|
||||
=> CopyTo(new MemoryStream(source), dest);
|
||||
|
||||
/// <summary>
|
||||
/// Decompress source data to an output stream
|
||||
/// </summary>
|
||||
public bool CopyTo(Stream source, Stream dest)
|
||||
{
|
||||
// Ignore unwritable streams
|
||||
if (!dest.CanWrite)
|
||||
return false;
|
||||
|
||||
// Input/output state
|
||||
var state = new State(source, dest);
|
||||
|
||||
// Attempt to decompress using the above state
|
||||
int err;
|
||||
try
|
||||
{
|
||||
err = Decompress(state);
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
// This was originally a jump, which is bad form for C#
|
||||
err = 2;
|
||||
}
|
||||
|
||||
// Write any leftover output and update the error code if needed
|
||||
if (err != 1 && state.Next != 0 && !state.ProcessOutput() && err == 0)
|
||||
err = 1;
|
||||
|
||||
return err == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode PKWare Compression Library stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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
|
||||
/// twelve copies the last four bytes three times. A simple forward copy
|
||||
/// ignoring whether the length is greater than the distance or not implements
|
||||
/// this correctly.
|
||||
/// </remarks>
|
||||
private int Decompress(State state)
|
||||
{
|
||||
int symbol; // decoded symbol, extra bits for distance
|
||||
int len; // length for copy
|
||||
uint dist; // distance for copy
|
||||
int copy; // copy counter
|
||||
int from, to; // copy pointers
|
||||
|
||||
// Read header
|
||||
int lit = state.ReadBits(8); // true if literals are coded
|
||||
if (lit > 1)
|
||||
return -1;
|
||||
|
||||
int dict = state.ReadBits(8); // log2(dictionary size) - 6
|
||||
if (dict < 4 || dict > 6)
|
||||
return -2;
|
||||
|
||||
// Decode literals and length/distance pairs
|
||||
while (true)
|
||||
{
|
||||
if (state.ReadBits(1) != 0)
|
||||
{
|
||||
// Get length
|
||||
symbol = lencode.Decode(state);
|
||||
len = baseLength[symbol] + state.ReadBits(extra[symbol]);
|
||||
if (len == 519)
|
||||
break; // end code
|
||||
|
||||
// Get distance
|
||||
symbol = len == 2 ? 2 : dict;
|
||||
dist = (uint)(distcode.Decode(state) << symbol);
|
||||
dist += (uint)state.ReadBits(symbol);
|
||||
dist++;
|
||||
if (state.First && dist > state.Next)
|
||||
return -3; //distance too far back
|
||||
|
||||
// Copy length bytes from distance bytes back
|
||||
do
|
||||
{
|
||||
to = (int)state.Next;
|
||||
from = (int)(to - dist);
|
||||
copy = MAXWIN;
|
||||
if (state.Next < dist)
|
||||
{
|
||||
from += copy;
|
||||
copy = (int)dist;
|
||||
}
|
||||
|
||||
copy -= (int)state.Next;
|
||||
if (copy > len)
|
||||
copy = len;
|
||||
|
||||
len -= copy;
|
||||
state.Next += (uint)copy;
|
||||
state.CopyOutputBytes(to, from, copy);
|
||||
|
||||
if (state.Next == MAXWIN)
|
||||
{
|
||||
if (!state.ProcessOutput())
|
||||
return 1;
|
||||
|
||||
state.Next = 0;
|
||||
state.First = false;
|
||||
}
|
||||
}
|
||||
while (len != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get literal and write it
|
||||
symbol = lit != 0 ? litcode.Decode(state) : state.ReadBits(8);
|
||||
state.WriteToOutput((byte)symbol);
|
||||
if (state.Next == MAXWIN)
|
||||
{
|
||||
if (!state.ProcessOutput())
|
||||
return 1;
|
||||
|
||||
state.Next = 0;
|
||||
state.First = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
198
SabreTools.IO/Compression/Blast/Huffman.cs
Normal file
198
SabreTools.IO/Compression/Blast/Huffman.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using static SabreTools.IO.Compression.Blast.Constants;
|
||||
|
||||
namespace SabreTools.IO.Compression.Blast
|
||||
{
|
||||
/// <summary>
|
||||
/// Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of
|
||||
/// each length, which for a canonical code are stepped through in order.
|
||||
/// symbol[] are the symbol values in canonical order, where the number of
|
||||
/// entries is the sum of the counts in count[]. The decoding process can be
|
||||
/// seen in the function decode() below.
|
||||
/// </summary>
|
||||
public class Huffman
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of symbols of each length
|
||||
/// </summary>
|
||||
public short[] Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pointer to number of symbols of each length
|
||||
/// </summary>
|
||||
public int CountPtr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Canonically ordered symbols
|
||||
/// </summary>
|
||||
public short[] Symbol { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="countLength">Length of the Count array</param>
|
||||
/// <param name="symbolLength">Length of the Symbol array</param>
|
||||
public Huffman(int countLength, int symbolLength)
|
||||
{
|
||||
Count = new short[countLength];
|
||||
Symbol = new short[symbolLength];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a list of repeated code lengths rep[0..n-1], where each byte is a
|
||||
/// count (high four bits + 1) and a code length (low four bits), generate the
|
||||
/// list of code lengths. This compaction reduces the size of the object code.
|
||||
/// Then given the list of code lengths length[0..n-1] representing a canonical
|
||||
/// Huffman code for n symbols, construct the tables required to decode those
|
||||
/// codes. Those tables are the number of codes of each length, and the symbols
|
||||
/// sorted by length, retaining their original order within each length. The
|
||||
/// return value is zero for a complete code set, negative for an over-
|
||||
/// subscribed code set, and positive for an incomplete code set. The tables
|
||||
/// can be used if the return value is zero or positive, but they cannot be used
|
||||
/// if the return value is negative. If the return value is zero, it is not
|
||||
/// possible for decode() using that table to return an error--any stream of
|
||||
/// enough bits will resolve to a symbol. If the return value is positive, then
|
||||
/// it is possible for decode() using that table to return an error for received
|
||||
/// codes past the end of the incomplete lengths.
|
||||
/// </summary>
|
||||
/// <param name="rep">Repeated code length array</param>
|
||||
public int Initialize(byte[] rep)
|
||||
{
|
||||
int n = rep.Length; // Length of the bit length array
|
||||
short symbol = 0; // Current symbol when stepping through length[]
|
||||
short len; // Current length when stepping through h.Count[]
|
||||
int left; // Number of possible codes left of current length
|
||||
short[] offs = new short[MAXBITS + 1]; // offsets in symbol table for each length
|
||||
short[] length = new short[256]; // Code lengths
|
||||
|
||||
// Convert compact repeat counts into symbol bit length list
|
||||
int repPtr = 0;
|
||||
do
|
||||
{
|
||||
len = rep[repPtr++];
|
||||
left = (len >> 4) + 1;
|
||||
len &= 15;
|
||||
do
|
||||
{
|
||||
length[symbol++] = len;
|
||||
}
|
||||
while (--left != 0);
|
||||
}
|
||||
while (--n != 0);
|
||||
|
||||
n = symbol;
|
||||
|
||||
// Count number of codes of each length
|
||||
for (len = 0; len <= MAXBITS; len++)
|
||||
{
|
||||
Count[len] = 0;
|
||||
}
|
||||
|
||||
// Assumes lengths are within bounds
|
||||
for (symbol = 0; symbol < n; symbol++)
|
||||
{
|
||||
Count[length[symbol]]++;
|
||||
}
|
||||
|
||||
// No codes! Complete, but decode() will fail
|
||||
if (Count[0] == n)
|
||||
return 0;
|
||||
|
||||
// Check for an over-subscribed or incomplete set of lengths
|
||||
left = 1; // One possible code of zero length
|
||||
for (len = 1; len <= MAXBITS; len++)
|
||||
{
|
||||
left <<= 1; // One more bit, double codes left
|
||||
left -= Count[len]; // Deduct count from possible codes
|
||||
if (left < 0)
|
||||
return left; // over-subscribed--return negative
|
||||
}
|
||||
|
||||
// Generate offsets into symbol table for each length for sorting
|
||||
offs[1] = 0;
|
||||
for (len = 1; len < MAXBITS; len++)
|
||||
{
|
||||
offs[len + 1] = (short)(offs[len] + Count[len]);
|
||||
}
|
||||
|
||||
// Put symbols in table sorted by length, by symbol order within each length
|
||||
for (symbol = 0; symbol < n; symbol++)
|
||||
{
|
||||
if (length[symbol] != 0)
|
||||
Symbol[offs[length[symbol]]++] = symbol;
|
||||
}
|
||||
|
||||
// Return zero for complete set, positive for incomplete set
|
||||
return left;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decode a code from the stream s using huffman table h. Return the symbol or
|
||||
/// a negative value if there is an error. If all of the lengths are zero, i.e.
|
||||
/// an empty code, or if the code is incomplete and an invalid code is received,
|
||||
/// then -9 is returned after reading MAXBITS bits.
|
||||
/// </summary>
|
||||
/// <param name="state">Current input/output state to process</param>
|
||||
/// <remarks>
|
||||
/// The codes as stored in the compressed data are bit-reversed relative to
|
||||
/// a simple integer ordering of codes of the same lengths. Hence below the
|
||||
/// 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
|
||||
/// code, the last code of the longest length will be all zeros. To support
|
||||
/// this ordering, the bits pulled during decoding are inverted to apply the
|
||||
/// more "natural" ordering starting with all zeros and incrementing.
|
||||
/// </remarks>
|
||||
public int Decode(State state)
|
||||
{
|
||||
int len = 1; // Current number of bits in code
|
||||
int code = 0; // len bits being decoded
|
||||
int first = 0; // First code of length len
|
||||
int count; // Number of codes of length len
|
||||
int index = 0; // Index of first code of length len in symbol table
|
||||
int bitbuf = state.BitBuf; // Bits from stream
|
||||
int left = state.BitCnt; // Bits left in next or left to process
|
||||
int nextPtr = CountPtr + 1; // Next number of codes
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (left-- != 0)
|
||||
{
|
||||
// Invert code
|
||||
code |= (bitbuf & 1) ^ 1;
|
||||
bitbuf >>= 1;
|
||||
count = Count[nextPtr++];
|
||||
|
||||
// If length len, return symbol
|
||||
if (code < first + count)
|
||||
{
|
||||
state.BitBuf = bitbuf;
|
||||
state.BitCnt = (state.BitCnt - len) & 7;
|
||||
return Symbol[index + (code - first)];
|
||||
}
|
||||
|
||||
// Else update for next length
|
||||
index += count;
|
||||
first += count;
|
||||
first <<= 1;
|
||||
code <<= 1;
|
||||
len++;
|
||||
}
|
||||
|
||||
left = MAXBITS + 1 - len;
|
||||
if (left == 0)
|
||||
break;
|
||||
|
||||
bitbuf = state.ReadNextByte();
|
||||
if (left > 8)
|
||||
left = 8;
|
||||
}
|
||||
|
||||
// Ran out of codes
|
||||
return -9;
|
||||
}
|
||||
};
|
||||
}
|
||||
183
SabreTools.IO/Compression/Blast/State.cs
Normal file
183
SabreTools.IO/Compression/Blast/State.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using static SabreTools.IO.Compression.Blast.Constants;
|
||||
|
||||
namespace SabreTools.IO.Compression.Blast
|
||||
{
|
||||
/// <summary>
|
||||
/// Input and output state
|
||||
/// </summary>
|
||||
public class State
|
||||
{
|
||||
#region Input State
|
||||
|
||||
/// <summary>
|
||||
/// Opaque information passed to InputFunction()
|
||||
/// </summary>
|
||||
private readonly Stream _source;
|
||||
|
||||
/// <summary>
|
||||
/// Next input location
|
||||
/// </summary>
|
||||
private readonly byte[] _input = new byte[MAXWIN];
|
||||
|
||||
/// <summary>
|
||||
/// Pointer to the next input location
|
||||
/// </summary>
|
||||
private int _inputPtr;
|
||||
|
||||
/// <summary>
|
||||
/// Available input at in
|
||||
/// </summary>
|
||||
private uint _available;
|
||||
|
||||
/// <summary>
|
||||
/// Bit buffer
|
||||
/// </summary>
|
||||
public int BitBuf { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of bits in bit buffer
|
||||
/// </summary>
|
||||
public int BitCnt { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Output State
|
||||
|
||||
/// <summary>
|
||||
/// Opaque information passed to OutputFunction()
|
||||
/// </summary>
|
||||
private readonly Stream _dest;
|
||||
|
||||
/// <summary>
|
||||
/// Index of next write location in out[]
|
||||
/// </summary>
|
||||
public uint Next { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True to check distances (for first 4K)
|
||||
/// </summary>
|
||||
public bool First { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Output buffer and sliding window
|
||||
/// </summary>
|
||||
private readonly byte[] _output = new byte[MAXWIN];
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public State(Stream source, Stream dest)
|
||||
{
|
||||
_source = source;
|
||||
_inputPtr = 0;
|
||||
_available = 0;
|
||||
BitBuf = 0;
|
||||
BitCnt = 0;
|
||||
|
||||
_dest = dest;
|
||||
Next = 0;
|
||||
First = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy bytes in the output buffer between locations
|
||||
/// </summary>
|
||||
public void CopyOutputBytes(int to, int from, int len)
|
||||
{
|
||||
do
|
||||
{
|
||||
_output[to++] = _output[from++];
|
||||
}
|
||||
while (--len > 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return need bits from the input stream. This always leaves less than
|
||||
/// eight bits in the buffer. bits() works properly for need == 0.
|
||||
/// </summary>
|
||||
/// <param name="need">Number of bits to read</param>
|
||||
/// <remarks>
|
||||
/// Bits are stored in bytes from the least significant bit to the most
|
||||
/// significant bit. Therefore bits are dropped from the bottom of the bit
|
||||
/// buffer, using shift right, and new bytes are appended to the top of the
|
||||
/// bit buffer, using shift left.
|
||||
/// </remarks>
|
||||
public int ReadBits(int need)
|
||||
{
|
||||
// Load at least need bits into val
|
||||
int val = BitBuf;
|
||||
while (BitCnt < need)
|
||||
{
|
||||
// Load eight bits
|
||||
EnsureAvailable();
|
||||
val |= _input[_inputPtr++] << BitCnt;
|
||||
BitCnt += 8;
|
||||
}
|
||||
|
||||
// Drop need bits and update buffer, always zero to seven bits left
|
||||
BitBuf = val >> need;
|
||||
BitCnt -= need;
|
||||
|
||||
// Return need bits, zeroing the bits above that
|
||||
return val & ((1 << need) - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process output for the current state
|
||||
/// </summary>
|
||||
/// <returns>True if the output could be added, false otherwise</returns>
|
||||
public bool ProcessOutput()
|
||||
{
|
||||
try
|
||||
{
|
||||
_dest.Write(_output, 0, (int)Next);
|
||||
_dest.Flush();
|
||||
|
||||
Next = 0;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the next byte from the input buffer
|
||||
/// </summary>
|
||||
public byte ReadNextByte()
|
||||
{
|
||||
EnsureAvailable();
|
||||
return _input[_inputPtr++];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a byte value to the output buffer
|
||||
/// </summary>
|
||||
public void WriteToOutput(byte value)
|
||||
=> _output[Next++] = value;
|
||||
|
||||
/// <summary>
|
||||
/// Ensure there are bytes available, if possible
|
||||
/// </summary>
|
||||
/// <exception cref="IndexOutOfRangeException"></exception>
|
||||
private void EnsureAvailable()
|
||||
{
|
||||
// If there are bytes
|
||||
if (_available != 0 && _inputPtr < _available)
|
||||
return;
|
||||
|
||||
// Read the next block
|
||||
_available = (uint)_source.Read(_input, 0, MAXWIN);
|
||||
if (_available == 0)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
// Reset the pointer
|
||||
_inputPtr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
177
SabreTools.IO/Compression/Deflate/Adler.cs
Normal file
177
SabreTools.IO/Compression/Deflate/Adler.cs
Normal file
@@ -0,0 +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
|
||||
{
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
78
SabreTools.IO/Compression/Deflate/BlockState.cs
Normal file
78
SabreTools.IO/Compression/Deflate/BlockState.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
// Deflate.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: <2011-August-03 19:52:15>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines logic for handling the Deflate or compression.
|
||||
//
|
||||
// This code is based on multiple sources:
|
||||
// - the original zlib v1.2.3 source, which is Copyright (C) 1995-2005 Jean-loup Gailly.
|
||||
// - the original jzlib, which is Copyright (c) 2000-2003 ymnk, JCraft,Inc.
|
||||
//
|
||||
// However, this code is significantly different from both.
|
||||
// The object model is not the same, and many of the behaviors are different.
|
||||
//
|
||||
// In keeping with the license for these other works, the copyrights for
|
||||
// jzlib and zlib are 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
|
||||
{
|
||||
internal enum BlockState
|
||||
{
|
||||
NeedMore = 0, // block not completed, need more input or more output
|
||||
BlockDone, // block flush performed
|
||||
FinishStarted, // finish started, need only more output at next deflate
|
||||
FinishDone // finish done, accept no more input or output
|
||||
}
|
||||
}
|
||||
824
SabreTools.IO/Compression/Deflate/CRC32.cs
Normal file
824
SabreTools.IO/Compression/Deflate/CRC32.cs
Normal file
@@ -0,0 +1,824 @@
|
||||
// CRC32.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-August-02 18:25:54>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines the CRC32 class, which can do the CRC32 algorithm, using
|
||||
// arbitrary starting polynomials, and bit reversal. The bit reversal is what
|
||||
// distinguishes this CRC-32 used in BZip2 from the CRC-32 that is used in PKZIP
|
||||
// files, or GZIP files. This class does both.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using Interop = System.Runtime.InteropServices;
|
||||
|
||||
#nullable disable
|
||||
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
|
||||
/// reversal. This can be used for GZIP, BZip2, or ZIP.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This type is used internally by DotNetZip; it is generally not used
|
||||
/// directly by applications wishing to create, read, or manipulate zip
|
||||
/// archive files.
|
||||
/// </remarks>
|
||||
|
||||
[Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000C")]
|
||||
[Interop.ComVisible(true)]
|
||||
#if !NETCF
|
||||
[Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
|
||||
#endif
|
||||
public class CRC32
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the total number of bytes applied to the CRC.
|
||||
/// </summary>
|
||||
public Int64 TotalBytesRead
|
||||
{
|
||||
get
|
||||
{
|
||||
return _TotalBytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the current CRC for all blocks slurped in.
|
||||
/// </summary>
|
||||
public Int32 Crc32Result
|
||||
{
|
||||
get
|
||||
{
|
||||
return unchecked((Int32)(~_register));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the CRC32 for the specified stream.
|
||||
/// </summary>
|
||||
/// <param name="input">The stream over which to calculate the CRC32</param>
|
||||
/// <returns>the CRC32 calculation</returns>
|
||||
public Int32 GetCrc32(System.IO.Stream input)
|
||||
{
|
||||
return GetCrc32AndCopy(input, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the CRC32 for the specified stream, and writes the input into the
|
||||
/// output stream.
|
||||
/// </summary>
|
||||
/// <param name="input">The stream over which to calculate the CRC32</param>
|
||||
/// <param name="output">The stream into which to deflate the input</param>
|
||||
/// <returns>the CRC32 calculation</returns>
|
||||
public Int32 GetCrc32AndCopy(System.IO.Stream input, System.IO.Stream output)
|
||||
{
|
||||
if (input is null)
|
||||
throw new Exception("The input stream must not be null.");
|
||||
|
||||
unchecked
|
||||
{
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int readSize = BUFFER_SIZE;
|
||||
|
||||
_TotalBytesRead = 0;
|
||||
int count = input.Read(buffer, 0, readSize);
|
||||
output?.Write(buffer, 0, count);
|
||||
_TotalBytesRead += count;
|
||||
while (count > 0)
|
||||
{
|
||||
SlurpBlock(buffer, 0, count);
|
||||
count = input.Read(buffer, 0, readSize);
|
||||
output?.Write(buffer, 0, count);
|
||||
_TotalBytesRead += count;
|
||||
}
|
||||
|
||||
return (Int32)(~_register);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the CRC32 for the given (word,byte) combo. This is a
|
||||
/// computation defined by PKzip for PKZIP 2.0 (weak) encryption.
|
||||
/// </summary>
|
||||
/// <param name="W">The word to start with.</param>
|
||||
/// <param name="B">The byte to combine it with.</param>
|
||||
/// <returns>The CRC-ized result.</returns>
|
||||
public Int32 ComputeCrc32(Int32 W, byte B)
|
||||
{
|
||||
return _InternalComputeCrc32((UInt32)W, B);
|
||||
}
|
||||
|
||||
internal Int32 _InternalComputeCrc32(UInt32 W, byte B)
|
||||
{
|
||||
return (Int32)(crc32Table[(W ^ B) & 0xFF] ^ (W >> 8));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Update the value for the running CRC32 using the given block of bytes.
|
||||
/// This is useful when using the CRC32() class in a Stream.
|
||||
/// </summary>
|
||||
/// <param name="block">block of bytes to slurp</param>
|
||||
/// <param name="offset">starting point in the block</param>
|
||||
/// <param name="count">how many bytes within the block to slurp</param>
|
||||
public void SlurpBlock(byte[] block, int offset, int count)
|
||||
{
|
||||
if (block is null)
|
||||
throw new Exception("The data buffer must not be null.");
|
||||
|
||||
// bzip algorithm
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int x = offset + i;
|
||||
byte b = block[x];
|
||||
if (this.reverseBits)
|
||||
{
|
||||
UInt32 temp = (_register >> 24) ^ b;
|
||||
_register = (_register << 8) ^ crc32Table[temp];
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 temp = (_register & 0x000000FF) ^ b;
|
||||
_register = (_register >> 8) ^ crc32Table[temp];
|
||||
}
|
||||
}
|
||||
_TotalBytesRead += count;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Process one byte in the CRC.
|
||||
/// </summary>
|
||||
/// <param name = "b">the byte to include into the CRC . </param>
|
||||
public void UpdateCRC(byte b)
|
||||
{
|
||||
if (this.reverseBits)
|
||||
{
|
||||
UInt32 temp = (_register >> 24) ^ b;
|
||||
_register = (_register << 8) ^ crc32Table[temp];
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 temp = (_register & 0x000000FF) ^ b;
|
||||
_register = (_register >> 8) ^ crc32Table[temp];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a run of N identical bytes into the CRC.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method serves as an optimization for updating the CRC when a
|
||||
/// run of identical bytes is found. Rather than passing in a buffer of
|
||||
/// length n, containing all identical bytes b, this method accepts the
|
||||
/// byte value and the length of the (virtual) buffer - the length of
|
||||
/// the run.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name = "b">the byte to include into the CRC. </param>
|
||||
/// <param name = "n">the number of times that byte should be repeated. </param>
|
||||
public void UpdateCRC(byte b, int n)
|
||||
{
|
||||
while (n-- > 0)
|
||||
{
|
||||
if (this.reverseBits)
|
||||
{
|
||||
uint temp = (_register >> 24) ^ b;
|
||||
_register = (_register << 8) ^ crc32Table[(temp >= 0)
|
||||
? temp
|
||||
: (temp + 256)];
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 temp = (_register & 0x000000FF) ^ b;
|
||||
_register = (_register >> 8) ^ crc32Table[(temp >= 0)
|
||||
? temp
|
||||
: (temp + 256)];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static uint ReverseBits(uint data)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint ret = data;
|
||||
ret = (ret & 0x55555555) << 1 | (ret >> 1) & 0x55555555;
|
||||
ret = (ret & 0x33333333) << 2 | (ret >> 2) & 0x33333333;
|
||||
ret = (ret & 0x0F0F0F0F) << 4 | (ret >> 4) & 0x0F0F0F0F;
|
||||
ret = (ret << 24) | ((ret & 0xFF00) << 8) | ((ret >> 8) & 0xFF00) | (ret >> 24);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte ReverseBits(byte data)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint u = (uint)data * 0x00020202;
|
||||
uint m = 0x01044010;
|
||||
uint s = u & m;
|
||||
uint t = (u << 2) & (m << 1);
|
||||
return (byte)((0x01001001 * (s + t)) >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void GenerateLookupTable()
|
||||
{
|
||||
crc32Table = new UInt32[256];
|
||||
unchecked
|
||||
{
|
||||
UInt32 dwCrc;
|
||||
byte i = 0;
|
||||
do
|
||||
{
|
||||
dwCrc = i;
|
||||
for (byte j = 8; j > 0; j--)
|
||||
{
|
||||
if ((dwCrc & 1) == 1)
|
||||
{
|
||||
dwCrc = (dwCrc >> 1) ^ dwPolynomial;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwCrc >>= 1;
|
||||
}
|
||||
}
|
||||
if (reverseBits)
|
||||
{
|
||||
crc32Table[ReverseBits(i)] = ReverseBits(dwCrc);
|
||||
}
|
||||
else
|
||||
{
|
||||
crc32Table[i] = dwCrc;
|
||||
}
|
||||
i++;
|
||||
} while (i != 0);
|
||||
}
|
||||
|
||||
#if VERBOSE
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("private static readonly UInt32[] crc32Table = {");
|
||||
for (int i = 0; i < crc32Table.Length; i+=4)
|
||||
{
|
||||
Console.Write(" ");
|
||||
for (int j=0; j < 4; j++)
|
||||
{
|
||||
Console.Write(" 0x{0:X8}U,", crc32Table[i+j]);
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
Console.WriteLine("};");
|
||||
Console.WriteLine();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
private uint gf2_matrix_times(uint[] matrix, uint vec)
|
||||
{
|
||||
uint sum = 0;
|
||||
int i = 0;
|
||||
while (vec != 0)
|
||||
{
|
||||
if ((vec & 0x01) == 0x01)
|
||||
sum ^= matrix[i];
|
||||
vec >>= 1;
|
||||
i++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
private void gf2_matrix_square(uint[] square, uint[] mat)
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
square[i] = gf2_matrix_times(mat, mat[i]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Combines the given CRC32 value with the current running total.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is useful when using a divide-and-conquer approach to
|
||||
/// calculating a CRC. Multiple threads can each calculate a
|
||||
/// CRC32 on a segment of the data, and then combine the
|
||||
/// individual CRC32 values at the end.
|
||||
/// </remarks>
|
||||
/// <param name="crc">the crc value to be combined with this one</param>
|
||||
/// <param name="length">the length of data the CRC value was calculated on</param>
|
||||
public void Combine(int crc, int length)
|
||||
{
|
||||
uint[] even = new uint[32]; // even-power-of-two zeros operator
|
||||
uint[] odd = new uint[32]; // odd-power-of-two zeros operator
|
||||
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
uint crc1 = ~_register;
|
||||
uint crc2 = (uint)crc;
|
||||
|
||||
// put operator for one zero bit in odd
|
||||
odd[0] = this.dwPolynomial; // the CRC-32 polynomial
|
||||
uint row = 1;
|
||||
for (int i = 1; i < 32; i++)
|
||||
{
|
||||
odd[i] = row;
|
||||
row <<= 1;
|
||||
}
|
||||
|
||||
// put operator for two zero bits in even
|
||||
gf2_matrix_square(even, odd);
|
||||
|
||||
// put operator for four zero bits in odd
|
||||
gf2_matrix_square(odd, even);
|
||||
|
||||
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
|
||||
{
|
||||
// apply zeros operator for this bit of len2
|
||||
gf2_matrix_square(even, odd);
|
||||
|
||||
if ((len2 & 1) == 1)
|
||||
crc1 = gf2_matrix_times(even, crc1);
|
||||
len2 >>= 1;
|
||||
|
||||
if (len2 == 0)
|
||||
break;
|
||||
|
||||
// another iteration of the loop with odd and even swapped
|
||||
gf2_matrix_square(odd, even);
|
||||
if ((len2 & 1) == 1)
|
||||
crc1 = gf2_matrix_times(odd, crc1);
|
||||
len2 >>= 1;
|
||||
|
||||
|
||||
} while (len2 != 0);
|
||||
|
||||
crc1 ^= crc2;
|
||||
|
||||
_register = ~crc1;
|
||||
|
||||
//return (int) crc1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of the CRC32 class using the default settings: no
|
||||
/// bit reversal, and a polynomial of 0xEDB88320.
|
||||
/// </summary>
|
||||
public CRC32() : this(false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of the CRC32 class, specifying whether to reverse
|
||||
/// data bits or not.
|
||||
/// </summary>
|
||||
/// <param name='reverseBits'>
|
||||
/// specify true if the instance should reverse data bits.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
|
||||
/// want a CRC32 with compatibility with BZip2, you should pass true
|
||||
/// here. In the CRC-32 used by GZIP and PKZIP, the bits are not
|
||||
/// reversed; Therefore if you want a CRC32 with compatibility with
|
||||
/// those, you should pass false.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public CRC32(bool reverseBits) :
|
||||
this(unchecked((int)0xEDB88320), reverseBits)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of the CRC32 class, specifying the polynomial and
|
||||
/// whether to reverse data bits or not.
|
||||
/// </summary>
|
||||
/// <param name='polynomial'>
|
||||
/// The polynomial to use for the CRC, expressed in the reversed (LSB)
|
||||
/// format: the highest ordered bit in the polynomial value is the
|
||||
/// coefficient of the 0th power; the second-highest order bit is the
|
||||
/// coefficient of the 1 power, and so on. Expressed this way, the
|
||||
/// polynomial for the CRC-32C used in IEEE 802.3, is 0xEDB88320.
|
||||
/// </param>
|
||||
/// <param name='reverseBits'>
|
||||
/// specify true if the instance should reverse data bits.
|
||||
/// </param>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
|
||||
/// want a CRC32 with compatibility with BZip2, you should pass true
|
||||
/// here for the <c>reverseBits</c> parameter. In the CRC-32 used by
|
||||
/// GZIP and PKZIP, the bits are not reversed; Therefore if you want a
|
||||
/// CRC32 with compatibility with those, you should pass false for the
|
||||
/// <c>reverseBits</c> parameter.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public CRC32(int polynomial, bool reverseBits)
|
||||
{
|
||||
this.reverseBits = reverseBits;
|
||||
this.dwPolynomial = (uint)polynomial;
|
||||
this.GenerateLookupTable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the CRC-32 class - clear the CRC "remainder register."
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Use this when employing a single instance of this class to compute
|
||||
/// multiple, distinct CRCs on multiple, distinct data blocks.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void Reset()
|
||||
{
|
||||
_register = 0xFFFFFFFFU;
|
||||
}
|
||||
|
||||
// private member vars
|
||||
private readonly UInt32 dwPolynomial;
|
||||
private Int64 _TotalBytesRead;
|
||||
private readonly bool reverseBits;
|
||||
private UInt32[] crc32Table;
|
||||
private const int BUFFER_SIZE = 8192;
|
||||
private UInt32 _register = 0xFFFFFFFFU;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A Stream that calculates a CRC32 (a checksum) on all bytes read,
|
||||
/// or on all bytes written.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This class can be used to verify the CRC of a ZipEntry when
|
||||
/// reading from a stream, or to calculate a CRC when writing to a
|
||||
/// stream. The stream should be used to either read, or write, but
|
||||
/// not both. If you intermix reads and writes, the results are not
|
||||
/// defined.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// This class is intended primarily for use internally by the
|
||||
/// DotNetZip library.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class CrcCalculatorStream : System.IO.Stream, System.IDisposable
|
||||
{
|
||||
private static readonly Int64 UnsetLengthLimit = -99;
|
||||
|
||||
internal System.IO.Stream _innerStream;
|
||||
private readonly CRC32 _Crc32;
|
||||
private readonly Int64 _lengthLimit = -99;
|
||||
private bool _leaveOpen;
|
||||
|
||||
/// <summary>
|
||||
/// The default constructor.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Instances returned from this constructor will leave the underlying
|
||||
/// stream open upon Close(). The stream uses the default CRC32
|
||||
/// algorithm, which implies a polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream)
|
||||
: this(true, CrcCalculatorStream.UnsetLengthLimit, stream, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The constructor allows the caller to specify how to handle the
|
||||
/// underlying stream at close.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the default CRC32 algorithm, which implies a
|
||||
/// polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="leaveOpen">true to leave the underlying stream
|
||||
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, bool leaveOpen)
|
||||
: this(leaveOpen, CrcCalculatorStream.UnsetLengthLimit, stream, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A constructor allowing the specification of the length of the stream
|
||||
/// to read.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the default CRC32 algorithm, which implies a
|
||||
/// polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Instances returned from this constructor will leave the underlying
|
||||
/// stream open upon Close().
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="length">The length of the stream to slurp</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, Int64 length)
|
||||
: this(true, length, stream, null)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new ArgumentException("length");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A constructor allowing the specification of the length of the stream
|
||||
/// to read, as well as whether to keep the underlying stream open upon
|
||||
/// Close().
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the default CRC32 algorithm, which implies a
|
||||
/// polynomial of 0xEDB88320.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="length">The length of the stream to slurp</param>
|
||||
/// <param name="leaveOpen">true to leave the underlying stream
|
||||
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen)
|
||||
: this(leaveOpen, length, stream, null)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new ArgumentException("length");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A constructor allowing the specification of the length of the stream
|
||||
/// to read, as well as whether to keep the underlying stream open upon
|
||||
/// Close(), and the CRC32 instance to use.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The stream uses the specified CRC32 instance, which allows the
|
||||
/// application to specify how the CRC gets calculated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="stream">The underlying stream</param>
|
||||
/// <param name="length">The length of the stream to slurp</param>
|
||||
/// <param name="leaveOpen">true to leave the underlying stream
|
||||
/// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
|
||||
/// <param name="crc32">the CRC32 instance to use to calculate the CRC32</param>
|
||||
public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen,
|
||||
CRC32 crc32)
|
||||
: this(leaveOpen, length, stream, crc32)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new ArgumentException("length");
|
||||
}
|
||||
|
||||
|
||||
// This ctor is private - no validation is done here. This is to allow the use
|
||||
// of a (specific) negative value for the _lengthLimit, to indicate that there
|
||||
// is no length set. So we validate the length limit in those ctors that use an
|
||||
// explicit param, otherwise we don't validate, because it could be our special
|
||||
// value.
|
||||
private CrcCalculatorStream
|
||||
(bool leaveOpen, Int64 length, System.IO.Stream stream, CRC32 crc32)
|
||||
: base()
|
||||
{
|
||||
_innerStream = stream;
|
||||
_Crc32 = crc32 ?? new CRC32();
|
||||
_lengthLimit = length;
|
||||
_leaveOpen = leaveOpen;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of bytes run through the CRC32 calculator.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// This is either the total number of bytes read, or the total number of
|
||||
/// bytes written, depending on the direction of this stream.
|
||||
/// </remarks>
|
||||
public Int64 TotalBytesSlurped
|
||||
{
|
||||
get { return _Crc32.TotalBytesRead; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides the current CRC for all blocks slurped in.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The running total of the CRC is kept as data is written or read
|
||||
/// through the stream. read this property after all reads or writes to
|
||||
/// get an accurate CRC for the entire stream.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public Int32 Crc
|
||||
{
|
||||
get { return _Crc32.Crc32Result; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the underlying stream will be left open when the
|
||||
/// <c>CrcCalculatorStream</c> is Closed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Set this at any point before calling <see cref="Close()"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool LeaveOpen
|
||||
{
|
||||
get { return _leaveOpen; }
|
||||
set { _leaveOpen = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from the stream
|
||||
/// </summary>
|
||||
/// <param name="buffer">the buffer to read</param>
|
||||
/// <param name="offset">the offset at which to start</param>
|
||||
/// <param name="count">the number of bytes to read</param>
|
||||
/// <returns>the number of bytes actually read</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int bytesToRead = count;
|
||||
|
||||
// Need to limit the # of bytes returned, if the stream is intended to have
|
||||
// a definite length. This is especially useful when returning a stream for
|
||||
// the uncompressed data directly to the application. The app won't
|
||||
// necessarily read only the UncompressedSize number of bytes. For example
|
||||
// wrapping the stream returned from OpenReader() into a StreadReader() and
|
||||
// calling ReadToEnd() on it, We can "over-read" the zip data and get a
|
||||
// corrupt string. The length limits that, prevents that problem.
|
||||
|
||||
if (_lengthLimit != CrcCalculatorStream.UnsetLengthLimit)
|
||||
{
|
||||
if (_Crc32.TotalBytesRead >= _lengthLimit) return 0; // EOF
|
||||
Int64 bytesRemaining = _lengthLimit - _Crc32.TotalBytesRead;
|
||||
if (bytesRemaining < count) bytesToRead = (int)bytesRemaining;
|
||||
}
|
||||
int n = _innerStream.Read(buffer, offset, bytesToRead);
|
||||
if (n > 0) _Crc32.SlurpBlock(buffer, offset, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write to the stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">the buffer from which to write</param>
|
||||
/// <param name="offset">the offset at which to start writing</param>
|
||||
/// <param name="count">the number of bytes to write</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (count > 0) _Crc32.SlurpBlock(buffer, offset, count);
|
||||
_innerStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream supports reading.
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return _innerStream.CanRead; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream supports seeking.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Always returns false.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream supports writing.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return _innerStream.CanWrite; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush the stream.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
_innerStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the length of the underlying stream.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_lengthLimit == CrcCalculatorStream.UnsetLengthLimit)
|
||||
return _innerStream.Length;
|
||||
else return _lengthLimit;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The getter for this property returns the total bytes read.
|
||||
/// If you use the setter, it will throw
|
||||
/// <see cref="NotSupportedException"/>.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get { return _Crc32.TotalBytesRead; }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seeking is not supported on this stream. This method always throws
|
||||
/// <see cref="NotSupportedException"/>
|
||||
/// </summary>
|
||||
/// <param name="offset">N/A</param>
|
||||
/// <param name="origin">N/A</param>
|
||||
/// <returns>N/A</returns>
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method always throws
|
||||
/// <see cref="NotSupportedException"/>
|
||||
/// </summary>
|
||||
/// <param name="value">N/A</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the stream.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
if (!_leaveOpen)
|
||||
_innerStream.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
167
SabreTools.IO/Compression/Deflate/CompressionLevel.cs
Normal file
167
SabreTools.IO/Compression/Deflate/CompressionLevel.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
// 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>
|
||||
/// The compression level to be used when using a DeflateStream or ZlibStream with CompressionMode.Compress.
|
||||
/// </summary>
|
||||
public enum CompressionLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// None means that the data will be simply stored, with no change at all.
|
||||
/// If you are producing ZIPs for use on Mac OSX, be aware that archives produced with CompressionLevel.None
|
||||
/// cannot be opened with the default zip reader. Use a different CompressionLevel.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// Same as None.
|
||||
/// </summary>
|
||||
Level0 = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The fastest but least effective compression.
|
||||
/// </summary>
|
||||
BestSpeed = 1,
|
||||
|
||||
/// <summary>
|
||||
/// A synonym for BestSpeed.
|
||||
/// </summary>
|
||||
Level1 = 1,
|
||||
|
||||
/// <summary>
|
||||
/// A little slower, but better, than level 1.
|
||||
/// </summary>
|
||||
Level2 = 2,
|
||||
|
||||
/// <summary>
|
||||
/// A little slower, but better, than level 2.
|
||||
/// </summary>
|
||||
Level3 = 3,
|
||||
|
||||
/// <summary>
|
||||
/// A little slower, but better, than level 3.
|
||||
/// </summary>
|
||||
Level4 = 4,
|
||||
|
||||
/// <summary>
|
||||
/// A little slower than level 4, but with better compression.
|
||||
/// </summary>
|
||||
Level5 = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The default compression level, with a good balance of speed and compression efficiency.
|
||||
/// </summary>
|
||||
Default = 6,
|
||||
/// <summary>
|
||||
/// A synonym for Default.
|
||||
/// </summary>
|
||||
Level6 = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Pretty good compression!
|
||||
/// </summary>
|
||||
Level7 = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Better compression than Level7!
|
||||
/// </summary>
|
||||
Level8 = 8,
|
||||
|
||||
/// <summary>
|
||||
/// The "best" compression, where best means greatest reduction in size of the input data stream.
|
||||
/// This is also the slowest compression.
|
||||
/// </summary>
|
||||
BestCompression = 9,
|
||||
|
||||
/// <summary>
|
||||
/// A synonym for BestCompression.
|
||||
/// </summary>
|
||||
Level9 = 9,
|
||||
}
|
||||
}
|
||||
105
SabreTools.IO/Compression/Deflate/CompressionMode.cs
Normal file
105
SabreTools.IO/Compression/Deflate/CompressionMode.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
// 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>
|
||||
/// An enum to specify the direction of transcoding - whether to compress or decompress.
|
||||
/// </summary>
|
||||
public enum CompressionMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to specify that the stream should compress the data.
|
||||
/// </summary>
|
||||
Compress = 0,
|
||||
/// <summary>
|
||||
/// Used to specify that the stream should decompress the data.
|
||||
/// </summary>
|
||||
Decompress = 1,
|
||||
}
|
||||
}
|
||||
118
SabreTools.IO/Compression/Deflate/CompressionStrategy.cs
Normal file
118
SabreTools.IO/Compression/Deflate/CompressionStrategy.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
// 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>
|
||||
/// Describes options for how the compression algorithm is executed. Different strategies
|
||||
/// work better on different sorts of data. The strategy parameter can affect the compression
|
||||
/// ratio and the speed of compression but not the correctness of the compresssion.
|
||||
/// </summary>
|
||||
public enum CompressionStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// The default strategy is probably the best for normal data.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The <c>Filtered</c> strategy is intended to be used most effectively with data produced by a
|
||||
/// filter or predictor. By this definition, filtered data consists mostly of small
|
||||
/// values with a somewhat random distribution. In this case, the compression algorithm
|
||||
/// is tuned to compress them better. The effect of <c>Filtered</c> is to force more Huffman
|
||||
/// coding and less string matching; it is a half-step between <c>Default</c> and <c>HuffmanOnly</c>.
|
||||
/// </summary>
|
||||
Filtered = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Using <c>HuffmanOnly</c> will force the compressor to do Huffman encoding only, with no
|
||||
/// string matching.
|
||||
/// </summary>
|
||||
HuffmanOnly = 2,
|
||||
}
|
||||
}
|
||||
77
SabreTools.IO/Compression/Deflate/DeflateFlavor.cs
Normal file
77
SabreTools.IO/Compression/Deflate/DeflateFlavor.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
// Deflate.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: <2011-August-03 19:52:15>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines logic for handling the Deflate or compression.
|
||||
//
|
||||
// This code is based on multiple sources:
|
||||
// - the original zlib v1.2.3 source, which is Copyright (C) 1995-2005 Jean-loup Gailly.
|
||||
// - the original jzlib, which is Copyright (c) 2000-2003 ymnk, JCraft,Inc.
|
||||
//
|
||||
// However, this code is significantly different from both.
|
||||
// The object model is not the same, and many of the behaviors are different.
|
||||
//
|
||||
// In keeping with the license for these other works, the copyrights for
|
||||
// jzlib and zlib are 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
|
||||
{
|
||||
internal enum DeflateFlavor
|
||||
{
|
||||
Store,
|
||||
Fast,
|
||||
Slow
|
||||
}
|
||||
}
|
||||
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; }
|
||||
}
|
||||
}
|
||||
1880
SabreTools.IO/Compression/Deflate/DeflateManager.cs
Normal file
1880
SabreTools.IO/Compression/Deflate/DeflateManager.cs
Normal file
File diff suppressed because it is too large
Load Diff
751
SabreTools.IO/Compression/Deflate/DeflateStream.cs
Normal file
751
SabreTools.IO/Compression/Deflate/DeflateStream.cs
Normal file
@@ -0,0 +1,751 @@
|
||||
// DeflateStream.cs
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2009-2010 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 (in emacs):
|
||||
// Time-stamp: <2011-July-31 14:48:11>
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
// This module defines the DeflateStream class, which can be used as a replacement for
|
||||
// the System.IO.Compression.DeflateStream class in the .NET BCL.
|
||||
//
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
|
||||
namespace SabreTools.IO.Compression.Deflate
|
||||
{
|
||||
#pragma warning disable IDE0001
|
||||
#pragma warning disable IDE0002
|
||||
#pragma warning disable IDE0036
|
||||
#pragma warning disable IDE0040
|
||||
#pragma warning disable IDE0047
|
||||
#pragma warning disable IDE0049
|
||||
#pragma warning disable IDE2000
|
||||
#pragma warning disable IDE2002
|
||||
/// <summary>
|
||||
/// A class for compressing and decompressing streams using the Deflate algorithm.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
///
|
||||
/// <para>
|
||||
/// The DeflateStream is a <see
|
||||
/// href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</see> on a <see
|
||||
/// cref="System.IO.Stream"/>. It adds DEFLATE compression or decompression to any
|
||||
/// stream.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// Using this stream, applications can compress or decompress data via stream
|
||||
/// <c>Read</c> and <c>Write</c> operations. Either compresssion or decompression
|
||||
/// can occur through either reading or writing. The compression format used is
|
||||
/// DEFLATE, which is documented in <see
|
||||
/// href="http://www.ietf.org/rfc/rfc1951.txt">IETF RFC 1951</see>, "DEFLATE
|
||||
/// Compressed Data Format Specification version 1.3.".
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// This class is similar to <see cref="ZlibStream"/>, except that
|
||||
/// <c>ZlibStream</c> adds the <see href="http://www.ietf.org/rfc/rfc1950.txt">RFC
|
||||
/// 1950 - ZLIB</see> framing bytes to a compressed stream when compressing, or
|
||||
/// expects the RFC1950 framing bytes when decompressing. The <c>DeflateStream</c>
|
||||
/// does not.
|
||||
/// </para>
|
||||
///
|
||||
/// </remarks>
|
||||
///
|
||||
/// <seealso cref="ZlibStream" />
|
||||
/// <seealso cref="GZipStream" />
|
||||
public class DeflateStream : System.IO.Stream
|
||||
{
|
||||
internal ZlibBaseStream _baseStream;
|
||||
internal System.IO.Stream _innerStream;
|
||||
bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Create a DeflateStream using the specified CompressionMode.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// When mode is <c>CompressionMode.Compress</c>, the DeflateStream will use
|
||||
/// the default compression level. The "captive" stream will be closed when
|
||||
/// the DeflateStream is closed.
|
||||
/// </remarks>
|
||||
///
|
||||
/// <example>
|
||||
/// This example uses a DeflateStream to compress data from a file, and writes
|
||||
/// the compressed data to another file.
|
||||
/// <code>
|
||||
/// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
|
||||
/// {
|
||||
/// using (var raw = System.IO.File.Create(fileToCompress + ".deflated"))
|
||||
/// {
|
||||
/// using (Stream compressor = new DeflateStream(raw, CompressionMode.Compress))
|
||||
/// {
|
||||
/// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
|
||||
/// int n;
|
||||
/// while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
|
||||
/// {
|
||||
/// compressor.Write(buffer, 0, n);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
///
|
||||
/// <code lang="VB">
|
||||
/// Using input As Stream = File.OpenRead(fileToCompress)
|
||||
/// Using raw As FileStream = File.Create(fileToCompress & ".deflated")
|
||||
/// Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress)
|
||||
/// Dim buffer As Byte() = New Byte(4096) {}
|
||||
/// Dim n As Integer = -1
|
||||
/// Do While (n <> 0)
|
||||
/// If (n > 0) Then
|
||||
/// compressor.Write(buffer, 0, n)
|
||||
/// End If
|
||||
/// n = input.Read(buffer, 0, buffer.Length)
|
||||
/// Loop
|
||||
/// End Using
|
||||
/// End Using
|
||||
/// End Using
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <param name="stream">The stream which will be read or written.</param>
|
||||
/// <param name="mode">Indicates whether the DeflateStream will compress or decompress.</param>
|
||||
public DeflateStream(System.IO.Stream stream, CompressionMode mode)
|
||||
: this(stream, mode, CompressionLevel.Default, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a DeflateStream using the specified CompressionMode and the specified CompressionLevel.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
///
|
||||
/// <para>
|
||||
/// When mode is <c>CompressionMode.Decompress</c>, the level parameter is
|
||||
/// ignored. The "captive" stream will be closed when the DeflateStream is
|
||||
/// closed.
|
||||
/// </para>
|
||||
///
|
||||
/// </remarks>
|
||||
///
|
||||
/// <example>
|
||||
///
|
||||
/// This example uses a DeflateStream to compress data from a file, and writes
|
||||
/// the compressed data to another file.
|
||||
///
|
||||
/// <code>
|
||||
/// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
|
||||
/// {
|
||||
/// using (var raw = System.IO.File.Create(fileToCompress + ".deflated"))
|
||||
/// {
|
||||
/// using (Stream compressor = new DeflateStream(raw,
|
||||
/// CompressionMode.Compress,
|
||||
/// CompressionLevel.BestCompression))
|
||||
/// {
|
||||
/// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
|
||||
/// int n= -1;
|
||||
/// while (n != 0)
|
||||
/// {
|
||||
/// if (n > 0)
|
||||
/// compressor.Write(buffer, 0, n);
|
||||
/// n= input.Read(buffer, 0, buffer.Length);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
///
|
||||
/// <code lang="VB">
|
||||
/// Using input As Stream = File.OpenRead(fileToCompress)
|
||||
/// Using raw As FileStream = File.Create(fileToCompress & ".deflated")
|
||||
/// Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression)
|
||||
/// Dim buffer As Byte() = New Byte(4096) {}
|
||||
/// Dim n As Integer = -1
|
||||
/// Do While (n <> 0)
|
||||
/// If (n > 0) Then
|
||||
/// compressor.Write(buffer, 0, n)
|
||||
/// End If
|
||||
/// n = input.Read(buffer, 0, buffer.Length)
|
||||
/// Loop
|
||||
/// End Using
|
||||
/// End Using
|
||||
/// End Using
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <param name="stream">The stream to be read or written while deflating or inflating.</param>
|
||||
/// <param name="mode">Indicates whether the <c>DeflateStream</c> will compress or decompress.</param>
|
||||
/// <param name="level">A tuning knob to trade speed for effectiveness.</param>
|
||||
public DeflateStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level)
|
||||
: this(stream, mode, level, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a <c>DeflateStream</c> using the specified
|
||||
/// <c>CompressionMode</c>, and explicitly specify whether the
|
||||
/// stream should be left open after Deflation or Inflation.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
///
|
||||
/// <para>
|
||||
/// This constructor allows the application to request that the captive stream
|
||||
/// remain open after the deflation or inflation occurs. By default, after
|
||||
/// <c>Close()</c> is called on the stream, the captive stream is also
|
||||
/// closed. In some cases this is not desired, for example if the stream is a
|
||||
/// memory stream that will be re-read after compression. Specify true for
|
||||
/// the <paramref name="leaveOpen"/> parameter to leave the stream open.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// The <c>DeflateStream</c> will use the default compression level.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// See the other overloads of this constructor for example code.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
///
|
||||
/// <param name="stream">
|
||||
/// The stream which will be read or written. This is called the
|
||||
/// "captive" stream in other places in this documentation.
|
||||
/// </param>
|
||||
///
|
||||
/// <param name="mode">
|
||||
/// Indicates whether the <c>DeflateStream</c> will compress or decompress.
|
||||
/// </param>
|
||||
///
|
||||
/// <param name="leaveOpen">true if the application would like the stream to
|
||||
/// remain open after inflation/deflation.</param>
|
||||
public DeflateStream(System.IO.Stream stream, CompressionMode mode, bool leaveOpen)
|
||||
: this(stream, mode, CompressionLevel.Default, leaveOpen)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a <c>DeflateStream</c> using the specified <c>CompressionMode</c>
|
||||
/// and the specified <c>CompressionLevel</c>, and explicitly specify whether
|
||||
/// the stream should be left open after Deflation or Inflation.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
///
|
||||
/// <para>
|
||||
/// When mode is <c>CompressionMode.Decompress</c>, the level parameter is ignored.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// This constructor allows the application to request that the captive stream
|
||||
/// remain open after the deflation or inflation occurs. By default, after
|
||||
/// <c>Close()</c> is called on the stream, the captive stream is also
|
||||
/// closed. In some cases this is not desired, for example if the stream is a
|
||||
/// <see cref="System.IO.MemoryStream"/> that will be re-read after
|
||||
/// compression. Specify true for the <paramref name="leaveOpen"/> parameter
|
||||
/// to leave the stream open.
|
||||
/// </para>
|
||||
///
|
||||
/// </remarks>
|
||||
///
|
||||
/// <example>
|
||||
///
|
||||
/// This example shows how to use a <c>DeflateStream</c> to compress data from
|
||||
/// a file, and store the compressed data into another file.
|
||||
///
|
||||
/// <code>
|
||||
/// using (var output = System.IO.File.Create(fileToCompress + ".deflated"))
|
||||
/// {
|
||||
/// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
|
||||
/// {
|
||||
/// using (Stream compressor = new DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true))
|
||||
/// {
|
||||
/// byte[] buffer = new byte[WORKING_BUFFER_SIZE];
|
||||
/// int n= -1;
|
||||
/// while (n != 0)
|
||||
/// {
|
||||
/// if (n > 0)
|
||||
/// compressor.Write(buffer, 0, n);
|
||||
/// n= input.Read(buffer, 0, buffer.Length);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// // can write additional data to the output stream here
|
||||
/// }
|
||||
/// </code>
|
||||
///
|
||||
/// <code lang="VB">
|
||||
/// Using output As FileStream = File.Create(fileToCompress & ".deflated")
|
||||
/// Using input As Stream = File.OpenRead(fileToCompress)
|
||||
/// Using compressor As Stream = New DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True)
|
||||
/// Dim buffer As Byte() = New Byte(4096) {}
|
||||
/// Dim n As Integer = -1
|
||||
/// Do While (n <> 0)
|
||||
/// If (n > 0) Then
|
||||
/// compressor.Write(buffer, 0, n)
|
||||
/// End If
|
||||
/// n = input.Read(buffer, 0, buffer.Length)
|
||||
/// Loop
|
||||
/// End Using
|
||||
/// End Using
|
||||
/// ' can write additional data to the output stream here.
|
||||
/// End Using
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <param name="stream">The stream which will be read or written.</param>
|
||||
/// <param name="mode">Indicates whether the DeflateStream will compress or decompress.</param>
|
||||
/// <param name="leaveOpen">true if the application would like the stream to remain open after inflation/deflation.</param>
|
||||
/// <param name="level">A tuning knob to trade speed for effectiveness.</param>
|
||||
public DeflateStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen)
|
||||
{
|
||||
_innerStream = stream;
|
||||
_baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, leaveOpen);
|
||||
}
|
||||
|
||||
#region Zlib properties
|
||||
|
||||
/// <summary>
|
||||
/// This property sets the flush behavior on the stream.
|
||||
/// </summary>
|
||||
/// <remarks> See the ZLIB documentation for the meaning of the flush behavior.
|
||||
/// </remarks>
|
||||
virtual public FlushType FlushMode
|
||||
{
|
||||
get { return (this._baseStream._flushMode); }
|
||||
set
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException("DeflateStream");
|
||||
this._baseStream._flushMode = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The size of the working buffer for the compression codec.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The working buffer is used for all stream operations. The default size is
|
||||
/// 1024 bytes. The minimum size is 128 bytes. You may get better performance
|
||||
/// with a larger buffer. Then again, you might not. You would have to test
|
||||
/// it.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// Set this before the first call to <c>Read()</c> or <c>Write()</c> on the
|
||||
/// stream. If you try to set it afterwards, it will throw.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public int BufferSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._baseStream._bufferSize;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException("DeflateStream");
|
||||
if (this._baseStream._workingBuffer is not null)
|
||||
throw new ZlibException("The working buffer is already set.");
|
||||
if (value < ZlibConstants.WorkingBufferSizeMin)
|
||||
throw new ZlibException(String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, ZlibConstants.WorkingBufferSizeMin));
|
||||
this._baseStream._bufferSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The ZLIB strategy to be used during compression.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// By tweaking this parameter, you may be able to optimize the compression for
|
||||
/// data with particular characteristics.
|
||||
/// </remarks>
|
||||
public CompressionStrategy Strategy
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._baseStream.Strategy;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException("DeflateStream");
|
||||
this._baseStream.Strategy = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Returns the total number of bytes input so far.</summary>
|
||||
virtual public long TotalIn
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._baseStream._z.TotalBytesIn;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Returns the total number of bytes output so far.</summary>
|
||||
virtual public long TotalOut
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._baseStream._z.TotalBytesOut;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region System.IO.Stream methods
|
||||
/// <summary>
|
||||
/// Dispose the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This may or may not result in a <c>Close()</c> call on the captive
|
||||
/// stream. See the constructors that have a <c>leaveOpen</c> parameter
|
||||
/// for more information.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Application code won't call this code directly. This method may be
|
||||
/// invoked in two distinct scenarios. If disposing == true, the method
|
||||
/// has been called directly or indirectly by a user's code, for example
|
||||
/// via the public Dispose() method. In this case, both managed and
|
||||
/// unmanaged resources can be referenced and disposed. If disposing ==
|
||||
/// false, the method has been called by the runtime from inside the
|
||||
/// object finalizer and this method should not reference other objects;
|
||||
/// in that case only unmanaged resources must be referenced or
|
||||
/// disposed.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="disposing">
|
||||
/// true if the Dispose method was invoked by user code.
|
||||
/// </param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing && (this._baseStream is not null))
|
||||
this._baseStream.Close();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream can be read.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The return value depends on whether the captive stream supports reading.
|
||||
/// </remarks>
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException("DeflateStream");
|
||||
return _baseStream._stream.CanRead;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream supports Seek operations.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Always returns false.
|
||||
/// </remarks>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the stream can be written.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The return value depends on whether the captive stream supports writing.
|
||||
/// </remarks>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException("DeflateStream");
|
||||
return _baseStream._stream.CanWrite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flush the stream.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException("DeflateStream");
|
||||
_baseStream.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reading this property always throws a <see cref="NotImplementedException"/>.
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The position of the stream pointer.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Setting this property always throws a <see
|
||||
/// cref="NotImplementedException"/>. Reading will return the total bytes
|
||||
/// written out, if used in writing, or the total bytes read in, if used in
|
||||
/// reading. The count may refer to compressed bytes or uncompressed bytes,
|
||||
/// depending on how you've used the stream.
|
||||
/// </remarks>
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._baseStream._streamMode == SabreTools.IO.Compression.Deflate.ZlibBaseStream.StreamMode.Writer)
|
||||
return this._baseStream._z.TotalBytesOut;
|
||||
if (this._baseStream._streamMode == SabreTools.IO.Compression.Deflate.ZlibBaseStream.StreamMode.Reader)
|
||||
return this._baseStream._z.TotalBytesIn;
|
||||
return 0;
|
||||
}
|
||||
set { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read data from the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// <para>
|
||||
/// If you wish to use the <c>DeflateStream</c> to compress data while
|
||||
/// reading, you can create a <c>DeflateStream</c> with
|
||||
/// <c>CompressionMode.Compress</c>, providing an uncompressed data stream.
|
||||
/// Then call Read() on that <c>DeflateStream</c>, and the data read will be
|
||||
/// compressed as you read. If you wish to use the <c>DeflateStream</c> to
|
||||
/// decompress data while reading, you can create a <c>DeflateStream</c> with
|
||||
/// <c>CompressionMode.Decompress</c>, providing a readable compressed data
|
||||
/// stream. Then call Read() on that <c>DeflateStream</c>, and the data read
|
||||
/// will be decompressed as you read.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not both.
|
||||
/// </para>
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="buffer">The buffer into which the read data should be placed.</param>
|
||||
/// <param name="offset">the offset within that data array to put the first byte read.</param>
|
||||
/// <param name="count">the number of bytes to read.</param>
|
||||
/// <returns>the number of bytes actually read</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException("DeflateStream");
|
||||
return _baseStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calling this method always throws a <see cref="NotImplementedException"/>.
|
||||
/// </summary>
|
||||
/// <param name="offset">this is irrelevant, since it will always throw!</param>
|
||||
/// <param name="origin">this is irrelevant, since it will always throw!</param>
|
||||
/// <returns>irrelevant!</returns>
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calling this method always throws a <see cref="NotImplementedException"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">this is irrelevant, since it will always throw!</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write data to the stream.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// <para>
|
||||
/// If you wish to use the <c>DeflateStream</c> to compress data while
|
||||
/// writing, you can create a <c>DeflateStream</c> with
|
||||
/// <c>CompressionMode.Compress</c>, and a writable output stream. Then call
|
||||
/// <c>Write()</c> on that <c>DeflateStream</c>, providing uncompressed data
|
||||
/// as input. The data sent to the output stream will be the compressed form
|
||||
/// of the data written. If you wish to use the <c>DeflateStream</c> to
|
||||
/// decompress data while writing, you can create a <c>DeflateStream</c> with
|
||||
/// <c>CompressionMode.Decompress</c>, and a writable output stream. Then
|
||||
/// call <c>Write()</c> on that stream, providing previously compressed
|
||||
/// data. The data sent to the output stream will be the decompressed form of
|
||||
/// the data written.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>,
|
||||
/// but not both.
|
||||
/// </para>
|
||||
///
|
||||
/// </remarks>
|
||||
///
|
||||
/// <param name="buffer">The buffer holding data to write to the stream.</param>
|
||||
/// <param name="offset">the offset within that data array to find the first byte to write.</param>
|
||||
/// <param name="count">the number of bytes to write.</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_disposed) throw new ObjectDisposedException("DeflateStream");
|
||||
_baseStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the dictionary to be used for either Inflation or Deflation.
|
||||
/// </summary>
|
||||
/// <param name="dictionary">The dictionary bytes to use.</param>
|
||||
/// <param name="check">Determines if dictionary checks are run</param>
|
||||
/// <returns>Z_OK if all goes well.</returns>
|
||||
public int SetDictionary(byte[] dictionary, bool check = true)
|
||||
{
|
||||
return _baseStream.SetDictionary(dictionary, check);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Compress a string into a byte array using DEFLATE (RFC 1951).
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Uncompress it with <see cref="DeflateStream.UncompressString(byte[])"/>.
|
||||
/// </remarks>
|
||||
///
|
||||
/// <seealso cref="DeflateStream.UncompressString(byte[])">DeflateStream.UncompressString(byte[])</seealso>
|
||||
/// <seealso cref="DeflateStream.CompressBuffer(byte[])">DeflateStream.CompressBuffer(byte[])</seealso>
|
||||
/// <seealso cref="GZipStream.CompressString(string)">GZipStream.CompressString(string)</seealso>
|
||||
/// <seealso cref="ZlibStream.CompressString(string)">ZlibStream.CompressString(string)</seealso>
|
||||
///
|
||||
/// <param name="s">
|
||||
/// A string to compress. The string will first be encoded
|
||||
/// using UTF8, then compressed.
|
||||
/// </param>
|
||||
///
|
||||
/// <returns>The string in compressed form</returns>
|
||||
public static byte[] CompressString(String s)
|
||||
{
|
||||
using var ms = new System.IO.MemoryStream();
|
||||
System.IO.Stream compressor =
|
||||
new DeflateStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression);
|
||||
ZlibBaseStream.CompressString(s, compressor);
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Compress a byte array into a new byte array using DEFLATE.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Uncompress it with <see cref="DeflateStream.UncompressBuffer(byte[])"/>.
|
||||
/// </remarks>
|
||||
///
|
||||
/// <seealso cref="DeflateStream.CompressString(string)">DeflateStream.CompressString(string)</seealso>
|
||||
/// <seealso cref="DeflateStream.UncompressBuffer(byte[])">DeflateStream.UncompressBuffer(byte[])</seealso>
|
||||
/// <seealso cref="GZipStream.CompressBuffer(byte[])">GZipStream.CompressBuffer(byte[])</seealso>
|
||||
/// <seealso cref="ZlibStream.CompressBuffer(byte[])">ZlibStream.CompressBuffer(byte[])</seealso>
|
||||
///
|
||||
/// <param name="b">
|
||||
/// A buffer to compress.
|
||||
/// </param>
|
||||
///
|
||||
/// <returns>The data in compressed form</returns>
|
||||
public static byte[] CompressBuffer(byte[] b)
|
||||
{
|
||||
using var ms = new System.IO.MemoryStream();
|
||||
System.IO.Stream compressor =
|
||||
new DeflateStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression);
|
||||
|
||||
ZlibBaseStream.CompressBuffer(b, compressor);
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Uncompress a DEFLATE'd byte array into a single string.
|
||||
/// </summary>
|
||||
///
|
||||
/// <seealso cref="DeflateStream.CompressString(String)">DeflateStream.CompressString(String)</seealso>
|
||||
/// <seealso cref="DeflateStream.UncompressBuffer(byte[])">DeflateStream.UncompressBuffer(byte[])</seealso>
|
||||
/// <seealso cref="GZipStream.UncompressString(byte[])">GZipStream.UncompressString(byte[])</seealso>
|
||||
/// <seealso cref="ZlibStream.UncompressString(byte[])">ZlibStream.UncompressString(byte[])</seealso>
|
||||
///
|
||||
/// <param name="compressed">
|
||||
/// A buffer containing DEFLATE-compressed data.
|
||||
/// </param>
|
||||
///
|
||||
/// <returns>The uncompressed string</returns>
|
||||
public static String UncompressString(byte[] compressed)
|
||||
{
|
||||
using var input = new System.IO.MemoryStream(compressed);
|
||||
System.IO.Stream decompressor =
|
||||
new DeflateStream(input, CompressionMode.Decompress);
|
||||
|
||||
return ZlibBaseStream.UncompressString(compressed, decompressor);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Uncompress a DEFLATE'd byte array into a byte array.
|
||||
/// </summary>
|
||||
///
|
||||
/// <seealso cref="DeflateStream.CompressBuffer(byte[])">DeflateStream.CompressBuffer(byte[])</seealso>
|
||||
/// <seealso cref="DeflateStream.UncompressString(byte[])">DeflateStream.UncompressString(byte[])</seealso>
|
||||
/// <seealso cref="GZipStream.UncompressBuffer(byte[])">GZipStream.UncompressBuffer(byte[])</seealso>
|
||||
/// <seealso cref="ZlibStream.UncompressBuffer(byte[])">ZlibStream.UncompressBuffer(byte[])</seealso>
|
||||
///
|
||||
/// <param name="compressed">
|
||||
/// A buffer containing data that has been compressed with DEFLATE.
|
||||
/// </param>
|
||||
///
|
||||
/// <returns>The data in uncompressed form</returns>
|
||||
public static byte[] UncompressBuffer(byte[] compressed)
|
||||
{
|
||||
using var input = new System.IO.MemoryStream(compressed);
|
||||
System.IO.Stream decompressor =
|
||||
new DeflateStream(input, CompressionMode.Decompress);
|
||||
|
||||
return ZlibBaseStream.UncompressBuffer(compressed, decompressor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user