├── .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 | [![ASM License: 0BSD](https://img.shields.io/badge/ASM%20License-BSD%200--Clause-orange.svg)](https://tldrlegal.com/license/bsd-0-clause-license) 4 | [![Non-ASM License: LGPL v3](https://img.shields.io/badge/Non--ASM%20License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) 5 | 6 | [![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/flamewing/mdcomp?label=codefactor&logo=codefactor&logoColor=white)](https://www.codefactor.io/repository/github/flamewing/mdcomp) 7 | [![LGTM Alerts](https://img.shields.io/lgtm/alerts/github/flamewing/mdcomp?logo=LGTM)](https://lgtm.com/projects/g/flamewing/mdcomp/alerts/) 8 | [![LGTM Grade](https://img.shields.io/lgtm/grade/cpp/github/flamewing/mdcomp?logo=LGTM)](https://lgtm.com/projects/g/flamewing/mdcomp/context:cpp) 9 | 10 | [![CI Mac OS Catalina 10.15](https://img.shields.io/github/workflow/status/flamewing/mdcomp/ci-macos?label=CI%20Mac%20OS%20X&logo=Apple&logoColor=white)](https://github.com/flamewing/mdcomp/actions?query=workflow%3Aci-macos) 11 | [![CI Ubuntu 20.04](https://img.shields.io/github/workflow/status/flamewing/mdcomp/ci-linux?label=CI%20Ubuntu&logo=Ubuntu&logoColor=white)](https://github.com/flamewing/mdcomp/actions?query=workflow%3Aci-linux) 12 | [![CI Windows Server 2019](https://img.shields.io/github/workflow/status/flamewing/mdcomp/ci-windows?label=CI%20Windows&logo=Windows&logoColor=white)](https://github.com/flamewing/mdcomp/actions?query=workflow%3Aci-windows) 13 | 14 | [![Coverity Scan Analysis](https://img.shields.io/github/workflow/status/flamewing/mdcomp/coverity-scan?label=Coverity%20Scan%20Analysis&logo=data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjU2IDI1MiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjYuOTUgMTA5LjA4bC0zLjUyLTkuNDUgMzcuOTYgNzAuODloLjg1bDQ3LjMzLTExOC4xM2MuODMtMi41NiA4LjI2LTIxLjc0IDguNTEtMzAuMi42My0yMS44NC0xNC4xLTIzLjgxLTI5Ljc3LTE5LjM5QzM2Ljg3IDE5LjQ2LS4yNCA2Ny44My4wMSAxMjQuNzhjLjIgNTIuOTcgMzIuNjQgOTguMjQgNzguNjUgMTE3LjM4TDI2Ljk1IDEwOS4wOE0xNzQuMzMgNS40OGMtNi4zMiAxMi43LTEzLjEgMjYuMzctMjEuNjggNDguMDhMNzkuMjIgMjQyLjM5YzE1LjA5IDYuMiAzMS42MyA5LjYgNDguOTYgOS41MiA3MC41LS4yNyAxMjcuNDItNTcuNjcgMTI3LjEzLTEyOC4xOC0uMjItNTMuODMtMzMuNzYtOTkuNy04MC45OC0xMTguMjYiIGZpbGw9IiNmZmYiLz48L3N2Zz4=)](https://github.com/flamewing/mdcomp/actions?query=workflow%3Acoverity-scan) 15 | [![Coverity Scan](https://img.shields.io/coverity/scan/10872?label=Coverity%20Scan%20Results&logo=data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjU2IDI1MiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjYuOTUgMTA5LjA4bC0zLjUyLTkuNDUgMzcuOTYgNzAuODloLjg1bDQ3LjMzLTExOC4xM2MuODMtMi41NiA4LjI2LTIxLjc0IDguNTEtMzAuMi42My0yMS44NC0xNC4xLTIzLjgxLTI5Ljc3LTE5LjM5QzM2Ljg3IDE5LjQ2LS4yNCA2Ny44My4wMSAxMjQuNzhjLjIgNTIuOTcgMzIuNjQgOTguMjQgNzguNjUgMTE3LjM4TDI2Ljk1IDEwOS4wOE0xNzQuMzMgNS40OGMtNi4zMiAxMi43LTEzLjEgMjYuMzctMjEuNjggNDguMDhMNzkuMjIgMjQyLjM5YzE1LjA5IDYuMiAzMS42MyA5LjYgNDguOTYgOS41MiA3MC41LS4yNyAxMjcuNDItNTcuNjcgMTI3LjEzLTEyOC4xOC0uMjItNTMuODMtMzMuNzYtOTkuNy04MC45OC0xMTguMjYiIGZpbGw9IiNmZmYiLz48L3N2Zz4=)](https://scan.coverity.com/projects/flamewing-mdcomp) 16 | 17 | [![Windows snapshot build](https://img.shields.io/github/workflow/status/flamewing/mdcomp/snapshots-windows?label=Windows%20Snapshot%20build&logo=windows&logoColor=white)](https://github.com/flamewing/mdcomp/actions?query=workflow%3Asnapshots-windows) 18 | [![Latest Windows snapshot](https://img.shields.io/github/release-date/flamewing/mdcomp?label=Latest%20Windows%20snapshot&logo=windows&logoColor=white)](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 long_options{ 55 | option{"extract", optional_argument, nullptr, 'x'}, 56 | option{"moduled", no_argument, nullptr, 'm'}, 57 | option{"crunch", no_argument, nullptr, 'c'}, 58 | option{nullptr, 0, nullptr, 0}}; 59 | 60 | bool extract = false; 61 | bool moduled = false; 62 | bool crunch = false; 63 | size_t pointer = 0; 64 | 65 | while (true) { 66 | int option_index = 0; 67 | int option_char = getopt_long( 68 | argc, argv, "x::mc", long_options.data(), &option_index); 69 | if (option_char == -1) { 70 | break; 71 | } 72 | 73 | switch (option_char) { 74 | case 'x': 75 | extract = true; 76 | if (optarg != nullptr) { 77 | pointer = strtoul(optarg, nullptr, 0); 78 | } 79 | break; 80 | case 'c': 81 | crunch = true; 82 | break; 83 | case 'm': 84 | moduled = true; 85 | break; 86 | default: 87 | break; 88 | } 89 | } 90 | 91 | if ((!crunch && argc - optind < 2) || (crunch && argc - optind < 1)) { 92 | usage(argv[0]); 93 | return 1; 94 | } 95 | 96 | if (extract && crunch) { 97 | cerr << "Error: --extract and --crunch can't be used at the same time." 98 | << endl 99 | << endl; 100 | return 4; 101 | } 102 | 103 | const char* outfile 104 | = crunch && argc - optind < 2 ? argv[optind] : argv[optind + 1]; 105 | 106 | ifstream fin(argv[optind], ios::in | ios::binary); 107 | if (!fin.good()) { 108 | cerr << "Input file '" << argv[optind] << "' could not be opened." 109 | << endl 110 | << endl; 111 | return 2; 112 | } 113 | 114 | if (crunch) { 115 | stringstream buffer(ios::in | ios::out | ios::binary); 116 | fin.seekg(pointer); 117 | comper::decode(fin, buffer); 118 | fin.close(); 119 | buffer.seekg(0); 120 | 121 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 122 | if (!fout.good()) { 123 | cerr << "Output file '" << argv[optind + 1] 124 | << "' could not be opened." << endl 125 | << endl; 126 | return 3; 127 | } 128 | if (moduled) { 129 | comper::moduled_encode(buffer, fout); 130 | } else { 131 | comper::encode(buffer, fout); 132 | } 133 | } else { 134 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 135 | if (!fout.good()) { 136 | cerr << "Output file '" << argv[optind + 1] 137 | << "' could not be opened." << endl 138 | << endl; 139 | return 3; 140 | } 141 | 142 | if (extract) { 143 | fin.seekg(pointer); 144 | if (moduled) { 145 | comper::moduled_decode(fin, fout); 146 | } else { 147 | comper::decode(fin, fout); 148 | } 149 | } else { 150 | if (moduled) { 151 | comper::moduled_encode(fin, fout); 152 | } else { 153 | comper::encode(fin, fout); 154 | } 155 | } 156 | } 157 | 158 | return 0; 159 | } 160 | -------------------------------------------------------------------------------- /src/tools/comperx.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 long_options{ 55 | option{"extract", optional_argument, nullptr, 'x'}, 56 | option{"moduled", no_argument, nullptr, 'm'}, 57 | option{"crunch", no_argument, nullptr, 'c'}, 58 | option{nullptr, 0, nullptr, 0}}; 59 | 60 | bool extract = false; 61 | bool moduled = false; 62 | bool crunch = false; 63 | size_t pointer = 0; 64 | 65 | while (true) { 66 | int option_index = 0; 67 | int option_char = getopt_long( 68 | argc, argv, "x::mc", long_options.data(), &option_index); 69 | if (option_char == -1) { 70 | break; 71 | } 72 | 73 | switch (option_char) { 74 | case 'x': 75 | extract = true; 76 | if (optarg != nullptr) { 77 | pointer = strtoul(optarg, nullptr, 0); 78 | } 79 | break; 80 | case 'c': 81 | crunch = true; 82 | break; 83 | case 'm': 84 | moduled = true; 85 | break; 86 | default: 87 | break; 88 | } 89 | } 90 | 91 | if ((!crunch && argc - optind < 2) || (crunch && argc - optind < 1)) { 92 | usage(argv[0]); 93 | return 1; 94 | } 95 | 96 | if (extract && crunch) { 97 | cerr << "Error: --extract and --crunch can't be used at the same time." 98 | << endl 99 | << endl; 100 | return 4; 101 | } 102 | 103 | const char* outfile 104 | = crunch && argc - optind < 2 ? argv[optind] : argv[optind + 1]; 105 | 106 | ifstream fin(argv[optind], ios::in | ios::binary); 107 | if (!fin.good()) { 108 | cerr << "Input file '" << argv[optind] << "' could not be opened." 109 | << endl 110 | << endl; 111 | return 2; 112 | } 113 | 114 | if (crunch) { 115 | stringstream buffer(ios::in | ios::out | ios::binary); 116 | fin.seekg(pointer); 117 | comperx::decode(fin, buffer); 118 | fin.close(); 119 | buffer.seekg(0); 120 | 121 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 122 | if (!fout.good()) { 123 | cerr << "Output file '" << argv[optind + 1] 124 | << "' could not be opened." << endl 125 | << endl; 126 | return 3; 127 | } 128 | if (moduled) { 129 | comperx::moduled_encode(buffer, fout); 130 | } else { 131 | comperx::encode(buffer, fout); 132 | } 133 | } else { 134 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 135 | if (!fout.good()) { 136 | cerr << "Output file '" << argv[optind + 1] 137 | << "' could not be opened." << endl 138 | << endl; 139 | return 3; 140 | } 141 | 142 | if (extract) { 143 | fin.seekg(pointer); 144 | if (moduled) { 145 | comperx::moduled_decode(fin, fout); 146 | } else { 147 | comperx::decode(fin, fout); 148 | } 149 | } else { 150 | if (moduled) { 151 | comperx::moduled_encode(fin, fout); 152 | } else { 153 | comperx::encode(fin, fout); 154 | } 155 | } 156 | } 157 | 158 | return 0; 159 | } 160 | -------------------------------------------------------------------------------- /src/tools/enicmp.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) Flamewing 2011-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 | 26 | using std::cerr; 27 | using std::endl; 28 | using std::fstream; 29 | using std::ifstream; 30 | using std::ios; 31 | using std::ofstream; 32 | using std::stringstream; 33 | 34 | static void usage(char* prog) { 35 | cerr << "Usage: " << prog 36 | << " [-x|--extract=[{pointer}]] {input_filename} {output_filename}" 37 | << endl; 38 | cerr << endl; 39 | cerr << "\t-x,--extract\tExtract from {pointer} address in file." << endl 40 | << endl; 41 | } 42 | 43 | int main(int argc, char* argv[]) { 44 | static constexpr const std::array long_options{ 45 | option{"extract", optional_argument, nullptr, 'x'}, 46 | option{nullptr, 0, nullptr, 0}}; 47 | 48 | bool extract = false; 49 | size_t pointer = 0; 50 | 51 | while (true) { 52 | int option_index = 0; 53 | int option_char = getopt_long( 54 | argc, argv, "x::", long_options.data(), &option_index); 55 | if (option_char == -1) { 56 | break; 57 | } 58 | 59 | if (option_char == 'x') { 60 | extract = true; 61 | if (optarg != nullptr) { 62 | pointer = strtoul(optarg, nullptr, 0); 63 | } 64 | } 65 | } 66 | 67 | if (argc - optind < 2) { 68 | usage(argv[0]); 69 | return 1; 70 | } 71 | 72 | ifstream fin(argv[optind], ios::in | ios::binary); 73 | if (!fin.good()) { 74 | cerr << "Input file '" << argv[optind] << "' could not be opened." 75 | << endl 76 | << endl; 77 | return 2; 78 | } 79 | 80 | ofstream fout(argv[optind + 1], ios::out | ios::binary); 81 | if (!fout.good()) { 82 | cerr << "Output file '" << argv[optind + 1] << "' could not be opened." 83 | << endl 84 | << endl; 85 | return 3; 86 | } 87 | 88 | if (extract) { 89 | fin.seekg(pointer); 90 | enigma::decode(fin, fout); 91 | } else { 92 | enigma::encode(fin, fout); 93 | } 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /src/tools/koscmp.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) Flamewing 2011-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 | "[-p|--padding=[{len}]] {input_filename} {output_filename}" 39 | << endl; 40 | cerr << endl; 41 | cerr << "\t-x,--extract\tExtract from {pointer} address in file." << endl; 42 | cerr << "\t-c,--crunch \tAssume input file is Kosinski-compressed and " 43 | "recompress to output file." 44 | << endl 45 | << "\t \tIf --crunch is in effect, a missing " 46 | "output_filename means recompress" 47 | << endl 48 | << "\t \tto input_filename. All parameters affect only the " 49 | "output file, except" 50 | << endl 51 | << "\t \tfor the -m parameter, which makes both input and " 52 | "output files moduled" 53 | << endl 54 | << "\t \t(but the optional module size affects only the " 55 | "output file)." 56 | << endl; 57 | cerr << "\t-m,--moduled\tUse compression in modules of 4096 bytes." << endl; 58 | cerr << "\t-p|--padding\tFor moduled compression only. Changes internal " 59 | "module padding to {len}." 60 | << endl 61 | << "\t \tEach module will be padded to a multiple of the " 62 | "given number; use 1 for" 63 | << endl 64 | << "\t \tno padding. Must be a power of 2 (default: " 65 | << moduled_kosinski::ModulePadding << ")." << endl 66 | << endl; 67 | } 68 | 69 | int main(int argc, char* argv[]) { 70 | static constexpr const std::array long_options{ 71 | option{"extract", optional_argument, nullptr, 'x'}, 72 | option{"moduled", no_argument, nullptr, 'm'}, 73 | option{"crunch", no_argument, nullptr, 'c'}, 74 | option{"padding", required_argument, nullptr, 'p'}, 75 | option{nullptr, 0, nullptr, 0}}; 76 | 77 | bool extract = false; 78 | bool moduled = false; 79 | bool crunch = false; 80 | size_t pointer = 0ULL; 81 | size_t padding = moduled_kosinski::ModulePadding; 82 | 83 | while (true) { 84 | int option_index = 0; 85 | int option_char = getopt_long( 86 | argc, argv, "x::mcr:s:p:", long_options.data(), &option_index); 87 | if (option_char == -1) { 88 | break; 89 | } 90 | 91 | switch (option_char) { 92 | case 'x': 93 | extract = true; 94 | if (optarg != nullptr) { 95 | pointer = strtoul(optarg, nullptr, 0); 96 | } 97 | break; 98 | case 'c': 99 | crunch = true; 100 | break; 101 | case 'm': 102 | moduled = true; 103 | break; 104 | case 'p': 105 | if (optarg != nullptr) { 106 | padding = strtoul(optarg, nullptr, 0); 107 | } 108 | if ((padding == 0U) || (padding & (padding - 1)) != 0) { 109 | padding = 16; 110 | } 111 | break; 112 | default: 113 | break; 114 | } 115 | } 116 | 117 | if ((!crunch && argc - optind < 2) || (crunch && argc - optind < 1)) { 118 | usage(argv[0]); 119 | return 1; 120 | } 121 | 122 | if (extract && crunch) { 123 | cerr << "Error: --extract and --crunch can't be used at the same time." 124 | << endl 125 | << endl; 126 | return 4; 127 | } 128 | 129 | const char* outfile 130 | = crunch && argc - optind < 2 ? argv[optind] : argv[optind + 1]; 131 | 132 | ifstream fin(argv[optind], ios::in | ios::binary); 133 | if (!fin.good()) { 134 | cerr << "Input file '" << argv[optind] << "' could not be opened." 135 | << endl 136 | << endl; 137 | return 2; 138 | } 139 | 140 | if (crunch) { 141 | stringstream buffer(ios::in | ios::out | ios::binary); 142 | fin.seekg(pointer); 143 | if (moduled) { 144 | kosinski::moduled_decode(fin, buffer, padding); 145 | } else { 146 | kosinski::decode(fin, buffer); 147 | } 148 | fin.close(); 149 | buffer.seekg(0); 150 | 151 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 152 | if (!fout.good()) { 153 | cerr << "Output file '" << argv[optind + 1] 154 | << "' could not be opened." << endl 155 | << endl; 156 | return 3; 157 | } 158 | if (moduled) { 159 | kosinski::moduled_encode(buffer, fout, padding); 160 | } else { 161 | kosinski::encode(buffer, fout); 162 | } 163 | } else { 164 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 165 | if (!fout.good()) { 166 | cerr << "Output file '" << argv[optind + 1] 167 | << "' could not be opened." << endl 168 | << endl; 169 | return 3; 170 | } 171 | 172 | if (extract) { 173 | fin.seekg(pointer); 174 | if (moduled) { 175 | kosinski::moduled_decode(fin, fout, padding); 176 | } else { 177 | kosinski::decode(fin, fout); 178 | } 179 | } else { 180 | if (moduled) { 181 | kosinski::moduled_encode(fin, fout, padding); 182 | } else { 183 | kosinski::encode(fin, fout); 184 | } 185 | } 186 | } 187 | 188 | return 0; 189 | } 190 | -------------------------------------------------------------------------------- /src/tools/kosplus.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) Flamewing 2011-2013 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} {output_filename}" 39 | << endl; 40 | cerr << endl; 41 | cerr << "\t-x,--extract\tExtract from {pointer} address in file." << endl; 42 | cerr << "\t-c,--crunch \tAssume input file is KosPlus-compressed and " 43 | "recompress to output file." 44 | << endl 45 | << "\t \tIf --crunch is in effect, a missing " 46 | "output_filename means recompress" 47 | << endl 48 | << "\t \tto input_filename. All parameters affect only the " 49 | "output file, except" 50 | << endl 51 | << "\t \tfor the -m parameter, which makes both input and " 52 | "output files moduled" 53 | << endl 54 | << "\t \t(but the optional module size affects only the " 55 | "output file)." 56 | << endl; 57 | cerr << "\t-m,--moduled\tUse compression in modules of 4096 bytes." << endl; 58 | } 59 | 60 | int main(int argc, char* argv[]) { 61 | static constexpr const std::array long_options{ 62 | option{"extract", optional_argument, nullptr, 'x'}, 63 | option{"moduled", no_argument, nullptr, 'm'}, 64 | option{"crunch", no_argument, nullptr, 'c'}, 65 | option{nullptr, 0, nullptr, 0}}; 66 | 67 | bool extract = false; 68 | bool moduled = false; 69 | bool crunch = false; 70 | size_t pointer = 0; 71 | 72 | while (true) { 73 | int option_index = 0; 74 | int option_char = getopt_long( 75 | argc, argv, "x::mc", long_options.data(), &option_index); 76 | if (option_char == -1) { 77 | break; 78 | } 79 | 80 | switch (option_char) { 81 | case 'x': 82 | extract = true; 83 | if (optarg != nullptr) { 84 | pointer = strtoul(optarg, nullptr, 0); 85 | } 86 | break; 87 | case 'c': 88 | crunch = true; 89 | break; 90 | case 'm': 91 | moduled = true; 92 | break; 93 | default: 94 | break; 95 | } 96 | } 97 | 98 | if ((!crunch && argc - optind < 2) || (crunch && argc - optind < 1)) { 99 | usage(argv[0]); 100 | return 1; 101 | } 102 | 103 | if (extract && crunch) { 104 | cerr << "Error: --extract and --crunch can't be used at the same time." 105 | << endl 106 | << endl; 107 | return 4; 108 | } 109 | 110 | const char* outfile 111 | = crunch && argc - optind < 2 ? argv[optind] : argv[optind + 1]; 112 | 113 | ifstream fin(argv[optind], ios::in | ios::binary); 114 | if (!fin.good()) { 115 | cerr << "Input file '" << argv[optind] << "' could not be opened." 116 | << endl 117 | << endl; 118 | return 2; 119 | } 120 | 121 | if (crunch) { 122 | stringstream buffer(ios::in | ios::out | ios::binary); 123 | fin.seekg(pointer); 124 | if (moduled) { 125 | kosplus::moduled_decode(fin, buffer); 126 | } else { 127 | kosplus::decode(fin, buffer); 128 | } 129 | fin.close(); 130 | buffer.seekg(0); 131 | 132 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 133 | if (!fout.good()) { 134 | cerr << "Output file '" << argv[optind + 1] 135 | << "' could not be opened." << endl 136 | << endl; 137 | return 3; 138 | } 139 | if (moduled) { 140 | kosplus::moduled_encode(buffer, fout); 141 | } else { 142 | kosplus::encode(buffer, fout); 143 | } 144 | } else { 145 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 146 | if (!fout.good()) { 147 | cerr << "Output file '" << argv[optind + 1] 148 | << "' could not be opened." << endl 149 | << endl; 150 | return 3; 151 | } 152 | 153 | if (extract) { 154 | fin.seekg(pointer); 155 | if (moduled) { 156 | kosplus::moduled_decode(fin, fout); 157 | } else { 158 | kosplus::decode(fin, fout); 159 | } 160 | } else { 161 | if (moduled) { 162 | kosplus::moduled_encode(fin, fout); 163 | } else { 164 | kosplus::encode(fin, fout); 165 | } 166 | } 167 | } 168 | 169 | return 0; 170 | } 171 | -------------------------------------------------------------------------------- /src/tools/lzkn1cmp.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) Flamewing 2011-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} {output_filename}" 39 | << endl; 40 | cerr << endl; 41 | cerr << "\t-x,--extract\tExtract from {pointer} address in file." << endl; 42 | cerr << "\t-c,--crunch \tAssume input file is Konami LZSS Type 1 and " 43 | "recompress to output file." 44 | << endl 45 | << "\t \tIf --crunch is in effect, a missing " 46 | "output_filename means recompress" 47 | << endl 48 | << "\t \tto input_filename. All parameters affect only the " 49 | "output file, except" 50 | << endl 51 | << "\t \tfor the -m parameter, which makes both input and " 52 | "output files moduled" 53 | << endl 54 | << "\t \t(but the optional module size affects only the " 55 | "output file)." 56 | << endl; 57 | cerr << "\t-m,--moduled\tUse compression in modules of 4096 bytes." << endl; 58 | cerr << "\t-p|--padding\tFor moduled compression only. Changes internal " 59 | "module padding to {len}." 60 | << endl 61 | << "\t \tEach module will be padded to a multiple of the " 62 | "given number; use 1 for" 63 | << endl 64 | << "\t \tno padding. Must be a power of 2 (default: " 65 | << moduled_lzkn1::ModulePadding << ")." << endl 66 | << endl; 67 | } 68 | 69 | int main(int argc, char* argv[]) { 70 | static constexpr const std::array long_options{ 71 | option{"extract", optional_argument, nullptr, 'x'}, 72 | option{"moduled", no_argument, nullptr, 'm'}, 73 | option{"crunch", no_argument, nullptr, 'c'}, 74 | option{nullptr, 0, nullptr, 0}}; 75 | 76 | bool extract = false; 77 | bool moduled = false; 78 | bool crunch = false; 79 | size_t pointer = 0ULL; 80 | 81 | while (true) { 82 | int option_index = 0; 83 | int option_char = getopt_long( 84 | argc, argv, "x::mcr:s:p:", long_options.data(), &option_index); 85 | if (option_char == -1) { 86 | break; 87 | } 88 | 89 | switch (option_char) { 90 | case 'x': 91 | extract = true; 92 | if (optarg != nullptr) { 93 | pointer = strtoul(optarg, nullptr, 0); 94 | } 95 | break; 96 | case 'c': 97 | crunch = true; 98 | break; 99 | case 'm': 100 | moduled = true; 101 | break; 102 | default: 103 | break; 104 | } 105 | } 106 | 107 | if ((!crunch && argc - optind < 2) || (crunch && argc - optind < 1)) { 108 | usage(argv[0]); 109 | return 1; 110 | } 111 | 112 | if (extract && crunch) { 113 | cerr << "Error: --extract and --crunch can't be used at the same time." 114 | << endl 115 | << endl; 116 | return 4; 117 | } 118 | 119 | const char* outfile 120 | = crunch && argc - optind < 2 ? argv[optind] : argv[optind + 1]; 121 | 122 | ifstream fin(argv[optind], ios::in | ios::binary); 123 | if (!fin.good()) { 124 | cerr << "Input file '" << argv[optind] << "' could not be opened." 125 | << endl 126 | << endl; 127 | return 2; 128 | } 129 | 130 | if (crunch) { 131 | stringstream buffer(ios::in | ios::out | ios::binary); 132 | fin.seekg(pointer); 133 | if (moduled) { 134 | lzkn1::moduled_decode(fin, buffer); 135 | } else { 136 | lzkn1::decode(fin, buffer); 137 | } 138 | fin.close(); 139 | buffer.seekg(0); 140 | 141 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 142 | if (!fout.good()) { 143 | cerr << "Output file '" << argv[optind + 1] 144 | << "' could not be opened." << endl 145 | << endl; 146 | return 3; 147 | } 148 | if (moduled) { 149 | lzkn1::moduled_encode(buffer, fout); 150 | } else { 151 | lzkn1::encode(buffer, fout); 152 | } 153 | } else { 154 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 155 | if (!fout.good()) { 156 | cerr << "Output file '" << argv[optind + 1] 157 | << "' could not be opened." << endl 158 | << endl; 159 | return 3; 160 | } 161 | 162 | if (extract) { 163 | fin.seekg(pointer); 164 | if (moduled) { 165 | lzkn1::moduled_decode(fin, fout); 166 | } else { 167 | lzkn1::decode(fin, fout); 168 | } 169 | } else { 170 | if (moduled) { 171 | lzkn1::moduled_encode(fin, fout); 172 | } else { 173 | lzkn1::encode(fin, fout); 174 | } 175 | } 176 | } 177 | 178 | return 0; 179 | } 180 | -------------------------------------------------------------------------------- /src/tools/nemcmp.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) Flamewing 2011-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 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | using std::cerr; 30 | using std::cout; 31 | using std::endl; 32 | using std::fstream; 33 | using std::hex; 34 | using std::ifstream; 35 | using std::ios; 36 | using std::ofstream; 37 | using std::right; 38 | using std::setfill; 39 | using std::setw; 40 | using std::stringstream; 41 | using std::uppercase; 42 | 43 | static void usage(char* prog) { 44 | cerr << "Usage: " << prog 45 | << " [-i] [-c|--crunch|-x|--extract=[{pointer}]] {input_filename} " 46 | "{output_filename}" 47 | << endl; 48 | cerr << endl; 49 | cerr << "\t-i \tWhen extracting, print out the position where the " 50 | "Nemesis data ends." 51 | << endl; 52 | cerr << "\t-x,--extract\tExtract from {pointer} address in file." << endl; 53 | cerr << "\t-c,--crunch \tAssume input file is Nemesis-compressed and " 54 | "recompress to output file." 55 | << endl 56 | << "\t \tIf --crunch is in effect, a missing " 57 | "output_filename means recompress" 58 | << endl 59 | << "\t \tto input_filename." << endl 60 | << endl; 61 | } 62 | 63 | int main(int argc, char* argv[]) { 64 | static constexpr const std::array long_options{ 65 | option{"extract", optional_argument, nullptr, 'x'}, 66 | option{"crunch", no_argument, nullptr, 'c'}, 67 | option{nullptr, 0, nullptr, 0}}; 68 | 69 | bool extract = false; 70 | bool printend = false; 71 | bool crunch = false; 72 | size_t pointer = 0; 73 | 74 | while (true) { 75 | int option_index = 0; 76 | int option_char = getopt_long( 77 | argc, argv, "x::ic", long_options.data(), &option_index); 78 | if (option_char == -1) { 79 | break; 80 | } 81 | 82 | switch (option_char) { 83 | case 'i': 84 | printend = true; 85 | break; 86 | case 'x': 87 | extract = true; 88 | if (optarg != nullptr) { 89 | pointer = strtoul(optarg, nullptr, 0); 90 | } 91 | break; 92 | case 'c': 93 | crunch = true; 94 | break; 95 | default: 96 | break; 97 | } 98 | } 99 | 100 | if ((!crunch && argc - optind < 2) || (crunch && argc - optind < 1)) { 101 | usage(argv[0]); 102 | return 1; 103 | } 104 | 105 | if (extract && crunch) { 106 | cerr << "Error: --extract and --crunch can't be used at the same time." 107 | << endl 108 | << endl; 109 | return 4; 110 | } 111 | if (printend && !extract) { 112 | cerr << "Error: -i must be used with --extract." << endl << endl; 113 | return 5; 114 | } 115 | 116 | const char* outfile 117 | = crunch && argc - optind < 2 ? argv[optind] : argv[optind + 1]; 118 | 119 | ifstream fin(argv[optind], ios::in | ios::binary); 120 | if (!fin.good()) { 121 | cerr << "Input file '" << argv[optind] << "' could not be opened." 122 | << endl 123 | << endl; 124 | return 2; 125 | } 126 | 127 | if (crunch) { 128 | stringstream buffer(ios::in | ios::out | ios::binary); 129 | fin.seekg(pointer); 130 | nemesis::decode(fin, buffer); 131 | fin.close(); 132 | buffer.seekg(0); 133 | 134 | ofstream fout(outfile, ios::out | ios::binary); 135 | if (!fout.good()) { 136 | cerr << "Output file '" << outfile << "' could not be opened." 137 | << endl 138 | << endl; 139 | return 3; 140 | } 141 | nemesis::encode(buffer, fout); 142 | } else { 143 | ofstream fout(outfile, ios::out | ios::binary); 144 | if (!fout.good()) { 145 | cerr << "Output file '" << outfile << "' could not be opened." 146 | << endl 147 | << endl; 148 | return 3; 149 | } 150 | 151 | if (extract) { 152 | fin.seekg(pointer); 153 | nemesis::decode(fin, fout); 154 | if (printend) { 155 | boost::io::ios_all_saver flags(cout); 156 | cout << "0x" << hex << setw(6) << setfill('0') << uppercase 157 | << right << fin.tellg() << endl; 158 | } 159 | } else { 160 | nemesis::encode(fin, fout); 161 | } 162 | } 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /src/tools/rockcmp.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}]] {input_filename} " 38 | "{output_filename}" 39 | << endl; 40 | cerr << endl; 41 | cerr << "\t-x,--extract\tExtract from {pointer} address in file." << endl; 42 | cerr << "\t-c,--crunch \tAssume input file is Rocket-compressed and " 43 | "recompress to output file." 44 | << endl 45 | << "\t \tIf --crunch is in effect, a missing " 46 | "output_filename means recompress" 47 | << endl 48 | << "\t \tto input_filename." << endl 49 | << endl; 50 | } 51 | 52 | int main(int argc, char* argv[]) { 53 | static constexpr const std::array long_options{ 54 | option{"extract", optional_argument, nullptr, 'x'}, 55 | option{"crunch", no_argument, nullptr, 'c'}, 56 | option{nullptr, 0, nullptr, 0}}; 57 | 58 | bool extract = false; 59 | bool crunch = false; 60 | size_t pointer = 0; 61 | 62 | while (true) { 63 | int option_index = 0; 64 | int option_char = getopt_long( 65 | argc, argv, "x::c", long_options.data(), &option_index); 66 | if (option_char == -1) { 67 | break; 68 | } 69 | 70 | switch (option_char) { 71 | case 'x': 72 | extract = true; 73 | if (optarg != nullptr) { 74 | pointer = strtoul(optarg, nullptr, 0); 75 | } 76 | break; 77 | case 'c': 78 | crunch = true; 79 | break; 80 | default: 81 | break; 82 | } 83 | } 84 | 85 | if ((!crunch && argc - optind < 2) || (crunch && argc - optind < 1)) { 86 | usage(argv[0]); 87 | return 1; 88 | } 89 | 90 | if (extract && crunch) { 91 | cerr << "Error: --extract and --crunch can't be used at the same time." 92 | << endl 93 | << endl; 94 | return 4; 95 | } 96 | 97 | const char* outfile 98 | = crunch && argc - optind < 2 ? argv[optind] : argv[optind + 1]; 99 | 100 | ifstream fin(argv[optind], ios::in | ios::binary); 101 | if (!fin.good()) { 102 | cerr << "Input file '" << argv[optind] << "' could not be opened." 103 | << endl 104 | << endl; 105 | return 2; 106 | } 107 | 108 | if (crunch) { 109 | stringstream buffer(ios::in | ios::out | ios::binary); 110 | fin.seekg(pointer); 111 | rocket::decode(fin, buffer); 112 | fin.close(); 113 | buffer.seekg(0); 114 | 115 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 116 | if (!fout.good()) { 117 | cerr << "Output file '" << argv[optind + 1] 118 | << "' could not be opened." << endl 119 | << endl; 120 | return 3; 121 | } 122 | rocket::encode(buffer, fout); 123 | } else { 124 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 125 | if (!fout.good()) { 126 | cerr << "Output file '" << argv[optind + 1] 127 | << "' could not be opened." << endl 128 | << endl; 129 | return 3; 130 | } 131 | 132 | if (extract) { 133 | fin.seekg(pointer); 134 | rocket::decode(fin, fout); 135 | } else { 136 | rocket::encode(fin, fout); 137 | } 138 | } 139 | 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /src/tools/saxcmp.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 | #include 27 | 28 | using std::cerr; 29 | using std::endl; 30 | using std::fstream; 31 | using std::ifstream; 32 | using std::ios; 33 | using std::ofstream; 34 | using std::stringstream; 35 | 36 | static void usage(char* prog) { 37 | cerr << "Usage: " << prog 38 | << " [-s size|-S] [-c|--crunch|-x|--extract=[{pointer}]] " 39 | "{input_filename} {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 Saxman-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 | << "\t-s size \tAssume input file does not have a file size and " 51 | "use value given instead." 52 | << endl 53 | << "\t \tOnly affects decompression." << endl 54 | << "\t-S \tCauses the compressor to not output a file size. " 55 | "Only affects compression." 56 | << endl 57 | << endl; 58 | } 59 | 60 | int main(int argc, char* argv[]) { 61 | static constexpr const std::array long_options{ 62 | option{"extract", optional_argument, nullptr, 'x'}, 63 | option{"crunch", no_argument, nullptr, 'c'}, 64 | option{nullptr, 0, nullptr, 0}}; 65 | 66 | bool extract = false; 67 | bool crunch = false; 68 | bool WithSize = true; 69 | size_t pointer = 0; 70 | size_t BSize = 0; 71 | 72 | while (true) { 73 | int option_index = 0; 74 | int option_char = getopt_long( 75 | argc, argv, "x::cs:S", long_options.data(), &option_index); 76 | if (option_char == -1) { 77 | break; 78 | } 79 | 80 | switch (option_char) { 81 | case 'x': 82 | extract = true; 83 | if (optarg != nullptr) { 84 | pointer = strtoul(optarg, nullptr, 0); 85 | } 86 | break; 87 | case 'c': 88 | crunch = true; 89 | break; 90 | case 's': 91 | assert(optarg != nullptr); 92 | BSize = strtoul(optarg, nullptr, 0); 93 | if (BSize == 0) { 94 | cerr << "Error: specified size must be a positive number." 95 | << endl 96 | << endl; 97 | return 4; 98 | } 99 | break; 100 | case 'S': 101 | WithSize = false; 102 | break; 103 | default: 104 | break; 105 | } 106 | } 107 | 108 | if ((!crunch && argc - optind < 2) || (crunch && argc - optind < 1)) { 109 | usage(argv[0]); 110 | return 1; 111 | } 112 | 113 | if (extract && crunch) { 114 | cerr << "Error: --extract and --crunch can't be used at the same time." 115 | << endl 116 | << endl; 117 | return 4; 118 | } 119 | 120 | const char* outfile 121 | = crunch && argc - optind < 2 ? argv[optind] : argv[optind + 1]; 122 | 123 | ifstream fin(argv[optind], ios::in | ios::binary); 124 | if (!fin.good()) { 125 | cerr << "Input file '" << argv[optind] << "' could not be opened." 126 | << endl 127 | << endl; 128 | return 2; 129 | } 130 | 131 | if (crunch) { 132 | stringstream buffer(ios::in | ios::out | ios::binary); 133 | fin.seekg(pointer); 134 | saxman::decode(fin, buffer, BSize); 135 | fin.close(); 136 | buffer.seekg(0); 137 | 138 | ofstream fout(outfile, ios::out | ios::binary); 139 | if (!fout.good()) { 140 | cerr << "Output file '" << argv[optind + 1] 141 | << "' could not be opened." << endl 142 | << endl; 143 | return 3; 144 | } 145 | saxman::encode(buffer, fout, WithSize); 146 | } else { 147 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 148 | if (!fout.good()) { 149 | cerr << "Output file '" << argv[optind + 1] 150 | << "' could not be opened." << endl 151 | << endl; 152 | return 3; 153 | } 154 | 155 | if (extract) { 156 | fin.seekg(pointer); 157 | saxman::decode(fin, fout, BSize); 158 | } else { 159 | saxman::encode(fin, fout, WithSize); 160 | } 161 | } 162 | 163 | return 0; 164 | } 165 | -------------------------------------------------------------------------------- /src/tools/snkcmp.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) Flamewing 2017 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}]] {input_filename} " 38 | "{output_filename}" 39 | << endl; 40 | cerr << endl; 41 | cerr << "\t-x,--extract\tExtract from {pointer} address in file." << endl; 42 | cerr << "\t-c,--crunch \tAssume input file is SNK-RLE-compressed and " 43 | "recompress to output file." 44 | << endl 45 | << "\t \tIf --crunch is in effect, a missing " 46 | "output_filename means recompress" 47 | << endl 48 | << "\t \tto input_filename." << endl 49 | << endl; 50 | } 51 | 52 | int main(int argc, char* argv[]) { 53 | static constexpr const std::array long_options{ 54 | option{"extract", optional_argument, nullptr, 'x'}, 55 | option{"crunch", no_argument, nullptr, 'c'}, 56 | option{nullptr, 0, nullptr, 0}}; 57 | 58 | bool extract = false; 59 | bool crunch = false; 60 | size_t pointer = 0; 61 | 62 | while (true) { 63 | int option_index = 0; 64 | int option_char = getopt_long( 65 | argc, argv, "x::c", long_options.data(), &option_index); 66 | if (option_char == -1) { 67 | break; 68 | } 69 | 70 | switch (option_char) { 71 | case 'x': 72 | extract = true; 73 | if (optarg != nullptr) { 74 | pointer = strtoul(optarg, nullptr, 0); 75 | } 76 | break; 77 | case 'c': 78 | crunch = true; 79 | break; 80 | default: 81 | break; 82 | } 83 | } 84 | 85 | if ((!crunch && argc - optind < 2) || (crunch && argc - optind < 1)) { 86 | usage(argv[0]); 87 | return 1; 88 | } 89 | 90 | if (extract && crunch) { 91 | cerr << "Error: --extract and --crunch can't be used at the same time." 92 | << endl 93 | << endl; 94 | return 4; 95 | } 96 | 97 | const char* outfile 98 | = crunch && argc - optind < 2 ? argv[optind] : argv[optind + 1]; 99 | 100 | ifstream fin(argv[optind], ios::in | ios::binary); 101 | if (!fin.good()) { 102 | cerr << "Input file '" << argv[optind] << "' could not be opened." 103 | << endl 104 | << endl; 105 | return 2; 106 | } 107 | 108 | if (crunch) { 109 | stringstream buffer(ios::in | ios::out | ios::binary); 110 | fin.seekg(pointer); 111 | snkrle::decode(fin, buffer); 112 | fin.close(); 113 | buffer.seekg(0); 114 | 115 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 116 | if (!fout.good()) { 117 | cerr << "Output file '" << argv[optind + 1] 118 | << "' could not be opened." << endl 119 | << endl; 120 | return 3; 121 | } 122 | snkrle::encode(buffer, fout); 123 | } else { 124 | fstream fout(outfile, ios::in | ios::out | ios::binary | ios::trunc); 125 | if (!fout.good()) { 126 | cerr << "Output file '" << argv[optind + 1] 127 | << "' could not be opened." << endl 128 | << endl; 129 | return 3; 130 | } 131 | 132 | if (extract) { 133 | fin.seekg(pointer); 134 | snkrle::decode(fin, fout); 135 | } else { 136 | snkrle::encode(fin, fout); 137 | } 138 | } 139 | 140 | return 0; 141 | } 142 | --------------------------------------------------------------------------------