28 Commits

Author SHA1 Message Date
ce378021ba Implement HA's ASC and HSC algorithms. 2025-09-06 18:59:18 +01:00
4df2934506 Add AMG compressed sample. 2025-09-06 17:13:37 +01:00
3b91dcef7c Bump version to 6.0.0-alpha.11.4. 2025-09-02 13:35:48 +01:00
54410bf59e Add PAK methods 10 (crush) and 11 (distill). 2025-09-02 13:01:16 +01:00
d188ebe02e Update build script. 2025-09-02 11:31:54 +01:00
e97dd11da5 Fix missing includes. 2025-09-02 11:31:26 +01:00
27e2baf54a Bump version to 6.0.0-alpha.11.3. 2025-09-02 10:20:30 +01:00
1323bba72f Add ARC methods 8 (Crunch) and 9 (squash), 12-bit and 13-bit Dynamic LZW. 2025-09-02 10:19:51 +01:00
a39e6abb97 Add ARC methods 5, 6 and 7, LZW with different hash tables, with and without non-repeat packing, aka crunch. 2025-09-02 03:52:35 +01:00
afc6f3e2bc Add ARC method 4 Huffman squeezing decompression implementation and tests 2025-09-02 03:06:31 +01:00
bfb9a6b524 Add ARC non-repeat packing decompression implementation and tests. 2025-09-01 23:30:57 +01:00
750df1cca9 Added comments from Copilot. 2025-08-26 02:06:19 +01:00
a336ce953e Bump version to v6.0.0-alpha.11.2. 2025-08-26 01:54:43 +01:00
057d0c0242 Add support for decompressing Lempel-Ziv-Huffman, LH5 variant. 2025-08-26 01:02:37 +01:00
0068268c65 Add LZD testfile. 2025-08-23 22:55:10 +01:00
beb8b405db Asked Copilot to comment the code. 2025-08-23 22:54:33 +01:00
b3474d88f6 Fix lzd exported functions declarations. 2025-08-23 22:46:10 +01:00
9ed17b84c3 Update build script. 2025-08-23 22:45:45 +01:00
8ba4d258bf Bump version to 6.0.0-alpha.11.1. 2025-08-23 22:09:31 +01:00
9db2e3212d Add codealike configuration file. 2025-08-23 22:09:14 +01:00
6637fb486f Implement LZD from ZOO (method 1), heavily modified to support .NET straming mechanisms. 2025-08-23 22:07:11 +01:00
17d4446fb1 Updated flac to new API. 2025-08-23 21:55:21 +01:00
b285754ad4 Update copyright year. 2024-12-19 15:26:07 +00:00
36102254a5 Update editorconfig file. 2024-12-19 15:24:27 +00:00
c215979aaf Update IntelliJ project files. 2024-12-19 15:24:07 +00:00
e948c31fba Up version to 6.0.0-alpha.10 2024-04-30 15:37:47 +01:00
123879fc7c General refactor and cleanup. 2024-04-30 15:37:29 +01:00
47e6c8e50f Update editorconfig and clang-format. 2024-04-30 15:36:41 +01:00
86 changed files with 11914 additions and 1440 deletions

View File

@@ -1,94 +1,92 @@
---
Language: Cpp
AccessModifierOffset: -2
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: Right
AlignOperands: true
AlignArrayOfStructures: Right
AlignConsecutiveAssignments: AcrossComments
AlignConsecutiveBitFields: true
AlignConsecutiveDeclarations: AcrossComments
AlignConsecutiveMacros: AcrossComments
AlignConsecutiveShortCaseStatements:
Enabled: true
AcrossEmptyLines: false
AcrossComments: true
AlignCaseColons: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Always
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: true
AfterClass: false
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BeforeCatch: true
BeforeElse: true
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Allman
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^(<winsock2.h>)'
Priority: -3
SortPriority: -4
- Regex: '^(<windows.h>)'
Priority: -3
SortPriority: -3
- Regex: '^(<.*)'
Priority: -2
SortPriority: -2
- Regex: '^("(win32|windows))'
Priority: 1
SortPriority: -1
- Regex: '^("library.h")'
Priority: 0
SortPriority: -1
- Regex: '.*'
Priority: 0
SortPriority: 0
IncludeIsMainRegex: '(Test)?$'
- Regex: '^<ext/.*\.h>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: 'library\.h'
Priority: 2
- Regex: '.*'
Priority: 3
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: true
JavaScriptQuotes: Double
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
KeepEmptyLinesAtTheStartOfBlocks: true
LineEnding: LF
MacroBlockBegin: ''
MacroBlockEnd: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBlockIndentWidth: 4
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
@@ -98,23 +96,21 @@ PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
PointerAlignment: Right
ReflowComments: true
SeparateDefinitionBlocks: Always
SortIncludes: CaseInsensitive
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: Never
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...
Standard: Latest
TabWidth: 4
UseTab: Never

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,105 @@
<option name="TEMPLATE_CALL_ARGUMENTS_ALIGN_MULTILINE_PARS" value="true" />
<option name="ALIGN_DICTIONARY_PAIR_VALUES" value="true" />
</Objective-C>
<RiderCodeStyleSettings>
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="NEXT_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="NEXT_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="NEXT_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="NEXT_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/FREE_BLOCK_BRACES/@EntryValue" value="NEXT_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="NEXT_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="NEXT_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="NEXT_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
</RiderCodeStyleSettings>
<Shell_Script>
<option name="SWITCH_CASES_INDENTED" value="true" />
<option name="REDIRECT_FOLLOWED_BY_SPACE" value="true" />
@@ -36,22 +135,6 @@
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
</codeStyleSettings>
<codeStyleSettings language="ObjectiveC">
<option name="BRACE_STYLE" value="2" />
<option name="CLASS_BRACE_STYLE" value="2" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="WHILE_ON_NEW_LINE" value="true" />
<option name="CATCH_ON_NEW_LINE" value="true" />
<option name="FINALLY_ON_NEW_LINE" value="true" />
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
<option name="ALIGN_GROUP_FIELD_DECLARATIONS" value="true" />
<option name="SPACE_AFTER_TYPE_CAST" value="false" />
<option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_SYNCHRONIZED_PARENTHESES" value="false" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<indentOptions>
<option name="LABEL_INDENT_ABSOLUTE" value="true" />
</indentOptions>

40
3rdparty/bzip2.cmake vendored
View File

@@ -17,28 +17,28 @@ message(STATUS "BZIP2 VERSION: ${BZ_VERSION}")
# Do not disable assertions based on CMAKE_BUILD_TYPE.
foreach(_build_type Release MinSizeRel RelWithDebInfo)
foreach(_lang C)
string(TOUPPER CMAKE_${_lang}_FLAGS_${_build_type} _var)
string(REGEX REPLACE "(^|)[/-]D *NDEBUG($|)" " " ${_var} "${${_var}}")
endforeach()
foreach(_lang C)
string(TOUPPER CMAKE_${_lang}_FLAGS_${_build_type} _var)
string(REGEX REPLACE "(^|)[/-]D *NDEBUG($|)" " " ${_var} "${${_var}}")
endforeach()
endforeach()
# Support the latest c++ standard available.
include(ExtractValidFlags)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the build type" FORCE)
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the build type" FORCE)
# Include "None" as option to disable any additional (optimization) flags,
# relying on just CMAKE_C_FLAGS and CMAKE_CXX_FLAGS (which are empty by
# default). These strings are presented in cmake-gui.
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
None Debug Release MinSizeRel RelWithDebInfo)
# Include "None" as option to disable any additional (optimization) flags,
# relying on just CMAKE_C_FLAGS and CMAKE_CXX_FLAGS (which are empty by
# default). These strings are presented in cmake-gui.
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
None Debug Release MinSizeRel RelWithDebInfo)
endif()
# Always use '-fPIC'/'-fPIE' option, except when using MingW to compile for WoA.
if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW" OR (NOT "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "aarch64" AND NOT "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm"))
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
# Checks for header files.
@@ -60,13 +60,13 @@ include(CheckTypeSize)
# Checks for typedefs, structures, and compiler characteristics.
# AC_TYPE_SIZE_T
if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW" OR (NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" AND NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64"))
check_type_size("ssize_t" SIZEOF_SSIZE_T)
check_type_size("ssize_t" SIZEOF_SSIZE_T)
endif()
if(NOT SIZEOF_SSIZE_T)
# ssize_t is a signed type in POSIX storing at least -1.
# Set it to "int" to match the behavior of AC_TYPE_SSIZE_T (autotools).
set(ssize_t int)
# ssize_t is a signed type in POSIX storing at least -1.
# Set it to "int" to match the behavior of AC_TYPE_SSIZE_T (autotools).
set(ssize_t int)
endif()
include(CheckStructHasMember)
@@ -82,11 +82,11 @@ include(CheckSymbolExists)
# XXX does this correctly detect initgroups (un)availability on cygwin?
check_symbol_exists(initgroups grp.h HAVE_DECL_INITGROUPS)
if(NOT HAVE_DECL_INITGROUPS AND HAVE_UNISTD_H)
# FreeBSD declares initgroups() in unistd.h
check_symbol_exists(initgroups unistd.h HAVE_DECL_INITGROUPS2)
if(HAVE_DECL_INITGROUPS2)
set(HAVE_DECL_INITGROUPS 1)
endif()
# FreeBSD declares initgroups() in unistd.h
check_symbol_exists(initgroups unistd.h HAVE_DECL_INITGROUPS2)
if(HAVE_DECL_INITGROUPS2)
set(HAVE_DECL_INITGROUPS 1)
endif()
endif()
# The build targets.

62
3rdparty/flac.cmake vendored
View File

@@ -51,13 +51,13 @@ check_include_file("arm_neon.h" FLAC__HAS_NEONINTRIN)
check_include_file("semaphore.h" HAVE_SEMAPHORE_H)
if(NOT HAVE_STDINT_H OR NOT HAVE_STDBOOL_H)
message(SEND_ERROR "Header stdint.h and/or stdbool.h not found")
message(SEND_ERROR "Header stdint.h and/or stdbool.h not found")
endif()
if(MSVC)
check_include_file("intrin.h" FLAC__HAS_X86INTRIN)
check_include_file("intrin.h" FLAC__HAS_X86INTRIN)
else()
check_include_file("x86intrin.h" FLAC__HAS_X86INTRIN)
check_include_file("x86intrin.h" FLAC__HAS_X86INTRIN)
endif()
check_function_exists(fseeko HAVE_FSEEKO)
@@ -66,14 +66,14 @@ check_c_source_compiles("int main() { return __builtin_bswap16 (0) ; }" HAVE_BSW
check_c_source_compiles("int main() { return __builtin_bswap32 (0) ; }" HAVE_BSWAP32)
if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW" OR (NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" AND NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64"))
test_big_endian(CPU_IS_BIG_ENDIAN)
test_big_endian(CPU_IS_BIG_ENDIAN)
endif()
check_c_compiler_flag(-mstackrealign HAVE_STACKREALIGN_FLAG)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "i686" AND HAVE_STACKREALIGN_FLAG)
add_compile_options(-mstackrealign)
add_compile_options($<$<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>:-mstackrealign>)
add_compile_options(-mstackrealign)
add_compile_options($<$<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>:-mstackrealign>)
endif()
include_directories("3rdparty/flac/include")
@@ -82,9 +82,9 @@ include_directories("${CMAKE_CURRENT_BINARY_DIR}/3rdparty/flac")
add_definitions(-DHAVE_CONFIG_H)
if(MSVC)
add_definitions(
-D_CRT_SECURE_NO_WARNINGS
-D_USE_MATH_DEFINES)
add_definitions(
-D_CRT_SECURE_NO_WARNINGS
-D_USE_MATH_DEFINES)
endif()
option(WITH_ASM "Use any assembly optimization routines" ON)
@@ -101,36 +101,36 @@ include(CheckA64NEON)
check_cpu_arch_x64(FLAC__CPU_X86_64)
if(NOT FLAC__CPU_X86_64)
check_cpu_arch_x86(FLAC__CPU_IA32)
check_cpu_arch_x86(FLAC__CPU_IA32)
endif()
if(FLAC__CPU_X86_64 OR FLAC__CPU_IA32)
set(FLAC__ALIGN_MALLOC_DATA 1)
option(WITH_AVX "Enable AVX, AVX2 optimizations (with runtime detection, resulting binary does not require AVX2, so only necessary when a compiler doesn't know about AVX)" ON)
if(WITH_AVX AND MSVC)
set_source_files_properties(fixed_intrin_avx2.c lpc_intrin_avx2.c stream_encoder_intrin_avx2.c PROPERTIES COMPILE_FLAGS /arch:AVX2)
set_source_files_properties(lpc_intrin_fma.c PROPERTIES COMPILE_FLAGS "/arch:AVX2 /fp:fast")
endif()
if(WITH_AVX AND (CMAKE_C_COMPILER_ID MATCHES "Clang"))
set_source_files_properties(lpc_intrin_fma.c PROPERTIES COMPILE_FLAGS "-ffast-math")
endif()
set(FLAC__ALIGN_MALLOC_DATA 1)
option(WITH_AVX "Enable AVX, AVX2 optimizations (with runtime detection, resulting binary does not require AVX2, so only necessary when a compiler doesn't know about AVX)" ON)
if(WITH_AVX AND MSVC)
set_source_files_properties(fixed_intrin_avx2.c lpc_intrin_avx2.c stream_encoder_intrin_avx2.c PROPERTIES COMPILE_FLAGS /arch:AVX2)
set_source_files_properties(lpc_intrin_fma.c PROPERTIES COMPILE_FLAGS "/arch:AVX2 /fp:fast")
endif()
if(WITH_AVX AND (CMAKE_C_COMPILER_ID MATCHES "Clang"))
set_source_files_properties(lpc_intrin_fma.c PROPERTIES COMPILE_FLAGS "-ffast-math")
endif()
else()
if(FLAC__CPU_ARM64)
check_a64neon(FLAC__HAS_A64NEONINTRIN)
endif()
if(FLAC__CPU_ARM64)
check_a64neon(FLAC__HAS_A64NEONINTRIN)
endif()
endif()
if(NOT WITH_ASM)
add_definitions(-DFLAC__NO_ASM)
add_definitions(-DFLAC__NO_ASM)
endif()
if(HAVE_SEMAPHORE_H)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads)
if(CMAKE_USE_PTHREADS_INIT)
set(HAVE_PTHREAD 1)
endif()
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads)
if(CMAKE_USE_PTHREADS_INIT)
set(HAVE_PTHREAD 1)
endif()
endif()
include_directories("3rdparty/flac/src/libFLAC/include")
@@ -177,13 +177,13 @@ target_compile_definitions("Aaru.Compression.Native" PUBLIC FLAC__NO_FILEIO)
# Disable fortify source when not-release or when cross-building with MingW for WoA
if(CMAKE_BUILD_TYPE STREQUAL Debug OR CMAKE_BUILD_TYPE STREQUAL RelWithDebInfo OR "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW")
set(DODEFINE_FORTIFY_SOURCE 0)
set(DODEFINE_FORTIFY_SOURCE 0)
endif()
set_property(TARGET "Aaru.Compression.Native" PROPERTY C_VISIBILITY_PRESET hidden)
if(ARCHITECTURE_IS_64BIT)
set(ENABLE_64_BIT_WORDS 1)
set(ENABLE_64_BIT_WORDS 1)
endif()
configure_file(3rdparty/flac/config.cmake.h.in 3rdparty/flac/config.h)

26
3rdparty/lzfse.cmake vendored
View File

@@ -8,28 +8,28 @@ include(CheckCCompilerFlag)
# set it to OFF in your project before you add_subdirectory(lzfse).
get_directory_property(LZFSE_PARENT_DIRECTORY PARENT_DIRECTORY)
if("${LZFSE_BUNDLE_MODE}" STREQUAL "")
# Bundled mode hasn't been set one way or the other, set the default
# depending on whether or not we are the top-level project.
if(LZFSE_PARENT_DIRECTORY)
set(LZFSE_BUNDLE_MODE ON)
else()
set(LZFSE_BUNDLE_MODE OFF)
endif(LZFSE_PARENT_DIRECTORY)
# Bundled mode hasn't been set one way or the other, set the default
# depending on whether or not we are the top-level project.
if(LZFSE_PARENT_DIRECTORY)
set(LZFSE_BUNDLE_MODE ON)
else()
set(LZFSE_BUNDLE_MODE OFF)
endif(LZFSE_PARENT_DIRECTORY)
endif()
mark_as_advanced(LZFSE_BUNDLE_MODE)
if(CMAKE_VERSION VERSION_GREATER 3.2)
cmake_policy(SET CMP0063 NEW)
cmake_policy(SET CMP0063 NEW)
endif()
if(CMAKE_VERSION VERSION_GREATER 3.9)
cmake_policy(SET CMP0069 NEW)
cmake_policy(SET CMP0069 NEW)
endif()
if(ENABLE_SANITIZER)
set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
endif()
set(LZFSE_SOURCES
@@ -47,5 +47,5 @@ target_sources("Aaru.Compression.Native" PRIVATE ${LZFSE_SOURCES})
if(NOT AARU_MUSL AND (NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm"))
set_property(TARGET "Aaru.Compression.Native" PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
set_property(TARGET "Aaru.Compression.Native" PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()

64
3rdparty/lzma.cmake vendored
View File

@@ -11,29 +11,29 @@ target_compile_definitions("Aaru.Compression.Native" PUBLIC _7ZIP_ST)
# All assembly for x86 and x64 disabled because it uses a custom, non GAS, non MASM, assembler
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64")
set(IS_X64 1)
target_compile_definitions("Aaru.Compression.Native" PUBLIC IS_X64)
set(IS_X64 1)
target_compile_definitions("Aaru.Compression.Native" PUBLIC IS_X64)
# if(NOT "${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
# set(USE_ASM 1)
# endif()
# if(NOT "${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
# set(USE_ASM 1)
# endif()
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "i686")
set(IS_X86 1)
target_compile_definitions("Aaru.Compression.Native" PUBLIC IS_X86)
# set(USE_ASM 1)
set(IS_X86 1)
target_compile_definitions("Aaru.Compression.Native" PUBLIC IS_X86)
# set(USE_ASM 1)
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
set(IS_ARM64 1)
target_compile_definitions("Aaru.Compression.Native" PUBLIC IS_ARM64)
set(USE_ASM 1)
set(IS_ARM64 1)
target_compile_definitions("Aaru.Compression.Native" PUBLIC IS_ARM64)
set(USE_ASM 1)
endif()
if("${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang" OR "${CMAKE_C_COMPILER_ID}" MATCHES "Clang")
set(USE_CLANG 1)
target_compile_definitions("Aaru.Compression.Native" PUBLIC USE_CLANG)
set(USE_CLANG 1)
target_compile_definitions("Aaru.Compression.Native" PUBLIC USE_CLANG)
endif()
if(DEFINED AARU_MUSL)
target_compile_definitions("Aaru.Compression.Native" PUBLIC Z7_AFFINITY_DISABLE)
target_compile_definitions("Aaru.Compression.Native" PUBLIC Z7_AFFINITY_DISABLE)
endif()
#target_compile_options(lzma PUBLIC -Wall)
@@ -43,10 +43,10 @@ target_compile_definitions("Aaru.Compression.Native" PUBLIC $<$<COMPILE_LANGUAGE
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64")
target_compile_options("Aaru.Compression.Native" PUBLIC $<$<COMPILE_LANGUAGE:ASM>:-elf64>)
target_compile_options("Aaru.Compression.Native" PUBLIC $<$<COMPILE_LANGUAGE:ASM>:-elf64>)
else()
target_compile_options("Aaru.Compression.Native" PUBLIC $<$<COMPILE_LANGUAGE:ASM>:-elf>)
target_compile_definitions("Aaru.Compression.Native" PUBLIC $<$<COMPILE_LANGUAGE:ASM>:-DABI_CDECL>)
target_compile_options("Aaru.Compression.Native" PUBLIC $<$<COMPILE_LANGUAGE:ASM>:-elf>)
target_compile_definitions("Aaru.Compression.Native" PUBLIC $<$<COMPILE_LANGUAGE:ASM>:-DABI_CDECL>)
endif()
#target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_C_DIRECTORY}/7zAlloc.c)
@@ -104,9 +104,9 @@ target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_C_DIRECTORY}/LzmaLib.c)
#target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_ASM_DIRECTORY}/x86/7zCrcOpt.asm)
if(USE_ASM)
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "i686" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64")
set(USE_X86_ASM 1)
endif()
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "i686" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64")
set(USE_X86_ASM 1)
endif()
endif()
#if(USE_X86_ASM)
@@ -124,21 +124,21 @@ endif()
#endif()
if(USE_LZMA_DEC_ASM)
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64")
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_ASM_DIRECTORY}/x86/LzFindOpt.asm)
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_ASM_DIRECTORY}/x86/LzmaDecOpt.asm)
endif()
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64")
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_ASM_DIRECTORY}/x86/LzFindOpt.asm)
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_ASM_DIRECTORY}/x86/LzmaDecOpt.asm)
endif()
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_ASM_DIRECTORY}/arm64/LzmaDecOpt.S)
# target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_ASM_DIRECTORY}/arm64/7zAsm.S)
endif()
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_ASM_DIRECTORY}/arm64/LzmaDecOpt.S)
# target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_ASM_DIRECTORY}/arm64/7zAsm.S)
endif()
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_C_DIRECTORY}/LzFindOpt.c)
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_C_DIRECTORY}/LzmaDec.c)
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_C_DIRECTORY}/LzFindOpt.c)
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_C_DIRECTORY}/LzmaDec.c)
else()
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_C_DIRECTORY}/LzFindOpt.c)
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_C_DIRECTORY}/LzmaDec.c)
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_C_DIRECTORY}/LzFindOpt.c)
target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_C_DIRECTORY}/LzmaDec.c)
endif()
#target_sources("Aaru.Compression.Native" PRIVATE ${LZMA_C_DIRECTORY}/XzDec.c)

256
3rdparty/zstd.cmake vendored
View File

@@ -14,12 +14,12 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
set(ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION "3")
set(ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION "13") #Policies never changed at PATCH level
if("${CMAKE_MAJOR_VERSION}" LESS 3)
set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}")
set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}")
elseif("${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}" EQUAL "${CMAKE_MAJOR_VERSION}" AND
"${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}" GREATER "${CMAKE_MINOR_VERSION}")
set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}")
set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}")
else()
set(ZSTD_CMAKE_POLICY_VERSION "${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}.${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}.0")
set(ZSTD_CMAKE_POLICY_VERSION "${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}.${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}.0")
endif()
cmake_policy(VERSION ${ZSTD_CMAKE_POLICY_VERSION})
@@ -32,22 +32,22 @@ include(GetZstdLibraryVersion)
getzstdlibraryversion(${LIBRARY_DIR}/zstd.h zstd_VERSION_MAJOR zstd_VERSION_MINOR zstd_VERSION_PATCH)
if(CMAKE_MAJOR_VERSION LESS 3)
## Provide cmake 3+ behavior for older versions of cmake
project(zstd)
set(PROJECT_VERSION_MAJOR ${zstd_VERSION_MAJOR})
set(PROJECT_VERSION_MINOR ${zstd_VERSION_MINOR})
set(PROJECT_VERSION_PATCH ${zstd_VERSION_PATCH})
set(PROJECT_VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}")
enable_language(C) # Main library is in C
enable_language(ASM) # And ASM
enable_language(CXX) # Testing contributed code also utilizes CXX
## Provide cmake 3+ behavior for older versions of cmake
project(zstd)
set(PROJECT_VERSION_MAJOR ${zstd_VERSION_MAJOR})
set(PROJECT_VERSION_MINOR ${zstd_VERSION_MINOR})
set(PROJECT_VERSION_PATCH ${zstd_VERSION_PATCH})
set(PROJECT_VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}")
enable_language(C) # Main library is in C
enable_language(ASM) # And ASM
enable_language(CXX) # Testing contributed code also utilizes CXX
else()
project(zstd
VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}"
LANGUAGES C # Main library is in C
ASM # And ASM
CXX # Testing contributed code also utilizes CXX
)
project(zstd
VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}"
LANGUAGES C # Main library is in C
ASM # And ASM
CXX # Testing contributed code also utilizes CXX
)
endif()
message(STATUS "ZSTD VERSION: ${zstd_VERSION}")
@@ -56,10 +56,10 @@ set(zstd_DESCRIPTION "Zstandard is a real-time compression algorithm, providing
# Set a default build type if none was specified
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'Release' as none was specified.")
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
message(STATUS "Setting build type to 'Release' as none was specified.")
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
#-----------------------------------------------------------------------------
@@ -70,83 +70,83 @@ include(CheckCXXCompilerFlag)
include(CheckCCompilerFlag)
function(enablecompilerflag _flag _C _CXX)
string(REGEX REPLACE "\\+" "PLUS" varname "${_flag}")
string(REGEX REPLACE "[^A-Za-z0-9]+" "_" varname "${varname}")
string(REGEX REPLACE "^_+" "" varname "${varname}")
string(TOUPPER "${varname}" varname)
if(_C)
check_c_compiler_flag(${_flag} C_FLAG_${varname})
if(C_FLAG_${varname})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_flag}" PARENT_SCOPE)
endif()
string(REGEX REPLACE "\\+" "PLUS" varname "${_flag}")
string(REGEX REPLACE "[^A-Za-z0-9]+" "_" varname "${varname}")
string(REGEX REPLACE "^_+" "" varname "${varname}")
string(TOUPPER "${varname}" varname)
if(_C)
check_c_compiler_flag(${_flag} C_FLAG_${varname})
if(C_FLAG_${varname})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_flag}" PARENT_SCOPE)
endif()
if(_CXX)
check_cxx_compiler_flag(${_flag} CXX_FLAG_${varname})
if(CXX_FLAG_${varname})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flag}" PARENT_SCOPE)
endif()
endif()
if(_CXX)
check_cxx_compiler_flag(${_flag} CXX_FLAG_${varname})
if(CXX_FLAG_${varname})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flag}" PARENT_SCOPE)
endif()
endif()
endfunction()
macro(add_zstd_compilation_flags)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" OR MINGW) #Not only UNIX but also WIN32 for MinGW
#Set c++11 by default
enablecompilerflag("-std=c++11" false true)
#Set c99 by default
enablecompilerflag("-std=c99" true false)
# if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC)
# # clang-cl normally maps -Wall to -Weverything.
# EnableCompilerFlag("/clang:-Wall" true true)
# else ()
# EnableCompilerFlag("-Wall" true true)
# endif ()
# EnableCompilerFlag("-Wextra" true true)
# EnableCompilerFlag("-Wundef" true true)
# EnableCompilerFlag("-Wshadow" true true)
# EnableCompilerFlag("-Wcast-align" true true)
# EnableCompilerFlag("-Wcast-qual" true true)
# EnableCompilerFlag("-Wstrict-prototypes" true false)
# Enable asserts in Debug mode
if(CMAKE_BUILD_TYPE MATCHES "Debug")
enablecompilerflag("-DDEBUGLEVEL=1" true true)
endif()
elseif(MSVC) # Add specific compilation flags for Windows Visual
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang" OR MINGW) #Not only UNIX but also WIN32 for MinGW
#Set c++11 by default
enablecompilerflag("-std=c++11" false true)
#Set c99 by default
enablecompilerflag("-std=c99" true false)
# if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC)
# # clang-cl normally maps -Wall to -Weverything.
# EnableCompilerFlag("/clang:-Wall" true true)
# else ()
# EnableCompilerFlag("-Wall" true true)
# endif ()
# EnableCompilerFlag("-Wextra" true true)
# EnableCompilerFlag("-Wundef" true true)
# EnableCompilerFlag("-Wshadow" true true)
# EnableCompilerFlag("-Wcast-align" true true)
# EnableCompilerFlag("-Wcast-qual" true true)
# EnableCompilerFlag("-Wstrict-prototypes" true false)
# Enable asserts in Debug mode
if(CMAKE_BUILD_TYPE MATCHES "Debug")
enablecompilerflag("-DDEBUGLEVEL=1" true true)
endif()
elseif(MSVC) # Add specific compilation flags for Windows Visual
set(ACTIVATE_MULTITHREADED_COMPILATION "ON" CACHE BOOL "activate multi-threaded compilation (/MP flag)")
if(CMAKE_GENERATOR MATCHES "Visual Studio" AND ACTIVATE_MULTITHREADED_COMPILATION)
enablecompilerflag("/MP" true true)
endif()
# UNICODE SUPPORT
enablecompilerflag("/D_UNICODE" true true)
enablecompilerflag("/DUNICODE" true true)
# Enable asserts in Debug mode
if(CMAKE_BUILD_TYPE MATCHES "Debug")
enablecompilerflag("/DDEBUGLEVEL=1" true true)
endif()
set(ACTIVATE_MULTITHREADED_COMPILATION "ON" CACHE BOOL "activate multi-threaded compilation (/MP flag)")
if(CMAKE_GENERATOR MATCHES "Visual Studio" AND ACTIVATE_MULTITHREADED_COMPILATION)
enablecompilerflag("/MP" true true)
endif()
# Remove duplicates compilation flags
# UNICODE SUPPORT
enablecompilerflag("/D_UNICODE" true true)
enablecompilerflag("/DUNICODE" true true)
# Enable asserts in Debug mode
if(CMAKE_BUILD_TYPE MATCHES "Debug")
enablecompilerflag("/DDEBUGLEVEL=1" true true)
endif()
endif()
# Remove duplicates compilation flags
foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag_var})
separate_arguments(${flag_var})
string(REPLACE ";" " " ${flag_var} "${${flag_var}}")
endif()
endforeach()
if(MSVC AND ZSTD_USE_STATIC_RUNTIME)
foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag_var})
separate_arguments(${flag_var})
string(REPLACE ";" " " ${flag_var} "${${flag_var}}")
endif()
if(${flag_var})
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif()
endforeach()
if(MSVC AND ZSTD_USE_STATIC_RUNTIME)
foreach(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag_var})
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif()
endforeach()
endif()
endif()
endmacro()
@@ -170,31 +170,31 @@ add_definitions(-DXXH_NAMESPACE=ZSTD_)
option(ZSTD_LEGACY_SUPPORT "LEGACY SUPPORT" OFF)
if(ZSTD_LEGACY_SUPPORT)
message(STATUS "ZSTD_LEGACY_SUPPORT defined!")
add_definitions(-DZSTD_LEGACY_SUPPORT=5)
message(STATUS "ZSTD_LEGACY_SUPPORT defined!")
add_definitions(-DZSTD_LEGACY_SUPPORT=5)
else()
message(STATUS "ZSTD_LEGACY_SUPPORT not defined!")
add_definitions(-DZSTD_LEGACY_SUPPORT=0)
message(STATUS "ZSTD_LEGACY_SUPPORT not defined!")
add_definitions(-DZSTD_LEGACY_SUPPORT=0)
endif()
# Multi-threading support
if(ANDROID)
option(ZSTD_MULTITHREAD_SUPPORT "MULTITHREADING SUPPORT" OFF)
option(ZSTD_MULTITHREAD_SUPPORT "MULTITHREADING SUPPORT" OFF)
else()
option(ZSTD_MULTITHREAD_SUPPORT "MULTITHREADING SUPPORT" ON)
option(ZSTD_MULTITHREAD_SUPPORT "MULTITHREADING SUPPORT" ON)
endif()
#-----------------------------------------------------------------------------
# External dependencies
#-----------------------------------------------------------------------------
if(ZSTD_MULTITHREAD_SUPPORT AND UNIX)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
if(CMAKE_USE_PTHREADS_INIT)
set(THREADS_LIBS "${CMAKE_THREAD_LIBS_INIT}")
else()
message(SEND_ERROR "ZSTD currently does not support thread libraries other than pthreads")
endif()
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
if(CMAKE_USE_PTHREADS_INIT)
set(THREADS_LIBS "${CMAKE_THREAD_LIBS_INIT}")
else()
message(SEND_ERROR "ZSTD currently does not support thread libraries other than pthreads")
endif()
endif()
project(libzstd C)
@@ -230,32 +230,32 @@ set(Headers
${DictBuilderHeaders})
if(ZSTD_LEGACY_SUPPORT)
set(LIBRARY_LEGACY_DIR ${LIBRARY_DIR}/legacy)
include_directories(${LIBRARY_LEGACY_DIR})
set(LIBRARY_LEGACY_DIR ${LIBRARY_DIR}/legacy)
include_directories(${LIBRARY_LEGACY_DIR})
set(Sources ${Sources}
${LIBRARY_LEGACY_DIR}/zstd_v01.c
${LIBRARY_LEGACY_DIR}/zstd_v02.c
${LIBRARY_LEGACY_DIR}/zstd_v03.c
${LIBRARY_LEGACY_DIR}/zstd_v04.c
${LIBRARY_LEGACY_DIR}/zstd_v05.c
${LIBRARY_LEGACY_DIR}/zstd_v06.c
${LIBRARY_LEGACY_DIR}/zstd_v07.c)
set(Sources ${Sources}
${LIBRARY_LEGACY_DIR}/zstd_v01.c
${LIBRARY_LEGACY_DIR}/zstd_v02.c
${LIBRARY_LEGACY_DIR}/zstd_v03.c
${LIBRARY_LEGACY_DIR}/zstd_v04.c
${LIBRARY_LEGACY_DIR}/zstd_v05.c
${LIBRARY_LEGACY_DIR}/zstd_v06.c
${LIBRARY_LEGACY_DIR}/zstd_v07.c)
set(Headers ${Headers}
${LIBRARY_LEGACY_DIR}/zstd_legacy.h
${LIBRARY_LEGACY_DIR}/zstd_v01.h
${LIBRARY_LEGACY_DIR}/zstd_v02.h
${LIBRARY_LEGACY_DIR}/zstd_v03.h
${LIBRARY_LEGACY_DIR}/zstd_v04.h
${LIBRARY_LEGACY_DIR}/zstd_v05.h
${LIBRARY_LEGACY_DIR}/zstd_v06.h
${LIBRARY_LEGACY_DIR}/zstd_v07.h)
set(Headers ${Headers}
${LIBRARY_LEGACY_DIR}/zstd_legacy.h
${LIBRARY_LEGACY_DIR}/zstd_v01.h
${LIBRARY_LEGACY_DIR}/zstd_v02.h
${LIBRARY_LEGACY_DIR}/zstd_v03.h
${LIBRARY_LEGACY_DIR}/zstd_v04.h
${LIBRARY_LEGACY_DIR}/zstd_v05.h
${LIBRARY_LEGACY_DIR}/zstd_v06.h
${LIBRARY_LEGACY_DIR}/zstd_v07.h)
endif()
if(MSVC)
set(MSVC_RESOURCE_DIR ${ZSTD_SOURCE_DIR}/build/VS2010/libzstd-dll)
set(PlatformDependResources ${MSVC_RESOURCE_DIR}/libzstd-dll.rc)
set(MSVC_RESOURCE_DIR ${ZSTD_SOURCE_DIR}/build/VS2010/libzstd-dll)
set(PlatformDependResources ${MSVC_RESOURCE_DIR}/libzstd-dll.rc)
endif()
# Explicitly set the language to C for all files, including ASM files.
@@ -270,23 +270,23 @@ set(library_targets)
add_library(libzstd_static STATIC ${Sources} ${Headers})
list(APPEND library_targets libzstd_static)
if(ZSTD_MULTITHREAD_SUPPORT)
set_property(TARGET libzstd_static APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_MULTITHREAD")
if(UNIX)
target_link_libraries(libzstd_static ${THREADS_LIBS})
endif()
set_property(TARGET libzstd_static APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_MULTITHREAD")
if(UNIX)
target_link_libraries(libzstd_static ${THREADS_LIBS})
endif()
endif()
#endif ()
# Add specific compile definitions for MSVC project
if(MSVC)
set_property(TARGET libzstd_static APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_HEAPMODE=0;_CRT_SECURE_NO_WARNINGS")
set_property(TARGET libzstd_static APPEND PROPERTY COMPILE_DEFINITIONS "ZSTD_HEAPMODE=0;_CRT_SECURE_NO_WARNINGS")
endif()
# With MSVC static library needs to be renamed to avoid conflict with import library
if(MSVC)
set(STATIC_LIBRARY_BASE_NAME zstd_static)
set(STATIC_LIBRARY_BASE_NAME zstd_static)
else()
set(STATIC_LIBRARY_BASE_NAME zstd)
set(STATIC_LIBRARY_BASE_NAME zstd)
endif()
# Define static and shared library names
@@ -298,5 +298,5 @@ set_target_properties(
#endif ()
if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW" OR (NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" AND NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64"))
set_property(TARGET libzstd_static PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libzstd_static PROPERTY POSITION_INDEPENDENT_CODE ON)
endif()

View File

@@ -2,12 +2,12 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Aaru.Compression.Native</id>
<version>6.0.0-alpha10</version>
<version>6.0.0-alpha.11.4</version>
<description>C implementation of compression algorithms used by Aaru.</description>
<authors>claunia</authors>
<projectUrl>https://github.com/aaru-dps/Aaru.Compression.Native</projectUrl>
<licenseUrl>https://spdx.org/licenses/LGPL-2.1-only.html</licenseUrl>
<copyright>Copyright © 2011-2023 Natalia Portillo</copyright>
<copyright>Copyright © 2011-2025 Natalia Portillo</copyright>
<repository type="git" url="https://github.com/aaru-dps/Aaru.Compression.Native.git" />
</metadata>
<files>

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.15)
# This file is part of the Aaru Data Preservation Suite.
# Copyright (c) 2019-2023 Natalia Portillo.
# Copyright (c) 2019-2025 Natalia Portillo.
#
# This library is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
@@ -17,48 +17,48 @@ cmake_minimum_required(VERSION 3.15)
# License along with this library; if not, see <http://www.gnu.org/licenses/>.
if(APPLE)
# Too early cmake has not yet set it
if((NOT DEFINED CMAKE_SYSTEM_PROCESSOR) AND (NOT DEFINED AARU_MACOS_TARGET_ARCH))
execute_process(COMMAND uname -m OUTPUT_VARIABLE AARU_MACOS_TARGET_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
# Too early cmake has not yet set it
if((NOT DEFINED CMAKE_SYSTEM_PROCESSOR) AND (NOT DEFINED AARU_MACOS_TARGET_ARCH))
execute_process(COMMAND uname -m OUTPUT_VARIABLE AARU_MACOS_TARGET_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
if(NOT DEFINED AARU_MACOS_TARGET_ARCH)
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64")
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "Build architectures for macOS" FORCE)
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm64")
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "Build architectures for macOS" FORCE)
else()
message(FATAL_ERROR "Unknown system processor ${CMAKE_SYSTEM_PROCESSOR} for macOS")
endif()
elseif(AARU_MACOS_TARGET_ARCH STREQUAL "x86_64")
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "Build architectures for macOS" FORCE)
elseif(AARU_MACOS_TARGET_ARCH STREQUAL "arm64")
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "Build architectures for macOS" FORCE)
if(NOT DEFINED AARU_MACOS_TARGET_ARCH)
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64")
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "Build architectures for macOS" FORCE)
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm64")
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "Build architectures for macOS" FORCE)
else()
message(FATAL_ERROR "Unknown Aaru target architecture ${AARU_MACOS_TARGET_ARCH} for macOS")
message(FATAL_ERROR "Unknown system processor ${CMAKE_SYSTEM_PROCESSOR} for macOS")
endif()
elseif(AARU_MACOS_TARGET_ARCH STREQUAL "x86_64")
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "Build architectures for macOS" FORCE)
elseif(AARU_MACOS_TARGET_ARCH STREQUAL "arm64")
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "Build architectures for macOS" FORCE)
else()
message(FATAL_ERROR "Unknown Aaru target architecture ${AARU_MACOS_TARGET_ARCH} for macOS")
endif()
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
endif(APPLE)
project("Aaru.Compression.Native" C)
if("${CMAKE_C_COMPILER_ID}" MATCHES "MSVC" AND "${CMAKE_C_COMPILER_ARCHITECTURE_ID}" MATCHES "ARMV7")
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD 11)
else()
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD 99)
endif()
if("${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW")
if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "aarch64" OR "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm")
set(WIN32 TRUE)
endif()
if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "aarch64" OR "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm")
set(WIN32 TRUE)
endif()
add_link_options(-static-libgcc)
add_link_options(-static-libgcc)
endif()
if(DEFINED AARU_MACOS_TARGET_ARCH)
message("Requested target architecture: ${AARU_MACOS_TARGET_ARCH}")
message("Requested target architecture: ${AARU_MACOS_TARGET_ARCH}")
endif()
message("Detected system processor: ${CMAKE_SYSTEM_PROCESSOR}")
message("Detected vs platform name: ${CMAKE_C_COMPILER_ARCHITECTURE_ID}")
@@ -69,66 +69,80 @@ message("Size of (void*): ${CMAKE_SIZEOF_VOID_P}")
# Check if target is 64-bit
if("${CMAKE_SIZEOF_VOID_P}" MATCHES "8" OR "${CMAKE_C_COMPILER_ARCHITECTURE_ID}" MATCHES "x64" OR "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86_64" OR "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "AMD64" OR "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "aarch64")
set(ARCHITECTURE_IS_64BIT TRUE)
set(ARCHITECTURE_IS_64BIT TRUE)
endif()
if("${CMAKE_BUILD_TYPE}" MATCHES "Release" OR "${CMAKE_BUILD_TYPE}" MATCHES "RelWithDebInfo" OR "${CMAKE_BUILD_TYPE}" MATCHES "MinSizeRel")
if("${CMAKE_BUILD_TYPE}" MATCHES "Release")
add_compile_definitions(NDEBUG)
if("${CMAKE_BUILD_TYPE}" MATCHES "Release")
add_compile_definitions(NDEBUG)
endif()
if("${CMAKE_C_COMPILER_ID}" MATCHES "MSVC")
add_compile_options("/O2 /Ob2 /Oi /Ot /Oy /Og /fp:fast")
if(${CMAKE_C_COMPILER_ARCHITECTURE_ID} MATCHES "X86")
add_compile_options("/arch:SSE2")
elseif(${CMAKE_C_COMPILER_ARCHITECTURE_ID} MATCHES "ARM")
add_compile_options("/arch:VFPv4")
endif()
else()
add_compile_options(-ffast-math -Ofast)
if("${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
if(${AARU_MACOS_TARGET_ARCH} MATCHES "x86_64")
add_compile_options(-march=ivybridge -mtune=westmere -msse4.2)
elseif(${AARU_MACOS_TARGET_ARCH} MATCHES "arm64")
add_compile_options(-mcpu=apple-m1 -mtune=apple-m1)
endif()
endif()
if("${CMAKE_C_COMPILER_ID}" MATCHES "MSVC")
add_compile_options("/O2 /Ob2 /Oi /Ot /Oy /Og /fp:fast")
if(${CMAKE_C_COMPILER_ARCHITECTURE_ID} MATCHES "X86")
add_compile_options("/arch:SSE2")
elseif(${CMAKE_C_COMPILER_ARCHITECTURE_ID} MATCHES "ARM")
add_compile_options("/arch:VFPv4")
endif()
else()
add_compile_options(-ffast-math -Ofast)
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "i686" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64")
if(NOT "${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
add_compile_options(-march=westmere -mtune=skylake -mfpmath=sse)
add_compile_options(-msse4.2)
endif()
if("${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
if(${AARU_MACOS_TARGET_ARCH} MATCHES "x86_64")
add_compile_options(-march=ivybridge -mtune=westmere -msse4.2)
elseif(${AARU_MACOS_TARGET_ARCH} MATCHES "arm64")
add_compile_options(-mcpu=apple-m1 -mtune=apple-m1)
endif()
endif()
if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW")
add_compile_options(-flto)
endif()
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
if(NOT "${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
add_compile_options(-mtune=cortex-a53)
endif()
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "i686" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64")
if(NOT "${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
add_compile_options(-march=westmere -mtune=skylake -mfpmath=sse)
add_compile_options(-msse4.2)
endif()
if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW")
add_compile_options(-flto)
endif()
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
if(NOT "${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
add_compile_options(-mtune=cortex-a53)
endif()
if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW")
add_compile_options(-flto)
endif()
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "armv7l" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" AND NOT "${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang")
add_compile_options(-mtune=cortex-a53 -mcpu=cortex-a7)
else()
add_compile_options(-mtune=cortex-a53 -march=armv7-a+neon-vfpv4)
endif()
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "mips")
if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW")
add_compile_options(-flto)
endif()
endif()
if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW")
add_compile_options(-flto)
endif()
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "armv7l" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" AND NOT "${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang")
add_compile_options(-mtune=cortex-a53 -mcpu=cortex-a7)
else()
add_compile_options(-mtune=cortex-a53 -march=armv7-a+neon-vfpv4)
endif()
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "mips")
if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW")
add_compile_options(-flto)
endif()
endif()
endif()
endif()
add_subdirectory(3rdparty)
add_library("Aaru.Compression.Native" SHARED library.c apple_rle.c apple_rle.h adc.c adc.h lzip.c flac.c flac.h)
add_library("Aaru.Compression.Native" SHARED library.c apple_rle.c apple_rle.h adc.c adc.h lzip.c flac.c flac.h
zoo/lzd.c zoo/lzd.h zoo/lzh.c zoo/decode.c zoo/huf.c zoo/io.c zoo/lh5.c zoo/lh5.h zoo/lzh.h zoo/ar.h zoo/maketbl.c
arc/pack.c arc/squeeze.c arc/crunch.c arc/lzw.c
pak/crush.c pak/distill.c pak/bitstream.c pak/bitstream.h pak/lzw.c pak/lzw.h pak/prefixcode.c
pak/prefixcode.h
ha/acoder.c
ha/acoder.h
ha/asc.c
ha/asc.h
ha/decompress.c
ha/hsc.c
ha/hsc.h
ha/internal.h
ha/swdict.c
ha/swdict.h)
include(3rdparty/bzip2.cmake)
include(3rdparty/flac.cmake)
@@ -137,22 +151,22 @@ include(3rdparty/lzip.cmake)
include(3rdparty/lzma.cmake)
macro(target_link_libraries_whole_archive target)
if("${CMAKE_C_COMPILER_ID}" MATCHES "MSVC")
foreach(arg IN LISTS ARGN)
set_target_properties(
${target} PROPERTIES LINK_FLAGS "/WHOLEARCHIVE:${lib}"
)
endforeach()
if("${CMAKE_C_COMPILER_ID}" MATCHES "MSVC")
foreach(arg IN LISTS ARGN)
set_target_properties(
${target} PROPERTIES LINK_FLAGS "/WHOLEARCHIVE:${lib}"
)
endforeach()
else()
if("${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
set(LINK_FLAGS "-Wl,-all_load")
set(UNDO_FLAGS "-Wl")
else()
if("${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang")
set(LINK_FLAGS "-Wl,-all_load")
set(UNDO_FLAGS "-Wl")
else()
set(LINK_FLAGS "-Wl,--whole-archive")
set(UNDO_FLAGS "-Wl,--no-whole-archive")
endif()
target_link_libraries(${target} ${LINK_FLAGS} ${ARGN} ${UNDO_FLAGS})
set(LINK_FLAGS "-Wl,--whole-archive")
set(UNDO_FLAGS "-Wl,--no-whole-archive")
endif()
target_link_libraries(${target} ${LINK_FLAGS} ${ARGN} ${UNDO_FLAGS})
endif()
endmacro()
target_link_libraries_whole_archive("Aaru.Compression.Native" libzstd_static m)
@@ -160,22 +174,22 @@ target_link_libraries_whole_archive("Aaru.Compression.Native" libzstd_static m)
check_include_file("semaphore.h" HAVE_SEMAPHORE_H)
if(HAVE_SEMAPHORE_H)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads)
if(CMAKE_USE_PTHREADS_INIT)
set(HAVE_PTHREAD 1)
endif()
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads)
if(CMAKE_USE_PTHREADS_INIT)
set(HAVE_PTHREAD 1)
endif()
endif()
if(HAVE_PTHREAD)
target_link_libraries_whole_archive("Aaru.Compression.Native" Threads::Threads)
target_link_libraries_whole_archive("Aaru.Compression.Native" Threads::Threads)
endif()
if(NOT "${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW" OR (NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" AND NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64"))
set_property(TARGET "Aaru.Compression.Native" PROPERTY POSITION_INDEPENDENT_CODE TRUE)
set_property(TARGET "Aaru.Compression.Native" PROPERTY POSITION_INDEPENDENT_CODE TRUE)
else()
set_property(TARGET "Aaru.Compression.Native" PROPERTY POSITION_INDEPENDENT_CODE FALSE)
set_property(TARGET "Aaru.Compression.Native" PROPERTY POSITION_INDEPENDENT_CODE FALSE)
endif()
add_subdirectory(tests)

View File

@@ -4,11 +4,14 @@ This repository contains the Aaru.Compression.Native library for [Aaru](https://
The purpose of this library is to provide compression and de-compression algorithms for Aaru.
No archiver processing code should fall here, those go in [Aaru.Compression](https://github.com/aaru-dps/Aaru/tree/devel/Aaru.Compression).
No archiver processing code should fall here, those go
in [Aaru.Compression](https://github.com/aaru-dps/Aaru/tree/devel/Aaru.Compression).
To build you just need Docker on Linux and run `build.sh`, that will generate a NuGet package for use with Aaru.Compression.
To build you just need Docker on Linux and run `build.sh`, that will generate a NuGet package for use with
Aaru.Compression.
Currently implemented algorithms are:
- Apple Data Compression (RLE with sliding dictionary created for Apple Disk Copy's NDIF)
- Apple RLE (Run Length Encoding created for Apple DART)
- [BZIP2](https://gitlab.com/bzip2/bzip2.git)
@@ -24,4 +27,4 @@ The resulting output of `build.sh` falls under the LGPL 2.1 license as stated in
Any new algorithm added should be under a license compatible with the LGPL 2.1 license to be accepted.
© 2021-2023 Natalia Portillo
© 2021-2025 Natalia Portillo

30
adc.c
View File

@@ -19,10 +19,14 @@ FORCE_INLINE int GetChunkSize(uint8_t byt)
{
switch(GetChunkType(byt))
{
case ADC_PLAIN: return (byt & 0x7F) + 1;
case ADC_TWO_BYTE: return ((byt & 0x3F) >> 2) + 3;
case ADC_THREE_BYTE: return (byt & 0x3F) + 4;
default: return -1;
case ADC_PLAIN:
return (byt & 0x7F) + 1;
case ADC_TWO_BYTE:
return ((byt & 0x3F) >> 2) + 3;
case ADC_THREE_BYTE:
return (byt & 0x3F) + 4;
default:
return -1;
}
}
@@ -30,17 +34,19 @@ FORCE_INLINE int GetOffset(uint8_t chunk[])
{
switch(GetChunkType(chunk[0]))
{
case ADC_PLAIN: return 0;
case ADC_TWO_BYTE: return ((chunk[0] & 0x03) << 8) + chunk[1];
case ADC_THREE_BYTE: return (chunk[1] << 8) + chunk[2];
default: return -1;
case ADC_PLAIN:
return 0;
case ADC_TWO_BYTE:
return ((chunk[0] & 0x03) << 8) + chunk[1];
case ADC_THREE_BYTE:
return (chunk[1] << 8) + chunk[2];
default:
return -1;
}
}
AARU_EXPORT int32_t AARU_CALL AARU_adc_decode_buffer(uint8_t* dst_buffer,
int32_t dst_size,
const uint8_t* src_buffer,
int32_t src_size)
AARU_EXPORT int32_t AARU_CALL AARU_adc_decode_buffer(uint8_t *dst_buffer, int32_t dst_size, const uint8_t *src_buffer,
int32_t src_size)
{
int inputPosition = 0;
int chunkSize;

6
adc.h
View File

@@ -5,8 +5,8 @@
#ifndef AARU_COMPRESSION_NATIVE__ADC_H_
#define AARU_COMPRESSION_NATIVE__ADC_H_
#define ADC_PLAIN 1
#define ADC_TWO_BYTE 2
#define ADC_PLAIN 1
#define ADC_TWO_BYTE 2
#define ADC_THREE_BYTE 3
#endif // AARU_COMPRESSION_NATIVE__ADC_H_
#endif // AARU_COMPRESSION_NATIVE__ADC_H_

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
* Copyright © 2018-2019 David Ryskalczyk
*
* This library is free software; you can redistribute it and/or modify
@@ -24,15 +24,13 @@
#include "library.h"
#include "apple_rle.h"
AARU_EXPORT int32_t AARU_CALL AARU_apple_rle_decode_buffer(uint8_t* dst_buffer,
int32_t dst_size,
const uint8_t* src_buffer,
int32_t src_size)
AARU_EXPORT int32_t AARU_CALL AARU_apple_rle_decode_buffer(uint8_t *dst_buffer, int32_t dst_size,
const uint8_t *src_buffer, int32_t src_size)
{
static int32_t count = 0;
static bool nextA = true; // true if A, false if B
static bool nextA = true; // true if A, false if B
static uint8_t repeatedByteA = 0, repeatedByteB = 0;
static bool repeatMode = false; // true if we're repeating, false if we're just copying
static bool repeatMode = false; // true if we're repeating, false if we're just copying
int32_t in_pos = 0, out_pos = 0;
while(in_pos <= src_size && out_pos <= dst_size)

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -21,4 +21,4 @@
#define DART_CHUNK 20960
#endif // AARU_CHECKSUMS_NATIVE__APPLE_RLE_H_
#endif // AARU_CHECKSUMS_NATIVE__APPLE_RLE_H_

295
arc/crunch.c Normal file
View File

@@ -0,0 +1,295 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
* Copyright © 2018-2019 David Ryskalczyk
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "../library.h"
#define FALSE 0
#define TRUE !FALSE
#define TABSIZE 4096 // Size of the string table.
#define NO_PRED 0xFFFF // Indicates no predecessor in the string table.
#define EMPTY 0xFFFF // Indicates an empty stack.
typedef unsigned char u_char;
typedef unsigned short u_short;
// Entry in the string table.
struct entry
{
char used; // Is this entry in use?
u_char follower; // The character that follows the string.
u_short next; // Next entry in a collision chain.
u_short predecessor; // Code for the preceding string.
};
// Static variables for decompression state.
static struct entry *string_tab;
static u_char *stack;
static int sp;
// Buffer management variables.
static const u_char *in_buf_ptr;
static size_t in_len_rem;
static int inflag;
// Pointer to the hash function to use.
static u_short (*h)(u_short, u_char);
// Original hash function from ARC.
static u_short oldh(u_short pred, u_char foll)
{
long local;
local = ((pred + foll) | 0x0800) & 0xFFFF;
local *= local;
return (local >> 6) & 0x0FFF;
}
// Newer, faster hash function.
static u_short newh(u_short pred, u_char foll) { return (((pred + foll) & 0xFFFF) * 15073) & 0xFFF; }
// Finds the end of a collision list.
static u_short eolist(u_short index)
{
int temp;
while((temp = string_tab[index].next)) index = temp;
return index;
}
// Hashes a string to find its position in the table.
static u_short hash_it(u_short pred, u_char foll)
{
u_short local, tempnext;
struct entry *ep;
local = (*h)(pred, foll);
if(!string_tab[local].used)
return local;
else
{
local = eolist(local);
tempnext = (local + 101) & 0x0FFF;
ep = &string_tab[tempnext];
while(ep->used)
{
if(++tempnext == TABSIZE)
{
tempnext = 0;
ep = string_tab;
}
else
++ep;
}
string_tab[local].next = tempnext;
return tempnext;
}
}
// Adds a new string to the table.
static void upd_tab(u_short pred, u_short foll)
{
struct entry *ep;
ep = &string_tab[hash_it(pred, foll)];
ep->used = TRUE;
ep->next = 0;
ep->predecessor = pred;
ep->follower = foll;
}
// Initializes the string table.
static void init_tab()
{
memset((char *)string_tab, 0, TABSIZE * sizeof(struct entry));
for(unsigned int i = 0; i < 256; i++) upd_tab(NO_PRED, i);
}
// Reads a 12-bit code from the input buffer.
static int get_code()
{
int code;
if(in_len_rem < 2) return -1;
if((inflag ^= 1))
{
code = (*in_buf_ptr++ << 4);
code |= (*in_buf_ptr >> 4);
in_len_rem--;
}
else
{
code = (*in_buf_ptr++ & 0x0f) << 8;
code |= (*in_buf_ptr++);
in_len_rem -= 2;
}
return code;
}
// Pushes a character onto the stack.
#define PUSH(c) \
do { \
stack[sp] = ((char)(c)); \
if(++sp >= TABSIZE) return -1; \
} while(0)
// Pops a character from the stack.
#define POP() ((sp > 0) ? (int)stack[--sp] : EMPTY)
// Internal crunch decompression logic.
static int arc_decompress_crunch_internal(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len, int new_hash)
{
// Basic validation of pointers.
if(!in_buf || !out_buf || !out_len) { return -1; }
// Allocate memory for tables.
string_tab = (struct entry *)malloc(TABSIZE * sizeof(struct entry));
stack = (u_char *)malloc(TABSIZE * sizeof(u_char));
if(!string_tab || !stack)
{
if(string_tab) free(string_tab);
if(stack) free(stack);
return -1;
}
// Select the hash function.
if(new_hash)
h = newh;
else
h = oldh;
// Initialize state.
sp = 0;
init_tab();
int code_count = TABSIZE - 256;
in_buf_ptr = in_buf;
in_len_rem = in_len;
inflag = 0;
// Main decompression loop.
int oldcode = get_code();
if(oldcode == -1)
{
*out_len = 0;
free(string_tab);
free(stack);
return 0;
}
int finchar = string_tab[oldcode].follower;
size_t out_pos = 0;
if(out_pos < *out_len) { out_buf[out_pos++] = finchar; }
int newcode;
while((newcode = get_code()) != -1)
{
int code = newcode;
struct entry *ep = &string_tab[code];
// Handle unknown codes and KwKwK case.
if(!ep->used)
{
code = oldcode;
ep = &string_tab[code];
PUSH(finchar);
}
// Decode the string by traversing the table.
while(ep->predecessor != NO_PRED)
{
PUSH(ep->follower);
code = ep->predecessor;
ep = &string_tab[code];
}
PUSH(finchar = ep->follower);
// Add the new string to the table if there's room.
if(code_count)
{
upd_tab(oldcode, finchar);
--code_count;
}
oldcode = newcode;
// Write the decoded string to the output buffer.
while(sp > 0)
{
int c = POP();
if(c == EMPTY) break;
if(out_pos < *out_len) { out_buf[out_pos++] = (unsigned char)c; }
}
}
// Clean up and return.
*out_len = out_pos;
free(string_tab);
free(stack);
return 0;
}
// Decompresses crunched data.
AARU_EXPORT int AARU_CALL arc_decompress_crunch(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len)
{
return arc_decompress_crunch_internal(in_buf, in_len, out_buf, out_len, 0);
}
// Decompresses crunched data with non-repeat packing.
AARU_EXPORT int AARU_CALL arc_decompress_crunch_nrpack(const unsigned char *in_buf, size_t in_len,
unsigned char *out_buf, size_t *out_len)
{
// Allocate a temporary buffer for the intermediate decompressed data.
size_t temp_len = *out_len * 2; // Heuristic for temp buffer size.
unsigned char *temp_buf = malloc(temp_len);
if(!temp_buf) return -1;
// First, decompress the crunched data.
int result = arc_decompress_crunch_internal(in_buf, in_len, temp_buf, &temp_len, 0);
if(result == 0)
{
// Then, decompress the non-repeat packing.
result = arc_decompress_pack(temp_buf, temp_len, out_buf, out_len);
}
free(temp_buf);
return result;
}
// Decompresses crunched data with non-repeat packing and the new hash function.
AARU_EXPORT int AARU_CALL arc_decompress_crunch_nrpack_new(const unsigned char *in_buf, size_t in_len,
unsigned char *out_buf, size_t *out_len)
{
// Allocate a temporary buffer.
size_t temp_len = *out_len * 2; // Heuristic.
unsigned char *temp_buf = malloc(temp_len);
if(!temp_buf) return -1;
// Decompress crunched data with the new hash.
int result = arc_decompress_crunch_internal(in_buf, in_len, temp_buf, &temp_len, 1);
if(result == 0)
{
// Decompress non-repeat packing.
result = arc_decompress_pack(temp_buf, temp_len, out_buf, out_len);
}
free(temp_buf);
return result;
}

271
arc/lzw.c Normal file
View File

@@ -0,0 +1,271 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
* Copyright © 2018-2019 David Ryskalczyk
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "../library.h"
#define CRBITS 12 // Max bits for crunching.
#define SQBITS 13 // Max bits for squashing.
#define INIT_BITS 9 // Initial number of bits per code.
#define MAXCODE(n) ((1 << (n)) - 1) // Macro to calculate max code for n bits.
#define FIRST 257 // First available code.
#define CLEAR 256 // Code to clear the dictionary.
// LZW decompression state variables.
static int Bits;
static int max_maxcode;
static int n_bits;
static int maxcode;
static int clear_flg;
static int free_ent;
static unsigned short *prefix;
static unsigned char *suffix;
static unsigned char *stack;
// Buffer management variables.
static const unsigned char *in_buf_ptr;
static size_t in_len_rem;
static int offset;
static char buf[SQBITS];
// Reads a variable-length code from the input buffer.
static int getcode()
{
int code;
static int size = 0;
int r_off, bits;
unsigned char *bp = (unsigned char *)buf;
// Check if we need to increase code size or handle a clear flag.
if(clear_flg > 0 || offset >= size || free_ent > maxcode)
{
if(free_ent > maxcode)
{
n_bits++;
if(n_bits == Bits)
maxcode = max_maxcode;
else
maxcode = MAXCODE(n_bits);
}
if(clear_flg > 0)
{
maxcode = MAXCODE(n_bits = INIT_BITS);
clear_flg = 0;
}
// Read n_bits bytes into the buffer.
for(size = 0; size < n_bits; size++)
{
if(in_len_rem == 0)
{
code = -1;
break;
}
code = *in_buf_ptr++;
in_len_rem--;
buf[size] = (char)code;
}
if(size <= 0) return -1; // End of file.
offset = 0;
size = (size << 3) - (n_bits - 1);
}
r_off = offset;
bits = n_bits;
// Extract the code from the buffer.
bp += (r_off >> 3);
r_off &= 7;
code = (*bp++ >> r_off);
bits -= 8 - r_off;
r_off = 8 - r_off;
if(bits >= 8)
{
code |= *bp++ << r_off;
r_off += 8;
bits -= 8;
}
code |= (*bp & ((1 << bits) - 1)) << r_off;
offset += n_bits;
return code;
}
// Main LZW decompression logic.
static int arc_decompress_lzw(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf, size_t *out_len,
int squash)
{
// Basic validation of pointers.
if(!in_buf || !out_buf || !out_len) { return -1; }
// Initialize buffer pointers and lengths.
in_buf_ptr = in_buf;
in_len_rem = in_len;
// Set parameters based on whether we're unsquashing or uncrushing.
if(squash) { Bits = SQBITS; }
else
{
Bits = CRBITS;
if(in_len_rem > 0)
{
// Crunch format has a header byte indicating max bits.
if(*in_buf_ptr != CRBITS) return -1;
in_buf_ptr++;
in_len_rem--;
}
}
if(in_len_rem <= 0)
{
*out_len = 0;
return 0;
}
// Initialize LZW parameters.
max_maxcode = 1 << Bits;
clear_flg = 0;
n_bits = INIT_BITS;
maxcode = MAXCODE(n_bits);
// Allocate memory for LZW tables.
prefix = (unsigned short *)malloc(max_maxcode * sizeof(unsigned short));
suffix = (unsigned char *)malloc(max_maxcode * sizeof(unsigned char));
stack = (unsigned char *)malloc(max_maxcode * sizeof(unsigned char));
if(!prefix || !suffix || !stack)
{
if(prefix) free(prefix);
if(suffix) free(suffix);
if(stack) free(stack);
return -1;
}
// Initialize the first 256 entries of the dictionary.
memset(prefix, 0, 256 * sizeof(unsigned short));
for(int code = 255; code >= 0; code--) { suffix[code] = (unsigned char)code; }
free_ent = FIRST;
offset = 0;
// Main decompression loop.
int finchar, oldcode, incode;
finchar = oldcode = getcode();
if(oldcode == -1)
{
*out_len = 0;
free(prefix);
free(suffix);
free(stack);
return 0;
}
size_t out_pos = 0;
if(out_pos < *out_len) { out_buf[out_pos++] = finchar; }
unsigned char *stackp = stack;
int code;
while((code = getcode()) > -1)
{
if(code == CLEAR)
{
// Clear the dictionary.
memset(prefix, 0, 256 * sizeof(unsigned short));
clear_flg = 1;
free_ent = FIRST - 1;
if((code = getcode()) == -1) break;
}
incode = code;
// Handle KwKwK case.
if(code >= free_ent)
{
if(code > free_ent)
{
// Error: invalid code.
break;
}
*stackp++ = finchar;
code = oldcode;
}
// Decode the string by traversing the dictionary.
while(code >= 256)
{
*stackp++ = suffix[code];
code = prefix[code];
}
*stackp++ = finchar = suffix[code];
// Write the decoded string to the output buffer.
do {
if(out_pos < *out_len) { out_buf[out_pos++] = *--stackp; }
else
{
stackp--; // Discard if output buffer is full.
}
} while(stackp > stack);
// Add the new string to the dictionary.
if((code = free_ent) < max_maxcode)
{
prefix[code] = (unsigned short)oldcode;
suffix[code] = finchar;
free_ent = code + 1;
}
oldcode = incode;
}
// Clean up and return.
*out_len = out_pos;
free(prefix);
free(suffix);
free(stack);
return 0;
}
// Decompresses squashed data.
AARU_EXPORT int AARU_CALL arc_decompress_squash(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len)
{
return arc_decompress_lzw(in_buf, in_len, out_buf, out_len, 1);
}
// Decompresses crunched data.
AARU_EXPORT int AARU_CALL arc_decompress_crunch_dynamic(const unsigned char *in_buf, size_t in_len,
unsigned char *out_buf, size_t *out_len)
{
// Allocate a temporary buffer.
size_t temp_len = *out_len * 2; // Heuristic.
unsigned char *temp_buf = malloc(temp_len);
if(!temp_buf) return -1;
// Decompress crunched data.
int result = arc_decompress_lzw(in_buf, in_len, temp_buf, &temp_len, 0);
if(result == 0)
{
// Decompress non-repeat packing.
result = arc_decompress_pack(temp_buf, temp_len, out_buf, out_len);
}
free(temp_buf);
return result;
}

78
arc/pack.c Normal file
View File

@@ -0,0 +1,78 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
* Copyright © 2018-2019 David Ryskalczyk
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include "../library.h"
#define DLE 0x90 // Data Link Escape character, used as a repeat marker.
// Decompresses data using non-repeat packing.
// This algorithm encodes runs of identical bytes.
AARU_EXPORT int AARU_CALL arc_decompress_pack(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf, size_t *out_len)
{
// Basic validation of pointers.
if(!in_buf || !out_buf || !out_len) { return -1; }
size_t in_pos = 0;
size_t out_pos = 0;
unsigned char state = 0; // 0 for normal (NOHIST), 1 for in-repeat (INREP).
unsigned char lastc = 0; // Last character seen.
// Loop through the input buffer until it's exhausted or the output buffer is full.
while(in_pos < in_len && out_pos < *out_len)
{
if(state == 1)
{ // We are in a repeat sequence.
if(in_buf[in_pos])
{ // The byte after DLE is the repeat count.
unsigned char count = in_buf[in_pos];
// Write the last character 'count' times.
while(--count && out_pos < *out_len) { out_buf[out_pos++] = lastc; }
}
else
{ // A count of 0 means the DLE character itself should be written.
if(out_pos < *out_len) { out_buf[out_pos++] = DLE; }
}
state = 0; // Return to normal state.
in_pos++;
}
else
{ // Normal state.
if(in_buf[in_pos] != DLE)
{ // Not a repeat sequence.
if(out_pos < *out_len)
{
// Copy the character and save it as the last character.
out_buf[out_pos++] = lastc = in_buf[in_pos];
}
}
else
{ // DLE marks the start of a repeat sequence.
state = 1; // Enter repeat state.
}
in_pos++;
}
}
// Update the output length to the number of bytes written.
*out_len = out_pos;
// Return success.
return 0;
}

148
arc/squeeze.c Normal file
View File

@@ -0,0 +1,148 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
* Copyright © 2018-2019 David Ryskalczyk
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "../library.h"
#define SPEOF 256 // Special end-of-file token.
#define NUMVALS 257 // Number of values in the Huffman tree (256 chars + SPEOF).
// Node structure for the Huffman decoding tree.
struct nd
{
int child[2]; // Children of the node.
};
// Static variables for the decompression state.
static struct nd nodes[NUMVALS]; // The Huffman tree.
static int numnodes; // Number of nodes in the tree.
static int bpos; // Bit position in the current byte.
static unsigned char curin; // Current byte being read.
// Pointers for buffer management.
static const unsigned char *in_buf_ptr;
static size_t in_len_rem;
static unsigned char *out_buf_ptr;
static size_t out_len_rem;
// Reads a byte from the input buffer.
static int get_byte()
{
if(in_len_rem == 0) { return EOF; }
in_len_rem--;
return *in_buf_ptr++;
}
static int arc_decompress_huffman(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf, size_t *out_len)
{
// Basic validation of pointers.
if(!in_buf || !out_buf || !out_len) { return -1; }
// Initialize buffer pointers and lengths.
in_buf_ptr = in_buf;
in_len_rem = in_len;
out_buf_ptr = out_buf;
out_len_rem = *out_len;
bpos = 99; // Force initial read.
// Read the number of nodes in the Huffman tree.
if(in_len_rem < 2) return -1;
numnodes = get_byte();
numnodes |= get_byte() << 8;
if(numnodes < 0 || numnodes >= NUMVALS)
{
return -1; // Invalid tree.
}
// ARC: initialize for possible empty tree (SPEOF only)
nodes[0].child[0] = -(SPEOF + 1);
nodes[0].child[1] = -(SPEOF + 1);
// Read the Huffman tree from the input buffer, sign-extend 16-bit values
for(int i = 0; i < numnodes; ++i)
{
if(in_len_rem < 4) return -1;
uint8_t b0 = get_byte();
uint8_t b1 = get_byte();
uint8_t b2 = get_byte();
uint8_t b3 = get_byte();
nodes[i].child[0] = (int16_t)((b0) | (b1 << 8));
nodes[i].child[1] = (int16_t)((b2) | (b3 << 8));
}
size_t written = 0;
// bpos is already 99 from init
while(written < *out_len)
{
int i = 0;
// follow bit stream in tree to a leaf
while(i >= 0)
{
if(++bpos > 7)
{
int c = get_byte();
if(c == EOF)
{
*out_len = written;
return 0; // End of input
}
curin = c;
bpos = 0;
// move a level deeper in tree
i = nodes[i].child[curin & 1];
}
else { i = nodes[i].child[1 & (curin >>= 1)]; }
}
// decode fake node index to original data value
int value = -(i + 1);
if(value == SPEOF)
{
break; // End of data
}
*out_buf_ptr++ = value;
written++;
}
*out_len = written;
return 0;
}
// Decompresses data using Huffman squeezing.
AARU_EXPORT int AARU_CALL arc_decompress_squeeze(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len)
{
size_t temp_len = *out_len * 2;
unsigned char *temp_buf = malloc(temp_len);
if(!temp_buf) return -1;
int result = arc_decompress_huffman(in_buf, in_len, temp_buf, &temp_len);
if(result == 0) { result = arc_decompress_pack(temp_buf, temp_len, out_buf, out_len); }
free(temp_buf);
return result;
}

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# This file is part of the Aaru Data Preservation Suite.
# Copyright (c) 2019-2023 Natalia Portillo.
# Copyright (c) 2019-2025 Natalia Portillo.
#
# This library is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
@@ -179,7 +179,7 @@ docker/dockcross-win-arm cmake -DCMAKE_BUILD_TYPE=Release -DAARU_BUILD_PACKAGE=1
sed -e 's/\-soname,libAaru\.Compression\.Native\.so//g' ./CMakeFiles/Aaru.Compression.Native.dir/link.txt > link.txt
mv link.txt ./CMakeFiles/Aaru.Compression.Native.dir/link.txt
docker/dockcross-win-arm make Aaru.Compression.Native
mv libAaru.Compression.Native.so runtimes/win-arm/native/libAaru.Compression.Native.dll
mv libAaru.Compression.Native.dll runtimes/win-arm/native/
## Windows (ARM64)
# Detected system processor: aarch64
@@ -191,14 +191,14 @@ docker/dockcross-win-arm64 cmake -DCMAKE_BUILD_TYPE=Release -DAARU_BUILD_PACKAGE
sed -e 's/\-soname,libAaru\.Compression\.Native\.so//g' ./CMakeFiles/Aaru.Compression.Native.dir/link.txt > link.txt
mv link.txt ./CMakeFiles/Aaru.Compression.Native.dir/link.txt
docker/dockcross-win-arm64 make Aaru.Compression.Native
mv libAaru.Compression.Native.so runtimes/win-arm64/native/libAaru.Compression.Native.dll
mv libAaru.Compression.Native.dll runtimes/win-arm64/native/
## Windows (AMD64)
# Detected system processor: x86_64
# TODO: Requires MSVCRT.DLL
rm -f CMakeCache.txt
mkdir -p runtimes/win-x64/native
docker run --rm dockcross/windows-shared-x64 > docker/dockcross-win-x64
docker run --rm dockcross/windows-static-x64 > docker/dockcross-win-x64
chmod +x docker/dockcross-win-x64
docker/dockcross-win-x64 cmake -DCMAKE_BUILD_TYPE=Release -DAARU_BUILD_PACKAGE=1 .
docker/dockcross-win-x64 make Aaru.Compression.Native
@@ -209,7 +209,7 @@ mv libAaru.Compression.Native.dll runtimes/win-x64/native/
# TODO: Requires MSVCRT.DLL
rm -f CMakeCache.txt
mkdir -p runtimes/win-x86/native
docker run --rm dockcross/windows-shared-x86 > docker/dockcross-win-x86
docker run --rm dockcross/windows-static-x86 > docker/dockcross-win-x86
chmod +x docker/dockcross-win-x86
docker/dockcross-win-x86 cmake -DCMAKE_BUILD_TYPE=Release -DAARU_BUILD_PACKAGE=1 .
docker/dockcross-win-x86 make Aaru.Compression.Native
@@ -222,6 +222,7 @@ if [[ ${OS_NAME} == Darwin ]]; then
make Aaru.Compression.Native
mkdir -p runtimes/osx-x64/native
mv libAaru.Compression.Native.dylib runtimes/osx-x64/native
make clean
rm -f CMakeCache.txt
cmake -DCMAKE_BUILD_TYPE=Release -DAARU_BUILD_PACKAGE=1 -DAARU_MACOS_TARGET_ARCH=arm64 .

1
codealike.json Normal file
View File

@@ -0,0 +1 @@
{"projectId":"748d69bc-5b46-4b80-9066-57e2fbcd92d0","projectName":"Aaru.Compression.Native"}

101
flac.c
View File

@@ -6,29 +6,34 @@
#include <stdlib.h>
#include <string.h>
#include "library.h"
#include "3rdparty/flac/include/FLAC/metadata.h"
#include "3rdparty/flac/include/FLAC/stream_decoder.h"
#include "3rdparty/flac/include/FLAC/stream_encoder.h"
#include "library.h"
#include "flac.h"
static FLAC__StreamDecoderReadStatus
read_callback(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data);
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* decoder,
const FLAC__Frame* frame,
const FLAC__int32* const buffer[],
void* client_data);
static void
error_callback(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data);
static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder,
FLAC__byte buffer[],
size_t * bytes,
void * client_data);
AARU_EXPORT size_t AARU_CALL AARU_flac_decode_redbook_buffer(uint8_t* dst_buffer,
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder,
const FLAC__Frame * frame,
const FLAC__int32 *const buffer[],
void * client_data);
static void error_callback(const FLAC__StreamDecoder * decoder,
FLAC__StreamDecoderErrorStatus status,
void * client_data);
AARU_EXPORT size_t AARU_CALL AARU_flac_decode_redbook_buffer(uint8_t * dst_buffer,
size_t dst_size,
const uint8_t* src_buffer,
const uint8_t *src_buffer,
size_t src_size)
{
FLAC__StreamDecoder* decoder;
FLAC__StreamDecoder * decoder;
FLAC__StreamDecoderInitStatus init_status;
aaru_flac_ctx* ctx = (aaru_flac_ctx*)malloc(sizeof(aaru_flac_ctx));
aaru_flac_ctx * ctx = (aaru_flac_ctx *)malloc(sizeof(aaru_flac_ctx));
size_t ret_size;
memset(ctx, 0, sizeof(aaru_flac_ctx));
@@ -51,8 +56,16 @@ AARU_EXPORT size_t AARU_CALL AARU_flac_decode_redbook_buffer(uint8_t* dst_
FLAC__stream_decoder_set_md5_checking(decoder, false);
init_status = FLAC__stream_decoder_init_stream(
decoder, read_callback, NULL, NULL, NULL, NULL, write_callback, NULL, error_callback, ctx);
init_status = FLAC__stream_decoder_init_stream(decoder, read_callback, // 1
NULL, // 2 seek
NULL, // 3 tell
NULL, // 4 length
NULL, // 5 eof
write_callback, // 6 write
NULL, // 7 metadata
error_callback, // 8 error
ctx // 9 client_data
);
if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
{
@@ -72,10 +85,12 @@ AARU_EXPORT size_t AARU_CALL AARU_flac_decode_redbook_buffer(uint8_t* dst_
return ret_size;
}
static FLAC__StreamDecoderReadStatus
read_callback(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data)
static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder,
FLAC__byte buffer[],
size_t * bytes,
void * client_data)
{
aaru_flac_ctx* ctx = (aaru_flac_ctx*)client_data;
aaru_flac_ctx *ctx = (aaru_flac_ctx *)client_data;
if(ctx->src_len - ctx->src_pos < *bytes) *bytes = ctx->src_len - ctx->src_pos;
@@ -87,14 +102,14 @@ static FLAC__StreamDecoderReadStatus
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* decoder,
const FLAC__Frame* frame,
const FLAC__int32* const buffer[],
void* client_data)
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder,
const FLAC__Frame * frame,
const FLAC__int32 *const buffer[],
void * client_data)
{
aaru_flac_ctx* ctx = (aaru_flac_ctx*)client_data;
aaru_flac_ctx *ctx = (aaru_flac_ctx *)client_data;
size_t i;
uint16_t* buffer16 = (uint16_t*)(ctx->dst_buffer + ctx->dst_pos);
uint16_t * buffer16 = (uint16_t *)(ctx->dst_buffer + ctx->dst_pos);
// Why FLAC does not interleave the channels as PCM do, oh the mistery, we could use memcpy instead of looping
for(i = 0; i < frame->header.blocksize && ctx->dst_pos < ctx->dst_len; i++)
@@ -119,47 +134,47 @@ static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder*
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
static void error_callback(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data)
static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
{
aaru_flac_ctx* ctx = (aaru_flac_ctx*)client_data;
aaru_flac_ctx *ctx = (aaru_flac_ctx *)client_data;
fprintf(stderr, "Got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
ctx->error = 1;
}
static FLAC__StreamEncoderWriteStatus encoder_write_callback(const FLAC__StreamEncoder* encoder,
static FLAC__StreamEncoderWriteStatus encoder_write_callback(const FLAC__StreamEncoder *encoder,
const FLAC__byte buffer[],
size_t bytes,
uint32_t samples,
uint32_t current_frame,
void* client_data);
void * client_data);
AARU_EXPORT size_t AARU_CALL AARU_flac_encode_redbook_buffer(uint8_t* dst_buffer,
AARU_EXPORT size_t AARU_CALL AARU_flac_encode_redbook_buffer(uint8_t * dst_buffer,
size_t dst_size,
const uint8_t* src_buffer,
const uint8_t *src_buffer,
size_t src_size,
uint32_t blocksize,
int32_t do_mid_side_stereo,
int32_t loose_mid_side_stereo,
const char* apodization,
const char * apodization,
uint32_t max_lpc_order,
uint32_t qlp_coeff_precision,
int32_t do_qlp_coeff_prec_search,
int32_t do_exhaustive_model_search,
uint32_t min_residual_partition_order,
uint32_t max_residual_partition_order,
const char* application_id,
const char * application_id,
uint32_t application_id_len)
{
FLAC__StreamEncoder* encoder;
aaru_flac_ctx* ctx = (aaru_flac_ctx*)malloc(sizeof(aaru_flac_ctx));
FLAC__StreamEncoder * encoder;
aaru_flac_ctx * ctx = (aaru_flac_ctx *)malloc(sizeof(aaru_flac_ctx));
FLAC__StreamEncoderInitStatus init_status;
size_t ret_size;
FLAC__int32* pcm;
FLAC__int32 * pcm;
int i;
int16_t* buffer16 = (int16_t*)src_buffer;
FLAC__StreamMetadata* metadata[1];
int16_t * buffer16 = (int16_t *)src_buffer;
FLAC__StreamMetadata * metadata[1];
memset(ctx, 0, sizeof(aaru_flac_ctx));
@@ -213,8 +228,8 @@ AARU_EXPORT size_t AARU_CALL AARU_flac_encode_redbook_buffer(uint8_t* dst_
if(application_id_len > 0 && application_id != NULL)
if((metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)) != NULL)
FLAC__metadata_object_application_set_data(
metadata[0], (unsigned char*)application_id, application_id_len, true);
FLAC__metadata_object_application_set_data(metadata[0], (unsigned char *)application_id, application_id_len,
true);
FLAC__stream_encoder_set_metadata(encoder, metadata, 1);
@@ -228,7 +243,7 @@ AARU_EXPORT size_t AARU_CALL AARU_flac_encode_redbook_buffer(uint8_t* dst_
pcm = malloc((src_size / 2) * sizeof(FLAC__int32));
for(i = 0; i < src_size / 2; i++) pcm[i] = (FLAC__int32) * (buffer16++);
for(i = 0; i < src_size / 2; i++) pcm[i] = (FLAC__int32)*(buffer16++);
FLAC__stream_encoder_process_interleaved(encoder, pcm, src_size / 4);
@@ -245,14 +260,14 @@ AARU_EXPORT size_t AARU_CALL AARU_flac_encode_redbook_buffer(uint8_t* dst_
return ret_size;
}
static FLAC__StreamEncoderWriteStatus encoder_write_callback(const FLAC__StreamEncoder* encoder,
static FLAC__StreamEncoderWriteStatus encoder_write_callback(const FLAC__StreamEncoder *encoder,
const FLAC__byte buffer[],
size_t bytes,
uint32_t samples,
uint32_t current_frame,
void* client_data)
void * client_data)
{
aaru_flac_ctx* ctx = (aaru_flac_ctx*)client_data;
aaru_flac_ctx *ctx = (aaru_flac_ctx *)client_data;
if(bytes > ctx->dst_len - ctx->dst_pos) bytes = ctx->dst_len - ctx->dst_pos;

6
flac.h
View File

@@ -7,13 +7,13 @@
typedef struct
{
const uint8_t* src_buffer;
const uint8_t *src_buffer;
size_t src_len;
size_t src_pos;
uint8_t* dst_buffer;
uint8_t *dst_buffer;
size_t dst_len;
size_t dst_pos;
uint8_t error;
} aaru_flac_ctx;
#endif // AARU_COMPRESSION_NATIVE__FLAC_H_
#endif // AARU_COMPRESSION_NATIVE__FLAC_H_

134
ha/acoder.c Normal file
View File

@@ -0,0 +1,134 @@
/***********************************************************************
This file is part of HA, a general purpose file archiver.
Copyright (C) 1995 Harri Hirvola
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
************************************************************************
HA arithmetic coder
***********************************************************************/
/***********************************************************************
This file contains some small changes made by Nico de Vries (AIP-NL)
allowing it to be compiled with Borland C++ 3.1.
***********************************************************************/
/***********************************************************************
Modified to work with memory buffers instead of files by
Copyright (C) 2005 Natalia Portillo
************************************************************************/
#include "internal.h"
#include "acoder.h"
#include <string.h>
static decompress_context_t *g_ctx = NULL;
static U16B h, l, v;
static S16B gpat;
/* Get byte from input buffer */
static int getbyte_from_buffer(void)
{
if(!g_ctx || g_ctx->input.pos >= g_ctx->input.size) { return -1; }
return g_ctx->input.data[g_ctx->input.pos++];
}
/* Bit input from memory buffer */
static int getbit_from_buffer(void)
{
if(!g_ctx || g_ctx->input.error) { return -1; }
gpat <<= 1;
if(!(gpat & 0xff))
{
int byte = getbyte_from_buffer();
if(byte < 0) { gpat = 0x100; }
else
{
gpat = byte;
gpat <<= 1;
gpat |= 1;
}
}
return (gpat & 0x100) >> 8;
}
#define getbit(b) { \
int _bit = getbit_from_buffer(); \
if (_bit < 0) { \
g_ctx->input.error = 1; \
b = 0; \
} else { \
b |= _bit; \
} \
}
void ac_init_decode(decompress_context_t *ctx)
{
g_ctx = ctx;
h = 0xffff;
l = 0;
gpat = 0;
int b1 = getbyte_from_buffer();
int b2 = getbyte_from_buffer();
if(b1 < 0 || b2 < 0)
{
ctx->input.error = 1;
v = 0;
return;
}
v = (b1 << 8) | (0xff & b2);
}
void ac_in(U16B low, U16B high, U16B tot)
{
if(!g_ctx || g_ctx->input.error) return;
U32B r = (U32B)(h - l) + 1;
h = (U16B)(r * high / tot - 1) + l;
l += (U16B)(r * low / tot);
while(!((h ^ l) & 0x8000))
{
l <<= 1;
h <<= 1;
h |= 1;
v <<= 1;
getbit(v);
if(g_ctx->input.error) return;
}
while((l & 0x4000) && !(h & 0x4000))
{
l <<= 1;
l &= 0x7fff;
h <<= 1;
h |= 0x8001;
v <<= 1;
v ^= 0x8000;
getbit(v);
if(g_ctx->input.error) return;
}
}
U16B ac_threshold_val(U16B tot)
{
if(!g_ctx || g_ctx->input.error) return 0;
U32B r = (U32B)(h - l) + 1;
return (U16B)((((U32B)(v - l) + 1) * tot - 1) / r);
}

38
ha/acoder.h Normal file
View File

@@ -0,0 +1,38 @@
/***********************************************************************
This file is part of HA, a general purpose file archiver.
Copyright (C) 1995 Harri Hirvola
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
************************************************************************
HA arithmetic coder
***********************************************************************/
/***********************************************************************
Modified to work with memory buffers instead of files by
Copyright (C) 2005 Natalia Portillo
************************************************************************/
#ifndef ACODER_H
#define ACODER_H
#include "internal.h"
void ac_init_decode(decompress_context_t *ctx);
void ac_in(U16B low, U16B high, U16B tot);
U16B ac_threshold_val(U16B tot);
#endif /* ACODER_H */

304
ha/asc.c Normal file
View File

@@ -0,0 +1,304 @@
/***********************************************************************
This file is part of HA, a general purpose file archiver.
Copyright (C) 1995 Harri Hirvola
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
************************************************************************
HA ASC method
***********************************************************************/
/***********************************************************************
Modified to work with memory buffers instead of files by
Copyright (C) 2005 Natalia Portillo
************************************************************************/
#include "internal.h"
#include "acoder.h"
#include "swdict.h"
#include "asc.h"
#include <stdlib.h>
#include <string.h>
static decompress_context_t *g_ctx = NULL;
static void tabinit(U16B t[], U16B tl, U16B ival)
{
register U16B i, j;
for(i = tl; i < 2 * tl; ++i) t[i] = ival;
for(i = tl - 1, j = (tl << 1) - 2; i; --i, j -= 2) { t[i] = t[j] + t[j + 1]; }
}
static void tscale(U16B t[], U16B tl)
{
register U16B i, j;
for(i = (tl << 1) - 1; i >= tl; --i) { if(t[i] > 1) t[i] >>= 1; }
for(i = tl - 1, j = (tl << 1) - 2; i; --i, j -= 2) { t[i] = t[j] + t[j + 1]; }
}
static void tupd(U16B t[], U16B tl, U16B maxt, U16B step, U16B p)
{
register S16B i;
for(i = p + tl; i; i >>= 1) t[i] += step;
if(t[1] >= maxt) tscale(t, tl);
}
static void tzero(U16B t[], U16B tl, U16B p)
{
register S16B i, step;
for(i = p + tl, step = t[i]; i; i >>= 1) t[i] -= step;
}
static void model_init(void)
{
register S16B i;
ces = CTSTEP;
les = LTSTEP;
ccnt = 0;
ttcon = 0;
npt = pmax = 1;
for(i = 0; i < TTORD; ++i) ttab[i][0] = ttab[i][1] = TTSTEP;
tabinit(ltab, LTCODES, 0);
tabinit(eltab, LTCODES, 1);
tabinit(ctab, CTCODES, 0);
tabinit(ectab, CTCODES, 1);
tabinit(ptab, PTCODES, 0);
tupd(ptab, PTCODES, MAXPT, PTSTEP, 0);
}
static void unpack_init(decompress_context_t *ctx)
{
g_ctx = ctx;
model_init();
ac_init_decode(ctx);
}
static void ttscale(U16B con)
{
ttab[con][0] >>= 1;
if(ttab[con][0] == 0) ttab[con][0] = 1;
ttab[con][1] >>= 1;
if(ttab[con][1] == 0) ttab[con][1] = 1;
}
static void flush_output(void)
{
/* Output flushing is handled by the buffer management */
}
int asc_unpack(decompress_context_t *ctx)
{
register U16B l, p, tv, i, lt;
swd_dinit(ctx, POSCODES);
if(ctx->output.error) return -1;
unpack_init(ctx);
if(ctx->input.error)
{
swd_cleanup();
return -1;
}
for(;;)
{
if(ctx->input.error || ctx->output.error) break;
tv = ac_threshold_val(ttab[ttcon][0] + ttab[ttcon][1] + 1);
i = ttab[ttcon][0] + ttab[ttcon][1];
if(ttab[ttcon][0] > tv)
{
ac_in(0, ttab[ttcon][0], i + 1);
ttab[ttcon][0] += TTSTEP;
if(i >= MAXTT) ttscale(ttcon);
ttcon = (ttcon << 1) & TTOMASK;
tv = ac_threshold_val(ctab[1] + ces);
if(tv >= ctab[1])
{
ac_in(ctab[1], ctab[1] + ces, ctab[1] + ces);
tv = ac_threshold_val(ectab[1]);
for(l = 2, lt = 0;;)
{
if(lt + ectab[l] <= tv)
{
lt += ectab[l];
++l;
}
if(l >= CTCODES)
{
l -= CTCODES;
break;
}
l <<= 1;
}
ac_in(lt, lt + ectab[CTCODES + l], ectab[1]);
tzero(ectab, CTCODES, l);
if(ectab[1] != 0) ces += CTSTEP;
else ces = 0;
for(i = l < CPLEN ? 0 : l - CPLEN; i < (l + CPLEN >= CTCODES - 1 ? CTCODES - 1 : l + CPLEN); ++i)
{
if(ectab[CTCODES + i]) tupd(ectab, CTCODES, MAXCT, 1, i);
}
}
else
{
for(l = 2, lt = 0;;)
{
if(lt + ctab[l] <= tv)
{
lt += ctab[l];
l++;
}
if(l >= CTCODES)
{
l -= CTCODES;
break;
}
l <<= 1;
}
ac_in(lt, lt + ctab[CTCODES + l], ctab[1] + ces);
}
tupd(ctab, CTCODES, MAXCT, CTSTEP, l);
if(ctab[CTCODES + l] == CCUTOFF) ces -= CTSTEP < ces ? CTSTEP : ces - 1;
swd_dchar(l);
if(ccnt < POSCODES) ++ccnt;
}
else if(i > tv)
{
ac_in(ttab[ttcon][0], i, i + 1);
ttab[ttcon][1] += TTSTEP;
if(i >= MAXTT) ttscale(ttcon);
ttcon = ((ttcon << 1) | 1) & TTOMASK;
while(ccnt > pmax)
{
tupd(ptab, PTCODES, MAXPT, PTSTEP, npt++);
pmax <<= 1;
}
tv = ac_threshold_val(ptab[1]);
for(p = 2, lt = 0;;)
{
if(lt + ptab[p] <= tv)
{
lt += ptab[p];
p++;
}
if(p >= PTCODES)
{
p -= PTCODES;
break;
}
p <<= 1;
}
ac_in(lt, lt + ptab[PTCODES + p], ptab[1]);
tupd(ptab, PTCODES, MAXPT, PTSTEP, p);
if(p > 1)
{
for(i = 1; p; i <<= 1, --p);
i >>= 1;
if(i == (pmax >> 1)) l = ccnt - (pmax >> 1);
else l = i;
p = ac_threshold_val(l);
ac_in(p, p + 1, l);
p += i;
}
tv = ac_threshold_val(ltab[1] + les);
if(tv >= ltab[1])
{
ac_in(ltab[1], ltab[1] + les, ltab[1] + les);
tv = ac_threshold_val(eltab[1]);
for(l = 2, lt = 0;;)
{
if(lt + eltab[l] <= tv)
{
lt += eltab[l];
++l;
}
if(l >= LTCODES)
{
l -= LTCODES;
break;
}
l <<= 1;
}
ac_in(lt, lt + eltab[LTCODES + l], eltab[1]);
tzero(eltab, LTCODES, l);
if(eltab[1] != 0) les += LTSTEP;
else les = 0;
for(i = l < LPLEN ? 0 : l - LPLEN; i < (l + LPLEN >= LTCODES - 1 ? LTCODES - 1 : l + LPLEN); ++i)
{
if(eltab[LTCODES + i]) tupd(eltab, LTCODES, MAXLT, 1, i);
}
}
else
{
for(l = 2, lt = 0;;)
{
if(lt + ltab[l] <= tv)
{
lt += ltab[l];
++l;
}
if(l >= LTCODES)
{
l -= LTCODES;
break;
}
l <<= 1;
}
ac_in(lt, lt + ltab[LTCODES + l], ltab[1] + les);
}
tupd(ltab, LTCODES, MAXLT, LTSTEP, l);
if(ltab[LTCODES + l] == LCUTOFF) les -= LTSTEP < les ? LTSTEP : les - 1;
if(l == SLCODES - 1) l = LENCODES - 1;
else if(l >= SLCODES)
{
i = ac_threshold_val(LLLEN);
ac_in(i, i + 1, LLLEN);
l = ((l - SLCODES) << LLBITS) + i + SLCODES - 1;
}
l += 3;
if(ccnt < POSCODES)
{
ccnt += l;
if(ccnt > POSCODES) ccnt = POSCODES;
}
swd_dpair(l, p);
}
else
{
ac_in(i, i + 1, i + 1);
flush_output();
swd_cleanup();
return 0;
}
if(ctx->input.error || ctx->output.error) break;
}
swd_cleanup();
return -1;
}

71
ha/asc.h Normal file
View File

@@ -0,0 +1,71 @@
/***********************************************************************
This file is part of HA, a general purpose file archiver.
Copyright (C) 1995 Harri Hirvola
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
************************************************************************
HA ASC method
***********************************************************************/
/***********************************************************************
Modified to work with memory buffers instead of files by
Copyright (C) 2005 Natalia Portillo
************************************************************************/
#ifndef ASC_H
#define ASC_H
#include "internal.h"
int asc_unpack(decompress_context_t *ctx);
#define POSCODES 31200
#define SLCODES 16
#define LLCODES 48
#define LLLEN 16
#define LLBITS 4
#define LLMASK (LLLEN-1)
#define LENCODES (SLCODES+LLCODES*LLLEN)
#define LTCODES (SLCODES+LLCODES)
#define CTCODES 256
#define PTCODES 16
#define LTSTEP 8
#define MAXLT (750*LTSTEP)
#define CTSTEP 1
#define MAXCT (1000*CTSTEP)
#define PTSTEP 24
#define MAXPT (250*PTSTEP)
#define TTSTEP 40
#define MAXTT (150*TTSTEP)
#define TTORD 4
#define TTOMASK (TTORD-1)
#define LCUTOFF (3*LTSTEP)
#define CCUTOFF (3*CTSTEP)
#define CPLEN 8
#define LPLEN 4
#define MINLENLIM 4096
static U16B ltab[2 * LTCODES];
static U16B eltab[2 * LTCODES];
static U16B ptab[2 * PTCODES];
static U16B ctab[2 * CTCODES];
static U16B ectab[2 * CTCODES];
static U16B ttab[TTORD][2];
static U16B ccnt, pmax, npt;
static U16B ces;
static U16B les;
static U16B ttcon;
#endif /* ASC_H */

70
ha/decompress.c Normal file
View File

@@ -0,0 +1,70 @@
/***********************************************************************
Modified to work with memory buffers instead of files by
Copyright (C) 2005 Natalia Portillo
************************************************************************/
#include "internal.h"
#include "asc.h"
#include "hsc.h"
#include "../library.h"
#include <string.h>
int ha_algorithm_decompress(ha_algorithm_t algorithm,
const unsigned char *in_buf,
size_t in_len,
unsigned char * out_buf,
size_t * out_len)
{
if(!in_buf || !out_buf || !out_len || in_len == 0) { return -1; }
decompress_context_t ctx;
memset(&ctx, 0, sizeof(ctx));
/* Initialize input buffer */
ctx.input.data = in_buf;
ctx.input.size = in_len;
ctx.input.pos = 0;
ctx.input.error = 0;
/* Initialize output buffer */
ctx.output.data = out_buf;
ctx.output.size = 0;
ctx.output.pos = 0;
ctx.output.max_size = *out_len;
ctx.output.error = 0;
ctx.algorithm = algorithm;
int result;
switch(algorithm)
{
case HA_ALGORITHM_ASC:
result = asc_unpack(&ctx);
break;
case HA_ALGORITHM_HSC:
result = hsc_unpack(&ctx);
break;
default:
return -1;
}
*out_len = ctx.output.size;
return result;
}
AARU_EXPORT int AARU_CALL ha_asc_decompress(const unsigned char *in_buf,
size_t in_len,
unsigned char * out_buf,
size_t * out_len)
{
return ha_algorithm_decompress(HA_ALGORITHM_ASC, in_buf, in_len, out_buf, out_len);
}
AARU_EXPORT int AARU_CALL ha_hsc_decompress(const unsigned char *in_buf,
size_t in_len,
unsigned char * out_buf,
size_t * out_len)
{
return ha_algorithm_decompress(HA_ALGORITHM_HSC, in_buf, in_len, out_buf, out_len);
}

568
ha/hsc.c Normal file
View File

@@ -0,0 +1,568 @@
/***********************************************************************
This file is part of HA, a general purpose file archiver.
Copyright (C) 1995 Harri Hirvola
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
************************************************************************
HA HSC method
***********************************************************************/
/***********************************************************************
Modified to work with memory buffers instead of files by
Copyright (C) 2005 Natalia Portillo
************************************************************************/
#include "internal.h"
#include "acoder.h"
#include "hsc.h"
#include <stdlib.h>
#include <string.h>
static decompress_context_t *g_ctx = NULL;
static void hsc_cleanup(void)
{
if(ht != NULL) free(ht), ht = NULL;
if(fc != NULL) free(fc), fc = NULL;
if(fa != NULL) free(fa), fa = NULL;
if(ft != NULL) free(ft), ft = NULL;
if(fe != NULL) free(fe), fe = NULL;
if(nb != NULL) free(nb), nb = NULL;
if(hp != NULL) free(hp), hp = NULL;
if(elp != NULL) free(elp), elp = NULL;
if(eln != NULL) free(eln), eln = NULL;
if(cl != NULL) free(cl), cl = NULL;
if(cc != NULL) free(cc), cc = NULL;
if(rfm != NULL) free(rfm), rfm = NULL;
if(con != NULL) free(con), con = NULL;
}
static int putbyte_to_buffer(unsigned char c)
{
if(!g_ctx || g_ctx->output.pos >= g_ctx->output.max_size)
{
if(g_ctx) g_ctx->output.error = 1;
return -1;
}
g_ctx->output.data[g_ctx->output.pos++] = c;
if(g_ctx->output.pos > g_ctx->output.size) { g_ctx->output.size = g_ctx->output.pos; }
return 0;
}
static U16B make_context(unsigned char cl, S16B c);
static int init_model(void)
{
register S16B i;
S32B z, l, h, t;
ht = malloc(HTLEN * sizeof(*ht));
hp = malloc(NUMCON * sizeof(*hp));
elp = malloc(NUMCON * sizeof(*elp));
eln = malloc(NUMCON * sizeof(*eln));
cl = malloc(NUMCON * sizeof(*cl));
cc = malloc(NUMCON * sizeof(*cc));
ft = malloc(NUMCON * sizeof(*ft));
fe = malloc(NUMCON * sizeof(*fe));
rfm = malloc(NUMCON * sizeof(*rfm));
con = malloc(NUMCON * sizeof(*con));
fc = malloc(NUMCFB * sizeof(*fc));
fa = malloc(NUMCFB * sizeof(*fa));
nb = malloc(NUMCFB * sizeof(*nb));
if(hp == NULL || elp == NULL || eln == NULL || cl == NULL || rfm == NULL || con == NULL || cc == NULL || ft == NULL
|| fe == NULL || fc == NULL || fa == NULL || nb == NULL || ht == NULL)
{
hsc_cleanup();
return -1;
}
maxclen = MAXCLEN;
iec[0] = (IECLIM >> 1);
for(i = 1; i <= MAXCLEN; ++i) iec[i] = (IECLIM >> 1) - 1;
dropcnt = NUMCON / 4;
nec = 0;
nrel = 0;
hs[0] = 0;
for(i = 0; i < HTLEN; ++i) ht[i] = NIL;
for(i = 0; i < NUMCON; ++i)
{
eln[i] = i + 1;
elp[i] = i - 1;
cl[i] = 0xff;
nb[i] = NIL;
}
elf = 0;
ell = NUMCON - 1;
for(i = NUMCON; i < NUMCFB - 1; ++i) nb[i] = i + 1;
nb[i] = NIL;
fcfbl = NUMCON;
curcon[3] = curcon[2] = curcon[1] = curcon[0] = 0;
cmsp = 0;
for(i = 0; i < 256; ++i) cmask[i] = 0;
for(z = 10, i = 0; i < HTLEN; ++i)
{
h = z / (2147483647L / 16807L);
l = z % (2147483647L / 16807L);
if((t = 16807L * l - (2147483647L % 16807L) * h) > 0) z = t;
else z = t + 2147483647L;
hrt[i] = (U16B)z & (HTLEN - 1);
}
return 0;
}
static int init_unpack(decompress_context_t *ctx)
{
g_ctx = ctx;
if(init_model() < 0) return -1;
ac_init_decode(ctx);
return 0;
}
#define HASH(s,l,h) { \
h = 0; \
if (l) h = hrt[s[0]]; \
if (l > 1) h = hrt[(s[1] + h) & (HTLEN - 1)]; \
if (l > 2) h = hrt[(s[2] + h) & (HTLEN - 1)]; \
if (l > 3) h = hrt[(s[3] + h) & (HTLEN - 1)]; \
}
#define move_context(c) curcon[3] = curcon[2], curcon[2] = curcon[1], \
curcon[1] = curcon[0], curcon[0] = c
static void release_cfblocks(void)
{
register U16B i, j, d;
do
{
do if(++nrel == NUMCON) nrel = 0; while(nb[nrel] == NIL);
for(i = 0; i <= usp; ++i) if((cps[i] & 0x7fff) == nrel) break;
}
while(i <= usp);
for(i = nb[nrel], d = fa[nrel]; i != NIL; i = nb[i]) if(fa[i] < d) d = fa[i];
++d;
if(fa[nrel] < d)
{
for(i = nb[nrel]; fa[i] < d && nb[i] != NIL; i = nb[i]);
fa[nrel] = fa[i];
fc[nrel] = fc[i];
j = nb[i];
nb[i] = fcfbl;
fcfbl = nb[nrel];
if((nb[nrel] = j) == NIL)
{
cc[nrel] = 0;
fe[nrel] = (ft[nrel] = fa[nrel]) < ESCTH ? 1 : 0;
return;
}
}
fe[nrel] = (ft[nrel] = fa[nrel] /= d) < ESCTH ? 1 : 0;
cc[nrel] = 0;
for(j = nrel, i = nb[j]; i != NIL;)
{
if(fa[i] < d)
{
nb[j] = nb[i];
nb[i] = fcfbl;
fcfbl = i;
i = nb[j];
}
else
{
++cc[nrel];
ft[nrel] += fa[i] /= d;
if(fa[i] < ESCTH) fe[nrel]++;
j = i;
i = nb[i];
}
}
}
static U16B make_context(unsigned char conlen, S16B c)
{
register S16B i;
register U16B nc, fp;
nc = ell;
ell = elp[nc];
elp[elf] = nc;
eln[nc] = elf;
elf = nc;
if(cl[nc] != 0xff)
{
if(cl[nc] == MAXCLEN && --dropcnt == 0) maxclen = MAXCLEN - 1;
HASH(con[nc], cl[nc], i);
if(ht[i] == nc) ht[i] = hp[nc];
else
{
for(i = ht[i]; hp[i] != nc; i = hp[i]);
hp[i] = hp[nc];
}
if(nb[nc] != NIL)
{
for(fp = nb[nc]; nb[fp] != NIL; fp = nb[fp]);
nb[fp] = fcfbl;
fcfbl = nb[nc];
}
}
nb[nc] = NIL;
fe[nc] = ft[nc] = fa[nc] = 1;
fc[nc] = c;
rfm[nc] = RFMINI;
cc[nc] = 0;
cl[nc] = conlen;
con[nc][0] = curcon[0];
con[nc][1] = curcon[1];
con[nc][2] = curcon[2];
con[nc][3] = curcon[3];
HASH(curcon, conlen, i);
hp[nc] = ht[i];
ht[i] = nc;
return nc;
}
static void el_movefront(U16B cp)
{
if(cp == elf) return;
if(cp == ell) ell = elp[cp];
else
{
elp[eln[cp]] = elp[cp];
eln[elp[cp]] = eln[cp];
}
elp[elf] = cp;
eln[cp] = elf;
elf = cp;
}
static void add_model(S16B c)
{
register U16B i;
register S16B cp;
while(usp != 0)
{
i = as[--usp];
cp = cps[usp];
if(cp & 0x8000)
{
cp &= 0x7fff;
if(fcfbl == NIL) release_cfblocks();
nb[i] = fcfbl;
i = nb[i];
fcfbl = nb[fcfbl];
nb[i] = NIL;
fa[i] = 1;
fc[i] = c;
++cc[cp];
++fe[cp];
}
else if(++fa[i] == ESCTH) --fe[cp];
if((fa[i] << 1) < ++ft[cp] / (cc[cp] + 1)) --rfm[cp];
else if(rfm[cp] < RFMINI) ++rfm[cp];
if(!rfm[cp] || ft[cp] >= MAXTVAL)
{
++rfm[cp];
fe[cp] = ft[cp] = 0;
for(i = cp; i != NIL; i = nb[i])
{
if(fa[i] > 1)
{
ft[cp] += fa[i] >>= 1;
if(fa[i] < ESCTH) ++fe[cp];
}
else
{
++ft[cp];
++fe[cp];
}
}
}
}
}
static U16B find_next(void)
{
register S16B i, k;
register U16B cp;
for(i = cslen - 1; i >= 0; --i)
{
k = hs[i];
for(cp = ht[k]; cp != NIL; cp = hp[cp])
{
if(cl[cp] == i)
{
switch(i)
{
case 4:
if(curcon[3] != con[cp][3]) break;
case 3:
if(curcon[2] != con[cp][2]) break;
case 2:
if(curcon[1] != con[cp][1]) break;
case 1:
if(curcon[0] != con[cp][0]) break;
case 0:
cslen = i;
return cp;
}
}
}
}
return NIL;
}
static U16B find_longest(void)
{
hs[1] = hrt[curcon[0]];
hs[2] = hrt[(curcon[1] + hs[1]) & (HTLEN - 1)];
hs[3] = hrt[(curcon[2] + hs[2]) & (HTLEN - 1)];
hs[4] = hrt[(curcon[3] + hs[3]) & (HTLEN - 1)];
usp = 0;
while(cmsp) cmask[cmstack[--cmsp]] = 0;
cslen = MAXCLEN + 1;
return find_next();
}
static U16B adj_escape_prob(U16B esc, U16B cp)
{
if(ft[cp] == 1) return iec[cl[cp]] >= (IECLIM >> 1) ? 2 : 1;
if(cc[cp] == 255) return 1;
if(cc[cp] && ((cc[cp] + 1) << 1) >= ft[cp])
{
esc = (S16B)((S32B)esc * ((cc[cp] + 1) << 1) / ft[cp]);
if(cc[cp] + 1 == ft[cp]) esc += (cc[cp] + 1) >> 1;
}
return esc ? esc : 1;
}
static S16B decode_first(U16B cp)
{
register U16B c;
register U16B tv;
register U16B i;
register S16B sum, tot, esc, cf;
register unsigned char sv;
esc = adj_escape_prob(fe[cp], cp);
tot = ft[cp];
if(nec >= NECLIM)
{
if(tot <= NECTLIM && nec == NECMAX) sv = 2;
else sv = 1;
tot <<= sv;
tv = ac_threshold_val(tot + esc) >> sv;
for(c = cp, sum = 0;; c = nb[c])
{
if(c == NIL) break;
if(sum + fa[c] <= tv) sum += fa[c];
else
{
cf = fa[c] << sv;
break;
}
}
sum <<= sv;
}
else
{
tv = ac_threshold_val(tot + esc);
for(c = cp, sum = 0;; c = nb[c])
{
if(c == NIL) break;
if(sum + fa[c] <= tv) sum += fa[c];
else
{
cf = fa[c];
break;
}
}
}
usp = 1;
if(c != NIL)
{
ac_in(sum, sum + cf, tot + esc);
if(ft[cp] == 1 && iec[cl[cp]]) --iec[cl[cp]];
as[0] = c;
cps[0] = cp;
c = fc[c];
if(nec < NECMAX) ++nec;
}
else
{
ac_in(tot, tot + esc, tot + esc);
if(ft[cp] == 1 && iec[cl[cp]] < IECLIM) ++iec[cl[cp]];
for(i = cp; i != NIL; sum = i, i = nb[i])
{
cmstack[cmsp++] = fc[i];
cmask[fc[i]] = 1;
}
cps[0] = 0x8000 | cp;
as[0] = sum;
c = ESC;
nec = 0;
}
return c;
}
static S16B decode_rest(U16B cp)
{
register U16B c;
register U16B tv;
register U16B i;
register S16B sum, tot, esc, cf;
esc = tot = 0;
for(i = cp; i != NIL; i = nb[i])
{
if(!cmask[fc[i]])
{
tot += fa[i];
if(fa[i] < ESCTH) ++esc;
}
}
esc = adj_escape_prob(esc, cp);
tv = ac_threshold_val(tot + esc);
for(c = cp, sum = 0;; c = nb[c])
{
if(c == NIL) break;
if(!cmask[fc[c]])
{
if(sum + fa[c] <= tv) sum += fa[c];
else
{
cf = fa[c];
break;
}
}
}
if(c != NIL)
{
ac_in(sum, sum + cf, tot + esc);
if(ft[cp] == 1 && iec[cl[cp]]) --iec[cl[cp]];
as[usp] = c;
cps[usp++] = cp;
c = fc[c];
++nec;
}
else
{
ac_in(tot, tot + esc, tot + esc);
if(ft[cp] == 1 && iec[cl[cp]] < IECLIM) ++iec[cl[cp]];
for(i = cp; i != NIL; sum = i, i = nb[i])
{
if(!cmask[fc[i]])
{
cmstack[cmsp++] = fc[i];
cmask[fc[i]] = 1;
}
}
cps[usp] = 0x8000 | cp;
as[usp++] = sum;
c = ESC;
}
return c;
}
static S16B decode_new(void)
{
register S16B c;
register U16B tv, sum, tot;
tot = 257 - cmsp;
tv = ac_threshold_val(tot);
for(c = sum = 0; c < 256; ++c)
{
if(cmask[c]) continue;
if(sum + 1 <= tv) ++sum;
else break;
}
ac_in(sum, sum + 1, tot);
return c;
}
#define decode_byte(cp) (cmsp ? decode_rest(cp) : decode_first(cp))
static void flush_output(void)
{
/* Output flushing is handled by the buffer management */
}
int hsc_unpack(decompress_context_t *ctx)
{
S16B c;
U16B cp;
unsigned char ncmax, ncmin;
if(init_unpack(ctx) < 0) return -1;
for(;;)
{
if(ctx->input.error || ctx->output.error) break;
cp = find_longest();
ncmin = cp == NIL ? 0 : cl[cp] + 1;
ncmax = maxclen + 1;
for(;;)
{
if(cp == NIL)
{
c = decode_new();
break;
}
if((c = decode_byte(cp)) != ESC)
{
el_movefront(cp);
break;
}
cp = find_next();
}
if(c == ESC) break;
add_model(c);
while(ncmax > ncmin) make_context(--ncmax, c);
if(putbyte_to_buffer(c) < 0) break;
move_context(c);
if(ctx->input.error || ctx->output.error) break;
}
flush_output();
hsc_cleanup();
return (ctx->input.error || ctx->output.error) ? -1 : 0;
}

90
ha/hsc.h Normal file
View File

@@ -0,0 +1,90 @@
/***********************************************************************
This file is part of HA, a general purpose file archiver.
Copyright (C) 1995 Harri Hirvola
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
************************************************************************
HA HSC method
***********************************************************************/
/***********************************************************************
Modified to work with memory buffers instead of files by
Copyright (C) 2005 Natalia Portillo
************************************************************************/
#ifndef HSC_H
#define HSC_H
#include "internal.h"
int hsc_unpack(decompress_context_t *ctx);
#define IECLIM 32
#define NECLIM 5
#define NECTLIM 4
#define NECMAX 10
#define MAXCLEN 4
#define NUMCON 10000
#define NUMCFB 32760
#define ESCTH 3
#define MAXTVAL 8000
#define RFMINI 4
#define HTLEN 16384
#define NIL 0xffff
#define ESC 256
typedef unsigned char Context[4];
/* Model data */
static Context curcon;
static U16B * ht = NULL;
static U16B * hp = NULL;
static Context * con = NULL;
static unsigned char *cl = NULL;
static unsigned char *cc = NULL;
static U16B * ft = NULL;
static unsigned char *fe = NULL;
static U16B * elp = NULL;
static U16B * eln = NULL;
static U16B elf, ell;
static unsigned char *rfm = NULL;
static U16B * fa = NULL;
static unsigned char *fc = NULL;
static U16B * nb = NULL;
static U16B fcfbl;
static U16B nrel;
/* Frequency mask system */
static unsigned char cmask[256];
static unsigned char cmstack[256];
static S16B cmsp;
/* Escape probability modifying system variables */
static unsigned char nec;
static unsigned char iec[MAXCLEN + 1];
/* Update stack variables */
static U16B usp;
static U16B cps[MAXCLEN + 1];
static U16B as[MAXCLEN + 1];
/* Miscellaneous */
static S16B dropcnt;
static unsigned char maxclen;
static U16B hrt[HTLEN];
static U16B hs[MAXCLEN + 1];
static S16B cslen;
#endif /* HSC_H */

45
ha/internal.h Normal file
View File

@@ -0,0 +1,45 @@
/***********************************************************************
Modified to work with memory buffers instead of files by
Copyright (C) 2005 Natalia Portillo
************************************************************************/
#ifndef INTERNAL_H
#define INTERNAL_H
#include <stdint.h>
#include <stddef.h>
/* Type definitions matching original HA code */
typedef int16_t S16B;
typedef uint16_t U16B;
typedef int32_t S32B;
typedef uint32_t U32B;
/* Memory buffer management */
typedef struct
{
const unsigned char *data;
size_t size;
size_t pos;
int error;
} input_buffer_t;
typedef struct
{
unsigned char *data;
size_t size;
size_t pos;
size_t max_size;
int error;
} output_buffer_t;
/* Decompression context */
typedef struct
{
input_buffer_t input;
output_buffer_t output;
int algorithm;
} decompress_context_t;
#endif /* INTERNAL_H */

99
ha/swdict.c Normal file
View File

@@ -0,0 +1,99 @@
/***********************************************************************
This file is part of HA, a general purpose file archiver.
Copyright (C) 1995 Harri Hirvola
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
************************************************************************
HA sliding window dictionary
***********************************************************************/
/***********************************************************************
Modified to work with memory buffers instead of files by
Copyright (C) 2005 Natalia Portillo
************************************************************************/
#include "internal.h"
#include "swdict.h"
#include <stdlib.h>
#include <string.h>
U16B swd_bpos, swd_mlf;
S16B swd_char;
static decompress_context_t *g_ctx = NULL;
static U16B cblen, bbf;
static unsigned char * b = NULL;
void swd_cleanup(void)
{
if(b != NULL)
{
free(b);
b = NULL;
}
}
void swd_dinit(decompress_context_t *ctx, U16B bufl)
{
g_ctx = ctx;
cblen = bufl;
b = malloc(cblen * sizeof(unsigned char));
if(b == NULL)
{
ctx->output.error = 1;
return;
}
bbf = 0;
}
static int putbyte_to_buffer(unsigned char c)
{
if(!g_ctx || g_ctx->output.pos >= g_ctx->output.max_size)
{
if(g_ctx) g_ctx->output.error = 1;
return -1;
}
g_ctx->output.data[g_ctx->output.pos++] = c;
if(g_ctx->output.pos > g_ctx->output.size) { g_ctx->output.size = g_ctx->output.pos; }
return 0;
}
void swd_dpair(U16B l, U16B p)
{
if(!g_ctx || g_ctx->output.error) return;
if(bbf > p) p = bbf - 1 - p;
else p = cblen - 1 - p + bbf;
while(l--)
{
b[bbf] = b[p];
if(putbyte_to_buffer(b[p]) < 0) return;
if(++bbf == cblen) bbf = 0;
if(++p == cblen) p = 0;
}
}
void swd_dchar(S16B c)
{
if(!g_ctx || g_ctx->output.error) return;
b[bbf] = c;
if(putbyte_to_buffer(c) < 0) return;
if(++bbf == cblen) bbf = 0;
}

45
ha/swdict.h Normal file
View File

@@ -0,0 +1,45 @@
/***********************************************************************
This file is part of HA, a general purpose file archiver.
Copyright (C) 1995 Harri Hirvola
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
************************************************************************
HA sliding window dictionary
***********************************************************************/
/***********************************************************************
Modified to work with memory buffers instead of files by
Copyright (C) 2005 Natalia Portillo
************************************************************************/
#ifndef SWDICT_H
#define SWDICT_H
#include "internal.h"
#define MINLEN 3 /* Minimum possible match length */
void swd_dinit(decompress_context_t *ctx, U16B bufl);
void swd_cleanup(void);
void swd_dpair(U16B l, U16B p);
void swd_dchar(S16B c);
extern U16B swd_bpos, swd_mlf;
extern S16B swd_char;
#endif /* SWDICT_H */

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -25,86 +25,59 @@
#include "3rdparty/lzma/C/LzmaLib.h"
#include "3rdparty/zstd/lib/zstd.h"
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_decode_buffer(uint8_t* dst_buffer,
uint32_t* dst_size,
const uint8_t* src_buffer,
uint32_t src_size)
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_decode_buffer(uint8_t *dst_buffer, uint32_t *dst_size,
const uint8_t *src_buffer, uint32_t src_size)
{
return BZ2_bzBuffToBuffDecompress((char*)dst_buffer, dst_size, (char*)src_buffer, src_size, 0, 0);
return BZ2_bzBuffToBuffDecompress((char *)dst_buffer, dst_size, (char *)src_buffer, src_size, 0, 0);
}
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_encode_buffer(uint8_t* dst_buffer,
uint32_t* dst_size,
const uint8_t* src_buffer,
uint32_t src_size,
int32_t blockSize100k)
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_encode_buffer(uint8_t *dst_buffer, uint32_t *dst_size,
const uint8_t *src_buffer, uint32_t src_size,
int32_t blockSize100k)
{
return BZ2_bzBuffToBuffCompress((char*)dst_buffer, dst_size, (char*)src_buffer, src_size, blockSize100k, 0, 0);
return BZ2_bzBuffToBuffCompress((char *)dst_buffer, dst_size, (char *)src_buffer, src_size, blockSize100k, 0, 0);
}
AARU_EXPORT size_t AARU_CALL AARU_lzfse_decode_buffer(uint8_t* dst_buffer,
size_t dst_size,
const uint8_t* src_buffer,
size_t src_size,
void* scratch_buffer)
AARU_EXPORT size_t AARU_CALL AARU_lzfse_decode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer,
size_t src_size, void *scratch_buffer)
{
return lzfse_decode_buffer(dst_buffer, dst_size, src_buffer, src_size, scratch_buffer);
}
AARU_EXPORT size_t AARU_CALL AARU_lzfse_encode_buffer(uint8_t* dst_buffer,
size_t dst_size,
const uint8_t* src_buffer,
size_t src_size,
void* scratch_buffer)
AARU_EXPORT size_t AARU_CALL AARU_lzfse_encode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer,
size_t src_size, void *scratch_buffer)
{
return lzfse_encode_buffer(dst_buffer, dst_size, src_buffer, src_size, scratch_buffer);
}
AARU_EXPORT int32_t AARU_CALL AARU_lzma_decode_buffer(uint8_t* dst_buffer,
size_t* dst_size,
const uint8_t* src_buffer,
size_t* srcLen,
const uint8_t* props,
size_t propsSize)
AARU_EXPORT int32_t AARU_CALL AARU_lzma_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
size_t *srcLen, const uint8_t *props, size_t propsSize)
{
return LzmaUncompress(dst_buffer, dst_size, src_buffer, srcLen, props, propsSize);
}
AARU_EXPORT int32_t AARU_CALL AARU_lzma_encode_buffer(uint8_t* dst_buffer,
size_t* dst_size,
const uint8_t* src_buffer,
size_t srcLen,
uint8_t* outProps,
size_t* outPropsSize,
int32_t level,
uint32_t dictSize,
int32_t lc,
int32_t lp,
int32_t pb,
int32_t fb,
int32_t numThreads)
AARU_EXPORT int32_t AARU_CALL AARU_lzma_encode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
size_t srcLen, uint8_t *outProps, size_t *outPropsSize,
int32_t level, uint32_t dictSize, int32_t lc, int32_t lp,
int32_t pb, int32_t fb, int32_t numThreads)
{
return LzmaCompress(
dst_buffer, dst_size, src_buffer, srcLen, outProps, outPropsSize, level, dictSize, lc, lp, pb, fb, numThreads);
return LzmaCompress(dst_buffer, dst_size, src_buffer, srcLen, outProps, outPropsSize, level, dictSize, lc, lp, pb,
fb, numThreads);
}
AARU_EXPORT size_t AARU_CALL AARU_zstd_decode_buffer(void* dst_buffer,
size_t dst_size,
const void* src_buffer,
size_t src_size)
AARU_EXPORT size_t AARU_CALL AARU_zstd_decode_buffer(void *dst_buffer, size_t dst_size, const void *src_buffer,
size_t src_size)
{
return ZSTD_decompress(dst_buffer, dst_size, src_buffer, src_size);
}
AARU_EXPORT size_t AARU_CALL AARU_zstd_encode_buffer(void* dst_buffer,
size_t dst_size,
const void* src_buffer,
size_t src_size,
int32_t compressionLevel)
AARU_EXPORT size_t AARU_CALL AARU_zstd_encode_buffer(void *dst_buffer, size_t dst_size, const void *src_buffer,
size_t src_size, int32_t compressionLevel)
{
return ZSTD_compress(dst_buffer, dst_size, src_buffer, src_size, compressionLevel);
}
// This is required if BZ_NO_STDIO
void bz_internal_error ( int errcode ) { }
void bz_internal_error(int errcode) {}
AARU_EXPORT uint64_t AARU_CALL AARU_get_acn_version() { return AARU_CHECKUMS_NATIVE_VERSION; }

185
library.h
View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -26,7 +26,7 @@
#endif
#if defined(_WIN32)
#define AARU_CALL __stdcall
#define AARU_CALL __stdcall
#define AARU_EXPORT EXTERNC __declspec(dllexport)
#define AARU_LOCAL
#ifndef PATH_MAX
@@ -36,11 +36,11 @@
#define AARU_CALL
#if defined(__APPLE__)
#define AARU_EXPORT EXTERNC __attribute__((visibility("default")))
#define AARU_LOCAL __attribute__((visibility("hidden")))
#define AARU_LOCAL __attribute__((visibility("hidden")))
#else
#if __GNUC__ >= 4
#define AARU_EXPORT EXTERNC __attribute__((visibility("default")))
#define AARU_LOCAL __attribute__((visibility("hidden")))
#define AARU_LOCAL __attribute__((visibility("hidden")))
#else
#define AARU_EXPORT EXTERNC
#define AARU_LOCAL
@@ -54,107 +54,112 @@
#define FORCE_INLINE static inline __attribute__((always_inline))
#endif
AARU_EXPORT int32_t AARU_CALL AARU_adc_decode_buffer(uint8_t* dst_buffer,
int32_t dst_size,
const uint8_t* src_buffer,
int32_t src_size);
AARU_EXPORT int32_t AARU_CALL AARU_adc_decode_buffer(uint8_t *dst_buffer, int32_t dst_size, const uint8_t *src_buffer,
int32_t src_size);
AARU_EXPORT int32_t AARU_CALL AARU_apple_rle_decode_buffer(uint8_t* dst_buffer,
int32_t dst_size,
const uint8_t* src_buffer,
int32_t src_size);
AARU_EXPORT int32_t AARU_CALL AARU_apple_rle_decode_buffer(uint8_t *dst_buffer, int32_t dst_size,
const uint8_t *src_buffer, int32_t src_size);
AARU_EXPORT size_t AARU_CALL AARU_flac_decode_redbook_buffer(uint8_t* dst_buffer,
size_t dst_size,
const uint8_t* src_buffer,
size_t src_size);
AARU_EXPORT size_t AARU_CALL AARU_flac_decode_redbook_buffer(uint8_t *dst_buffer, size_t dst_size,
const uint8_t *src_buffer, size_t src_size);
AARU_EXPORT size_t AARU_CALL AARU_flac_encode_redbook_buffer(uint8_t* dst_buffer,
size_t dst_size,
const uint8_t* src_buffer,
size_t src_size,
uint32_t blocksize,
int32_t do_mid_side_stereo,
int32_t loose_mid_side_stereo,
const char* apodization,
uint32_t max_lpc_order,
uint32_t qlp_coeff_precision,
int32_t do_qlp_coeff_prec_search,
int32_t do_exhaustive_model_search,
uint32_t min_residual_partition_order,
uint32_t max_residual_partition_order,
const char* application_id,
uint32_t application_id_len);
AARU_EXPORT size_t AARU_CALL AARU_flac_encode_redbook_buffer(
uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer, size_t src_size, uint32_t blocksize,
int32_t do_mid_side_stereo, int32_t loose_mid_side_stereo, const char *apodization, uint32_t max_lpc_order,
uint32_t qlp_coeff_precision, int32_t do_qlp_coeff_prec_search, int32_t do_exhaustive_model_search,
uint32_t min_residual_partition_order, uint32_t max_residual_partition_order, const char *application_id,
uint32_t application_id_len);
AARU_EXPORT int32_t AARU_CALL AARU_lzip_decode_buffer(uint8_t* dst_buffer,
int32_t dst_size,
const uint8_t* src_buffer,
int32_t src_size);
AARU_EXPORT int32_t AARU_CALL AARU_lzip_decode_buffer(uint8_t *dst_buffer, int32_t dst_size, const uint8_t *src_buffer,
int32_t src_size);
AARU_EXPORT int32_t AARU_CALL AARU_lzip_encode_buffer(uint8_t* dst_buffer,
int32_t dst_size,
const uint8_t* src_buffer,
int32_t src_size,
int32_t dictionary_size,
int32_t match_len_limit);
AARU_EXPORT int32_t AARU_CALL AARU_lzip_encode_buffer(uint8_t *dst_buffer, int32_t dst_size, const uint8_t *src_buffer,
int32_t src_size, int32_t dictionary_size,
int32_t match_len_limit);
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_decode_buffer(uint8_t* dst_buffer,
uint32_t* dst_size,
const uint8_t* src_buffer,
uint32_t src_size);
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_decode_buffer(uint8_t *dst_buffer, uint32_t *dst_size,
const uint8_t *src_buffer, uint32_t src_size);
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_encode_buffer(uint8_t* dst_buffer,
uint32_t* dst_size,
const uint8_t* src_buffer,
uint32_t src_size,
int32_t blockSize100k);
AARU_EXPORT int32_t AARU_CALL AARU_bzip2_encode_buffer(uint8_t *dst_buffer, uint32_t *dst_size,
const uint8_t *src_buffer, uint32_t src_size,
int32_t blockSize100k);
AARU_EXPORT size_t AARU_CALL AARU_lzfse_decode_buffer(uint8_t* dst_buffer,
size_t dst_size,
const uint8_t* src_buffer,
size_t src_size,
void* scratch_buffer);
AARU_EXPORT size_t AARU_CALL AARU_lzfse_decode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer,
size_t src_size, void *scratch_buffer);
AARU_EXPORT size_t AARU_CALL AARU_lzfse_encode_buffer(uint8_t* dst_buffer,
size_t dst_size,
const uint8_t* src_buffer,
size_t src_size,
void* scratch_buffer);
AARU_EXPORT size_t AARU_CALL AARU_lzfse_encode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer,
size_t src_size, void *scratch_buffer);
AARU_EXPORT int32_t AARU_CALL AARU_lzma_decode_buffer(uint8_t* dst_buffer,
size_t* dst_size,
const uint8_t* src_buffer,
size_t* src_size,
const uint8_t* props,
size_t propsSize);
AARU_EXPORT int32_t AARU_CALL AARU_lzma_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
size_t *src_size, const uint8_t *props, size_t propsSize);
AARU_EXPORT int32_t AARU_CALL AARU_lzma_encode_buffer(uint8_t* dst_buffer,
size_t* dst_size,
const uint8_t* src_buffer,
size_t src_size,
uint8_t* outProps,
size_t* outPropsSize,
int32_t level,
uint32_t dictSize,
int32_t lc,
int32_t lp,
int32_t pb,
int32_t fb,
int32_t numThreads);
AARU_EXPORT int32_t AARU_CALL AARU_lzma_encode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer,
size_t src_size, uint8_t *outProps, size_t *outPropsSize,
int32_t level, uint32_t dictSize, int32_t lc, int32_t lp,
int32_t pb, int32_t fb, int32_t numThreads);
AARU_EXPORT size_t AARU_CALL AARU_zstd_decode_buffer(void* dst_buffer,
size_t dst_size,
const void* src_buffer,
size_t src_size);
AARU_EXPORT size_t AARU_CALL AARU_zstd_decode_buffer(void *dst_buffer, size_t dst_size, const void *src_buffer,
size_t src_size);
AARU_EXPORT size_t AARU_CALL AARU_zstd_encode_buffer(void* dst_buffer,
size_t dst_size,
const void* src_buffer,
size_t src_size,
int32_t compressionLevel);
AARU_EXPORT size_t AARU_CALL AARU_zstd_encode_buffer(void *dst_buffer, size_t dst_size, const void *src_buffer,
size_t src_size, int32_t compressionLevel);
AARU_EXPORT void AARU_CALL *CreateLZDContext(void);
AARU_EXPORT void AARU_CALL DestroyLZDContext(void *ctx);
AARU_EXPORT int AARU_CALL LZD_FeedNative(void *ctx, const unsigned char *data, size_t length);
AARU_EXPORT int AARU_CALL LZD_DrainNative(void *ctx, unsigned char *outBuf, size_t outBufLen, size_t *produced);
AARU_EXPORT int AARU_CALL lh5_decompress(const uint8_t *in_buf, size_t in_len, uint8_t *out_buf, size_t *out_len);
#define AARU_CHECKUMS_NATIVE_VERSION 0x06000089
AARU_EXPORT uint64_t AARU_CALL AARU_get_acn_version();
#endif // AARU_COMPRESSION_NATIVE_LIBRARY_H
// ARC method 3: Stored with non-repeat packing
AARU_EXPORT int AARU_CALL arc_decompress_pack(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len);
// ARC method 4: Huffman squeezing
AARU_EXPORT int AARU_CALL arc_decompress_squeeze(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len);
// ARC Method 5: LZW (crunching)
AARU_EXPORT int AARU_CALL arc_decompress_crunch(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len);
// ARC Method 6: LZW with non-repeat packing (crunching)
AARU_EXPORT int AARU_CALL arc_decompress_crunch_nrpack(const unsigned char *in_buf, size_t in_len,
unsigned char *out_buf, size_t *out_len);
// ARC Method 7: LZW with non-repeat packing and new hash (Crunching)
AARU_EXPORT int AARU_CALL arc_decompress_crunch_nrpack_new(const unsigned char *in_buf, size_t in_len,
unsigned char *out_buf, size_t *out_len);
// ARC Method 8: Dynamic LZW (crunching)
AARU_EXPORT int AARU_CALL arc_decompress_crunch_dynamic(const unsigned char *in_buf, size_t in_len,
unsigned char *out_buf, size_t *out_len);
// ARC Method 9: Dynamic LZW with 13 bits (squashing)
AARU_EXPORT int AARU_CALL arc_decompress_squash(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len);
// ARC/PAK Method 10: LZW (crush) (unsure why it's different of the others but even XADMaster uses different codepaths)
AARU_EXPORT int AARU_CALL pak_decompress_crush(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len);
// ARC/PAK Method 11: LZSS (distill)
AARU_EXPORT int AARU_CALL pak_decompress_distill(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len);
/**
* HA Algorithm Types
*/
typedef enum {
HA_ALGORITHM_ASC = 0, /* ASC algorithm */
HA_ALGORITHM_HSC = 1 /* HSC algorithm */
} ha_algorithm_t;
AARU_EXPORT int AARU_CALL ha_asc_decompress(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf, size_t *out_len);
AARU_EXPORT int AARU_CALL ha_hsc_decompress(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf, size_t *out_len);
#endif // AARU_COMPRESSION_NATIVE_LIBRARY_H

21
lzip.c
View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
* Copyright © 2018-2019 David Ryskalczyk
*
* This library is free software; you can redistribute it and/or modify
@@ -23,13 +23,11 @@
#include "library.h"
#include "3rdparty/lzlib/lzlib.h"
AARU_EXPORT int32_t AARU_CALL AARU_lzip_decode_buffer(uint8_t* dst_buffer,
int32_t dst_size,
const uint8_t* src_buffer,
int32_t src_size)
AARU_EXPORT int32_t AARU_CALL AARU_lzip_decode_buffer(uint8_t *dst_buffer, int32_t dst_size, const uint8_t *src_buffer,
int32_t src_size)
{
int max_in_size;
void* ctx;
void *ctx;
enum LZ_Errno lz_err;
int32_t in_pos = 0, out_pos = 0, in_size;
int rd;
@@ -83,15 +81,12 @@ AARU_EXPORT int32_t AARU_CALL AARU_lzip_decode_buffer(uint8_t* dst_buffer,
return out_pos;
}
AARU_EXPORT int32_t AARU_CALL AARU_lzip_encode_buffer(uint8_t* dst_buffer,
int32_t dst_size,
const uint8_t* src_buffer,
int32_t src_size,
int32_t dictionary_size,
int32_t match_len_limit)
AARU_EXPORT int32_t AARU_CALL AARU_lzip_encode_buffer(uint8_t *dst_buffer, int32_t dst_size, const uint8_t *src_buffer,
int32_t src_size, int32_t dictionary_size,
int32_t match_len_limit)
{
int max_in_size;
void* ctx;
void *ctx;
enum LZ_Errno lz_err;
int32_t in_pos = 0, out_pos = 0, in_size;
int rd;

166
pak/bitstream.c Normal file
View File

@@ -0,0 +1,166 @@
/*
* bitstream.c - Bit stream input implementation
*
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "bitstream.h"
void bitstream_init(BitStream *bs, const uint8_t *data, size_t length)
{
bs->data = data;
bs->length = length;
bs->pos = 0;
bs->bitbuffer = 0;
bs->bitcount = 0;
bs->eof = false;
}
static void bitstream_fill_buffer(BitStream *bs)
{
while(bs->bitcount < 24 && bs->pos < bs->length)
{
bs->bitbuffer |= (uint32_t)bs->data[bs->pos] << (24 - bs->bitcount);
bs->bitcount += 8;
bs->pos++;
}
if(bs->pos >= bs->length && bs->bitcount == 0) { bs->eof = true; }
}
uint32_t bitstream_read_bit(BitStream *bs)
{
if(bs->eof) return 0;
if(bs->bitcount == 0) { bitstream_fill_buffer(bs); }
if(bs->bitcount == 0)
{
bs->eof = true;
return 0;
}
uint32_t bit = (bs->bitbuffer >> 31) & 1;
bs->bitbuffer <<= 1;
bs->bitcount--;
return bit;
}
uint32_t bitstream_read_bit_le(BitStream *bs)
{
if(bs->eof) return 0;
if(bs->bitcount == 0)
{
if(bs->pos >= bs->length)
{
bs->eof = true;
return 0;
}
bs->bitbuffer = bs->data[bs->pos++];
bs->bitcount = 8;
}
uint32_t bit = bs->bitbuffer & 1;
bs->bitbuffer >>= 1;
bs->bitcount--;
return bit;
}
uint32_t bitstream_read_bits(BitStream *bs, int count)
{
uint32_t result = 0;
for(int i = 0; i < count; i++) { result = (result << 1) | bitstream_read_bit(bs); }
return result;
}
uint32_t bitstream_read_bits_le(BitStream *bs, int count)
{
uint32_t result = 0;
for(int i = 0; i < count; i++) { result |= bitstream_read_bit_le(bs) << i; }
return result;
}
uint32_t bitstream_peek_bits(BitStream *bs, int count)
{
// Save current state
uint32_t saved_buffer = bs->bitbuffer;
int saved_bitcount = bs->bitcount;
size_t saved_pos = bs->pos;
bool saved_eof = bs->eof;
// Read the bits
uint32_t result = bitstream_read_bits(bs, count);
// Restore state
bs->bitbuffer = saved_buffer;
bs->bitcount = saved_bitcount;
bs->pos = saved_pos;
bs->eof = saved_eof;
return result;
}
uint32_t bitstream_peek_bits_le(BitStream *bs, int count)
{
// Save current state
uint32_t saved_buffer = bs->bitbuffer;
int saved_bitcount = bs->bitcount;
size_t saved_pos = bs->pos;
bool saved_eof = bs->eof;
// Read the bits
uint32_t result = bitstream_read_bits_le(bs, count);
// Restore state
bs->bitbuffer = saved_buffer;
bs->bitcount = saved_bitcount;
bs->pos = saved_pos;
bs->eof = saved_eof;
return result;
}
void bitstream_skip_bits(BitStream *bs, int count) { bitstream_read_bits(bs, count); }
void bitstream_skip_bits_le(BitStream *bs, int count) { bitstream_read_bits_le(bs, count); }
uint8_t bitstream_read_byte(BitStream *bs)
{
if(bs->pos >= bs->length)
{
bs->eof = true;
return 0;
}
return bs->data[bs->pos++];
}
uint16_t bitstream_read_uint16_le(BitStream *bs)
{
if(bs->pos + 1 >= bs->length)
{
bs->eof = true;
return 0;
}
uint16_t result = bs->data[bs->pos] | (bs->data[bs->pos + 1] << 8);
bs->pos += 2;
return result;
}
bool bitstream_eof(BitStream *bs) { return bs->eof; }

75
pak/bitstream.h Normal file
View File

@@ -0,0 +1,75 @@
/*
* bitstream.h - Bit stream input implementation
*
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef BITSTREAM_H
#define BITSTREAM_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef struct BitStream
{
const uint8_t *data;
size_t length;
size_t pos;
uint32_t bitbuffer;
int bitcount;
bool eof;
} BitStream;
// Initialize bit stream
void bitstream_init(BitStream *bs, const uint8_t *data, size_t length);
// Read a single bit (MSB first)
uint32_t bitstream_read_bit(BitStream *bs);
// Read a single bit (LSB first)
uint32_t bitstream_read_bit_le(BitStream *bs);
// Read multiple bits (MSB first)
uint32_t bitstream_read_bits(BitStream *bs, int count);
// Read multiple bits (LSB first)
uint32_t bitstream_read_bits_le(BitStream *bs, int count);
// Peek at bits without consuming them (MSB first)
uint32_t bitstream_peek_bits(BitStream *bs, int count);
// Peek at bits without consuming them (LSB first)
uint32_t bitstream_peek_bits_le(BitStream *bs, int count);
// Skip previously peeked bits (MSB first)
void bitstream_skip_bits(BitStream *bs, int count);
// Skip previously peeked bits (LSB first)
void bitstream_skip_bits_le(BitStream *bs, int count);
// Read a byte
uint8_t bitstream_read_byte(BitStream *bs);
// Read a 16-bit little endian integer
uint16_t bitstream_read_uint16_le(BitStream *bs);
// Check if end of stream reached
bool bitstream_eof(BitStream *bs);
#endif /* BITSTREAM_H */

219
pak/crush.c Normal file
View File

@@ -0,0 +1,219 @@
/*
* arc_crush.c - ARC Crush decompression algorithm
*
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "../library.h"
#include "bitstream.h"
#include "lzw.h"
int pak_decompress_crush_internal(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf, size_t *out_len)
{
if(!in_buf || !out_buf || !out_len || in_len == 0) { return -1; }
BitStream bs;
bitstream_init(&bs, (const uint8_t *)in_buf, in_len);
LZW *lzw = lzw_alloc(8192, 1);
if(!lzw) { return -1; }
// Initialize state
int symbolsize = 1;
int nextsizebump = 2;
bool useliteralbit = true;
int numrecentstrings = 0;
int ringindex = 0;
bool stringring[500];
memset(stringring, 0, sizeof(stringring));
int usageindex = 0x101;
uint8_t usage[8192];
memset(usage, 0, sizeof(usage));
int currbyte = 0;
uint8_t buffer[8192];
size_t outpos = 0;
size_t max_output = *out_len;
while(!bitstream_eof(&bs) && outpos < max_output)
{
if(!currbyte)
{
// Read the next symbol. How depends on the mode we are operating in.
int symbol;
if(useliteralbit)
{
// Use codes prefixed by a bit that selects literal or string codes.
// Literals are always 8 bits, strings vary.
if(bitstream_read_bit_le(&bs)) { symbol = bitstream_read_bits_le(&bs, symbolsize) + 256; }
else { symbol = bitstream_read_bits_le(&bs, 8); }
}
else
{
// Use same-length codes for both literals and strings.
// Due to an optimization quirk in the original decruncher,
// literals have their bits inverted.
symbol = bitstream_read_bits_le(&bs, symbolsize);
if(symbol < 0x100) symbol ^= 0xff;
}
// Code 0x100 is the EOF code.
if(symbol == 0x100) { break; }
// Walk through the LZW tree, and set the usage count of the current
// string and all its parents to 4. This is not necessary for literals,
// but we do it anyway for simplicity.
LZWTreeNode *nodes = lzw_symbols(lzw);
int marksymbol = symbol;
while(marksymbol >= 0)
{
if(marksymbol < 8192) { usage[marksymbol] = 4; }
marksymbol = nodes[marksymbol].parent;
}
// Adjust the count of recent strings versus literals.
// Use a ring buffer of length 500 as a window to keep track
// of how many strings have been encountered lately.
// First, decrease the count if a string leaves the window.
if(stringring[ringindex]) numrecentstrings--;
// Then store the current type of symbol in the window, and
// increase the count if the current symbol is a string.
if(symbol < 0x100) { stringring[ringindex] = false; }
else
{
stringring[ringindex] = true;
numrecentstrings++;
}
// Move the window forward.
ringindex = (ringindex + 1) % 500;
// Check the number of strings. If there have been many literals
// lately, bit-prefixed codes should be used. If we need to change
// mode, re-calculate the point where we increase the code length.
bool manyliterals = numrecentstrings < 375;
if(manyliterals != useliteralbit)
{
useliteralbit = manyliterals;
nextsizebump = 1 << symbolsize;
if(!useliteralbit) nextsizebump -= 0x100;
}
// Update the LZW tree.
if(!lzw_symbol_list_full(lzw))
{
// If there is space in the tree, just add a new string as usual.
if(lzw_next_symbol(lzw, symbol) != LZW_NO_ERROR)
{
lzw_free(lzw);
return -1;
}
// Set the usage count of the newly created entry.
int count = lzw_symbol_count(lzw);
if(count > 0 && count - 1 < 8192) { usage[count - 1] = 2; }
}
else
{
// If the tree is full, find a less-used symbol, and replace it.
int minindex = 0, minusage = INT_MAX;
int index = usageindex;
do {
index++;
if(index == 8192) index = 0x101;
if(usage[index] < minusage)
{
minindex = index;
minusage = usage[index];
}
usage[index]--;
if(usage[index] == 0) break;
} while(index != usageindex);
usageindex = index;
if(lzw_replace_symbol(lzw, minindex, symbol) != LZW_NO_ERROR)
{
lzw_free(lzw);
return -1;
}
// Set the usage count of the replaced entry.
if(minindex < 8192) { usage[minindex] = 2; }
}
// Extract the data to output.
currbyte = lzw_reverse_output_to_buffer(lzw, buffer);
// Check if we need to increase the code size. The point at which
// to increase varies depending on the coding mode.
if(lzw_symbol_count(lzw) - 257 >= nextsizebump)
{
symbolsize++;
nextsizebump = 1 << symbolsize;
if(!useliteralbit) nextsizebump -= 0x100;
}
}
if(currbyte > 0 && outpos < max_output) { out_buf[outpos++] = (char)buffer[--currbyte]; }
else if(currbyte == 0)
{
// No more bytes in buffer, continue to next symbol
continue;
}
else
{
// Output buffer full
break;
}
}
lzw_free(lzw);
*out_len = outpos;
return 0;
}
AARU_EXPORT int AARU_CALL pak_decompress_crush(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len)
{
// Allocate a temporary buffer.
size_t temp_len = *out_len * 2; // Heuristic.
unsigned char *temp_buf = malloc(temp_len);
if(!temp_buf) return -1;
// Decompress crunched data.
int result = pak_decompress_crush_internal(in_buf, in_len, temp_buf, &temp_len);
if(result == 0)
{
// Decompress non-repeat packing.
result = arc_decompress_pack(temp_buf, temp_len, out_buf, out_len);
}
free(temp_buf);
return result;
}

182
pak/distill.c Normal file
View File

@@ -0,0 +1,182 @@
/*
* arc_distill.c - ARC Distill decompression algorithm
*
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "../library.h"
#include "bitstream.h"
#include "prefixcode.h"
static const int offset_lengths[0x40] = {
3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
};
static const int offset_codes[0x40] = {
0x00, 0x02, 0x04, 0x0c, 0x01, 0x06, 0x0a, 0x0e, 0x11, 0x16, 0x1a, 0x1e, 0x05, 0x09, 0x0d, 0x15,
0x19, 0x1d, 0x25, 0x29, 0x2d, 0x35, 0x39, 0x3d, 0x03, 0x07, 0x0b, 0x13, 0x17, 0x1b, 0x23, 0x27,
0x2b, 0x33, 0x37, 0x3b, 0x43, 0x47, 0x4b, 0x53, 0x57, 0x5b, 0x63, 0x67, 0x6b, 0x73, 0x77, 0x7b,
0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f, 0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff,
};
static void build_code_from_tree(PrefixCode *code, int *tree, int node, int numnodes, int depth)
{
if(depth > 64)
{
// Too deep - error
return;
}
if(node >= numnodes) { prefix_code_make_leaf_with_value(code, node - numnodes); }
else
{
prefix_code_start_zero_branch(code);
build_code_from_tree(code, tree, tree[node], numnodes, depth + 1);
prefix_code_start_one_branch(code);
build_code_from_tree(code, tree, tree[node + 1], numnodes, depth + 1);
prefix_code_finish_branches(code);
}
}
AARU_EXPORT int AARU_CALL pak_decompress_distill(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
size_t *out_len)
{
if(!in_buf || !out_buf || !out_len || in_len == 0) { return -1; }
BitStream bs;
bitstream_init(&bs, (const uint8_t *)in_buf, in_len);
// Read header information
int numnodes = bitstream_read_uint16_le(&bs);
int codelength = bitstream_read_byte(&bs);
if(numnodes < 2 || numnodes > 0x274) { return -1; }
// Read tree nodes
int *nodes = malloc(numnodes * sizeof(int));
if(!nodes) { return -1; }
for(int i = 0; i < numnodes; i++) { nodes[i] = bitstream_read_bits_le(&bs, codelength); }
// Build main code tree
PrefixCode *maincode = prefix_code_alloc();
if(!maincode)
{
free(nodes);
return -1;
}
prefix_code_start_building_tree(maincode);
build_code_from_tree(maincode, nodes, numnodes - 2, numnodes, 0);
free(nodes);
// Build offset code tree
PrefixCode *offsetcode = prefix_code_alloc();
if(!offsetcode)
{
prefix_code_free(maincode);
return -1;
}
for(int i = 0; i < 0x40; i++)
{
if(prefix_code_add_value_low_bit_first(offsetcode, i, offset_codes[i], offset_lengths[i]) != PREFIX_CODE_OK)
{
prefix_code_free(maincode);
prefix_code_free(offsetcode);
return -1;
}
}
// LZSS decompression
uint8_t window[8192];
memset(window, 0, sizeof(window));
int windowpos = 0;
size_t outpos = 0;
size_t max_output = *out_len;
while(!bitstream_eof(&bs) && outpos < max_output)
{
int symbol = prefix_code_read_symbol_le(&bs, maincode);
if(symbol < 0) break;
if(symbol < 256)
{
// Literal byte
if(outpos < max_output) { out_buf[outpos++] = (char)symbol; }
window[windowpos] = symbol;
windowpos = (windowpos + 1) & 0x1fff;
}
else if(symbol == 256)
{
// End of stream
break;
}
else
{
// Match
int length = symbol - 0x101 + 3;
int offsetsymbol = prefix_code_read_symbol_le(&bs, offsetcode);
if(offsetsymbol < 0) break;
int extralength;
if(outpos >= 0x1000 - 0x3c)
extralength = 7;
else if(outpos >= 0x800 - 0x3c)
extralength = 6;
else if(outpos >= 0x400 - 0x3c)
extralength = 5;
else if(outpos >= 0x200 - 0x3c)
extralength = 4;
else if(outpos >= 0x100 - 0x3c)
extralength = 3;
else if(outpos >= 0x80 - 0x3c)
extralength = 2;
else if(outpos >= 0x40 - 0x3c)
extralength = 1;
else
extralength = 0;
int extrabits = bitstream_read_bits_le(&bs, extralength);
int offset = (offsetsymbol << extralength) + extrabits + 1;
// Copy match
for(int i = 0; i < length; i++)
{
int sourcepos = (windowpos - offset) & 0x1fff;
uint8_t byte = window[sourcepos];
if(outpos < max_output) { out_buf[outpos++] = (char)byte; }
window[windowpos] = byte;
windowpos = (windowpos + 1) & 0x1fff;
}
}
}
prefix_code_free(maincode);
prefix_code_free(offsetcode);
*out_len = outpos;
return 0;
}

162
pak/lzw.c Normal file
View File

@@ -0,0 +1,162 @@
/*
* lzw.c - LZW decompression implementation
*
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "lzw.h"
#include <stdlib.h>
LZW *lzw_alloc(int maxsymbols, int reservedsymbols)
{
LZW *self = (LZW *)malloc(sizeof(LZW) + sizeof(LZWTreeNode) * maxsymbols);
if(!self) return NULL;
if(maxsymbols < 256 + reservedsymbols)
{
free(self);
return NULL;
}
self->maxsymbols = maxsymbols;
self->reservedsymbols = reservedsymbols;
self->buffer = NULL;
self->buffersize = 0;
for(int i = 0; i < 256; i++)
{
self->nodes[i].chr = i;
self->nodes[i].parent = -1;
}
lzw_clear_table(self);
return self;
}
void lzw_free(LZW *self)
{
if(self)
{
free(self->buffer);
free(self);
}
}
void lzw_clear_table(LZW *self)
{
self->numsymbols = 256 + self->reservedsymbols;
self->prevsymbol = -1;
self->symbolsize = 9; // TODO: technically this depends on reservedsymbols
}
static uint8_t find_first_byte(LZWTreeNode *nodes, int symbol)
{
while(nodes[symbol].parent >= 0) symbol = nodes[symbol].parent;
return nodes[symbol].chr;
}
int lzw_next_symbol(LZW *self, int symbol)
{
if(self->prevsymbol < 0)
{
if(symbol >= self->numsymbols) return LZW_INVALID_CODE_ERROR;
self->prevsymbol = symbol;
return LZW_NO_ERROR;
}
int postfixbyte;
if(symbol < self->numsymbols) { postfixbyte = find_first_byte(self->nodes, symbol); }
else if(symbol == self->numsymbols) { postfixbyte = find_first_byte(self->nodes, self->prevsymbol); }
else { return LZW_INVALID_CODE_ERROR; }
int parent = self->prevsymbol;
self->prevsymbol = symbol;
if(!lzw_symbol_list_full(self))
{
self->nodes[self->numsymbols].parent = parent;
self->nodes[self->numsymbols].chr = postfixbyte;
self->numsymbols++;
if(!lzw_symbol_list_full(self))
{
if((self->numsymbols & (self->numsymbols - 1)) == 0) { self->symbolsize++; }
}
return LZW_NO_ERROR;
}
else { return LZW_TOO_MANY_CODES_ERROR; }
}
int lzw_replace_symbol(LZW *self, int oldsymbol, int symbol)
{
if(symbol >= self->numsymbols) return LZW_INVALID_CODE_ERROR;
self->nodes[oldsymbol].parent = self->prevsymbol;
self->nodes[oldsymbol].chr = find_first_byte(self->nodes, symbol);
self->prevsymbol = symbol;
return LZW_NO_ERROR;
}
int lzw_output_length(LZW *self)
{
int symbol = self->prevsymbol;
int n = 0;
while(symbol >= 0)
{
symbol = self->nodes[symbol].parent;
n++;
}
return n;
}
int lzw_output_to_buffer(LZW *self, uint8_t *buffer)
{
int symbol = self->prevsymbol;
int n = lzw_output_length(self);
buffer += n;
while(symbol >= 0)
{
*--buffer = self->nodes[symbol].chr;
symbol = self->nodes[symbol].parent;
}
return n;
}
int lzw_reverse_output_to_buffer(LZW *self, uint8_t *buffer)
{
int symbol = self->prevsymbol;
int n = 0;
while(symbol >= 0)
{
*buffer++ = self->nodes[symbol].chr;
symbol = self->nodes[symbol].parent;
n++;
}
return n;
}

83
pak/lzw.h Normal file
View File

@@ -0,0 +1,83 @@
/*
* lzw.h - LZW decompression implementation
*
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef LZW_H
#define LZW_H
#include <stdbool.h>
#include <stdint.h>
#define LZW_NO_ERROR 0
#define LZW_INVALID_CODE_ERROR 1
#define LZW_TOO_MANY_CODES_ERROR 2
typedef struct LZWTreeNode
{
uint8_t chr;
int parent;
} LZWTreeNode;
typedef struct LZW
{
int numsymbols;
int maxsymbols;
int reservedsymbols;
int prevsymbol;
int symbolsize;
uint8_t *buffer;
int buffersize;
LZWTreeNode nodes[]; // Flexible array member (C99)
} LZW;
// Allocate LZW structure
LZW *lzw_alloc(int maxsymbols, int reservedsymbols);
// Free LZW structure
void lzw_free(LZW *self);
// Clear/reset LZW table
void lzw_clear_table(LZW *self);
// Process next symbol
int lzw_next_symbol(LZW *self, int symbol);
// Replace a symbol
int lzw_replace_symbol(LZW *self, int oldsymbol, int symbol);
// Get output length
int lzw_output_length(LZW *self);
// Output to buffer (normal order)
int lzw_output_to_buffer(LZW *self, uint8_t *buffer);
// Output to buffer (reverse order)
int lzw_reverse_output_to_buffer(LZW *self, uint8_t *buffer);
// Inline helper functions
static inline int lzw_symbol_count(LZW *self) { return self->numsymbols; }
static inline bool lzw_symbol_list_full(LZW *self) { return self->numsymbols == self->maxsymbols; }
static inline LZWTreeNode *lzw_symbols(LZW *self) { return self->nodes; }
#endif /* LZW_H */

539
pak/prefixcode.c Normal file
View File

@@ -0,0 +1,539 @@
/*
* prefixcode.c - Prefix code tree implementation
*
* Copyright (c) 2017-pstatic inline bool is_invalid_node(PrefixCode *self, int node) {
(void)self; // Suppress unused parameter warning
return (node < 0);
}ent, MacPaw Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "prefixcode.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
// Safe realloc that frees original pointer on failure
static void *safe_realloc(void *ptr, size_t newsize)
{
void *newptr = realloc(ptr, newsize);
if(!newptr && newsize > 0)
{
free(ptr);
return NULL;
}
return newptr;
}
// Inline helper functions
static inline CodeTreeNode *node_pointer(PrefixCode *self, int node) { return &self->tree[node]; }
static inline int branch(PrefixCode *self, int node, int bit) { return node_pointer(self, node)->branches[bit]; }
static inline void set_branch(PrefixCode *self, int node, int bit, int nextnode)
{
node_pointer(self, node)->branches[bit] = nextnode;
}
static inline int left_branch(PrefixCode *self, int node) { return branch(self, node, 0); }
static inline int right_branch(PrefixCode *self, int node) { return branch(self, node, 1); }
static inline void set_left_branch(PrefixCode *self, int node, int nextnode) { set_branch(self, node, 0, nextnode); }
static inline void set_right_branch(PrefixCode *self, int node, int nextnode) { set_branch(self, node, 1, nextnode); }
static inline int leaf_value(PrefixCode *self, int node) { return left_branch(self, node); }
static inline void set_leaf_value(PrefixCode *self, int node, int value)
{
set_left_branch(self, node, value);
set_right_branch(self, node, value);
}
static inline void set_empty_node(PrefixCode *self, int node)
{
set_left_branch(self, node, -1);
set_right_branch(self, node, -2);
}
static inline bool is_invalid_node(PrefixCode *self, int node) { return node < 0; }
static inline bool is_open_branch(PrefixCode *self, int node, int bit)
{
return is_invalid_node(self, branch(self, node, bit));
}
static inline bool is_empty_node(PrefixCode *self, int node)
{
return left_branch(self, node) == -1 && right_branch(self, node) == -2;
}
static inline bool is_leaf_node(PrefixCode *self, int node)
{
return left_branch(self, node) == right_branch(self, node);
}
static int new_node(PrefixCode *self)
{
CodeTreeNode *newtree = safe_realloc(self->tree, (self->numentries + 1) * sizeof(CodeTreeNode));
if(!newtree) return -1;
self->tree = newtree;
set_empty_node(self, self->numentries);
return self->numentries++;
}
// Stack implementation for tree building
static PrefixCodeStack *prefix_code_stack_alloc(void)
{
PrefixCodeStack *stack = malloc(sizeof(PrefixCodeStack));
if(!stack) return NULL;
stack->data = malloc(16 * sizeof(int));
if(!stack->data)
{
free(stack);
return NULL;
}
stack->count = 0;
stack->capacity = 16;
return stack;
}
static void prefix_code_stack_free(PrefixCodeStack *stack)
{
if(!stack) return;
free(stack->data);
free(stack);
}
static int prefix_code_stack_push(PrefixCodeStack *stack, int value)
{
if(stack->count >= stack->capacity)
{
int newcapacity = stack->capacity * 2;
int *newdata = safe_realloc(stack->data, newcapacity * sizeof(int));
if(!newdata) return -1;
stack->data = newdata;
stack->capacity = newcapacity;
}
stack->data[stack->count++] = value;
return 0;
}
static int prefix_code_stack_pop(PrefixCodeStack *stack)
{
if(stack->count == 0) return -1;
return stack->data[--stack->count];
}
static void prefix_code_stack_clear(PrefixCodeStack *stack) { stack->count = 0; }
// Bit reversal functions
static uint32_t reverse_32(uint32_t val)
{
val = ((val >> 1) & 0x55555555) | ((val & 0x55555555) << 1);
val = ((val >> 2) & 0x33333333) | ((val & 0x33333333) << 2);
val = ((val >> 4) & 0x0F0F0F0F) | ((val & 0x0F0F0F0F) << 4);
val = ((val >> 8) & 0x00FF00FF) | ((val & 0x00FF00FF) << 8);
return (val >> 16) | (val << 16);
}
static uint32_t reverse_n(uint32_t val, int length) { return reverse_32(val) >> (32 - length); }
// Table construction functions
#define TABLE_MAX_SIZE 10
static void make_table(PrefixCode *code, int node, CodeTableEntry *table, int depth, int maxdepth)
{
int currtablesize = 1 << (maxdepth - depth);
if(is_invalid_node(code, node))
{
for(int i = 0; i < currtablesize; i++) table[i].length = -1;
}
else if(is_leaf_node(code, node))
{
for(int i = 0; i < currtablesize; i++)
{
table[i].length = depth;
table[i].value = leaf_value(code, node);
}
}
else
{
if(depth == maxdepth)
{
table[0].length = maxdepth + 1;
table[0].value = node;
}
else
{
make_table(code, left_branch(code, node), table, depth + 1, maxdepth);
make_table(code, right_branch(code, node), table + currtablesize / 2, depth + 1, maxdepth);
}
}
}
static void make_table_le(PrefixCode *code, int node, CodeTableEntry *table, int depth, int maxdepth)
{
int currtablesize = 1 << (maxdepth - depth);
int currstride = 1 << depth;
if(is_invalid_node(code, node))
{
for(int i = 0; i < currtablesize; i++) table[i * currstride].length = -1;
}
else if(is_leaf_node(code, node))
{
for(int i = 0; i < currtablesize; i++)
{
table[i * currstride].length = depth;
table[i * currstride].value = leaf_value(code, node);
}
}
else
{
if(depth == maxdepth)
{
table[0].length = maxdepth + 1;
table[0].value = node;
}
else
{
make_table_le(code, left_branch(code, node), table, depth + 1, maxdepth);
make_table_le(code, right_branch(code, node), table + currstride, depth + 1, maxdepth);
}
}
}
static int prefix_code_make_table(PrefixCode *self)
{
if(self->table1) return PREFIX_CODE_OK;
if(self->maxlength < self->minlength)
self->tablesize = TABLE_MAX_SIZE; // no code lengths recorded
else if(self->maxlength >= TABLE_MAX_SIZE)
self->tablesize = TABLE_MAX_SIZE;
else
self->tablesize = self->maxlength;
self->table1 = malloc(sizeof(CodeTableEntry) * (1 << self->tablesize));
if(!self->table1) return PREFIX_CODE_INVALID;
make_table(self, 0, self->table1, 0, self->tablesize);
return PREFIX_CODE_OK;
}
static int prefix_code_make_table_le(PrefixCode *self)
{
if(self->table2) return PREFIX_CODE_OK;
if(self->maxlength < self->minlength)
self->tablesize = TABLE_MAX_SIZE; // no code lengths recorded
else if(self->maxlength >= TABLE_MAX_SIZE)
self->tablesize = TABLE_MAX_SIZE;
else
self->tablesize = self->maxlength;
self->table2 = malloc(sizeof(CodeTableEntry) * (1 << self->tablesize));
if(!self->table2) return PREFIX_CODE_INVALID;
make_table_le(self, 0, self->table2, 0, self->tablesize);
return PREFIX_CODE_OK;
}
// Public functions
PrefixCode *prefix_code_alloc(void)
{
PrefixCode *self = malloc(sizeof(PrefixCode));
if(!self) return NULL;
self->tree = malloc(sizeof(CodeTreeNode));
if(!self->tree)
{
free(self);
return NULL;
}
set_empty_node(self, 0);
self->numentries = 1;
self->minlength = INT_MAX;
self->maxlength = INT_MIN;
self->isstatic = false;
self->stack = NULL;
self->table1 = self->table2 = NULL;
self->tablesize = 0;
self->currnode = 0;
return self;
}
PrefixCode *prefix_code_alloc_with_static_table(int (*statictable)[2])
{
PrefixCode *self = malloc(sizeof(PrefixCode));
if(!self) return NULL;
self->tree = (CodeTreeNode *)statictable; // TODO: fix the ugly cast
self->isstatic = true;
self->stack = NULL;
self->table1 = self->table2 = NULL;
self->tablesize = 0;
self->currnode = 0;
self->numentries = 0;
self->minlength = INT_MAX;
self->maxlength = INT_MIN;
return self;
}
PrefixCode *prefix_code_alloc_with_lengths(const int *lengths, int numsymbols, int maxcodelength, bool zeros)
{
PrefixCode *self = prefix_code_alloc();
if(!self) return NULL;
int code = 0, symbolsleft = numsymbols;
for(int length = 1; length <= maxcodelength; length++)
{
for(int i = 0; i < numsymbols; i++)
{
if(lengths[i] != length) continue;
// Instead of reversing to get a low-bit-first code, we shift and use high-bit-first.
int result;
if(zeros) { result = prefix_code_add_value_high_bit_first(self, i, code, length); }
else { result = prefix_code_add_value_high_bit_first(self, i, ~code, length); }
if(result != PREFIX_CODE_OK)
{
prefix_code_free(self);
return NULL;
}
code++;
if(--symbolsleft == 0) return self; // early exit if all codes have been handled
}
code <<= 1;
}
return self;
}
void prefix_code_free(PrefixCode *self)
{
if(!self) return;
if(!self->isstatic) free(self->tree);
free(self->table1);
free(self->table2);
if(self->stack) prefix_code_stack_free(self->stack);
free(self);
}
int prefix_code_add_value_high_bit_first(PrefixCode *self, int value, uint32_t code, int length)
{
return prefix_code_add_value_high_bit_first_repeat(self, value, code, length, length);
}
int prefix_code_add_value_high_bit_first_repeat(PrefixCode *self, int value, uint32_t code, int length, int repeatpos)
{
if(!self || self->isstatic) return PREFIX_CODE_INVALID;
free(self->table1);
free(self->table2);
self->table1 = self->table2 = NULL;
if(length > self->maxlength) self->maxlength = length;
if(length < self->minlength) self->minlength = length;
repeatpos = length - 1 - repeatpos;
if(repeatpos == 0 ||
(repeatpos >= 0 && (((code >> (repeatpos - 1)) & 3) == 0 || ((code >> (repeatpos - 1)) & 3) == 3)))
{
return PREFIX_CODE_INVALID;
}
int lastnode = 0;
for(int bitpos = length - 1; bitpos >= 0; bitpos--)
{
int bit = (code >> bitpos) & 1;
if(is_leaf_node(self, lastnode)) return PREFIX_CODE_INVALID;
if(bitpos == repeatpos)
{
if(!is_open_branch(self, lastnode, bit)) return PREFIX_CODE_INVALID;
int repeatnode = new_node(self);
int nextnode = new_node(self);
if(repeatnode < 0 || nextnode < 0) return PREFIX_CODE_INVALID;
set_branch(self, lastnode, bit, repeatnode);
set_branch(self, repeatnode, bit, repeatnode);
set_branch(self, repeatnode, bit ^ 1, nextnode);
lastnode = nextnode;
bitpos++; // terminating bit already handled, skip it
}
else
{
if(is_open_branch(self, lastnode, bit))
{
int newnode = new_node(self);
if(newnode < 0) return PREFIX_CODE_INVALID;
set_branch(self, lastnode, bit, newnode);
}
lastnode = branch(self, lastnode, bit);
}
}
if(!is_empty_node(self, lastnode)) return PREFIX_CODE_INVALID;
set_leaf_value(self, lastnode, value);
return PREFIX_CODE_OK;
}
int prefix_code_add_value_low_bit_first(PrefixCode *self, int value, uint32_t code, int length)
{
return prefix_code_add_value_high_bit_first(self, value, reverse_n(code, length), length);
}
int prefix_code_add_value_low_bit_first_repeat(PrefixCode *self, int value, uint32_t code, int length, int repeatpos)
{
return prefix_code_add_value_high_bit_first_repeat(self, value, reverse_n(code, length), length, repeatpos);
}
void prefix_code_start_building_tree(PrefixCode *self)
{
if(!self) return;
self->currnode = 0;
if(!self->stack) { self->stack = prefix_code_stack_alloc(); }
else { prefix_code_stack_clear(self->stack); }
}
void prefix_code_start_zero_branch(PrefixCode *self)
{
if(!self) return;
int new = new_node(self);
if(new < 0) return;
set_branch(self, self->currnode, 0, new);
prefix_code_stack_push(self->stack, self->currnode);
self->currnode = new;
}
void prefix_code_start_one_branch(PrefixCode *self)
{
if(!self) return;
int new = new_node(self);
if(new < 0) return;
set_branch(self, self->currnode, 1, new);
prefix_code_stack_push(self->stack, self->currnode);
self->currnode = new;
}
void prefix_code_finish_branches(PrefixCode *self)
{
if(!self || !self->stack) return;
int node = prefix_code_stack_pop(self->stack);
if(node >= 0) self->currnode = node;
}
void prefix_code_make_leaf_with_value(PrefixCode *self, int value)
{
if(!self) return;
set_leaf_value(self, self->currnode, value);
prefix_code_finish_branches(self);
}
// BitStream interface functions
int prefix_code_read_symbol(BitStream *bs, PrefixCode *code)
{
if(!code) return PREFIX_CODE_INVALID;
if(!code->table1)
{
if(prefix_code_make_table(code) != PREFIX_CODE_OK) return PREFIX_CODE_INVALID;
}
int bits = bitstream_peek_bits(bs, code->tablesize);
int length = code->table1[bits].length;
int value = code->table1[bits].value;
if(length < 0) return PREFIX_CODE_INVALID;
if(length <= code->tablesize)
{
bitstream_skip_bits(bs, length);
return value;
}
bitstream_skip_bits(bs, code->tablesize);
int node = value;
while(!is_leaf_node(code, node))
{
int bit = bitstream_read_bit(bs);
if(is_open_branch(code, node, bit)) return PREFIX_CODE_INVALID;
node = branch(code, node, bit);
}
return leaf_value(code, node);
}
int prefix_code_read_symbol_le(BitStream *bs, PrefixCode *code)
{
if(!code) return PREFIX_CODE_INVALID;
if(!code->table2)
{
if(prefix_code_make_table_le(code) != PREFIX_CODE_OK) return PREFIX_CODE_INVALID;
}
int bits = bitstream_peek_bits_le(bs, code->tablesize);
int length = code->table2[bits].length;
int value = code->table2[bits].value;
if(length < 0) return PREFIX_CODE_INVALID;
if(length <= code->tablesize)
{
bitstream_skip_bits_le(bs, length);
return value;
}
bitstream_skip_bits_le(bs, code->tablesize);
int node = value;
while(!is_leaf_node(code, node))
{
int bit = bitstream_read_bit_le(bs);
if(is_open_branch(code, node, bit)) return PREFIX_CODE_INVALID;
node = branch(code, node, bit);
}
return leaf_value(code, node);
}

89
pak/prefixcode.h Normal file
View File

@@ -0,0 +1,89 @@
/*
* prefixcode.h - Prefix code tree implementation
*
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef PREFIXCODE_H
#define PREFIXCODE_H
#include <stdbool.h>
#include <stdint.h>
#include "bitstream.h"
// Error codes
#define PREFIX_CODE_OK 0
#define PREFIX_CODE_INVALID -1
typedef struct CodeTreeNode
{
int branches[2];
} CodeTreeNode;
typedef struct CodeTableEntry
{
uint32_t length;
int32_t value;
} CodeTableEntry;
// Simple stack implementation for tree building
typedef struct PrefixCodeStack
{
int *data;
int count;
int capacity;
} PrefixCodeStack;
typedef struct PrefixCode
{
CodeTreeNode *tree;
int numentries;
int minlength;
int maxlength;
bool isstatic;
int currnode;
PrefixCodeStack *stack;
int tablesize;
CodeTableEntry *table1;
CodeTableEntry *table2;
} PrefixCode;
// Function declarations
PrefixCode *prefix_code_alloc(void);
PrefixCode *prefix_code_alloc_with_lengths(const int *lengths, int numsymbols, int maxlength, bool shortestCodeIsZeros);
PrefixCode *prefix_code_alloc_with_static_table(int (*statictable)[2]);
void prefix_code_free(PrefixCode *self);
int prefix_code_add_value_high_bit_first(PrefixCode *self, int value, uint32_t code, int length);
int prefix_code_add_value_high_bit_first_repeat(PrefixCode *self, int value, uint32_t code, int length, int repeatpos);
int prefix_code_add_value_low_bit_first(PrefixCode *self, int value, uint32_t code, int length);
int prefix_code_add_value_low_bit_first_repeat(PrefixCode *self, int value, uint32_t code, int length, int repeatpos);
void prefix_code_start_building_tree(PrefixCode *self);
void prefix_code_start_zero_branch(PrefixCode *self);
void prefix_code_start_one_branch(PrefixCode *self);
void prefix_code_finish_branches(PrefixCode *self);
void prefix_code_make_leaf_with_value(PrefixCode *self, int value);
// BitStream interface functions
int prefix_code_read_symbol(BitStream *bs, PrefixCode *code);
int prefix_code_read_symbol_le(BitStream *bs, PrefixCode *code);
#endif /* PREFIXCODE_H */

View File

@@ -1,5 +1,5 @@
if("${CMAKE_C_PLATFORM_ID}" MATCHES "MinGW" OR "${AARU_BUILD_PACKAGE}" MATCHES 1)
return()
return()
endif()
# 'Google_test' is the subproject name
@@ -39,7 +39,42 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/audio.bin
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/data.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/alice29.lzd
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/alice29.lh5
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/arcpack.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/arcsqueeze.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/arccrunchnr.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/arccrunch_dynamic.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/arcsquash.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/pak_crush.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/pak_distill.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/ha_asc.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/ha_hsc.bin
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
# 'Google_Tests_run' is the target name
# 'test1.cpp tests2.cpp' are source files with tests
add_executable(tests_run apple_rle.cpp crc32.c crc32.h adc.cpp bzip2.cpp lzip.cpp lzfse.cpp zstd.cpp lzma.cpp flac.cpp)
add_executable(tests_run apple_rle.cpp crc32.c crc32.h adc.cpp bzip2.cpp lzip.cpp lzfse.cpp zstd.cpp lzma.cpp flac.cpp
zoo/lzd.cpp arc/pack.cpp lh5.cpp arc/squeeze.cpp arc/crunch.cpp arc/squash.cpp pak/crush.cpp
pak/distill.cpp ha.cpp)
target_link_libraries(tests_run gtest gtest_main "Aaru.Compression.Native")

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -20,25 +20,25 @@
#include <cstdint>
#include <cstring>
#include "../adc.h"
#include "../library.h"
#include "../adc.h"
#include "crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0x5a5a7388
static const uint8_t* buffer;
static const uint8_t *buffer;
class adcFixture : public ::testing::Test
{
public:
public:
adcFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
protected:
void SetUp()
{
char path[PATH_MAX];
@@ -47,13 +47,13 @@ class adcFixture : public ::testing::Test
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/adc.bin", path);
FILE* file = fopen(filename, "rb");
buffer = (const uint8_t*)malloc(34367);
fread((void*)buffer, 1, 34367, file);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(34367);
fread((void *)buffer, 1, 34367, file);
fclose(file);
}
void TearDown() { free((void*)buffer); }
void TearDown() { free((void *)buffer); }
~adcFixture()
{
@@ -65,7 +65,7 @@ class adcFixture : public ::testing::Test
TEST_F(adcFixture, adc)
{
auto* outBuf = (uint8_t*)malloc(327680);
auto *outBuf = (uint8_t *)malloc(327680);
auto decoded = AARU_adc_decode_buffer(outBuf, 327680, buffer, 34367);

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -20,25 +20,25 @@
#include <cstdint>
#include <cstring>
#include "../apple_rle.h"
#include "../library.h"
#include "../apple_rle.h"
#include "crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0x3525ef06
static const uint8_t* buffer;
static const uint8_t *buffer;
class apple_rleFixture : public ::testing::Test
{
public:
public:
apple_rleFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
protected:
void SetUp()
{
char path[PATH_MAX];
@@ -47,13 +47,13 @@ class apple_rleFixture : public ::testing::Test
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/apple_rle.bin", path);
FILE* file = fopen(filename, "rb");
buffer = (const uint8_t*)malloc(1102);
fread((void*)buffer, 1, 1102, file);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(1102);
fread((void *)buffer, 1, 1102, file);
fclose(file);
}
void TearDown() { free((void*)buffer); }
void TearDown() { free((void *)buffer); }
~apple_rleFixture()
{
@@ -65,7 +65,7 @@ class apple_rleFixture : public ::testing::Test
TEST_F(apple_rleFixture, apple_rle)
{
auto* outBuf = (uint8_t*)malloc(32768);
auto *outBuf = (uint8_t *)malloc(32768);
auto decoded = AARU_apple_rle_decode_buffer(outBuf, 32768, buffer, 1102);

133
tests/arc/crunch.cpp Normal file
View File

@@ -0,0 +1,133 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <climits>
#include <cstddef>
#include <cstdint>
#include "../../library.h"
#include "../crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0x66007dba
static const uint8_t *buffer;
class crunchFixture : public ::testing::Test
{
public:
crunchFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/arccrunchnr.bin", path);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(72537);
fread((void *)buffer, 1, 72537, file);
fclose(file);
}
void TearDown() { free((void *)buffer); }
~crunchFixture()
{
// resources cleanup, no exceptions allowed
}
// shared user data
};
TEST_F(crunchFixture, crunch)
{
size_t destLen = 152089;
size_t srcLen = 72537;
auto *outBuf = (uint8_t *)malloc(152089);
auto err = arc_decompress_crunch_nrpack(buffer, srcLen, outBuf, &destLen);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}
class crunchDynamicFixture : public ::testing::Test
{
public:
crunchDynamicFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/arccrunch_dynamic.bin", path);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(73189);
fread((void *)buffer, 1, 73189, file);
fclose(file);
}
void TearDown() { free((void *)buffer); }
~crunchDynamicFixture()
{
// resources cleanup, no exceptions allowed
}
// shared user data
};
TEST_F(crunchDynamicFixture, crunchDynamic)
{
size_t destLen = 152089;
size_t srcLen = 73189;
auto *outBuf = (uint8_t *)malloc(152089);
auto err = arc_decompress_crunch_dynamic(buffer, srcLen, outBuf, &destLen);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}

82
tests/arc/pack.cpp Normal file
View File

@@ -0,0 +1,82 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <climits>
#include <cstddef>
#include <cstdint>
#include "../../library.h"
#include "../crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0x66007dba
static const uint8_t *buffer;
class packFixture : public ::testing::Test
{
public:
packFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/arcpack.bin", path);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(149855);
fread((void *)buffer, 1, 149855, file);
fclose(file);
}
void TearDown() { free((void *)buffer); }
~packFixture()
{
// resources cleanup, no exceptions allowed
}
// shared user data
};
TEST_F(packFixture, pack)
{
uint8_t params[] = {0x5D, 0x00, 0x00, 0x00, 0x02};
size_t destLen = 152089;
size_t srcLen = 149855;
auto *outBuf = (uint8_t *)malloc(152089);
auto err = arc_decompress_pack(buffer, srcLen, outBuf, &destLen);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}

81
tests/arc/squash.cpp Normal file
View File

@@ -0,0 +1,81 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <climits>
#include <cstddef>
#include <cstdint>
#include "../../library.h"
#include "../crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0x66007dba
static const uint8_t *buffer;
class squashFixture : public ::testing::Test
{
public:
squashFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/arcsquash.bin", path);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(67308);
fread((void *)buffer, 1, 67308, file);
fclose(file);
}
void TearDown() { free((void *)buffer); }
~squashFixture()
{
// resources cleanup, no exceptions allowed
}
// shared user data
};
TEST_F(squashFixture, squash)
{
size_t destLen = 152089;
size_t srcLen = 67308;
auto *outBuf = (uint8_t *)malloc(152089);
auto err = arc_decompress_squash(buffer, srcLen, outBuf, &destLen);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}

81
tests/arc/squeeze.cpp Normal file
View File

@@ -0,0 +1,81 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <climits>
#include <cstddef>
#include <cstdint>
#include "../../library.h"
#include "../crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0x66007dba
static const uint8_t *buffer;
class squeezeFixture : public ::testing::Test
{
public:
squeezeFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/arcsqueeze.bin", path);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(88044);
fread((void *)buffer, 1, 88044, file);
fclose(file);
}
void TearDown() { free((void *)buffer); }
~squeezeFixture()
{
// resources cleanup, no exceptions allowed
}
// shared user data
};
TEST_F(squeezeFixture, squeeze)
{
size_t destLen = 152089;
size_t srcLen = 88044;
auto *outBuf = (uint8_t *)malloc(152089);
auto err = arc_decompress_squeeze(buffer, srcLen, outBuf, &destLen);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -26,18 +26,18 @@
#define EXPECTED_CRC32 0xc64059c0
static const uint8_t* buffer;
static const uint8_t *buffer;
class bzip2Fixture : public ::testing::Test
{
public:
public:
bzip2Fixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
protected:
void SetUp()
{
char path[PATH_MAX];
@@ -46,13 +46,13 @@ class bzip2Fixture : public ::testing::Test
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/bzip2.bz2", path);
FILE* file = fopen(filename, "rb");
buffer = (const uint8_t*)malloc(1053934);
fread((void*)buffer, 1, 1053934, file);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(1053934);
fread((void *)buffer, 1, 1053934, file);
fclose(file);
}
void TearDown() { free((void*)buffer); }
void TearDown() { free((void *)buffer); }
~bzip2Fixture()
{
@@ -65,7 +65,7 @@ class bzip2Fixture : public ::testing::Test
TEST_F(bzip2Fixture, bzip2)
{
uint real_size = 1048576;
auto* outBuf = (uint8_t*)malloc(1048576);
auto *outBuf = (uint8_t *)malloc(1048576);
auto bz_err = AARU_bzip2_decode_buffer(outBuf, &real_size, buffer, 1053934);
@@ -87,24 +87,24 @@ TEST_F(bzip2Fixture, bzip2Compress)
uint decmp_len = original_len;
char path[PATH_MAX];
char filename[PATH_MAX * 2];
FILE* file;
FILE *file;
uint32_t original_crc, decmp_crc;
int bz_err;
const uint8_t* original;
uint8_t* cmp_buffer;
uint8_t* decmp_buffer;
const uint8_t *original;
uint8_t *cmp_buffer;
uint8_t *decmp_buffer;
// Allocate buffers
original = (const uint8_t*)malloc(original_len);
cmp_buffer = (uint8_t*)malloc(cmp_len);
decmp_buffer = (uint8_t*)malloc(decmp_len);
original = (const uint8_t *)malloc(original_len);
cmp_buffer = (uint8_t *)malloc(cmp_len);
decmp_buffer = (uint8_t *)malloc(decmp_len);
// Read the file
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/data.bin", path);
file = fopen(filename, "rb");
fread((void*)original, 1, original_len, file);
fread((void *)original, 1, original_len, file);
fclose(file);
// Calculate the CRC
@@ -125,7 +125,7 @@ TEST_F(bzip2Fixture, bzip2Compress)
decmp_crc = crc32_data(decmp_buffer, decmp_len);
// Free buffers
free((void*)original);
free((void *)original);
free(cmp_buffer);
free(decmp_buffer);

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -19,37 +19,38 @@
extern "C"
{
#endif
#include <stdint.h>
#define CRC32_ISO_POLY 0xEDB88320
#define CRC32_ISO_SEED 0xFFFFFFFF
uint32_t crc32_data(const uint8_t *data, uint32_t len)
{
uint32_t localHashInt = CRC32_ISO_SEED;
uint32_t localTable[256];
int i, j;
for(i = 0; i < 256; i++)
uint32_t crc32_data(const uint8_t *data, uint32_t len)
{
uint32_t entry = (uint32_t)i;
uint32_t localHashInt = CRC32_ISO_SEED;
uint32_t localTable[256];
int i, j;
for(j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ CRC32_ISO_POLY;
else
entry >>= 1;
for(i = 0; i < 256; i++)
{
uint32_t entry = (uint32_t)i;
localTable[i] = entry;
for(j = 0; j < 8; j++)
if((entry & 1) == 1)
entry = (entry >> 1) ^ CRC32_ISO_POLY;
else
entry >>= 1;
localTable[i] = entry;
}
for(i = 0; i < len; i++) localHashInt = (localHashInt >> 8) ^ localTable[data[i] ^ (localHashInt & 0xff)];
localHashInt ^= CRC32_ISO_SEED;
return localHashInt;
}
for(i = 0; i < len; i++)
localHashInt = (localHashInt >> 8) ^ localTable[data[i] ^ (localHashInt & 0xff)];
localHashInt ^= CRC32_ISO_SEED;
return localHashInt;
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -23,8 +23,9 @@ extern "C"
{
#endif
uint32_t crc32_data(const uint8_t* data, uint32_t len);
uint32_t crc32_data(const uint8_t *data, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif // AARU_CHECKSUMS_NATIVE_TESTS_CRC32_H_
#endif // AARU_CHECKSUMS_NATIVE_TESTS_CRC32_H_

BIN
tests/data/alice29.lh5 Normal file

Binary file not shown.

BIN
tests/data/alice29.lzd Normal file

Binary file not shown.

BIN
tests/data/amg.bin Executable file

Binary file not shown.

BIN
tests/data/arccrunch_dynamic.bin Executable file

Binary file not shown.

BIN
tests/data/arccrunchnr.bin Executable file

Binary file not shown.

3628
tests/data/arcpack.bin Executable file

File diff suppressed because it is too large Load Diff

BIN
tests/data/arcsquash.bin Executable file

Binary file not shown.

BIN
tests/data/arcsqueeze.bin Executable file

Binary file not shown.

BIN
tests/data/pak_crush.bin Normal file

Binary file not shown.

BIN
tests/data/pak_distill.bin Normal file

Binary file not shown.

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -20,25 +20,25 @@
#include <cstddef>
#include <cstdint>
#include "../flac.h"
#include "../library.h"
#include "../flac.h"
#include "crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0xdfbc99bb
static const uint8_t* buffer;
static const uint8_t *buffer;
class flacFixture : public ::testing::Test
{
public:
public:
flacFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
protected:
void SetUp()
{
char path[PATH_MAX];
@@ -47,13 +47,13 @@ class flacFixture : public ::testing::Test
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/flac.flac", path);
FILE* file = fopen(filename, "rb");
buffer = (const uint8_t*)malloc(6534197);
fread((void*)buffer, 1, 6534197, file);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(6534197);
fread((void *)buffer, 1, 6534197, file);
fclose(file);
}
void TearDown() { free((void*)buffer); }
void TearDown() { free((void *)buffer); }
~flacFixture()
{
@@ -65,7 +65,7 @@ class flacFixture : public ::testing::Test
TEST_F(flacFixture, flac)
{
auto* outBuf = (uint8_t*)malloc(9633792);
auto *outBuf = (uint8_t *)malloc(9633792);
auto decoded = AARU_flac_decode_redbook_buffer(outBuf, 9633792, buffer, 6534197);
@@ -85,46 +85,33 @@ TEST_F(flacFixture, flacCompress)
uint decmp_len = original_len;
char path[PATH_MAX];
char filename[PATH_MAX * 2];
FILE* file;
FILE *file;
uint32_t original_crc, decmp_crc;
const uint8_t* original;
uint8_t* cmp_buffer;
uint8_t* decmp_buffer;
const uint8_t *original;
uint8_t *cmp_buffer;
uint8_t *decmp_buffer;
size_t newSize;
// Allocate buffers
original = (const uint8_t*)malloc(original_len);
cmp_buffer = (uint8_t*)malloc(cmp_len);
decmp_buffer = (uint8_t*)malloc(decmp_len);
original = (const uint8_t *)malloc(original_len);
cmp_buffer = (uint8_t *)malloc(cmp_len);
decmp_buffer = (uint8_t *)malloc(decmp_len);
// Read the file
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/audio.bin", path);
file = fopen(filename, "rb");
fread((void*)original, 1, original_len, file);
fread((void *)original, 1, original_len, file);
fclose(file);
// Calculate the CRC
original_crc = crc32_data(original, original_len);
// Compress
newSize = AARU_flac_encode_redbook_buffer(cmp_buffer,
cmp_len,
original,
original_len,
4608,
1,
0,
"partial_tukey(0/1.0/1.0)",
12,
0,
1,
false,
0,
8,
"Aaru.Compression.Native.Tests",
strlen("Aaru.Compression.Native.Tests"));
newSize = AARU_flac_encode_redbook_buffer(cmp_buffer, cmp_len, original, original_len, 4608, 1, 0,
"partial_tukey(0/1.0/1.0)", 12, 0, 1, false, 0, 8,
"Aaru.Compression.Native.Tests", strlen("Aaru.Compression.Native.Tests"));
cmp_len = newSize;
// Decompress
@@ -136,7 +123,7 @@ TEST_F(flacFixture, flacCompress)
decmp_crc = crc32_data(decmp_buffer, decmp_len);
// Free buffers
free((void*)original);
free((void *)original);
free(cmp_buffer);
free(decmp_buffer);

133
tests/ha.cpp Normal file
View File

@@ -0,0 +1,133 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <climits>
#include <cstddef>
#include <cstdint>
#include "../library.h"
#include "crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0x66007dba
static const uint8_t *buffer;
class ha_ascFixture : public ::testing::Test
{
public:
ha_ascFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/ha_asc.bin", path);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(53654);
fread((void *)buffer, 1, 53654, file);
fclose(file);
}
void TearDown() { free((void *)buffer); }
~ha_ascFixture()
{
// resources cleanup, no exceptions allowed
}
// shared user data
};
TEST_F(ha_ascFixture, ha_asc)
{
size_t destLen = 152089;
size_t srcLen = 53654;
auto * outBuf = (uint8_t *)malloc(53654);
auto err = ha_asc_decompress(buffer, srcLen, outBuf, &destLen);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}
class ha_hscFixture : public ::testing::Test
{
public:
ha_hscFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/ha_hsc.bin", path);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(41839);
fread((void *)buffer, 1, 41839, file);
fclose(file);
}
void TearDown() { free((void *)buffer); }
~ha_hscFixture()
{
// resources cleanup, no exceptions allowed
}
// shared user data
};
TEST_F(ha_hscFixture, ha_hsc)
{
size_t destLen = 152089;
size_t srcLen = 41839;
auto * outBuf = (uint8_t *)malloc(152089);
auto err = ha_hsc_decompress(buffer, srcLen, outBuf, &destLen);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}

84
tests/lh5.cpp Normal file
View File

@@ -0,0 +1,84 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "../zoo/lh5.h"
#include <climits>
#include <cstddef>
#include <cstdint>
#include "../library.h"
#include "crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0x66007dba
static const uint8_t *buffer;
class lh5Fixture : public ::testing::Test
{
public:
lh5Fixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/alice29.lh5", path);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(59104);
fread((void *)buffer, 1, 59104, file);
fclose(file);
}
void TearDown() { free((void *)buffer); }
~lh5Fixture()
{
// resources cleanup, no exceptions allowed
}
// shared user data
};
TEST_F(lh5Fixture, lh5)
{
uint8_t params[] = {0x5D, 0x00, 0x00, 0x00, 0x02};
size_t destLen = 152089;
size_t srcLen = 59104;
auto *outBuf = (uint8_t *)malloc(152089);
auto err = lh5_decompress(buffer, srcLen, outBuf, &destLen);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -26,18 +26,18 @@
#define EXPECTED_CRC32 0xc64059c0
static const uint8_t* buffer;
static const uint8_t *buffer;
class lzfseFixture : public ::testing::Test
{
public:
public:
lzfseFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
protected:
void SetUp()
{
char path[PATH_MAX];
@@ -46,13 +46,13 @@ class lzfseFixture : public ::testing::Test
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/lzfse.bin", path);
FILE* file = fopen(filename, "rb");
buffer = (const uint8_t*)malloc(1059299);
fread((void*)buffer, 1, 1059299, file);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(1059299);
fread((void *)buffer, 1, 1059299, file);
fclose(file);
}
void TearDown() { free((void*)buffer); }
void TearDown() { free((void *)buffer); }
~lzfseFixture()
{
@@ -64,7 +64,7 @@ class lzfseFixture : public ::testing::Test
TEST_F(lzfseFixture, lzfse)
{
auto* outBuf = (uint8_t*)malloc(1048576);
auto *outBuf = (uint8_t *)malloc(1048576);
auto decoded = AARU_lzfse_decode_buffer(outBuf, 1048576, buffer, 1059299, nullptr);
@@ -84,24 +84,24 @@ TEST_F(lzfseFixture, lzfseCompress)
uint decmp_len = original_len;
char path[PATH_MAX];
char filename[PATH_MAX * 2];
FILE* file;
FILE *file;
uint32_t original_crc, decmp_crc;
const uint8_t* original;
uint8_t* cmp_buffer;
uint8_t* decmp_buffer;
const uint8_t *original;
uint8_t *cmp_buffer;
uint8_t *decmp_buffer;
size_t newSize;
// Allocate buffers
original = (const uint8_t*)malloc(original_len);
cmp_buffer = (uint8_t*)malloc(cmp_len);
decmp_buffer = (uint8_t*)malloc(decmp_len);
original = (const uint8_t *)malloc(original_len);
cmp_buffer = (uint8_t *)malloc(cmp_len);
decmp_buffer = (uint8_t *)malloc(decmp_len);
// Read the file
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/data.bin", path);
file = fopen(filename, "rb");
fread((void*)original, 1, original_len, file);
fread((void *)original, 1, original_len, file);
fclose(file);
// Calculate the CRC
@@ -120,7 +120,7 @@ TEST_F(lzfseFixture, lzfseCompress)
decmp_crc = crc32_data(decmp_buffer, decmp_len);
// Free buffers
free((void*)original);
free((void *)original);
free(cmp_buffer);
free(decmp_buffer);

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -26,18 +26,18 @@
#define EXPECTED_CRC32 0xc64059c0
static const uint8_t* buffer;
static const uint8_t *buffer;
class lzipFixture : public ::testing::Test
{
public:
public:
lzipFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
protected:
void SetUp()
{
char path[PATH_MAX];
@@ -46,13 +46,13 @@ class lzipFixture : public ::testing::Test
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/lzip.lz", path);
FILE* file = fopen(filename, "rb");
buffer = (const uint8_t*)malloc(1062874);
fread((void*)buffer, 1, 1062874, file);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(1062874);
fread((void *)buffer, 1, 1062874, file);
fclose(file);
}
void TearDown() { free((void*)buffer); }
void TearDown() { free((void *)buffer); }
~lzipFixture()
{
@@ -64,7 +64,7 @@ class lzipFixture : public ::testing::Test
TEST_F(lzipFixture, lzip)
{
auto* outBuf = (uint8_t*)malloc(1048576);
auto *outBuf = (uint8_t *)malloc(1048576);
auto decoded = AARU_lzip_decode_buffer(outBuf, 1048576, buffer, 1062874);
@@ -84,24 +84,24 @@ TEST_F(lzipFixture, lzipCompress)
int32_t decmp_len = original_len;
char path[PATH_MAX];
char filename[PATH_MAX * 2];
FILE* file;
FILE *file;
uint32_t original_crc, decmp_crc;
const uint8_t* original;
uint8_t* cmp_buffer;
uint8_t* decmp_buffer;
const uint8_t *original;
uint8_t *cmp_buffer;
uint8_t *decmp_buffer;
int32_t newSize;
// Allocate buffers
original = (const uint8_t*)malloc(original_len);
cmp_buffer = (uint8_t*)malloc(cmp_len);
decmp_buffer = (uint8_t*)malloc(decmp_len);
original = (const uint8_t *)malloc(original_len);
cmp_buffer = (uint8_t *)malloc(cmp_len);
decmp_buffer = (uint8_t *)malloc(decmp_len);
// Read the file
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/data.bin", path);
file = fopen(filename, "rb");
fread((void*)original, 1, original_len, file);
fread((void *)original, 1, original_len, file);
fclose(file);
// Calculate the CRC
@@ -120,7 +120,7 @@ TEST_F(lzipFixture, lzipCompress)
decmp_crc = crc32_data(decmp_buffer, decmp_len);
// Free buffers
free((void*)original);
free((void *)original);
free(cmp_buffer);
free(decmp_buffer);

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -26,18 +26,18 @@
#define EXPECTED_CRC32 0x954bf76e
static const uint8_t* buffer;
static const uint8_t *buffer;
class lzmaFixture : public ::testing::Test
{
public:
public:
lzmaFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
protected:
void SetUp()
{
char path[PATH_MAX];
@@ -46,13 +46,13 @@ class lzmaFixture : public ::testing::Test
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/lzma.bin", path);
FILE* file = fopen(filename, "rb");
buffer = (const uint8_t*)malloc(1200275);
fread((void*)buffer, 1, 1200275, file);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(1200275);
fread((void *)buffer, 1, 1200275, file);
fclose(file);
}
void TearDown() { free((void*)buffer); }
void TearDown() { free((void *)buffer); }
~lzmaFixture()
{
@@ -67,7 +67,7 @@ TEST_F(lzmaFixture, lzma)
uint8_t params[] = {0x5D, 0x00, 0x00, 0x00, 0x02};
size_t destLen = 8388608;
size_t srcLen = 1200275;
auto* outBuf = (uint8_t*)malloc(8388608);
auto *outBuf = (uint8_t *)malloc(8388608);
auto err = AARU_lzma_decode_buffer(outBuf, &destLen, buffer, &srcLen, params, 5);
@@ -88,34 +88,34 @@ TEST_F(lzmaFixture, lzmaCompress)
size_t decmp_len = original_len;
char path[PATH_MAX];
char filename[PATH_MAX * 2];
FILE* file;
FILE *file;
uint32_t original_crc, decmp_crc;
const uint8_t* original;
uint8_t* cmp_buffer;
uint8_t* decmp_buffer;
const uint8_t *original;
uint8_t *cmp_buffer;
uint8_t *decmp_buffer;
int err;
uint8_t props[5];
size_t props_len = 5;
// Allocate buffers
original = (const uint8_t*)malloc(original_len);
cmp_buffer = (uint8_t*)malloc(cmp_len);
decmp_buffer = (uint8_t*)malloc(decmp_len);
original = (const uint8_t *)malloc(original_len);
cmp_buffer = (uint8_t *)malloc(cmp_len);
decmp_buffer = (uint8_t *)malloc(decmp_len);
// Read the file
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/data.bin", path);
file = fopen(filename, "rb");
fread((void*)original, 1, original_len, file);
fread((void *)original, 1, original_len, file);
fclose(file);
// Calculate the CRC
original_crc = crc32_data(original, original_len);
// Compress
err = AARU_lzma_encode_buffer(
cmp_buffer, &cmp_len, original, original_len, props, &props_len, 9, 1048576, 3, 0, 2, 273, 2);
err = AARU_lzma_encode_buffer(cmp_buffer, &cmp_len, original, original_len, props, &props_len, 9, 1048576, 3, 0, 2,
273, 2);
EXPECT_EQ(err, 0);
// Decompress
@@ -127,7 +127,7 @@ TEST_F(lzmaFixture, lzmaCompress)
decmp_crc = crc32_data(decmp_buffer, decmp_len);
// Free buffers
free((void*)original);
free((void *)original);
free(cmp_buffer);
free(decmp_buffer);

81
tests/pak/crush.cpp Normal file
View File

@@ -0,0 +1,81 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <climits>
#include <cstddef>
#include <cstdint>
#include "../../library.h"
#include "../crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0x66007dba
static const uint8_t *buffer;
class crushFixture : public ::testing::Test
{
public:
crushFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/pak_crush.bin", path);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(63282);
fread((void *)buffer, 1, 63282, file);
fclose(file);
}
void TearDown() { free((void *)buffer); }
~crushFixture()
{
// resources cleanup, no exceptions allowed
}
// shared user data
};
TEST_F(crushFixture, crush)
{
size_t destLen = 152089;
size_t srcLen = 63282;
auto *outBuf = (uint8_t *)malloc(152089);
auto err = pak_decompress_crush(buffer, srcLen, outBuf, &destLen);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}

81
tests/pak/distill.cpp Normal file
View File

@@ -0,0 +1,81 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <climits>
#include <cstddef>
#include <cstdint>
#include "../../library.h"
#include "../crc32.h"
#include "gtest/gtest.h"
#define EXPECTED_CRC32 0x66007dba
static const uint8_t *buffer;
class distillFixture : public ::testing::Test
{
public:
distillFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
void SetUp()
{
char path[PATH_MAX];
char filename[PATH_MAX];
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/pak_distill.bin", path);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(60540);
fread((void *)buffer, 1, 60540, file);
fclose(file);
}
void TearDown() { free((void *)buffer); }
~distillFixture()
{
// resources cleanup, no exceptions allowed
}
// shared user data
};
TEST_F(distillFixture, distill)
{
size_t destLen = 152089;
size_t srcLen = 60540;
auto *outBuf = (uint8_t *)malloc(152089);
auto err = pak_decompress_distill(buffer, srcLen, outBuf, &destLen);
EXPECT_EQ(err, 0);
EXPECT_EQ(destLen, 152089);
auto crc = crc32_data(outBuf, 152089);
free(outBuf);
EXPECT_EQ(crc, EXPECTED_CRC32);
}

182
tests/zoo/lzd.cpp Normal file
View File

@@ -0,0 +1,182 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <climits>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/stat.h>
#include <unistd.h>
#include "../../library.h"
#include "../crc32.h"
#include "gtest/gtest.h"
#define OUTPUT_CHUNK 8192
#define EXPECTED_SIZE 152089
#define EXPECTED_CRC32_VAL 0x66007dba
static long long filesize_of(const char* path)
{
struct stat st;
if(stat(path, &st) == 0) return (long long)st.st_size;
return -1;
}
class lzdFixture : public ::testing::Test
{
protected:
void SetUp() override
{
char cwd[PATH_MAX];
char filename[PATH_MAX];
getcwd(cwd, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/alice29.lzd", cwd);
inFile = fopen(filename, "rb");
ASSERT_NE(inFile, nullptr) << "Failed to open input file";
fileSize = filesize_of(filename);
}
void TearDown() override
{
if(inFile) fclose(inFile);
}
FILE* inFile = nullptr;
long long fileSize = 0;
};
typedef enum {
LZD_OK = 0,
LZD_NEED_INPUT = 1,
LZD_NEED_OUTPUT = 2,
LZD_DONE = 3
} LZDStatus;
TEST_F(lzdFixture, ZooMethod1)
{
unsigned char inbuf[OUTPUT_CHUNK];
unsigned char outbuf[OUTPUT_CHUNK];
bool flushed = false;
bool eof = false;
size_t total_out = 0;
size_t total_in = 0;
size_t iter = 0;
fprintf(stderr, "INPUT FILE SIZE=%lld bytes\n", fileSize);
void* ctx = CreateLZDContext();
ASSERT_NE(ctx, nullptr) << "Failed to create LZD context";
// allocate buffer for full output to CRC at the end
uint8_t* full_out = (uint8_t*)malloc(EXPECTED_SIZE);
ASSERT_NE(full_out, nullptr);
size_t full_offset = 0;
while(!eof)
{
size_t nread = fread(inbuf, 1, sizeof inbuf, inFile);
if(nread == 0)
{
fprintf(stderr, "[FEED] size=0 flushed=0 (final empty feed)\n");
LZD_FeedNative(ctx, nullptr, 0);
flushed = true;
}
else
{
total_in += nread;
fprintf(stderr, "[FEED] size=%zu flushed=0 (real data) total_in=%zu\n",
nread, total_in);
LZD_FeedNative(ctx, inbuf, nread);
}
size_t produced = 0;
int st = LZD_OK;
do
{
produced = 0;
st = LZD_DrainNative(ctx, outbuf, sizeof outbuf, &produced);
fprintf(stderr, "-- LOOP iter=%zu total_out=%zu --\n", iter++, total_out);
fprintf(stderr, "[DRAIN] produced=%zu status=%d flushed=%d eof=%d\n",
produced, st, flushed ? 1 : 0, eof ? 1 : 0);
if(produced > 0)
{
memcpy(full_out + full_offset, outbuf, produced);
full_offset += produced;
total_out += produced;
}
if(st == LZD_DONE)
{
fprintf(stderr, ">>> SET eof=1 (DONE from decoder)\n");
eof = true;
}
} while(produced > 0);
if(flushed)
{
for(int spins = 0; spins < 8 && !eof; spins++)
{
size_t more = 0;
int st2 = LZD_DrainNative(ctx, outbuf, sizeof outbuf, &more);
fprintf(stderr, "-- LOOP iter=%zu total_out=%zu --\n", iter++, total_out);
fprintf(stderr, "[DRAIN] produced=%zu status=%d flushed=1 eof=%d\n",
more, st2, eof ? 1 : 0);
if(more > 0)
{
memcpy(full_out + full_offset, outbuf, more);
full_offset += more;
total_out += more;
}
else if(st2 == LZD_DONE)
{
fprintf(stderr, ">>> SET eof=1 (DONE after flush)\n");
eof = true;
}
else
{
break;
}
}
if(!eof)
{
fprintf(stderr, ">>> SET eof=1 (no more data and already flushed)\n");
eof = true;
}
}
}
fprintf(stderr, "\nTOTAL IN=%zu bytes\n", total_in);
fprintf(stderr, "TOTAL OUT=%zu bytes\n", total_out);
DestroyLZDContext(ctx);
// Now verify the decompressed size and CRC
EXPECT_EQ(total_out, static_cast<size_t>(EXPECTED_SIZE));
uint32_t crc = crc32_data(full_out, total_out);
free(full_out);
EXPECT_EQ(crc, static_cast<uint32_t>(EXPECTED_CRC32_VAL));
EXPECT_EQ(total_in, static_cast<size_t>(fileSize));
}

View File

@@ -1,6 +1,6 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2023 Natalia Portillo.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -26,18 +26,18 @@
#define EXPECTED_CRC32 0xc64059c0
static const uint8_t* buffer;
static const uint8_t *buffer;
class zstdFixture : public ::testing::Test
{
public:
public:
zstdFixture()
{
// initialization;
// can also be done in SetUp()
}
protected:
protected:
void SetUp()
{
char path[PATH_MAX];
@@ -46,13 +46,13 @@ class zstdFixture : public ::testing::Test
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/zstd.zst", path);
FILE* file = fopen(filename, "rb");
buffer = (const uint8_t*)malloc(1048613);
fread((void*)buffer, 1, 1048613, file);
FILE *file = fopen(filename, "rb");
buffer = (const uint8_t *)malloc(1048613);
fread((void *)buffer, 1, 1048613, file);
fclose(file);
}
void TearDown() { free((void*)buffer); }
void TearDown() { free((void *)buffer); }
~zstdFixture()
{
@@ -64,7 +64,7 @@ class zstdFixture : public ::testing::Test
TEST_F(zstdFixture, zstd)
{
auto* outBuf = (uint8_t*)malloc(1048576);
auto *outBuf = (uint8_t *)malloc(1048576);
auto decoded = AARU_zstd_decode_buffer(outBuf, 1048576, buffer, 1048613);
@@ -84,24 +84,24 @@ TEST_F(zstdFixture, zstdCompress)
uint decmp_len = original_len;
char path[PATH_MAX];
char filename[PATH_MAX * 2];
FILE* file;
FILE *file;
uint32_t original_crc, decmp_crc;
const uint8_t* original;
uint8_t* cmp_buffer;
uint8_t* decmp_buffer;
const uint8_t *original;
uint8_t *cmp_buffer;
uint8_t *decmp_buffer;
size_t newSize;
// Allocate buffers
original = (const uint8_t*)malloc(original_len);
cmp_buffer = (uint8_t*)malloc(cmp_len);
decmp_buffer = (uint8_t*)malloc(decmp_len);
original = (const uint8_t *)malloc(original_len);
cmp_buffer = (uint8_t *)malloc(cmp_len);
decmp_buffer = (uint8_t *)malloc(decmp_len);
// Read the file
getcwd(path, PATH_MAX);
snprintf(filename, PATH_MAX, "%s/data/data.bin", path);
file = fopen(filename, "rb");
fread((void*)original, 1, original_len, file);
fread((void *)original, 1, original_len, file);
fclose(file);
// Calculate the CRC
@@ -120,7 +120,7 @@ TEST_F(zstdFixture, zstdCompress)
decmp_crc = crc32_data(decmp_buffer, decmp_len);
// Free buffers
free((void*)original);
free((void *)original);
free(cmp_buffer);
free(decmp_buffer);

40
zoo/ar.h Normal file
View File

@@ -0,0 +1,40 @@
/*$Source: /usr/home/dhesi/zoo/RCS/ar.h,v $*/
/*$Id: ar.h,v 1.17 91/07/09 01:39:50 dhesi Exp $*/
/***********************************************************
ar.h
Adapted from "ar" archiver written by Haruhiko Okumura.
***********************************************************/
// Modified for in-memory decompression by Natalia Portillo, 2025
#include <stdint.h>
#include <stdio.h>
/* all the prototypes follow here for all files */
/* DECODE.C */
void decode_start();
int decode(uint32_t count, uint8_t *buffer);
/* HUF.C */
void output(uint32_t c, uint32_t p);
uint32_t decode_c(void);
uint32_t decode_p(void);
void huf_decode_start(void);
/* IO.C */
void fillbuf(int n);
uint32_t getbits(int n);
void putbits(int n, uint32_t x);
void init_getbits(void);
void init_putbits(void);
/* MAKETBL.C */
void make_table(int nchar, uint8_t bitlen[], int tablebits, uint16_t table[]);
/* MAKETREE.C */
int make_tree(int nparm, uint16_t freqparm[], uint8_t lenparm[], uint16_t codeparm[]);
/* for lzh modules and also for ar.c to use in defining buffer size */
#define DICBIT 13 /* 12(-lh4-) or 13(-lh5-) */
#define DICSIZ ((unsigned)1 << DICBIT)

104
zoo/decode.c Normal file
View File

@@ -0,0 +1,104 @@
/*$Source: /usr/home/dhesi/zoo/RCS/decode.c,v $*/
/*$Id: decode.c,v 1.6 91/07/09 01:39:49 dhesi Exp $*/
/***********************************************************
decode.c
Adapted from Haruhiko Okumuras “ar” archiver. This
version has been modified in 2025 by Natalia Portillo
for in-memory decompression.
***********************************************************/
#include <limits.h> // for UCHAR_MAX
#include <stdint.h> // for fixed-width integer types
#include "ar.h" // archive format constants
#include "lzh.h" // LZH-specific constants (DICSIZ, THRESHOLD, etc.)
extern int decoded; // flag set by decode_c() when end-of-stream is reached
static int j; // number of literal/copy runs remaining from a match
/*
* decode_start()
*
* Prepare the decoder for a new file:
* - Initialize the Huffman bitstream (via huf_decode_start())
* - Reset the sliding-window copy counter `j`
* - Clear the end-of-data flag `decoded`
*/
void decode_start()
{
huf_decode_start(); // reset bit-reader state
j = 0; // no pending copy runs yet
decoded = 0; // not yet at end-of-stream
}
/*
* decode(count, buffer)
*
* Decode up to `count` bytes (usually DICSIZ) into `buffer[]`.
* Returns the actual number of bytes written, or 0 if `decoded` is set.
*
* Slidingwindow logic:
* 1. If `j` > 0, we are in the middle of copying a previous match:
* - Copy one byte from `buffer[i]` into `buffer[r]`
* - Advance `i` (circular within DICSIZ) and `r`
* - Decrement `j` and repeat until `j` = 0 or `r` = count
* 2. Otherwise, fetch the next symbol `c = decode_c()`:
* - If `c <= UCHAR_MAX`, its a literal byte: emit it directly
* - Else its a match:
* • compute `j = match_length = c - (UCHAR_MAX + 1 - THRESHOLD)`
* • compute `i = (r - match_offset - 1) mod DICSIZ`,
* where match_offset = decode_p()
* • enter copy loop from step 1
*/
int decode(uint32_t count, uint8_t *buffer)
{
static uint32_t i; // sliding-window read index (circular)
uint32_t r; // write position in buffer
uint32_t c; // symbol or match code
r = 0;
// Step 1: finish any pending copy from a previous match
while(--j >= 0)
{
buffer[r] = buffer[i]; // copy one byte from history
i = (i + 1) & (DICSIZ - 1); // wrap index within [0, DICSIZ)
if(++r == count) // if output buffer is full
return r; // return bytes written so far
}
// Step 2: decode new symbols until end-of-stream or buffer full
for(;;)
{
c = decode_c(); // get next Huffman symbol
if(decoded) // end-of-stream marker reached
return r; // no more bytes to decode
if(c <= UCHAR_MAX)
{
// Literal byte: emit it directly
buffer[r] = (uint8_t)c;
if(++r == count) return r;
}
else
{
// Match sequence: compute how many bytes to copy
// j = match length
j = c - (UCHAR_MAX + 1 - THRESHOLD);
// i = start position in sliding window:
// current output position minus offset minus 1, wrapped
i = (r - decode_p() - 1) & (DICSIZ - 1);
// Copy `j` bytes from history
while(--j >= 0)
{
buffer[r] = buffer[i];
i = (i + 1) & (DICSIZ - 1);
if(++r == count) return r;
}
}
}
}

244
zoo/huf.c Normal file
View File

@@ -0,0 +1,244 @@
/*$Source: /usr/home/dhesi/zoo/RCS/huf.c,v $*/
/*$Id: huf.c,v 1.9 91/07/09 01:39:55 dhesi Exp $*/
/***********************************************************
huf.c -- static Huffman decoding
Adapted from Haruhiko Okumuras “ar” archiver.
Modified in 2025 by Natalia Portillo for in-memory I/O.
***********************************************************/
#include <limits.h> // UCHAR_MAX
#include "ar.h" // archive format constants
#include "lzh.h" // LZH algorithm constants (NC, DICBIT, CODE_BIT, etc.)
// NP = number of position codes = DICBIT+1
// NT = number of tree codes = CODE_BIT+3
// PBIT, TBIT = bitwidth to transmit NP/NT in header
#define NP (DICBIT + 1)
#define NT (CODE_BIT + 3)
#define PBIT 4 /* smallest bits so (1<<PBIT)>NP */
#define TBIT 5 /* smallest bits so (1<<TBIT)>NT */
// NPT = max(NP,NT) for prefixtree lengths
#if NT > NP
#define NPT NT
#else
#define NPT NP
#endif
// forward declarations of helper routines
static void read_pt_len(int nn, int nbit, int i_special);
static void read_c_len(void);
int decoded; // flag set when end-of-stream block is seen
// Huffman tree storage arrays
// left[]/right[] store the binary tree structure for fast decoding
uint16_t left[2 * NC - 1], right[2 * NC - 1];
// c_len[] = code lengths for literal/length tree (NC symbols)
// pt_len[] = code lengths for positiontree / prefix table (NPT symbols)
// buf = temporary buffer pointer used during encoding; unused in decode
static uint8_t *buf, c_len[NC], pt_len[NPT];
// size of buf if used, and remaining symbols in current block
static uint32_t bufsiz = 0, blocksize;
// Frequency, code and decodetable structures
static uint16_t c_freq[2 * NC - 1], // literal/length frequency counts
c_table[4096], // fastlookup table for literal/length decoding
c_code[NC], // canonical Huffman codes for literals
p_freq[2 * NP - 1], // position frequency counts
pt_table[256], // prefixtree fast lookup (for reading code lengths)
pt_code[NPT], // canonical codes for prefixtree
t_freq[2 * NT - 1]; // temporary freq for tree of codelength codes
/***** decoding helper: read prefixtree code-lengths *****/
static void read_pt_len(int nn, int nbit, int i_special)
{
int i, c, n;
uint32_t mask;
// 1) read how many codelengths to consume
n = getbits(nbit);
if(n == 0)
{
// special case: all codelengths are identical
c = getbits(nbit);
for(i = 0; i < nn; i++) // zero out lengths
pt_len[i] = 0;
for(i = 0; i < 256; i++) // prefixtable always returns 'c'
pt_table[i] = c;
}
else
{
// 2) read code lengths one by one
i = 0;
while(i < n)
{
// peek top 3 bits of bitbuf to guess small lengths
c = bitbuf >> (BITBUFSIZ - 3);
if(c == 7)
{
// if all three bits are 1, count additional ones
mask = 1U << (BITBUFSIZ - 1 - 3);
while(mask & bitbuf)
{
c++;
mask >>= 1;
}
}
// consume the actual length bits
fillbuf((c < 7) ? 3 : (c - 3));
pt_len[i++] = c;
// at special index, read a small run of zeros
if(i == i_special)
{
c = getbits(2);
while(--c >= 0 && i < nn) pt_len[i++] = 0;
}
}
// any remaining symbols get codelength zero
while(i < nn) pt_len[i++] = 0;
// build fast lookup table from lengths
make_table(nn, pt_len, 8, pt_table);
}
}
/***** decoding helper: read literal/length codelengths *****/
static void read_c_len(void)
{
int i, c, n;
uint32_t mask;
// 1) how many literal codes?
n = getbits(CBIT);
if(n == 0)
{
// all codelengths identical
c = getbits(CBIT);
for(i = 0; i < NC; i++) c_len[i] = 0;
for(i = 0; i < 4096; i++) c_table[i] = c;
}
else
{
// 2) read each code length via prefixtree
i = 0;
while(i < n)
{
// lookup next symbol in prefixtable
c = pt_table[bitbuf >> (BITBUFSIZ - 8)];
if(c >= NT)
{
// if prefix code is non-leaf, walk tree
mask = 1U << (BITBUFSIZ - 1 - 8);
do {
c = (bitbuf & mask) ? right[c] : left[c];
mask >>= 1;
} while(c >= NT);
}
// consume codelength bits
fillbuf(pt_len[c]);
// c ≤ 2: run-length encoding of zeros
if(c <= 2)
{
if(c == 0)
c = 1;
else if(c == 1)
c = getbits(4) + 3;
else
c = getbits(CBIT) + 20;
while(--c >= 0 && i < NC) c_len[i++] = 0;
}
else
{
// real code-length = c2
c_len[i++] = (uint8_t)(c - 2);
}
}
// fill rest with zero lengths
while(i < NC) c_len[i++] = 0;
// build fast lookup for literal/length codes
make_table(NC, c_len, 12, c_table);
}
}
/***** decode next literal/length symbol or end-of-block *****/
uint32_t decode_c(void)
{
uint32_t j, mask;
// if starting a new block, read its header
if(blocksize == 0)
{
blocksize = getbits(16); // block size = number of symbols
if(blocksize == 0)
{ // zero block → end of data
decoded = 1;
return 0;
}
// read three Huffman trees for this block:
// 1) code-length codes for literal tree (NT,TBIT,3)
read_pt_len(NT, TBIT, 3);
// 2) literal/length tree lengths (CBIT)
read_c_len();
// 3) prefix-tree lengths for positions (NP,PBIT,-1)
read_pt_len(NP, PBIT, -1);
}
// consume one symbol from this block
blocksize--;
// fast table lookup: top 12 bits
j = c_table[bitbuf >> (BITBUFSIZ - 12)];
if(j >= NC)
{
// need to walk tree if overflow
mask = 1U << (BITBUFSIZ - 1 - 12);
do {
j = (bitbuf & mask) ? right[j] : left[j];
mask >>= 1;
} while(j >= NC);
}
// remove js code length bits from bitbuf
fillbuf(c_len[j]);
return j;
}
/***** decode match-position extra bits *****/
uint32_t decode_p(void)
{
uint32_t j, mask;
// fast table lookup: top 8 bits
j = pt_table[bitbuf >> (BITBUFSIZ - 8)];
if(j >= NP)
{
// tree walk for long codes
mask = 1U << (BITBUFSIZ - 1 - 8);
do {
j = (bitbuf & mask) ? right[j] : left[j];
mask >>= 1;
} while(j >= NP);
}
// consume prefix bits
fillbuf(pt_len[j]);
// if non-zero, read extra bits to form full position
if(j != 0) j = (1U << (j - 1)) + getbits((int)(j - 1));
return j;
}
/***** start a new Huffman decode session *****/
void huf_decode_start(void)
{
init_getbits(); // reset bit buffer & subbitbuf state
blocksize = 0; // force reading a fresh block header
}

129
zoo/io.c Normal file
View File

@@ -0,0 +1,129 @@
/*$Source: /usr/home/dhesi/zoo/RCS/io.c,v $*/
/*$Id: io.c,v 1.14 91/07/09 01:39:54 dhesi Exp $*/
/***********************************************************
io.c -- input/output (modified for in-memory I/O)
Adapted from Haruhiko Okumuras “ar” archiver.
This version feeds compressed bytes from a memory buffer
(via mem_getc()) and writes decompressed output to a buffer
(via mem_putc()), eliminating FILE* dependencies.
Modified for in-memory decompression by Natalia Portillo, 2025
***********************************************************/
#include <limits.h> // Provides CHAR_BIT for bit-width operations
#include "ar.h" // Archive format constants (e.g., CODE_BIT, NC)
#include "lh5.h" // Declarations for mem_getc(), mem_putc(), buffer state
#include "lzh.h" // LZH algorithm constants (e.g., BITBUFSIZ, DICSIZ)
//-----------------------------------------------------------------------------
// Global bit-I/O state
//-----------------------------------------------------------------------------
uint16_t bitbuf; // Accumulates bits shifted in from the input stream
int unpackable; // Unused in decompression here (was for encode error)
// Byte counters (optional diagnostics; not used to gate decompression)
size_t compsize; // Count of output bytes produced (for compression mode)
size_t origsize; // Count of input bytes consumed (for CRC in file I/O)
uint32_t subbitbuf; // Holds the last byte fetched; bits are consumed from here
int bitcount; // How many valid bits remain in subbitbuf
//-----------------------------------------------------------------------------
// fillbuf(n)
// Shift the global bitbuf left by n bits, then read in n new bits
// from the input buffer (in-memory) to replenish bitbuf.
//-----------------------------------------------------------------------------
void fillbuf(int n) /* Shift bitbuf n bits left, read n bits */
{
// Make room for n bits
bitbuf <<= n;
// While we still need more bits than we have in subbitbuf...
while(n > bitcount)
{
// Pull any remaining bits from subbitbuf into bitbuf
bitbuf |= subbitbuf << (n -= bitcount);
// Fetch the next compressed byte from input memory
{
int c = mem_getc(); // read one byte or 0 at EOF
subbitbuf = (c == EOF ? 0 : (uint8_t)c);
}
// Reset bitcount: a full new byte is available
bitcount = CHAR_BIT;
}
// Finally, consume the last n bits from subbitbuf into bitbuf
bitbuf |= subbitbuf >> (bitcount -= n);
}
//-----------------------------------------------------------------------------
// getbits(n)
// Return the next n bits from bitbuf (highest-order bits), then
// call fillbuf(n) to replace them. Useful for reading variable-length codes.
//-----------------------------------------------------------------------------
uint32_t getbits(int n)
{
uint32_t x = bitbuf >> (BITBUFSIZ - n); // extract top n bits
fillbuf(n); // replenish bitbuf for future reads
return x;
}
//-----------------------------------------------------------------------------
// putbits(n, x)
// Write the lowest n bits of x into the output buffer, packing them
// into bytes via subbitbuf/bitcount and sending full bytes out
// with mem_putc(). Used by the encoder; kept here for completeness.
//-----------------------------------------------------------------------------
void putbits(int n, uint32_t x) /* Write rightmost n bits of x */
{
// If we have enough room in subbitbuf, just pack the bits
if(n < bitcount) { subbitbuf |= x << (bitcount -= n); }
else
{
// Output the first full byte when subbitbuf fills
{
int w = (int)(subbitbuf | (x >> (n -= bitcount)));
mem_putc(w);
compsize++; // increment output counter (for compression)
}
// If remaining bits don't fill a full byte, stash them
if(n < CHAR_BIT) { subbitbuf = x << (bitcount = CHAR_BIT - n); }
else
{
// Otherwise, flush a second full byte
{
int w2 = (int)(x >> (n - CHAR_BIT));
mem_putc(w2);
compsize++;
}
// And stash any leftover bits beyond two bytes
subbitbuf = x << (bitcount = 2 * CHAR_BIT - n);
}
}
}
//-----------------------------------------------------------------------------
// init_getbits()
// Reset the bit-reader state so that fillbuf() will load fresh bits
// from the start of the input buffer.
//-----------------------------------------------------------------------------
void init_getbits()
{
bitbuf = 0; // clear accumulated bits
subbitbuf = 0; // no pending byte
bitcount = 0; // no bits available
fillbuf(BITBUFSIZ); // pre-load the bit buffer fully
}
//-----------------------------------------------------------------------------
// init_putbits()
// Reset the bit-writer state so subsequent putbits() calls start fresh.
//-----------------------------------------------------------------------------
void init_putbits()
{
bitcount = CHAR_BIT; // subbitbuf is empty but ready for CHAR_BIT bits
subbitbuf = 0; // clear any leftover byte data
}

94
zoo/lh5.c Normal file
View File

@@ -0,0 +1,94 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/* lh5_mem.c
*
* In-memory I/O glue for LH5 decompression.
* Implements mem_getc(), mem_putc(), and the top-level
* lh5_decompress() entry point.
*/
#include "lh5.h"
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "../library.h"
/* Forward-declaration of the decompression driver in lzh.c */
extern int lzh_decode(void);
/* Buffer I/O state (see lh5_mem.h for externs) */
const uint8_t *in_ptr;
size_t in_left;
uint8_t *out_ptr;
size_t out_left;
int mem_error;
/*
* mem_getc(): return next compressed byte, or 0 when in_left==0.
* Never sets mem_error on input underflow.
*/
int mem_getc(void)
{
if(in_left == 0) { return 0; /* mimic feof → subbitbuf = 0 */ }
int c = *in_ptr++;
in_left--;
return c;
}
/*
* mem_putc(): write one output byte, set mem_error on overflow.
*/
int mem_putc(int c)
{
if(out_left == 0)
{
mem_error = 1;
return EOF;
}
*out_ptr++ = (uint8_t)c;
out_left--;
return c;
}
/*
* Top-level in-memory decompressor.
*
* in_buf points to 'in_len' bytes of compressed data.
* out_buf must have at least *out_len bytes available.
* On return *out_len is set to the number of bytes written.
*
* Returns 0 on success
* -1 on error (bad stream or output too small)
*/
AARU_EXPORT int AARU_CALL lh5_decompress(const uint8_t *in_buf, size_t in_len, uint8_t *out_buf, size_t *out_len)
{
/* Initialize buffer pointers and error flag */
in_ptr = in_buf;
in_left = in_len;
out_ptr = out_buf;
out_left = *out_len;
mem_error = 0;
/* Invoke the core LH5 decode routine (now buffer-based) */
if(lzh_decode() != 0 || mem_error) { return -1; }
/* Compute actual output size */
*out_len = (size_t)(out_ptr - out_buf);
return 0;
}

54
zoo/lh5.h Normal file
View File

@@ -0,0 +1,54 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/* lh5_mem.h
*
* In-memory I/O glue for LH5 decompression.
* Defines the mem_getc()/mem_putc() buffer readers/writers
* and declares the lh5_decompress() entry point.
*/
#ifndef AARU_COMPRESSION_NATIVE_LH5_H
#define AARU_COMPRESSION_NATIVE_LH5_H
#include <stddef.h>
#include <stdint.h>
/* --------------------------------------------------------------------------
* State for in-memory I/O
* --------------------------------------------------------------------------
* in_ptr/in_left: where to read next compressed byte
* out_ptr/out_left: where to write next decompressed byte
* mem_error: set to 1 on underflow/overflow
*/
extern const uint8_t *in_ptr;
extern size_t in_left;
extern uint8_t *out_ptr;
extern size_t out_left;
extern int mem_error;
/* --------------------------------------------------------------------------
* Fetch one byte from in_buf; returns EOF on underflow
* -------------------------------------------------------------------------- */
int mem_getc(void);
/* --------------------------------------------------------------------------
* Write one byte into out_buf; returns c or EOF on overflow
* -------------------------------------------------------------------------- */
int mem_putc(int c);
#endif // AARU_COMPRESSION_NATIVE_LH5_H

230
zoo/lzd.c Normal file
View File

@@ -0,0 +1,230 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
// Lempel-Ziv-Davis compression implementation based on the public domain code from
// Rahul Dhesi from zoo
#include "lzd.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../library.h"
// Reset the dictionary to its initial state
static void init_dict(LZDContext *ctx)
{
ctx->nbits = 9; // start with 9bit codes
ctx->max_code = 1u << 9; // maximum code value for current nbits
ctx->free_code = FIRST_FREE; // next free dictionary slot
ctx->have_old = 0; // no "previous code" yet
}
// Follow the head[] chain until you get the first literal byte of a code
static int firstch(LZDContext *ctx, int code)
{
int steps = 0;
while(code > 255)
{ // follow links until you hit a literal (0255)
if((unsigned)code > MAXMAX) return -1; // invalid code range
if(++steps > (int)MAXMAX) return -1; // prevent infinite loop
code = ctx->head[code];
}
return code;
}
// Ensure there are at least nbits available in the bit buffer
static int fill_bits(LZDContext *ctx)
{
while(ctx->bitcount < (int)ctx->nbits)
{
if(ctx->in_pos >= ctx->in_len) return -1; // no more input available
// pull a byte from the input stream into bitbuf at current position
ctx->bitbuf |= (uint64_t)ctx->in_ptr[ctx->in_pos++] << ctx->bitcount;
ctx->bitcount += 8;
}
return 0;
}
// Read the next code of nbits from the bit buffer
static int read_code(LZDContext *ctx)
{
if(fill_bits(ctx) < 0) return -1; // top up bits if needed
int code = (int)(ctx->bitbuf & masks[ctx->nbits]); // mask off the low nbits
ctx->bitbuf >>= ctx->nbits; // consume bits
ctx->bitcount -= ctx->nbits;
return code;
}
// Initialise a decompression context: allocate tables, set up initial dictionary
LZDStatus LZD_Init(LZDContext *ctx)
{
memset(ctx, 0, sizeof *ctx);
// allocate head, tail and stack arrays to hold dictionary links and output stack
ctx->head = malloc((MAXMAX + 1) * sizeof *ctx->head);
ctx->tail = malloc((MAXMAX + 1) * sizeof *ctx->tail);
ctx->stack = malloc((MAXMAX + 1) * sizeof *ctx->stack);
if(!ctx->head || !ctx->tail || !ctx->stack) return LZD_NEED_INPUT;
// initialise first 256 dictionary entries to literal bytes
for(int i = 0; i < 256; i++)
{
ctx->head[i] = -1;
ctx->tail[i] = (uint8_t)i;
}
// set stack pointers to empty
ctx->stack_lim = ctx->stack + (MAXMAX + 1);
ctx->stack_ptr = ctx->stack_lim;
init_dict(ctx); // reset code size/free_code
ctx->bitbuf = 0;
ctx->bitcount = 0;
return LZD_OK;
}
// Point the context at a new input buffer
LZDStatus LZD_Feed(LZDContext *ctx, const unsigned char *in, size_t in_len)
{
ctx->in_ptr = in;
ctx->in_len = in_len;
ctx->in_pos = 0;
return LZD_OK;
}
// Pull decompressed bytes into `out` up to out_len or until input is exhausted
LZDStatus LZD_Drain(LZDContext *ctx, unsigned char *out, size_t out_len, size_t *out_produced)
{
size_t outpos = 0;
while(outpos < out_len)
{
// If there are bytes on the stack (from expanding a code), emit them first
if(ctx->stack_ptr < ctx->stack_lim)
{
out[outpos++] = (uint8_t)*ctx->stack_ptr++;
continue;
}
// Otherwise, read the next code from the bitstream
int raw = read_code(ctx);
if(raw < 0)
{
*out_produced = outpos;
// If we emitted something, signal OK; otherwise tell caller we need more input
return outpos > 0 ? LZD_OK : LZD_NEED_INPUT;
}
unsigned code = (unsigned)raw;
// Special code: CLEAR reset the dictionary and read a fresh literal
if(code == CLEAR)
{
init_dict(ctx);
int lit = read_code(ctx);
if(lit < 0)
{
*out_produced = outpos;
return outpos > 0 ? LZD_OK : LZD_NEED_INPUT;
}
ctx->old_code = (unsigned)lit;
ctx->have_old = 1;
out[outpos++] = (uint8_t)lit;
continue;
}
// Special code: Z_EOF end of compressed stream
if(code == Z_EOF)
{
*out_produced = outpos;
return LZD_DONE;
}
unsigned in_code = code;
// Handle KwKwK case: code not yet in the dictionary
if(code >= ctx->free_code)
{
if(!ctx->have_old) return LZD_DONE;
int fc = firstch(ctx, ctx->old_code); // get first character of previous code
if(fc < 0) return LZD_DONE;
*--ctx->stack_ptr = (char)fc;
code = ctx->old_code;
}
// Walk backwards through dictionary, pushing bytes onto the stack
while(code > 255)
{
*--ctx->stack_ptr = (char)ctx->tail[code];
code = ctx->head[code];
}
uint8_t first_byte = (uint8_t)code;
*--ctx->stack_ptr = (char)first_byte;
// Add new sequence to dictionary if we have a valid previous code
if(ctx->have_old && ctx->free_code <= MAXMAX)
{
ctx->tail[ctx->free_code] = first_byte;
ctx->head[ctx->free_code] = (int)ctx->old_code;
ctx->free_code++;
// Increase code width when table fills up to current max_code
if(ctx->free_code >= ctx->max_code && ctx->nbits < MAXBITS)
{
ctx->nbits++;
ctx->max_code <<= 1;
}
}
ctx->old_code = in_code;
ctx->have_old = 1;
}
*out_produced = outpos;
return LZD_OK;
}
// Free dynamic allocations inside an LZDContext
void LZD_Destroy(LZDContext *ctx)
{
if(!ctx) return;
free(ctx->head);
free(ctx->tail);
free(ctx->stack);
}
// Public API: allocate+initialise a new context
AARU_EXPORT void AARU_CALL *CreateLZDContext(void)
{
LZDContext *c = malloc(sizeof *c);
return c && LZD_Init(c) == LZD_OK ? c : (free(c), NULL);
}
// Public API: destroy and free a context
AARU_EXPORT void AARU_CALL DestroyLZDContext(void *ctx)
{
if(ctx)
{
LZD_Destroy(ctx);
free(ctx);
}
}
// Public API wrapper to feed new compressed data
AARU_EXPORT int AARU_CALL LZD_FeedNative(void *ctx, const unsigned char *data, size_t length)
{
return LZD_Feed(ctx, data, length);
}
// Public API wrapper to drain decompressed data
AARU_EXPORT int AARU_CALL LZD_DrainNative(void *ctx, unsigned char *outBuf, size_t outBufLen, size_t *produced)
{
return LZD_Drain(ctx, outBuf, outBufLen, produced);
}

86
zoo/lzd.h Normal file
View File

@@ -0,0 +1,86 @@
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LZD_H
#define LZD_H
#include <stddef.h>
#include <stdint.h>
#define MAXBITS 13
#define MAXMAX ((1U << MAXBITS) - 1) // 8191
#define FIRST_FREE 258 // first free code after CLEAR+EOF
#define CLEAR 256
#define Z_EOF 257
typedef enum
{
LZD_OK = 0,
LZD_NEED_INPUT = 1,
LZD_NEED_OUTPUT = 2,
LZD_DONE = 3
} LZDStatus;
typedef struct
{
int * head;
uint8_t *tail;
unsigned nbits;
unsigned max_code;
unsigned free_code;
unsigned old_code;
int have_old;
char *stack;
char *stack_lim;
char *stack_ptr;
uint64_t bitbuf;
int bitcount;
const unsigned char *in_ptr;
size_t in_len;
size_t in_pos;
} LZDContext;
static const unsigned masks[MAXBITS + 1] = {
0,
0,
0,
0,
0,
0,
0,
0,
0,
(1u << 9) - 1,
(1u << 10) - 1,
(1u << 11) - 1,
(1u << 12) - 1,
(1u << 13) - 1
};
LZDStatus LZD_Init(LZDContext *ctx);
LZDStatus LZD_Feed(LZDContext *ctx, const unsigned char *in, size_t in_len);
LZDStatus LZD_Drain(LZDContext *ctx, unsigned char *out, size_t out_len, size_t *out_produced);
void LZD_Destroy(LZDContext *ctx);
#endif // LZD_H

31
zoo/lzh.c Normal file
View File

@@ -0,0 +1,31 @@
/* $Id: lzh.c,v 1.15 91/07/06 19:18:51 dhesi Exp $ */
// Modified for in-memory decompression by Natalia Portillo, 2025
#include "lzh.h" /* prototypes for encode(), lzh_decode() */
#include <stdint.h>
#include "ar.h"
#include "lh5.h" /* mem_getc(), mem_putc(), in_ptr/in_left, out_ptr/out_left */
extern int decoded; /* from huf.c */
/*
* lzh_decode now reads from in_buf/in_len and writes into out_buf/out_len
* entirely in memory, via mem_getc()/mem_putc().
*/
int lzh_decode(void)
{
int n, i;
uint8_t buffer[DICSIZ];
/* Initialize the Huffman bit reader and sliding-window state */
decode_start();
/* Decode blocks of up to DICSIZ bytes until endofstream */
while(!decoded)
{
n = decode(DICSIZ, buffer);
for(i = 0; i < n; i++) { mem_putc(buffer[i]); }
}
return mem_error ? -1 : 0;
}

31
zoo/lzh.h Normal file
View File

@@ -0,0 +1,31 @@
/*$Source: /usr/home/dhesi/zoo/RCS/lzh.h,v $*/
/*$Id: lzh.h,v 1.3 91/07/09 01:39:23 dhesi Exp $*/
/*
Adapted from "ar" archiver written by Haruhiko Okumura.
*/
// Modified for in-memory decompression by Natalia Portillo, 2025
/* io.c */
#include <stdint.h>
extern uint16_t bitbuf;
#define BITBUFSIZ (CHAR_BIT * sizeof bitbuf)
/* encode.c and decode.c */
#define MATCHBIT 8 /* bits for MAXMATCH - THRESHOLD */
#define MAXMATCH 256 /* formerly F (not more than UCHAR_MAX + 1) */
#define THRESHOLD 3 /* choose optimal value */
#define PERC_FLAG ((unsigned)0x8000)
/* huf.c */
#define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
/* alphabet = {0, 1, 2, ..., NC - 1} */
#define CBIT 9 /* $\lfloor \log_2 NC \rfloor + 1$ */
#define CODE_BIT 16 /* codeword length */
extern uint16_t left[], right[];

130
zoo/maketbl.c Normal file
View File

@@ -0,0 +1,130 @@
/*$Source: /usr/home/dhesi/zoo/RCS/maketbl.c,v $*/
/*$Id: maketbl.c,v 1.8 91/07/09 01:39:52 dhesi Exp $*/
/***********************************************************
maketbl.c -- make table for decoding
Builds a fast lookup table + fallback tree for Huffman
codes given code lengths. Used by decode_c() to map
input bit patterns to symbols efficiently.
Adapted from Haruhiko Okumuras “ar” archiver.
Modified for in-memory decompression by Natalia Portillo, 2025
***********************************************************/
#include <stdio.h>
#include "ar.h" // provides NC, CODE_BIT, etc.
#include "lzh.h" // provides BITBUFSIZ
/*
* make_table(nchar, bitlen, tablebits, table):
*
* nchar = number of symbols
* bitlen[] = array of code lengths for each symbol [0..nchar-1]
* tablebits = number of bits for fast direct lookup
* table[] = output table of size (1<<tablebits), entries are:
* - symbol index if code length ≤ tablebits
* - zero or tree node index to follow for longer codes
*
* Algorithm steps:
* 1) Count how many codes of each length (count[1..16]).
* 2) Compute 'start' offsets for each length in a 16-bit code space.
* 3) Normalize starts to 'tablebits' prefix domain, build 'weight'.
* 4) Fill direct-mapped entries for short codes.
* 5) Build binary tree (using left[]/right[]) for codes longer than tablebits.
*/
void make_table(int nchar, uint8_t *bitlen, int tablebits, uint16_t *table)
{
uint16_t count[17]; // count[L] = number of symbols with length L
uint16_t weight[17]; // weight[L] = step size in prefix domain for length L
uint16_t start[18]; // start[L] = base code for length L in 16-bit space
uint16_t *p; // pointer into 'table' or tree
uint32_t i, k, len, ch;
uint32_t jutbits; // bits to drop when mapping into tablebits
uint32_t avail; // next free node index for left[]/right[] tree
uint32_t nextcode; // end-of-range code for current length
uint32_t mask; // bitmask for tree insertion
// 1) Zero counts, then tally code-lengths
for(i = 1; i <= 16; i++) count[i] = 0;
for(i = 0; i < (uint32_t)nchar; i++) count[bitlen[i]]++;
// 2) Compute cumulative start positions in the 16-bit code space
start[1] = 0;
for(i = 1; i <= 16; i++) start[i + 1] = start[i] + (count[i] << (16 - i));
// Validate: sum of all codes must fill 16-bit range
if(start[17] != (uint16_t)(1U << 16)) fprintf(stderr, "make_table: Bad decode table\n");
// Prepare for mapping into tablebits-bit table
jutbits = 16 - tablebits;
for(i = 1; i <= (uint32_t)tablebits; i++)
{
// Shrink start[i] into prefix domain
start[i] >>= jutbits;
// Weight = 2^(tablebits - i)
weight[i] = (uint16_t)(1U << (tablebits - i));
}
// For lengths > tablebits, weight = 2^(16 - length)
for(; i <= 16; i++) weight[i] = (uint16_t)(1U << (16 - i));
// 3) Clear any unused table slots between last short code and end
i = start[tablebits + 1] >> jutbits;
if(i != (uint16_t)(1U << tablebits))
{
k = 1U << tablebits;
while(i < k) table[i++] = 0;
}
// Initialize tree node index after the direct table entries
avail = nchar;
// Mask for inspecting bits when building tree
mask = 1U << (15 - tablebits);
// 4) For each symbol, place its codes in table or tree
for(ch = 0; ch < (uint32_t)nchar; ch++)
{
len = bitlen[ch];
if(len == 0) continue; // skip symbols with no code
// Next code range = [start[len], start[len]+weight[len])
nextcode = start[len] + weight[len];
if(len <= tablebits)
{
// Direct mapping: fill all table slots in this range
for(k = start[len]; k < nextcode; k++) table[k] = (uint16_t)ch;
}
else
{
// Build or extend tree for longer codes
// Start at table index for this prefix
k = start[len];
p = &table[k >> jutbits];
// Number of extra bits beyond tablebits
uint32_t extra = len - tablebits;
// Walk/construct tree nodes bit by bit
while(extra-- > 0)
{
if(*p == 0)
{
// allocate a new node for left[]/right[]
left[avail] = right[avail] = 0;
*p = (uint16_t)avail++;
}
// branch left or right based on current code bit
if(k & mask)
p = &right[*p];
else
p = &left[*p];
// shift to next bit in code
k <<= 1;
}
// At leaf: assign symbol
*p = (uint16_t)ch;
}
// Advance start[len] for next code of same length
start[len] = nextcode;
}
}