├── .clang-format
├── .clang-tidy
├── .gitattributes
├── .github
└── workflows
│ ├── ci-linux.yml
│ ├── ci-macos.yml
│ ├── ci-windows.yml
│ ├── coverity-scan.yml
│ ├── released.yml
│ └── snapshots-windows.yml
├── .gitignore
├── .lgtm.yml
├── CMakeLists.txt
├── COPYING
├── COPYING-asm
├── README.md
├── include
└── mdcomp
│ ├── artc42.hh
│ ├── basic_decoder.hh
│ ├── bigendian_io.hh
│ ├── bitstream.hh
│ ├── comper.hh
│ ├── comperx.hh
│ ├── enigma.hh
│ ├── ignore_unused_variable_warning.hh
│ ├── kosinski.hh
│ ├── kosplus.hh
│ ├── lzkn1.hh
│ ├── lzss.hh
│ ├── moduled_adaptor.hh
│ ├── nemesis.hh
│ ├── rocket.hh
│ ├── saxman.hh
│ ├── snkrle.hh
│ └── unreachable.hh
└── src
├── asm
├── Comper.asm
├── ComperX.asm
├── Enigma.asm
├── KosM.asm
├── Kosinski.a80
├── Kosinski.asm
├── KosinskiPlus.a80
├── KosinskiPlus.asm
├── Kosinski_internal.asm
├── Rocket.asm
├── SNKRLE.asm
└── Saxman.asm
├── lib
├── artc42.cc
├── basic_decoder.cc
├── bigendian_io.cc
├── bitstream.cc
├── comper.cc
├── comperx.cc
├── enigma.cc
├── ignore_unused_variable_warning.cc
├── kosinski.cc
├── kosplus.cc
├── lzkn1.cc
├── lzss.cc
├── moduled_adaptor.cc
├── nemesis.cc
├── rocket.cc
├── saxman.cc
└── snkrle.cc
└── tools
├── compcmp.cc
├── comperx.cc
├── enicmp.cc
├── koscmp.cc
├── kosplus.cc
├── lzkn1cmp.cc
├── nemcmp.cc
├── rockcmp.cc
├── saxcmp.cc
└── snkcmp.cc
/.clang-format:
--------------------------------------------------------------------------------
1 | Language: Cpp
2 | AccessModifierOffset: -4
3 | AlignAfterOpenBracket: AlwaysBreak
4 | AlignArrayOfStructures: None
5 | AlignConsecutiveMacros: Consecutive
6 | AlignConsecutiveAssignments: Consecutive
7 | AlignConsecutiveBitFields: Consecutive
8 | AlignConsecutiveDeclarations: Consecutive
9 | AlignEscapedNewlines: Left
10 | AlignOperands: Align
11 | AlignTrailingComments: true
12 | AllowAllArgumentsOnNextLine: true
13 | AllowAllConstructorInitializersOnNextLine: true
14 | AllowAllParametersOfDeclarationOnNextLine: true
15 | # AllowShortEnumsOnASingleLine: false
16 | AllowShortBlocksOnASingleLine: Never
17 | AllowShortCaseLabelsOnASingleLine: false
18 | AllowShortFunctionsOnASingleLine: Empty
19 | AllowShortLambdasOnASingleLine: Empty
20 | AllowShortIfStatementsOnASingleLine: Never
21 | AllowShortLoopsOnASingleLine: false
22 | AlwaysBreakAfterDefinitionReturnType: None
23 | AlwaysBreakAfterReturnType: None
24 | AlwaysBreakBeforeMultilineStrings: false
25 | AlwaysBreakTemplateDeclarations: Yes
26 | AttributeMacros:
27 | - __capability
28 | BinPackArguments: true
29 | BinPackParameters: true
30 | BraceWrapping:
31 | AfterCaseLabel: false
32 | AfterClass: false
33 | AfterControlStatement: Never
34 | AfterEnum: false
35 | AfterFunction: false
36 | AfterNamespace: false
37 | AfterObjCDeclaration: false
38 | AfterStruct: false
39 | AfterUnion: false
40 | AfterExternBlock: false
41 | BeforeCatch: false
42 | BeforeElse: false
43 | BeforeLambdaBody: false
44 | BeforeWhile: false
45 | IndentBraces: false
46 | SplitEmptyFunction: true
47 | SplitEmptyRecord: true
48 | SplitEmptyNamespace: true
49 | BreakBeforeBinaryOperators: All
50 | BreakBeforeConceptDeclarations: true
51 | BreakBeforeBraces: Attach
52 | BreakInheritanceList: BeforeColon
53 | BreakBeforeTernaryOperators: true
54 | BreakConstructorInitializers: BeforeColon
55 | BreakStringLiterals: true
56 | ColumnLimit: 80
57 | CompactNamespaces: true
58 | ConstructorInitializerIndentWidth: 8
59 | ContinuationIndentWidth: 8
60 | Cpp11BracedListStyle: true
61 | DeriveLineEnding: true
62 | DerivePointerAlignment: false
63 | DisableFormat: false
64 | EmptyLineAfterAccessModifier: Never
65 | EmptyLineBeforeAccessModifier: LogicalBlock
66 | FixNamespaceComments: true
67 | IncludeBlocks: Regroup
68 | IncludeCategories:
69 | # Headers in <> without extension.
70 | - Regex: '<([A-Za-z0-9\Q/-_\E])+>'
71 | Priority: 5
72 | SortPriority: 0
73 | CaseSensitive: false
74 | # Headers in <> with extension.
75 | - Regex: '<([A-Za-z0-9.\Q/-_\E])+>'
76 | Priority: 3
77 | SortPriority: 0
78 | CaseSensitive: false
79 | # Headers in "" with extension.
80 | - Regex: '"([A-Za-z0-9.\Q/-_\E])+"'
81 | Priority: 2
82 | SortPriority: 0
83 | CaseSensitive: false
84 | IncludeIsMainRegex: '$'
85 | IncludeIsMainSourceRegex: ''
86 | IndentAccessModifiers: false
87 | IndentCaseLabels: false
88 | IndentCaseBlocks: false
89 | IndentGotoLabels: true
90 | IndentPPDirectives: AfterHash
91 | IndentExternBlock: AfterExternBlock
92 | IndentRequires: true
93 | IndentWidth: 4
94 | IndentWrappedFunctionNames: true
95 | InsertTrailingCommas: None
96 | KeepEmptyLinesAtTheStartOfBlocks: false
97 | LambdaBodyIndentation: Signature
98 | MaxEmptyLinesToKeep: 1
99 | NamespaceIndentation: All
100 | PenaltyExcessCharacter: 1000000
101 | PenaltyReturnTypeOnItsOwnLine: 10000000
102 | PointerAlignment: Left
103 | PPIndentWidth: -1
104 | ReferenceAlignment: Pointer
105 | ReflowComments: true
106 | CommentPragmas: '^\\.+'
107 | ShortNamespaceLines: 1
108 | SortIncludes: CaseSensitive
109 | SortUsingDeclarations: true
110 | SpaceAfterCStyleCast: false
111 | SpaceAfterLogicalNot: false
112 | SpaceAfterTemplateKeyword: true
113 | SpaceBeforeAssignmentOperators: true
114 | SpaceBeforeCaseColon: false
115 | SpaceBeforeCpp11BracedList: false
116 | SpaceBeforeCtorInitializerColon: true
117 | SpaceBeforeInheritanceColon: true
118 | SpaceBeforeParens: ControlStatements
119 | SpaceAroundPointerQualifiers: Default
120 | SpaceBeforeRangeBasedForLoopColon: true
121 | SpaceInEmptyBlock: false
122 | SpaceInEmptyParentheses: false
123 | SpacesBeforeTrailingComments: 4
124 | SpacesInAngles: Never
125 | SpacesInConditionalStatement: false
126 | SpacesInContainerLiterals: false
127 | SpacesInCStyleCastParentheses: false
128 | SpacesInLineCommentPrefix:
129 | Minimum: 1
130 | Maximum: -1
131 | SpacesInParentheses: false
132 | SpacesInSquareBrackets: false
133 | SpaceBeforeSquareBrackets: false
134 | BitFieldColonSpacing: Both
135 | Standard: Latest
136 | TabWidth: 4
137 | UseCRLF: false
138 | UseTab: Never
--------------------------------------------------------------------------------
/.clang-tidy:
--------------------------------------------------------------------------------
1 | Checks: >
2 | -*,
3 | bugprone-*,
4 | cert-dcl50-cpp,
5 | cert-env33-c,
6 | cert-err34-c,
7 | cert-err52-cpp,
8 | cert-err60-cpp,
9 | cert-flp30-c,
10 | cert-msc50-cpp,
11 | cert-msc51-cpp,
12 | clang-diagnostic-*,
13 | clang-analyzer-*,
14 | clang-analyzer-alpha*,
15 | cppcoreguidelines-*,
16 | -cppcoreguidelines-avoid-magic-numbers,
17 | -cppcoreguidelines-avoid-non-const-global-variables,
18 | -cppcoreguidelines-init-variables,
19 | -cppcoreguidelines-macro-usage,
20 | -cppcoreguidelines-pro-bounds-constant-array-index,
21 | -cppcoreguidelines-pro-type-reinterpret-cast,
22 | -cppcoreguidelines-pro-type-union-access,
23 | -cppcoreguidelines-pro-bounds-pointer-arithmetic,
24 | google-build-using-namespace,
25 | google-explicit-constructor,
26 | google-global-names-in-headers,
27 | google-readability-casting,
28 | google-runtime-int,
29 | google-runtime-operator,
30 | hicpp-*,
31 | -hicpp-named-parameter,
32 | misc-*,
33 | -misc-no-recursion,
34 | modernize-*,
35 | -modernize-use-trailing-return-type,
36 | performance-*,
37 | readability-*,
38 | -readability-magic-numbers,
39 | -readability-named-parameter,
40 | -readability-function-cognitive-complexity
41 | CheckOptions:
42 | - key: bugprone-argument-comment.StrictMode
43 | value: 1
44 | - key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
45 | value: 1
46 | - key: bugprone-signed-char-misuse.CharTypdefsToIgnore
47 | value: "int8_t"
48 | FormatStyle: "file"
49 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.ac text
2 | *.am text
3 | *.in text
4 | *.m4 eol=lf
5 |
6 | *.sh text
7 |
8 | *.cfg text
9 | *.txt text
10 |
11 | *.asm text diff=cpp
12 | *.c text diff=cpp
13 | *.cc text diff=cpp
14 | *.cpp text diff=cpp
15 | *.cxx text diff=cpp
16 | *.c++ text diff=cpp
17 | *.h text diff=cpp
18 | *.hh text diff=cpp
19 | *.hpp text diff=cpp
20 | *.ll text diff=cpp
21 | *.rc text
22 | *.uc text
23 | *.yy text diff=cpp
24 |
25 | Makefile* text
26 |
27 | AUTHORS text
28 | COPYING text
29 | FAQ text
30 | INSTALL text
31 | NEWS text
32 | README* text
33 |
34 |
--------------------------------------------------------------------------------
/.github/workflows/ci-linux.yml:
--------------------------------------------------------------------------------
1 | name: ci-linux
2 |
3 | on:
4 | push:
5 | paths:
6 | - "**"
7 | - "!COPYING"
8 | - "!COPYING-asm"
9 | - "!INSTALL"
10 | - "!**.md"
11 | - "!.clang*"
12 | - "!.gitignore"
13 | - "!.gitattributes"
14 | - "!.github/workflows/*"
15 | - ".github/workflows/ci-linux.yml"
16 | pull_request:
17 | paths:
18 | - "**"
19 | - "!COPYING"
20 | - "!COPYING-asm"
21 | - "!INSTALL"
22 | - "!**.md"
23 | - "!.clang*"
24 | - "!.gitignore"
25 | - "!.gitattributes"
26 | - "!.github/workflows/*"
27 | - ".github/workflows/ci-linux.yml"
28 |
29 | jobs:
30 | ci-linux:
31 | runs-on: ubuntu-latest
32 | strategy:
33 | matrix:
34 | compiler: [gcc, clang]
35 | generator: [make, ninja]
36 | include:
37 | - compiler: gcc
38 | cc: gcc
39 | cxx: g++
40 | - compiler: clang
41 | cc: clang
42 | cxx: clang++
43 | - generator: make
44 | cmake_generator: "Unix Makefiles"
45 | - generator: ninja
46 | cmake_generator: "Ninja"
47 | steps:
48 | - name: Install dependencies
49 | run: |
50 | if ! apt-fast -- help &> /dev/null; then
51 | sudo add-apt-repository -u -y ppa:apt-fast/stable
52 | sudo apt-get update
53 | echo debconf apt-fast/maxdownloads string 16 | sudo debconf-set-selections
54 | echo debconf apt-fast/dlflag boolean true | sudo debconf-set-selections
55 | echo debconf apt-fast/aptmanager string apt-get | sudo debconf-set-selections
56 | DEBIAN_FRONTEND=noninteractive sudo apt install -y apt-fast
57 | else
58 | sudo apt-fast update
59 | fi
60 | sudo apt-fast install -y libboost-all-dev ninja-build
61 | - name: Checkout code
62 | uses: actions/checkout@master
63 | - name: Configure
64 | env:
65 | OVERRIDE_CC: ${{ matrix.cc }}
66 | OVERRIDE_CXX: ${{ matrix.cxx }}
67 | run: |
68 | export CC=$(which $OVERRIDE_CC)
69 | export CXX=$(which $OVERRIDE_CXX)
70 | cmake -S . -B build -G "${{ matrix.cmake_generator }}"
71 | - name: Build
72 | run: |
73 | cmake --build build -j2
74 |
--------------------------------------------------------------------------------
/.github/workflows/ci-macos.yml:
--------------------------------------------------------------------------------
1 | name: ci-macos
2 |
3 | on:
4 | push:
5 | paths:
6 | - '**'
7 | - '!COPYING'
8 | - '!COPYING-asm'
9 | - '!INSTALL'
10 | - '!**.md'
11 | - '!.clang*'
12 | - '!.gitignore'
13 | - '!.gitattributes'
14 | - '!.github/workflows/*'
15 | - '.github/workflows/ci-macos.yml'
16 | pull_request:
17 | paths:
18 | - '**'
19 | - '!COPYING'
20 | - '!COPYING-asm'
21 | - '!INSTALL'
22 | - '!**.md'
23 | - '!.clang*'
24 | - '!.gitignore'
25 | - '!.gitattributes'
26 | - '!.github/workflows/*'
27 | - '.github/workflows/ci-macos.yml'
28 |
29 | jobs:
30 | ci-macos:
31 | runs-on: macos-latest
32 | strategy:
33 | matrix:
34 | generator: [make, ninja, xcode]
35 | include:
36 | - generator: make
37 | cmake_generator: "Unix Makefiles"
38 | - generator: ninja
39 | cmake_generator: "Ninja"
40 | - generator: xcode
41 | cmake_generator: "Xcode"
42 | steps:
43 | - name: Install dependencies
44 | run: |
45 | brew install boost make ninja
46 | - name: Checkout code
47 | uses: actions/checkout@master
48 | - name: Configure
49 | run: |
50 | export LDFLAGS="-L$(brew --prefix boost)/lib $LDFLAGS"
51 | export CFLAGS="-I$(brew --prefix boost)/include $CFLAGS"
52 | export CXXFLAGS="-I$(brew --prefix boost)/include $CXXFLAGS"
53 | cmake -S . -B build -G "${{ matrix.cmake_generator }}"
54 | - name: Build
55 | run: |
56 | export LDFLAGS="-L$(brew --prefix boost)/lib $LDFLAGS"
57 | export CFLAGS="-I$(brew --prefix boost)/include $CFLAGS"
58 | export CXXFLAGS="-I$(brew --prefix boost)/include $CXXFLAGS"
59 | cmake --build build -j2
60 |
--------------------------------------------------------------------------------
/.github/workflows/ci-windows.yml:
--------------------------------------------------------------------------------
1 | name: ci-windows
2 |
3 | on:
4 | push:
5 | paths:
6 | - '**'
7 | - '!COPYING'
8 | - '!COPYING-asm'
9 | - '!INSTALL'
10 | - '!**.md'
11 | - '!.clang*'
12 | - '!.gitignore'
13 | - '!.gitattributes'
14 | - '!.github/workflows/*'
15 | - '.github/workflows/ci-windows.yml'
16 | pull_request:
17 | paths:
18 | - '**'
19 | - '!COPYING'
20 | - '!COPYING-asm'
21 | - '!INSTALL'
22 | - '!**.md'
23 | - '!.clang*'
24 | - '!.gitignore'
25 | - '!.gitattributes'
26 | - '!.github/workflows/*'
27 | - '.github/workflows/ci-windows.yml'
28 |
29 | jobs:
30 | ci-windows:
31 | runs-on: windows-latest
32 | strategy:
33 | matrix:
34 | # generator: [make, msys, vs2019]
35 | generator: [make, msys]
36 | architecture: [i686, x86_64]
37 | include:
38 | - generator: make
39 | cmake_generator: "Unix Makefiles"
40 | - generator: msys
41 | cmake_generator: "MSYS Makefiles"
42 | # - generator: vs2019
43 | # cmake_generator: "Visual Studio 16 2019"
44 | - architecture: i686
45 | msystem: MINGW32
46 | arch: i686
47 | - architecture: x86_64
48 | msystem: MINGW64
49 | arch: x86_64
50 | defaults:
51 | run:
52 | shell: msys2 {0}
53 | steps:
54 | - name: Install dependencies
55 | uses: msys2/setup-msys2@v2
56 | with:
57 | msystem: ${{ matrix.msystem }}
58 | install:
59 | base-devel git
60 | mingw-w64-${{ matrix.arch }}-toolchain mingw-w64-${{ matrix.arch }}-binutils
61 | mingw-w64-${{ matrix.arch }}-ntldd mingw-w64-${{ matrix.arch }}-boost
62 | mingw-w64-${{ matrix.arch }}-cmake
63 | - name: Checkout code
64 | uses: actions/checkout@master
65 | - name: Configure
66 | run: |
67 | cmake -S . -B build -G "${{ matrix.cmake_generator }}"
68 | - name: Build
69 | run: |
70 | cmake --build build -j2
71 |
--------------------------------------------------------------------------------
/.github/workflows/coverity-scan.yml:
--------------------------------------------------------------------------------
1 | name: coverity-scan
2 |
3 | on:
4 | schedule:
5 | - cron: "0 00 * * *" # Daily at 00:00 UTC
6 | workflow_dispatch:
7 |
8 | env:
9 | TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
10 | EMAIL: ${{ secrets.COVERITY_SCAN_EMAIL }}
11 | SHA1: ${{ github.sha }}
12 | FILE: mdcomp-ubuntu-gcc.tgz
13 | PROJ: flamewing/mdcomp
14 |
15 | jobs:
16 | coverity-linux:
17 | if: ${{ github.repository_owner == 'flamewing' }}
18 | runs-on: ubuntu-latest
19 | steps:
20 | - name: Activity check
21 | run: |
22 | DATEUTC=$(curl -sL https://api.github.com/repos/flamewing/mdcomp/commits | jq -r '[.[]][0]' | jq -r '.commit.committer.date')
23 | TIMESTAMP=$(date --utc -d "$DATEUTC" +%s)
24 | DAYS=$(( ($(date --utc +%s) - $TIMESTAMP) / 86400 ))
25 | if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
26 | echo REPO_ALIVE=true >> $GITHUB_ENV
27 | else
28 | if [ $DAYS -gt 0 ]; then
29 | echo REPO_ALIVE=false >> $GITHUB_ENV
30 | else
31 | echo REPO_ALIVE=true >> $GITHUB_ENV
32 | fi
33 | fi
34 | - name: Install dependencies
35 | if: ${{ env.REPO_ALIVE == 'true' }}
36 | run: |
37 | if ! apt-fast -- help &> /dev/null; then
38 | sudo add-apt-repository -u -y ppa:apt-fast/stable
39 | sudo apt-get update
40 | echo debconf apt-fast/maxdownloads string 16 | sudo debconf-set-selections
41 | echo debconf apt-fast/dlflag boolean true | sudo debconf-set-selections
42 | echo debconf apt-fast/aptmanager string apt-get | sudo debconf-set-selections
43 | DEBIAN_FRONTEND=noninteractive sudo apt install -y apt-fast
44 | else
45 | sudo apt-fast update
46 | fi
47 | sudo apt-fast install -y libboost-all-dev ninja-build
48 | - name: Download Coverity Build Tool
49 | if: ${{ env.REPO_ALIVE == 'true' }}
50 | run: |
51 | wget -q https://scan.coverity.com/download/Linux --post-data "token=$TOKEN&project=$PROJ" -O /tmp/cov-analysis-linux64.tar.gz
52 | mkdir /tmp/cov-analysis-linux64
53 | tar xzf /tmp/cov-analysis-linux64.tar.gz --strip 1 -C /tmp/cov-analysis-linux64
54 | - name: Checkout code
55 | if: ${{ env.REPO_ALIVE == 'true' }}
56 | uses: actions/checkout@master
57 | - name: Configure
58 | if: ${{ env.REPO_ALIVE == 'true' }}
59 | run: |
60 | cmake -S . -B build -G 'Unix Makefiles'
61 | - name: Build with cov-build
62 | if: ${{ env.REPO_ALIVE == 'true' }}
63 | run: |
64 | export PATH=/tmp/cov-analysis-linux64/bin:$PATH
65 | cov-build --dir cov-int cmake --build build -j2
66 | - name: Submit the result to Coverity Scan
67 | if: ${{ env.REPO_ALIVE == 'true' }}
68 | run: |
69 | tar czvf $FILE cov-int
70 | curl \
71 | --form project=$PROJ \
72 | --form token=$TOKEN \
73 | --form email=$EMAIL \
74 | --form file=@$FILE \
75 | --form version=master \
76 | --form description="$SHA1" \
77 | https://scan.coverity.com/builds?project=$PROJ
78 |
--------------------------------------------------------------------------------
/.github/workflows/released.yml:
--------------------------------------------------------------------------------
1 | name: released
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | virustotal:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: VirusTotal Scan
12 | uses: crazy-max/ghaction-virustotal@v2
13 | with:
14 | vt_api_key: ${{ secrets.VT_API_KEY }}
15 | github_token: ${{ github.token }}
16 | update_release_body: true
17 | files: |
18 | .exe$
19 |
--------------------------------------------------------------------------------
/.github/workflows/snapshots-windows.yml:
--------------------------------------------------------------------------------
1 | name: snapshots-windows
2 |
3 | on:
4 | schedule:
5 | - cron: "0 00 * * *" # Daily at 00:00 UTC
6 | workflow_dispatch:
7 |
8 | jobs:
9 | snapshots-windows:
10 | if: ${{ github.repository_owner == 'flamewing' }}
11 | runs-on: windows-latest
12 | defaults:
13 | run:
14 | shell: msys2 {0}
15 | steps:
16 | - name: Activity check
17 | shell: bash
18 | run: |
19 | DATEUTC=$(curl -sL https://api.github.com/repos/flamewing/mdcomp/commits | jq -r '[.[]][0]' | jq -r '.commit.committer.date')
20 | TIMESTAMP=$(date --utc -d "$DATEUTC" +%s)
21 | DAYS=$(( ($(date --utc +%s) - $TIMESTAMP) / 86400 ))
22 | if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
23 | echo REPO_ALIVE=true >> $GITHUB_ENV
24 | else
25 | if [ $DAYS -gt 0 ]; then
26 | echo REPO_ALIVE=false >> $GITHUB_ENV
27 | else
28 | echo REPO_ALIVE=true >> $GITHUB_ENV
29 | fi
30 | fi
31 | - name: Install dependencies
32 | if: ${{ env.REPO_ALIVE == 'true' }}
33 | uses: msys2/setup-msys2@v2
34 | with:
35 | msystem: MINGW32
36 | install:
37 | base-devel git p7zip
38 | mingw-w64-i686-toolchain mingw-w64-i686-binutils mingw-w64-i686-ntldd mingw-w64-i686-boost mingw-w64-i686-cmake
39 | - name: Checkout code
40 | if: ${{ env.REPO_ALIVE == 'true' }}
41 | uses: actions/checkout@master
42 | - name: Configure
43 | if: ${{ env.REPO_ALIVE == 'true' }}
44 | run: |
45 | cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -G 'Unix Makefiles'
46 | - name: Build
47 | if: ${{ env.REPO_ALIVE == 'true' }}
48 | run: |
49 | cmake --build build -j2
50 | - name: Create package
51 | if: ${{ env.REPO_ALIVE == 'true' }}
52 | run: |
53 | for ff in $(${MSYSTEM_PREFIX}/bin/ntldd -R build/*.exe | tr '\\' '/' | grep -io "$(cygpath -m ${MSYSTEM_PREFIX}).\+\.dll" | sort -u); do
54 | cp $(cygpath -u "$ff") build/
55 | done
56 | SNAPSHOT_PATH=$(cygpath -m $(pwd -P))
57 | echo "SNAPSHOT_PATH=${SNAPSHOT_PATH}" >> $GITHUB_ENV
58 | export BUILDFILE="v0.2.0.$(date --utc +'%Y%m%d')"
59 | echo "BUILDFILE=${BUILDFILE}" >> $GITHUB_ENV
60 | cd build
61 | "/c/Program Files/7-Zip/7z.exe" -tzip a ${SNAPSHOT_PATH}/mdcomp-${BUILDFILE}.zip -mx9 -mmt *.{exe,dll}
62 | - name: VirusTotal Scan
63 | if: ${{ env.REPO_ALIVE == 'true' }}
64 | id: scan_files
65 | uses: crazy-max/ghaction-virustotal@v2
66 | with:
67 | vt_api_key: ${{ secrets.VT_API_KEY }}
68 | github_token: ${{ github.token }}
69 | update_release_body: true
70 | files: |
71 | ${{ env.SNAPSHOT_PATH }}/mdcomp-${{ env.BUILDFILE }}.zip
72 | - name: Generate VirusTotal Body
73 | if: ${{ env.REPO_ALIVE == 'true' }}
74 | run: |
75 | echo "Snapshot ${{ env.BUILDFILE }}" > ${{ env.SNAPSHOT_PATH }}/body.txt
76 | echo "" >> ${{ env.SNAPSHOT_PATH }}/body.txt
77 | echo "🛡 [VirusTotal GitHub Action](https://github.com/crazy-max/ghaction-virustotal) analysis:" >> ${{ env.SNAPSHOT_PATH }}/body.txt
78 | echo "" >> ${{ env.SNAPSHOT_PATH }}/body.txt
79 | analysis="${{ steps.scan_files.outputs.analysis }}"
80 | while read -d, -r pair; do
81 | IFS='=' read -r filename analysisURL <<<"$pair"
82 | echo "* [$(basename $filename)]($analysisURL)" >> ${{ env.SNAPSHOT_PATH }}/body.txt
83 | done <<<"$analysis,"
84 | - name: Create release
85 | if: ${{ env.REPO_ALIVE == 'true' }}
86 | id: create_release
87 | uses: actions/create-release@v1
88 | env:
89 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
90 | with:
91 | tag_name: snapshot-${{ env.BUILDFILE }}
92 | release_name: Snapshot ${{ env.BUILDFILE }}
93 | body_path: ${{ env.SNAPSHOT_PATH }}/body.txt
94 | draft: true
95 | prerelease: false
96 | # Theses pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`.
97 | # See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
98 | - name: Upload snapshot
99 | if: ${{ env.REPO_ALIVE == 'true' }}
100 | uses: actions/upload-release-asset@v1
101 | env:
102 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
103 | with:
104 | upload_url: ${{ steps.create_release.outputs.upload_url }}
105 | asset_path: ${{ env.SNAPSHOT_PATH }}/mdcomp-${{ env.BUILDFILE }}.zip
106 | asset_name: mdcomp-${{ env.BUILDFILE }}.zip
107 | asset_content_type: application/zip
108 | - name: Finish release
109 | if: ${{ env.REPO_ALIVE == 'true' }}
110 | uses: eregon/publish-release@v1
111 | env:
112 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
113 | with:
114 | release_id: ${{ steps.create_release.outputs.id }}
115 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.bak
2 | *~
3 | *.sw[a-z]
4 | .deps
5 | .libs
6 | Makefile
7 | Makefile.in
8 |
9 |
10 | ##### C/C++ #####
11 | # Compiled Object files
12 | *.slo
13 | *.lo
14 | *.o
15 | *.ko
16 | *.obj
17 | *.elf
18 |
19 | # Precompiled Headers
20 | *.gch
21 | *.pch
22 |
23 | # Compiled Dynamic libraries
24 | *.so
25 | *.so.*
26 | *.dylib
27 | *.dll
28 | *.lo
29 |
30 | # Fortran module files
31 | *.mod
32 |
33 | # Compiled Static libraries
34 | *.lai
35 | *.la
36 | *.a
37 | *.lib
38 |
39 | # Executables
40 | *.exe
41 | *.out
42 | *.app
43 | *.i*86
44 | *.x86_64
45 | *.hex
46 | /src/tools/compcmp
47 | /src/tools/enicmp
48 | /src/tools/koscmp
49 | /src/tools/kosplus
50 | /src/tools/lzkn1cmp
51 | /src/tools/mkoscmp
52 | /src/tools/nemcmp
53 | /src/tools/saxcmp
54 | /src/tools/snkcmp
55 | /src/tools/rockcmp
56 |
57 | # Debug files
58 | *.dSYM/
59 |
60 | ##### Autotools #####
61 | # http://www.gnu.org/software/automake
62 |
63 | Makefile.in
64 | config.h.in
65 | po/Makefile.in.in
66 |
67 | # http://www.gnu.org/software/autoconf
68 |
69 | /autom4te.cache
70 | /aclocal.m4
71 | /compile
72 | /configure
73 | config.guess
74 | config.sub
75 | /depcomp
76 | /install-sh
77 | /missing
78 | /stamp-h1
79 | /config.h
80 | /config.log
81 | /config.status
82 | /po/POTFILES
83 | /po/stamp-it
84 | /config.cache
85 |
86 | ##### Anjuta #####
87 | # Local configuration folder and symbol database
88 | /.anjuta/
89 | /.anjuta_sym_db.db
90 | /Debug
91 | /Optimized
92 | /Profiling
93 |
94 | ##### INTL #####
95 | /intltool-extract.in
96 | /intltool-merge.in
97 | /intltool-update.in
98 | /libtool
99 | /ltmain.sh
100 |
101 | #### clangd ####
102 | .clangd
103 | test
104 | .cache
105 |
106 | .vscode
107 |
108 | #### cmake ####
109 | build
--------------------------------------------------------------------------------
/.lgtm.yml:
--------------------------------------------------------------------------------
1 | extraction:
2 | cpp:
3 | after_prepare:
4 | - mkdir custom_cmake
5 | - wget --quiet -O - "http://www.cmake.org/files/v3.20/cmake-3.20.3-linux-x86_64.tar.gz" | tar --strip-components=1 -xz -C custom_cmake
6 | - export PATH=$(pwd)/custom_cmake/bin:${PATH}
7 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | This license does not apply to src/asm directory.
2 |
3 | GNU LESSER GENERAL PUBLIC LICENSE
4 | Version 3, 29 June 2007
5 |
6 | Copyright (C) 2007 Free Software Foundation, Inc.
7 | Everyone is permitted to copy and distribute verbatim copies
8 | of this license document, but changing it is not allowed.
9 |
10 |
11 | This version of the GNU Lesser General Public License incorporates
12 | the terms and conditions of version 3 of the GNU General Public
13 | License, supplemented by the additional permissions listed below.
14 |
15 | 0. Additional Definitions.
16 |
17 | As used herein, "this License" refers to version 3 of the GNU Lesser
18 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
19 | General Public License.
20 |
21 | "The Library" refers to a covered work governed by this License,
22 | other than an Application or a Combined Work as defined below.
23 |
24 | An "Application" is any work that makes use of an interface provided
25 | by the Library, but which is not otherwise based on the Library.
26 | Defining a subclass of a class defined by the Library is deemed a mode
27 | of using an interface provided by the Library.
28 |
29 | A "Combined Work" is a work produced by combining or linking an
30 | Application with the Library. The particular version of the Library
31 | with which the Combined Work was made is also called the "Linked
32 | Version".
33 |
34 | The "Minimal Corresponding Source" for a Combined Work means the
35 | Corresponding Source for the Combined Work, excluding any source code
36 | for portions of the Combined Work that, considered in isolation, are
37 | based on the Application, and not on the Linked Version.
38 |
39 | The "Corresponding Application Code" for a Combined Work means the
40 | object code and/or source code for the Application, including any data
41 | and utility programs needed for reproducing the Combined Work from the
42 | Application, but excluding the System Libraries of the Combined Work.
43 |
44 | 1. Exception to Section 3 of the GNU GPL.
45 |
46 | You may convey a covered work under sections 3 and 4 of this License
47 | without being bound by section 3 of the GNU GPL.
48 |
49 | 2. Conveying Modified Versions.
50 |
51 | If you modify a copy of the Library, and, in your modifications, a
52 | facility refers to a function or data to be supplied by an Application
53 | that uses the facility (other than as an argument passed when the
54 | facility is invoked), then you may convey a copy of the modified
55 | version:
56 |
57 | a) under this License, provided that you make a good faith effort to
58 | ensure that, in the event an Application does not supply the
59 | function or data, the facility still operates, and performs
60 | whatever part of its purpose remains meaningful, or
61 |
62 | b) under the GNU GPL, with none of the additional permissions of
63 | this License applicable to that copy.
64 |
65 | 3. Object Code Incorporating Material from Library Header Files.
66 |
67 | The object code form of an Application may incorporate material from
68 | a header file that is part of the Library. You may convey such object
69 | code under terms of your choice, provided that, if the incorporated
70 | material is not limited to numerical parameters, data structure
71 | layouts and accessors, or small macros, inline functions and templates
72 | (ten or fewer lines in length), you do both of the following:
73 |
74 | a) Give prominent notice with each copy of the object code that the
75 | Library is used in it and that the Library and its use are
76 | covered by this License.
77 |
78 | b) Accompany the object code with a copy of the GNU GPL and this license
79 | document.
80 |
81 | 4. Combined Works.
82 |
83 | You may convey a Combined Work under terms of your choice that,
84 | taken together, effectively do not restrict modification of the
85 | portions of the Library contained in the Combined Work and reverse
86 | engineering for debugging such modifications, if you also do each of
87 | the following:
88 |
89 | a) Give prominent notice with each copy of the Combined Work that
90 | the Library is used in it and that the Library and its use are
91 | covered by this License.
92 |
93 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
94 | document.
95 |
96 | c) For a Combined Work that displays copyright notices during
97 | execution, include the copyright notice for the Library among
98 | these notices, as well as a reference directing the user to the
99 | copies of the GNU GPL and this license document.
100 |
101 | d) Do one of the following:
102 |
103 | 0) Convey the Minimal Corresponding Source under the terms of this
104 | License, and the Corresponding Application Code in a form
105 | suitable for, and under terms that permit, the user to
106 | recombine or relink the Application with a modified version of
107 | the Linked Version to produce a modified Combined Work, in the
108 | manner specified by section 6 of the GNU GPL for conveying
109 | Corresponding Source.
110 |
111 | 1) Use a suitable shared library mechanism for linking with the
112 | Library. A suitable mechanism is one that (a) uses at run time
113 | a copy of the Library already present on the user's computer
114 | system, and (b) will operate properly with a modified version
115 | of the Library that is interface-compatible with the Linked
116 | Version.
117 |
118 | e) Provide Installation Information, but only if you would otherwise
119 | be required to provide such information under section 6 of the
120 | GNU GPL, and only to the extent that such information is
121 | necessary to install and execute a modified version of the
122 | Combined Work produced by recombining or relinking the
123 | Application with a modified version of the Linked Version. (If
124 | you use option 4d0, the Installation Information must accompany
125 | the Minimal Corresponding Source and Corresponding Application
126 | Code. If you use option 4d1, you must provide the Installation
127 | Information in the manner specified by section 6 of the GNU GPL
128 | for conveying Corresponding Source.)
129 |
130 | 5. Combined Libraries.
131 |
132 | You may place library facilities that are a work based on the
133 | Library side by side in a single library together with other library
134 | facilities that are not Applications and are not covered by this
135 | License, and convey such a combined library under terms of your
136 | choice, if you do both of the following:
137 |
138 | a) Accompany the combined library with a copy of the same work based
139 | on the Library, uncombined with any other library facilities,
140 | conveyed under the terms of this License.
141 |
142 | b) Give prominent notice with the combined library that part of it
143 | is a work based on the Library, and explaining where to find the
144 | accompanying uncombined form of the same work.
145 |
146 | 6. Revised Versions of the GNU Lesser General Public License.
147 |
148 | The Free Software Foundation may publish revised and/or new versions
149 | of the GNU Lesser General Public License from time to time. Such new
150 | versions will be similar in spirit to the present version, but may
151 | differ in detail to address new problems or concerns.
152 |
153 | Each version is given a distinguishing version number. If the
154 | Library as you received it specifies that a certain numbered version
155 | of the GNU Lesser General Public License "or any later version"
156 | applies to it, you have the option of following the terms and
157 | conditions either of that published version or of any later version
158 | published by the Free Software Foundation. If the Library as you
159 | received it does not specify a version number of the GNU Lesser
160 | General Public License, you may choose any version of the GNU Lesser
161 | General Public License ever published by the Free Software Foundation.
162 |
163 | If the Library as you received it specifies that a proxy can decide
164 | whether future versions of the GNU Lesser General Public License shall
165 | apply, that proxy's public statement of acceptance of any version is
166 | permanent authorization for you to choose that version for the
167 | Library.
168 |
--------------------------------------------------------------------------------
/COPYING-asm:
--------------------------------------------------------------------------------
1 | This license applies for src/asm difectory.
2 |
3 | BSD Zero Clause License
4 |
5 | Website: https://spdx.org/licenses/0BSD.html
6 |
7 | tl;drLegal: https://tldrlegal.com/license/bsd-0-clause-license
8 |
9 | Permission to use, copy, modify, and/or distribute this software for any
10 | purpose with or without fee is hereby granted.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
18 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 |
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Badges
2 |
3 | [](https://tldrlegal.com/license/bsd-0-clause-license)
4 | [](https://www.gnu.org/licenses/lgpl-3.0)
5 |
6 | [](https://www.codefactor.io/repository/github/flamewing/mdcomp)
7 | [](https://lgtm.com/projects/g/flamewing/mdcomp/alerts/)
8 | [](https://lgtm.com/projects/g/flamewing/mdcomp/context:cpp)
9 |
10 | [](https://github.com/flamewing/mdcomp/actions?query=workflow%3Aci-macos)
11 | [](https://github.com/flamewing/mdcomp/actions?query=workflow%3Aci-linux)
12 | [](https://github.com/flamewing/mdcomp/actions?query=workflow%3Aci-windows)
13 |
14 | [](https://github.com/flamewing/mdcomp/actions?query=workflow%3Acoverity-scan)
15 | [](https://scan.coverity.com/projects/flamewing-mdcomp)
16 |
17 | [](https://github.com/flamewing/mdcomp/actions?query=workflow%3Asnapshots-windows)
18 | [](https://github.com/flamewing/mdcomp/releases/latest)
19 |
20 | ## mdcomp
21 |
22 | Assorted compression formats for the Sega Mega Drive.
23 |
24 | ## License
25 |
26 | The src/asm directory is licensed under a bsd 0-Clause License (0BSD). The tl;dr version is [here](https://tldrlegal.com/license/bsd-0-clause-license).
27 |
28 | Basically, you can use it however you want, and you don't have to add credits, licenses, or anything to your hack.
29 |
30 | I only ask for the courtesy of giving some credit if you use it, but you are not forced to do it.
31 |
32 | The remainder is licensed under the GNU Lesser General Public License v3 (LGPL-3.0). The tl;dr version is [here](https://tldrlegal.com/license/gnu-lesser-general-public-license-v3-(lgpl-3)).
33 |
34 | ## Create and install the package
35 |
36 | You need a C++ development toolchain, including `cmake` at least 3.19 and [Boost](https://www.boost.org/) at least 1.54. With the dependencies installed, you run the following commands:
37 |
38 | ```bash
39 | cmake -S . -B build -G
40 | cmake --build build -j2
41 | cmake --install build
42 | ```
43 |
44 | Here, `` is one appropriate for your platform/IDE. It can be any of the following:
45 |
46 | - `MSYS Makefiles`
47 | - `Ninja`
48 | - `Unix Makefiles`
49 | - `Visual Studio 16 2019`
50 | - `Xcode`
51 |
52 | Some IDEs support cmake by default, and you can just ask for the IDE to configure/build/install without needing to use the terminal.
53 |
54 | ## TODO
55 |
56 | - [ ] Detail compression formats
57 | - [ ] Use Boost::Program Options
58 | - [ ] Make universal compressor/decompressor
59 | - [ ] Finish this readme
60 |
--------------------------------------------------------------------------------
/include/mdcomp/artc42.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2015-2016
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef LIB_ARTC42_HH
20 | #define LIB_ARTC42_HH
21 |
22 | #include
23 |
24 | class artc42 {
25 | public:
26 | static bool decode(std::istream& Src, std::ostream& Dst);
27 | static bool encode(std::istream& Src, std::ostream& Dst);
28 | };
29 |
30 | #endif // LIB_ARTC42_HH
31 |
--------------------------------------------------------------------------------
/include/mdcomp/basic_decoder.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2016
3 | *
4 | *
5 | * This program is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 2.1 of the License, or (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with main.c; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
18 | */
19 |
20 | #ifndef LIB_BASIC_DECODER_H
21 | #define LIB_BASIC_DECODER_H
22 |
23 | #include
24 |
25 | #include
26 | #include
27 | #include
28 |
29 | enum class PadMode { DontPad, PadEven };
30 |
31 | template
32 | class BasicDecoder {
33 | public:
34 | static bool encode(std::istream& Src, std::ostream& Dst, Args... args);
35 | static void extract(std::istream& Src, std::iostream& Dst);
36 | };
37 |
38 | template
39 | bool BasicDecoder::encode(
40 | std::istream& Src, std::ostream& Dst, Args... args) {
41 | size_t Start = Src.tellg();
42 | Src.ignore(std::numeric_limits::max());
43 | size_t FullSize = Src.gcount();
44 | Src.seekg(Start);
45 | std::vector data;
46 | if (Pad == PadMode::PadEven) {
47 | data.resize(FullSize + (FullSize % 2));
48 | } else {
49 | data.resize(FullSize);
50 | }
51 | Src.read(reinterpret_cast(&(data.front())), data.size());
52 | if (Pad == PadMode::PadEven && data.size() > FullSize) {
53 | data.back() = 0;
54 | }
55 | if (Format::encode(
56 | Dst, data.data(), data.size(), std::forward(args)...)) {
57 | // Pad to even size.
58 | if ((Dst.tellp() % 2) != 0) {
59 | Dst.put(0);
60 | }
61 | return true;
62 | }
63 | return false;
64 | }
65 |
66 | template
67 | void BasicDecoder::extract(
68 | std::istream& Src, std::iostream& Dst) {
69 | Dst << Src.rdbuf();
70 | // Pad to even size.
71 | if ((Dst.tellp() % 2) != 0) {
72 | Dst.put(0);
73 | }
74 | Dst.seekg(0);
75 | }
76 |
77 | #endif // LIB_MODULED_ADAPTOR_H
78 |
--------------------------------------------------------------------------------
/include/mdcomp/bitstream.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2011-2016
3 | *
4 | * This program is free software: you can redistribute it and/or modify it
5 | * under the terms of the GNU Lesser General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the GNU Lesser General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Lesser General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef LIB_BITSTREAM_HH
19 | #define LIB_BITSTREAM_HH
20 |
21 | #include
22 |
23 | #include
24 | #include
25 | #include
26 |
27 | namespace detail {
28 | #if !defined(__clang__)
29 | # if defined(_MSC_VER) && _MSC_VER < 1910
30 | // MSVC compiler is not c++14 compliant before 19.10.
31 | # define CONSTEXPR
32 | # else
33 | # define CONSTEXPR constexpr
34 | # endif
35 | template
36 | constexpr inline T nextMask(T mask) noexcept {
37 | return mask ^ (mask << sz);
38 | }
39 |
40 | template
41 | struct reverseByteBits {
42 | CONSTEXPR inline T operator()(T val, T mask) const noexcept {
43 | constexpr const size_t nsz = sz >> 1;
44 | mask = nextMask(mask);
45 | T val1 = (val & mask);
46 | T val2 = val ^ val1;
47 | constexpr const T factor = T(1) << nsz;
48 | val = factor * val1 + val2 / factor;
49 | return reverseByteBits{}(val, mask);
50 | }
51 | };
52 |
53 | template
54 | struct reverseByteBits {
55 | constexpr inline T operator()(T val, T /*mask*/) const noexcept {
56 | return val;
57 | }
58 | };
59 |
60 | template
61 | struct getMask {
62 | constexpr inline T operator()(T mask) const noexcept {
63 | return getMask> 1)>{}(nextMask> 1)>(mask));
64 | }
65 | };
66 |
67 | template
68 | struct getMask {
69 | constexpr inline T operator()(T mask) const noexcept {
70 | return mask;
71 | }
72 | };
73 | #endif
74 |
75 | template
76 | auto reverseBits(T val) noexcept
77 | -> std::enable_if_t::value, T> {
78 | #ifdef __clang__
79 | if (sizeof(T) == 1) {
80 | val = __builtin_bitreverse8(val);
81 | } else if (sizeof(T) == 2) {
82 | val = __builtin_bitreverse16(val);
83 | } else if (sizeof(T) == 4) {
84 | val = __builtin_bitreverse32(val);
85 | } else if (sizeof(T) == 8) {
86 | val = __builtin_bitreverse64(val);
87 | }
88 | return val;
89 | #else
90 | constexpr size_t sz = CHAR_BIT; // bit size; must be power of 2
91 | constexpr T mask = getMask{}(~T(0));
92 | val = bswap(val);
93 | return reverseByteBits{}(val, mask);
94 | #endif
95 | }
96 |
97 | template
98 | auto reverseBits(T val) noexcept
99 | -> std::enable_if_t::value, T> {
100 | return reverseBits(std::make_unsigned_t(val));
101 | }
102 | } // namespace detail
103 |
104 | // This class allows reading bits from a stream.
105 | // "EarlyRead" means, in this context, to read a new T as soon as the old one
106 | // runs out of bits; the alternative is to read when a new bit is needed.
107 | template <
108 | typename T, bool EarlyRead, bool LittleEndianBits = false,
109 | typename Endian = BigEndian>
110 | class ibitstream {
111 | private:
112 | std::istream& src;
113 | size_t readbits;
114 | T bitbuffer;
115 | size_t read() noexcept {
116 | return Endian::template ReadN(src);
117 | }
118 | T read_bits() noexcept {
119 | T bits = read();
120 | return LittleEndianBits ? detail::reverseBits(bits) : bits;
121 | }
122 | void check_buffer() noexcept {
123 | if (readbits != 0U) {
124 | return;
125 | }
126 |
127 | bitbuffer = read_bits();
128 | readbits = sizeof(T) * CHAR_BIT;
129 | }
130 |
131 | public:
132 | explicit ibitstream(std::istream& s) noexcept
133 | : src(s), readbits(sizeof(T) * CHAR_BIT), bitbuffer(read_bits()) {}
134 | // Gets a single bit from the stream. Remembers previously read bits, and
135 | // gets a new T from the actual stream once all bits in the current T has
136 | // been used up.
137 | T pop() noexcept {
138 | if (!EarlyRead) {
139 | check_buffer();
140 | }
141 | --readbits;
142 | T bit = (bitbuffer >> readbits) & 1U;
143 | bitbuffer ^= (bit << readbits);
144 | if (EarlyRead) {
145 | check_buffer();
146 | }
147 | return bit;
148 | }
149 | // Reads up to sizeof(T) * CHAR_BIT bits from the stream. This remembers
150 | // previously read bits, and gets another T from the actual stream once all
151 | // bits in the current T have been read.
152 | T read(uint8_t const cnt) noexcept {
153 | if (!EarlyRead) {
154 | check_buffer();
155 | }
156 | T bits;
157 | if (readbits < cnt) {
158 | size_t delta = (cnt - readbits);
159 | bits = bitbuffer << delta;
160 | bitbuffer = read_bits();
161 | readbits = (sizeof(T) * CHAR_BIT) - delta;
162 | T newbits = (bitbuffer >> readbits);
163 | bitbuffer ^= (newbits << readbits);
164 | bits |= newbits;
165 | } else {
166 | readbits -= cnt;
167 | bits = bitbuffer >> readbits;
168 | bitbuffer ^= (bits << readbits);
169 | }
170 | if (EarlyRead) {
171 | check_buffer();
172 | }
173 | return bits;
174 | }
175 | size_t have_waiting_bits() const noexcept {
176 | return readbits;
177 | }
178 | };
179 |
180 | // This class allows outputting bits into a stream.
181 | template <
182 | typename T, bool LittleEndianBits = false, typename Endian = BigEndian>
183 | class obitstream {
184 | private:
185 | std::ostream& dst;
186 | size_t waitingbits;
187 | T bitbuffer;
188 |
189 | void write(T const c) noexcept {
190 | Endian::template WriteN(dst, c);
191 | }
192 | void write_bits(T const bits) noexcept {
193 | write(LittleEndianBits ? detail::reverseBits(bits) : bits);
194 | }
195 |
196 | public:
197 | explicit obitstream(std::ostream& d) noexcept
198 | : dst(d), waitingbits(0), bitbuffer(0) {}
199 | // Puts a single bit into the stream. Remembers previously written bits, and
200 | // outputs a T to the actual stream once there are at least sizeof(T) *
201 | // CHAR_BIT bits stored in the buffer.
202 | bool push(T const data) noexcept {
203 | bitbuffer = (bitbuffer << 1U) | (data & 1U);
204 | if (++waitingbits >= sizeof(T) * CHAR_BIT) {
205 | write_bits(bitbuffer);
206 | waitingbits = 0;
207 | bitbuffer = 0;
208 | return true;
209 | }
210 | return false;
211 | }
212 | // Writes up to sizeof(T) * CHAR_BIT bits to the stream. This remembers
213 | // previously written bits, and outputs a T to the actual stream once there
214 | // are at least sizeof(T) * CHAR_BIT bits stored in the buffer.
215 | bool write(T const data, uint8_t const size) noexcept {
216 | if (waitingbits + size >= sizeof(T) * CHAR_BIT) {
217 | size_t delta = (sizeof(T) * CHAR_BIT - waitingbits);
218 | waitingbits = (waitingbits + size) % (sizeof(T) * CHAR_BIT);
219 | T bits = (bitbuffer << delta) | (data >> waitingbits);
220 | write_bits(bits);
221 | constexpr const T ones = std::numeric_limits::max();
222 | bitbuffer = (data & (ones >> (sizeof(T) * CHAR_BIT - waitingbits)));
223 | return true;
224 | }
225 | bitbuffer = (bitbuffer << size) | data;
226 | waitingbits += size;
227 | return false;
228 | }
229 | // Flushes remaining bits (if any) to the buffer, completing the byte by
230 | // padding with zeroes.
231 | bool flush() noexcept {
232 | if (waitingbits != 0U) {
233 | bitbuffer <<= ((sizeof(T) * CHAR_BIT) - waitingbits);
234 | write_bits(bitbuffer);
235 | waitingbits = 0;
236 | return true;
237 | }
238 | return false;
239 | }
240 | size_t have_waiting_bits() const noexcept {
241 | return waitingbits;
242 | }
243 | };
244 |
245 | #endif // LIB_BITSTREAM_HH
246 |
--------------------------------------------------------------------------------
/include/mdcomp/comper.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2013-2016
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef LIB_COMPER_HH
20 | #define LIB_COMPER_HH
21 |
22 | #include
23 | #include
24 |
25 | #include
26 |
27 | class comper;
28 | using basic_comper = BasicDecoder;
29 | using moduled_comper = ModuledAdaptor;
30 |
31 | class comper : public basic_comper, public moduled_comper {
32 | friend basic_comper;
33 | friend moduled_comper;
34 | static bool encode(std::ostream& Dst, uint8_t const* data, size_t Size);
35 |
36 | public:
37 | using basic_comper::encode;
38 | static bool decode(std::istream& Src, std::iostream& Dst);
39 | };
40 |
41 | #endif // LIB_COMPER_HH
42 |
--------------------------------------------------------------------------------
/include/mdcomp/comperx.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2013-2016
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef LIB_COMPERX_HH
20 | #define LIB_COMPERX_HH
21 |
22 | #include
23 | #include
24 |
25 | #include
26 |
27 | class comperx;
28 | using basic_comperx = BasicDecoder;
29 | using moduled_comperx = ModuledAdaptor;
30 |
31 | class comperx : public basic_comperx, public moduled_comperx {
32 | friend basic_comperx;
33 | friend moduled_comperx;
34 | static bool encode(std::ostream& Dst, uint8_t const* data, size_t Size);
35 |
36 | public:
37 | using basic_comperx::encode;
38 | static bool decode(std::istream& Src, std::iostream& Dst);
39 | };
40 |
41 | #endif // LIB_COMPERX_HH
42 |
--------------------------------------------------------------------------------
/include/mdcomp/enigma.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2011-2016
3 | * Copyright (C) 2002-2004 The KENS Project Development Team
4 | * Copyright (C) 2002-2003 Roger Sanders (AKA Nemesis)
5 | *
6 | * This program is free software: you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published
8 | * by the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful, but
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 | * See the GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #ifndef LIB_ENIGMA_HH
21 | #define LIB_ENIGMA_HH
22 |
23 | #include
24 | #include
25 |
26 | #include
27 |
28 | class enigma;
29 | using basic_enigma = BasicDecoder;
30 | using moduled_enigma = ModuledAdaptor;
31 |
32 | class enigma : public basic_enigma, public moduled_enigma {
33 | friend basic_enigma;
34 | friend moduled_enigma;
35 | static bool encode(std::ostream& Dst, uint8_t const* data, size_t Size);
36 |
37 | public:
38 | static bool encode(std::istream& Src, std::ostream& Dst);
39 | static bool decode(std::istream& Src, std::ostream& Dst);
40 | };
41 |
42 | #endif // LIB_ENIGMA_HH
43 |
--------------------------------------------------------------------------------
/include/mdcomp/ignore_unused_variable_warning.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2016
3 | *
4 | * This program is free software: you can redistribute it and/or modify it
5 | * under the terms of the GNU Lesser General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the GNU Lesser General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Lesser General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef LIB_IGNORE_UNUSED_VARIABLE_WARNING_HH
19 | #define LIB_IGNORE_UNUSED_VARIABLE_WARNING_HH
20 |
21 | template
22 | constexpr inline void ignore_unused_variable_warning(T const&...) {}
23 |
24 | #endif // LIB_IGNORE_UNUSED_VARIABLE_WARNING_HH
25 |
--------------------------------------------------------------------------------
/include/mdcomp/kosinski.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2011-2016
3 | * Copyright (C) 2002-2004 The KENS Project Development Team
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef LIB_KOSINSKI_HH
20 | #define LIB_KOSINSKI_HH
21 |
22 | #include
23 | #include
24 |
25 | #include
26 |
27 | class kosinski;
28 | using basic_kosinski = BasicDecoder;
29 | using moduled_kosinski = ModuledAdaptor;
30 |
31 | class kosinski : public basic_kosinski, public moduled_kosinski {
32 | friend basic_kosinski;
33 | friend moduled_kosinski;
34 | static bool encode(std::ostream& Dst, uint8_t const* data, size_t Size);
35 |
36 | public:
37 | using basic_kosinski::encode;
38 | static bool decode(std::istream& Src, std::iostream& Dst);
39 | };
40 |
41 | #endif // LIB_KOSINSKI_HH
42 |
--------------------------------------------------------------------------------
/include/mdcomp/kosplus.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2015-2016
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef LIB_KOSPLUS_HH
20 | #define LIB_KOSPLUS_HH
21 |
22 | #include
23 | #include
24 |
25 | #include
26 |
27 | class kosplus;
28 | using basic_kosplus = BasicDecoder;
29 | using moduled_kosplus = ModuledAdaptor;
30 |
31 | class kosplus : public basic_kosplus, public moduled_kosplus {
32 | friend basic_kosplus;
33 | friend moduled_kosplus;
34 | static bool encode(std::ostream& Dst, uint8_t const* data, size_t Size);
35 |
36 | public:
37 | using basic_kosplus::encode;
38 | static bool decode(std::istream& Src, std::iostream& Dst);
39 | };
40 |
41 | #endif // LIB_KOSPLUS_HH
42 |
--------------------------------------------------------------------------------
/include/mdcomp/lzkn1.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2011-2016
3 | * Copyright (C) 2002-2004 The KENS Project Development Team
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef LIB_LZKN1_HH
20 | #define LIB_LZKN1_HH
21 |
22 | #include
23 | #include
24 |
25 | #include
26 |
27 | class lzkn1;
28 | using basic_lzkn1 = BasicDecoder;
29 | using moduled_lzkn1 = ModuledAdaptor;
30 |
31 | class lzkn1 : public basic_lzkn1, public moduled_lzkn1 {
32 | friend basic_lzkn1;
33 | friend moduled_lzkn1;
34 | static bool encode(std::ostream& Dst, uint8_t const* data, size_t Size);
35 |
36 | public:
37 | using basic_lzkn1::encode;
38 | static bool decode(std::istream& Src, std::iostream& Dst);
39 | };
40 |
41 | #endif // LIB_LZKN1_HH
42 |
--------------------------------------------------------------------------------
/include/mdcomp/moduled_adaptor.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2016
3 | *
4 | *
5 | * This program is free software; you can redistribute it and/or
6 | * modify it under the terms of the GNU Lesser General Public
7 | * License as published by the Free Software Foundation; either
8 | * version 2.1 of the License, or (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 | * Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public
16 | * License along with main.c; if not, write to the Free Software
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
18 | */
19 |
20 | #ifndef LIB_MODULED_ADAPTOR_HH
21 | #define LIB_MODULED_ADAPTOR_HH
22 |
23 | #include
24 |
25 | #include
26 | #include
27 | #include
28 |
29 | template <
30 | typename Format, size_t DefaultModuleSize, size_t DefaultModulePadding>
31 | class ModuledAdaptor {
32 | public:
33 | enum {
34 | ModuleSize = DefaultModuleSize,
35 | ModulePadding = DefaultModulePadding
36 | };
37 | static size_t PadMaskBits;
38 | static bool moduled_decode(
39 | std::istream& Src, std::iostream& Dst,
40 | size_t ModulePadding = DefaultModulePadding);
41 |
42 | static bool moduled_encode(
43 | std::istream& Src, std::ostream& Dst,
44 | size_t ModulePadding = DefaultModulePadding);
45 | };
46 |
47 | template <
48 | typename Format, size_t DefaultModuleSize, size_t DefaultModulePadding>
49 | bool ModuledAdaptor::
50 | moduled_decode(
51 | std::istream& Src, std::iostream& Dst,
52 | size_t const ModulePadding) {
53 | int64_t const FullSize = BigEndian::Read2(Src);
54 | std::stringstream in(std::ios::in | std::ios::out | std::ios::binary);
55 | in << Src.rdbuf();
56 |
57 | // Pad to even length, for safety.
58 | if ((in.tellp() % 2) != 0) {
59 | in.put(0);
60 | }
61 |
62 | in.seekg(0);
63 | size_t const PadMask = ModulePadding - 1;
64 |
65 | while (true) {
66 | Format::decode(in, Dst);
67 | if (Dst.tellp() >= FullSize) {
68 | break;
69 | }
70 |
71 | // Skip padding between modules
72 | size_t const paddingEnd = (size_t(in.tellg()) + PadMask) & ~PadMask;
73 | in.seekg(paddingEnd);
74 | }
75 |
76 | return true;
77 | }
78 |
79 | template <
80 | typename Format, size_t DefaultModuleSize, size_t DefaultModulePadding>
81 | bool ModuledAdaptor::
82 | moduled_encode(
83 | std::istream& Src, std::ostream& Dst,
84 | size_t const ModulePadding) {
85 | size_t Location = Src.tellg();
86 | Src.ignore(std::numeric_limits::max());
87 | size_t FullSize = Src.gcount();
88 | Src.seekg(Location);
89 | std::vector data;
90 | data.resize(FullSize);
91 | auto ptr = data.cbegin();
92 | Src.read(reinterpret_cast(&(data.front())), data.size());
93 |
94 | size_t const PadMask = ModulePadding - 1;
95 |
96 | BigEndian::Write2(Dst, FullSize);
97 | std::stringstream sout(std::ios::in | std::ios::out | std::ios::binary);
98 |
99 | while (FullSize > ModuleSize) {
100 | // We want to manage internal padding for all modules but the last.
101 | PadMaskBits = 8 * ModulePadding - 1U;
102 | Format::encode(sout, &(*ptr), ModuleSize);
103 | FullSize -= ModuleSize;
104 | ptr += ModuleSize;
105 |
106 | // Padding between modules
107 | int64_t const paddingEnd = (size_t(sout.tellp()) + PadMask) & ~PadMask;
108 | for (; sout.tellp() < paddingEnd; sout.put(0)) {
109 | }
110 | }
111 |
112 | PadMaskBits = 7U;
113 | Format::encode(sout, &(*ptr), FullSize);
114 |
115 | // Pad to even size.
116 | Dst << sout.rdbuf();
117 | if ((Dst.tellp() % 2) != 0) {
118 | Dst.put(0);
119 | }
120 | return true;
121 | }
122 |
123 | #endif // LIB_MODULED_ADAPTOR_HH
124 |
--------------------------------------------------------------------------------
/include/mdcomp/nemesis.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2011-2016
3 | * Loosely based on code by Roger Sanders (AKA Nemesis) and William Sanders
4 | * (AKA Milamber)
5 | *
6 | * This program is free software: you can redistribute it and/or modify it
7 | * under the terms of the GNU Lesser General Public License as published
8 | * by the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful, but
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 | * See the GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #ifndef LIB_NEMESIS_HH
21 | #define LIB_NEMESIS_HH
22 |
23 | #include
24 | #include
25 |
26 | #include
27 |
28 | class nemesis;
29 | using basic_nemesis = BasicDecoder;
30 | using moduled_nemesis = ModuledAdaptor;
31 |
32 | class nemesis : public basic_nemesis, public moduled_nemesis {
33 | friend basic_nemesis;
34 | friend moduled_nemesis;
35 | static bool encode(std::ostream& Dst, uint8_t const* data, size_t Size);
36 |
37 | public:
38 | static bool encode(std::istream& Src, std::ostream& Dst);
39 | static bool decode(std::istream& Src, std::ostream& Dst);
40 | };
41 |
42 | #endif // LIB_NEMESIS_HH
43 |
--------------------------------------------------------------------------------
/include/mdcomp/rocket.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Clownacy 2016
3 | * Copyright (C) Flamewing 2016
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef LIB_ROCKET_HH
20 | #define LIB_ROCKET_HH
21 |
22 | #include
23 | #include
24 |
25 | #include
26 |
27 | class rocket;
28 | using basic_rocket = BasicDecoder;
29 | using moduled_rocket = ModuledAdaptor;
30 |
31 | class rocket : public basic_rocket, public moduled_rocket {
32 | friend basic_rocket;
33 | friend moduled_rocket;
34 | static bool encode(std::ostream& Dst, uint8_t const* data, size_t Size);
35 |
36 | public:
37 | static bool encode(std::istream& Src, std::ostream& Dst);
38 | static bool decode(std::istream& Src, std::iostream& Dst);
39 | };
40 |
41 | #endif // LIB_ROCKET_HH
42 |
--------------------------------------------------------------------------------
/include/mdcomp/saxman.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2013-2016
3 | * Very loosely based on code by the KENS Project Development Team
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef LIB_SAXMAN_HH
20 | #define LIB_SAXMAN_HH
21 |
22 | #include
23 | #include
24 |
25 | #include
26 |
27 | class saxman;
28 | using basic_saxman = BasicDecoder;
29 | using moduled_saxman = ModuledAdaptor;
30 |
31 | class saxman : public basic_saxman, public moduled_saxman {
32 | friend basic_saxman;
33 | friend moduled_saxman;
34 | static bool encode(
35 | std::ostream& Dst, uint8_t const* data, size_t Size,
36 | bool WithSize = true);
37 |
38 | public:
39 | using basic_saxman::encode;
40 | static bool decode(std::istream& Src, std::iostream& Dst, size_t Size = 0);
41 | };
42 |
43 | #endif // LIB_SAXMAN_HH
44 |
--------------------------------------------------------------------------------
/include/mdcomp/snkrle.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2017
3 | * Loosely based on code by snkenjoi
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #ifndef LIB_SNKRLE_HH
20 | #define LIB_SNKRLE_HH
21 |
22 | #include
23 | #include
24 |
25 | #include
26 |
27 | class snkrle;
28 | using basic_snkrle = BasicDecoder;
29 | using moduled_snkrle = ModuledAdaptor;
30 |
31 | class snkrle : public basic_snkrle, public moduled_snkrle {
32 | friend basic_snkrle;
33 | friend moduled_snkrle;
34 | static bool encode(std::ostream& Dst, uint8_t const* data, size_t Size);
35 |
36 | public:
37 | using basic_snkrle::encode;
38 | static bool decode(std::istream& Src, std::ostream& Dst);
39 | };
40 |
41 | #endif // LIB_SNKRLE_HH
42 |
--------------------------------------------------------------------------------
/include/mdcomp/unreachable.hh:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2016
3 | *
4 | * This program is free software: you can redistribute it and/or modify it
5 | * under the terms of the GNU Lesser General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the GNU Lesser General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Lesser General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef LIB_UNREACHABLE_HH
19 | #define LIB_UNREACHABLE_HH
20 |
21 | #ifdef _MSC_VER
22 | # ifndef __clang__
23 | [[noreturn]] inline void __builtin_unreachable() {
24 | __assume(false);
25 | }
26 | # endif
27 | #endif
28 |
29 | #endif // LIB_UNREACHABLE_HH
30 |
--------------------------------------------------------------------------------
/src/asm/Comper.asm:
--------------------------------------------------------------------------------
1 | ; ---------------------------------------------------------------------------
2 | ; Original version written by vladikcomper, with improvements by Flamewing
3 | ; ---------------------------------------------------------------------------
4 | ; Permission to use, copy, modify, and/or distribute this software for any
5 | ; purpose with or without fee is hereby granted.
6 | ;
7 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 | ; OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 | ; ---------------------------------------------------------------------------
15 | ; FUNCTION:
16 | ; CompDec
17 | ;
18 | ; DESCRIPTION
19 | ; Comper Decompressor
20 | ;
21 | ; INPUT:
22 | ; a0 Source address
23 | ; a1 Destination address
24 | ; ---------------------------------------------------------------------------
25 | _Comp_LoopUnroll = 3
26 |
27 | _Comp_RunBitStream macro
28 | dbra d3,.mainloop ; if bits counter remains, parse the next word
29 | bra.ATTRIBUTE .newblock ; start a new block
30 | endm
31 |
32 | _Comp_ReadBit macro
33 | add.w d0,d0 ; roll description field
34 | endm
35 | ; ===========================================================================
36 |
37 |
38 | ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
39 | ; ---------------------------------------------------------------------------
40 | CompDec:
41 | if _Comp_LoopUnroll>0
42 | moveq #(1<<_Comp_LoopUnroll)-1,d7
43 | endif
44 |
45 | .newblock:
46 | move.w (a0)+,d0 ; fetch description field
47 | moveq #15,d3 ; set bits counter to 16
48 |
49 | .mainloop:
50 | _Comp_ReadBit
51 | bcs.s .flag ; if a flag issued, branch
52 | move.w (a0)+,(a1)+ ; otherwise, do uncompressed data
53 | _Comp_RunBitStream.s
54 | ; ---------------------------------------------------------------------------
55 | .flag:
56 | moveq #-1,d1 ; init displacement
57 | move.b (a0)+,d1 ; load displacement
58 | add.w d1,d1
59 | moveq #0,d2 ; init copy count
60 | move.b (a0)+,d2 ; load copy length
61 | beq.s .end ; if zero, branch
62 | lea (a1,d1.w),a2 ; load start copy address
63 | if _Comp_LoopUnroll>0
64 | move.w d2,d4
65 | not.w d4
66 | and.w d7,d4
67 | add.w d4,d4
68 | lsr.w #_Comp_LoopUnroll,d2
69 | jmp .loop(pc,d4.w)
70 | endif
71 | ; ---------------------------------------------------------------------------
72 | .loop:
73 | rept (1<<_Comp_LoopUnroll)
74 | move.w (a2)+,(a1)+ ; copy given sequence
75 | endm
76 | dbra d2,.loop ; repeat
77 | _Comp_RunBitStream.s
78 | ; ---------------------------------------------------------------------------
79 | .end:
80 | rts
81 | ; ===========================================================================
82 |
83 |
--------------------------------------------------------------------------------
/src/asm/ComperX.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Comper-X a newer, much faster implementation of Comper compression
3 | ;
4 | ; (c) 2021, vladikcomper
5 | ; -----------------------------------------------------------------------------
6 | ; Permission to use, copy, modify, and/or distribute this software for any
7 | ; purpose with or without fee is hereby granted.
8 | ;
9 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 | ; OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 | ; -----------------------------------------------------------------------------
17 | ; INPUT:
18 | ; a0 - Source Offset
19 | ; a1 - Destination Offset
20 | ;
21 | ; USES:
22 | ; d0-d4, a2
23 | ; -----------------------------------------------------------------------------
24 |
25 | ; -----------------------------------------------------------------------------
26 | ; Copy device for RLE transfers
27 | ;
28 | ; This is located above the compressor for accesibility reasons.
29 | ; -----------------------------------------------------------------------------
30 |
31 | rts ; copy length = 0 stops decompression
32 | rept 127
33 | move.l d4, (a1)+
34 | endm
35 | ComperXDec_CopyDevice_RLE:
36 | dbf d3, ComperXDec.fetch_flag ; if bits counter remains, parse the next word
37 | ;bra ComperXDec.load_flags_field ; ... fall through ...
38 |
39 | ; -----------------------------------------------------------------------------
40 | ; Decompressor starts here ...
41 | ; -----------------------------------------------------------------------------
42 |
43 | ComperXDec:
44 | moveq #-1, d1 ; d1 is used for negative sign-extended displacement
45 | moveq #0, d2 ; d2 is used as 8-bit index for copy jump tables
46 |
47 | .load_flags_field:
48 | moveq #16-1, d3 ; d3 = description field bits counter
49 | move.w (a0)+, d0 ; d0 = description field data
50 |
51 | .fetch_flag:
52 | add.w d0, d0 ; roll description field
53 | bcs.s .flag ; if a flag issued, branch
54 | move.w (a0)+, (a1)+ ; otherwise, do uncompressed data
55 |
56 | .flag_next:
57 | dbf d3, .fetch_flag ; if bits counter remains, parse the next word
58 | bra.s .load_flags_field ; start a new block
59 | ; -----------------------------------------------------------------------------
60 | .end:
61 | rts
62 | ; -----------------------------------------------------------------------------
63 | .flag: move.b (a0)+, d1 ; d1 = Displacement (words) (sign-extended)
64 | beq.s .copy_rle ; displacement value of 0 (-1) triggers RLE mode
65 | move.b (a0)+, d2 ; d2 = Copy length field
66 |
67 | add.w d1, d1 ; d1 = Displacement * 2 (sign-extended)
68 | lea -2(a1,d1.w), a2 ; a2 = Start copy address
69 |
70 | moveq #-1, d1 ; restore the value of d1 now ...
71 | add.b d2, d2 ; test MSB of copy length field ...
72 | bcc.s .copy_long_start ; if not set, then transfer is even words, branch ...
73 | move.w (a2)+, (a1)+ ; otherwise, copy odd word before falling into longwords loop ...
74 |
75 | .copy_long_start:
76 | jmp ComperXDec_CopyDevice(pc,d2.w) ; d2 = 0..$FE
77 | ; -----------------------------------------------------------------------------
78 | .copy_rle:
79 | move.b (a0)+, d1 ; d1 = - $100 + Copy length
80 |
81 | move.w -(a1), d4
82 | swap d4
83 | move.w (a1)+, d4 ; d4 = data to copy
84 |
85 | add.b d1, d1 ; test MSB of copy length field ...
86 | bcc.s .copy_long_rle_start ; if not set, then transfer is even words, branch ...
87 | move.w d4, (a1)+ ; otherwise, copy odd word before falling into longwords loop ...
88 |
89 | .copy_long_rle_start:
90 | jmp ComperXDec_CopyDevice_RLE(pc,d1.w) ; d1 = -$100..-2
91 | ; =============================================================================
92 |
93 | ; -----------------------------------------------------------------------------
94 | ; Copy device for RLE transfers
95 | ;
96 | ; This is located below the compressor for accesibility reasons.
97 | ; -----------------------------------------------------------------------------
98 |
99 | ComperXDec_CopyDevice:
100 | rts ; copy length = 0 stops decompression
101 | ; -----------------------------------------------------------------------------
102 | rept 127
103 | move.l (a2)+, (a1)+
104 | endm
105 | dbf d3, ComperXDec.fetch_flag ; if bits counter remains, parse the next word
106 | bra ComperXDec.load_flags_field
107 | ; =============================================================================
108 |
109 | ; =============================================================================
110 | ; -----------------------------------------------------------------------------
111 | ; Subroutine to decompress Moduled Comper-X
112 | ; -----------------------------------------------------------------------------
113 | ; INPUT:
114 | ; a0 - Source Offset
115 | ; a1 - Destination buffer
116 | ; -----------------------------------------------------------------------------
117 |
118 | ComperXMDec:
119 | lea ComperXDec(pc), a3
120 | move.w (a0)+, d0
121 | subq.w #1, d0 ; this is a trick to reduce number of blocks by one if size is modulo $1000
122 | rol.w #5, d0
123 | and.w #$1E, d0 ; d0 = Number of blocks to decompress * 2 (0..1E)
124 | neg.w d0
125 | jmp .decompress_device(pc,d0)
126 | ; -----------------------------------------------------------------------------
127 | rept 16-1
128 | jsr (a3)
129 | endm
130 | .decompress_device:
131 | jmp (a3)
132 | ; =============================================================================
133 |
134 |
--------------------------------------------------------------------------------
/src/asm/Enigma.asm:
--------------------------------------------------------------------------------
1 | ; ---------------------------------------------------------------------------
2 | ; For format explanation see https://segaretro.org/Enigma_compression
3 | ; ---------------------------------------------------------------------------
4 | ; Permission to use, copy, modify, and/or distribute this software for any
5 | ; purpose with or without fee is hereby granted.
6 | ;
7 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 | ; OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 | ; ---------------------------------------------------------------------------
15 | ; FUNCTION:
16 | ; EniDec
17 | ;
18 | ; DESCRIPTION
19 | ; Enigma Decompressor
20 | ;
21 | ; INPUT:
22 | ; d0 Starting pattern name (added to each 8x8 before writing to destination)
23 | ; a0 Source address
24 | ; a1 Destination address
25 | ; ---------------------------------------------------------------------------
26 |
27 | flip_x = (1<<11)
28 | flip_y = (1<<12)
29 | palette_line_1 = (1<<13)
30 | palette_line_2 = (2<<13)
31 | high_priority = (1<<15)
32 |
33 | ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
34 | ; ---------------------------------------------------------------------------
35 | EniDec:
36 | movem.l d0-d7/a1-a5,-(sp)
37 | movea.w d0,a3 ; store starting art tile
38 | move.b (a0)+,d0
39 | ext.w d0
40 | movea.w d0,a5 ; store first byte, extended to word
41 | move.b (a0)+,d4 ; store second byte
42 | lsl.b #3,d4 ; multiply by 8
43 | movea.w (a0)+,a2 ; store third and fourth byte
44 | adda.w a3,a2 ; add starting art tile
45 | movea.w (a0)+,a4 ; store fifth and sixth byte
46 | adda.w a3,a4 ; add starting art tile
47 | move.b (a0)+,d5 ; store seventh byte
48 | asl.w #8,d5 ; shift up by a byte
49 | move.b (a0)+,d5 ; store eighth byte in lower register byte
50 | moveq #16,d6 ; 16 bits = 2 bytes
51 |
52 | EniDec_Loop:
53 | moveq #7,d0 ; process 7 bits at a time
54 | move.w d6,d7
55 | sub.w d0,d7
56 | move.w d5,d1
57 | lsr.w d7,d1
58 | andi.w #$7F,d1 ; keep only lower 7 bits
59 | move.w d1,d2
60 | cmpi.w #$40,d1 ; is bit 6 set?
61 | bhs.s .got_field ; if it is, branch
62 | moveq #6,d0 ; if not, process 6 bits instead of 7
63 | lsr.w #1,d2 ; bitfield now becomes TTSSSS instead of TTTSSSS
64 |
65 | .got_field:
66 | bsr.w EniDec_ChkGetNextByte
67 | andi.w #$F,d2 ; keep only lower nybble
68 | lsr.w #4,d1 ; store upper nybble (max value = 7)
69 | add.w d1,d1
70 | jmp EniDec_JmpTable(pc,d1.w)
71 | ; ---------------------------------------------------------------------------
72 | EniDec_Sub0:
73 | move.w a2,(a1)+ ; write to destination
74 | addq.w #1,a2 ; increment
75 | dbra d2,EniDec_Sub0 ; repeat
76 | bra.s EniDec_Loop
77 | ; ---------------------------------------------------------------------------
78 | EniDec_Sub4:
79 | move.w a4,(a1)+ ; write to destination
80 | dbra d2,EniDec_Sub4 ; repeat
81 | bra.s EniDec_Loop
82 | ; ---------------------------------------------------------------------------
83 | EniDec_Sub8:
84 | bsr.w EniDec_GetInlineCopyVal
85 |
86 | .loop:
87 | move.w d1,(a1)+
88 | dbra d2,.loop
89 |
90 | bra.s EniDec_Loop
91 | ; ---------------------------------------------------------------------------
92 | EniDec_SubA:
93 | bsr.w EniDec_GetInlineCopyVal
94 |
95 | .loop:
96 | move.w d1,(a1)+
97 | addq.w #1,d1
98 | dbra d2,.loop
99 |
100 | bra.s EniDec_Loop
101 | ; ---------------------------------------------------------------------------
102 | EniDec_SubC:
103 | bsr.w EniDec_GetInlineCopyVal
104 |
105 | .loop:
106 | move.w d1,(a1)+
107 | subq.w #1,d1
108 | dbra d2,.loop
109 |
110 | bra.s EniDec_Loop
111 | ; ---------------------------------------------------------------------------
112 | EniDec_SubE:
113 | cmpi.w #$F,d2
114 | beq.s EniDec_End
115 |
116 | .loop:
117 | bsr.w EniDec_GetInlineCopyVal
118 | move.w d1,(a1)+
119 | dbra d2,.loop
120 |
121 | bra.s EniDec_Loop
122 | ; ---------------------------------------------------------------------------
123 | ; Enigma_JmpTable:
124 | EniDec_JmpTable:
125 | bra.s EniDec_Sub0
126 | bra.s EniDec_Sub0
127 | bra.s EniDec_Sub4
128 | bra.s EniDec_Sub4
129 | bra.s EniDec_Sub8
130 | bra.s EniDec_SubA
131 | bra.s EniDec_SubC
132 | bra.s EniDec_SubE
133 | ; ---------------------------------------------------------------------------
134 | EniDec_End:
135 | subq.w #1,a0
136 | cmpi.w #16,d6 ; were we going to start on a completely new byte?
137 | bne.s .got_byte ; if not, branch
138 | subq.w #1,a0
139 |
140 | .got_byte:
141 | move.w a0,d0
142 | lsr.w #1,d0 ; are we on an odd byte?
143 | bhs.s .even_loc ; if not, branch
144 | addq.w #1,a0 ; ensure we're on an even byte
145 |
146 | .even_loc:
147 | movem.l (sp)+,d0-d7/a1-a5
148 | rts
149 | ; End of function EniDec
150 | ; ===========================================================================
151 |
152 | ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
153 | ; ---------------------------------------------------------------------------
154 | EniDec_GetInlineCopyVal:
155 | move.w a3,d3 ; store starting art tile
156 | move.b d4,d1
157 | add.b d1,d1
158 | bhs.s .skip_pri ; if d4 was < $80
159 | subq.w #1,d6 ; get next bit number
160 | btst d6,d5 ; is the bit set?
161 | beq.s .skip_pri ; if not, branch
162 | ori.w #high_priority,d3 ; set high priority bit
163 |
164 | .skip_pri:
165 | add.b d1,d1
166 | bhs.s .skip_pal2 ; if d4 was < $40
167 | subq.w #1,d6 ; get next bit number
168 | btst d6,d5
169 | beq.s .skip_pal2
170 | addi.w #palette_line_2,d3 ; set second palette line bit
171 |
172 | .skip_pal2:
173 | add.b d1,d1
174 | bhs.s .skip_pal1 ; if d4 was < $20
175 | subq.w #1,d6 ; get next bit number
176 | btst d6,d5
177 | beq.s .skip_pal1
178 | addi.w #palette_line_1,d3 ; set first palette line bit
179 |
180 | .skip_pal1:
181 | add.b d1,d1
182 | bhs.s .skip_flipy ; if d4 was < $10
183 | subq.w #1,d6 ; get next bit number
184 | btst d6,d5
185 | beq.s .skip_flipy
186 | ori.w #flip_y,d3 ; set Y-flip bit
187 |
188 | .skip_flipy:
189 | add.b d1,d1
190 | bhs.s .skip_flipx ; if d4 was < 8
191 | subq.w #1,d6
192 | btst d6,d5
193 | beq.s .skip_flipx
194 | ori.w #flip_x,d3 ; set X-flip bit
195 |
196 | .skip_flipx:
197 | move.w d5,d1
198 | move.w d6,d7 ; get remaining bits
199 | sub.w a5,d7 ; subtract minimum bit number
200 | bhs.s .got_enough ; if we're beyond that, branch
201 | move.w d7,d6
202 | addi.w #16,d6 ; 16 bits = 2 bytes
203 | neg.w d7 ; calculate bit deficit
204 | lsl.w d7,d1 ; make space for this many bits
205 | move.b (a0),d5 ; get next byte
206 | rol.b d7,d5 ; make the upper X bits the lower X bits
207 | add.w d7,d7
208 | and.w EniDec_AndVals-2(pc,d7.w),d5 ; only keep X lower bits
209 | add.w d5,d1 ; compensate for the bit deficit
210 |
211 | .got_field:
212 | move.w a5,d0
213 | add.w d0,d0
214 | and.w EniDec_AndVals-2(pc,d0.w),d1 ; only keep as many bits as required
215 | add.w d3,d1 ; add starting art tile
216 | move.b (a0)+,d5 ; get current byte, move onto next byte
217 | lsl.w #8,d5 ; shift up by a byte
218 | move.b (a0)+,d5 ; store next byte in lower register byte
219 | rts
220 | ; ---------------------------------------------------------------------------
221 | .got_enough:
222 | beq.s .got_exact ; if the exact number of bits are leftover, branch
223 | lsr.w d7,d1 ; remove unneeded bits
224 | move.w a5,d0
225 | add.w d0,d0
226 | and.w EniDec_AndVals-2(pc,d0.w),d1 ; only keep as many bits as required
227 | add.w d3,d1 ; add starting art tile
228 | move.w a5,d0 ; store number of bits used up by inline copy
229 | bra.s EniDec_ChkGetNextByte ; move onto next byte
230 | ; ---------------------------------------------------------------------------
231 | .got_exact:
232 | moveq #16,d6 ; 16 bits = 2 bytes
233 | bra.s .got_field
234 | ; ---------------------------------------------------------------------------
235 | EniDec_AndVals:
236 | dc.w 1, 3, 7, $F
237 | dc.w $1F, $3F, $7F, $FF
238 | dc.w $1FF, $3FF, $7FF, $FFF
239 | dc.w $1FFF,$3FFF,$7FFF,$FFFF
240 | ; End of function EniDec_GetInlineCopyVal
241 | ; ===========================================================================
242 |
243 | ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
244 | ; ---------------------------------------------------------------------------
245 | EniDec_ChkGetNextByte:
246 | sub.w d0,d6
247 | cmpi.w #9,d6
248 | bhs.s .done
249 | addq.w #8,d6 ; 8 bits = 1 byte
250 | asl.w #8,d5 ; shift up by a byte
251 | move.b (a0)+,d5 ; store next byte in lower register byte
252 |
253 | .done:
254 | rts
255 | ; End of function EniDec_ChkGetNextByte
256 | ; ===========================================================================
257 |
258 |
--------------------------------------------------------------------------------
/src/asm/Kosinski.a80:
--------------------------------------------------------------------------------
1 | ; ---------------------------------------------------------------------------
2 | ; For format explanation see https://segaretro.org/Kosinski_compression
3 | ; New faster version written by vladikcomper, with additional improvements
4 | ; by MarkeyJester and Flamewing
5 | ; ---------------------------------------------------------------------------
6 | ; Permission to use, copy, modify, and/or distribute this software for any
7 | ; purpose with or without fee is hereby granted.
8 | ;
9 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 | ; OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 | ; ---------------------------------------------------------------------------
17 | ; FUNCTION:
18 | ; zKosDec
19 | ;
20 | ; DESCRIPTION
21 | ; Kosinski Decompressor
22 | ;
23 | ; INPUT:
24 | ; hl source address
25 | ; de destination address
26 | ; ---------------------------------------------------------------------------
27 | ; Reads 2 bytes from input and sets number of bits remaining to 16
28 | _zKos_ReadDescriptor macro
29 | ld b, (hl) ; Get desc field hi-byte.
30 | inc hl
31 | ld c, (hl) ; Get desc field low-byte.
32 | inc hl
33 | ld a, 16 ; Set repeat count to 16.
34 | endm
35 |
36 | ; Decrements bit count and reloads a new descriptor field if needed
37 | _zKos_RunBitStream macro
38 | ex af, af' ; Save flags, get bit count
39 | dec a ; Have all 16 bits been used up?
40 | jr nz, .skip ; Branch if not.
41 | _zKos_ReadDescriptor
42 | .skip
43 | ex af, af' ; Save bit count, restore flags
44 | endm
45 |
46 | ; Reads a bit from bc into carry
47 | _zKos_ReadBit macro
48 | rr b ; Get a bit from b...
49 | rr c ; ... put it on c and get a bit from c
50 | endm
51 | ; ===========================================================================
52 | ; KozDec_193A:
53 | zKosDec:
54 | _zKos_ReadDescriptor
55 | ex af, af' ; Save bit count
56 | jr .FetchNewCode
57 | ; ---------------------------------------------------------------------------
58 | .FetchCodeLoop:
59 | ; Code 1 (Uncompressed byte).
60 | _zKos_RunBitStream
61 | ldi
62 | inc bc ; Compensate for ldi
63 |
64 | .FetchNewCode:
65 | _zKos_ReadBit
66 | jr c, .FetchCodeLoop ; If code = 1, branch.
67 |
68 | ; Codes 00 and 01.
69 | _zKos_RunBitStream
70 | _zKos_ReadBit
71 | jr c, .Code_01
72 |
73 | ; Code 00 (Dictionary ref. short).
74 | xor a
75 | _zKos_RunBitStream
76 | _zKos_ReadBit
77 | rla
78 | _zKos_RunBitStream
79 | _zKos_ReadBit
80 | rla
81 | _zKos_RunBitStream
82 | push bc ; Save bitstream bits
83 | ld c, (hl) ; Get the displacement byte
84 | inc hl ; Move past the displacement byte
85 | ld b, -1 ; bc = displacement
86 |
87 | .StreamCopy:
88 | push hl ; Save input position
89 | ld l, e
90 | ld h, d ; hl = pointer to output
91 | add hl, bc ; hl = pointer to source of data to copy from
92 | ld c, a
93 | ld b, 0 ; bc = number of copies-2
94 |
95 | ldir
96 | ldi
97 | ldi
98 | pop hl ; Restore input position
99 | pop bc ; Restore bitstream bits
100 | jr .FetchNewCode
101 | ; ---------------------------------------------------------------------------
102 | .Code_01:
103 | ; Code 01 (Dictionary ref. long / special).
104 | _zKos_RunBitStream
105 | push bc ; Save bitstream bits
106 | ld c, (hl) ; c = %LLLLLLLL.
107 | inc hl ; Move past the lower displacement byte
108 | ld a, (hl) ; a = %HHHHHCCC.
109 | or 7 ; a = %HHHHH111.
110 | rra ; a = %1HHHHH11.
111 | rra ; a = %11HHHHH1.
112 | rra ; a = %111HHHHH.
113 | ld b, a ; bc = %111HHHHH LLLLLLLL.
114 | ld a, (hl) ; a = %HHHHHCCC.
115 | inc hl ; Move past the displacement byte
116 | and 7 ; a = %00000CCC = number of copies-2
117 | jr nz, .StreamCopy ; if CCC<>0, branch.
118 |
119 | ; special mode (extended counter)
120 | ld a, (hl) ; Read cnt
121 | or a
122 | ret z ; If cnt=0, quit decompression.
123 | inc hl ; Move past the displacement byte
124 | dec a
125 | jr z, .FetchNewCode ; If cnt=1, fetch a new code.
126 | jr .StreamCopy
127 | ; ===========================================================================
128 |
--------------------------------------------------------------------------------
/src/asm/Kosinski.asm:
--------------------------------------------------------------------------------
1 | ; ---------------------------------------------------------------------------
2 | ; For format explanation see https://segaretro.org/Kosinski_compression
3 | ; New faster version written by vladikcomper, with additional improvements
4 | ; by MarkeyJester and Flamewing
5 | ; ---------------------------------------------------------------------------
6 | ; Permission to use, copy, modify, and/or distribute this software for any
7 | ; purpose with or without fee is hereby granted.
8 | ;
9 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 | ; OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 | ; ---------------------------------------------------------------------------
17 | ; FUNCTION:
18 | ; KosDec
19 | ;
20 | ; DESCRIPTION
21 | ; Kosinski Decompressor
22 | ;
23 | ; INPUT:
24 | ; a0 source address
25 | ; a1 destination address
26 | ; ---------------------------------------------------------------------------
27 | _Kos_UseLUT = 1
28 | _Kos_LoopUnroll = 3
29 | _Kos_ExtremeUnrolling = 1
30 |
31 | _Kos_RunBitStream macro
32 | dbra d2,.skip
33 | moveq #7,d2 ; We have 8 new bits, but will use one up below.
34 | move.b d1,d0 ; Use the remaining 8 bits.
35 | not.w d3 ; Have all 16 bits been used up?
36 | bne.s .skip ; Branch if not.
37 | move.b (a0)+,d0 ; Get desc field low-byte.
38 | move.b (a0)+,d1 ; Get desc field hi-byte.
39 | if _Kos_UseLUT==1
40 | move.b (a4,d0.w),d0 ; Invert bit order...
41 | move.b (a4,d1.w),d1 ; ... for both bytes.
42 | endif
43 | .skip
44 | endm
45 |
46 | _Kos_ReadBit macro
47 | if _Kos_UseLUT==1
48 | add.b d0,d0 ; Get a bit from the bitstream.
49 | else
50 | lsr.b #1,d0 ; Get a bit from the bitstream.
51 | endif
52 | endm
53 | ; ===========================================================================
54 |
55 | ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
56 | ; ---------------------------------------------------------------------------
57 | KosDec:
58 | include "_inc/Kosinski_internal.asm"
59 | rts ; End of function KosDec.
60 | ; ===========================================================================
61 | if _Kos_UseLUT==1
62 | KosDec_ByteMap:
63 | dc.b $00,$80,$40,$C0,$20,$A0,$60,$E0,$10,$90,$50,$D0,$30,$B0,$70,$F0
64 | dc.b $08,$88,$48,$C8,$28,$A8,$68,$E8,$18,$98,$58,$D8,$38,$B8,$78,$F8
65 | dc.b $04,$84,$44,$C4,$24,$A4,$64,$E4,$14,$94,$54,$D4,$34,$B4,$74,$F4
66 | dc.b $0C,$8C,$4C,$CC,$2C,$AC,$6C,$EC,$1C,$9C,$5C,$DC,$3C,$BC,$7C,$FC
67 | dc.b $02,$82,$42,$C2,$22,$A2,$62,$E2,$12,$92,$52,$D2,$32,$B2,$72,$F2
68 | dc.b $0A,$8A,$4A,$CA,$2A,$AA,$6A,$EA,$1A,$9A,$5A,$DA,$3A,$BA,$7A,$FA
69 | dc.b $06,$86,$46,$C6,$26,$A6,$66,$E6,$16,$96,$56,$D6,$36,$B6,$76,$F6
70 | dc.b $0E,$8E,$4E,$CE,$2E,$AE,$6E,$EE,$1E,$9E,$5E,$DE,$3E,$BE,$7E,$FE
71 | dc.b $01,$81,$41,$C1,$21,$A1,$61,$E1,$11,$91,$51,$D1,$31,$B1,$71,$F1
72 | dc.b $09,$89,$49,$C9,$29,$A9,$69,$E9,$19,$99,$59,$D9,$39,$B9,$79,$F9
73 | dc.b $05,$85,$45,$C5,$25,$A5,$65,$E5,$15,$95,$55,$D5,$35,$B5,$75,$F5
74 | dc.b $0D,$8D,$4D,$CD,$2D,$AD,$6D,$ED,$1D,$9D,$5D,$DD,$3D,$BD,$7D,$FD
75 | dc.b $03,$83,$43,$C3,$23,$A3,$63,$E3,$13,$93,$53,$D3,$33,$B3,$73,$F3
76 | dc.b $0B,$8B,$4B,$CB,$2B,$AB,$6B,$EB,$1B,$9B,$5B,$DB,$3B,$BB,$7B,$FB
77 | dc.b $07,$87,$47,$C7,$27,$A7,$67,$E7,$17,$97,$57,$D7,$37,$B7,$77,$F7
78 | dc.b $0F,$8F,$4F,$CF,$2F,$AF,$6F,$EF,$1F,$9F,$5F,$DF,$3F,$BF,$7F,$FF
79 | endif
80 | ; ===========================================================================
81 |
82 |
--------------------------------------------------------------------------------
/src/asm/KosinskiPlus.a80:
--------------------------------------------------------------------------------
1 | ; ---------------------------------------------------------------------------
2 | ; New format based on Kosinski. It changes several design decisions to allow
3 | ; a faster decompressor without loss of compression ratio.
4 | ; Created originally by Flamewing and vladikcomper (by discussions on IRC),
5 | ; further improvements by Clownacy.
6 | ; ---------------------------------------------------------------------------
7 | ; Permission to use, copy, modify, and/or distribute this software for any
8 | ; purpose with or without fee is hereby granted.
9 | ;
10 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 | ; OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | ; ---------------------------------------------------------------------------
18 | ; FUNCTION:
19 | ; zKosPlusDec
20 | ;
21 | ; DESCRIPTION
22 | ; Kosinski+ Decompressor
23 | ;
24 | ; INPUT:
25 | ; hl Source address
26 | ; de Destination address
27 | ; ---------------------------------------------------------------------------
28 | _zKosPlus_ReadBit macro
29 | dec c ; Have all 8 bits been used up?
30 | jr nz, .skip ; Branch if not.
31 | ld b, (hl) ; Get desc field byte.
32 | inc hl
33 | ld c, 8 ; Set repeat count to 8.
34 | .skip:
35 | rl b ; Get a bit from the bitstream.
36 | endm
37 | ; ===========================================================================
38 |
39 | ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
40 | ; ---------------------------------------------------------------------------
41 | zKosPlusDec:
42 | ld c, 1 ; Set to reload a new byte.
43 | jr .FetchNewCode
44 | ; ---------------------------------------------------------------------------
45 | .FetchCodeLoop:
46 | ; Code 1 (Uncompressed byte).
47 | ldi
48 | inc bc ; Compensate for ldi
49 |
50 | .FetchNewCode:
51 | _zKosPlus_ReadBit
52 | jr c, .FetchCodeLoop ; If code = 1, branch.
53 |
54 | ; Codes 00 and 01.
55 | _zKosPlus_ReadBit
56 | jr c, .Code_01
57 |
58 | ; Code 00 (Dictionary ref. short).
59 | xor a
60 | _zKos_ReadBit
61 | rla
62 | _zKos_ReadBit
63 | rla
64 | push bc ; Save bitstream info
65 | ld c, (hl) ; Get the displacement byte
66 | inc hl ; Move past the displacement byte
67 | ld b, -1 ; bc = displacement
68 |
69 | .StreamCopy:
70 | push hl ; Save input position
71 | ld l, e
72 | ld h, d ; hl = pointer to output
73 | add hl, bc ; hl = pointer to source of data to copy from
74 | ld c, a
75 | ld b, 0 ; bc = number of copies-2
76 |
77 | ldir
78 | ldi
79 | ldi
80 | pop hl ; Restore input position
81 | pop bc ; Restore bitstream bits
82 | jr .FetchNewCode
83 | ; ---------------------------------------------------------------------------
84 | .Code_01:
85 | ; Code 01 (Dictionary ref. long / special).
86 | push bc ; Save bitstream bits
87 | ld a, (hl) ; a = %HHHHHCCC.
88 | or 7 ; a = %HHHHH111.
89 | rra ; a = %1HHHHH11.
90 | rra ; a = %11HHHHH1.
91 | rra ; a = %111HHHHH.
92 | ld b, a ; b = %111HHHHH.
93 | ld a, (hl) ; a = %HHHHHCCC.
94 | inc hl ; Move past the displacement byte
95 | ld c, (hl) ; bc = %111HHHHH LLLLLLLL.
96 | inc hl ; Move past the displacement byte
97 | and 7 ; a = %00000CCC = 10-number of copies
98 | jr z, .LargeCopy ; if CCC=0, branch.
99 | neg ; a = number of copies-10
100 | add a, 8 ; a = number of copies-2
101 | jr .StreamCopy
102 | ; ---------------------------------------------------------------------------
103 | .LargeCopy:
104 | ; special mode (extended counter)
105 | ld a, (hl) ; a = number of copies-8
106 | or a
107 | ret z ; If cnt=0, quit decompression.
108 |
109 | inc hl ; Move past the count byte
110 | push hl ; Save input position
111 | ld l, e
112 | ld h, d ; hl = pointer to output
113 | add hl, bc ; hl = pointer to source of data to copy from
114 |
115 | ld bc, 8
116 | ldir
117 | ld c, a
118 | ld b, 0 ; bc = number of copies-8
119 | ldir
120 | pop hl ; Restore input position
121 | pop bc ; Restore bitstream bits
122 | jr .FetchNewCode
123 | ; ===========================================================================
124 |
--------------------------------------------------------------------------------
/src/asm/KosinskiPlus.asm:
--------------------------------------------------------------------------------
1 | ; ---------------------------------------------------------------------------
2 | ; New format based on Kosinski. It changes several design decisions to allow
3 | ; a faster decompressor without loss of compression ratio.
4 | ; Created originally by Flamewing and vladikcomper (by discussions on IRC),
5 | ; further improvements by Clownacy.
6 | ; ---------------------------------------------------------------------------
7 | ; Permission to use, copy, modify, and/or distribute this software for any
8 | ; purpose with or without fee is hereby granted.
9 | ;
10 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 | ; OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | ; ---------------------------------------------------------------------------
18 | ; FUNCTION:
19 | ; KosPlusDec
20 | ;
21 | ; DESCRIPTION
22 | ; Kosinski+ Decompressor
23 | ;
24 | ; INPUT:
25 | ; a0 Source address
26 | ; a1 Destination address
27 | ; ---------------------------------------------------------------------------
28 | _KosPlus_LoopUnroll = 3
29 |
30 | _KosPlus_ReadBit macro
31 | dbra d2,.skip
32 | moveq #7,d2 ; We have 8 new bits, but will use one up below.
33 | move.b (a0)+,d0 ; Get desc field low-byte.
34 | .skip:
35 | add.b d0,d0 ; Get a bit from the bitstream.
36 | endm
37 | ; ===========================================================================
38 |
39 | ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
40 | ; ---------------------------------------------------------------------------
41 | KosPlusDec:
42 | if _KosPlus_LoopUnroll>0
43 | moveq #(1<<_KosPlus_LoopUnroll)-1,d7
44 | endif
45 | moveq #0,d2 ; Flag as having no bits left.
46 | bra.s .FetchNewCode
47 | ; ---------------------------------------------------------------------------
48 | .FetchCodeLoop:
49 | ; Code 1 (Uncompressed byte).
50 | move.b (a0)+,(a1)+
51 |
52 | .FetchNewCode:
53 | _KosPlus_ReadBit
54 | bcs.s .FetchCodeLoop ; If code = 1, branch.
55 |
56 | ; Codes 00 and 01.
57 | moveq #-1,d5
58 | lea (a1),a5
59 | _KosPlus_ReadBit
60 | bcs.s .Code_01
61 |
62 | ; Code 00 (Dictionary ref. short).
63 | move.b (a0)+,d5 ; d5 = displacement.
64 | adda.w d5,a5
65 | ; Always copy at least two bytes.
66 | move.b (a5)+,(a1)+
67 | move.b (a5)+,(a1)+
68 | _KosPlus_ReadBit
69 | bcc.s .Copy_01
70 | move.b (a5)+,(a1)+
71 | move.b (a5)+,(a1)+
72 |
73 | .Copy_01:
74 | _KosPlus_ReadBit
75 | bcc.s .FetchNewCode
76 | move.b (a5)+,(a1)+
77 | bra.s .FetchNewCode
78 | ; ---------------------------------------------------------------------------
79 | .Code_01:
80 | moveq #0,d4 ; d4 will contain copy count.
81 | ; Code 01 (Dictionary ref. long / special).
82 | move.b (a0)+,d4 ; d4 = %HHHHHCCC.
83 | move.b d4,d5 ; d5 = %11111111 HHHHHCCC.
84 | lsl.w #5,d5 ; d5 = %111HHHHH CCC00000.
85 | move.b (a0)+,d5 ; d5 = %111HHHHH LLLLLLLL.
86 | if _KosPlus_LoopUnroll==3
87 | and.w d7,d4 ; d4 = %00000CCC.
88 | else
89 | andi.w #7,d4
90 | endif
91 | if _KosPlus_LoopUnroll>0
92 | bne.s .StreamCopy ; if CCC=0, branch.
93 |
94 | ; special mode (extended counter)
95 | move.b (a0)+,d4 ; Read cnt
96 | beq.s .Quit ; If cnt=0, quit decompression.
97 |
98 | adda.w d5,a5
99 | move.w d4,d6
100 | not.w d6
101 | and.w d7,d6
102 | add.w d6,d6
103 | lsr.w #_KosPlus_LoopUnroll,d4
104 | jmp .largecopy(pc,d6.w)
105 | else
106 | beq.s .dolargecopy
107 | endif
108 | ; ---------------------------------------------------------------------------
109 | .StreamCopy:
110 | adda.w d5,a5
111 | move.b (a5)+,(a1)+ ; Do 1 extra copy (to compensate +1 to copy counter).
112 | add.w d4,d4
113 | jmp .mediumcopy-2(pc,d4.w)
114 | ; ---------------------------------------------------------------------------
115 | if _KosPlus_LoopUnroll==0
116 | .dolargecopy:
117 | ; special mode (extended counter)
118 | move.b (a0)+,d4 ; Read cnt
119 | beq.s .Quit ; If cnt=0, quit decompression.
120 | adda.w d5,a5
121 | endif
122 |
123 | .largecopy:
124 | rept (1<<_KosPlus_LoopUnroll)
125 | move.b (a5)+,(a1)+
126 | endm
127 | dbra d4,.largecopy
128 |
129 | .mediumcopy:
130 | rept 8
131 | move.b (a5)+,(a1)+
132 | endm
133 | bra.w .FetchNewCode
134 | ; ---------------------------------------------------------------------------
135 | .Quit:
136 | rts
137 | ; ===========================================================================
138 |
139 |
--------------------------------------------------------------------------------
/src/asm/Kosinski_internal.asm:
--------------------------------------------------------------------------------
1 | ; ---------------------------------------------------------------------------
2 | ; This is the internal portion of the code, which is shared by KosDec and
3 | ; Process_Kos_Queue. DO NOT CALL THIS DIRECTLY.
4 | ; ---------------------------------------------------------------------------
5 | ; For format explanation see https://segaretro.org/Kosinski_compression
6 | ; ---------------------------------------------------------------------------
7 | ; Permission to use, copy, modify, and/or distribute this software for any
8 | ; purpose with or without fee is hereby granted.
9 | ;
10 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16 | ; OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | ; ---------------------------------------------------------------------------
18 | if _Kos_LoopUnroll>0
19 | moveq #(1<<_Kos_LoopUnroll)-1,d7
20 | endif
21 | if _Kos_UseLUT==1
22 | moveq #0,d0
23 | moveq #0,d1
24 | lea KosDec_ByteMap(pc),a4 ; Load LUT pointer.
25 | endif
26 | move.b (a0)+,d0 ; Get desc field low-byte.
27 | move.b (a0)+,d1 ; Get desc field hi-byte.
28 | if _Kos_UseLUT==1
29 | move.b (a4,d0.w),d0 ; Invert bit order...
30 | move.b (a4,d1.w),d1 ; ... for both bytes.
31 | endif
32 | moveq #7,d2 ; Set repeat count to 8.
33 | moveq #0,d3 ; d3 will be desc field switcher.
34 | bra.s .FetchNewCode
35 | ; ---------------------------------------------------------------------------
36 | .FetchCodeLoop:
37 | ; Code 1 (Uncompressed byte).
38 | _Kos_RunBitStream
39 | move.b (a0)+,(a1)+
40 |
41 | .FetchNewCode:
42 | _Kos_ReadBit
43 | bcs.s .FetchCodeLoop ; If code = 1, branch.
44 |
45 | ; Codes 00 and 01.
46 | moveq #-1,d5
47 | lea (a1),a5
48 | _Kos_RunBitStream
49 | if _Kos_ExtremeUnrolling==1
50 | _Kos_ReadBit
51 | bcs.w .Code_01
52 |
53 | ; Code 00 (Dictionary ref. short).
54 | _Kos_RunBitStream
55 | _Kos_ReadBit
56 | bcs.s .Copy45
57 | _Kos_RunBitStream
58 | _Kos_ReadBit
59 | bcs.s .Copy3
60 | _Kos_RunBitStream
61 | move.b (a0)+,d5 ; d5 = displacement.
62 | adda.w d5,a5
63 | move.b (a5)+,(a1)+
64 | move.b (a5)+,(a1)+
65 | bra.s .FetchNewCode
66 | ; ---------------------------------------------------------------------------
67 | .Copy3:
68 | _Kos_RunBitStream
69 | move.b (a0)+,d5 ; d5 = displacement.
70 | adda.w d5,a5
71 | move.b (a5)+,(a1)+
72 | move.b (a5)+,(a1)+
73 | move.b (a5)+,(a1)+
74 | bra.w .FetchNewCode
75 | ; ---------------------------------------------------------------------------
76 | .Copy45:
77 | _Kos_RunBitStream
78 | _Kos_ReadBit
79 | bcs.s .Copy5
80 | _Kos_RunBitStream
81 | move.b (a0)+,d5 ; d5 = displacement.
82 | adda.w d5,a5
83 | move.b (a5)+,(a1)+
84 | move.b (a5)+,(a1)+
85 | move.b (a5)+,(a1)+
86 | move.b (a5)+,(a1)+
87 | bra.w .FetchNewCode
88 | ; ---------------------------------------------------------------------------
89 | .Copy5:
90 | _Kos_RunBitStream
91 | move.b (a0)+,d5 ; d5 = displacement.
92 | adda.w d5,a5
93 | move.b (a5)+,(a1)+
94 | move.b (a5)+,(a1)+
95 | move.b (a5)+,(a1)+
96 | move.b (a5)+,(a1)+
97 | move.b (a5)+,(a1)+
98 | bra.w .FetchNewCode
99 | ; ---------------------------------------------------------------------------
100 | else
101 | moveq #0,d4 ; d4 will contain copy count.
102 | _Kos_ReadBit
103 | bcs.s .Code_01
104 |
105 | ; Code 00 (Dictionary ref. short).
106 | _Kos_RunBitStream
107 | _Kos_ReadBit
108 | addx.w d4,d4
109 | _Kos_RunBitStream
110 | _Kos_ReadBit
111 | addx.w d4,d4
112 | _Kos_RunBitStream
113 | move.b (a0)+,d5 ; d5 = displacement.
114 |
115 | .StreamCopy:
116 | adda.w d5,a5
117 | move.b (a5)+,(a1)+ ; Do 1 extra copy (to compensate +1 to copy counter).
118 |
119 | .copy:
120 | move.b (a5)+,(a1)+
121 | dbra d4,.copy
122 | bra.w .FetchNewCode
123 | endif
124 | ; ---------------------------------------------------------------------------
125 | .Code_01:
126 | moveq #0,d4 ; d4 will contain copy count.
127 | ; Code 01 (Dictionary ref. long / special).
128 | _Kos_RunBitStream
129 | move.b (a0)+,d6 ; d6 = %LLLLLLLL.
130 | move.b (a0)+,d4 ; d4 = %HHHHHCCC.
131 | move.b d4,d5 ; d5 = %11111111 HHHHHCCC.
132 | lsl.w #5,d5 ; d5 = %111HHHHH CCC00000.
133 | move.b d6,d5 ; d5 = %111HHHHH LLLLLLLL.
134 | if _Kos_LoopUnroll==3
135 | and.w d7,d4 ; d4 = %00000CCC.
136 | else
137 | andi.w #7,d4 ; d4 = %00000CCC.
138 | endif
139 | bne.s .StreamCopy ; if CCC=0, branch.
140 |
141 | ; special mode (extended counter)
142 | move.b (a0)+,d4 ; Read cnt
143 | beq.s .Quit ; If cnt=0, quit decompression.
144 | subq.b #1,d4
145 | beq.w .FetchNewCode ; If cnt=1, fetch a new code.
146 |
147 | adda.w d5,a5
148 | move.b (a5)+,(a1)+ ; Do 1 extra copy (to compensate +1 to copy counter).
149 | if _Kos_LoopUnroll>0
150 | move.w d4,d6
151 | not.w d6
152 | and.w d7,d6
153 | add.w d6,d6
154 | lsr.w #_Kos_LoopUnroll,d4
155 | jmp .largecopy(pc,d6.w)
156 | endif
157 | ; ---------------------------------------------------------------------------
158 | .largecopy:
159 | rept (1<<_Kos_LoopUnroll)
160 | move.b (a5)+,(a1)+
161 | endm
162 | dbra d4,.largecopy
163 | bra.w .FetchNewCode
164 | ; ---------------------------------------------------------------------------
165 | if _Kos_ExtremeUnrolling==1
166 | .StreamCopy:
167 | adda.w d5,a5
168 | move.b (a5)+,(a1)+ ; Do 1 extra copy (to compensate +1 to copy counter).
169 | if _Kos_LoopUnroll==3
170 | eor.w d7,d4
171 | else
172 | eori.w #7,d4
173 | endif
174 | add.w d4,d4
175 | jmp .mediumcopy(pc,d4.w)
176 | ; ---------------------------------------------------------------------------
177 | .mediumcopy:
178 | rept 8
179 | move.b (a5)+,(a1)+
180 | endm
181 | bra.w .FetchNewCode
182 | endif
183 | ; ---------------------------------------------------------------------------
184 | .Quit:
185 | ; ===========================================================================
186 |
187 |
--------------------------------------------------------------------------------
/src/asm/Rocket.asm:
--------------------------------------------------------------------------------
1 | ; ---------------------------------------------------------------------------
2 | ; Permission to use, copy, modify, and/or distribute this software for any
3 | ; purpose with or without fee is hereby granted.
4 | ;
5 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
6 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
7 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
8 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
9 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
10 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
11 | ; OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
12 | ; ---------------------------------------------------------------------------
13 | ; FUNCTION:
14 | ; RocketDec
15 | ;
16 | ; DESCRIPTION
17 | ; Rocket Decompressor. Actually based on my Saxman decompressor, instead
18 | ; of the original Rocket Knight Adventures decompressor.
19 | ;
20 | ; INPUT:
21 | ; a0 Source address
22 | ; a1 Destination address
23 | ; ---------------------------------------------------------------------------
24 | _Rocket_LoopUnroll = 3
25 |
26 | _Rocket_UseLUT = 1
27 |
28 | _Rocket_ReadBit macro
29 | dbra d2,.skip
30 | moveq #7,d2 ; we have 8 new bits, but will use one up below.
31 | move.b (a0)+,d0 ; get desc field low-byte.
32 | if _Rocket_UseLUT==1
33 | move.b (a2,d0.w),d0 ; invert bit order.
34 | endif
35 | .skip
36 | if _Rocket_UseLUT==1
37 | add.b d0,d0 ; get a bit from the bitstream.
38 | else
39 | lsr.b #1,d0 ; get a bit from the bitstream.
40 | endif
41 | endm
42 | ; ===========================================================================
43 |
44 | ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
45 | ; ---------------------------------------------------------------------------
46 | RocketDec:
47 | move.w (a0)+,d0 ; Read uncompressed file length, and discard it
48 | move.w (a0)+,d0 ; Read compressed data length
49 | lea (a0,d0.w),a3 ; End of compression pointer
50 | move.w #-$3C0,d0 ; Position bias
51 | lea (a1),a4 ; Copy of start position
52 | lea (a1,d1.w),a6 ; Apply also position bias
53 | moveq #$20,d1
54 | move.w #$FC00,d3
55 | if _Rocket_UseLUT==1
56 | moveq #0,d0
57 | lea RocketDec_ByteMap(pc),a2 ; Load LUT pointer.
58 | endif
59 | moveq #0,d2 ; Flag as having no bits left.
60 | if _Rocket_LoopUnroll>0
61 | moveq #(1<<_Rocket_LoopUnroll)-1,d7
62 | endif
63 |
64 | .loop:
65 | cmpa.l a3,a0 ; Are we at the end of the compressed data?
66 | bcc.s .end ; If so, we're finished; end decompression loop
67 | _Rocket_ReadBit
68 | bcc.s .read_compressed
69 | ; Uncompressed byte
70 | move.b (a0)+,(a1)+
71 | bra.s .loop
72 | ; ---------------------------------------------------------------------------
73 | .end:
74 | rts
75 | ; ---------------------------------------------------------------------------
76 | .fill20:
77 | rept (1<<_Rocket_LoopUnroll)
78 | move.b d1,(a1)+
79 | endm
80 | dbra d5,.fill20
81 | tst.w d4 ; Any copies left?
82 | bmi.s .loop ; Branch if not
83 |
84 | .just_copy:
85 | if _Rocket_LoopUnroll>0
86 | move.w d4,d6
87 | not.w d6
88 | and.w d7,d6
89 | add.w d6,d6
90 | lsr.w #_Rocket_LoopUnroll,d4
91 | jmp .copy(pc,d6.w)
92 | endif
93 | .copy:
94 | rept (1<<_Rocket_LoopUnroll)
95 | move.b (a5)+,(a1)+
96 | endm
97 | dbra d4,.copy
98 | bra.s .loop
99 | ; End of function RocketDec
100 | ; ---------------------------------------------------------------------------
101 | .read_compressed:
102 | moveq #0,d5
103 | move.b (a0)+,d5 ; d5 = %00000000ccccccdd
104 | ror.b #2,d5 ; d5 = %00000000ddcccccc
105 | moveq #$3F,d4 ; d4 = %0000000000111111
106 | and.w d5,d4 ; d4 is now copy count-1
107 | add.w d5,d5 ; d5 = %0000000ddcccccc0
108 | add.w d5,d5 ; d5 = %000000ddcccccc00
109 | move.b (a0)+,d5 ; d5 is now base offset
110 | ; Rebase offset
111 | sub.w a6,d5
112 | add.w a4,d5 ; d5 -= number of bytes decompressed - position bias
113 | or.w d3,d5 ; d5 = (d5 & $3FF) - $400
114 | lea (a1,d5.w),a5
115 | move.l a5,d5
116 | sub.l a4,d5 ; Is rebased offset is before start?
117 | bhs.s .just_copy ; Branch if not
118 | ; Need to copy some spaces. -d5 is how many.
119 | add.w d5,d4 ; d4 is number of copies-1 to do after
120 | sub.w d5,a5 ; Seek source of copy by as many 0x20's as we will write
121 | not.w d5 ; d5 = -d5-1, a loop index
122 | if _Rocket_LoopUnroll>0
123 | move.w d5,d6
124 | not.w d6
125 | and.w d7,d6
126 | add.w d6,d6
127 | lsr.w #_Rocket_LoopUnroll,d5
128 | jmp .fill20(pc,d6.w)
129 | else
130 | bra.s .fill20
131 | endif
132 | ; ===========================================================================
133 | if _Rocket_UseLUT==1
134 | RocketDec_ByteMap:
135 | dc.b $00,$80,$40,$C0,$20,$A0,$60,$E0,$10,$90,$50,$D0,$30,$B0,$70,$F0
136 | dc.b $08,$88,$48,$C8,$28,$A8,$68,$E8,$18,$98,$58,$D8,$38,$B8,$78,$F8
137 | dc.b $04,$84,$44,$C4,$24,$A4,$64,$E4,$14,$94,$54,$D4,$34,$B4,$74,$F4
138 | dc.b $0C,$8C,$4C,$CC,$2C,$AC,$6C,$EC,$1C,$9C,$5C,$DC,$3C,$BC,$7C,$FC
139 | dc.b $02,$82,$42,$C2,$22,$A2,$62,$E2,$12,$92,$52,$D2,$32,$B2,$72,$F2
140 | dc.b $0A,$8A,$4A,$CA,$2A,$AA,$6A,$EA,$1A,$9A,$5A,$DA,$3A,$BA,$7A,$FA
141 | dc.b $06,$86,$46,$C6,$26,$A6,$66,$E6,$16,$96,$56,$D6,$36,$B6,$76,$F6
142 | dc.b $0E,$8E,$4E,$CE,$2E,$AE,$6E,$EE,$1E,$9E,$5E,$DE,$3E,$BE,$7E,$FE
143 | dc.b $01,$81,$41,$C1,$21,$A1,$61,$E1,$11,$91,$51,$D1,$31,$B1,$71,$F1
144 | dc.b $09,$89,$49,$C9,$29,$A9,$69,$E9,$19,$99,$59,$D9,$39,$B9,$79,$F9
145 | dc.b $05,$85,$45,$C5,$25,$A5,$65,$E5,$15,$95,$55,$D5,$35,$B5,$75,$F5
146 | dc.b $0D,$8D,$4D,$CD,$2D,$AD,$6D,$ED,$1D,$9D,$5D,$DD,$3D,$BD,$7D,$FD
147 | dc.b $03,$83,$43,$C3,$23,$A3,$63,$E3,$13,$93,$53,$D3,$33,$B3,$73,$F3
148 | dc.b $0B,$8B,$4B,$CB,$2B,$AB,$6B,$EB,$1B,$9B,$5B,$DB,$3B,$BB,$7B,$FB
149 | dc.b $07,$87,$47,$C7,$27,$A7,$67,$E7,$17,$97,$57,$D7,$37,$B7,$77,$F7
150 | dc.b $0F,$8F,$4F,$CF,$2F,$AF,$6F,$EF,$1F,$9F,$5F,$DF,$3F,$BF,$7F,$FF
151 | endif
152 | ; ===========================================================================
153 |
154 |
155 |
--------------------------------------------------------------------------------
/src/asm/SNKRLE.asm:
--------------------------------------------------------------------------------
1 | ; ---------------------------------------------------------------------------
2 | ; Original by snkenjoi, this much faster version written by Flamewing
3 | ; ---------------------------------------------------------------------------
4 | ; Permission to use, copy, modify, and/or distribute this software for any
5 | ; purpose with or without fee is hereby granted.
6 | ;
7 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 | ; OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 | ; ---------------------------------------------------------------------------
15 | ; FUNCTION:
16 | ; SNKDec
17 | ;
18 | ; DESCRIPTION
19 | ; snkenjoi's RLE Decompressor
20 | ;
21 | ; INPUT:
22 | ; a0 Source address
23 | ; a1 Destination address
24 | ; ===========================================================================
25 | ; Note on preconditions:
26 | ; The following preconditions are conditions satisfied by the decoding logic at
27 | ; various points in the routine. They are referred to by their code.
28 | ; (1) There is an even number of bytes left to decompress.
29 | ; (1') There is an odd number of bytes left to decompress.
30 | ; (2) Last character read is in d3.
31 | ; (2') Last character read is in d6.
32 | ; (3) d3 was printed to the buffer (d6).
33 | ; (3') The buffer (d6) is empty.
34 | ; (3") The buffer (d3) is empty.
35 | ; (3*) The buffer (d6) has the last character written twice.
36 | ; (3^) The buffer (d6) has two different characters
37 | ; (4) We are at an even position on the output stream.
38 | ; (5) The two bytes of the low word of d6 are equal to d3.
39 | ; ===========================================================================
40 |
41 | ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
42 | ; ---------------------------------------------------------------------------
43 | SNKDec:
44 | ;16 words = 1 tile
45 | move.w #$FE,d0
46 | moveq #0,d1
47 | moveq #0,d4
48 | move.w (a0)+,d1
49 | lea SNKDec_CopyLUT_End(pc),a4
50 | ; PRECONDITIONS: (1), (3'), and (4) hold.
51 |
52 | .fetch_new_char:
53 | ; PRECONDITIONS: (1), (3'), and (4) hold
54 | ; Read and print the character to the temporary buffer (d6).
55 | movep.w 0(a0),d6
56 | ; Read the character again for ease of comparison.
57 | move.b (a0)+,d3
58 | ; PRECONDITIONS: (1) and (4) still hold; (2) now also holds, and (3') is
59 | ; replaced by (3).
60 |
61 | .main_loop:
62 | ; PRECONDITIONS: (1), (2), (3), and (4) hold.
63 | ; Read and print new character to the buffer.
64 | move.b (a0)+,d6
65 | ; We now have a word on the buffer. Write it to output stream.
66 | move.w d6,(a1)+
67 | subq.w #2,d1
68 | ; PRECONDITIONS: (1), (2), (3) and (4) still hold.
69 | ; Branch if decompression was finished.
70 | beq.s SNKDecEnd
71 | ; Is this a run of identical bytes?
72 | cmp.b d3,d6
73 | ; Branch if not.
74 | bne.s .main_loop_buffer_clear
75 | ; PRECONDITIONS: (1), (2), and (4) still hold; (3) is replaced by (3*).
76 | ; We have a run. Fetch number of repetitions.
77 | move.b (a0)+,d5
78 | ; Zero repetitions means we wrote what was required and emptied our buffer.
79 | beq.s .main_loop_buffer_clear
80 | ; PRECONDITIONS: (1), (2), (3*), and (4) still hold.
81 | ; Given all preconditions, we just have to write d6 several times.
82 | ; Save count for later.
83 | move.b d5,d4
84 | ; Strip off low bit, as well as junk in high bits. We will write words.
85 | and.w d0,d5
86 | ; Prepare for loop unroll.
87 | neg.w d5
88 | ; Copy with lookup table.
89 | jsr (a4,d5.w)
90 | ; NOTE: because of the preconditions in effect, then we have the theorem:
91 | ; (A) if the copy count is odd, we haven't finished the decompression.
92 | ; Therefore, if we have reached the end of file, we don't have to worry
93 | ; about the low bit of the copy count we saved above.
94 | ; Factor in all bytes we wrote.
95 | sub.w d4,d1
96 | ; Branch if decompression is over.
97 | beq.s SNKDecEnd
98 | ; Was the copy count an odd number?
99 | moveq #1,d5
100 | and.b d4,d5
101 | ; Branch if not.
102 | beq.s .no_single_byte
103 | ; PRECONDITIONS: (2), (3*), and (4) still hold; (1) is replaced by (1').
104 | ; Implicitly print byte at d3 to buffer at d6 by doing (almost) nothing.
105 | ; Add a byte back to count because we haven't put it into the output stream.
106 | addq.w #1,d1
107 | ; PRECONDITIONS: (1), (2), (3*), and (4) still hold.
108 | ; Was the copy count 255?
109 | addq.b #1,d4
110 | ; Branch if not.
111 | bne.s .main_loop
112 | ; We need to read in a new character, and we have one printed to the buffer.
113 | ; Read and print new character to the buffer.
114 | move.b (a0)+,d6
115 | ; PRECONDITIONS: (1), and (4) still hold; (2) is replaced by (2'), and (3*)
116 | ; is replaced by (3^).
117 | ; Write both to output stream.
118 | move.w d6,(a1)+
119 | subq.w #2,d1
120 | ; PRECONDITIONS: (1), (2'), and (4) still hold; (3) is replaced by (3").
121 | ; Branch if decompression was finished.
122 | beq.s SNKDecEnd
123 | bra.s .main_loop_buffer_clear
124 | ;----------------------------------------------------------------------------
125 | .no_single_byte:
126 | ; PRECONDITIONS: (1), and (4) still hold; (2) is replaced by (2'), and (3*)
127 | ; is replaced by (3").
128 | ; If copy count is 255, we need to fetch a new byte and write it to the
129 | ; buffer.
130 | ; Was the copy count 255?
131 | addq.b #1,d4
132 | ; Branch if yes.
133 | beq.s .fetch_new_char
134 |
135 | .main_loop_buffer_clear:
136 | ; PRECONDITIONS: (1), (2'), (3"), and (4) hold.
137 | ; Swap (empty) buffer to d6 and last character read to d6.
138 | move.b d6,d3
139 | ; PRECONDITIONS: (1), and (4) still hold; (2') is replaced by (2),
140 | ; and (3") is replaced by (3').
141 | ; Read and print new character to the buffer (d6).
142 | movep.w 0(a0),d6
143 | ; Print it again to buffer for ease of comparison.
144 | move.b (a0)+,d6
145 | ; PRECONDITIONS: (1), (2), and (4) still hold; (3') is replaced by (3*).
146 | ; Is this a run of identical bytes?
147 | cmp.b d6,d3
148 | ; Branch if not.
149 | bne.s .main_loop
150 | ; We have a run. Fetch number of repetitions.
151 | move.b (a0)+,d5
152 | ; Zero repetitions means we just need to print the character to the buffer.
153 | beq.s .main_loop
154 | ; By precondition (3*), we now have a word with two identical bytes on the
155 | ; buffer. Write it to output stream.
156 | move.w d6,(a1)+
157 | subq.w #2,d1
158 | ; PRECONDITIONS: (1), (2), (3*) and (4) still hold.
159 | ; Deduct one byte from the copy count since we printed it above.
160 | subq.b #1,d5
161 | ; Save count for later.
162 | move.b d5,d4
163 | ; Strip off low bit, as well as junk in high bits. We will write words.
164 | and.w d0,d5
165 | ; Prepare for loop unroll.
166 | neg.w d5
167 | ; Copy with lookup table.
168 | jsr (a4,d5.w)
169 | ; NOTE: because of the preconditions in effect, then we have the theorem:
170 | ; (B) if the copy count was even, we haven't finished the decompression.
171 | ; Therefore, if we have reached the end of file, we don't have to worry
172 | ; about the low bit of the copy count we saved above.
173 | ; Factor in all bytes we wrote.
174 | sub.w d4,d1
175 | ; Branch if decompression is over.
176 | beq.s SNKDecEnd
177 | ; Add 1 back to use some common code.
178 | addq.b #1,d4
179 | ; Was the copy count an odd number?
180 | moveq #1,d5
181 | and.b d4,d5
182 | ; Branch if yes.
183 | bne.s .no_single_byte
184 | ; PRECONDITIONS: (2), (3*), and (4) still hold; (1) is replaced by (1').
185 | ; Implicitly print byte at d3 to buffer at d6 by doing (almost) nothing.
186 | ; Add a byte back to count because we haven't put it into the output stream.
187 | addq.w #1,d1
188 | ; PRECONDITIONS: (2), (3*), and (4) still hold; (1') is replaced by (1).
189 | ; Was the copy count 255?
190 | addq.b #1,d4
191 | ; Branch if not.
192 | bne.s .main_loop
193 | ; We need to read in a new character, and we have one printed to the buffer.
194 | ; Read and print new character to the buffer.
195 | move.b (a0)+,d6
196 | ; PRECONDITIONS: (1), and (4) still hold; (2) is replaced by (2'), and (3*)
197 | ; is replaced by (3^).
198 | ; Write both to output stream.
199 | move.w d6,(a1)+
200 | subq.w #2,d1
201 | ; PRECONDITIONS: (1), (2'), and (4) still hold; (3) is replaced by (3").
202 | ; Branch if decompression was not finished.
203 | bne.s .main_loop_buffer_clear
204 |
205 | SNKDecEnd:
206 | rts
207 | ; ===========================================================================
208 | SNKDec_CopyLUT:
209 | rept 127
210 | move.w d6,(a1)+
211 | endm
212 | SNKDec_CopyLUT_End:
213 | rts
214 | ; ===========================================================================
215 |
--------------------------------------------------------------------------------
/src/asm/Saxman.asm:
--------------------------------------------------------------------------------
1 | ; ---------------------------------------------------------------------------
2 | ; For format explanation see https://segaretro.org/Saxman_compression
3 | ; ---------------------------------------------------------------------------
4 | ; Permission to use, copy, modify, and/or distribute this software for any
5 | ; purpose with or without fee is hereby granted.
6 | ;
7 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 | ; OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 | ; ---------------------------------------------------------------------------
15 | ; FUNCTION:
16 | ; SaxDec
17 | ;
18 | ; DESCRIPTION
19 | ; Saxman Decompressor. Assumes file length is at the start as a
20 | ; little-endian word. In S2, this means music.
21 | ;
22 | ; INPUT:
23 | ; a0 Source address
24 | ; a1 Destination address
25 | ; ---------------------------------------------------------------------------
26 | ; FUNCTION:
27 | ; SaxDec2
28 | ; DESCRIPTION
29 | ; Saxman Decompressor. Assumes file length is given by d6.
30 | ; In S2, this means the sound driver.
31 | ;
32 | ; INPUT:
33 | ; a0 Source address
34 | ; a1 Destination address
35 | ; d6 Length of compressed file
36 | ; ---------------------------------------------------------------------------
37 | _Sax_UseLUT = 1
38 |
39 | ; Assume source data is aligned in an even address.
40 | _Sax_AlignedSource = 1
41 |
42 | _SaxDec_ReadByte macro dst
43 | if "dst"<>""
44 | move.b (a0)+,dst
45 | shift
46 | _SaxDec_ReadByte ALLARGS
47 | endif
48 | endm
49 |
50 | _SaxDec_GetByte macro dst
51 | if ARGCOUNT>0
52 | if ARGCOUNT>8
53 | subi.w #ARGCOUNT,d6 ; decrement remaining number of bytes
54 | else
55 | subq.w #ARGCOUNT,d6 ; decrement remaining number of bytes
56 | endif
57 | if ARGCOUNT>1
58 | bhi.s .continue
59 | else
60 | bne.s .continue
61 | endif
62 | rts ; exit the decompressor by meddling with the stack
63 | .continue:
64 | _SaxDec_ReadByte ALLARGS
65 | endif
66 | endm
67 |
68 | _Sax_ReadBit macro
69 | dbra d2,.skip
70 | moveq #7,d2 ; we have 8 new bits, but will use one up below.
71 | _SaxDec_GetByte d0 ; get desc field low-byte.
72 | if _Sax_UseLUT==1
73 | move.b (a2,d0.w),d0 ; invert bit order.
74 | endif
75 | .skip
76 | if _Sax_UseLUT==1
77 | add.b d0,d0 ; get a bit from the bitstream.
78 | else
79 | lsr.b #1,d0 ; get a bit from the bitstream.
80 | endif
81 | endm
82 | ; ===========================================================================
83 |
84 | ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
85 | ; ---------------------------------------------------------------------------
86 | SaxDec:
87 | ; Read and byte-swap one word.
88 | if _Sax_AlignedSource==1
89 | move.w (a0)+,d6
90 | rol.w #8,d6
91 | else
92 | move.b (a0)+,d0
93 | move.b (a0)+,-(sp)
94 | move.w (sp)+,d6
95 | move.b d0,d6
96 | endif
97 | ; FALL THROUGH
98 |
99 | ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
100 | ; ---------------------------------------------------------------------------
101 | SaxDec2:
102 | moveq #0,d2 ; Flag as having no bits left.
103 | lea (a1),a4
104 | if _Sax_UseLUT==1
105 | moveq #0,d0
106 | lea SaxDec_ByteMap(pc),a2 ; Load LUT pointer.
107 | endif
108 | move.w #$F000,d3
109 | moveq #$F,d7 ; Unrolling mask
110 |
111 | .loop:
112 | _Sax_ReadBit
113 | bcc.s .read_compressed
114 | ; Uncompressed byte
115 | _SaxDec_GetByte (a1)+
116 | bra.s .loop
117 | ; ---------------------------------------------------------------------------
118 | .copy:
119 | rept 18
120 | move.b (a5)+,(a1)+
121 | endm
122 | bra.s .loop
123 | ; ---------------------------------------------------------------------------
124 | .fill0:
125 | rept 18
126 | move.b d3,(a1)+ ; Exploiting the fact that low byte of d3 is zero
127 | endm
128 | bra.s .loop
129 | ; ---------------------------------------------------------------------------
130 | .read_compressed:
131 | _SaxDec_GetByte d1, d5
132 | move.b d5,d4 ; Low nibble of d4 is the length of the match minus 3
133 | not.w d4 ; Flip bits for jump table
134 | and.w d7,d4 ; Want only the low nibble
135 | add.w d4,d4 ; Jump table is in words
136 | lsl.w #4,d5 ; Move high nibble into place
137 | move.b d1,d5 ; Put low byte in place
138 | addi.w #$12,d5 ; There is a weird $12 byte shift in Saxman format
139 | ; Rebase offset from its storage format to a more useful one.
140 | sub.w a1,d5
141 | add.w a4,d5 ; d5 -= number of bytes decompressed so far
142 | or.w d3,d5 ; d5 = (d5 & $FFF) - $1000
143 | lea (a1,d5.w),a5
144 | cmpa.l a4,a5 ; Is rebased offset is before start?
145 | blo.s .zero_fill ; Branch if yes
146 | jmp .copy(pc,d4.w)
147 | ; ---------------------------------------------------------------------------
148 | .zero_fill:
149 | jmp .fill0(pc,d4.w)
150 | ; End of function SaxDec
151 | ; ===========================================================================
152 | if _Sax_UseLUT==1
153 | SaxDec_ByteMap:
154 | dc.b $00,$80,$40,$C0,$20,$A0,$60,$E0,$10,$90,$50,$D0,$30,$B0,$70,$F0
155 | dc.b $08,$88,$48,$C8,$28,$A8,$68,$E8,$18,$98,$58,$D8,$38,$B8,$78,$F8
156 | dc.b $04,$84,$44,$C4,$24,$A4,$64,$E4,$14,$94,$54,$D4,$34,$B4,$74,$F4
157 | dc.b $0C,$8C,$4C,$CC,$2C,$AC,$6C,$EC,$1C,$9C,$5C,$DC,$3C,$BC,$7C,$FC
158 | dc.b $02,$82,$42,$C2,$22,$A2,$62,$E2,$12,$92,$52,$D2,$32,$B2,$72,$F2
159 | dc.b $0A,$8A,$4A,$CA,$2A,$AA,$6A,$EA,$1A,$9A,$5A,$DA,$3A,$BA,$7A,$FA
160 | dc.b $06,$86,$46,$C6,$26,$A6,$66,$E6,$16,$96,$56,$D6,$36,$B6,$76,$F6
161 | dc.b $0E,$8E,$4E,$CE,$2E,$AE,$6E,$EE,$1E,$9E,$5E,$DE,$3E,$BE,$7E,$FE
162 | dc.b $01,$81,$41,$C1,$21,$A1,$61,$E1,$11,$91,$51,$D1,$31,$B1,$71,$F1
163 | dc.b $09,$89,$49,$C9,$29,$A9,$69,$E9,$19,$99,$59,$D9,$39,$B9,$79,$F9
164 | dc.b $05,$85,$45,$C5,$25,$A5,$65,$E5,$15,$95,$55,$D5,$35,$B5,$75,$F5
165 | dc.b $0D,$8D,$4D,$CD,$2D,$AD,$6D,$ED,$1D,$9D,$5D,$DD,$3D,$BD,$7D,$FD
166 | dc.b $03,$83,$43,$C3,$23,$A3,$63,$E3,$13,$93,$53,$D3,$33,$B3,$73,$F3
167 | dc.b $0B,$8B,$4B,$CB,$2B,$AB,$6B,$EB,$1B,$9B,$5B,$DB,$3B,$BB,$7B,$FB
168 | dc.b $07,$87,$47,$C7,$27,$A7,$67,$E7,$17,$97,$57,$D7,$37,$B7,$77,$F7
169 | dc.b $0F,$8F,$4F,$CF,$2F,$AF,$6F,$EF,$1F,$9F,$5F,$DF,$3F,$BF,$7F,$FF
170 | endif
171 | ; ===========================================================================
172 |
173 |
174 |
--------------------------------------------------------------------------------
/src/lib/artc42.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2015-2016
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | using std::istream;
30 | using std::ostream;
31 |
32 | using EniIBitstream = ibitstream;
33 | using EniOBitstream = obitstream;
34 |
35 | class artc42_internal {
36 | public:
37 | static void decode(istream& Src, ostream& Dst) {
38 | ignore_unused_variable_warning(Src, Dst);
39 | }
40 |
41 | static void encode(istream& Src, ostream& Dst) {
42 | ignore_unused_variable_warning(Src, Dst);
43 | }
44 | };
45 |
46 | bool artc42::decode(istream& Src, ostream& Dst) {
47 | ignore_unused_variable_warning(Src, Dst);
48 | return false;
49 | }
50 |
51 | bool artc42::encode(istream& Src, ostream& Dst) {
52 | ignore_unused_variable_warning(Src, Dst);
53 | return false;
54 | }
55 |
--------------------------------------------------------------------------------
/src/lib/basic_decoder.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2021
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include
20 |
--------------------------------------------------------------------------------
/src/lib/bigendian_io.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2021
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include
20 |
--------------------------------------------------------------------------------
/src/lib/bitstream.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2021
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include
20 |
--------------------------------------------------------------------------------
/src/lib/comper.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2013-2016
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | using std::array;
32 | using std::ios;
33 | using std::iostream;
34 | using std::istream;
35 | using std::make_signed_t;
36 | using std::numeric_limits;
37 | using std::ostream;
38 | using std::streamsize;
39 | using std::stringstream;
40 |
41 | template <>
42 | size_t moduled_comper::PadMaskBits = 1U;
43 |
44 | class comper_internal {
45 | // NOTE: This has to be changed for other LZSS-based compression schemes.
46 | struct ComperAdaptor {
47 | using stream_t = uint16_t;
48 | using stream_endian_t = BigEndian;
49 | using descriptor_t = uint16_t;
50 | using descriptor_endian_t = BigEndian;
51 | using SlidingWindow_t = SlidingWindow;
52 | enum class EdgeType : size_t {
53 | invalid,
54 | terminator,
55 | symbolwise,
56 | dictionary
57 | };
58 | // Number of bits on descriptor bitfield.
59 | constexpr static size_t const NumDescBits = sizeof(descriptor_t) * 8;
60 | // Flag that tells the compressor that new descriptor fields is needed
61 | // when a new bit is needed and all bits in the previous one have been
62 | // used up.
63 | constexpr static bool const NeedEarlyDescriptor = false;
64 | // Flag that marks the descriptor bits as being in big-endian bit
65 | // order (that is, highest bits come out first).
66 | constexpr static bool const DescriptorLittleEndianBits = false;
67 | // How many characters to skip looking for matchs for at the start.
68 | constexpr static size_t const FirstMatchPosition = 0;
69 | // Size of the search buffer.
70 | constexpr static size_t const SearchBufSize = 256;
71 | // Size of the look-ahead buffer.
72 | constexpr static size_t const LookAheadBufSize = 256;
73 | // Creates the (multilayer) sliding window structure.
74 | static auto create_sliding_window(
75 | stream_t const* dt, size_t const size) noexcept {
76 | return array{SlidingWindow_t{
77 | dt, size, SearchBufSize, 2, LookAheadBufSize,
78 | EdgeType::dictionary}};
79 | }
80 | // Given an edge type, computes how many bits are used in the descriptor
81 | // field.
82 | constexpr static size_t desc_bits(EdgeType const type) noexcept {
83 | // Comper always uses a single bit descriptor.
84 | ignore_unused_variable_warning(type);
85 | return 1;
86 | }
87 | // Given an edge type, computes how many bits are used in total by this
88 | // edge. A return of "numeric_limits::max()" means "infinite",
89 | // or "no edge".
90 | constexpr static size_t edge_weight(
91 | EdgeType const type, size_t length) noexcept {
92 | ignore_unused_variable_warning(length);
93 | switch (type) {
94 | case EdgeType::symbolwise:
95 | case EdgeType::terminator:
96 | // 16-bit value.
97 | return desc_bits(type) + 16;
98 | case EdgeType::dictionary:
99 | // 8-bit distance, 8-bit length.
100 | return desc_bits(type) + 8 + 8;
101 | case EdgeType::invalid:
102 | return numeric_limits::max();
103 | }
104 | __builtin_unreachable();
105 | }
106 | // Comper finds no additional matches over normal LZSS.
107 | constexpr static bool extra_matches(
108 | stream_t const* data, size_t const basenode,
109 | size_t const ubound, size_t const lbound,
110 | std::vector>& matches) noexcept {
111 | ignore_unused_variable_warning(
112 | data, basenode, ubound, lbound, matches);
113 | // Do normal matches.
114 | return false;
115 | }
116 | // Comper needs no additional padding at the end-of-file.
117 | constexpr static size_t get_padding(size_t const totallen) noexcept {
118 | ignore_unused_variable_warning(totallen);
119 | return 0;
120 | }
121 | };
122 |
123 | public:
124 | static void decode(istream& in, iostream& Dst) {
125 | using CompIStream = LZSSIStream;
126 |
127 | CompIStream src(in);
128 |
129 | while (in.good()) {
130 | if (src.descbit() == 0U) {
131 | // Symbolwise match.
132 | BigEndian::Write2(Dst, BigEndian::Read2(in));
133 | } else {
134 | // Dictionary match.
135 | // Distance and length of match.
136 | size_t const distance = (size_t(0x100) - src.getbyte()) * 2;
137 | size_t const length = src.getbyte();
138 | if (length == 0) {
139 | break;
140 | }
141 |
142 | for (size_t i = 0; i <= length; i++) {
143 | size_t const Pointer = Dst.tellp();
144 | Dst.seekg(Pointer - distance);
145 | uint16_t const Word = BigEndian::Read2(Dst);
146 | Dst.seekp(Pointer);
147 | BigEndian::Write2(Dst, Word);
148 | }
149 | }
150 | }
151 | }
152 |
153 | static void encode(ostream& Dst, uint8_t const* Data, size_t const Size) {
154 | using EdgeType = typename ComperAdaptor::EdgeType;
155 | using CompOStream = LZSSOStream;
156 |
157 | // Compute optimal Comper parsing of input file.
158 | auto list = find_optimal_lzss_parse(Data, Size, ComperAdaptor{});
159 | CompOStream out(Dst);
160 |
161 | // Go through each edge in the optimal path.
162 | for (auto const& edge : list.parse_list) {
163 | switch (edge.get_type()) {
164 | case EdgeType::symbolwise: {
165 | size_t const value = edge.get_symbol();
166 | size_t const high = (value >> 8U) & 0xFFU;
167 | size_t const low = (value & 0xFFU);
168 | out.descbit(0);
169 | out.putbyte(high);
170 | out.putbyte(low);
171 | break;
172 | }
173 | case EdgeType::dictionary: {
174 | size_t const len = edge.get_length();
175 | size_t const dist = edge.get_distance();
176 | out.descbit(1);
177 | out.putbyte(-dist);
178 | out.putbyte(len - 1);
179 | break;
180 | }
181 | case EdgeType::terminator: {
182 | // Push descriptor for end-of-file marker.
183 | out.descbit(1);
184 | out.putbyte(0);
185 | out.putbyte(0);
186 | break;
187 | }
188 | case EdgeType::invalid:
189 | // This should be unreachable.
190 | std::cerr << "Compression produced invalid edge type "
191 | << static_cast(edge.get_type()) << std::endl;
192 | __builtin_unreachable();
193 | }
194 | }
195 | }
196 | };
197 |
198 | bool comper::decode(istream& Src, iostream& Dst) {
199 | size_t const Location = Src.tellg();
200 | stringstream in(ios::in | ios::out | ios::binary);
201 | extract(Src, in);
202 |
203 | comper_internal::decode(in, Dst);
204 | Src.seekg(Location + in.tellg());
205 | return true;
206 | }
207 |
208 | bool comper::encode(ostream& Dst, uint8_t const* data, size_t const Size) {
209 | comper_internal::encode(Dst, data, Size);
210 | return true;
211 | }
212 |
--------------------------------------------------------------------------------
/src/lib/comperx.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2013-2016
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | using std::array;
32 | using std::ios;
33 | using std::iostream;
34 | using std::istream;
35 | using std::make_signed_t;
36 | using std::numeric_limits;
37 | using std::ostream;
38 | using std::streamsize;
39 | using std::stringstream;
40 |
41 | template <>
42 | size_t moduled_comperx::PadMaskBits = 1U;
43 |
44 | class comperx_internal {
45 | // NOTE: This has to be changed for other LZSS-based compression schemes.
46 | struct ComperXAdaptor {
47 | using stream_t = uint16_t;
48 | using stream_endian_t = BigEndian;
49 | using descriptor_t = uint16_t;
50 | using descriptor_endian_t = BigEndian;
51 | using SlidingWindow_t = SlidingWindow;
52 | enum class EdgeType : size_t {
53 | invalid,
54 | terminator,
55 | symbolwise,
56 | dictionary
57 | };
58 | // Number of bits on descriptor bitfield.
59 | constexpr static size_t const NumDescBits = sizeof(descriptor_t) * 8;
60 | // Flag that tells the compressor that new descriptor fields is needed
61 | // when a new bit is needed and all bits in the previous one have been
62 | // used up.
63 | constexpr static bool const NeedEarlyDescriptor = false;
64 | // Flag that marks the descriptor bits as being in big-endian bit
65 | // order (that is, highest bits come out first).
66 | constexpr static bool const DescriptorLittleEndianBits = false;
67 | // How many characters to skip looking for matchs for at the start.
68 | constexpr static size_t const FirstMatchPosition = 0;
69 | // Size of the search buffer.
70 | constexpr static size_t const SearchBufSize = 256;
71 | // Size of the look-ahead buffer.
72 | constexpr static size_t const LookAheadBufSize = 255;
73 | // Creates the (multilayer) sliding window structure.
74 | static auto create_sliding_window(
75 | stream_t const* dt, size_t const size) noexcept {
76 | return array{SlidingWindow_t{
77 | dt, size, SearchBufSize, 2, LookAheadBufSize,
78 | EdgeType::dictionary}};
79 | }
80 | // Given an edge type, computes how many bits are used in the descriptor
81 | // field.
82 | constexpr static size_t desc_bits(EdgeType const type) noexcept {
83 | // Comper always uses a single bit descriptor.
84 | ignore_unused_variable_warning(type);
85 | return 1;
86 | }
87 | // Given an edge type, computes how many bits are used in total by this
88 | // edge. A return of "numeric_limits::max()" means "infinite",
89 | // or "no edge".
90 | constexpr static size_t edge_weight(
91 | EdgeType const type, size_t length) noexcept {
92 | ignore_unused_variable_warning(length);
93 | switch (type) {
94 | case EdgeType::symbolwise:
95 | case EdgeType::terminator:
96 | // 16-bit value.
97 | return desc_bits(type) + 16;
98 | case EdgeType::dictionary:
99 | // 8-bit distance, 8-bit length.
100 | return desc_bits(type) + 8 + 8;
101 | case EdgeType::invalid:
102 | return numeric_limits::max();
103 | }
104 | __builtin_unreachable();
105 | }
106 | // ComperX finds no additional matches over normal LZSS.
107 | constexpr static bool extra_matches(
108 | stream_t const* data, size_t const basenode,
109 | size_t const ubound, size_t const lbound,
110 | std::vector>& matches) noexcept {
111 | ignore_unused_variable_warning(
112 | data, basenode, ubound, lbound, matches);
113 | // Do normal matches.
114 | return false;
115 | }
116 | // ComperX needs no additional padding at the end-of-file.
117 | constexpr static size_t get_padding(size_t const totallen) noexcept {
118 | ignore_unused_variable_warning(totallen);
119 | return 0;
120 | }
121 | };
122 |
123 | public:
124 | static void decode(istream& in, iostream& Dst) {
125 | using CompIStream = LZSSIStream;
126 |
127 | CompIStream src(in);
128 |
129 | while (in.good()) {
130 | if (src.descbit() == 0U) {
131 | // Symbolwise match.
132 | BigEndian::Write2(Dst, BigEndian::Read2(in));
133 | } else {
134 | // Dictionary match.
135 | // Distance and length of match.
136 | uint8_t raw_dist = src.getbyte();
137 | uint8_t raw_len = src.getbyte();
138 |
139 | if (raw_len == 0) { /* Stop processing */
140 | break;
141 | }
142 |
143 | size_t const distance
144 | = raw_dist != 0U ? (0x100 - raw_dist + 1) * 2 : 2;
145 | size_t const length = (0x100 - ((raw_len & 0x7FU) << 1U))
146 | + ((raw_len & 0x80U) >> 7U);
147 |
148 | for (size_t i = 0; i < length; i++) {
149 | size_t const Pointer = Dst.tellp();
150 | Dst.seekg(Pointer - distance);
151 | uint16_t const Word = BigEndian::Read2(Dst);
152 | Dst.seekp(Pointer);
153 | BigEndian::Write2(Dst, Word);
154 | }
155 | }
156 | }
157 | }
158 |
159 | static void encode(ostream& Dst, uint8_t const* Data, size_t const Size) {
160 | using EdgeType = typename ComperXAdaptor::EdgeType;
161 | using CompOStream = LZSSOStream;
162 |
163 | // Compute optimal Comper parsing of input file.
164 | auto list = find_optimal_lzss_parse(Data, Size, ComperXAdaptor{});
165 | CompOStream out(Dst);
166 |
167 | // Go through each edge in the optimal path.
168 | for (auto const& edge : list.parse_list) {
169 | switch (edge.get_type()) {
170 | case EdgeType::symbolwise: {
171 | size_t const value = edge.get_symbol();
172 | size_t const high = (value >> 8U) & 0xFFU;
173 | size_t const low = (value & 0xFFU);
174 | out.descbit(0);
175 | out.putbyte(high);
176 | out.putbyte(low);
177 | break;
178 | }
179 | case EdgeType::dictionary: {
180 | size_t const len = edge.get_length();
181 | size_t const dist = edge.get_distance();
182 |
183 | out.descbit(1);
184 | out.putbyte(-dist + 1);
185 | out.putbyte((0x7FU - ((len - 2U) >> 1U)) | ((len & 1U) << 7U));
186 | break;
187 | }
188 | case EdgeType::terminator: {
189 | // Push descriptor for end-of-file marker.
190 | out.descbit(1);
191 | out.putbyte(-1);
192 | out.putbyte(0);
193 | break;
194 | }
195 | case EdgeType::invalid:
196 | // This should be unreachable.
197 | std::cerr << "Compression produced invalid edge type "
198 | << static_cast(edge.get_type()) << std::endl;
199 | __builtin_unreachable();
200 | }
201 | }
202 | }
203 | };
204 |
205 | bool comperx::decode(istream& Src, iostream& Dst) {
206 | size_t const Location = Src.tellg();
207 | stringstream in(ios::in | ios::out | ios::binary);
208 | extract(Src, in);
209 |
210 | comperx_internal::decode(in, Dst);
211 | Src.seekg(Location + in.tellg());
212 | return true;
213 | }
214 |
215 | bool comperx::encode(ostream& Dst, uint8_t const* data, size_t const Size) {
216 | comperx_internal::encode(Dst, data, Size);
217 | return true;
218 | }
219 |
--------------------------------------------------------------------------------
/src/lib/ignore_unused_variable_warning.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2021
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include
20 |
--------------------------------------------------------------------------------
/src/lib/lzss.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2021
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include
20 |
--------------------------------------------------------------------------------
/src/lib/moduled_adaptor.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2021
3 | *
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include
20 |
--------------------------------------------------------------------------------
/src/lib/snkrle.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2017
3 | * Loosely based on code by snkenjoi
4 | *
5 | * This program is free software: you can redistribute it and/or modify it
6 | * under the terms of the GNU Lesser General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful, but
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 | * See the GNU Lesser General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Lesser General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | using std::ios;
30 | using std::istream;
31 | using std::numeric_limits;
32 | using std::ostream;
33 | using std::streamsize;
34 | using std::stringstream;
35 |
36 | template <>
37 | size_t moduled_snkrle::PadMaskBits = 1U;
38 |
39 | class snkrle_internal {
40 | public:
41 | static void decode(istream& Src, ostream& Dst) {
42 | size_t Size = BigEndian::Read2(Src);
43 | if (Size == 0) {
44 | return;
45 | }
46 | uint8_t cc = Read1(Src);
47 | Write1(Dst, cc);
48 | Size--;
49 | while (Size > 0) {
50 | uint8_t nc = Read1(Src);
51 | Write1(Dst, nc);
52 | Size--;
53 | if (cc == nc) {
54 | // RLE marker. Get repeat count.
55 | size_t Count = Read1(Src);
56 | for (size_t ii = 0; ii < Count; ii++) {
57 | Write1(Dst, nc);
58 | }
59 | Size -= Count;
60 | if (Count == 255 && Size > 0) {
61 | cc = Read1(Src);
62 | Write1(Dst, nc);
63 | Size--;
64 | }
65 | } else {
66 | cc = nc;
67 | }
68 | }
69 | }
70 |
71 | static void encode(istream& Src, ostream& Dst) {
72 | size_t pos = Src.tellg();
73 | Src.ignore(numeric_limits::max());
74 | size_t Size = Src.gcount();
75 | Src.seekg(pos);
76 | BigEndian::Write2(Dst, Size);
77 | uint8_t cc = Read1(Src);
78 | while (Src.good()) {
79 | Write1(Dst, cc);
80 | uint8_t nc = Read1(Src);
81 | if (!Src.good()) {
82 | break;
83 | }
84 | if (nc == cc) {
85 | Write1(Dst, nc);
86 | size_t Count = 0;
87 | cc = Read1(Src);
88 | while (Src.good() && nc == cc && Count < 255) {
89 | Count++;
90 | cc = Read1(Src);
91 | }
92 | Write1(Dst, Count);
93 | } else {
94 | cc = nc;
95 | }
96 | }
97 | }
98 | };
99 |
100 | bool snkrle::decode(istream& Src, ostream& Dst) {
101 | size_t const Location = Src.tellg();
102 | stringstream in(ios::in | ios::out | ios::binary);
103 | extract(Src, in);
104 |
105 | snkrle_internal::decode(in, Dst);
106 | Src.seekg(Location + in.tellg());
107 | return true;
108 | }
109 |
110 | bool snkrle::encode(ostream& Dst, uint8_t const* data, size_t const Size) {
111 | stringstream Src(ios::in | ios::out | ios::binary);
112 | Src.write(reinterpret_cast(data), Size);
113 | Src.seekg(0);
114 | snkrle_internal::encode(Src, Dst);
115 | return true;
116 | }
117 |
--------------------------------------------------------------------------------
/src/tools/compcmp.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) Flamewing 2013-2015
3 | *
4 | * This program is free software: you can redistribute it and/or modify it
5 | * under the terms of the GNU Lesser General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful, but
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 | * See the GNU Lesser General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Lesser General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 | #include
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | using std::cerr;
28 | using std::endl;
29 | using std::fstream;
30 | using std::ifstream;
31 | using std::ios;
32 | using std::ofstream;
33 | using std::stringstream;
34 |
35 | static void usage(char* prog) {
36 | cerr << "Usage: " << prog
37 | << " [-c|--crunch|-x|--extract=[{pointer}]] [-m|--moduled] "
38 | "{input_filename} "
39 | "{output_filename}"
40 | << endl;
41 | cerr << endl;
42 | cerr << "\t-x,--extract\tExtract from {pointer} address in file." << endl;
43 | cerr << "\t-c,--crunch \tAssume input file is Comper-compressed and "
44 | "recompress to output file."
45 | << endl
46 | << "\t \tIf --crunch is in effect, a missing "
47 | "output_filename means recompress"
48 | << endl
49 | << "\t \tto input_filename." << endl;
50 | cerr << "\t-m,--moduled\tUse compression in modules of 4096 bytes." << endl;
51 | }
52 |
53 | int main(int argc, char* argv[]) {
54 | static constexpr const std::array