mirror of
https://github.com/SabreTools/SabreTools.IO.git
synced 2026-02-08 05:37:52 +00:00
Compare commits
326 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 | ||
|
|
b99c80390e | ||
|
|
3a79646650 | ||
|
|
f16f05beb9 | ||
|
|
e901b52143 | ||
|
|
a638b146b4 | ||
|
|
6bfc961a87 | ||
|
|
a825bae039 | ||
|
|
e0eba8e5bb | ||
|
|
fb4b533dfb | ||
|
|
6162af2216 | ||
|
|
3b5fd128f0 | ||
|
|
9beb2177aa | ||
|
|
f0033af712 | ||
|
|
3de5b2378d | ||
|
|
ee7ce59627 | ||
|
|
39bf9c19ad | ||
|
|
32cab49bae | ||
|
|
5d71957841 | ||
|
|
7ea182c7d8 | ||
|
|
b97ec13661 | ||
|
|
8caeea053f | ||
|
|
a7476b6ac9 | ||
|
|
f0095f9e41 | ||
|
|
a0b5ea1368 | ||
|
|
a94d2c8c64 | ||
|
|
8c19ad712a | ||
|
|
0317f751b9 | ||
|
|
b8d431b06b | ||
|
|
3fcf10e2f7 | ||
|
|
40e439b18c | ||
|
|
bf707b1c11 | ||
|
|
d074a6a7ee | ||
|
|
0c736c2491 | ||
|
|
964506057d | ||
|
|
cd08925411 | ||
|
|
6ea8aab7c7 | ||
|
|
561dbdcc9a | ||
|
|
b4bad28823 | ||
|
|
ec9db7e732 | ||
|
|
3c7401fefc | ||
|
|
09e66c9ec3 | ||
|
|
8d1bc3957c | ||
|
|
245ca9010a | ||
|
|
88207100f1 | ||
|
|
3befd9255a | ||
|
|
37f2848bb2 | ||
|
|
c5dca60d28 | ||
|
|
351e46534d | ||
|
|
d39324c887 | ||
|
|
163f49281d | ||
|
|
03d0f7dd18 | ||
|
|
fbbe77f5f2 | ||
|
|
4bffd9d31c | ||
|
|
904aed1c44 | ||
|
|
69a41b2487 | ||
|
|
f326c921e6 | ||
|
|
73c4e8dd50 | ||
|
|
e4c8bbc3f9 | ||
|
|
8df3fe2473 | ||
|
|
a2bb83ab9a | ||
|
|
bcb77f2de6 | ||
|
|
35d4c22a20 | ||
|
|
893cb73b0d | ||
|
|
607a0375c7 | ||
|
|
87d1dfe266 | ||
|
|
d8f16b12b5 | ||
|
|
cf08658b1e | ||
|
|
9547e1a355 | ||
|
|
20cdb5b65e | ||
|
|
fc10565186 | ||
|
|
c824db6b18 | ||
|
|
a3c26fed38 | ||
|
|
2dc259d978 | ||
|
|
2d950ddc54 | ||
|
|
294c5c26df | ||
|
|
dc356767ab | ||
|
|
0b6c7e9885 | ||
|
|
339da9fc16 | ||
|
|
7bc18c6952 | ||
|
|
ec3afeed73 | ||
|
|
658ceb5d0e | ||
|
|
e9a905d4a3 | ||
|
|
1127e96f26 | ||
|
|
89a8ad3703 | ||
|
|
ff7f7c0b8c | ||
|
|
32e948653a | ||
|
|
a93da97bbd | ||
|
|
65bdcc563d | ||
|
|
f3c5499754 | ||
|
|
02819f006b | ||
|
|
48512b486c | ||
|
|
6c289ee015 | ||
|
|
973e19366a | ||
|
|
f5ef39ab76 | ||
|
|
e4deb10db6 | ||
|
|
90d2382d5d | ||
|
|
c48d62fd5e | ||
|
|
0f10dc2ae4 | ||
|
|
c648ad9f5e | ||
|
|
cd01e170fe | ||
|
|
ecaec1d44a | ||
|
|
ce521d92ca | ||
|
|
a69b6dfa3a | ||
|
|
18b8357cd6 | ||
|
|
c19b59dc1c | ||
|
|
1bdb483205 | ||
|
|
b99f8531c1 | ||
|
|
602b951be7 | ||
|
|
046bb5875a | ||
|
|
6074fa3c3f | ||
|
|
bdad58c0dc | ||
|
|
4097a8cc8c | ||
|
|
8e3293dd7d | ||
|
|
7ac4df8201 | ||
|
|
f888cd4e57 | ||
|
|
04fc2dc96e | ||
|
|
2371813175 | ||
|
|
99b3bb25f2 | ||
|
|
2ee40e341f | ||
|
|
90ed6a9a65 | ||
|
|
89e29c9cab | ||
|
|
1a6ff6d64f | ||
|
|
878e9e97db | ||
|
|
09acfd3ad2 | ||
|
|
8c2eff6e3e | ||
|
|
dbf8548d8c | ||
|
|
bcbf5bff42 | ||
|
|
c3c58f004a | ||
|
|
cf11fe50d0 | ||
|
|
5ddd1e4213 | ||
|
|
75cc8376a8 | ||
|
|
0dea1fb437 | ||
|
|
92df6b21e3 | ||
|
|
7da7967762 |
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
|
||||
23
.github/workflows/check_pr.yml
vendored
Normal file
23
.github/workflows/check_pr.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Build PR
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- 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
|
||||
@@ -1,174 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SabreTools.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Big endian reading overloads for BinaryReader
|
||||
/// </summary>
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes from the stream, starting from a specified point in the byte array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read data into.</param>
|
||||
/// <param name="index">The starting point in the buffer at which to begin reading into the buffer.</param>
|
||||
/// <param name="count">The number of bytes to read.</param>
|
||||
/// <returns>The number of bytes read into buffer. This might be less than the number of bytes requested if that many bytes are not available, or it might be zero if the end of the stream is reached.</returns>
|
||||
public static int ReadBigEndian(this BinaryReader reader, byte[] buffer, int index, int count)
|
||||
{
|
||||
int retval = reader.Read(buffer, index, count);
|
||||
Array.Reverse(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of characters from the stream, starting from a specified point in the character array.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to read data into.</param>
|
||||
/// <param name="index">The starting point in the buffer at which to begin reading into the buffer.</param>
|
||||
/// <param name="count">The number of characters to read.</param>
|
||||
/// <returns>The total number of characters read into the buffer. This might be less than the number of characters requested if that many characters are not currently available, or it might be zero if the end of the stream is reached.</returns>
|
||||
public static int ReadBigEndian(this BinaryReader reader, char[] buffer, int index, int count)
|
||||
{
|
||||
int retval = reader.Read(buffer, index, count);
|
||||
Array.Reverse(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes from the current stream into a byte array and advances the current position by that number of bytes.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bytes to read. This value must be 0 or a non-negative number or an exception will occur.</param>
|
||||
/// <returns>A byte array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.</returns>
|
||||
public static byte[] ReadBytesBigEndian(this BinaryReader reader, int count)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(count);
|
||||
Array.Reverse(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of characters from the current stream, returns the data in a character array, and advances the current position in accordance with the Encoding used and the specific character being read from the stream.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of characters to read. This value must be 0 or a non-negative number or an exception will occur.</param>
|
||||
/// <returns>A character array containing data read from the underlying stream. This might be less than the number of bytes requested if the end of the stream is reached.</returns>
|
||||
public static char[] ReadCharsBigEndian(this BinaryReader reader, int count)
|
||||
{
|
||||
char[] retval = reader.ReadChars(count);
|
||||
Array.Reverse(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a decimal value from the current stream and advances the current position of the stream by sixteen bytes.
|
||||
/// </summary>
|
||||
/// <returns>A decimal value read from the current stream.</returns>
|
||||
public static decimal ReadDecimalBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(16);
|
||||
Array.Reverse(retval);
|
||||
|
||||
int i1 = BitConverter.ToInt32(retval, 0);
|
||||
int i2 = BitConverter.ToInt32(retval, 4);
|
||||
int i3 = BitConverter.ToInt32(retval, 8);
|
||||
int i4 = BitConverter.ToInt32(retval, 12);
|
||||
|
||||
return new decimal(new int[] { i1, i2, i3, i4 });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// eads an 8-byte floating point value from the current stream and advances the current position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte floating point value read from the current stream.</returns>
|
||||
public static double ReadDoubleBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToDouble(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte signed integer from the current stream and advances the current position of the stream by two bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 2-byte signed integer read from the current stream.</returns>
|
||||
public static short ReadInt16BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(2);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt16(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte signed integer from the current stream and advances the current position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte signed integer read from the current stream.</returns>
|
||||
public static int ReadInt32BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt32(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an 8-byte signed integer from the current stream and advances the current position of the stream by eight bytes.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte signed integer read from the current stream.</returns>
|
||||
public static long ReadInt64BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToInt64(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte floating point value from the current stream and advances the current position of the stream by four bytes.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte floating point value read from the current stream.</returns>
|
||||
public static float ReadSingleBigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToSingle(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 2-byte unsigned integer from the current stream using little-endian encoding and advances the position of the stream by two bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>A 2-byte unsigned integer read from this stream.</returns>
|
||||
public static ushort ReadUInt16BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(2);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt16(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 4-byte unsigned integer from the current stream and advances the position of the stream by four bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>A 4-byte unsigned integer read from this stream.</returns>
|
||||
public static uint ReadUInt32BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(4);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt32(retval, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an 8-byte unsigned integer from the current stream and advances the position of the stream by eight bytes.
|
||||
///
|
||||
/// This API is not CLS-compliant.
|
||||
/// </summary>
|
||||
/// <returns>An 8-byte unsigned integer read from this stream.</returns>
|
||||
public static ulong ReadUInt64BigEndian(this BinaryReader reader)
|
||||
{
|
||||
byte[] retval = reader.ReadBytes(8);
|
||||
Array.Reverse(retval);
|
||||
return BitConverter.ToUInt64(retval, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for byte arrays
|
||||
/// </summary>
|
||||
/// <remarks>TODO: Add U/Int24 and U/Int48 methods</remarks>
|
||||
public static class ByteArrayExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Read a UInt8 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static byte ReadByte(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 1);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt8[] and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static byte[]? ReadBytes(this byte[]? content, ref int offset, int count)
|
||||
{
|
||||
// If the byte array is invalid, don't do anything
|
||||
if (content == null)
|
||||
return null;
|
||||
|
||||
// If there's an invalid byte count, don't do anything
|
||||
if (count <= 0 || offset >= content.Length)
|
||||
return null;
|
||||
|
||||
// Allocate enough space for the data requested
|
||||
byte[] buffer = new byte[count];
|
||||
|
||||
// If we have less data left than requested, only read until the end
|
||||
if (offset + count >= content.Length)
|
||||
count = content.Length - offset;
|
||||
|
||||
// If we have a non-zero count, copy the data into the array
|
||||
if (count > 0)
|
||||
Array.Copy(content, offset, buffer, 0, Math.Min(count, content.Length - offset));
|
||||
|
||||
// Increment the offset and return
|
||||
offset += count;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Int8 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static sbyte ReadSByte(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 1);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
return (sbyte)buffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Char and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static char ReadChar(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 1);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
return (char)buffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Int16 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static short ReadInt16(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 2);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
return BitConverter.ToInt16(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Int16 in big-endian format and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static short ReadInt16BigEndian(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 2);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToInt16(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt16 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static ushort ReadUInt16(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 2);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
return BitConverter.ToUInt16(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt16 in big-endian format and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static ushort ReadUInt16BigEndian(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 2);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToUInt16(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Int32 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static int ReadInt32(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 4);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
return BitConverter.ToInt32(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Int32 in big-endian format and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static int ReadInt32BigEndian(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 4);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToInt32(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt32 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static uint ReadUInt32(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 4);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
return BitConverter.ToUInt32(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt32 in big-endian format and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static uint ReadUInt32BigEndian(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 4);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToUInt32(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Int64 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static long ReadInt64(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 8);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
return BitConverter.ToInt64(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Int64 in big-endian format and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static long ReadInt64BigEndian(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 8);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToInt64(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt64 and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static ulong ReadUInt64(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 8);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
return BitConverter.ToUInt64(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a UInt64 in big-endian format and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static ulong ReadUInt64BigEndian(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 8);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
Array.Reverse(buffer);
|
||||
return BitConverter.ToUInt64(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Guid and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static Guid ReadGuid(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 16);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
return new Guid(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a Guid in big-endian format and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static Guid ReadGuidBigEndian(this byte[] content, ref int offset)
|
||||
{
|
||||
byte[]? buffer = content.ReadBytes(ref offset, 16);
|
||||
if (buffer == null)
|
||||
return default;
|
||||
|
||||
Array.Reverse(buffer);
|
||||
return new Guid(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadString(this byte[] content, ref int offset) => content.ReadString(ref offset, Encoding.Default);
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated string from the stream
|
||||
/// </summary>
|
||||
public static string? ReadString(this byte[] content, ref int offset, Encoding encoding)
|
||||
{
|
||||
if (offset >= content.Length)
|
||||
return null;
|
||||
|
||||
byte[] nullTerminator = encoding.GetBytes(new char[] { '\0' });
|
||||
int charWidth = nullTerminator.Length;
|
||||
|
||||
List<char> keyChars = new List<char>();
|
||||
while (offset < content.Length)
|
||||
{
|
||||
char c = encoding.GetChars(content, offset, charWidth)[0];
|
||||
keyChars.Add(c);
|
||||
offset += charWidth;
|
||||
|
||||
if (c == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
return new string(keyChars.ToArray()).TrimEnd('\0');
|
||||
}
|
||||
}
|
||||
}
|
||||
130
IOExtensions.cs
130
IOExtensions.cs
@@ -1,130 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Methods around path operations
|
||||
/// </summary>
|
||||
public static class IOExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensure the output directory is a proper format and can be created
|
||||
/// </summary>
|
||||
/// <param name="dir">Directory to check</param>
|
||||
/// <param name="create">True if the directory should be created, false otherwise (default)</param>
|
||||
/// <returns>Full path to the directory</returns>
|
||||
public static string Ensure(this string dir, bool create = false)
|
||||
{
|
||||
// If the output directory is invalid
|
||||
if (string.IsNullOrEmpty(dir))
|
||||
dir = PathTool.GetRuntimeDirectory();
|
||||
|
||||
// Get the full path for the output directory
|
||||
dir = Path.GetFullPath(dir.Trim('"'));
|
||||
|
||||
// If we're creating the output folder, do so
|
||||
if (create && !Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines a text file's encoding by analyzing its byte order mark (BOM).
|
||||
/// Defaults to ASCII when detection of the text file's endianness fails.
|
||||
/// </summary>
|
||||
/// <param name="filename">The text file to analyze.</param>
|
||||
/// <returns>The detected encoding.</returns>
|
||||
/// <link>http://stackoverflow.com/questions/3825390/effective-way-to-find-any-files-encoding</link>
|
||||
public static Encoding GetEncoding(this string filename)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
return Encoding.Default;
|
||||
|
||||
if (!File.Exists(filename))
|
||||
return Encoding.Default;
|
||||
|
||||
// Try to open the file
|
||||
try
|
||||
{
|
||||
FileStream file = File.OpenRead(filename);
|
||||
if (file == null)
|
||||
return Encoding.Default;
|
||||
|
||||
// Read the BOM
|
||||
var bom = new byte[4];
|
||||
file.Read(bom, 0, 4);
|
||||
file.Dispose();
|
||||
|
||||
// Disable warning about UTF7 usage
|
||||
#pragma warning disable SYSLIB0001
|
||||
|
||||
// Analyze the BOM
|
||||
if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) return Encoding.UTF7;
|
||||
if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) return Encoding.UTF8;
|
||||
if (bom[0] == 0xff && bom[1] == 0xfe) return Encoding.Unicode; //UTF-16LE
|
||||
if (bom[0] == 0xfe && bom[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE
|
||||
if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return Encoding.UTF32;
|
||||
return Encoding.Default;
|
||||
|
||||
#pragma warning restore SYSLIB0001
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Encoding.Default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the extension from the path, if possible
|
||||
/// </summary>
|
||||
/// <param name="path">Path to get extension from</param>
|
||||
/// <returns>Extension, if possible</returns>
|
||||
public static string? GetNormalizedExtension(this string? path)
|
||||
{
|
||||
// Check null or empty first
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return null;
|
||||
|
||||
// Get the extension from the path, if possible
|
||||
string? ext = Path.GetExtension(path)?.ToLowerInvariant();
|
||||
|
||||
// Check if the extension is null or empty
|
||||
if (string.IsNullOrEmpty(ext))
|
||||
return null;
|
||||
|
||||
// Make sure that extensions are valid
|
||||
ext = ext!.TrimStart('.');
|
||||
|
||||
return ext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all empty folders within a root folder
|
||||
/// </summary>
|
||||
/// <param name="root">Root directory to parse</param>
|
||||
/// <returns>IEumerable containing all directories that are empty, an empty enumerable if the root is empty, null otherwise</returns>
|
||||
public static List<string>? ListEmpty(this string? root)
|
||||
{
|
||||
// Check null or empty first
|
||||
if (string.IsNullOrEmpty(root))
|
||||
return null;
|
||||
|
||||
// Then, check if the root exists
|
||||
if (!Directory.Exists(root))
|
||||
return null;
|
||||
|
||||
// If it does and it is empty, return a blank enumerable
|
||||
if (!Directory.EnumerateFileSystemEntries(root, "*", SearchOption.AllDirectories).Any())
|
||||
return new List<string>();
|
||||
|
||||
// Otherwise, get the complete list
|
||||
return Directory.EnumerateDirectories(root, "*", SearchOption.AllDirectories)
|
||||
.Where(dir => !Directory.EnumerateFileSystemEntries(dir, "*", SearchOption.AllDirectories).Any())
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
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.
|
||||
@@ -1,79 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
/// TODO: Make this namespace a separate library
|
||||
namespace NaturalSort
|
||||
{
|
||||
internal static class NaturalComparerUtil
|
||||
{
|
||||
public static int CompareNumeric(string s1, string s2)
|
||||
{
|
||||
// Save the orginal strings, for later comparison
|
||||
string s1orig = s1;
|
||||
string s2orig = s2;
|
||||
|
||||
// We want to normalize the strings, so we set both to lower case
|
||||
s1 = s1.ToLowerInvariant();
|
||||
s2 = s2.ToLowerInvariant();
|
||||
|
||||
// If the strings are the same exactly, return
|
||||
if (s1 == s2)
|
||||
return s1orig.CompareTo(s2orig);
|
||||
|
||||
// If one is null, then say that's less than
|
||||
if (s1 == null)
|
||||
return -1;
|
||||
if (s2 == null)
|
||||
return 1;
|
||||
|
||||
// Now split into path parts after converting AltDirSeparator to DirSeparator
|
||||
s1 = s1.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
s2 = s2.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
string[] s1parts = s1.Split(Path.DirectorySeparatorChar);
|
||||
string[] s2parts = s2.Split(Path.DirectorySeparatorChar);
|
||||
|
||||
// Then compare each part in turn
|
||||
for (int j = 0; j < s1parts.Length && j < s2parts.Length; j++)
|
||||
{
|
||||
int compared = CompareNumericPart(s1parts[j], s2parts[j]);
|
||||
if (compared != 0)
|
||||
return compared;
|
||||
}
|
||||
|
||||
// If we got out here, then it looped through at least one of the strings
|
||||
if (s1parts.Length > s2parts.Length)
|
||||
return 1;
|
||||
if (s1parts.Length < s2parts.Length)
|
||||
return -1;
|
||||
|
||||
return s1orig.CompareTo(s2orig);
|
||||
}
|
||||
|
||||
private static int CompareNumericPart(string s1, string s2)
|
||||
{
|
||||
// Otherwise, loop through until we have an answer
|
||||
for (int i = 0; i < s1.Length && i < s2.Length; i++)
|
||||
{
|
||||
int s1c = s1[i];
|
||||
int s2c = s2[i];
|
||||
|
||||
// If the characters are the same, continue
|
||||
if (s1c == s2c)
|
||||
continue;
|
||||
|
||||
// If they're different, check which one was larger
|
||||
if (s1c > s2c)
|
||||
return 1;
|
||||
if (s1c < s2c)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If we got out here, then it looped through at least one of the strings
|
||||
if (s1.Length > s2.Length)
|
||||
return 1;
|
||||
if (s1.Length < s2.Length)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
OldDotNet.cs
20
OldDotNet.cs
@@ -1,20 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#if NET40
|
||||
|
||||
namespace SabreTools.IO
|
||||
{
|
||||
internal delegate U LinqOrderByDelegate<T, U>(T str);
|
||||
|
||||
internal static partial class EnumerationExtensions
|
||||
{
|
||||
public static IEnumerable<T> OrderBy<T, U>(this IEnumerable<T> arr, LinqOrderByDelegate<T, U> func)
|
||||
{
|
||||
// TODO: Implement ordering
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,95 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SabreTools.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// A path that optionally contains a parent root
|
||||
/// </summary>
|
||||
public class ParentablePath
|
||||
{
|
||||
/// <summary>
|
||||
/// Current full path represented
|
||||
/// </summary>
|
||||
public string CurrentPath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Possible parent path represented (may be null or empty)
|
||||
/// </summary>
|
||||
public string? ParentPath { get; private set; }
|
||||
|
||||
public ParentablePath(string currentPath, string? parentPath = null)
|
||||
{
|
||||
CurrentPath = currentPath;
|
||||
ParentPath = parentPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the proper filename (with subpath) from the file and parent combination
|
||||
/// </summary>
|
||||
/// <param name="sanitize">True if path separators should be converted to '-', false otherwise</param>
|
||||
/// <returns>Subpath for the file</returns>
|
||||
public string? GetNormalizedFileName(bool sanitize)
|
||||
{
|
||||
// If the current path is empty, we can't do anything
|
||||
if (string.IsNullOrEmpty(CurrentPath))
|
||||
return null;
|
||||
|
||||
// Assume the current path is the filename
|
||||
string filename = Path.GetFileName(CurrentPath);
|
||||
|
||||
// If we have a true ParentPath, remove it from CurrentPath and return the remainder
|
||||
if (string.IsNullOrEmpty(ParentPath) && !string.Equals(CurrentPath, ParentPath, StringComparison.Ordinal))
|
||||
filename = CurrentPath.Remove(0, ParentPath!.Length + 1);
|
||||
|
||||
// If we're sanitizing the path after, do so
|
||||
if (sanitize)
|
||||
filename = filename.Replace(Path.DirectorySeparatorChar, '-').Replace(Path.AltDirectorySeparatorChar, '-');
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the proper output path for a given input file and output directory
|
||||
/// </summary>
|
||||
/// <param name="outDir">Output directory to use</param>
|
||||
/// <param name="inplace">True if the output file should go to the same input folder, false otherwise</param>
|
||||
/// <returns>Complete output path</returns>
|
||||
public string? GetOutputPath(string outDir, bool inplace)
|
||||
{
|
||||
// If the current path is empty, we can't do anything
|
||||
if (string.IsNullOrEmpty(CurrentPath))
|
||||
return null;
|
||||
|
||||
// If the output dir is empty (and we're not inplace), we can't do anything
|
||||
if (string.IsNullOrEmpty(outDir) && !inplace)
|
||||
return null;
|
||||
|
||||
// Check if we have a split path or not
|
||||
bool splitpath = !string.IsNullOrEmpty(ParentPath);
|
||||
|
||||
// If we have an inplace output, use the directory name from the input path
|
||||
if (inplace)
|
||||
return Path.GetDirectoryName(CurrentPath);
|
||||
|
||||
// If the current and parent paths are the same, just use the output directory
|
||||
if (!splitpath || CurrentPath.Length == (ParentPath?.Length ?? 0))
|
||||
return outDir;
|
||||
|
||||
// By default, the working parent directory is the parent path
|
||||
string workingParent = ParentPath ?? string.Empty;
|
||||
|
||||
// TODO: Should this be the default? Always create a subfolder if a folder is found?
|
||||
// If we are processing a path that is coming from a directory and we are outputting to the current directory, we want to get the subfolder to write to
|
||||
if (outDir == Environment.CurrentDirectory)
|
||||
workingParent = Path.GetDirectoryName(ParentPath ?? string.Empty) ?? string.Empty;
|
||||
|
||||
// Determine the correct subfolder based on the working parent directory
|
||||
int extraLength = workingParent.EndsWith(":")
|
||||
|| workingParent.EndsWith(Path.DirectorySeparatorChar.ToString())
|
||||
|| workingParent.EndsWith(Path.AltDirectorySeparatorChar.ToString()) ? 0 : 1;
|
||||
|
||||
return Path.GetDirectoryName(Path.Combine(outDir, CurrentPath.Remove(0, workingParent.Length + extraLength)));
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
2414
SabreTools.IO.Test/Extensions/BinaryReaderExtensionsTests.cs
Normal file
2414
SabreTools.IO.Test/Extensions/BinaryReaderExtensionsTests.cs
Normal file
File diff suppressed because it is too large
Load Diff
717
SabreTools.IO.Test/Extensions/BinaryWriterExtensionsTests.cs
Normal file
717
SabreTools.IO.Test/Extensions/BinaryWriterExtensionsTests.cs
Normal file
@@ -0,0 +1,717 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class BinaryWriterExtensionsTests
|
||||
{
|
||||
/// <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 WriteByteValueTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
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)];
|
||||
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)];
|
||||
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)];
|
||||
bw.Write('\0');
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteCharEncodingTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [0x00, 0x00];
|
||||
bw.Write('\0', Encoding.Unicode);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bw.Write((short)0x0100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
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)];
|
||||
bw.Write((ushort)0x0100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = bw.WriteBigEndian((ushort)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[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)];
|
||||
bw.Write(BitConverter.Int16BitsToHalf(0x0100));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteHalfBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = bw.WriteBigEndian(BitConverter.Int16BitsToHalf(0x0001));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[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)];
|
||||
bw.WriteAsInt24(0x020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = bw.WriteAsInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bw.WriteAsUInt24(0x020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = bw.WriteAsUInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bw.Write(0x03020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
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)];
|
||||
bw.Write((uint)0x03020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
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)];
|
||||
bw.Write(BitConverter.Int32BitsToSingle(0x03020100));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = bw.WriteBigEndian(BitConverter.Int32BitsToSingle(0x00010203));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bw.WriteAsInt48(0x050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = bw.WriteAsInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bw.WriteAsUInt48(0x050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = bw.WriteAsUInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bw.Write(0x0706050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
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)];
|
||||
bw.Write((ulong)0x0706050403020100);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
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)];
|
||||
bw.Write(BitConverter.Int64BitsToDouble(0x0706050403020100));
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDoubleBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = bw.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);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _decimalBytes.Take(16)];
|
||||
bw.Write(0.0123456789M);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDecimalBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _decimalBytes.Take(16).Reverse()];
|
||||
bool write = bw.WriteBigEndian(0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = bw.Write(new Guid(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = bw.WriteBigEndian(new Guid([.. Enumerable.Reverse(_bytes)]));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[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)];
|
||||
bool write = bw.Write((Int128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = bw.WriteBigEndian((Int128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = bw.Write((UInt128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = bw.WriteBigEndian((UInt128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[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()
|
||||
{
|
||||
byte[] bytesWithString =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x41, 0x42, 0x43, 0x00,
|
||||
];
|
||||
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
var obj = new TestStructExplicit
|
||||
{
|
||||
FirstValue = TestEnum.RecognizedTestValue,
|
||||
SecondValue = 0x07060504,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = [.. bytesWithString.Take(12)];
|
||||
bool write = bw.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeSequentialTest()
|
||||
{
|
||||
byte[] bytesWithString =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x41, 0x42, 0x43, 0x00,
|
||||
];
|
||||
|
||||
var stream = new MemoryStream(new byte[24], 0, count: 24, true, true);
|
||||
var bw = new BinaryWriter(stream);
|
||||
var obj = new TestStructSequential
|
||||
{
|
||||
FirstValue = TestEnum.RecognizedTestValue,
|
||||
SecondValue = 0x07060504,
|
||||
ThirdValue = 0x0908,
|
||||
FourthValue = 0x0B0A,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = [.. bytesWithString.Take(16)];
|
||||
bool write = bw.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate that a set of actual bytes matches the expected bytes
|
||||
/// </summary>
|
||||
private static void ValidateBytes(byte[] expected, byte[] actual)
|
||||
{
|
||||
for (int i = 0; i < expected.Length; i++)
|
||||
{
|
||||
Assert.Equal(expected[i], actual[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
736
SabreTools.IO.Test/Extensions/ByteArrayWriterExtensionsTests.cs
Normal file
736
SabreTools.IO.Test/Extensions/ByteArrayWriterExtensionsTests.cs
Normal file
@@ -0,0 +1,736 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class ByteArrayWriterExtensionsTests
|
||||
{
|
||||
/// <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 WriteByteTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
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)];
|
||||
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)];
|
||||
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)];
|
||||
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)];
|
||||
bool write = buffer.Write(ref offset, (short)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
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)];
|
||||
bool write = buffer.Write(ref offset, (ushort)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, (ushort)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[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)];
|
||||
bool write = buffer.Write(ref offset, BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteHalfBigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, BitConverter.Int16BitsToHalf(0x0001));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = buffer.WriteAsInt24(ref offset, 0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = buffer.WriteAsInt24BigEndian(ref offset, 0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = buffer.WriteAsUInt24(ref offset, 0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = buffer.WriteAsUInt24BigEndian(ref offset, 0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = buffer.Write(ref offset, 0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
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)];
|
||||
bool write = buffer.Write(ref offset, (uint)0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
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)];
|
||||
bool write = buffer.Write(ref offset, BitConverter.Int32BitsToSingle(0x03020100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleBigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, BitConverter.Int32BitsToSingle(0x00010203));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = buffer.WriteAsInt48(ref offset, 0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = buffer.WriteAsInt48BigEndian(ref offset, 0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = buffer.WriteAsUInt48(ref offset, 0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = buffer.WriteAsUInt48BigEndian(ref offset, 0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = buffer.Write(ref offset, 0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
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)];
|
||||
bool write = buffer.Write(ref offset, (ulong)0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
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)];
|
||||
bool write = buffer.Write(ref offset, 0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDecimalBigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _decimalBytes.Take(16).Reverse()];
|
||||
bool write = buffer.WriteBigEndian(ref offset, 0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.Write(ref offset, new Guid(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidBigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, new Guid([.. Enumerable.Reverse(_bytes)]));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt128Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.Write(ref offset, (Int128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt128BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, (Int128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128Test()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.Write(ref offset, (UInt128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128BigEndianTest()
|
||||
{
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = buffer.WriteBigEndian(ref offset, (UInt128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[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()
|
||||
{
|
||||
byte[] bytesWithString =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x41, 0x42, 0x43, 0x00,
|
||||
];
|
||||
|
||||
byte[] buffer = new byte[16];
|
||||
int offset = 0;
|
||||
var obj = new TestStructExplicit
|
||||
{
|
||||
FirstValue = TestEnum.RecognizedTestValue,
|
||||
SecondValue = 0x07060504,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = [.. bytesWithString.Take(12)];
|
||||
bool write = buffer.WriteType(ref offset, obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeSequentialTest()
|
||||
{
|
||||
byte[] bytesWithString =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x41, 0x42, 0x43, 0x00,
|
||||
];
|
||||
|
||||
byte[] buffer = new byte[24];
|
||||
int offset = 0;
|
||||
var obj = new TestStructSequential
|
||||
{
|
||||
FirstValue = TestEnum.RecognizedTestValue,
|
||||
SecondValue = 0x07060504,
|
||||
ThirdValue = 0x0908,
|
||||
FourthValue = 0x0B0A,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = [.. bytesWithString.Take(16)];
|
||||
bool write = buffer.WriteType(ref offset, obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate that a set of actual bytes matches the expected bytes
|
||||
/// </summary>
|
||||
private static void ValidateBytes(byte[] expected, byte[] actual)
|
||||
{
|
||||
for (int i = 0; i < expected.Length; i++)
|
||||
{
|
||||
Assert.Equal(expected[i], actual[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
184
SabreTools.IO.Test/Extensions/EnumerableExtensionsTests.cs
Normal file
184
SabreTools.IO.Test/Extensions/EnumerableExtensionsTests.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
#pragma warning disable IDE0060 // Remove unused parameter
|
||||
#pragma warning disable IDE0290 // Use primary constructor
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class EnumerableExtensionsTests
|
||||
{
|
||||
#region IterateWithAction
|
||||
|
||||
[Fact]
|
||||
public void IterateWithActionTest()
|
||||
{
|
||||
List<int> source = [1, 2, 3, 4];
|
||||
int actual = 0;
|
||||
|
||||
source.IterateWithAction(i => Interlocked.Add(ref actual, i));
|
||||
Assert.Equal(10, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SafeEnumerate
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerate_Empty()
|
||||
{
|
||||
var source = Enumerable.Empty<string>();
|
||||
var safe = source.SafeEnumerate();
|
||||
var list = safe.ToList();
|
||||
Assert.Empty(list);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
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();
|
||||
var list = safe.ToList();
|
||||
Assert.Equal(3, list.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SafeEnumerate_ErrorMid()
|
||||
{
|
||||
var source = new List<string> { "a", "ab", "abc" };
|
||||
var wrapper = new ErrorEnumerable(source);
|
||||
|
||||
var safe = wrapper.SafeEnumerate();
|
||||
var list = safe.ToList();
|
||||
Assert.Equal(2, list.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
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"/>
|
||||
/// </summary>
|
||||
private class ErrorEnumerable : IEnumerable<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerator to use during enumeration
|
||||
/// </summary>
|
||||
private readonly ErrorEnumerator _enumerator;
|
||||
|
||||
public ErrorEnumerable(IEnumerable<string> source)
|
||||
{
|
||||
_enumerator = new ErrorEnumerator(source);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<string> GetEnumerator() => _enumerator;
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => _enumerator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fake enumerator that throws an exception every other item while moving to the next item
|
||||
/// </summary>
|
||||
private class ErrorEnumerator : IEnumerator<string>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
return _enumerator.Current;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
/// <summary>
|
||||
/// Enumerator from the source enumerable
|
||||
/// </summary>
|
||||
private readonly IEnumerator<string> _enumerator;
|
||||
|
||||
/// <summary>
|
||||
/// Enumerators start before the data
|
||||
/// </summary>
|
||||
private int _index = -1;
|
||||
|
||||
public ErrorEnumerator(IEnumerable<string> source)
|
||||
{
|
||||
_enumerator = source.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose() { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool MoveNext()
|
||||
{
|
||||
// Move to the next item, if possible
|
||||
bool moved = _enumerator.MoveNext();
|
||||
if (!moved)
|
||||
return false;
|
||||
|
||||
// Get the next real item
|
||||
_index++;
|
||||
|
||||
// Every other move, throw an exception
|
||||
if (_index % 2 == 1)
|
||||
throw new Exception("Access issue for this item in the enumerable");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Reset()
|
||||
{
|
||||
_enumerator.Reset();
|
||||
_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();
|
||||
}
|
||||
}
|
||||
}
|
||||
312
SabreTools.IO.Test/Extensions/IOExtensionsTests.cs
Normal file
312
SabreTools.IO.Test/Extensions/IOExtensionsTests.cs
Normal file
@@ -0,0 +1,312 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
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)]
|
||||
[InlineData(" ", null)]
|
||||
[InlineData("no-extension", null)]
|
||||
[InlineData("NO-EXTENSION", null)]
|
||||
[InlineData("no-extension.", null)]
|
||||
[InlineData("NO-EXTENSION.", null)]
|
||||
[InlineData("filename.ext", "ext")]
|
||||
[InlineData("FILENAME.EXT", "ext")]
|
||||
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
|
||||
}
|
||||
}
|
||||
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
674
SabreTools.IO.Test/Extensions/StreamWriterExtensionsTests.cs
Normal file
674
SabreTools.IO.Test/Extensions/StreamWriterExtensionsTests.cs
Normal file
@@ -0,0 +1,674 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using SabreTools.IO.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
public class StreamWriterExtensionsTests
|
||||
{
|
||||
/// <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 WriteByteValueTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
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)];
|
||||
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)];
|
||||
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)];
|
||||
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)];
|
||||
bool write = stream.Write((short)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
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)];
|
||||
bool write = stream.Write((ushort)0x0100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt16BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = stream.WriteBigEndian((ushort)0x0001);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[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)];
|
||||
bool write = stream.Write(BitConverter.Int16BitsToHalf(0x0100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteHalfBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(2)];
|
||||
bool write = stream.WriteBigEndian(BitConverter.Int16BitsToHalf(0x0001));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = stream.WriteAsInt24(0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = stream.WriteAsInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = stream.WriteAsUInt24(0x020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt24BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(3)];
|
||||
bool write = stream.WriteAsUInt24BigEndian(0x000102);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = stream.Write(0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
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)];
|
||||
bool write = stream.Write((uint)0x03020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt32BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
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)];
|
||||
bool write = stream.Write(BitConverter.Int32BitsToSingle(0x03020100));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteSingleBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(4)];
|
||||
bool write = stream.WriteBigEndian(BitConverter.Int32BitsToSingle(0x00010203));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = stream.WriteAsInt48(0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = stream.WriteAsInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = stream.WriteAsUInt48(0x050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt48BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(6)];
|
||||
bool write = stream.WriteAsUInt48BigEndian(0x000102030405);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(8)];
|
||||
bool write = stream.Write(0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
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)];
|
||||
bool write = stream.Write((ulong)0x0706050403020100);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt64BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
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)];
|
||||
bool write = stream.Write(0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteDecimalBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _decimalBytes.Take(16).Reverse()];
|
||||
bool write = stream.WriteBigEndian(0.0123456789M);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.Write(new Guid(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteGuidBigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.WriteBigEndian(new Guid([.. Enumerable.Reverse(_bytes)]));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.Write((Int128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.WriteBigEndian((Int128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128Test()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.Write((UInt128)new BigInteger(_bytes));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteUInt128BigEndianTest()
|
||||
{
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
byte[] expected = [.. _bytes.Take(16)];
|
||||
bool write = stream.WriteBigEndian((UInt128)new BigInteger(Enumerable.Reverse(_bytes).ToArray()));
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[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()
|
||||
{
|
||||
byte[] bytesWithString =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x41, 0x42, 0x43, 0x00,
|
||||
];
|
||||
|
||||
var stream = new MemoryStream(new byte[16], 0, 16, true, true);
|
||||
var obj = new TestStructExplicit
|
||||
{
|
||||
FirstValue = TestEnum.RecognizedTestValue,
|
||||
SecondValue = 0x07060504,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = [.. bytesWithString.Take(12)];
|
||||
bool write = stream.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTypeSequentialTest()
|
||||
{
|
||||
byte[] bytesWithString =
|
||||
[
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x41, 0x42, 0x43, 0x00,
|
||||
];
|
||||
|
||||
var stream = new MemoryStream(new byte[24], 0, 24, true, true);
|
||||
var obj = new TestStructSequential
|
||||
{
|
||||
FirstValue = TestEnum.RecognizedTestValue,
|
||||
SecondValue = 0x07060504,
|
||||
ThirdValue = 0x0908,
|
||||
FourthValue = 0x0B0A,
|
||||
FifthValue = "ABC",
|
||||
};
|
||||
byte[] expected = [.. bytesWithString.Take(16)];
|
||||
bool write = stream.WriteType(obj);
|
||||
Assert.True(write);
|
||||
ValidateBytes(expected, stream.GetBuffer());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate that a set of actual bytes matches the expected bytes
|
||||
/// </summary>
|
||||
private static void ValidateBytes(byte[] expected, byte[] actual)
|
||||
{
|
||||
for (int i = 0; i < expected.Length; i++)
|
||||
{
|
||||
Assert.Equal(expected[i], actual[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
9
SabreTools.IO.Test/Extensions/TestEnum.cs
Normal file
9
SabreTools.IO.Test/Extensions/TestEnum.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
internal enum TestEnum : uint
|
||||
{
|
||||
None = 0x00000000,
|
||||
RecognizedTestValue = 0x03020100,
|
||||
UpperBoundaryValue = 0xFFFFFFFF,
|
||||
}
|
||||
}
|
||||
59
SabreTools.IO.Test/Extensions/TestStructArrays.cs
Normal file
59
SabreTools.IO.Test/Extensions/TestStructArrays.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal struct TestStructArrays
|
||||
{
|
||||
/// <summary>
|
||||
/// 4 entry byte array
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public byte[]? ByteArray;
|
||||
|
||||
/// <summary>
|
||||
/// 4 entry int array
|
||||
/// </summary>
|
||||
[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>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public TestStructPoint[]? StructArray;
|
||||
|
||||
/// <summary>
|
||||
/// 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 = 4)]
|
||||
public byte[]? LPByteArray;
|
||||
|
||||
// /// <summary>
|
||||
// /// 4 entry nested byte array
|
||||
// /// </summary>
|
||||
// /// <remarks>This will likely fail</remarks>
|
||||
// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
// public byte[][]? NestedByteArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Struct for nested tests
|
||||
/// </summary>
|
||||
internal struct TestStructPoint
|
||||
{
|
||||
public ushort X;
|
||||
public ushort Y;
|
||||
}
|
||||
}
|
||||
23
SabreTools.IO.Test/Extensions/TestStructExplicit.cs
Normal file
23
SabreTools.IO.Test/Extensions/TestStructExplicit.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
internal struct TestStructExplicit
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public TestEnum FirstValue;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public int SecondValue;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public ushort ThirdValue;
|
||||
|
||||
[FieldOffset(6)]
|
||||
public short FourthValue;
|
||||
|
||||
[FieldOffset(8), MarshalAs(UnmanagedType.LPStr)]
|
||||
public string? FifthValue;
|
||||
}
|
||||
}
|
||||
29
SabreTools.IO.Test/Extensions/TestStructInheritance.cs
Normal file
29
SabreTools.IO.Test/Extensions/TestStructInheritance.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal class TestStructInheritanceParent
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public byte[]? Signature;
|
||||
|
||||
public uint IdentifierType;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal class TestStructInheritanceChild1 : TestStructInheritanceParent
|
||||
{
|
||||
public uint FieldA;
|
||||
|
||||
public uint FieldB;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal class TestStructInheritanceChild2 : TestStructInheritanceParent
|
||||
{
|
||||
public ushort FieldA;
|
||||
|
||||
public ushort FieldB;
|
||||
}
|
||||
}
|
||||
19
SabreTools.IO.Test/Extensions/TestStructSequential.cs
Normal file
19
SabreTools.IO.Test/Extensions/TestStructSequential.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct TestStructSequential
|
||||
{
|
||||
public TestEnum FirstValue;
|
||||
|
||||
public int SecondValue;
|
||||
|
||||
public ushort ThirdValue;
|
||||
|
||||
public short FourthValue;
|
||||
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
public string? FifthValue;
|
||||
}
|
||||
}
|
||||
39
SabreTools.IO.Test/Extensions/TestStructStrings.cs
Normal file
39
SabreTools.IO.Test/Extensions/TestStructStrings.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable CS0618 // Obsolete unmanaged types
|
||||
namespace SabreTools.IO.Test.Extensions
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal struct TestStructStrings
|
||||
{
|
||||
/// <summary>
|
||||
/// ASCII-encoded, byte-length-prefixed string
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.AnsiBStr)]
|
||||
public string? AnsiBStr;
|
||||
|
||||
/// <summary>
|
||||
/// Unicode-encoded, WORD-length-prefixed string
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.BStr)]
|
||||
public string? BStr;
|
||||
|
||||
/// <summary>
|
||||
/// Fixed length string
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 3)]
|
||||
public string? ByValTStr;
|
||||
|
||||
/// <summary>
|
||||
/// ASCII-encoded, null-terminated string
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.LPStr)]
|
||||
public string? LPStr;
|
||||
|
||||
/// <summary>
|
||||
/// Unicode-encoded, null-terminated string
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string? LPWStr;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
87
SabreTools.IO.Test/ParentablePathTests.cs
Normal file
87
SabreTools.IO.Test/ParentablePathTests.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test
|
||||
{
|
||||
public class ParentablePathTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("", null, false, null)]
|
||||
[InlineData("", null, true, null)]
|
||||
[InlineData(" ", null, false, null)]
|
||||
[InlineData(" ", null, true, null)]
|
||||
[InlineData("C:\\Directory\\Filename.ext", null, false, "Filename.ext")]
|
||||
[InlineData("C:\\Directory\\Filename.ext", null, true, "Filename.ext")]
|
||||
[InlineData("C:\\Directory\\Filename.ext", "C:\\Directory\\Filename.ext", false, "Filename.ext")]
|
||||
[InlineData("C:\\Directory\\Filename.ext", "C:\\Directory\\Filename.ext", true, "Filename.ext")]
|
||||
[InlineData("C:\\Directory\\SubDir\\Filename.ext", "C:\\Directory", false, "SubDir\\Filename.ext")]
|
||||
[InlineData("C:\\Directory\\SubDir\\Filename.ext", "C:\\Directory", true, "SubDir-Filename.ext")]
|
||||
public void NormalizedFileNameTest(string current, string? parent, bool sanitize, string? expected)
|
||||
{
|
||||
// Hack to support Windows paths on Linux for testing only
|
||||
if (System.IO.Path.DirectorySeparatorChar == '/')
|
||||
{
|
||||
current = current.Replace('\\', '/');
|
||||
parent = parent?.Replace('\\', '/');
|
||||
expected = expected?.Replace('\\', '/');
|
||||
}
|
||||
|
||||
var path = new ParentablePath(current, parent);
|
||||
string? actual = path.GetNormalizedFileName(sanitize);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", null, null, false, null)]
|
||||
[InlineData("", null, null, true, null)]
|
||||
[InlineData(" ", null, null, false, null)]
|
||||
[InlineData(" ", null, null, true, null)]
|
||||
[InlineData("C:\\Directory\\Filename.ext", null, null, false, null)]
|
||||
[InlineData("C:\\Directory\\Filename.ext", null, null, true, "C:\\Directory")]
|
||||
[InlineData("C:\\Directory\\Filename.ext", "C:\\Directory\\Filename.ext", null, false, null)]
|
||||
[InlineData("C:\\Directory\\Filename.ext", "C:\\Directory\\Filename.ext", null, true, "C:\\Directory")]
|
||||
[InlineData("C:\\Directory\\SubDir\\Filename.ext", "C:\\Directory", null, false, null)]
|
||||
[InlineData("C:\\Directory\\SubDir\\Filename.ext", "C:\\Directory", null, true, "C:\\Directory\\SubDir")]
|
||||
[InlineData("", null, "D:\\OutputDirectory", false, null)]
|
||||
[InlineData("", null, "D:\\OutputDirectory", true, null)]
|
||||
[InlineData(" ", null, "D:\\OutputDirectory", false, null)]
|
||||
[InlineData(" ", null, "D:\\OutputDirectory", true, null)]
|
||||
[InlineData("C:\\Directory\\Filename.ext", null, "D:\\OutputDirectory", false, "D:\\OutputDirectory")]
|
||||
[InlineData("C:\\Directory\\Filename.ext", null, "D:\\OutputDirectory", true, "C:\\Directory")]
|
||||
[InlineData("C:\\Directory\\Filename.ext", "C:\\Directory\\Filename.ext", "D:\\OutputDirectory", false, "D:\\OutputDirectory")]
|
||||
[InlineData("C:\\Directory\\Filename.ext", "C:\\Directory\\Filename.ext", "D:\\OutputDirectory", true, "C:\\Directory")]
|
||||
[InlineData("C:\\Directory\\SubDir\\Filename.ext", "C:\\Directory", "D:\\OutputDirectory", false, "D:\\OutputDirectory\\SubDir")]
|
||||
[InlineData("C:\\Directory\\SubDir\\Filename.ext", "C:\\Directory", "D:\\OutputDirectory", true, "C:\\Directory\\SubDir")]
|
||||
[InlineData("", null, "%cd%", false, null)]
|
||||
[InlineData("", null, "%cd%", true, null)]
|
||||
[InlineData(" ", null, "%cd%", false, null)]
|
||||
[InlineData(" ", null, "%cd%", true, null)]
|
||||
[InlineData("C:\\Directory\\Filename.ext", null, "%cd%", false, "%cd%")]
|
||||
[InlineData("C:\\Directory\\Filename.ext", null, "%cd%", true, "C:\\Directory")]
|
||||
[InlineData("C:\\Directory\\Filename.ext", "C:\\Directory\\Filename.ext", "%cd%", false, "%cd%")]
|
||||
[InlineData("C:\\Directory\\Filename.ext", "C:\\Directory\\Filename.ext", "%cd%", true, "C:\\Directory")]
|
||||
[InlineData("C:\\Directory\\SubDir\\Filename.ext", "C:\\Directory", "%cd%", false, "%cd%\\Directory\\SubDir")]
|
||||
[InlineData("C:\\Directory\\SubDir\\Filename.ext", "C:\\Directory", "%cd%", true, "C:\\Directory\\SubDir")]
|
||||
public void GetOutputPathTest(string current, string? parent, string? outDir, bool inplace, string? expected)
|
||||
{
|
||||
// Hacks because I can't use environment vars as parameters
|
||||
if (outDir == "%cd%")
|
||||
outDir = Environment.CurrentDirectory.TrimEnd('\\', '/');
|
||||
if (expected?.Contains("%cd%") == true)
|
||||
expected = expected.Replace("%cd%", Environment.CurrentDirectory.TrimEnd('\\', '/'));
|
||||
|
||||
// Hack to support Windows paths on Linux for testing only
|
||||
if (System.IO.Path.DirectorySeparatorChar == '/')
|
||||
{
|
||||
current = current.Replace('\\', '/');
|
||||
parent = parent?.Replace('\\', '/');
|
||||
outDir = outDir?.Replace('\\', '/');
|
||||
expected = expected?.Replace('\\', '/');
|
||||
}
|
||||
|
||||
var path = new ParentablePath(current, parent);
|
||||
string? actual = path.GetOutputPath(outDir, inplace);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
39
SabreTools.IO.Test/SabreTools.IO.Test.csproj
Normal file
39
SabreTools.IO.Test/SabreTools.IO.Test.csproj
Normal file
@@ -0,0 +1,39 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<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
|
||||
}
|
||||
}
|
||||
119
SabreTools.IO.Test/Streams/ReadOnlyBitStreamTests.cs
Normal file
119
SabreTools.IO.Test/Streams/ReadOnlyBitStreamTests.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SabreTools.IO.Streams;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Streams
|
||||
{
|
||||
public class ReadOnlyBitStreamTests
|
||||
{
|
||||
[Fact]
|
||||
public void DefaultConstructorTest()
|
||||
{
|
||||
var stream = new ReadOnlyBitStream(new MemoryStream());
|
||||
Assert.Equal(0, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
|
||||
stream = new ReadOnlyBitStream(new MemoryStream(new byte[16], 0, 16, true, true));
|
||||
Assert.Equal(16, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadSingleBitTest()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
[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? 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 ReadByteTest()
|
||||
{
|
||||
byte[] data = [0b01010101, 0b01010101, 0b01010101, 0b01010101];
|
||||
byte expected = 0b01010101;
|
||||
|
||||
var stream = new ReadOnlyBitStream(new MemoryStream(data));
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
187
SabreTools.IO.Test/Streams/ReadOnlyCompositeStreamTests.cs
Normal file
187
SabreTools.IO.Test/Streams/ReadOnlyCompositeStreamTests.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SabreTools.IO.Streams;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.IO.Test.Streams
|
||||
{
|
||||
public class ReadOnlyCompositeStreamTests
|
||||
{
|
||||
#region Constructor
|
||||
|
||||
[Fact]
|
||||
public void Constructor_Default()
|
||||
{
|
||||
var stream = new ReadOnlyCompositeStream();
|
||||
Assert.Equal(0, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_EmptyArray()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream()];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
Assert.Equal(0, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_EmptyEnumerable()
|
||||
{
|
||||
List<Stream> list = [new MemoryStream()];
|
||||
var stream = new ReadOnlyCompositeStream(list);
|
||||
Assert.Equal(0, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_SingleStream()
|
||||
{
|
||||
var stream = new ReadOnlyCompositeStream(new MemoryStream(new byte[1024]));
|
||||
Assert.Equal(1024, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_FilledArray()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[1024]), new MemoryStream(new byte[1024])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
Assert.Equal(2048, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
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()
|
||||
{
|
||||
var stream = new ReadOnlyCompositeStream();
|
||||
Assert.Equal(0, stream.Length);
|
||||
Assert.Equal(0, stream.Position);
|
||||
|
||||
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 Read_EmptyStream()
|
||||
{
|
||||
var stream = new ReadOnlyCompositeStream();
|
||||
|
||||
byte[] buf = new byte[512];
|
||||
int read = stream.Read(buf, 0, 512);
|
||||
|
||||
Assert.Equal(0, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_SingleStream()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[1024])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
|
||||
byte[] buf = new byte[512];
|
||||
int read = stream.Read(buf, 0, 512);
|
||||
|
||||
Assert.Equal(512, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_MultipleStream_SingleContained()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[1024]), new MemoryStream(new byte[1024])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
|
||||
byte[] buf = new byte[512];
|
||||
int read = stream.Read(buf, 0, 512);
|
||||
|
||||
Assert.Equal(512, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_MultipleStream_MultipleContained()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[256]), new MemoryStream(new byte[256])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
|
||||
byte[] buf = new byte[512];
|
||||
int read = stream.Read(buf, 0, 512);
|
||||
|
||||
Assert.Equal(512, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_SingleStream_Extra()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[256])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
|
||||
byte[] buf = new byte[512];
|
||||
int read = stream.Read(buf, 0, 512);
|
||||
|
||||
Assert.Equal(256, read);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_MultipleStream_Extra()
|
||||
{
|
||||
Stream[] arr = [new MemoryStream(new byte[128]), new MemoryStream(new byte[128])];
|
||||
var stream = new ReadOnlyCompositeStream(arr);
|
||||
|
||||
byte[] buf = new byte[512];
|
||||
int read = stream.Read(buf, 0, 512);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.2.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
<Description>Common IO utilities by other SabreTools projects</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2019-2023</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/SabreTools/SabreTools.IO</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>io reading writing ini csv ssv tsv</PackageTags>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" Pack="true" PackagePath=""/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.IO", "SabreTools.IO.csproj", "{87CE4411-80D9-49FF-894C-761F1C20D9A5}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.IO", "SabreTools.IO\SabreTools.IO.csproj", "{87CE4411-80D9-49FF-894C-761F1C20D9A5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.IO.Test", "SabreTools.IO.Test\SabreTools.IO.Test.csproj", "{A9767735-5042-48A1-849C-96035DB1DD53}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -18,5 +20,9 @@ Global
|
||||
{87CE4411-80D9-49FF-894C-761F1C20D9A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{87CE4411-80D9-49FF-894C-761F1C20D9A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{87CE4411-80D9-49FF-894C-761F1C20D9A5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A9767735-5042-48A1-849C-96035DB1DD53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A9767735-5042-48A1-849C-96035DB1DD53}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A9767735-5042-48A1-849C-96035DB1DD53}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A9767735-5042-48A1-849C-96035DB1DD53}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -1,102 +1,90 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* 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.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
/// TODO: Make this namespace a separate library
|
||||
namespace NaturalSort
|
||||
namespace SabreTools.Text.Compare
|
||||
{
|
||||
internal class NaturalComparer : Comparer<string>, IDisposable
|
||||
public class NaturalComparer : Comparer<string>, IDisposable
|
||||
{
|
||||
private readonly Dictionary<string, string[]> table;
|
||||
private readonly Dictionary<string, string[]> _table;
|
||||
|
||||
public NaturalComparer()
|
||||
{
|
||||
table = new Dictionary<string, string[]>();
|
||||
_table = [];
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
table.Clear();
|
||||
_table.Clear();
|
||||
}
|
||||
|
||||
public override int Compare(string? x, string? y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
if (x is null || y is null)
|
||||
{
|
||||
if (x == null && y != null)
|
||||
if (x is null && y is not null)
|
||||
return -1;
|
||||
else if (x != null && y == null)
|
||||
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))
|
||||
|
||||
if (!_table.TryGetValue(x, out string[]? x1))
|
||||
{
|
||||
//x1 = Regex.Split(x.Replace(" ", string.Empty), "([0-9]+)");
|
||||
x1 = Regex.Split(x.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
table.Add(x, x1);
|
||||
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))
|
||||
|
||||
if (!_table.TryGetValue(y, out string[]? y1))
|
||||
{
|
||||
//y1 = Regex.Split(y.Replace(" ", string.Empty), "([0-9]+)");
|
||||
y1 = Regex.Split(y.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
table.Add(y, y1);
|
||||
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)
|
||||
{
|
||||
|
||||
if (x1.Length > y1.Length)
|
||||
return 1;
|
||||
}
|
||||
else if (x1.Length > y1.Length)
|
||||
{
|
||||
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.CompareNumeric(left, right);
|
||||
}
|
||||
return NaturalComparerUtil.ComparePaths(left, right);
|
||||
|
||||
if (!long.TryParse(right, out long y))
|
||||
{
|
||||
return NaturalComparerUtil.CompareNumeric(left, right);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,102 +1,90 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* 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.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
/// TODO: Make this namespace a separate library
|
||||
namespace NaturalSort
|
||||
namespace SabreTools.Text.Compare
|
||||
{
|
||||
internal class NaturalReversedComparer : Comparer<string>, IDisposable
|
||||
public class NaturalReversedComparer : Comparer<string>, IDisposable
|
||||
{
|
||||
private readonly Dictionary<string, string[]> table;
|
||||
private readonly Dictionary<string, string[]> _table;
|
||||
|
||||
public NaturalReversedComparer()
|
||||
{
|
||||
table = new Dictionary<string, string[]>();
|
||||
_table = [];
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
table.Clear();
|
||||
_table.Clear();
|
||||
}
|
||||
|
||||
public override int Compare(string? x, string? y)
|
||||
{
|
||||
if (x == null || y == null)
|
||||
if (x is null || y is null)
|
||||
{
|
||||
if (x == null && y != null)
|
||||
if (x is null && y is not null)
|
||||
return -1;
|
||||
else if (x != null && y == null)
|
||||
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))
|
||||
|
||||
if (!_table.TryGetValue(x, out string[]? x1))
|
||||
{
|
||||
//x1 = Regex.Split(x.Replace(" ", string.Empty), "([0-9]+)");
|
||||
x1 = Regex.Split(x.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
table.Add(x, x1);
|
||||
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))
|
||||
|
||||
if (!_table.TryGetValue(y, out string[]? y1))
|
||||
{
|
||||
//y1 = Regex.Split(y.Replace(" ", string.Empty), "([0-9]+)");
|
||||
y1 = Regex.Split(y.ToLowerInvariant(), "([0-9]+)").Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
table.Add(y, y1);
|
||||
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.CompareNumeric(right, left);
|
||||
}
|
||||
return NaturalComparerUtil.ComparePaths(right, left);
|
||||
|
||||
if (!long.TryParse(right, out long y))
|
||||
{
|
||||
return NaturalComparerUtil.CompareNumeric(right, left);
|
||||
}
|
||||
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,
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user