Projects
Extra
pkg2zip
_service:obs_scm:pkg2zip-2.2+git.c75a9b2.159215...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:obs_scm:pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2.obscpio of Package pkg2zip
07070100000000000081A4000001ED0000006B000000015EE6501B00000206000000000000000000000000000000000000003900000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/.appveyor.ymlversion: '#{build}' skip_tags: true build: off deploy: off environment: matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 PATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;%PATH% CC: gcc - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 PATH: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin;%PATH% CC: gcc - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 test_script: - if "%CC%" == "" call build.cmd - if "%CC%" == "gcc" mingw32-make 07070100000001000081A4000001ED0000006B000000015EE6501B00000107000000000000000000000000000000000000003700000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/.travis.ymllanguage: c matrix: include: - os: linux dist: trusty sudo: false compiler: gcc - os: linux dist: trusty sudo: false compiler: clang - os: osx osx_image: xcode9.1 compiler: clang script: - make 07070100000002000081A4000001ED0000006B000000015EE6501B000004BA000000000000000000000000000000000000003300000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/LICENSEThis is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to <http://unlicense.org> 07070100000003000081A4000001ED0000006B000000015EE6501B00001826000000000000000000000000000000000000003500000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/README.md# pkg2zip [![Travis CI Build Status][img_travis]][travis] [![AppVeyor Build Status][img_appveyor]][appveyor] [![Downloads][img_downloads]][downloads] [![Release][img_latest]][latest] [![License][img_license]][license] Utility that decrypts PlayStation Vita pkg file and creates zip package. Supported pkg files - main application, DLC, patch, theme and PSM files. Also supports PSX and PSP pkg files for use with [Adrenaline][]. Optionally writes [NoNpDrm][] or [NoPsmDrm][] fake license file from zRIF string. You must provide license key. # Requirements * [Henkaku][] / [Enso][] * [Enso][] for Vita Theme installation via bgdl. * [NoNpDrm][] * [NoPsmDrm][] for PSM titles * [VitaShell][] **v1.76** or newer required for DLC installation * [Adrenaline][] for PSX or PSP titles * [npdrm_free][] for PSP titles in eboot format. # Features * **portable**, written in cross-platform C code, runs on Windows, GNU/Linux, macOS (system dependent functionality is isolated in sys.c file). * **small**, has no external library dependencies and uses very minimal dynamic memory allocations. * **fast**, uses AESNI hardware accelerated AES decryption if supported by CPU (requires [AESNI][] and [SSSE3][] instructions). * **simple**, creates zip package with same folder structure that Vita expects (just drag & drop all file from zip archive to ux0:). Zip file is created directly from pkg without any intermediate temporary files. * **Vita DLC**, **Vita PATCH** and **PSM** pkg unpacking. * **PSX**, **PSP**, **PSP Updates**, **PSP DLC**, and **PSP THEME** pkg unpacking. Limitations: * no actual title name is extracted for PSM pkg files. # Usage If you have zRIF fake license, then execute: pkg2zip package.pkg zRIF_STRING This will create `title [id] [region].zip` file. Title, ID and region is automatically detected from pkg file. It will include work.bin file. If you don't have zRIF fake license, but just want to unpack files, then omit last argument: pkg2zip package.pkg Resulting zip file will not include work.bin. This is useful for patch pkg files. To get output file name of the zip, use `-l` (must come before pkg file and cannot be used with `-x`): pkg2zip -l package.pkg To avoid zipping process and create individual files, use `-x` argument (must come before pkg file): pkg2zip -x package.pkg [zRIF_STRING] To disable bgdl output for VITA Theme extraction, use the '-b' argument. pkg2zip -b -x package.pkg zRIF_STRING PSX or PSP pkg files do not require zRIF argument. It will be ignored. For PSP files pkg2zip by default will create a .ISO file. To create a compressed .CSO file pass -cN argument where N is compression factor. For example, for fastest compression use: pkg2zip -c1 package.pkg To create smaller cso file (more compression will require more time) use -c9, or anything inbetween: pkg2zip -c9 package.pkg You can combine -cN argument together with -x: pkg2zip -x -c9 package.pkg To extract PSP files in their original EBOOT.PBP format use the '-p' argument: pkg2zip -p package.pkg Note: On PSP hardware titles with DLC should be kept in ISO/CSO format due to limitations on the CFW NoDRM Engine. # Generating zRIF string If you have working NoNpDrm license file (work.bin or 6488b73b912a753a492e2714e9b38bc7.rif) you can create zRIF string with `rif2zrif.py` python script: $ python rif2zrif.py path/to/work.bin It will print zRIF string to stdout. To generate work.bin from zRIF string use `zrif2rif.py` script: $ python zrif2rif.py zRIF work.bin Last argument is optional, it specifies where to save file and defaults to work.bin name. # Download Get latest Windows binaries [here][downloads]. ArchLinux users can build binary with [pkg2zip][AUR] package in AUR repository. For example, with pacaur: $ pacaur -S pkg2zip openSUSE users can download the package from the [Packman](http://packman.links2linux.de/package/pkg2zip) repository. If this repository is enabled, just install pkg2zip with zypper. # zypper install pkg2zip # Building Execute `make` if you are on GNU/Linux or macOS (gcc comiler required) To install the resulting file use `make "install` as root On Windows you can build either with MinGW (get [MinGW-w64][]) or [Visual Studio 2017 Community Edition][vs2017ce]. * for MinGW make sure you have make installed, and then execute `mingw32-make` * for Visual Studio run `build.cmd` # Alternatives * https://github.com/RikuKH3/unpkg_vita * https://github.com/St4rk/PkgDecrypt * https://github.com/weaknespase/PkgDecrypt # License This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. [travis]: https://travis-ci.org/mmozeiko/pkg2zip/ [appveyor]: https://ci.appveyor.com/project/mmozeiko/pkg2zip/ [downloads]: https://github.com/lusid1/pkg2zip/releases [latest]: https://github.com/lusid1/pkg2zip/releases/latest [license]: https://github.com/lusid1/pkg2zip/blob/master/LICENSE [img_travis]: https://api.travis-ci.org/mmozeiko/pkg2zip.svg?branch=master [img_appveyor]: https://ci.appveyor.com/api/projects/status/xmkl6509ahlp9b7k/branch/master?svg=true [img_downloads]: https://img.shields.io/github/downloads/lusid1/pkg2zip/total.svg?maxAge=3600 [img_latest]: https://img.shields.io/github/release/lusid1/pkg2zip.svg?maxAge=3600 [img_license]: https://img.shields.io/github/license/mmozeiko/pkg2zip.svg?maxAge=2592000 [Adrenaline]: https://github.com/TheOfficialFloW/Adrenaline [NoNpDrm]: https://github.com/TheOfficialFloW/NoNpDrm [NoPsmDrm]: https://github.com/frangarcj/NoPsmDrm [Henkaku]: https://henkaku.xyz/ [Enso]: https://enso.henkaku.xyz/ [VitaShell]: https://github.com/TheOfficialFloW/VitaShell [AESNI]: https://en.wikipedia.org/wiki/AES_instruction_set [SSSE3]: https://en.wikipedia.org/wiki/SSSE3 [AUR]: https://aur.archlinux.org/packages/pkg2zip/ [MinGW-w64]: http://www.msys2.org/ [vs2017ce]: https://www.visualstudio.com/vs/community/ [npdrm_free]: https://github.com/qwikrazor87/npdrm_free 07070100000004000081A4000001ED0000006B000000015EE6501B0000019E000000000000000000000000000000000000003500000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/build.cmd@echo off call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 cd /d "%~dp0" set CL=/nologo /errorReport:none /Gm- /GF /GS- /MP /MT /W4 /WX /wd4324 /D_CRT_SECURE_NO_DEPRECATE set LINK=/errorReport:none /INCREMENTAL:NO set CL=%CL% /Ox rem set CL=%CL% /Od /Zi rem set LINK=%LINK% /DEBUG cl.exe pkg2zip*.c miniz_tdef.c puff.c /Fepkg2zip.exe 07070100000005000081A4000001ED0000006B000000015EE6501B0000049F000000000000000000000000000000000000003400000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/makefileifeq ($(OS),Windows_NT) RM := del /q EXE := .exe else EXE := endif DESTDIR = PREFIX = /usr/local BINDIR = $(PREFIX)/bin BIN = pkg2zip${EXE} SRC = ${wildcard pkg2zip*.c} miniz_tdef.c puff.c OBJ = ${SRC:.c=.o} DEP = ${SRC:.c=.d} CFLAGS = -std=c99 -pipe -fvisibility=hidden -Wall -Wextra -Werror -DNDEBUG -D_GNU_SOURCE -O2 ${BIN}: LDFLAGS += -s debug: CFLAGS += -g debug: LDFLAGS += -g .PHONY: all clean all: ${BIN} install: install -o root -g root -m 0755 ${BIN} $(DESTDIR)$(BINDIR)/${BIN} install -o root -g root -m 0755 rif2zrif.py $(DESTDIR)$(BINDIR)/rif2zrif install -o root -g root -m 0755 zrif2rif.py $(DESTDIR)$(BINDIR)/zrif2rif uninstall: rm -f $(DESTDIR)$(BINDIR)/${BIN} rm -f $(DESTDIR)$(BINDIR)/rif2zrif rm -f $(DESTDIR)$(BINDIR)/zrif2rif clean: @${RM} ${BIN} ${OBJ} ${DEP} ${BIN}: ${OBJ} @echo [L] $@ @${CC} ${LDFLAGS} -o $@ $^ debug: ${OBJ} @echo [L] ${BIN} @${CC} ${LDFLAGS} -o ${BIN} $^ %aes_x86.o: %aes_x86.c @echo [C] $< @${CC} ${CFLAGS} -maes -mssse3 -MMD -c -o $@ $< %crc32_x86.o: %crc32_x86.c @echo [C] $< @${CC} ${CFLAGS} -mpclmul -msse4 -MMD -c -o $@ $< %.o: %.c @echo [C] $< @${CC} ${CFLAGS} -MMD -c -o $@ $< -include ${DEP} 07070100000006000081A4000001ED0000006B000000015EE6501B0000F0A2000000000000000000000000000000000000003800000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/miniz_tdef.c#include "miniz_tdef.h" #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) /* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ #define MINIZ_X86_OR_X64_CPU 1 #else #define MINIZ_X86_OR_X64_CPU 0 #endif #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU /* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ #define MINIZ_LITTLE_ENDIAN 1 #else #define MINIZ_LITTLE_ENDIAN 0 #endif #if MINIZ_X86_OR_X64_CPU /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #else #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 #endif #if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) /* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ #define MINIZ_HAS_64BIT_REGISTERS 1 #else #define MINIZ_HAS_64BIT_REGISTERS 0 #endif // ------------------- Low-level Compression (independent from all decompression API's) // Purposely making these tables static for faster init and thread safety. static const mz_uint16 s_tdefl_len_sym[256] = { 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 }; static const mz_uint8 s_tdefl_len_extra[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 }; static const mz_uint8 s_tdefl_small_dist_sym[512] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 }; static const mz_uint8 s_tdefl_small_dist_extra[512] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }; static const mz_uint8 s_tdefl_large_dist_sym[128] = { 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; static const mz_uint8 s_tdefl_large_dist_extra[128] = { 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 }; // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) { mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { const mz_uint32 *pHist = &hist[pass << 8]; mz_uint offsets[256], cur_ofs = 0; for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; { tdefl_sym_freq *t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } } return pCur_syms; } // tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { int root, leaf, next, avbl, used, dpth; if (n == 0) return; else if (n == 1) { A[0].m_key = 1; return; } A[0].m_key += A[1].m_key; root = 0; leaf = 2; for (next = 1; next < n - 1; next++) { if (leaf >= n || A[root].m_key < A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = (mz_uint16)next; } else A[next].m_key = A[leaf++].m_key; if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); A[root++].m_key = (mz_uint16)next; } else A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); } A[n - 2].m_key = 0; for (next = n - 3; next >= 0; next--) A[next].m_key = A[A[next].m_key].m_key + 1; avbl = 1; used = dpth = 0; root = n - 2; next = n - 1; while (avbl > 0) { while (root >= 0 && (int)A[root].m_key == dpth) { used++; root--; } while (avbl > used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } avbl = 2 * used; dpth++; used = 0; } } // Limits canonical Huffman code table's max code size. enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) { int i; mz_uint32 total = 0; if (code_list_len <= 1) return; for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); while (total != (1UL << max_code_size)) { pNum_codes[max_code_size]--; for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } total--; } } static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) { int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); if (static_table) { for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; } else { tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; int num_used_syms = 0; const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); for (i = 1, j = num_used_syms; i <= code_size_limit; i++) for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); } next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); for (i = 0; i < table_len; i++) { mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; } } #define TDEFL_PUT_BITS(b, l) \ do \ { \ mz_uint bits = b; \ mz_uint len = l; \ MZ_ASSERT(bits <= ((1U << len) - 1U)); \ d->m_bit_buffer |= (bits << d->m_bits_in); \ d->m_bits_in += len; \ while (d->m_bits_in >= 8) \ { \ if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ d->m_bit_buffer >>= 8; \ d->m_bits_in -= 8; \ } \ } \ MZ_MACRO_END #define TDEFL_RLE_PREV_CODE_SIZE() \ { \ if (rle_repeat_count) \ { \ if (rle_repeat_count < 3) \ { \ d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ while (rle_repeat_count--) \ packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ } \ else \ { \ d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 16; \ packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ } \ rle_repeat_count = 0; \ } \ } #define TDEFL_RLE_ZERO_CODE_SIZE() \ { \ if (rle_z_count) \ { \ if (rle_z_count < 3) \ { \ d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ while (rle_z_count--) \ packed_code_sizes[num_packed_code_sizes++] = 0; \ } \ else if (rle_z_count <= 10) \ { \ d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 17; \ packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ } \ else \ { \ d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 18; \ packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ } \ rle_z_count = 0; \ } \ } static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; static void tdefl_start_dynamic_block(tdefl_compressor *d) { int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; d->m_huff_count[0][256] = 1; tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); for (i = 0; i < total_code_sizes_to_pack; i++) { mz_uint8 code_size = code_sizes_to_pack[i]; if (!code_size) { TDEFL_RLE_PREV_CODE_SIZE(); if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } } else { TDEFL_RLE_ZERO_CODE_SIZE(); if (code_size != prev_code_size) { TDEFL_RLE_PREV_CODE_SIZE(); d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; } else if (++rle_repeat_count == 6) { TDEFL_RLE_PREV_CODE_SIZE(); } } prev_code_size = code_size; } if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); TDEFL_PUT_BITS(2, 2); TDEFL_PUT_BITS(num_lit_codes - 257, 5); TDEFL_PUT_BITS(num_dist_codes - 1, 5); for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) { mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); } } static void tdefl_start_static_block(tdefl_compressor *d) { mz_uint i; mz_uint8 *p = &d->m_huff_code_sizes[0][0]; for (i = 0; i <= 143; ++i) *p++ = 8; for (; i <= 255; ++i) *p++ = 9; for (; i <= 279; ++i) *p++ = 7; for (; i <= 287; ++i) *p++ = 8; memset(d->m_huff_code_sizes[1], 5, 32); tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); TDEFL_PUT_BITS(1, 2); } static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; mz_uint8 *pOutput_buf = d->m_pOutput_buf; mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; mz_uint64 bit_buffer = d->m_bit_buffer; mz_uint bits_in = d->m_bits_in; #define TDEFL_PUT_BITS_FAST(b, l) \ { \ bit_buffer |= (((mz_uint64)(b)) << bits_in); \ bits_in += (l); \ } flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint s0, s1, n0, n1, sym, num_extra_bits; mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); // This sequence coaxes MSVC into using cmov's vs. jmp's. s0 = s_tdefl_small_dist_sym[match_dist & 511]; n0 = s_tdefl_small_dist_extra[match_dist & 511]; s1 = s_tdefl_large_dist_sym[match_dist >> 8]; n1 = s_tdefl_large_dist_extra[match_dist >> 8]; sym = (match_dist < 512) ? s0 : s1; num_extra_bits = (match_dist < 512) ? n0 : n1; MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } } if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; *(mz_uint64 *)pOutput_buf = bit_buffer; pOutput_buf += (bits_in >> 3); bit_buffer >>= (bits_in & ~7); bits_in &= 7; } #undef TDEFL_PUT_BITS_FAST d->m_pOutput_buf = pOutput_buf; d->m_bits_in = 0; d->m_bit_buffer = 0; while (bits_in) { mz_uint32 n = MZ_MIN(bits_in, 16); TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); bit_buffer >>= n; bits_in -= n; } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #else static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint sym, num_extra_bits; mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); if (match_dist < 512) { sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; } else { sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; } MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { if (static_block) tdefl_start_static_block(d); else tdefl_start_dynamic_block(d); return tdefl_compress_lz_codes(d); } static int tdefl_flush_block(tdefl_compressor *d, int flush) { mz_uint saved_bit_buf, saved_bits_in; mz_uint8 *pSaved_output_buf; mz_bool comp_block_succeeded = MZ_FALSE; int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; mz_uint8 *pOutput_buf_start = ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; d->m_pOutput_buf = pOutput_buf_start; d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; MZ_ASSERT(!d->m_output_flush_remaining); d->m_output_flush_ofs = 0; d->m_output_flush_remaining = 0; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); } TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; if (!use_raw_block) comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) { mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; TDEFL_PUT_BITS(0, 2); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); } for (i = 0; i < d->m_total_lz_bytes; ++i) { TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); } } // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. else if (!comp_block_succeeded) { d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; tdefl_compress_block(d, MZ_TRUE); } if (flush) { if (flush == TDEFL_FINISH) { if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } } else { mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } } } MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { if (pOutput_buf_start == d->m_output_buf) { int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); d->m_out_buf_ofs += bytes_to_copy; if ((n -= bytes_to_copy) != 0) { d->m_output_flush_ofs = bytes_to_copy; d->m_output_flush_remaining = n; } } else { d->m_out_buf_ofs += n; } } return d->m_output_flush_remaining; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES static MZ_FORCEINLINE mz_uint16 TDEFL_READ_UNALIGNED_WORD(const void* p) { return *(const mz_uint16 *)p; } static MZ_FORCEINLINE mz_uint32 TDEFL_READ_UNALIGNED_DWORD(const void* p) { return *(const mz_uint32 *)p; } static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for (;;) { for (;;) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; q = (const mz_uint16 *)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32; do { } while ((TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0)); if (!probe_len) { *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); break; } else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); } } } #else static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint8 *s = d->m_dict + pos, *p, *q; mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for (;;) { for (;;) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; if (probe_len > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; } } } #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN static mz_bool tdefl_compress_fast(tdefl_compressor *d) { // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); d->m_src_buf_left -= num_bytes_to_process; lookahead_size += num_bytes_to_process; while (num_bytes_to_process) { mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); memcpy(d->m_dict + dst_pos, d->m_pSrc, n); if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); d->m_pSrc += n; dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; num_bytes_to_process -= n; } dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; while (lookahead_size >= 4) { mz_uint cur_match_dist, cur_match_len = 1; mz_uint8 *pCur_dict = d->m_dict + cur_pos; mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; mz_uint probe_pos = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)lookahead_pos; if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((TDEFL_READ_UNALIGNED_DWORD(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) { const mz_uint16 *p = (const mz_uint16 *)pCur_dict; const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); mz_uint32 probe_len = 32; do { } while ((TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0)); cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); if (!probe_len) cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) { cur_match_len = 1; *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } else { mz_uint32 s0, s1; cur_match_len = MZ_MIN(cur_match_len, lookahead_size); MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); cur_match_dist--; pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; pLZ_code_buf += 3; *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; } } else { *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } total_lz_bytes += cur_match_len; lookahead_pos += cur_match_len; dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; MZ_ASSERT(lookahead_size >= cur_match_len); lookahead_size -= cur_match_len; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } while (lookahead_size) { mz_uint8 lit = d->m_dict[cur_pos]; total_lz_bytes++; *pLZ_code_buf++ = lit; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } d->m_huff_count[0][lit]++; lookahead_pos++; dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; lookahead_size--; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } } d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; return MZ_TRUE; } #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) { d->m_total_lz_bytes++; *d->m_pLZ_code_buf++ = lit; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } d->m_huff_count[0][lit]++; } static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) { mz_uint32 s0, s1; MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); d->m_total_lz_bytes += match_len; d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); match_dist -= 1; d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; } static mz_bool tdefl_compress_normal(tdefl_compressor *d) { const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; tdefl_flush flush = d->m_flush; while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; src_buf_left -= num_bytes_to_process; d->m_lookahead_size += num_bytes_to_process; while (pSrc != pSrc_end) { mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; } } else { while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { mz_uint8 c = *pSrc++; mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; src_buf_left--; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); } } } d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break; // Simple lazy/greedy parsing state machine. len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; } } else { tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); } if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { cur_match_dist = cur_match_len = 0; } if (d->m_saved_match_len) { if (cur_match_len > d->m_saved_match_len) { tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); if (cur_match_len >= 128) { tdefl_record_match(d, cur_match_len, cur_match_dist); d->m_saved_match_len = 0; len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } } else { tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; } } else if (!cur_match_dist) tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) { tdefl_record_match(d, cur_match_len, cur_match_dist); len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } // Move the lookahead forward by len_to_move bytes. d->m_lookahead_pos += len_to_move; MZ_ASSERT(d->m_lookahead_size >= len_to_move); d->m_lookahead_size -= len_to_move; d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); // Check if it's time to flush the current LZ codes to the internal output buffer. if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) { int n; d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; } } d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; return MZ_TRUE; } static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { if (d->m_pIn_buf_size) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; } if (d->m_pOut_buf_size) { size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); d->m_output_flush_ofs += (mz_uint)n; d->m_output_flush_remaining -= (mz_uint)n; d->m_out_buf_ofs += n; *d->m_pOut_buf_size = d->m_out_buf_ofs; } return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; } tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) { if (!d) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return TDEFL_STATUS_BAD_PARAM; } d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; d->m_out_buf_ofs = 0; d->m_flush = flush; if (((0) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); } d->m_wants_to_finish |= (flush == TDEFL_FINISH); if ((d->m_output_flush_remaining) || (d->m_finished)) return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) { if (!tdefl_compress_fast(d)) return d->m_prev_return_status; } else #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN { if (!tdefl_compress_normal(d)) return d->m_prev_return_status; } if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) { if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; d->m_finished = (flush == TDEFL_FINISH); if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } } return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); } tdefl_status tdefl_init(tdefl_compressor *d, int flags) { d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); return TDEFL_STATUS_OKAY; } static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; // level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) { mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; return comp_flags; } mz_uint32 mz_adler32(mz_uint32 adler, const unsigned char *ptr, size_t buf_len) { mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; if (!ptr) return MZ_ADLER32_INIT; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; } for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; } return (s2 << 16) + s1; } 07070100000007000081A4000001ED0000006B000000015EE6501B00001B7F000000000000000000000000000000000000003800000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/miniz_tdef.h#pragma once // public domain code from https://github.com/richgel999/miniz/tree/42c29103c304a6e9201d000c96c31cd3031efc4f #include <string.h> #include <stdint.h> // ------------------- Types and macros typedef uint8_t mz_uint8; typedef int16_t mz_int16; typedef uint16_t mz_uint16; typedef uint32_t mz_uint32; typedef uint32_t mz_uint; typedef int64_t mz_int64; typedef uint64_t mz_uint64; typedef int mz_bool; #define MZ_FALSE (0) #define MZ_TRUE (1) // Works around MSVC's spammy "warning C4127: conditional expression is constant" message. #ifdef _MSC_VER #define MZ_MACRO_END while (0, 0) #else #define MZ_MACRO_END while (0) #endif #define MZ_ASSERT(x) #define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) #ifdef _MSC_VER #define MZ_FORCEINLINE __forceinline #elif defined(__GNUC__) #define MZ_FORCEINLINE inline __attribute__((__always_inline__)) #else #define MZ_FORCEINLINE inline #endif // ------------------- Low-level Compression API Definitions // tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): // TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). enum { TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF }; // TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. // TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). // TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. // TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). // TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) // TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. // TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. // TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. // The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). enum { TDEFL_WRITE_ZLIB_HEADER = 0x01000, TDEFL_COMPUTE_ADLER32 = 0x02000, TDEFL_GREEDY_PARSING_FLAG = 0x04000, TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, TDEFL_RLE_MATCHES = 0x10000, TDEFL_FILTER_MATCHES = 0x20000, TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 }; enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; // The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. typedef enum { TDEFL_STATUS_BAD_PARAM = -2, TDEFL_STATUS_PUT_BUF_FAILED = -1, TDEFL_STATUS_OKAY = 0, TDEFL_STATUS_DONE = 1, } tdefl_status; // Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums typedef enum { TDEFL_NO_FLUSH = 0, TDEFL_SYNC_FLUSH = 2, TDEFL_FULL_FLUSH = 3, TDEFL_FINISH = 4 } tdefl_flush; // tdefl's compression state structure. typedef struct { mz_uint m_flags, m_max_probes[2]; int m_greedy_parsing; mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; tdefl_status m_prev_return_status; const void *m_pIn_buf; void *m_pOut_buf; size_t *m_pIn_buf_size, *m_pOut_buf_size; tdefl_flush m_flush; const mz_uint8 *m_pSrc; size_t m_src_buf_left, m_out_buf_ofs; mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; } tdefl_compressor; // Initializes the compressor. // There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. // flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) tdefl_status tdefl_init(tdefl_compressor *d, int flags); // Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); #define MZ_ADLER32_INIT (1) // mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. mz_uint32 mz_adler32(mz_uint32 adler, const unsigned char *ptr, size_t buf_len); // Compression strategies. enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; // Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; #define MZ_DEFAULT_WINDOW_BITS 15 // Create tdefl_compress() flags given zlib-style compression parameters. // level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) // window_bits may be -15 (raw deflate) or 15 (zlib) // strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); 07070100000008000081A4000001ED0000006B000000015EE6501B000099D8000000000000000000000000000000000000003500000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip.c#include "pkg2zip_aes.h" #include "pkg2zip_zip.h" #include "pkg2zip_out.h" #include "pkg2zip_psp.h" #include "pkg2zip_utils.h" #include "pkg2zip_zrif.h" #include <assert.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wunknown-warning-option" #pragma GCC diagnostic ignored "-Wformat-truncation" #endif #define PKG_HEADER_SIZE 192 #define PKG_HEADER_EXT_SIZE 64 // https://wiki.henkaku.xyz/vita/Packages#AES_Keys static const uint8_t pkg_ps3_key[] = { 0x2e, 0x7b, 0x71, 0xd7, 0xc9, 0xc9, 0xa1, 0x4e, 0xa3, 0x22, 0x1f, 0x18, 0x88, 0x28, 0xb8, 0xf8 }; static const uint8_t pkg_psp_key[] = { 0x07, 0xf2, 0xc6, 0x82, 0x90, 0xb5, 0x0d, 0x2c, 0x33, 0x81, 0x8d, 0x70, 0x9b, 0x60, 0xe6, 0x2b }; static const uint8_t pkg_vita_2[] = { 0xe3, 0x1a, 0x70, 0xc9, 0xce, 0x1d, 0xd7, 0x2b, 0xf3, 0xc0, 0x62, 0x29, 0x63, 0xf2, 0xec, 0xcb }; static const uint8_t pkg_vita_3[] = { 0x42, 0x3a, 0xca, 0x3a, 0x2b, 0xd5, 0x64, 0x9f, 0x96, 0x86, 0xab, 0xad, 0x6f, 0xd8, 0x80, 0x1f }; static const uint8_t pkg_vita_4[] = { 0xaf, 0x07, 0xfd, 0x59, 0x65, 0x25, 0x27, 0xba, 0xf1, 0x33, 0x89, 0x66, 0x8b, 0x17, 0xd9, 0xea }; // http://vitadevwiki.com/vita/System_File_Object_(SFO)_(PSF)#Internal_Structure // https://github.com/TheOfficialFloW/VitaShell/blob/1.74/sfo.h#L29 static void parse_sfo_content(const uint8_t* sfo, uint32_t sfo_size, char* category, char* title, char* content, char* min_version, char* pkg_version) { if (get32le(sfo) != 0x46535000) { sys_error("ERROR: incorrect sfo signature\n"); } uint32_t keys = get32le(sfo + 8); uint32_t values = get32le(sfo + 12); uint32_t count = get32le(sfo + 16); int title_index = -1; int content_index = -1; int category_index = -1; int minver_index = -1; int pkgver_index = -1; for (uint32_t i = 0; i < count; i++) { if (i * 16 + 20 + 2 > sfo_size) { sys_error("ERROR: sfo information is too small\n"); } char* key = (char*)sfo + keys + get16le(sfo + i * 16 + 20); if (strcmp(key, "TITLE") == 0) { if (title_index < 0) { title_index = (int)i; } } else if (strcmp(key, "STITLE") == 0) { title_index = (int)i; } else if (strcmp(key, "CONTENT_ID") == 0) { content_index = (int)i; } else if (strcmp(key, "CATEGORY") == 0) { category_index = (int)i; } else if (strcmp(key, "PSP2_DISP_VER") == 0) { minver_index = (int)i; } else if (strcmp(key, "APP_VER") == 0) { pkgver_index = (int)i; } } if (title_index < 0) { sys_error("ERROR: cannot find title from sfo file, pkg is probably corrupted\n"); } char* value = (char*)sfo + values + get32le(sfo + title_index * 16 + 20 + 12); size_t i; size_t max = 255; for (i = 0; i<max && *value; i++, value++) { if ((*value >= 32 && *value < 127 && strchr("<>\"/\\|?*", *value) == NULL) || (uint8_t)*value >= 128) { if (*value == ':') { *title++ = ' '; *title++ = '-'; max--; } else { *title++ = *value; } } else if (*value == 10) { *title++ = ' '; } } *title = 0; if (content_index >= 0 && content) { value = (char*)sfo + values + get32le(sfo + content_index * 16 + 20 + 12); while (*value) { *content++ = *value++; } *content = 0; } if (category_index >= 0) { value = (char*)sfo + values + get32le(sfo + category_index * 16 + 20 + 12); while (*value) { *category++ = *value++; } } *category = 0; if (minver_index >= 0 && min_version) { value = (char*)sfo + values + get32le(sfo + minver_index * 16 + 20 + 12); if (*value == '0') { value++; } while (*value) { *min_version++ = *value++; } if (min_version[-1] == '0') { min_version[-1] = 0; } else { *min_version = 0; } } if (pkgver_index >= 0 && pkg_version) { value = (char*)sfo + values + get32le(sfo + pkgver_index * 16 + 20 + 12); if (*value == '0') { value++; } while (*value) { *pkg_version++ = *value++; } *pkg_version = 0; } } static void parse_sfo(sys_file f, uint64_t sfo_offset, uint32_t sfo_size, char* category, char* title, char* content, char* min_version, char* pkg_version) { uint8_t sfo[16 * 1024]; if (sfo_size < 16) { sys_error("ERROR: sfo information is too small\n"); } if (sfo_size > sizeof(sfo)) { sys_error("ERROR: sfo information is too big, pkg file is probably corrupted\n"); } sys_read(f, sfo_offset, sfo, sfo_size); parse_sfo_content(sfo, sfo_size, category, title, content, min_version, pkg_version); } static void find_psp_sfo(const aes128_key* key, const aes128_key* ps3_key, const uint8_t* iv, sys_file pkg, uint64_t pkg_size, uint64_t enc_offset, uint64_t items_offset, uint32_t item_count, char* category, char* title) { for (uint32_t item_index = 0; item_index < item_count; item_index++) { uint8_t item[32]; uint64_t item_offset = items_offset + item_index * 32; sys_read(pkg, enc_offset + item_offset, item, sizeof(item)); aes128_ctr_xor(key, iv, item_offset / 16, item, sizeof(item)); uint32_t name_offset = get32be(item + 0); uint32_t name_size = get32be(item + 4); uint64_t data_offset = get64be(item + 8); uint64_t data_size = get64be(item + 16); uint8_t psp_type = item[24]; assert(name_offset % 16 == 0); assert(data_offset % 16 == 0); if (pkg_size < enc_offset + name_offset + name_size || pkg_size < enc_offset + data_offset + data_size) { sys_error("ERROR: pkg file is too short, possibly corrupted\n"); } const aes128_key* item_key = psp_type == 0x90 ? key : ps3_key; char name[ZIP_MAX_FILENAME]; sys_read(pkg, enc_offset + name_offset, name, name_size); aes128_ctr_xor(item_key, iv, name_offset / 16, (uint8_t*)name, name_size); name[name_size] = 0; if (strcmp(name, "PARAM.SFO") == 0) { uint8_t sfo[16 * 1024]; if (data_size < 16) { sys_error("ERROR: sfo information is too small\n"); } if (data_size > sizeof(sfo)) { sys_error("ERROR: sfo information is too big, pkg file is probably corrupted\n"); } sys_read(pkg, enc_offset + data_offset, sfo, (uint32_t)data_size); aes128_ctr_xor(item_key, iv, data_offset / 16, sfo, (uint32_t)data_size); parse_sfo_content(sfo, (uint32_t)data_size, category, title, NULL, NULL, NULL); return; } } } static const char* get_region(const char* id) { if (memcmp(id, "PCSE", 4) == 0 || memcmp(id, "PCSA", 4) == 0 || memcmp(id, "NPNA", 4) == 0) { return "USA"; } else if (memcmp(id, "PCSF", 4) == 0 || memcmp(id, "PCSB", 4) == 0 || memcmp(id, "NPOA", 4) == 0) { return "EUR"; } else if (memcmp(id, "PCSC", 4) == 0 || memcmp(id, "VCJS", 4) == 0 || memcmp(id, "PCSG", 4) == 0 || memcmp(id, "VLJS", 4) == 0 || memcmp(id, "VLJM", 4) == 0 || memcmp(id, "NPPA", 4) == 0) { return "JPN"; } else if (memcmp(id, "VCAS", 4) == 0 || memcmp(id, "PCSH", 4) == 0 || memcmp(id, "VLAS", 4) == 0 || memcmp(id, "PCSD", 4) == 0 || memcmp(id, "NPQA", 4) == 0) { return "ASA"; } else { return "unknown region"; } } void print_help(char* bin_name) { sys_output("Parameters:\n"); sys_output("\n"); sys_output("-x|--extract Extract only. No zip compression\n"); sys_output("-l|--list Shows the package (sfo) name and exits\n"); sys_output("-b|--no-bgdl Disable bgdl output for VITA Theme extraction\n"); sys_output("-q|--quiet Do not output anything to stdout\n"); sys_output("-h|--help Shows this help message\n"); sys_output("\n"); sys_output("PSP/PSX only options:\n"); sys_output("-c[NUM] Create a *.CSO file instead of ISO. [NUM] is the compression ratio\n"); sys_output("-p|--psp Extracts PSP files in their original EBOOT.PBP format\n"); sys_output("\n"); sys_output("Usage: %s [-x] [-c[N]] [-b] [-p] <file.pkg> [zRIF]\n", bin_name); } typedef enum { PKG_TYPE_VITA_APP, PKG_TYPE_VITA_DLC, PKG_TYPE_VITA_PATCH, PKG_TYPE_VITA_PSM, PKG_TYPE_VITA_THEME, PKG_TYPE_PSP, PKG_TYPE_PSP_THEME, PKG_TYPE_PSX, } pkg_type; int main(int argc, char* argv[]) { sys_output_init(); int zipped = 1; int listing = 0; int verbose = 1; int cso = 0; int pbp = 0; int bgdl = 1; const char* pkg_arg = NULL; const char* zrif_arg = NULL; for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-x") == 0 || strcmp(argv[i], "--extract") == 0) { zipped = 0; } else if (strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--list") == 0) { listing = 1; verbose = 0; } else if (strncmp(argv[i], "-c", 2) == 0) { if (argv[i][2] != 0) { cso = atoi(argv[i] + 2); cso = cso > 9 ? 9 : cso < 0 ? 0 : cso; } } else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--psp") == 0) { pbp = 1; } else if (strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--no-bgdl") == 0) { bgdl = 0; } else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0) { verbose = 0; } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { sys_output("pkg2zip v2.2\n"); sys_output("\n"); print_help(argv[0]); exit(0); } else { if (pkg_arg != NULL ) { if(strlen(argv[i]) != 0) { zrif_arg = argv[i]; } break; } else { pkg_arg = argv[i]; } } } if (pkg_arg == NULL) { fprintf(stderr, "ERROR: no pkg file specified\n"); print_help(argv[0]); exit(1); } if (verbose) { sys_output("pkg2zip v2.2\n"); } if (verbose) { sys_output("[*] loading...\n"); } uint64_t pkg_size; sys_file pkg = sys_open(pkg_arg, &pkg_size); uint8_t pkg_header[PKG_HEADER_SIZE + PKG_HEADER_EXT_SIZE]; sys_read(pkg, 0, pkg_header, sizeof(pkg_header)); if (get32be(pkg_header) != 0x7f504b47 || get32be(pkg_header + PKG_HEADER_SIZE) != 0x7F657874) { sys_error("ERROR: not a pkg file\n"); } // http://www.psdevwiki.com/ps3/PKG_files uint64_t meta_offset = get32be(pkg_header + 8); uint32_t meta_count = get32be(pkg_header + 12); uint32_t item_count = get32be(pkg_header + 20); uint64_t total_size = get64be(pkg_header + 24); uint64_t enc_offset = get64be(pkg_header + 32); uint64_t enc_size = get64be(pkg_header + 40); const uint8_t* iv = pkg_header + 0x70; int key_type = pkg_header[0xe7] & 7; if (pkg_size < total_size) { sys_error("ERROR: pkg file is too small\n"); } if (pkg_size < enc_offset + item_count * 32) { sys_error("ERROR: pkg file is too small\n"); } uint32_t content_type = 0; uint32_t sfo_offset = 0; uint32_t sfo_size = 0; uint32_t items_offset = 0; uint32_t items_size = 0; char install_directory[0x28] = {0}; for (uint32_t i = 0; i < meta_count; i++) { uint8_t block[16]; sys_read(pkg, meta_offset, block, sizeof(block)); uint32_t type = get32be(block + 0); uint32_t size = get32be(block + 4); if (type == 2) { content_type = get32be(block + 8); } else if (type == 13) { items_offset = get32be(block + 8); items_size = get32be(block + 12); } else if (type == 14) { sfo_offset = get32be(block + 8); sfo_size = get32be(block + 12); } else if (type == 10) { sys_read(pkg, meta_offset + 8 + 8, install_directory,sizeof(install_directory)); //sys_output("[*] DLC Install Directory: %s\n", install_directory); } meta_offset += 2 * sizeof(uint32_t) + size; } pkg_type type; // http://www.psdevwiki.com/ps3/PKG_files if (content_type == 6) { type = PKG_TYPE_PSX; } else if (content_type == 7 || content_type == 0xe || content_type == 0xf || content_type == 0x10) { // PSP & PSP-PCEngine & DLC / PSP-Go / PSP-Mini / PSP-NeoGeo type = PKG_TYPE_PSP; } else if (content_type == 0x9) { type = PKG_TYPE_PSP_THEME; } else if (content_type == 0x15) { type = PKG_TYPE_VITA_APP; } else if (content_type == 0x16) { type = PKG_TYPE_VITA_DLC; } else if (content_type == 0x18 || content_type == 0x1d) { type = PKG_TYPE_VITA_PSM; } else if (content_type == 0x1f) { type = PKG_TYPE_VITA_THEME; } else { sys_error("ERROR: unsupported content type 0x%x", content_type); } aes128_key ps3_key; uint8_t main_key[16]; if (key_type == 1) { memcpy(main_key, pkg_psp_key, sizeof(main_key)); aes128_init(&ps3_key, pkg_ps3_key); } else if (key_type == 2) { aes128_key key; aes128_init(&key, pkg_vita_2); aes128_ecb_encrypt(&key, iv, main_key); } else if (key_type == 3) { aes128_key key; aes128_init(&key, pkg_vita_3); aes128_ecb_encrypt(&key, iv, main_key); } else if (key_type == 4) { aes128_key key; aes128_init(&key, pkg_vita_4); aes128_ecb_encrypt(&key, iv, main_key); } aes128_key key; aes128_init(&key, main_key); char content[256]; char title[256]; char category[256]; char min_version[256]; char pkg_version[256]; const char* id = content + 7; const char* id2 = id + 13; // first 512 - for vita games - https://github.com/TheOfficialFloW/NoNpDrm/blob/v1.1/src/main.c#L42 // 1024 is used for PSM uint8_t rif[1024]; uint32_t rif_size = 0; if (type == PKG_TYPE_PSP || type == PKG_TYPE_PSX) { find_psp_sfo(&key, &ps3_key, iv, pkg, pkg_size, enc_offset, items_offset, item_count, category, title); id = (char*)pkg_header + 0x37; if (type == PKG_TYPE_PSX && zrif_arg != NULL) //pocketstation pkg type is PSX { rif_size = 512; zrif_decode(zrif_arg, rif, rif_size); } } else if (type == PKG_TYPE_PSP_THEME) { id = (char*)pkg_header + 0x37; memcpy(title, pkg_header + 0x44, 0x10); uint8_t item[32]; sys_read(pkg, enc_offset + items_offset, item, sizeof(item)); aes128_ctr_xor(&key, iv, items_offset / 16, item, sizeof(item)); uint64_t data_offset = get64be(item + 8); uint64_t data_size = get64be(item + 16); uint8_t psp_type = item[24]; assert(data_offset % 16 == 0); if (pkg_size < enc_offset + data_offset + data_size) { sys_error("ERROR: pkg file is too short, possibly corrupted\n"); } const aes128_key* item_key; item_key = psp_type == 0x90 ? &key : &ps3_key; get_psp_theme_title(title,item_key, iv, pkg, enc_offset, data_offset); //Theme names are prone to having colons for (uint32_t i = 0; i < sizeof(title); i++) { if (title[i] == 58) { title[i] = 32; } } } else // Vita { if (type == PKG_TYPE_VITA_PSM) { memcpy(content, pkg_header + 0x30, 0x30); rif_size = 1024; } else if (type == PKG_TYPE_VITA_THEME) { parse_sfo(pkg, sfo_offset, sfo_size, category, title, content, min_version, pkg_version); rif_size = 512; } else // Vita APP, DLC or PATCH { parse_sfo(pkg, sfo_offset, sfo_size, category, title, content, min_version, pkg_version); rif_size = 512; if (type == PKG_TYPE_VITA_APP && strcmp(category, "gp") == 0) { type = PKG_TYPE_VITA_PATCH; } } if (type != PKG_TYPE_VITA_PATCH && zrif_arg != NULL) { zrif_decode(zrif_arg, rif, rif_size); const char* rif_contentid = (char*)rif + (type == PKG_TYPE_VITA_PSM ? 0x50 : 0x10); if (strncmp(rif_contentid, content, 0x30) != 0) { sys_error("ERROR: zRIF content id '%s' doesn't match pkg '%s'\n", rif_contentid, content); } } } const char* ext = zipped ? ".zip" : ""; char root[1024]; if (type == PKG_TYPE_PSP) { const char* type_str; if (content_type == 7) { type_str = (strcmp(category, "HG") == 0) ? "PSP-PCEngine" : install_directory[0] != 0 ? "PSP-DLC" :"PSP"; } else { type_str = content_type == 0xe ? "PSP-Go" : content_type == 0xf ? "PSP-Mini" : "PSP-NeoGeo"; } snprintf(root, sizeof(root), "%s [%.9s] [%s]%s", title, id, type_str, ext); if (verbose) { sys_output("[*] unpacking %s\n", type_str); } } else if (type == PKG_TYPE_PSP_THEME) { snprintf(root, sizeof(root), "%s [%.9s] [PSP-Theme]%s", title, id, ext); if (verbose) { sys_output("[*] unpacking PSP Theme\n"); } } else if (type == PKG_TYPE_PSX) { snprintf(root, sizeof(root), "%s [%.9s] [PSX]%s", title, id, ext); if (verbose) { sys_output("[*] unpacking PSX\n"); } } else if (type == PKG_TYPE_VITA_DLC) { snprintf(root, sizeof(root), "%s [%.9s] [%s] [DLC-%s]%s", title, id, get_region(id), id2, ext); if (verbose) { sys_output("[*] unpacking Vita DLC\n"); } } else if (type == PKG_TYPE_VITA_PATCH) { snprintf(root, sizeof(root), "%s [%.9s] [%s] [PATCH] [v%s]%s", title, id, get_region(id), pkg_version, ext); if (verbose) { sys_output("[*] unpacking Vita PATCH\n"); } } else if (type == PKG_TYPE_VITA_PSM) { snprintf(root, sizeof(root), "%.9s [%s] [PSM]%s", id, get_region(id), ext); if (verbose) { sys_output("[*] unpacking Vita PSM\n"); } } else if (type == PKG_TYPE_VITA_APP) { snprintf(root, sizeof(root), "%s [%.9s] [%s]%s", title, id, get_region(id), ext); if (verbose) { sys_output("[*] unpacking Vita APP\n"); } } else if (type == PKG_TYPE_VITA_THEME) { snprintf(root, sizeof(root), "%s [%.9s] [%s]%s", title, id, get_region(id), ext); if (verbose) { sys_output("[*] unpacking Vita theme\n"); } } else { assert(0); sys_error("ERROR: unsupported type\n"); } if (listing && zipped) { sys_output("%s\n", root); exit(0); } else if (listing && zipped == 0) { sys_error("ERROR: Listing option without creating zip is useless\n"); } if (verbose) { sys_output("[*] creating '%s' archive\n", root); } out_begin(root, zipped); root[0] = 0; if (type == PKG_TYPE_PSP) { snprintf(root, sizeof(root), "pspemu/PSP/GAME/%.9s", id); } else if (type == PKG_TYPE_PSP_THEME) { snprintf(root, sizeof(root), "pspemu/PSP/THEME"); } else if (type == PKG_TYPE_PSX) { snprintf(root, sizeof(root), "pspemu/PSP/GAME/%.9s", id); } else if (type == PKG_TYPE_VITA_DLC) { sys_vstrncat(root, sizeof(root), "addcont"); out_add_folder(root); sys_vstrncat(root, sizeof(root), "/%.9s", id); out_add_folder(root); sys_vstrncat(root, sizeof(root), "/%s", id2); out_add_folder(root); } else if (type == PKG_TYPE_VITA_PATCH) { sys_vstrncat(root, sizeof(root), "patch"); out_add_folder(root); sys_vstrncat(root, sizeof(root), "/%.9s", id); out_add_folder(root); } else if (type == PKG_TYPE_VITA_PSM) { sys_vstrncat(root, sizeof(root), "psm"); out_add_folder(root); sys_vstrncat(root, sizeof(root), "/%.9s", id); out_add_folder(root); } else if (type == PKG_TYPE_VITA_APP) { sys_vstrncat(root, sizeof(root), "app"); out_add_folder(root); sys_vstrncat(root, sizeof(root), "/%.9s", id); out_add_folder(root); } else if (type == PKG_TYPE_VITA_THEME) { if (bgdl == 1) { sys_vstrncat(root, sizeof(root), "bgdl/t"); out_add_folder(root); uint32_t bgdl_task = 0; char dir[1024] = {0}; if(zipped == 0) { do { bgdl_task++; snprintf(dir, sizeof(dir), "%s/%08x",root, bgdl_task); } while (sys_test_dir(dir)); } else { bgdl_task = 1; } sys_vstrncat(root,sizeof(root), "/%08x", bgdl_task); out_add_folder(root); } else { sys_vstrncat(root, sizeof(root), "app"); out_add_folder(root); } sys_vstrncat(root, sizeof(root), "/%.9s", id); out_add_folder(root); } else { assert(0); sys_error("ERROR: unsupported type\n"); } char path[1024]; sys_output_progress_init(pkg_size); for (uint32_t item_index = 0; item_index < item_count; item_index++) { uint8_t item[32]; uint64_t item_offset = items_offset + item_index * 32; sys_read(pkg, enc_offset + item_offset, item, sizeof(item)); aes128_ctr_xor(&key, iv, item_offset / 16, item, sizeof(item)); uint32_t name_offset = get32be(item + 0); uint32_t name_size = get32be(item + 4); uint64_t data_offset = get64be(item + 8); uint64_t data_size = get64be(item + 16); uint8_t psp_type = item[24]; uint8_t flags = item[27]; assert(name_offset % 16 == 0); assert(data_offset % 16 == 0); if (pkg_size < enc_offset + name_offset + name_size || pkg_size < enc_offset + data_offset + data_size) { sys_error("ERROR: pkg file is too short, possibly corrupted\n"); } if (name_size >= ZIP_MAX_FILENAME) { sys_error("ERROR: pkg file contains file with very long name\n"); } const aes128_key* item_key; if (type == PKG_TYPE_PSP || type == PKG_TYPE_PSX || type == PKG_TYPE_PSP_THEME) { item_key = psp_type == 0x90 ? &key : &ps3_key; } else { item_key = &key; } char name[ZIP_MAX_FILENAME]; sys_read(pkg, enc_offset + name_offset, name, name_size); aes128_ctr_xor(item_key, iv, name_offset / 16, (uint8_t*)name, name_size); name[name_size] = 0; // sys_output("[%u/%u] %s\n", item_index + 1, item_count, name); if (flags == 4 || flags == 18) // Directory { if (type == PKG_TYPE_VITA_PSM) { // skip "content/" prefix char* slash = strchr(name, '/'); if (slash != NULL) { if (strstr(name, "runtime")) { snprintf(path, sizeof(path), "%s/%s", root, name + 9); } else { snprintf(path, sizeof(path), "%s/RO/%s", root, name + 9); } out_add_folder(path); } } else if (type == PKG_TYPE_VITA_APP || type == PKG_TYPE_VITA_DLC || type == PKG_TYPE_VITA_PATCH || type == PKG_TYPE_VITA_THEME) { snprintf(path, sizeof(path), "%s/%s", root, name); out_add_folder(path); } // sys_output("dir : %s\n", path); } else // File { int decrypt = 1; if ((type == PKG_TYPE_VITA_APP || type == PKG_TYPE_VITA_DLC || type == PKG_TYPE_VITA_PATCH || type == PKG_TYPE_VITA_THEME) && (strcmp("sce_sys/package/digs.bin", name) == 0 || strcmp("sce_sys/package/cert.bin", name) == 0 )) { snprintf(path, sizeof(path), "%s/sce_sys/package", root); out_add_folder(path); if (verbose) { sys_output("[*] renaming %s to body.bin\n", name); } snprintf(name, sizeof(name), "%s", "sce_sys/package/body.bin"); decrypt = 0; } if (type == PKG_TYPE_PSX) { if (strcmp("USRDIR/CONTENT/DOCUMENT.DAT", name) == 0) { snprintf(path, sizeof(path), "pspemu/PSP/GAME/%.9s/DOCUMENT.DAT", id); } else if (strcmp("USRDIR/CONTENT/EBOOT.PBP", name) == 0) { snprintf(path, sizeof(path), "pspemu/PSP/GAME/%.9s/KEYS.BIN", id); unpack_keys_bin(path, item_key, iv, pkg, enc_offset, data_offset, data_size); snprintf(path, sizeof(path), "pspemu/PSP/GAME/%.9s/EBOOT.PBP", id); } else if (strcmp("USRDIR/CONTENT/texture.enc", name) == 0) { snprintf(path, sizeof(path), "ps1emu/%.9s/texture.enc", id); } else { continue; } } else if (type == PKG_TYPE_PSP) { if (strcmp("USRDIR/CONTENT/EBOOT.PBP", name) == 0) { snprintf(path, sizeof(path), "pspemu/PSP/GAME/%.9s/EBOOT.PBP", id); if (!pbp) { snprintf(path, sizeof(path), "pspemu/ISO/%s [%.9s].%s", title, id, cso ? "cso" : "iso"); out_add_parent(path); unpack_psp_eboot(path, item_key, iv, pkg, enc_offset, data_offset, data_size, cso); continue; } } else if (strcmp("USRDIR/CONTENT/DOCUMENT.DAT", name) == 0) { snprintf(path, sizeof(path), "pspemu/PSP/GAME/%.9s/DOCUMENT.DAT", id); if (!pbp) { continue; } } else if (strcmp("USRDIR/CONTENT/DOCINFO.EDAT", name) == 0) { snprintf(path, sizeof(path), "pspemu/PSP/GAME/%.9s/DOCINFO.EDAT", id); if (!pbp) { continue; } } else if (strcmp("USRDIR/CONTENT/PSP-KEY.EDAT", name) == 0) { snprintf(path, sizeof(path), "pspemu/PSP/GAME/%.9s/PSP-KEY.EDAT", id); out_add_parent(path); unpack_psp_key(path, item_key, iv, pkg, enc_offset, data_offset, data_size); continue; } else if (strstr(name, "USRDIR/CONTENT")) { // skip "USRDIR/CONTENT" prefix char* slash = strchr(name+14, '/'); if (slash != NULL) { snprintf(path, sizeof(path), "pspemu/PSP/GAME/%.9s/%s", id, name+15); char* edat = strrchr(name, '.'); if (edat != NULL) { if (strcmp(edat, ".edat") == 0 || strcmp(edat, ".EDAT") == 0) { out_add_parent(path); unpack_psp_edat(path, item_key, iv, pkg, enc_offset, data_offset, data_size); continue; } } } else { continue; } } else { continue; } } else if (type == PKG_TYPE_PSP_THEME) { snprintf(path, sizeof(path), "pspemu/PSP/THEME/%s", name); out_add_parent(path); unpack_psp_edat(path, item_key, iv, pkg, enc_offset, data_offset, data_size); continue; } else if (type == PKG_TYPE_VITA_PSM) { // skip "content/" prefix if (strstr(name, "runtime")) { snprintf(path, sizeof(path), "%s/%s", root, name + 9); } else { snprintf(path, sizeof(path), "%s/RO/%s", root, name + 9); } } else { snprintf(path, sizeof(path), "%s/%s", root, name); } uint64_t offset = data_offset; out_add_parent(path); out_begin_file(path, 0); while (data_size != 0) { uint8_t PKG_ALIGN(16) buffer[1 << 16]; uint32_t size = (uint32_t)min64(data_size, sizeof(buffer)); sys_output_progress(enc_offset + offset); sys_read(pkg, enc_offset + offset, buffer, size); if (decrypt) { aes128_ctr_xor(item_key, iv, offset / 16, buffer, size); } out_write(buffer, size); offset += size; data_size -= size; } out_end_file(); } } if (verbose) { sys_output("[*] unpacking completed\n"); } if (type == PKG_TYPE_VITA_APP || type == PKG_TYPE_VITA_DLC || type == PKG_TYPE_VITA_PATCH || type == PKG_TYPE_VITA_THEME) { if (verbose) { sys_output("[*] creating sce_sys/package/head.bin\n"); } snprintf(path, sizeof(path), "%s/sce_sys/package/head.bin", root); out_add_parent(path); out_begin_file(path, 0); uint64_t head_size = enc_offset + items_size; uint64_t head_offset = 0; while (head_size != 0) { uint8_t PKG_ALIGN(16) buffer[1 << 16]; uint32_t size = (uint32_t)min64(head_size, sizeof(buffer)); sys_read(pkg, head_offset, buffer, size); out_write(buffer, size); head_size -= size; head_offset += size; } out_end_file(); if (verbose) { sys_output("[*] creating sce_sys/package/tail.bin\n"); } snprintf(path, sizeof(path), "%s/sce_sys/package/tail.bin", root); out_begin_file(path, 0); uint64_t tail_offset = enc_offset + enc_size; while (tail_offset != pkg_size) { uint8_t PKG_ALIGN(16) buffer[1 << 16]; uint32_t size = (uint32_t)min64(pkg_size - tail_offset, sizeof(buffer)); sys_read(pkg, tail_offset, buffer, size); out_write(buffer, size); tail_offset += size; } out_end_file(); if (verbose) { sys_output("[*] creating sce_sys/package/stat.bin\n"); } snprintf(path, sizeof(path), "%s/sce_sys/package/stat.bin", root); uint8_t stat[768] = { 0 }; out_begin_file(path, 0); out_write(stat, sizeof(stat)); out_end_file(); } if ((type == PKG_TYPE_VITA_APP || type == PKG_TYPE_VITA_DLC || type == PKG_TYPE_VITA_PSM || type == PKG_TYPE_VITA_THEME || type == PKG_TYPE_PSX) && zrif_arg != NULL) { if (type == PKG_TYPE_VITA_PSM) { if (verbose) { sys_output("[*] creating RO/License\n"); } snprintf(path, sizeof(path), "%s/RO/License", root); out_add_folder(path); if (verbose) { sys_output("[*] creating RO/License/FAKE.rif\n"); } snprintf(path, sizeof(path), "%s/RO/License/FAKE.rif", root); } else if (type == PKG_TYPE_PSX) { //For Pocketstation if (verbose) { sys_output("[*] creating rif"); } const char* rif_contentid = (char*)rif + 0x10; snprintf(path, sizeof(path), "pspemu/PSP/LICENSE"); out_add_folder(path); snprintf(path, sizeof(path), "pspemu/PSP/LICENSE/%s.rif", rif_contentid); } else { if (verbose) { sys_output("[*] creating sce_sys/package/work.bin\n"); } snprintf(path, sizeof(path), "%s/sce_sys/package/work.bin", root); } out_begin_file(path, 0); out_write(rif, rif_size); out_end_file(); } if (type == PKG_TYPE_VITA_THEME && bgdl == 1) { //get the parent directory char* lastslash = strrchr(root, '/'); if (lastslash != NULL) { root[strlen(root)-strlen(lastslash)] = 0; } uint8_t pdb[0x200] = { 0 }; //PDB entries :: https://www.psdevwiki.com/ps3/Project_Database_(PDB) memcpy(pdb+0x04,"\x64\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",0x10); memcpy(pdb+0x14,"\x65\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",0x10); // 02 in d0.pdb, 00 in d1.pdb memcpy(pdb+0x24,"\x66\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00",0x0D); // "Task unregister auto" memcpy(pdb+0x31,"\x68\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",0x10); // unknown but required memcpy(pdb+0x41,"\x6B\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x0C\x00\x00\x00",0x10); // "Task Subtype" memcpy(pdb+0x51,"\x6C\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00",0x10); // unknown but required memcpy(pdb+0x61,"\x6D\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00",0x10); // unknown but required memcpy(pdb+0x71,"\x6E\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00",0x0D); memcpy(pdb+0x7E,"\x6F\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",0x10); // unknown but required memcpy(pdb+0x8E,"\x70\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01",0x0D); memcpy(pdb+0x9B,"\x71\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01",0x0D); memcpy(pdb+0xA8,"\x72\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",0x10); memcpy(pdb+0xB8,"\x73\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00",0x0D); memcpy(pdb+0xC5,"\x74\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00",0x0D); memcpy(pdb+0xD2,"\x69\x00\x00\x00\x44\x00\x00\x00\x44\x00\x00\x00",0x0C); //pkg title memcpy(pdb+0xDE,title,0x40); memcpy(pdb+0x122,"\xD9\x00\x00\x00\x25\x00\x00\x00\x25\x00\x00\x00",0x0C); //ContentID memcpy(pdb+0x12E,id,0x25); memcpy(pdb+0x153,"\xDA\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01",0x0D); // Download Complete Flag memcpy(pdb+0x160,"\xDC\x00\x00\x00\x0A\x00\x00\x00\x0A\x00\x00\x00",0x0C); //Content ID memcpy(pdb+0x16C,id,0x09); pdb[0x20] = 0x02; if (verbose) { sys_output("[*] creating d0.pdb\n"); } snprintf(path, sizeof(path), "%s/d0.pdb", root); out_begin_file(path,0); out_write(pdb,sizeof(pdb)); out_end_file(); pdb[0x20] = 0x00; if (verbose) { sys_output("[*] creating d1.pdb\n"); } snprintf(path, sizeof(path), "%s/d1.pdb", root); out_begin_file(path,0); out_write(pdb,sizeof(pdb)); out_end_file(); if (verbose) { sys_output("[*] creating f0.pdb\n"); } snprintf(path, sizeof(path), "%s/f0.pdb", root); out_begin_file(path,0); out_write(pdb,0); out_end_file(); } if (type == PKG_TYPE_VITA_PSM) { if (verbose) { sys_output("[*] creating RW\n"); } snprintf(path, sizeof(path), "%s/RW", root); out_add_folder(path); if (verbose) { sys_output("[*] creating RW/Documents\n"); } snprintf(path, sizeof(path), "%s/RW/Documents", root); out_add_folder(path); if (verbose) { sys_output("[*] creating RW/Temp\n"); } snprintf(path, sizeof(path), "%s/RW/Temp", root); out_add_folder(path); if (verbose) { sys_output("[*] creating RW/System\n"); } snprintf(path, sizeof(path), "%s/RW/System", root); out_add_folder(path); if (verbose) { sys_output("[*] creating RW/System/content_id\n"); } snprintf(path, sizeof(path), "%s/RW/System/content_id", root); out_begin_file(path, 0); out_write(pkg_header + 0x30, 0x30); out_end_file(); if (verbose) { sys_output("[*] creating RW/System/pm.dat\n"); } snprintf(path, sizeof(path), "%s/RW/System/pm.dat", root); uint8_t pm[1 << 16] = { 0 }; out_begin_file(path, 0); out_write(pm, sizeof(pm)); out_end_file(); } out_end(); if (verbose) { if (type == PKG_TYPE_VITA_APP || type == PKG_TYPE_VITA_PATCH) { sys_output("[*] minimum fw version required: %s\n", min_version); } sys_output("[*] done!\n"); } sys_output_done(); } 07070100000009000081A4000001ED0000006B000000015EE6501B00005B74000000000000000000000000000000000000003900000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_aes.c#include "pkg2zip_aes.h" #include "pkg2zip_utils.h" #include <assert.h> #include <string.h> #if defined(_MSC_VER) #define PLATFORM_SUPPORTS_AESNI 1 #include <intrin.h> static void get_cpuid(uint32_t level, uint32_t* arr) { __cpuidex((int*)arr, level, 0); } #elif defined(__x86_64__) || defined(__i386__) #define PLATFORM_SUPPORTS_AESNI 1 #include <cpuid.h> static void get_cpuid(uint32_t level, uint32_t* arr) { __cpuid_count(level, 0, arr[0], arr[1], arr[2], arr[3]); } #else #define PLATFORM_SUPPORTS_AESNI 0 #endif #if PLATFORM_SUPPORTS_AESNI static int aes128_supported_x86() { static int init = 0; static int supported; if (!init) { init = 1; uint32_t a[4]; get_cpuid(0, a); if (a[0] >= 1) { get_cpuid(1, a); supported = ((a[2] & (1 << 9)) && (a[2] & (1 << 25))); } } return supported; } void aes128_init_x86(aes128_key* context, const uint8_t* key); void aes128_init_dec_x86(aes128_key* context, const uint8_t* key); void aes128_ecb_encrypt_x86(const aes128_key* context, const uint8_t* input, uint8_t* output); void aes128_ecb_decrypt_x86(const aes128_key* context, const uint8_t* input, uint8_t* output); void aes128_ctr_xor_x86(const aes128_key* context, const uint8_t* iv, uint8_t* buffer, size_t size); void aes128_cmac_process_x86(const aes128_key* ctx, uint8_t* block, const uint8_t *buffer, uint32_t size); void aes128_psp_decrypt_x86(const aes128_key* ctx, const uint8_t* prev, const uint8_t* block, uint8_t* buffer, uint32_t size); #endif static const uint8_t rcon[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, }; static const uint8_t Te[] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, }; static uint8_t Td[] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, }; static const uint32_t TE[] = { 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a, }; static const uint32_t TD[] = { 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742, }; static uint8_t byte32(uint32_t x, int n) { return (uint8_t)(x >> (8 * n)); } static uint32_t ror32(uint32_t x, int n) { return (x >> n) | (x << (32 - n)); } static uint32_t setup_mix(uint32_t x) { return (Te[byte32(x, 2)] << 24) ^ (Te[byte32(x, 1)] << 16) ^ (Te[byte32(x, 0)] << 8) ^ Te[byte32(x, 3)]; } static uint32_t setup_mix2(uint32_t x) { return TD[Te[byte32(x, 3)]] ^ ror32(TD[Te[byte32(x, 2)]], 8) ^ ror32(TD[Te[byte32(x, 1)]], 16) ^ ror32(TD[Te[byte32(x, 0)]], 24); } void aes128_init(aes128_key* ctx, const uint8_t* key) { #if PLATFORM_SUPPORTS_AESNI if (aes128_supported_x86()) { aes128_init_x86(ctx, key); return; } #endif uint32_t* ekey = ctx->key; ekey[0] = get32be(key + 0); ekey[1] = get32be(key + 4); ekey[2] = get32be(key + 8); ekey[3] = get32be(key + 12); for (size_t i=0; i<10; i++) { uint32_t temp = ekey[3]; ekey[4] = ekey[0] ^ setup_mix(temp) ^ (rcon[i] << 24); ekey[5] = ekey[1] ^ ekey[4]; ekey[6] = ekey[2] ^ ekey[5]; ekey[7] = ekey[3] ^ ekey[6]; ekey += 4; } } void aes128_init_dec(aes128_key* ctx, const uint8_t* key) { #if PLATFORM_SUPPORTS_AESNI if (aes128_supported_x86()) { aes128_init_dec_x86(ctx, key); return; } #endif aes128_key enc; aes128_init(&enc, key); uint32_t* ekey = enc.key + 40; uint32_t* dkey = ctx->key; *dkey++ = ekey[0]; *dkey++ = ekey[1]; *dkey++ = ekey[2]; *dkey++ = ekey[3]; ekey -= 4; for (size_t i = 0; i < 9; i++) { *dkey++ = setup_mix2(ekey[0]); *dkey++ = setup_mix2(ekey[1]); *dkey++ = setup_mix2(ekey[2]); *dkey++ = setup_mix2(ekey[3]); ekey -= 4; } *dkey++ = ekey[0]; *dkey++ = ekey[1]; *dkey++ = ekey[2]; *dkey++ = ekey[3]; } static void aes128_encrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output) { uint32_t t0, t1, t2, t3; const uint32_t* key = ctx->key; uint32_t s0 = get32be(input + 0) ^ *key++; uint32_t s1 = get32be(input + 4) ^ *key++; uint32_t s2 = get32be(input + 8) ^ *key++; uint32_t s3 = get32be(input + 12) ^ *key++; for (size_t i = 0; i<4; i++) { t0 = TE[byte32(s0, 3)] ^ ror32(TE[byte32(s1, 2)], 8) ^ ror32(TE[byte32(s2, 1)], 16) ^ ror32(TE[byte32(s3, 0)], 24) ^ *key++; t1 = TE[byte32(s1, 3)] ^ ror32(TE[byte32(s2, 2)], 8) ^ ror32(TE[byte32(s3, 1)], 16) ^ ror32(TE[byte32(s0, 0)], 24) ^ *key++; t2 = TE[byte32(s2, 3)] ^ ror32(TE[byte32(s3, 2)], 8) ^ ror32(TE[byte32(s0, 1)], 16) ^ ror32(TE[byte32(s1, 0)], 24) ^ *key++; t3 = TE[byte32(s3, 3)] ^ ror32(TE[byte32(s0, 2)], 8) ^ ror32(TE[byte32(s1, 1)], 16) ^ ror32(TE[byte32(s2, 0)], 24) ^ *key++; s0 = TE[byte32(t0, 3)] ^ ror32(TE[byte32(t1, 2)], 8) ^ ror32(TE[byte32(t2, 1)], 16) ^ ror32(TE[byte32(t3, 0)], 24) ^ *key++; s1 = TE[byte32(t1, 3)] ^ ror32(TE[byte32(t2, 2)], 8) ^ ror32(TE[byte32(t3, 1)], 16) ^ ror32(TE[byte32(t0, 0)], 24) ^ *key++; s2 = TE[byte32(t2, 3)] ^ ror32(TE[byte32(t3, 2)], 8) ^ ror32(TE[byte32(t0, 1)], 16) ^ ror32(TE[byte32(t1, 0)], 24) ^ *key++; s3 = TE[byte32(t3, 3)] ^ ror32(TE[byte32(t0, 2)], 8) ^ ror32(TE[byte32(t1, 1)], 16) ^ ror32(TE[byte32(t2, 0)], 24) ^ *key++; } t0 = TE[byte32(s0, 3)] ^ ror32(TE[byte32(s1, 2)], 8) ^ ror32(TE[byte32(s2, 1)], 16) ^ ror32(TE[byte32(s3, 0)], 24) ^ *key++; t1 = TE[byte32(s1, 3)] ^ ror32(TE[byte32(s2, 2)], 8) ^ ror32(TE[byte32(s3, 1)], 16) ^ ror32(TE[byte32(s0, 0)], 24) ^ *key++; t2 = TE[byte32(s2, 3)] ^ ror32(TE[byte32(s3, 2)], 8) ^ ror32(TE[byte32(s0, 1)], 16) ^ ror32(TE[byte32(s1, 0)], 24) ^ *key++; t3 = TE[byte32(s3, 3)] ^ ror32(TE[byte32(s0, 2)], 8) ^ ror32(TE[byte32(s1, 1)], 16) ^ ror32(TE[byte32(s2, 0)], 24) ^ *key++; s0 = (Te[byte32(t0, 3)] << 24) ^ (Te[byte32(t1, 2)] << 16) ^ (Te[byte32(t2, 1)] << 8) ^ Te[byte32(t3, 0)] ^ *key++; s1 = (Te[byte32(t1, 3)] << 24) ^ (Te[byte32(t2, 2)] << 16) ^ (Te[byte32(t3, 1)] << 8) ^ Te[byte32(t0, 0)] ^ *key++; s2 = (Te[byte32(t2, 3)] << 24) ^ (Te[byte32(t3, 2)] << 16) ^ (Te[byte32(t0, 1)] << 8) ^ Te[byte32(t1, 0)] ^ *key++; s3 = (Te[byte32(t3, 3)] << 24) ^ (Te[byte32(t0, 2)] << 16) ^ (Te[byte32(t1, 1)] << 8) ^ Te[byte32(t2, 0)] ^ *key++; set32be(output + 0, s0); set32be(output + 4, s1); set32be(output + 8, s2); set32be(output + 12, s3); } static void aes128_decrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output) { const uint32_t* key = ctx->key; uint32_t s0 = get32be(input + 0) ^ *key++; uint32_t s1 = get32be(input + 4) ^ *key++; uint32_t s2 = get32be(input + 8) ^ *key++; uint32_t s3 = get32be(input + 12) ^ *key++; uint32_t t0 = TD[byte32(s0, 3)] ^ ror32(TD[byte32(s3, 2)], 8) ^ ror32(TD[byte32(s2, 1)], 16) ^ ror32(TD[byte32(s1, 0)], 24) ^ *key++; uint32_t t1 = TD[byte32(s1, 3)] ^ ror32(TD[byte32(s0, 2)], 8) ^ ror32(TD[byte32(s3, 1)], 16) ^ ror32(TD[byte32(s2, 0)], 24) ^ *key++; uint32_t t2 = TD[byte32(s2, 3)] ^ ror32(TD[byte32(s1, 2)], 8) ^ ror32(TD[byte32(s0, 1)], 16) ^ ror32(TD[byte32(s3, 0)], 24) ^ *key++; uint32_t t3 = TD[byte32(s3, 3)] ^ ror32(TD[byte32(s2, 2)], 8) ^ ror32(TD[byte32(s1, 1)], 16) ^ ror32(TD[byte32(s0, 0)], 24) ^ *key++; for (size_t i = 0; i < 4; i++) { s0 = TD[byte32(t0, 3)] ^ ror32(TD[byte32(t3, 2)], 8) ^ ror32(TD[byte32(t2, 1)], 16) ^ ror32(TD[byte32(t1, 0)], 24) ^ *key++; s1 = TD[byte32(t1, 3)] ^ ror32(TD[byte32(t0, 2)], 8) ^ ror32(TD[byte32(t3, 1)], 16) ^ ror32(TD[byte32(t2, 0)], 24) ^ *key++; s2 = TD[byte32(t2, 3)] ^ ror32(TD[byte32(t1, 2)], 8) ^ ror32(TD[byte32(t0, 1)], 16) ^ ror32(TD[byte32(t3, 0)], 24) ^ *key++; s3 = TD[byte32(t3, 3)] ^ ror32(TD[byte32(t2, 2)], 8) ^ ror32(TD[byte32(t1, 1)], 16) ^ ror32(TD[byte32(t0, 0)], 24) ^ *key++; t0 = TD[byte32(s0, 3)] ^ ror32(TD[byte32(s3, 2)], 8) ^ ror32(TD[byte32(s2, 1)], 16) ^ ror32(TD[byte32(s1, 0)], 24) ^ *key++; t1 = TD[byte32(s1, 3)] ^ ror32(TD[byte32(s0, 2)], 8) ^ ror32(TD[byte32(s3, 1)], 16) ^ ror32(TD[byte32(s2, 0)], 24) ^ *key++; t2 = TD[byte32(s2, 3)] ^ ror32(TD[byte32(s1, 2)], 8) ^ ror32(TD[byte32(s0, 1)], 16) ^ ror32(TD[byte32(s3, 0)], 24) ^ *key++; t3 = TD[byte32(s3, 3)] ^ ror32(TD[byte32(s2, 2)], 8) ^ ror32(TD[byte32(s1, 1)], 16) ^ ror32(TD[byte32(s0, 0)], 24) ^ *key++; } s0 = (Td[byte32(t0, 3)] << 24) ^ (Td[byte32(t3, 2)] << 16) ^ (Td[byte32(t2, 1)] << 8) ^ Td[byte32(t1, 0)] ^ *key++; s1 = (Td[byte32(t1, 3)] << 24) ^ (Td[byte32(t0, 2)] << 16) ^ (Td[byte32(t3, 1)] << 8) ^ Td[byte32(t2, 0)] ^ *key++; s2 = (Td[byte32(t2, 3)] << 24) ^ (Td[byte32(t1, 2)] << 16) ^ (Td[byte32(t0, 1)] << 8) ^ Td[byte32(t3, 0)] ^ *key++; s3 = (Td[byte32(t3, 3)] << 24) ^ (Td[byte32(t2, 2)] << 16) ^ (Td[byte32(t1, 1)] << 8) ^ Td[byte32(t0, 0)] ^ *key++; set32be(output + 0, s0); set32be(output + 4, s1); set32be(output + 8, s2); set32be(output + 12, s3); } void aes128_ecb_encrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output) { #if PLATFORM_SUPPORTS_AESNI if (aes128_supported_x86()) { aes128_ecb_encrypt_x86(ctx, input, output); return; } #endif aes128_encrypt(ctx, input, output); } void aes128_ecb_decrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output) { #if PLATFORM_SUPPORTS_AESNI if (aes128_supported_x86()) { aes128_ecb_decrypt_x86(ctx, input, output); return; } #endif aes128_decrypt(ctx, input, output); } static void ctr_add(uint8_t* counter, uint64_t n) { for (int i=15; i>=0; i--) { n = n + counter[i]; counter[i] = (uint8_t)n; n >>= 8; } } void aes128_ctr_xor(const aes128_key* context, const uint8_t* iv, uint64_t block, uint8_t* buffer, size_t size) { uint8_t tmp[16]; uint8_t counter[16]; for (uint32_t i=0; i<16; i++) { counter[i] = iv[i]; } ctr_add(counter, block); #if PLATFORM_SUPPORTS_AESNI if (aes128_supported_x86()) { aes128_ctr_xor_x86(context, counter, buffer, size); return; } #endif while (size >= 16) { aes128_encrypt(context, counter, tmp); for (uint32_t i=0; i<16; i++) { *buffer++ ^= tmp[i]; } ctr_add(counter, 1); size -= 16; } if (size != 0) { aes128_encrypt(context, counter, tmp); for (size_t i=0; i<size; i++) { *buffer++ ^= tmp[i]; } } } // https://tools.ietf.org/rfc/rfc4493.txt typedef struct { aes128_key key; uint8_t last[16]; uint8_t block[16]; uint32_t size; } aes128_cmac_ctx; static void aes128_cmac_process(const aes128_key* ctx, uint8_t* block, const uint8_t *buffer, uint32_t size) { assert(size % 16 == 0); #if PLATFORM_SUPPORTS_AESNI if (aes128_supported_x86()) { aes128_cmac_process_x86(ctx, block, buffer, size); return; } #endif for (uint32_t i = 0; i < size; i += 16) { for (size_t k = 0; k < 16; k++) { block[k] ^= *buffer++; } aes128_ecb_encrypt(ctx, block, block); } } static void aes128_cmac_init(aes128_cmac_ctx* ctx, const uint8_t* key) { aes128_init(&ctx->key, key); memset(ctx->last, 0, 16); ctx->size = 0; } static void aes128_cmac_update(aes128_cmac_ctx* ctx, const uint8_t* buffer, uint32_t size) { if (ctx->size + size <= 16) { memcpy(ctx->block + ctx->size, buffer, size); ctx->size += size; return; } if (ctx->size != 0) { uint32_t avail = 16 - ctx->size; memcpy(ctx->block + ctx->size, buffer, avail < size ? avail : size); buffer += avail; size -= avail; aes128_cmac_process(&ctx->key, ctx->last, ctx->block, 16); } if (size >= 16) { uint32_t full = (size - 1) & ~15; aes128_cmac_process(&ctx->key, ctx->last, buffer, full); buffer += full; size -= full; } memcpy(ctx->block, buffer, size); ctx->size = size; } static void cmac_gfmul(uint8_t* block) { uint8_t carry = 0; for (int i = 15; i >= 0; i--) { uint8_t x = block[i]; block[i] = (block[i] << 1) | (carry >> 7); carry = x; } block[15] ^= (carry & 0x80 ? 0x87 : 0); } static void aes128_cmac_done(aes128_cmac_ctx* ctx, uint8_t* mac) { uint8_t zero[16] = { 0 }; aes128_ecb_encrypt(&ctx->key, zero, mac); cmac_gfmul(mac); if (ctx->size != 16) { cmac_gfmul(mac); ctx->block[ctx->size] = 0x80; memset(ctx->block + ctx->size + 1, 0, 16 - (ctx->size + 1)); } for (size_t i = 0; i < 16; i++) { mac[i] ^= ctx->block[i]; } aes128_cmac_process(&ctx->key, mac, ctx->last, 16); } void aes128_cmac(const uint8_t* key, const uint8_t* buffer, uint32_t size, uint8_t* mac) { aes128_cmac_ctx ctx; aes128_cmac_init(&ctx, key); aes128_cmac_update(&ctx, buffer, size); aes128_cmac_done(&ctx, mac); } void aes128_psp_decrypt(const aes128_key* ctx, const uint8_t* iv, uint32_t index, uint8_t* buffer, uint32_t size) { assert(size % 16 == 0); uint8_t PKG_ALIGN(16) prev[16]; uint8_t PKG_ALIGN(16) block[16]; if (index == 0) { memset(prev, 0, 16); } else { memcpy(prev, iv, 12); set32le(prev + 12, index); } memcpy(block, iv, 16); set32le(block + 12, index); #if PLATFORM_SUPPORTS_AESNI if (aes128_supported_x86()) { aes128_psp_decrypt_x86(ctx, prev, block, buffer, size); return; } #endif for (uint32_t i = 0; i < size; i += 16) { set32le(block + 12, get32le(block + 12) + 1); uint8_t out[16]; aes128_ecb_decrypt(ctx, block, out); for (size_t k = 0; k < 16; k++) { *buffer++ ^= prev[k] ^ out[k]; } memcpy(prev, block, 16); } } 0707010000000A000081A4000001ED0000006B000000015EE6501B000002D7000000000000000000000000000000000000003900000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_aes.h#pragma once #include "pkg2zip_utils.h" typedef struct aes128_key { uint32_t PKG_ALIGN(16) key[44]; } aes128_key; void aes128_init(aes128_key* ctx, const uint8_t* key); void aes128_init_dec(aes128_key* ctx, const uint8_t* key); void aes128_ecb_encrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output); void aes128_ecb_decrypt(const aes128_key* ctx, const uint8_t* input, uint8_t* output); void aes128_ctr_xor(const aes128_key* ctx, const uint8_t* iv, uint64_t block, uint8_t* buffer, size_t size); void aes128_cmac(const uint8_t* key, const uint8_t* buffer, uint32_t size, uint8_t* mac); void aes128_psp_decrypt(const aes128_key* ctx, const uint8_t* iv, uint32_t index, uint8_t* buffer, uint32_t size); 0707010000000B000081A4000001ED0000006B000000015EE6501B00001776000000000000000000000000000000000000003D00000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_aes_x86.c#include "pkg2zip_aes.h" #include <string.h> #include <wmmintrin.h> // AESNI #include <tmmintrin.h> // SSSE3 #define AES128_INIT(ctx, x, rcon) \ { \ __m128i a, b; \ _mm_store_si128(ctx, x); \ a = _mm_aeskeygenassist_si128(x, rcon); \ a = _mm_shuffle_epi32(a, 0xff); \ b = _mm_slli_si128(x, 4); \ x = _mm_xor_si128(x, b); \ b = _mm_slli_si128(b, 4); \ x = _mm_xor_si128(x, b); \ b = _mm_slli_si128(b, 4); \ x = _mm_xor_si128(x, b); \ x = _mm_xor_si128(x, a); \ } void aes128_init_x86(aes128_key* ctx, const uint8_t* key) { __m128i* ekey = (__m128i*)ctx->key; __m128i x = _mm_loadu_si128((const __m128i*)key); AES128_INIT(ekey + 0, x, 0x01); AES128_INIT(ekey + 1, x, 0x02); AES128_INIT(ekey + 2, x, 0x04); AES128_INIT(ekey + 3, x, 0x08); AES128_INIT(ekey + 4, x, 0x10); AES128_INIT(ekey + 5, x, 0x20); AES128_INIT(ekey + 6, x, 0x40); AES128_INIT(ekey + 7, x, 0x80); AES128_INIT(ekey + 8, x, 0x1b); AES128_INIT(ekey + 9, x, 0x36); _mm_store_si128(ekey + 10, x); } void aes128_init_dec_x86(aes128_key* ctx, const uint8_t* key) { aes128_key enc; aes128_init_x86(&enc, key); const __m128i* ekey = (__m128i*)&enc.key; __m128i* dkey = (__m128i*)&ctx->key; _mm_store_si128(dkey + 10, _mm_load_si128(ekey + 0)); for (size_t i = 1; i < 10; i++) { _mm_store_si128(dkey + 10 - i, _mm_aesimc_si128(_mm_load_si128(ekey + i))); } _mm_store_si128(dkey + 0, _mm_load_si128(ekey + 10)); } static __m128i aes128_encrypt_x86(__m128i input, const __m128i* key) { __m128i tmp = _mm_xor_si128(input, _mm_load_si128(key + 0)); tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 1)); tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 2)); tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 3)); tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 4)); tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 5)); tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 6)); tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 7)); tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 8)); tmp = _mm_aesenc_si128(tmp, _mm_load_si128(key + 9)); return _mm_aesenclast_si128(tmp, _mm_load_si128(key + 10)); } static __m128i aes128_decrypt_x86(__m128i input, const __m128i* key) { __m128i tmp = _mm_xor_si128(input, _mm_load_si128(key + 0)); tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 1)); tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 2)); tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 3)); tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 4)); tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 5)); tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 6)); tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 7)); tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 8)); tmp = _mm_aesdec_si128(tmp, _mm_load_si128(key + 9)); return _mm_aesdeclast_si128(tmp, _mm_load_si128(key + 10)); } void aes128_ecb_encrypt_x86(const aes128_key* ctx, const uint8_t* input, uint8_t* output) { const __m128i* key = (__m128i*)ctx->key; __m128i tmp = aes128_encrypt_x86(_mm_loadu_si128((const __m128i*)input), key); _mm_storeu_si128((__m128i*)output, tmp); } void aes128_ecb_decrypt_x86(const aes128_key* ctx, const uint8_t* input, uint8_t* output) { const __m128i* key = (__m128i*)ctx->key; __m128i tmp = aes128_decrypt_x86(_mm_loadu_si128((const __m128i*)input), key); _mm_storeu_si128((__m128i*)output, tmp); } static __m128i ctr_increment(__m128i counter) { __m128i swap = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); __m128i tmp = _mm_shuffle_epi8(counter, swap); tmp = _mm_add_epi64(tmp, _mm_set_epi32(0, 0, 0, 1)); return _mm_shuffle_epi8(tmp, swap); } void aes128_ctr_xor_x86(const aes128_key* ctx, const uint8_t* iv, uint8_t* buffer, size_t size) { const __m128i* key = (__m128i*)ctx->key; __m128i counter = _mm_loadu_si128((const __m128i*)iv); while (size >= 16) { __m128i block = aes128_encrypt_x86(counter, key); __m128i tmp = _mm_xor_si128(_mm_loadu_si128((const __m128i*)buffer), block); _mm_storeu_si128((__m128i*)buffer, tmp); counter = ctr_increment(counter); buffer += 16; size -= 16; } if (size != 0) { uint8_t full[16]; memcpy(full, buffer, size); memset(full + size, 0, 16 - size); __m128i block = aes128_encrypt_x86(counter, key); __m128i tmp = _mm_xor_si128(_mm_loadu_si128((const __m128i*)full), block); _mm_storeu_si128((__m128i*)full, tmp); memcpy(buffer, full, size); } } void aes128_cmac_process_x86(const aes128_key* ctx, uint8_t* block, const uint8_t* buffer, uint32_t size) { const __m128i* key = (__m128i*)ctx->key; __m128i* data = (__m128i*)buffer; __m128i tmp = _mm_loadu_si128((__m128i*)block); for (uint32_t i = 0; i < size; i += 16) { __m128i input = _mm_loadu_si128(data++); tmp = _mm_xor_si128(tmp, input); tmp = aes128_encrypt_x86(tmp, key); } _mm_storeu_si128((__m128i*)block, tmp); } void aes128_psp_decrypt_x86(const aes128_key* ctx, const uint8_t* prev, const uint8_t* block, uint8_t* buffer, uint32_t size) { const __m128i* key = (__m128i*)ctx->key; __m128i one = _mm_setr_epi32(0, 0, 0, 1); __m128i x = _mm_load_si128((__m128i*)prev); __m128i y = _mm_load_si128((__m128i*)block); __m128i* data = (__m128i*)buffer; for (uint32_t i = 0; i < size; i += 16) { y = _mm_add_epi32(y, one); __m128i out = aes128_decrypt_x86(y, key); out = _mm_xor_si128(out, _mm_loadu_si128(data)); out = _mm_xor_si128(out, x); _mm_storeu_si128(data++, out); x = y; } } 0707010000000C000081A4000001ED0000006B000000015EE6501B00004282000000000000000000000000000000000000003B00000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_crc32.c#include "pkg2zip_crc32.h" #include "pkg2zip_utils.h" #ifdef __linux__ #include <endian.h> #endif #if defined(_MSC_VER) #define PLATFORM_SUPPORTS_PCLMUL 1 #include <intrin.h> static void get_cpuid(uint32_t level, uint32_t* arr) { __cpuidex((int*)arr, level, 0); } #elif defined(__x86_64__) || defined(__i386__) #define PLATFORM_SUPPORTS_PCLMUL 1 #include <cpuid.h> static void get_cpuid(uint32_t level, uint32_t* arr) { __cpuid_count(level, 0, arr[0], arr[1], arr[2], arr[3]); } #else #define PLATFORM_SUPPORTS_PCLMUL 0 #endif #if PLATFORM_SUPPORTS_PCLMUL static int crc32_supported_x86() { static int init = 0; static int supported; if (!init) { init = 1; uint32_t a[4]; get_cpuid(0, a); if (a[0] >= 1) { get_cpuid(1, a); supported = ((a[2] & (1 << 9)) && (a[2] & (1 << 1)) && (a[2] & (1 << 19))); } } return supported; } void crc32_init_x86(crc32_ctx* ctx); void crc32_update_x86(crc32_ctx* ctx, const void* buffer, size_t size); uint32_t crc32_done_x86(crc32_ctx* ctx); #endif static const uint32_t crc32[4][256] = { { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, }, { 0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539, 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72, }, { 0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, 0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed, }, { 0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca, 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, 0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1, } }; void crc32_init(crc32_ctx* ctx) { #if PLATFORM_SUPPORTS_PCLMUL if (crc32_supported_x86()) { crc32_init_x86(ctx); return; } #endif ctx->crc[0] = 0xffffffff; } void crc32_update(crc32_ctx* ctx, const void* buffer, size_t size) { #if PLATFORM_SUPPORTS_PCLMUL if (crc32_supported_x86()) { crc32_update_x86(ctx, buffer, size); return; } #endif const uint8_t* buffer8 = buffer; uint32_t value = ctx->crc[0]; while (size >= 4) { #if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN uint32_t x = get32be(buffer8); value = __builtin_bswap32(value) ^ x; value = crc32[0][value & 0xff] ^ crc32[1][(value >> 8) & 0xff] ^ crc32[2][(value >> 16) & 0xff] ^ crc32[3][(value >> 24) & 0xff]; #else uint32_t x = get32le(buffer8); value = value ^ x; value = crc32[0][(value >> 24) & 0xff] ^ crc32[1][(value >> 16) & 0xff] ^ crc32[2][(value >> 8) & 0xff] ^ crc32[3][value & 0xff]; #endif buffer8 += sizeof(x); size -= sizeof(x); } while (size --> 0) { value = (value >> 8) ^ crc32[0][(uint8_t)value ^ *buffer8++]; } ctx->crc[0] = value; } uint32_t crc32_done(crc32_ctx* ctx) { #if PLATFORM_SUPPORTS_PCLMUL if (crc32_supported_x86()) { return crc32_done_x86(ctx); } #endif return ~ctx->crc[0]; } static uint32_t crc32_gfmulv(const uint32_t* m, uint32_t v) { uint32_t r = 0; while (v) { if (v & 1) { r ^= *m; } v >>= 1; m++; } return r; } static void crc32_gfsq(const uint32_t* m, uint32_t* r) { for (size_t i = 0; i < 32; i++) { r[i] = crc32_gfmulv(m, m[i]); } } uint32_t crc32_combine(uint32_t a, uint32_t b, uint32_t blen) { uint32_t m1[32]; uint32_t m2[32]; m1[0] = 0xedb88320; for (uint32_t i = 1; i < 32; i++) { m1[i] = 1 << (i - 1); } crc32_gfsq(m1, m2); crc32_gfsq(m2, m1); for (;;) { crc32_gfsq(m1, m2); if (blen & 1) { a = crc32_gfmulv(m2, a); } blen >>= 1; if (blen == 0) { break; } crc32_gfsq(m2, m1); if (blen & 1) { a = crc32_gfmulv(m1, a); } blen >>= 1; if (blen == 0) { break; } } return a ^ b; } 0707010000000D000081A4000001ED0000006B000000015EE6501B000001C0000000000000000000000000000000000000003B00000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_crc32.h#pragma once #include "pkg2zip_utils.h" typedef struct { uint32_t PKG_ALIGN(16) crc[4 * 5]; } crc32_ctx; void crc32_init(crc32_ctx* ctx); void crc32_update(crc32_ctx* ctx, const void* buffer, size_t size); uint32_t crc32_done(crc32_ctx* ctx); // returns crc32(x||y) // where a=crc32(x) and b=crc32(y) // crc32(x||y) = crc32(x||z) ^ crc32(y), where z=00...00 (same length as y) uint32_t crc32_combine(uint32_t a, uint32_t b, uint32_t blen); 0707010000000E000081A4000001ED0000006B000000015EE6501B0000340D000000000000000000000000000000000000003F00000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_crc32_x86.c#include "pkg2zip_crc32.h" #include <wmmintrin.h> // PCLMUL #include <tmmintrin.h> // SSSE3 #include <smmintrin.h> // SSS4 // Whitepaper: https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf // ZLIB licensed code from https://github.com/jtkukunas/zlib/blob/master/crc_folding.c static const uint32_t PKG_ALIGN(16) shift_table[] = { 0x84838281, 0x88878685, 0x8c8b8a89, 0x008f8e8d, 0x85848382, 0x89888786, 0x8d8c8b8a, 0x01008f8e, 0x86858483, 0x8a898887, 0x8e8d8c8b, 0x0201008f, 0x87868584, 0x8b8a8988, 0x8f8e8d8c, 0x03020100, 0x88878685, 0x8c8b8a89, 0x008f8e8d, 0x04030201, 0x89888786, 0x8d8c8b8a, 0x01008f8e, 0x05040302, 0x8a898887, 0x8e8d8c8b, 0x0201008f, 0x06050403, 0x8b8a8988, 0x8f8e8d8c, 0x03020100, 0x07060504, 0x8c8b8a89, 0x008f8e8d, 0x04030201, 0x08070605, 0x8d8c8b8a, 0x01008f8e, 0x05040302, 0x09080706, 0x8e8d8c8b, 0x0201008f, 0x06050403, 0x0a090807, 0x8f8e8d8c, 0x03020100, 0x07060504, 0x0b0a0908, 0x008f8e8d, 0x04030201, 0x08070605, 0x0c0b0a09, 0x01008f8e, 0x05040302, 0x09080706, 0x0d0c0b0a, 0x0201008f, 0x06050403, 0x0a090807, 0x0e0d0c0b, }; #define FOLD1(xmm0, xmm1, xmm2, xmm3) do \ { \ const __m128i fold4 = _mm_set_epi32( \ 0x00000001, 0x54442bd4, \ 0x00000001, 0xc6e41596); \ \ __m128i r0, r1, r2, r3, a, b; \ \ r0 = xmm1; \ r1 = xmm2; \ r2 = xmm3; \ \ a = _mm_clmulepi64_si128(xmm0, fold4, 0x01); \ b = _mm_clmulepi64_si128(xmm0, fold4, 0x10); \ r3 = _mm_xor_si128(a, b); \ \ xmm0 = r0; \ xmm1 = r1; \ xmm2 = r2; \ xmm3 = r3; \ } while (0) #define FOLD2(xmm0, xmm1, xmm2, xmm3) do \ { \ const __m128i fold4 = _mm_set_epi32( \ 0x00000001, 0x54442bd4, \ 0x00000001, 0xc6e41596); \ \ __m128i r0, r1, r2, r3, a, b; \ \ r0 = xmm2; \ r1 = xmm3; \ \ a = _mm_clmulepi64_si128(xmm0, fold4, 0x01); \ b = _mm_clmulepi64_si128(xmm0, fold4, 0x10); \ r2 = _mm_xor_si128(a, b); \ \ a = _mm_clmulepi64_si128(xmm1, fold4, 0x01); \ b = _mm_clmulepi64_si128(xmm1, fold4, 0x10); \ r3 = _mm_xor_si128(a, b); \ \ xmm0 = r0; \ xmm1 = r1; \ xmm2 = r2; \ xmm3 = r3; \ } while (0) #define FOLD3(xmm0, xmm1, xmm2, xmm3) do \ { \ const __m128i fold4 = _mm_set_epi32( \ 0x00000001, 0x54442bd4, \ 0x00000001, 0xc6e41596); \ \ __m128i r0, r1, r2, r3, a, b; \ \ r0 = xmm3; \ \ a = _mm_clmulepi64_si128(xmm0, fold4, 0x01); \ b = _mm_clmulepi64_si128(xmm0, fold4, 0x10); \ r1 = _mm_xor_si128(a, b); \ \ a = _mm_clmulepi64_si128(xmm1, fold4, 0x01); \ b = _mm_clmulepi64_si128(xmm1, fold4, 0x10); \ r2 = _mm_xor_si128(a, b); \ \ a = _mm_clmulepi64_si128(xmm2, fold4, 0x01); \ b = _mm_clmulepi64_si128(xmm2, fold4, 0x10); \ r3 = _mm_xor_si128(a, b); \ \ xmm0 = r0; \ xmm1 = r1; \ xmm2 = r2; \ xmm3 = r3; \ } while (0) #define FOLD4(xmm0, xmm1, xmm2, xmm3) do \ { \ const __m128i fold4 = _mm_set_epi32( \ 0x00000001, 0x54442bd4, \ 0x00000001, 0xc6e41596); \ \ __m128i a, b; \ \ a = _mm_clmulepi64_si128(xmm0, fold4, 0x01); \ b = _mm_clmulepi64_si128(xmm0, fold4, 0x10); \ xmm0 = _mm_xor_si128(a, b); \ \ a = _mm_clmulepi64_si128(xmm1, fold4, 0x01); \ b = _mm_clmulepi64_si128(xmm1, fold4, 0x10); \ xmm1 = _mm_xor_si128(a, b); \ \ a = _mm_clmulepi64_si128(xmm2, fold4, 0x01); \ b = _mm_clmulepi64_si128(xmm2, fold4, 0x10); \ xmm2 = _mm_xor_si128(a, b); \ \ a = _mm_clmulepi64_si128(xmm3, fold4, 0x01); \ b = _mm_clmulepi64_si128(xmm3, fold4, 0x10); \ xmm3 = _mm_xor_si128(a, b); \ } while (0) #define PARTIAL(len, xmm0, xmm1, xmm2, xmm3, xmm4) do \ { \ const __m128i fold4 = _mm_set_epi32( \ 0x00000001, 0x54442bd4, \ 0x00000001, 0xc6e41596); \ const __m128i mask = _mm_set1_epi32(0x80808080); \ \ __m128i shl = _mm_load_si128((__m128i *)shift_table + (len - 1)); \ __m128i shr = _mm_xor_si128(shl, mask); \ \ __m128i a, b, r; \ __m128i tmp = _mm_shuffle_epi8(xmm0, shl); \ \ a = _mm_shuffle_epi8(xmm0, shr); \ b = _mm_shuffle_epi8(xmm1, shl); \ xmm0 = _mm_or_si128(a, b); \ \ a = _mm_shuffle_epi8(xmm1, shr); \ b = _mm_shuffle_epi8(xmm2, shl); \ xmm1 = _mm_or_si128(a, b); \ \ a = _mm_shuffle_epi8(xmm2, shr); \ b = _mm_shuffle_epi8(xmm3, shl); \ xmm2 = _mm_or_si128(a, b); \ \ a = _mm_shuffle_epi8(xmm3, shr); \ b = _mm_shuffle_epi8(xmm4, shl); \ xmm4 = b; \ r = _mm_or_si128(a, b); \ \ a = _mm_clmulepi64_si128(tmp, fold4, 0x10); \ b = _mm_clmulepi64_si128(tmp, fold4, 0x01); \ \ r = _mm_xor_si128(r, a); \ r = _mm_xor_si128(r, b); \ xmm3 = r; \ } while(0) void crc32_init_x86(crc32_ctx* ctx) { __m128i init = _mm_cvtsi32_si128(0x9db42487); __m128i zero = _mm_setzero_si128(); _mm_store_si128((__m128i*)ctx->crc + 0, init); _mm_store_si128((__m128i*)ctx->crc + 1, zero); _mm_store_si128((__m128i*)ctx->crc + 2, zero); _mm_store_si128((__m128i*)ctx->crc + 3, zero); } void crc32_update_x86(crc32_ctx* ctx, const void* buffer, size_t size) { const uint8_t* buffer8 = buffer; __m128i xmm0 = _mm_load_si128((__m128i*)ctx->crc + 0); __m128i xmm1 = _mm_load_si128((__m128i*)ctx->crc + 1); __m128i xmm2 = _mm_load_si128((__m128i*)ctx->crc + 2); __m128i xmm3 = _mm_load_si128((__m128i*)ctx->crc + 3); __m128i xmm4 = _mm_load_si128((__m128i*)ctx->crc + 4); if (size < 16) { if (size == 0) { return; } xmm4 = _mm_loadu_si128((__m128i *)buffer8); goto partial; } uint32_t prefix = (0 - (uintptr_t)buffer8) & 0xF; if (prefix != 0) { xmm4 = _mm_loadu_si128((__m128i *)buffer8); buffer8 += prefix; size -= prefix; PARTIAL(prefix, xmm0, xmm1, xmm2, xmm3, xmm4); } while (size >= 64) { __m128i t0 = _mm_load_si128((__m128i *)buffer8 + 0); __m128i t1 = _mm_load_si128((__m128i *)buffer8 + 1); __m128i t2 = _mm_load_si128((__m128i *)buffer8 + 2); __m128i t3 = _mm_load_si128((__m128i *)buffer8 + 3); FOLD4(xmm0, xmm1, xmm2, xmm3); xmm0 = _mm_xor_si128(xmm0, t0); xmm1 = _mm_xor_si128(xmm1, t1); xmm2 = _mm_xor_si128(xmm2, t2); xmm3 = _mm_xor_si128(xmm3, t3); buffer8 += 64; size -= 64; } if (size >= 48) { __m128i t0 = _mm_load_si128((__m128i *)buffer8 + 0); __m128i t1 = _mm_load_si128((__m128i *)buffer8 + 1); __m128i t2 = _mm_load_si128((__m128i *)buffer8 + 2); FOLD3(xmm0, xmm1, xmm2, xmm3); xmm1 = _mm_xor_si128(xmm1, t0); xmm2 = _mm_xor_si128(xmm2, t1); xmm3 = _mm_xor_si128(xmm3, t2); buffer8 += 48; size -= 48; } else if (size >= 32) { __m128i t0 = _mm_load_si128((__m128i *)buffer8 + 0); __m128i t1 = _mm_load_si128((__m128i *)buffer8 + 1); FOLD2(xmm0, xmm1, xmm2, xmm3); xmm2 = _mm_xor_si128(xmm2, t0); xmm3 = _mm_xor_si128(xmm3, t1); buffer8 += 32; size -= 32; } else if (size >= 16) { __m128i t0 = _mm_load_si128((__m128i *)buffer8 + 0); FOLD1(xmm0, xmm1, xmm2, xmm3); xmm3 = _mm_xor_si128(xmm3, t0); buffer8 += 16; size -= 16; } if (size == 0) { goto done; } xmm4 = _mm_load_si128((__m128i *)buffer8); partial: PARTIAL(size, xmm0, xmm1, xmm2, xmm3, xmm4); done: _mm_store_si128((__m128i*)ctx->crc + 0, xmm0); _mm_store_si128((__m128i*)ctx->crc + 1, xmm1); _mm_store_si128((__m128i*)ctx->crc + 2, xmm2); _mm_store_si128((__m128i*)ctx->crc + 3, xmm3); _mm_store_si128((__m128i*)ctx->crc + 4, xmm4); } uint32_t crc32_done_x86(crc32_ctx* ctx) { const __m128i mask1 = _mm_setr_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000); const __m128i mask2 = _mm_setr_epi32(0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); __m128i xmm0 = _mm_load_si128((__m128i*)ctx->crc + 0); __m128i xmm1 = _mm_load_si128((__m128i*)ctx->crc + 1); __m128i xmm2 = _mm_load_si128((__m128i*)ctx->crc + 2); __m128i xmm3 = _mm_load_si128((__m128i*)ctx->crc + 3); __m128i fold; __m128i a, b, t; fold = _mm_setr_epi32(0xccaa009e, 0x00000000, 0x751997d0, 0x00000001); a = _mm_clmulepi64_si128(xmm0, fold, 0x10); b = _mm_clmulepi64_si128(xmm0, fold, 0x01); t = _mm_xor_si128(xmm1, a); t = _mm_xor_si128(t, b); a = _mm_clmulepi64_si128(t, fold, 0x10); b = _mm_clmulepi64_si128(t, fold, 0x01); t = _mm_xor_si128(xmm2, a); t = _mm_xor_si128(t, b); a = _mm_clmulepi64_si128(t, fold, 0x10); b = _mm_clmulepi64_si128(t, fold, 0x01); t = _mm_xor_si128(xmm3, a); t = _mm_xor_si128(t, b); fold = _mm_setr_epi32(0xccaa009e, 0x00000000, 0x63cd6124, 0x00000001); a = _mm_clmulepi64_si128(t, fold, 0); b = _mm_srli_si128(t, 8); a = _mm_xor_si128(a, b); b = _mm_slli_si128(a, 4); b = _mm_clmulepi64_si128(b, fold, 0x10); t = _mm_xor_si128(a, b); t = _mm_and_si128(t, mask2); fold = _mm_setr_epi32(0xf7011640, 0x00000001, 0xdb710640, 0x00000001); a = _mm_clmulepi64_si128(t, fold, 0); a = _mm_xor_si128(a, t); a = _mm_and_si128(a, mask1); b = _mm_clmulepi64_si128(a, fold, 0x10); b = _mm_xor_si128(b, a); b = _mm_xor_si128(b, t); uint32_t crc = _mm_extract_epi32(b, 2); return ~crc; } 0707010000000F000081A4000001ED0000006B000000015EE6501B000008C8000000000000000000000000000000000000003900000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_out.c#include "pkg2zip_out.h" #include "pkg2zip_sys.h" #include "pkg2zip_zip.h" #include <stdio.h> static zip out_zip; static int out_zipped; static sys_file out_file; static uint64_t out_file_offset; void out_begin(const char* name, int zipped) { if (zipped) { zip_create(&out_zip, name); } out_zipped = zipped; } void out_end(void) { if (out_zipped) { zip_close(&out_zip); } } void out_add_folder(const char* path) { if (out_zipped) { zip_add_folder(&out_zip, path); } else { sys_mkdir(path); } } void out_add_parent(const char* path) { char parent[1024]; char* lastslash = strrchr(path, '/'); if (lastslash != NULL) { snprintf(parent, strlen(path)-strlen(lastslash)+1, "%s", path); if (out_zipped) { zip_add_folder(&out_zip, parent); } else { sys_mkdir(parent); } } } uint64_t out_begin_file(const char* name, int compress) { if (out_zipped) { return zip_begin_file(&out_zip, name, compress); } else { out_file = sys_create(name); out_file_offset = 0; return 0; } } void out_end_file(void) { if (out_zipped) { zip_end_file(&out_zip); } else { sys_close(out_file); } } void out_write(const void* buffer, uint32_t size) { if (out_zipped) { zip_write_file(&out_zip, buffer, size); } else { sys_write(out_file, out_file_offset, buffer, size); out_file_offset += size; } } void out_write_at(uint64_t offset, const void* buffer, uint32_t size) { if (out_zipped) { zip_write_file_at(&out_zip, offset, buffer, size); } else { sys_write(out_file, offset, buffer, size); } } void out_set_offset(uint64_t offset) { if (out_zipped) { zip_set_offset(&out_zip, offset); } else { out_file_offset = offset; } } uint32_t out_zip_get_crc32(void) { if (out_zipped) { return zip_get_crc32(&out_zip); } return 0; } void out_zip_set_crc32(uint32_t crc) { if (out_zipped) { zip_set_crc32(&out_zip, crc); } } 07070100000010000081A4000001ED0000006B000000015EE6501B00000239000000000000000000000000000000000000003900000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_out.h#pragma once #include <stdint.h> void out_begin(const char* name, int zipped); void out_end(void); void out_add_folder(const char* path); void out_add_parent(const char* path); uint64_t out_begin_file(const char* name, int compress); void out_end_file(void); void out_write(const void* buffer, uint32_t size); // hacky solution to be able to write cso header after the data is written void out_write_at(uint64_t offset, const void* buffer, uint32_t size); void out_set_offset(uint64_t offset); uint32_t out_zip_get_crc32(void); void out_zip_set_crc32(uint32_t crc); 07070100000011000081A4000001ED0000006B000000015EE6501B000061DE000000000000000000000000000000000000003900000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_psp.c#include "pkg2zip_psp.h" #include "pkg2zip_out.h" #include "pkg2zip_crc32.h" #include "pkg2zip_utils.h" #include "miniz_tdef.h" #include <assert.h> #include <string.h> #define ISO_SECTOR_SIZE 2048 #define CSO_HEADER_SIZE 24 // https://vitadevwiki.com/vita/Keys_NonVita#PSPAESKirk4.2F7 static const uint8_t kirk7_key38[] = { 0x12, 0x46, 0x8d, 0x7e, 0x1c, 0x42, 0x20, 0x9b, 0xba, 0x54, 0x26, 0x83, 0x5e, 0xb0, 0x33, 0x03 }; static const uint8_t kirk7_key39[] = { 0xc4, 0x3b, 0xb6, 0xd6, 0x53, 0xee, 0x67, 0x49, 0x3e, 0xa9, 0x5f, 0xbc, 0x0c, 0xed, 0x6f, 0x8a }; static const uint8_t kirk7_key63[] = { 0x9c, 0x9b, 0x13, 0x72, 0xf8, 0xc6, 0x40, 0xcf, 0x1c, 0x62, 0xf5, 0xd5, 0x92, 0xdd, 0xb5, 0x82 }; // https://vitadevwiki.com/vita/Keys_NonVita#PSPAMHashKey static const uint8_t amctl_hashkey_3[] = { 0xe3, 0x50, 0xed, 0x1d, 0x91, 0x0a, 0x1f, 0xd0, 0x29, 0xbb, 0x1c, 0x3e, 0xf3, 0x40, 0x77, 0xfb }; static const uint8_t amctl_hashkey_4[] = { 0x13, 0x5f, 0xa4, 0x7c, 0xab, 0x39, 0x5b, 0xa4, 0x76, 0xb8, 0xcc, 0xa9, 0x8f, 0x3a, 0x04, 0x45 }; static const uint8_t amctl_hashkey_5[] = { 0x67, 0x8d, 0x7f, 0xa3, 0x2a, 0x9c, 0xa0, 0xd1, 0x50, 0x8a, 0xd8, 0x38, 0x5e, 0x4b, 0x01, 0x7e }; // lzrc decompression code from libkirk by tpu typedef struct { // input stream const uint8_t* input; uint32_t in_ptr; uint32_t in_len; // output stream uint8_t* output; uint32_t out_ptr; uint32_t out_len; // range decode uint32_t range; uint32_t code; uint32_t out_code; uint8_t lc; uint8_t bm_literal[8][256]; uint8_t bm_dist_bits[8][39]; uint8_t bm_dist[18][8]; uint8_t bm_match[8][8]; uint8_t bm_len[8][31]; } lzrc_decode; static void rc_init(lzrc_decode* rc, void* out, int out_len, const void* in, int in_len) { if (in_len < 5) { sys_error("ERROR: internal error - lzrc input underflow! pkg may be corrupted?\n"); } rc->input = in; rc->in_len = in_len; rc->in_ptr = 5; rc->output = out; rc->out_len = out_len; rc->out_ptr = 0; rc->range = 0xffffffff; rc->lc = rc->input[0]; rc->code = get32be(rc->input + 1); rc->out_code = 0xffffffff; memset(rc->bm_literal, 0x80, sizeof(rc->bm_literal)); memset(rc->bm_dist_bits, 0x80, sizeof(rc->bm_dist_bits)); memset(rc->bm_dist, 0x80, sizeof(rc->bm_dist)); memset(rc->bm_match, 0x80, sizeof(rc->bm_match)); memset(rc->bm_len, 0x80, sizeof(rc->bm_len)); } static void normalize(lzrc_decode* rc) { if (rc->range < 0x01000000) { rc->range <<= 8; rc->code = (rc->code << 8) + rc->input[rc->in_ptr]; rc->in_ptr++; } } static int rc_bit(lzrc_decode* rc, uint8_t *prob) { uint32_t bound; normalize(rc); bound = (rc->range >> 8) * (*prob); *prob -= *prob >> 3; if (rc->code < bound) { rc->range = bound; *prob += 31; return 1; } else { rc->code -= bound; rc->range -= bound; return 0; } } static int rc_bittree(lzrc_decode* rc, uint8_t *probs, int limit) { int number = 1; do { number = (number << 1) + rc_bit(rc, probs + number); } while (number < limit); return number; } static int rc_number(lzrc_decode* rc, uint8_t *prob, uint32_t n) { int number = 1; if (n > 3) { number = (number << 1) + rc_bit(rc, prob + 3); if (n > 4) { number = (number << 1) + rc_bit(rc, prob + 3); if (n > 5) { // direct bits normalize(rc); for (uint32_t i = 0; i < n - 5; i++) { rc->range >>= 1; number <<= 1; if (rc->code < rc->range) { number += 1; } else { rc->code -= rc->range; } } } } } if (n > 0) { number = (number << 1) + rc_bit(rc, prob); if (n > 1) { number = (number << 1) + rc_bit(rc, prob + 1); if (n > 2) { number = (number << 1) + rc_bit(rc, prob + 2); } } } return number; } static int lzrc_decompress(void* out, int out_len, const void* in, int in_len) { lzrc_decode rc; rc_init(&rc, out, out_len, in, in_len); if (rc.lc & 0x80) { // plain text memcpy(rc.output, rc.input + 5, rc.code); return rc.code; } int rc_state = 0; uint8_t last_byte = 0; for (;;) { uint32_t match_step = 0; int bit = rc_bit(&rc, &rc.bm_match[rc_state][match_step]); if (bit == 0) // literal { if (rc_state > 0) { rc_state -= 1; } int byte = rc_bittree(&rc, &rc.bm_literal[((last_byte >> rc.lc) & 0x07)][0], 0x100); byte -= 0x100; if (rc.out_ptr == rc.out_len) { sys_error("ERROR: internal error - lzrc output overflow! pkg may be corrupted?\n"); } rc.output[rc.out_ptr++] = (uint8_t)byte; last_byte = (uint8_t)byte; } else // match { // find bits of match length uint32_t len_bits = 0; for (int i = 0; i < 7; i++) { match_step += 1; bit = rc_bit(&rc, &rc.bm_match[rc_state][match_step]); if (bit == 0) { break; } len_bits += 1; } // find match length uint32_t match_len; if (len_bits == 0) { match_len = 1; } else { uint32_t len_state = ((len_bits - 1) << 2) + ((rc.out_ptr << (len_bits - 1)) & 0x03); match_len = rc_number(&rc, &rc.bm_len[rc_state][len_state], len_bits); if (match_len == 0xFF) { // end of stream return rc.out_ptr; } } // find number of bits of match distance uint32_t dist_state = 0; uint32_t limit = 8; if (match_len > 2) { dist_state += 7; limit = 44; } int dist_bits = rc_bittree(&rc, &rc.bm_dist_bits[len_bits][dist_state], limit); dist_bits -= limit; // find match distance uint32_t match_dist; if (dist_bits > 0) { match_dist = rc_number(&rc, &rc.bm_dist[dist_bits][0], dist_bits); } else { match_dist = 1; } // copy match bytes if (match_dist > rc.out_ptr) { sys_error("ERROR: internal error - lzrc match_dist out of range! pkg may be corrupted?\n"); } if (rc.out_ptr + match_len + 1 > rc.out_len) { sys_error("ERROR: internal error - lzrc output overflow! pkg may be corrupted?\n"); } const uint8_t* match_src = rc.output + rc.out_ptr - match_dist; for (uint32_t i = 0; i <= match_len; i++) { rc.output[rc.out_ptr++] = *match_src++; } last_byte = match_src[-1]; rc_state = 6 + ((rc.out_ptr + 1) & 1); } } } static void init_psp_decrypt(aes128_key* key, uint8_t* iv, int eboot, const uint8_t* mac, const uint8_t* header, uint32_t offset1, uint32_t offset2) { uint8_t tmp[16]; aes128_init_dec(key, kirk7_key63); if (eboot) { aes128_ecb_decrypt(key, header + offset1, tmp); } else { memcpy(tmp, header + offset1, 16); } aes128_key aes; aes128_init_dec(&aes, kirk7_key38); aes128_ecb_decrypt(&aes, tmp, tmp); for (size_t i = 0; i < 16; i++) { iv[i] = mac[i] ^ tmp[i] ^ header[offset2 + i] ^ amctl_hashkey_3[i] ^ amctl_hashkey_5[i]; } aes128_init_dec(&aes, kirk7_key39); aes128_ecb_decrypt(&aes, iv, iv); for (size_t i = 0; i < 16; i++) { iv[i] ^= amctl_hashkey_4[i]; } } static void init_psx_keys(uint8_t* iv, const uint8_t* mac, const uint8_t* header, uint32_t offset1) { uint8_t tmp[16]; memcpy(tmp, header + offset1, 16); aes128_key aes; aes128_init_dec(&aes, kirk7_key38); aes128_ecb_decrypt(&aes, tmp, tmp); for (size_t i = 0; i < 16; i++) { iv[i] = mac[i] ^ tmp[i] ^ amctl_hashkey_3[i]; } } void unpack_psp_eboot(const char* path, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset, uint64_t item_size, int cso) { if (item_size < 0x28) { sys_error("ERROR: eboot.pbp file is to short!\n"); } uint8_t eboot_header[0x28]; sys_read(pkg, enc_offset + item_offset, eboot_header, sizeof(eboot_header)); aes128_ctr_xor(pkg_key, pkg_iv, item_offset / 16, eboot_header, sizeof(eboot_header)); if (memcmp(eboot_header, "\x00PBP", 4) != 0) { sys_error("ERROR: wrong eboot.pbp header signature!\n"); } uint32_t psar_offset = get32le(eboot_header + 0x24); if (psar_offset + 256 > item_size) { sys_error("ERROR: eboot.pbp file is to short!\n"); } assert(psar_offset % 16 == 0); uint8_t psar_header[256]; sys_read(pkg, enc_offset + item_offset + psar_offset, psar_header, sizeof(psar_header)); aes128_ctr_xor(pkg_key, pkg_iv, (item_offset + psar_offset) / 16, psar_header, sizeof(psar_header)); if (memcmp(psar_header, "NPUMDIMG", 8) != 0) { sys_error("ERROR: wrong data.psar header signature!\n"); } uint32_t iso_block = get32le(psar_header + 0x0c); if (iso_block > 16) { sys_error("ERROR: unsupported data.psar block size %u, max %u supported!\b", iso_block, 16); } uint8_t mac[16]; aes128_cmac(kirk7_key38, psar_header, 0xc0, mac); aes128_key psp_key; uint8_t psp_iv[16]; init_psp_decrypt(&psp_key, psp_iv, 1, mac, psar_header, 0xc0, 0xa0); aes128_psp_decrypt(&psp_key, psp_iv, 0, psar_header + 0x40, 0x60); uint32_t iso_start = get32le(psar_header + 0x54); uint32_t iso_end = get32le(psar_header + 0x64); uint32_t iso_total = iso_end - iso_start - 1; uint32_t block_count = (iso_total + iso_block - 1) / iso_block; uint32_t iso_table = get32le(psar_header + 0x6c); if (iso_table + block_count * 32 > item_size) { sys_error("ERROR: offset table in data.psar file is too large!\n"); } mz_uint cso_compress_flags = 0; uint32_t cso_index = 0; uint32_t cso_offset = 0; uint64_t cso_size = 0; uint32_t* cso_block = NULL; uint32_t initial_size = 0; uint64_t file_offset = out_begin_file(path, !cso); if (cso) { cso_size = block_count * iso_block * ISO_SECTOR_SIZE; cso_compress_flags = tdefl_create_comp_flags_from_zip_params(cso, -MZ_DEFAULT_WINDOW_BITS, MZ_FIXED); uint32_t cso_block_count = (uint32_t)(1 + (cso_size + ISO_SECTOR_SIZE - 1) / ISO_SECTOR_SIZE); cso_block = sys_realloc(NULL, cso_block_count * sizeof(uint32_t)); initial_size = CSO_HEADER_SIZE + cso_block_count * sizeof(uint32_t); out_set_offset(file_offset + initial_size); cso_offset = initial_size; } for (uint32_t i = 0; i < block_count; i++) { uint64_t table_offset = item_offset + psar_offset + iso_table + 32 * i; uint8_t table[32]; sys_read(pkg, enc_offset + table_offset, table, sizeof(table)); aes128_ctr_xor(pkg_key, pkg_iv, table_offset / 16, table, sizeof(table)); uint32_t t[8]; for (size_t k = 0; k < 8; k++) { t[k] = get32le(table + k * 4); } uint32_t block_offset = t[4] ^ t[2] ^ t[3]; uint32_t block_size = t[5] ^ t[1] ^ t[2]; uint32_t block_flags = t[6] ^ t[0] ^ t[3]; if (psar_offset + block_size > item_size) { sys_error("ERROR: iso block size/offset is to large!\n"); } uint8_t PKG_ALIGN(16) data[16 * ISO_SECTOR_SIZE]; uint64_t abs_offset = item_offset + psar_offset + block_offset; sys_output_progress(enc_offset + abs_offset); sys_read(pkg, enc_offset + abs_offset, data, block_size); aes128_ctr_xor(pkg_key, pkg_iv, abs_offset / 16, data, block_size); if ((block_flags & 4) == 0) { aes128_psp_decrypt(&psp_key, psp_iv, block_offset / 16, data, block_size); } uint32_t out_size; if (block_size == iso_block * ISO_SECTOR_SIZE) { if (cso) { for (size_t n = 0; n < iso_block * ISO_SECTOR_SIZE; n += ISO_SECTOR_SIZE) { cso_block[cso_index] = cso_offset; uint8_t PKG_ALIGN(16) output[ISO_SECTOR_SIZE]; size_t insize = ISO_SECTOR_SIZE; size_t outsize = sizeof(output); tdefl_compressor c; tdefl_init(&c, cso_compress_flags); tdefl_status st = tdefl_compress(&c, data + n, &insize, output, &outsize, TDEFL_FINISH); if (st == TDEFL_STATUS_DONE) { out_write(output, (uint32_t)outsize); cso_offset += (uint32_t)outsize; } else { cso_block[cso_index] |= 0x80000000; out_write(data + n, ISO_SECTOR_SIZE); cso_offset += ISO_SECTOR_SIZE; } cso_index++; } } else { out_write(data, (uint32_t)block_size); } } else { uint8_t PKG_ALIGN(16) uncompressed[16 * ISO_SECTOR_SIZE]; out_size = lzrc_decompress(uncompressed, sizeof(uncompressed), data, block_size); if (out_size != iso_block * ISO_SECTOR_SIZE) { sys_error("ERROR: internal error - lzrc decompression failed! pkg may be corrupted?\n"); } if (cso) { for (size_t n = 0; n < iso_block * ISO_SECTOR_SIZE; n += ISO_SECTOR_SIZE) { cso_block[cso_index] = cso_offset; uint8_t output[ISO_SECTOR_SIZE]; size_t insize = ISO_SECTOR_SIZE; size_t outsize = sizeof(output); tdefl_compressor c; tdefl_init(&c, cso_compress_flags); tdefl_status st = tdefl_compress(&c, uncompressed + n, &insize, output, &outsize, TDEFL_FINISH); if (st == TDEFL_STATUS_DONE) { out_write(output, (uint32_t)outsize); cso_offset += (uint32_t)outsize; } else { cso_block[cso_index] |= 0x80000000; out_write(uncompressed + n, ISO_SECTOR_SIZE); cso_offset += ISO_SECTOR_SIZE; } cso_index++; } } else { out_write(uncompressed, (uint32_t)out_size); } } } if (cso) { cso_block[cso_index++] = cso_offset; uint8_t cso_header[CSO_HEADER_SIZE] = { 0x43, 0x49, 0x53, 0x4f }; // header size set32le(cso_header + 4, sizeof(cso_header)); // original size set64le(cso_header + 8, cso_size); // block size set32le(cso_header + 16, ISO_SECTOR_SIZE); // version cso_header[20] = 1; out_write_at(file_offset, cso_header, sizeof(cso_header)); out_write_at(file_offset + sizeof(cso_header), cso_block, cso_index * sizeof(uint32_t)); crc32_ctx cheader; crc32_init(&cheader); crc32_update(&cheader, cso_header, sizeof(cso_header)); crc32_update(&cheader, cso_block, cso_index * sizeof(uint32_t)); uint32_t header_crc32 = crc32_done(&cheader); uint32_t data_crc32 = out_zip_get_crc32(); uint32_t data_len = (uint32_t)(cso_offset - initial_size); uint32_t crc32 = crc32_combine(header_crc32, data_crc32, data_len); out_zip_set_crc32(crc32); sys_realloc(cso_block, 0); } out_end_file(); } void unpack_psp_key(const char* path, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset, uint64_t item_size) { if (item_size < 0x90 + 0xa0) { sys_error("ERROR: PSP-KEY.EDAT file is to short!\n"); } uint8_t key_header[0xa0]; sys_read(pkg, enc_offset + item_offset + 0x90, key_header, sizeof(key_header)); aes128_ctr_xor(pkg_key, pkg_iv, (item_offset + 0x90) / 16, key_header, sizeof(key_header)); if (memcmp(key_header, "\x00PGD", 4) != 0) { sys_error("ERROR: wrong PSP-KEY.EDAT header signature!\n"); } uint32_t key_index = get32le(key_header + 4); uint32_t drm_type = get32le(key_header + 8); if (key_index != 1 || drm_type != 1) { sys_error("ERROR: unsupported PSP-KEY.EDAT file, key/drm type is wrong!\n"); } uint8_t mac[16]; aes128_cmac(kirk7_key38, key_header, 0x70, mac); aes128_key psp_key; uint8_t psp_iv[16]; init_psp_decrypt(&psp_key, psp_iv, 0, mac, key_header, 0x70, 0x10); aes128_psp_decrypt(&psp_key, psp_iv, 0, key_header + 0x30, 0x30); uint32_t data_size = get32le(key_header + 0x44); uint32_t data_offset = get32le(key_header + 0x4c); if (data_size != 0x10 || data_offset != 0x90) { sys_error("ERROR: unsupported PSP-KEY.EDAT file, data/offset is wrong!\n"); } init_psp_decrypt(&psp_key, psp_iv, 0, mac, key_header, 0x70, 0x30); aes128_psp_decrypt(&psp_key, psp_iv, 0, key_header + 0x90, 0x10); out_begin_file(path, 0); out_write(key_header + 0x90, 0x10); out_end_file(); } void unpack_psp_edat(const char* path, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset, uint64_t item_size) { if (item_size < 0x90 + 0xa0) { sys_error("ERROR: EDAT file is to short!\n"); } uint8_t item_header[90]; sys_read(pkg, enc_offset + item_offset, item_header, sizeof(item_header)); aes128_ctr_xor(pkg_key, pkg_iv, (item_offset) / 16, item_header, sizeof(item_header)); uint8_t key_header_offset = item_header[0xC]; uint8_t key_header[0xa0]; sys_read(pkg, enc_offset + item_offset + key_header_offset, key_header, sizeof(key_header)); aes128_ctr_xor(pkg_key, pkg_iv, (item_offset + key_header_offset) / 16, key_header, sizeof(key_header)); if (memcmp(key_header, "\x00PGD", 4) != 0) { sys_error("ERROR: wrong EDAT header signature!\n"); } uint32_t key_index = get32le(key_header + 4); uint32_t drm_type = get32le(key_header + 8); if (key_index != 1 || drm_type != 1) { sys_error("ERROR: unsupported EDAT file, key/drm type is wrong!\n"); } uint8_t mac[16]; aes128_cmac(kirk7_key38, key_header, 0x70, mac); aes128_key psp_key; uint8_t psp_iv[16]; init_psp_decrypt(&psp_key, psp_iv, 0, mac, key_header, 0x70, 0x10); aes128_psp_decrypt(&psp_key, psp_iv, 0, key_header + 0x30, 0x30); uint32_t data_size = get32le(key_header + 0x44); uint32_t data_offset = get32le(key_header + 0x4c); if (data_offset != 0x90) { sys_error("ERROR: unsupported EDAT file, data offset is wrong!\n"); } init_psp_decrypt(&psp_key, psp_iv, 0, mac, key_header, 0x70, 0x30); uint32_t block_size = 0x10; uint32_t block_count = ((data_size + (block_size - 1)) / block_size ); out_begin_file(path, 0); for (uint32_t i = 0; i < block_count; i++) { uint8_t block[0x10]; uint32_t block_offset = (data_offset + (i * block_size)); sys_read(pkg, enc_offset + item_offset + key_header_offset + block_offset, block, block_size); aes128_ctr_xor(pkg_key, pkg_iv, (item_offset + key_header_offset + block_offset) / 16, block, block_size); aes128_psp_decrypt(&psp_key, psp_iv, i * block_size / 16, block, block_size); uint32_t out_size = 0x10; if ( ((i + 1) * block_size) > data_size ) { out_size = data_size - (i * block_size); } out_write(block, out_size); } out_end_file(); } void unpack_keys_bin(const char* path, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset, uint64_t item_size) { if (item_size < 0x28 + 0x10 + 0x1f0) { sys_error("ERROR: EBOOT file is to short!\n"); } uint8_t eboot_header[0x28]; sys_read(pkg, enc_offset + item_offset, eboot_header, sizeof(eboot_header)); aes128_ctr_xor(pkg_key, pkg_iv, item_offset / 16, eboot_header, sizeof(eboot_header)); if (memcmp(eboot_header, "\x00PBP", 4) != 0) { sys_error("ERROR: wrong eboot header signature!\n"); } uint32_t psar_offset = get32le(eboot_header + 0x24); if (psar_offset + 16 > item_size) { sys_error("ERROR: eboot file is to short!\n"); } assert(psar_offset % 16 == 0); uint8_t psar_header[16]; sys_read(pkg, enc_offset + item_offset + psar_offset, psar_header, sizeof(psar_header)); aes128_ctr_xor(pkg_key, pkg_iv, (item_offset + psar_offset) / 16, psar_header, sizeof(psar_header)); uint32_t key_header_offset = 0; if (memcmp(psar_header, "PSTITLE", 7) == 0) { key_header_offset = 0x1f0; } else if (memcmp(psar_header, "PSISO", 5) == 0) { key_header_offset = 0x3f0; } else { sys_error("ERROR: wrong psar header signature!\n"); } uint8_t key_header[0x90]; sys_read(pkg, enc_offset + item_offset + psar_offset+ 16 + key_header_offset, key_header, sizeof(key_header)); aes128_ctr_xor(pkg_key, pkg_iv, (item_offset + psar_offset + 16 + key_header_offset) / 16, key_header, sizeof(key_header)); if (memcmp(key_header, "\x00PGD", 4) != 0) { sys_error("ERROR: wrong key header signature!\n"); } uint32_t key_index = get32le(key_header + 4); uint32_t drm_type = get32le(key_header + 8); if (key_index != 1 || drm_type != 1) { sys_error("ERROR: unsupported EBOOT file, key/drm type is unsupported!\n"); } uint8_t mac[16]; aes128_cmac(kirk7_key38, key_header, 0x70, mac); uint8_t keys_bin[16]; init_psx_keys(keys_bin, mac, key_header, 0x70); out_begin_file(path, 0); out_write(keys_bin, sizeof(keys_bin)); out_end_file(); } void get_psp_theme_title(char* title, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset) { uint8_t item_header[90]; sys_read(pkg, enc_offset + item_offset, item_header, sizeof(item_header)); aes128_ctr_xor(pkg_key, pkg_iv, (item_offset) / 16, item_header, sizeof(item_header)); uint8_t key_header_offset = item_header[0xC]; uint8_t key_header[0xa0]; sys_read(pkg, enc_offset + item_offset + key_header_offset, key_header, sizeof(key_header)); aes128_ctr_xor(pkg_key, pkg_iv, (item_offset + key_header_offset) / 16, key_header, sizeof(key_header)); if (memcmp(key_header, "\x00PGD", 4) != 0) { sys_error("ERROR: wrong EDAT header signature!\n"); } uint32_t key_index = get32le(key_header + 4); uint32_t drm_type = get32le(key_header + 8); if (key_index != 1 || drm_type != 1) { sys_error("ERROR: unsupported EDAT file, key/drm type is wrong!\n"); } uint8_t mac[16]; aes128_cmac(kirk7_key38, key_header, 0x70, mac); aes128_key psp_key; uint8_t psp_iv[16]; init_psp_decrypt(&psp_key, psp_iv, 0, mac, key_header, 0x70, 0x10); aes128_psp_decrypt(&psp_key, psp_iv, 0, key_header + 0x30, 0x30); uint32_t data_offset = get32le(key_header + 0x4c); uint8_t theme_header[256]; sys_read(pkg, enc_offset + item_offset + key_header_offset + data_offset, theme_header, sizeof(theme_header)); aes128_ctr_xor(pkg_key, pkg_iv, (item_offset + key_header_offset + data_offset)/ 16, theme_header, sizeof(theme_header)); init_psp_decrypt(&psp_key, psp_iv, 0, mac, key_header, 0x70, 0x30); aes128_psp_decrypt(&psp_key, psp_iv, 0, theme_header, sizeof(theme_header)); if (memcmp(theme_header, "\x00PTF", 4) != 0) { sys_error("ERROR: wrong PTF header signature!\n"); } memcpy(title,theme_header+8, 128); title[128]=0; } 07070100000012000081A4000001ED0000006B000000015EE6501B0000036F000000000000000000000000000000000000003900000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_psp.h#include "pkg2zip_aes.h" #include "pkg2zip_sys.h" void unpack_psp_eboot(const char* path, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset, uint64_t item_size, int cso); void unpack_psp_key(const char* path, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset, uint64_t item_size); void unpack_psp_edat(const char* path, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset, uint64_t item_size); void unpack_keys_bin(const char* path, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset, uint64_t item_size); void get_psp_theme_title(char* title, const aes128_key* pkg_key, const uint8_t* pkg_iv, sys_file* pkg, uint64_t enc_offset, uint64_t item_offset); 07070100000013000081A4000001ED0000006B000000015EE6501B00001DEC000000000000000000000000000000000000003900000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_sys.c#include "pkg2zip_sys.h" #include "pkg2zip_utils.h" #include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdarg.h> #include <sys/stat.h> #include <errno.h> #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #include <windows.h> static HANDLE gStdout; static int gStdoutRedirected; static UINT gOldCP; void sys_output_init(void) { gOldCP = GetConsoleOutputCP(); SetConsoleOutputCP(CP_UTF8); gStdout = GetStdHandle(STD_OUTPUT_HANDLE); DWORD mode; gStdoutRedirected = !GetConsoleMode(gStdout, &mode); } void sys_output_done(void) { SetConsoleOutputCP(gOldCP); } void sys_output(const char* msg, ...) { char buffer[1024]; va_list arg; va_start(arg, msg); vsnprintf(buffer, sizeof(buffer), msg, arg); va_end(arg); if (!gStdoutRedirected) { WCHAR wbuffer[sizeof(buffer)]; int wcount = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, wbuffer, sizeof(buffer)); DWORD written; WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), wbuffer, wcount - 1, &written, NULL); return; } fputs(buffer, stdout); } void sys_error(const char* msg, ...) { char buffer[1024]; va_list arg; va_start(arg, msg); vsnprintf(buffer, sizeof(buffer), msg, arg); va_end(arg); DWORD mode; if (GetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), &mode)) { WCHAR wbuffer[sizeof(buffer)]; int wcount = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, wbuffer, sizeof(buffer)); DWORD written; WriteConsoleW(GetStdHandle(STD_ERROR_HANDLE), wbuffer, wcount - 1, &written, NULL); } else { fputs(buffer, stderr); } SetConsoleOutputCP(gOldCP); exit(EXIT_FAILURE); } static void sys_mkdir_real(const char* path) { WCHAR wpath[MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH); if (CreateDirectoryW(wpath, NULL) == 0) { if (GetLastError() != ERROR_ALREADY_EXISTS) { sys_error("ERROR: cannot create '%s' folder\n", path); } } } sys_file sys_open(const char* fname, uint64_t* size) { WCHAR path[MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, fname, -1, path, MAX_PATH); HANDLE handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (handle == INVALID_HANDLE_VALUE) { sys_error("ERROR: cannot open '%s' file\n", fname); } LARGE_INTEGER sz; if (!GetFileSizeEx(handle, &sz)) { sys_error("ERROR: cannot get size of '%s' file\n", fname); } *size = sz.QuadPart; return handle; } sys_file sys_create(const char* fname) { WCHAR path[MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, fname, -1, path, MAX_PATH); HANDLE handle = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if (handle == INVALID_HANDLE_VALUE) { sys_error("ERROR:1: cannot create '%s' file\n", fname); } return handle; } void sys_close(sys_file file) { if (!CloseHandle(file)) { sys_error("ERROR: failed to close file\n"); } } void sys_read(sys_file file, uint64_t offset, void* buffer, uint32_t size) { DWORD read; OVERLAPPED ov; ov.hEvent = NULL; ov.Offset = (uint32_t)offset; ov.OffsetHigh = (uint32_t)(offset >> 32); if (!ReadFile(file, buffer, size, &read, &ov) || read != size) { sys_error("ERROR: failed to read %u bytes from file\n", size); } } void sys_write(sys_file file, uint64_t offset, const void* buffer, uint32_t size) { DWORD written; OVERLAPPED ov; ov.hEvent = NULL; ov.Offset = (uint32_t)offset; ov.OffsetHigh = (uint32_t)(offset >> 32); if (!WriteFile(file, buffer, size, &written, &ov) || written != size) { sys_error("ERROR: failed to write %u bytes to file\n", size); } } #else #define _FILE_OFFSET_BITS 64 #include <stdio.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <sys/stat.h> static int gStdoutRedirected; void sys_output_init(void) { gStdoutRedirected = !isatty(STDOUT_FILENO); } void sys_output_done(void) { } void sys_output(const char* msg, ...) { va_list arg; va_start(arg, msg); vfprintf(stdout, msg, arg); va_end(arg); } void sys_error(const char* msg, ...) { va_list arg; va_start(arg, msg); vfprintf(stderr, msg, arg); va_end(arg); exit(EXIT_FAILURE); } static void sys_mkdir_real(const char* path) { if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) { if (errno != EEXIST) { sys_error("ERROR: cannot create '%s' folder\n", path); } } } sys_file sys_open(const char* fname, uint64_t* size) { int fd = open(fname, O_RDONLY); if (fd < 0) { sys_error("ERROR: cannot open '%s' file\n", fname); } struct stat st; if (fstat(fd, &st) != 0) { sys_error("ERROR: cannot get size of '%s' file\n", fname); } *size = st.st_size; return (void*)(intptr_t)fd; } sys_file sys_create(const char* fname) { int fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { sys_error("ERROR:2: cannot create '%s' file\n", fname); } return (void*)(intptr_t)fd; } void sys_close(sys_file file) { if (close((int)(intptr_t)file) != 0) { sys_error("ERROR: failed to close file\n"); } } void sys_read(sys_file file, uint64_t offset, void* buffer, uint32_t size) { ssize_t read = pread((int)(intptr_t)file, buffer, size, offset); if (read < 0 || read != (ssize_t)size) { sys_error("ERROR: failed to read %u bytes from file\n", size); } } void sys_write(sys_file file, uint64_t offset, const void* buffer, uint32_t size) { ssize_t wrote = pwrite((int)(intptr_t)file, buffer, size, offset); if (wrote < 0 || wrote != (ssize_t)size) { sys_error("ERROR: failed to read %u bytes from file\n", size); } } #endif void sys_mkdir(const char* path) { char* last = strrchr(path, '/'); if (last) { *last = 0; sys_mkdir(path); *last = '/'; } sys_mkdir_real(path); } void* sys_realloc(void* ptr, size_t size) { void* result = NULL; if (!ptr && size) { result = malloc(size); } else if (ptr && !size) { free(ptr); return NULL; } else if (ptr && size) { result = realloc(ptr, size); } else { sys_error("ERROR: internal error, wrong sys_realloc usage\n"); } if (!result) { sys_error("ERROR: out of memory\n"); } return result; } void sys_vstrncat(char* dst, size_t n, const char* format, ...) { char temp[1024]; va_list args; va_start(args, format); vsnprintf(temp, sizeof(temp), format, args); va_end(args); strncat(dst, temp, n - strlen(dst) - 1); } static uint64_t out_size; static uint32_t out_next; void sys_output_progress_init(uint64_t size) { out_size = size; out_next = 0; } void sys_output_progress(uint64_t progress) { if (gStdoutRedirected) { return; } uint32_t now = (uint32_t)(progress * 100 / out_size); if (now >= out_next) { sys_output("[*] unpacking... %u%%\r", now); out_next = now + 1; } } int sys_test_dir(const char* const path) { struct stat info; int statRC = stat( path, &info ); if( statRC != 0 ) { if (errno == ENOENT) { return 0; } if (errno == ENOTDIR) { return 0; } return -1; } return ( info.st_mode & S_IFDIR ) ? 1 : 0; } 07070100000014000081A4000001ED0000006B000000015EE6501B0000037B000000000000000000000000000000000000003900000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_sys.h#pragma once #include "pkg2zip_utils.h" // correctly outputs utf8 string void sys_output_init(void); void sys_output_done(void); void sys_output(const char* msg, ...); void NORETURN sys_error(const char* msg, ...); void sys_output_progress_init(uint64_t size); void sys_output_progress(uint64_t progress); typedef void* sys_file; void sys_mkdir(const char* path); sys_file sys_open(const char* fname, uint64_t* size); sys_file sys_create(const char* fname); void sys_close(sys_file file); void sys_read(sys_file file, uint64_t offset, void* buffer, uint32_t size); void sys_write(sys_file file, uint64_t offset, const void* buffer, uint32_t size); // if !ptr && size => malloc // if ptr && !size => free // if ptr && size => realloc void* sys_realloc(void* ptr, size_t size); void sys_vstrncat(char* dst, size_t n, const char* format, ...); int sys_test_dir(const char* const path);07070100000015000081A4000001ED0000006B000000015EE6501B00000B4A000000000000000000000000000000000000003B00000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_utils.h#pragma once #include <stdint.h> #include <stddef.h> #if defined(_MSC_VER) # define NORETURN __declspec(noreturn) # define PKG_ALIGN(x) __declspec(align(x)) #else # define NORETURN __attribute__((noreturn)) # define PKG_ALIGN(x) __attribute__((aligned(x))) #endif static inline uint32_t min32(uint32_t a, uint32_t b) { return a < b ? a : b; } static inline uint64_t min64(uint64_t a, uint64_t b) { return a < b ? a : b; } static inline uint16_t get16le(const uint8_t* bytes) { return (bytes[0]) | (bytes[1] << 8); } static inline uint32_t get32le(const uint8_t* bytes) { return (bytes[0]) | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); } static inline uint64_t get64le(const uint8_t* bytes) { return (uint64_t)bytes[0] | ((uint64_t)bytes[1] << 8) | ((uint64_t)bytes[2] << 16) | ((uint64_t)bytes[3] << 24) | ((uint64_t)bytes[4] << 32) | ((uint64_t)bytes[5] << 40) | ((uint64_t)bytes[6] << 48) | ((uint64_t)bytes[7] << 56); } static inline uint16_t get16be(const uint8_t* bytes) { return (bytes[1]) | (bytes[0] << 8); } static inline uint32_t get32be(const uint8_t* bytes) { return (bytes[3]) | (bytes[2] << 8) | (bytes[1] << 16) | (bytes[0] << 24); } static inline uint64_t get64be(const uint8_t* bytes) { return (uint64_t)bytes[7] | ((uint64_t)bytes[6] << 8) | ((uint64_t)bytes[5] << 16) | ((uint64_t)bytes[4] << 24) | ((uint64_t)bytes[3] << 32) | ((uint64_t)bytes[2] << 40) | ((uint64_t)bytes[1] << 48) | ((uint64_t)bytes[0] << 56); } static inline void set16le(uint8_t* bytes, uint16_t x) { bytes[0] = (uint8_t)x; bytes[1] = (uint8_t)(x >> 8); } static inline void set32le(uint8_t* bytes, uint32_t x) { bytes[0] = (uint8_t)x; bytes[1] = (uint8_t)(x >> 8); bytes[2] = (uint8_t)(x >> 16); bytes[3] = (uint8_t)(x >> 24); } static inline void set64le(uint8_t* bytes, uint64_t x) { bytes[0] = (uint8_t)x; bytes[1] = (uint8_t)(x >> 8); bytes[2] = (uint8_t)(x >> 16); bytes[3] = (uint8_t)(x >> 24); bytes[4] = (uint8_t)(x >> 32); bytes[5] = (uint8_t)(x >> 40); bytes[6] = (uint8_t)(x >> 48); bytes[7] = (uint8_t)(x >> 56); } static inline void set16be(uint8_t* bytes, uint16_t x) { bytes[0] = (uint8_t)(x >> 8); bytes[1] = (uint8_t)x; } static inline void set32be(uint8_t* bytes, uint32_t x) { bytes[0] = (uint8_t)(x >> 24); bytes[1] = (uint8_t)(x >> 16); bytes[2] = (uint8_t)(x >> 8); bytes[3] = (uint8_t)x; } static inline void set64be(uint8_t* bytes, uint64_t x) { bytes[0] = (uint8_t)(x >> 56); bytes[1] = (uint8_t)(x >> 48); bytes[2] = (uint8_t)(x >> 40); bytes[3] = (uint8_t)(x >> 32); bytes[4] = (uint8_t)(x >> 24); bytes[5] = (uint8_t)(x >> 16); bytes[6] = (uint8_t)(x >> 8); bytes[7] = (uint8_t)x; } 07070100000016000081A4000001ED0000006B000000015EE6501B00003291000000000000000000000000000000000000003900000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_zip.c#if defined(__MINGW32__) && !defined(__x86_64__) # define _USE_32BIT_TIME_T # define __CRT__NO_INLINE #endif #include "pkg2zip_zip.h" #include "pkg2zip_out.h" #include "pkg2zip_crc32.h" #include "pkg2zip_utils.h" #include <string.h> #include <time.h> #define ZIP_MEMORY_BLOCK (1024 * 1024) // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT #define ZIP_VERSION 45 #define ZIP_METHOD_STORE 0 #define ZIP_METHOD_DEFLATE 8 #define ZIP_UTF8_FLAG (1 << 11) #define ZIP_DOS_ATTRIBUTE_DIRECTORY 0x10 #define ZIP_DOS_ATTRIBUTE_ARCHIVE 0x20 #define ZIP_LOCAL_HEADER_SIZE 30 #define ZIP_GLOBAL_HEADER_SIZE 46 #define ZIP64_EOC_DIR_SIZE 56 #define ZIP64_EOC_DIR_LOCATOR_SIZE 20 #define ZIP_EOC_DIR_SIZE 22 #define ZIP_LOCAL_HEADER_CRC32_OFFSET 14 #define ZIP_LOCAL_HEADER_FILENAME_LENGTH_OFFSET 26 struct zip_file { uint64_t offset; uint64_t size; uint64_t compressed; uint32_t crc32; int compress; }; static zip_file* zip_new_file(zip* z) { if (z->count == z->max) { z->allocated += ZIP_MEMORY_BLOCK; z->files = sys_realloc(z->files, z->allocated); z->max = z->allocated / sizeof(zip_file); } return z->files + z->count++; } void zip_create(zip* z, const char* name) { z->file = sys_create(name); z->total = 0; z->count = 0; z->max = 0; z->allocated = 0; z->files = NULL; z->current = NULL; time_t t = time(NULL); struct tm* tm = localtime(&t); z->date = (uint16_t)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); z->time = (uint16_t)((tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2)); } void zip_add_folder(zip* z, const char* name) { size_t name_length = strlen(name) + 1; if (name_length > ZIP_MAX_FILENAME) { sys_error("ERROR: dirname too long\n"); } zip_file* f = zip_new_file(z); f->offset = z->total; f->size = 0; f->compressed = 0; f->crc32 = 0; f->compress = 0; uint8_t header[ZIP_LOCAL_HEADER_SIZE] = { 0x50, 0x4b, 0x03, 0x04 }; // version needed to extract set16le(header + 4, ZIP_VERSION); // general purpose bit flag set16le(header + 6, ZIP_UTF8_FLAG); // compression method set16le(header + 8, ZIP_METHOD_STORE); // last mod file time set16le(header + 10, z->time); // last mod file date set16le(header + 12, z->date); // file name length set16le(header + 26, (uint16_t)name_length); sys_write(z->file, z->total, header, sizeof(header)); z->total += sizeof(header); sys_write(z->file, z->total, name, (uint16_t)name_length); z->total += name_length - 1; char slash = '/'; sys_write(z->file, z->total, &slash, 1); z->total += 1; } uint64_t zip_begin_file(zip* z, const char* name, int compress) { size_t name_length = strlen(name); if (name_length > ZIP_MAX_FILENAME) { sys_error("ERROR: filename too long\n"); } zip_file* f = zip_new_file(z); f->offset = z->total; f->size = 0; f->compressed = 0; f->compress = compress; z->current = f; crc32_init(&z->crc32); z->crc32_set = 0; uint8_t header[ZIP_LOCAL_HEADER_SIZE] = { 0x50, 0x4b, 0x03, 0x04 }; // version needed to extract set16le(header + 4, ZIP_VERSION); // general purpose bit flag set16le(header + 6, ZIP_UTF8_FLAG); // compression method set16le(header + 8, compress ? ZIP_METHOD_DEFLATE : ZIP_METHOD_STORE); // last mod file time set16le(header + 10, z->time); // last mod file date set16le(header + 12, z->date); // file name length set16le(header + 26, (uint16_t)name_length); sys_write(z->file, z->total, header, sizeof(header)); z->total += sizeof(header); sys_write(z->file, z->total, name, (uint16_t)name_length); z->total += name_length; if (compress) { int flags = tdefl_create_comp_flags_from_zip_params(MZ_BEST_SPEED, -MZ_DEFAULT_WINDOW_BITS, MZ_DEFAULT_STRATEGY); tdefl_init(&z->tdefl, flags); } return z->total - f->offset; } void zip_write_file(zip* z, const void* data, uint32_t size) { z->current->size += size; crc32_update(&z->crc32, data, size); if (z->current->compress) { const uint8_t* data8 = data; while (size != 0) { uint8_t buffer[4096]; size_t isize = size; size_t osize = sizeof(buffer); tdefl_compress(&z->tdefl, data8, &isize, buffer, &osize, TDEFL_NO_FLUSH); if (osize != 0) { sys_write(z->file, z->total, buffer, (uint32_t)osize); z->current->compressed += osize; z->total += osize; } data8 += isize; size -= (uint32_t)isize; } } else { sys_write(z->file, z->total, data, size); z->current->compressed += size; z->total += size; } } void zip_end_file(zip* z) { if (z->current->compress) { for (;;) { uint8_t buffer[4096]; size_t isize = 0; size_t osize = sizeof(buffer); tdefl_status st = tdefl_compress(&z->tdefl, NULL, &isize, buffer, &osize, TDEFL_FINISH); if (osize != 0) { sys_write(z->file, z->total, buffer, (uint32_t)osize); z->current->compressed += osize; z->total += osize; } if (st == TDEFL_STATUS_DONE) { break; } } } if (!z->crc32_set) { z->current->crc32 = crc32_done(&z->crc32); } if (z->current->size != 0) { uint8_t update[3 * sizeof(uint32_t)]; // crc-32 set32le(update + 0, z->current->crc32); // compressed size set32le(update + 4, (uint32_t)min64(z->current->compressed, 0xffffffff)); // uncompressed size set32le(update + 8, (uint32_t)min64(z->current->size, 0xffffffff)); sys_write(z->file, z->current->offset + ZIP_LOCAL_HEADER_CRC32_OFFSET, update, sizeof(update)); } z->current = NULL; } void zip_close(zip* z) { uint64_t central_dir_offset = z->total; // central directory headers for (uint32_t i = 0; i < z->count; i++) { const zip_file* f = z->files + i; uint8_t local[ZIP_LOCAL_HEADER_SIZE]; sys_read(z->file, f->offset, local, sizeof(local)); uint32_t filename_length = get16le(local + ZIP_LOCAL_HEADER_FILENAME_LENGTH_OFFSET); uint8_t global[ZIP_GLOBAL_HEADER_SIZE + ZIP_MAX_FILENAME] = { 0x50, 0x4b, 0x01, 0x02 }; sys_read(z->file, f->offset + sizeof(local), global + ZIP_GLOBAL_HEADER_SIZE, filename_length); int is_folder = global[ZIP_GLOBAL_HEADER_SIZE + filename_length - 1] == '/'; uint8_t extra[28]; uint16_t extra_size = 0; uint64_t size = f->size; uint64_t compressed = f->compressed; uint64_t offset = f->offset; uint32_t attributes = ZIP_DOS_ATTRIBUTE_ARCHIVE; if (is_folder) { attributes |= ZIP_DOS_ATTRIBUTE_DIRECTORY; if (offset > 0xffffffff) { extra_size += sizeof(uint64_t); } } else { if (size > 0xffffffff) { extra_size += sizeof(uint64_t); } if (compressed > 0xffffffff) { extra_size += sizeof(uint64_t); } if (offset > 0xffffffff) { extra_size += sizeof(uint64_t); } } if (extra_size) { extra_size += 2 * sizeof(uint16_t); } // version made by set16le(global + 4, ZIP_VERSION); // version needed to extract set16le(global + 6, ZIP_VERSION); // general purpose bit flag set16le(global + 8, ZIP_UTF8_FLAG); // compression method set16le(global + 10, f->compress ? ZIP_METHOD_DEFLATE : ZIP_METHOD_STORE); // last mod file time set16le(global + 12, z->time); // last mod file date set16le(global + 14, z->date); // crc-32 set32le(global + 16, f->crc32); // compressed size set32le(global + 20, (uint32_t)min64(compressed, 0xffffffff)); // uncompressed size set32le(global + 24, (uint32_t)min64(size, 0xffffffff)); // file name length set16le(global + 28, (uint16_t)filename_length); // extra field length set16le(global + 30, extra_size); // external file attributes set32le(global + 38, attributes); // relative offset of local header 4 bytes set32le(global + 42, (uint32_t)min64(offset, 0xffffffff)); sys_write(z->file, z->total, global, ZIP_GLOBAL_HEADER_SIZE + filename_length); z->total += ZIP_GLOBAL_HEADER_SIZE + filename_length; // zip64 Extended Information Extra Field set16le(extra + 0, 1); // size of this "extra" block uint32_t extra_offset = 2 * sizeof(uint16_t); set16le(extra + 2, (uint16_t)(extra_size - extra_offset)); if (compressed > 0xffffffff) { // size of compressed data set64le(extra + extra_offset, compressed); extra_offset += sizeof(uint64_t); } if (size > 0xffffffff) { // original uncompressed file size set64le(extra + extra_offset, size); extra_offset += sizeof(uint64_t); } if (offset > 0xffffffff) { // offset of local header record set64le(extra + extra_offset, offset); extra_offset += sizeof(uint64_t); } if (extra_size > 2 * sizeof(uint16_t)) { sys_write(z->file, z->total, extra, extra_size); z->total += extra_size; } } uint64_t end_of_central_dir_offset = z->total; uint64_t central_dir_size = end_of_central_dir_offset - central_dir_offset; // zip64 end of central directory record { uint8_t header[ZIP64_EOC_DIR_SIZE] = { 0x50, 0x4b, 0x06, 0x06 }; // size of zip64 end of central directory record set64le(header + 4, sizeof(header) - sizeof(uint32_t) - sizeof(uint64_t)); // version made by set16le(header + 12, ZIP_VERSION); // version needed to extract set16le(header + 14, ZIP_VERSION); // total number of entries in the central directory on this disk set64le(header + 24, z->count); // total number of entries in the central directory set64le(header + 32, z->count); // size of the central directory set64le(header + 40, central_dir_size); // offset of start of central directory with respect to the starting disk number set64le(header + 48, central_dir_offset); sys_write(z->file, z->total, header, sizeof(header)); z->total += sizeof(header); } // zip64 end of central directory locator { uint8_t header[ZIP64_EOC_DIR_LOCATOR_SIZE] = { 0x50, 0x4b, 0x06, 0x07 }; // relative offset of the zip64 end of central directory record 8 bytes set64le(header + 8, end_of_central_dir_offset); // total number of disks set32le(header + 16, 1); sys_write(z->file, z->total, header, sizeof(header)); z->total += sizeof(header); } // end of central directory record { uint8_t header[ZIP_EOC_DIR_SIZE] = { 0x50, 0x4b, 0x05, 0x06 }; // total number of entries in the central directory on this disk set16le(header + 8, (uint16_t)min32(z->count, 0xffff)); // total number of entries in the central directory set16le(header + 10, (uint16_t)min32(z->count, 0xffff)); // size of the central directory set32le(header + 12, (uint32_t)min64(central_dir_size, 0xffffffff)); // offset of start of central directory with respect to the starting disk number set32le(header + 16, (uint32_t)min64(central_dir_offset, 0xffffffff)); sys_write(z->file, z->total, header, sizeof(header)); z->total += sizeof(header); } sys_close(z->file); sys_realloc(z->files, 0); } void zip_write_file_at(zip* z, uint64_t offset, const void* data, uint32_t size) { if (z->current->compress) { sys_error("ERROR: cannot write at specific offset for compressed files\n"); } sys_write(z->file, z->current->offset + offset, data, size); z->current->size += size; z->current->compressed += size; } void zip_set_offset(zip* z, uint64_t offset) { z->total = z->current->offset + offset; } void zip_set_crc32(zip* z, uint32_t crc) { z->current->crc32 = crc; z->crc32_set = 1; } uint32_t zip_get_crc32(zip* z) { return crc32_done(&z->crc32); } 07070100000017000081A4000001ED0000006B000000015EE6501B00000405000000000000000000000000000000000000003900000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_zip.h#pragma once #include "pkg2zip_sys.h" #include "pkg2zip_crc32.h" #include "miniz_tdef.h" #include <stddef.h> #include <stdint.h> #define ZIP_MAX_FILENAME 1024 typedef struct zip_file zip_file; typedef struct { sys_file file; uint64_t total; uint32_t count; uint32_t max; uint16_t time; uint16_t date; tdefl_compressor tdefl; crc32_ctx crc32; int crc32_set; uint32_t allocated; // bytes zip_file* files; zip_file* current; } zip; void zip_create(zip* z, const char* name); void zip_add_folder(zip* z, const char* name); uint64_t zip_begin_file(zip* z, const char* name, int compress); void zip_write_file(zip* z, const void* data, uint32_t size); void zip_end_file(zip* z); void zip_close(zip* z); // hacky solution to be able to write cso header after the data is written void zip_write_file_at(zip* z, uint64_t offset, const void* data, uint32_t size); void zip_set_offset(zip* z, uint64_t offset); void zip_set_crc32(zip* z, uint32_t crc); uint32_t zip_get_crc32(zip* z); 07070100000018000081A4000001ED0000006B000000015EE6501B00001CAD000000000000000000000000000000000000003A00000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_zrif.c#include "pkg2zip_zrif.h" #include "pkg2zip_utils.h" #include "pkg2zip_sys.h" #include "miniz_tdef.h" #include "puff.h" #include <assert.h> #include <string.h> #define ADLER32_MOD 65521 #define ZLIB_DEFLATE_METHOD 8 #define ZLIB_DICTIONARY_ID_ZRIF 0x627d1d5d static const uint8_t zrif_dict[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 54, 48, 48, 48, 48, 55, 48, 48, 48, 48, 56, 0, 48, 48, 48, 48, 51, 48, 48, 48, 48, 52, 48, 48, 48, 48, 53, 48, 95, 48, 48, 45, 65, 68, 68, 67, 79, 78, 84, 48, 48, 48, 48, 50, 45, 80, 67, 83, 71, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 45, 80, 67, 83, 69, 48, 48, 48, 45, 80, 67, 83, 70, 48, 48, 48, 45, 80, 67, 83, 67, 48, 48, 48, 45, 80, 67, 83, 68, 48, 48, 48, 45, 80, 67, 83, 65, 48, 48, 48, 45, 80, 67, 83, 66, 48, 48, 48, 0, 1, 0, 1, 0, 1, 0, 2, 239, 205, 171, 137, 103, 69, 35, 1, }; static const uint8_t b64d[] = { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, }; static uint32_t base64_decode(const char* in, uint8_t* out) { const uint8_t* out0 = out; const uint8_t* in8 = (uint8_t*)in; size_t len = strlen(in); if (in[len - 1] == '=') { len--; } if (in[len - 1] == '=') { len--; } for (size_t i = 0; i < len / 4; i++) { *out++ = (b64d[in8[0]] << 2) + ((b64d[in8[1]] & 0x30) >> 4); *out++ = (b64d[in8[1]] << 4) + (b64d[in8[2]] >> 2); *out++ = (b64d[in8[2]] << 6) + b64d[in8[3]]; in8 += 4; } size_t left = len % 4; if (left == 2) { *out++ = (b64d[in8[0]] << 2) + ((b64d[in8[1]] & 0x30) >> 4); *out++ = (b64d[in8[1]] << 4); } else if (left == 3) { *out++ = (b64d[in8[0]] << 2) + ((b64d[in8[1]] & 0x30) >> 4); *out++ = (b64d[in8[1]] << 4) + (b64d[in8[2]] >> 2); *out++ = b64d[in8[2]] << 6; } return (uint32_t)(out - out0); } // https://www.ietf.org/rfc/rfc1950.txt static uint32_t zlib_inflate(const uint8_t* in, uint32_t inlen, uint8_t* out, uint32_t outlen) { if (inlen < 2 + 4) { sys_error("ERROR: zRIF length too short\n"); } if (((in[0] << 8) + in[1]) % 31 != 0) { sys_error("ERROR: zRIF header is corrupted\n"); } if ((in[0] & 0xf) != ZLIB_DEFLATE_METHOD) { sys_error("ERROR: only deflate method supported in zRIF\n"); } unsigned long slen = inlen - 4; unsigned long dlen = outlen; unsigned long dictlen = 0; if (in[1] & (1 << 5)) { assert(outlen > sizeof(zrif_dict)); memcpy(out, zrif_dict, sizeof(zrif_dict)); dictlen = sizeof(zrif_dict); if (get32be(in + 2) != ZLIB_DICTIONARY_ID_ZRIF) { sys_error("ERROR: zRIF uses unknown dictionary\n"); } in += 6; slen -= 6; } else { in += 2; slen -= 2; } if (puff(dictlen, out, &dlen, in, &slen) != 0) { sys_error("ERROR: failed to uncompress zRIF\n"); } memmove(out, out + dictlen, dlen); if (mz_adler32(MZ_ADLER32_INIT, out, dlen) != get32be(in + slen)) { sys_error("ERROR: zRIF is corrupted, wrong checksum\n"); } return dlen; } void zrif_decode(const char* str, uint8_t* rif, uint32_t rif_size) { uint8_t raw[1024]; uint32_t len = base64_decode(str, raw); uint8_t out[sizeof(zrif_dict) + 1024]; len = zlib_inflate(raw, len, out, sizeof(out)); if (len != rif_size) { sys_error("ERROR: wrong size of zRIF, is it corrupted?\n"); } memcpy(rif, out, rif_size); } 07070100000019000081A4000001ED0000006B000000015EE6501B00000067000000000000000000000000000000000000003A00000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/pkg2zip_zrif.h#pragma once #include <stdint.h> void zrif_decode(const char* str, uint8_t* rif, uint32_t rif_size); 0707010000001A000081A4000001ED0000006B000000015EE6501B00003F9D000000000000000000000000000000000000003200000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/puff.c/* * puff.c * Copyright (C) 2002-2013 Mark Adler * For conditions of distribution and use, see copyright notice in puff.h * version 2.3, 21 Jan 2013 */ #include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */ #include "puff.h" /* prototype for puff() */ #define local static /* for local function definitions */ #define MAXBITS 15 /* maximum bits in a code */ #define MAXLCODES 286 /* maximum number of literal/length codes */ #define MAXDCODES 30 /* maximum number of distance codes */ #define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */ #define FIXLCODES 288 /* number of fixed literal/length codes */ /* input and output state */ struct state { /* output state */ unsigned char *out; /* output buffer */ unsigned long outlen; /* available space at out */ unsigned long outcnt; /* bytes written to out so far */ /* input state */ const unsigned char *in; /* input buffer */ unsigned long inlen; /* available input at in */ unsigned long incnt; /* bytes read so far */ int bitbuf; /* bit buffer */ int bitcnt; /* number of bits in bit buffer */ /* input limit error return state for bits() and decode() */ jmp_buf env; }; local int bits(struct state *s, int need) { long val; /* bit accumulator (can use up to 20 bits) */ /* load at least need bits into val */ val = s->bitbuf; while (s->bitcnt < need) { if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */ val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */ s->bitcnt += 8; } /* drop need bits and update buffer, always zero to seven bits left */ s->bitbuf = (int)(val >> need); s->bitcnt -= need; /* return need bits, zeroing the bits above that */ return (int)(val & ((1L << need) - 1)); } local int stored(struct state *s) { unsigned len; /* length of stored block */ /* discard leftover bits from current byte (assumes s->bitcnt < 8) */ s->bitbuf = 0; s->bitcnt = 0; /* get length and check against its one's complement */ if (s->incnt + 4 > s->inlen) return 2; /* not enough input */ len = s->in[s->incnt++]; len |= s->in[s->incnt++] << 8; if (s->in[s->incnt++] != (~len & 0xff) || s->in[s->incnt++] != ((~len >> 8) & 0xff)) return -2; /* didn't match complement! */ /* copy len bytes from in to out */ if (s->incnt + len > s->inlen) return 2; /* not enough input */ if (s->out != NIL) { if (s->outcnt + len > s->outlen) return 1; /* not enough output space */ while (len--) s->out[s->outcnt++] = s->in[s->incnt++]; } else { /* just scanning */ s->outcnt += len; s->incnt += len; } /* done with a valid stored block */ return 0; } struct huffman { short *count; /* number of symbols of each length */ short *symbol; /* canonically ordered symbols */ }; local int decode(struct state *s, const struct huffman *h) { int len; /* current number of bits in code */ int code; /* len bits being decoded */ int first; /* first code of length len */ int count; /* number of codes of length len */ int index; /* index of first code of length len in symbol table */ int bitbuf; /* bits from stream */ int left; /* bits left in next or left to process */ short *next; /* next number of codes */ bitbuf = s->bitbuf; left = s->bitcnt; code = first = index = 0; len = 1; next = h->count + 1; while (1) { while (left--) { code |= bitbuf & 1; bitbuf >>= 1; count = *next++; if (code - count < first) { /* if length len, return symbol */ s->bitbuf = bitbuf; s->bitcnt = (s->bitcnt - len) & 7; return h->symbol[index + (code - first)]; } index += count; /* else update for next length */ first += count; first <<= 1; code <<= 1; len++; } left = (MAXBITS+1) - len; if (left == 0) break; if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */ bitbuf = s->in[s->incnt++]; if (left > 8) left = 8; } return -10; /* ran out of codes */ } local int construct(struct huffman *h, const short *length, int n) { int symbol; /* current symbol when stepping through length[] */ int len; /* current length when stepping through h->count[] */ int left; /* number of possible codes left of current length */ short offs[MAXBITS+1]; /* offsets in symbol table for each length */ /* count number of codes of each length */ for (len = 0; len <= MAXBITS; len++) h->count[len] = 0; for (symbol = 0; symbol < n; symbol++) (h->count[length[symbol]])++; /* assumes lengths are within bounds */ if (h->count[0] == n) /* no codes! */ return 0; /* complete, but decode() will fail */ /* check for an over-subscribed or incomplete set of lengths */ left = 1; /* one possible code of zero length */ for (len = 1; len <= MAXBITS; len++) { left <<= 1; /* one more bit, double codes left */ left -= h->count[len]; /* deduct count from possible codes */ if (left < 0) return left; /* over-subscribed--return negative */ } /* left > 0 means incomplete */ /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h->count[len]; /* * put symbols in table sorted by length, by symbol order within each * length */ for (symbol = 0; symbol < n; symbol++) if (length[symbol] != 0) h->symbol[offs[length[symbol]]++] = (short)symbol; /* return zero for complete set, positive for incomplete set */ return left; } local int codes(struct state *s, const struct huffman *lencode, const struct huffman *distcode) { int symbol; /* decoded symbol */ int len; /* length for copy */ unsigned dist; /* distance for copy */ static const short lens[29] = { /* Size base for length codes 257..285 */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; static const short lext[29] = { /* Extra bits for length codes 257..285 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; static const short dists[30] = { /* Offset base for distance codes 0..29 */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; static const short dext[30] = { /* Extra bits for distance codes 0..29 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; /* decode literals and length/distance pairs */ do { symbol = decode(s, lencode); if (symbol < 0) return symbol; /* invalid symbol */ if (symbol < 256) { /* literal: symbol is the byte */ /* write out the literal */ if (s->out != NIL) { if (s->outcnt == s->outlen) return 1; s->out[s->outcnt] = (unsigned char)symbol; } s->outcnt++; } else if (symbol > 256) { /* length */ /* get and compute length */ symbol -= 257; if (symbol >= 29) return -10; /* invalid fixed code */ len = lens[symbol] + bits(s, lext[symbol]); /* get and check distance */ symbol = decode(s, distcode); if (symbol < 0) return symbol; /* invalid symbol */ dist = dists[symbol] + bits(s, dext[symbol]); #ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (dist > s->outcnt) return -11; /* distance too far back */ #endif /* copy length bytes from distance bytes back */ if (s->out != NIL) { if (s->outcnt + len > s->outlen) return 1; while (len--) { s->out[s->outcnt] = #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR dist > s->outcnt ? 0 : #endif s->out[s->outcnt - dist]; s->outcnt++; } } else s->outcnt += len; } } while (symbol != 256); /* end of block symbol */ /* done with a valid fixed or dynamic block */ return 0; } local int fixed(struct state *s) { static int virgin = 1; static short lencnt[MAXBITS+1], lensym[FIXLCODES]; static short distcnt[MAXBITS+1], distsym[MAXDCODES]; static struct huffman lencode, distcode; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { int symbol; short lengths[FIXLCODES]; /* construct lencode and distcode */ lencode.count = lencnt; lencode.symbol = lensym; distcode.count = distcnt; distcode.symbol = distsym; /* literal/length table */ for (symbol = 0; symbol < 144; symbol++) lengths[symbol] = 8; for (; symbol < 256; symbol++) lengths[symbol] = 9; for (; symbol < 280; symbol++) lengths[symbol] = 7; for (; symbol < FIXLCODES; symbol++) lengths[symbol] = 8; construct(&lencode, lengths, FIXLCODES); /* distance table */ for (symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5; construct(&distcode, lengths, MAXDCODES); /* do this just once */ virgin = 0; } /* decode data until end-of-block code */ return codes(s, &lencode, &distcode); } local int dynamic(struct state *s) { int nlen, ndist, ncode; /* number of lengths in descriptor */ int index; /* index of lengths[] */ int err; /* construct() return value */ short lengths[MAXCODES]; /* descriptor code lengths */ short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */ short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */ struct huffman lencode, distcode; /* length and distance codes */ static const short order[19] = /* permutation of code length codes */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* construct lencode and distcode */ lencode.count = lencnt; lencode.symbol = lensym; distcode.count = distcnt; distcode.symbol = distsym; /* get number of lengths in each table, check lengths */ nlen = bits(s, 5) + 257; ndist = bits(s, 5) + 1; ncode = bits(s, 4) + 4; if (nlen > MAXLCODES || ndist > MAXDCODES) return -3; /* bad counts */ /* read code length code lengths (really), missing lengths are zero */ for (index = 0; index < ncode; index++) lengths[order[index]] = (short)bits(s, 3); for (; index < 19; index++) lengths[order[index]] = 0; /* build huffman table for code lengths codes (use lencode temporarily) */ err = construct(&lencode, lengths, 19); if (err != 0) /* require complete code set here */ return -4; /* read length/literal and distance code length tables */ index = 0; while (index < nlen + ndist) { int symbol; /* decoded value */ int len; /* last length to repeat */ symbol = decode(s, &lencode); if (symbol < 0) return symbol; /* invalid symbol */ if (symbol < 16) /* length in 0..15 */ lengths[index++] = (short)symbol; else { /* repeat instruction */ len = 0; /* assume repeating zeros */ if (symbol == 16) { /* repeat last length 3..6 times */ if (index == 0) return -5; /* no last length! */ len = lengths[index - 1]; /* last length */ symbol = 3 + bits(s, 2); } else if (symbol == 17) /* repeat zero 3..10 times */ symbol = 3 + bits(s, 3); else /* == 18, repeat zero 11..138 times */ symbol = 11 + bits(s, 7); if (index + symbol > nlen + ndist) return -6; /* too many lengths! */ while (symbol--) /* repeat last or zero symbol times */ lengths[index++] = (short)len; } } /* check for end-of-block code -- there better be one! */ if (lengths[256] == 0) return -9; /* build huffman table for literal/length codes */ err = construct(&lencode, lengths, nlen); if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1])) return -7; /* incomplete code ok only for single length 1 code */ /* build huffman table for distance codes */ err = construct(&distcode, lengths + nlen, ndist); if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1])) return -8; /* incomplete code ok only for single length 1 code */ /* decode data until end-of-block code */ return codes(s, &lencode, &distcode); } int puff(unsigned long dictlen, // length of custom dictionary unsigned char *dest, /* pointer to destination pointer */ unsigned long *destlen, /* amount of output space */ const unsigned char *source, /* pointer to source data pointer */ unsigned long *sourcelen) /* amount of input available */ { struct state s; /* input/output state */ int last, type; /* block information */ int err; /* return value */ /* initialize output state */ s.out = dest; s.outlen = *destlen; /* ignored if dest is NIL */ s.outcnt = dictlen; /* initialize input state */ s.in = source; s.inlen = *sourcelen; s.incnt = 0; s.bitbuf = 0; s.bitcnt = 0; /* return if bits() or decode() tries to read past available input */ if (setjmp(s.env) != 0) /* if came back here via longjmp() */ err = 2; /* then skip do-loop, return error */ else { /* process blocks until last block or error */ do { last = bits(&s, 1); /* one if last block */ type = bits(&s, 2); /* block type 0..3 */ err = type == 0 ? stored(&s) : (type == 1 ? fixed(&s) : (type == 2 ? dynamic(&s) : -1)); /* type == 3, invalid */ if (err != 0) break; /* return with error */ } while (!last); } /* update the lengths and return */ if (err <= 0) { *destlen = s.outcnt - dictlen; *sourcelen = s.incnt; } return err; } 0707010000001B000081A4000001ED0000006B000000015EE6501B00000634000000000000000000000000000000000000003200000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/puff.h/* puff.h Copyright (C) 2002-2013 Mark Adler, all rights reserved version 2.3, 21 Jan 2013 This software is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Mark Adler madler@alumni.caltech.edu */ // Extra modifications to support custom dictionary for pkg2zip /* * See puff.c for purpose and usage. */ #ifndef NIL # define NIL ((unsigned char *)0) /* for no output option */ #endif int puff(unsigned long dictlen, // length of custom dictionary (must be placed in beginning of dest) unsigned char *dest, /* pointer to destination pointer */ unsigned long *destlen, /* amount of output space */ const unsigned char *source, /* pointer to source data pointer */ unsigned long *sourcelen); /* amount of input available */ 0707010000001C000081ED000001ED0000006B000000015EE6501B00000285000000000000000000000000000000000000003700000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/rif2zrif.py#!/usr/bin/env python3 import sys import zlib import base64 zrif_dict = list(zlib.decompress(base64.b64decode( b"eNpjYBgFo2AU0AsYAIElGt8MRJiDCAsw3xhEmIAIU4N4AwNdRxcXZ3+/EJCAkW6Ac7C7ARwYgviuQAaIdoPSzlDaBUo7QmknIM3ACIZM78+u7kx3VWYEAGJ9HV0="))) if len(sys.argv) != 2: exit("Usage: %s path/to/file.rif" % sys.argv[0]) rif = open(sys.argv[1], "rb").read() c = zlib.compressobj(level=9, wbits=10, memLevel=8, zdict=bytes(zrif_dict)) bin = c.compress(rif) bin += c.flush() if len(bin) % 3 != 0: bin += b"\0" * (3 - len(bin) % 3) content = rif[0x10:0x40].rstrip(b"\0").decode("ascii") print(content, base64.b64encode(bin).decode("ascii")) 0707010000001D000081ED000001ED0000006B000000015EE6501B00000251000000000000000000000000000000000000003700000000pkg2zip-2.2+git.c75a9b2.1592152091.c75a9b2/zrif2rif.py#!/usr/bin/env python3 import sys import zlib import base64 zrif_dict = list(zlib.decompress(base64.b64decode( b"eNpjYBgFo2AU0AsYAIElGt8MRJiDCAsw3xhEmIAIU4N4AwNdRxcXZ3+/EJCAkW6Ac7C7ARwYgviuQAaIdoPSzlDaBUo7QmknIM3ACIZM78+u7kx3VWYEAGJ9HV0="))) if len(sys.argv) != 2 and len(sys.argv) != 3: exit("Usage: %s zRIF [path/to/work.bin]" % sys.argv[0]) bin = base64.b64decode(sys.argv[1].encode("ascii")) d = zlib.decompressobj(wbits=10, zdict=bytes(zrif_dict)) rif = d.decompress(bin) rif += d.flush() output = sys.argv[2] if len(sys.argv) == 3 else "work.bin" open(output, "wb").write(rif) 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!517 blocks
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.