Showing preview only (273K chars total). Download the full file or copy to clipboard to get everything.
Repository: lusid1/pkg2zip
Branch: master
Commit: 88fe198dc8ae
Files: 32
Total size: 262.2 KB
Directory structure:
gitextract_0natt280/
├── .appveyor.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── build.cmd
├── build32.cmd
├── makefile
├── miniz_tdef.c
├── miniz_tdef.h
├── pkg2zip.c
├── pkg2zip_aes.c
├── pkg2zip_aes.h
├── pkg2zip_aes_x86.c
├── pkg2zip_crc32.c
├── pkg2zip_crc32.h
├── pkg2zip_crc32_x86.c
├── pkg2zip_out.c
├── pkg2zip_out.h
├── pkg2zip_psp.c
├── pkg2zip_psp.h
├── pkg2zip_sys.c
├── pkg2zip_sys.h
├── pkg2zip_utils.h
├── pkg2zip_zip.c
├── pkg2zip_zip.h
├── pkg2zip_zrif.c
├── pkg2zip_zrif.h
├── puff.c
├── puff.h
├── rif2zrif.py
└── zrif2rif.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .appveyor.yml
================================================
version: '#{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
================================================
FILE: .gitignore
================================================
pkg2zip
pkg2zip.exe
*.d
*.o
*.obj
*.pdb
*.zip
================================================
FILE: .travis.yml
================================================
language: 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
================================================
FILE: 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.
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>
================================================
FILE: 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
================================================
FILE: 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
================================================
FILE: build32.cmd
================================================
@echo off
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" -arch=x86 -host_arch=x86
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
================================================
FILE: makefile
================================================
ifeq ($(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 -D -m 0755 ${BIN} $(DESTDIR)$(BINDIR)/${BIN}
install -D -m 0755 rif2zrif.py $(DESTDIR)$(BINDIR)/rif2zrif
install -D -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}
================================================
FILE: 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;
}
================================================
FILE: 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);
================================================
FILE: 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
#define VER "2.5"
// 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, char* discid)
{
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;
int discid_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;
}
else if (strcmp(key, "DISC_ID") == 0)
{
discid_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;
if(title) {
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 && category)
{
value = (char*)sfo + values + get32le(sfo + category_index * 16 + 20 + 12);
while (*value)
{
*category++ = *value++;
}
*category = 0;
}
if(discid_index >= 0 && discid){
value = (char*)sfo + values + get32le(sfo + discid_index * 16 + 20 + 12);
while (*value)
{
*discid++ = *value++;
}
*discid = 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, char* discid)
{
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, discid);
}
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, NULL);
return;
}
}
}
static void find_pbp_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* discid)
{
memset(discid, 0x00, 0x0A);
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, "USRDIR/CONTENT/EBOOT.PBP") == 0 || strcmp(name, "USRDIR/CONTENT/PBOOT.PBP") == 0 || strcmp(name, "USRDIR/CONTENT/PARAM.PBP") == 0)
{
uint8_t eboot_header[0x28];
uint8_t sfo[16 * 1024];
sys_read(pkg, enc_offset + data_offset, eboot_header, sizeof(eboot_header));
aes128_ctr_xor(item_key, iv, data_offset / 16, eboot_header, sizeof(eboot_header));
if (data_size < 0x28)
{
sys_error("ERROR: eboot.pbp file is too small\n");
}
if (memcmp(eboot_header, "\x00PBP", 4) != 0)
{
sys_error("ERROR: wrong eboot.pbp header signature!\n");
}
uint32_t sfo_offset = get32le(eboot_header + 0x8);
uint32_t icon0_offset = get32le(eboot_header + 0xC);
uint32_t sfo_size = (icon0_offset - sfo_offset);
// get sfo header aligned to aes block size
uint32_t sfo_offset_aligned = (sfo_offset - (sfo_offset % 16));
uint32_t sfo_offset_off = sfo_offset % 16;
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(pkg, enc_offset + data_offset + sfo_offset_aligned, sfo, sfo_size + sfo_offset_off);
aes128_ctr_xor(item_key, iv, (data_offset + sfo_offset_aligned) / 16, sfo, sfo_size + sfo_offset_off);
parse_sfo_content(sfo + sfo_offset_off, sfo_size, NULL, NULL, NULL, NULL, NULL, discid);
return;
}
}
}
static const char* get_region(const char* id) {
if (memcmp(id, "NPEE", 4) == 0 || memcmp(id, "NPEF", 4) == 0 || // PS1 EUR
memcmp(id, "UCES", 4) == 0 || memcmp(id, "ULES", 4) == 0 || // PSP EUR
memcmp(id, "NPEG", 4) == 0 || memcmp(id, "NPEH", 4) == 0 || // PSP EUR
memcmp(id, "NPEX", 4) == 0 || memcmp(id, "NPEZ", 4) == 0 || // PSP EUR
memcmp(id, "PCSB", 4) == 0 || memcmp(id, "PCSF", 4) == 0 || // PSV EUR
memcmp(id, "NPOA", 4) == 0) { // PSM EUR
return "EUR";
}
else if (memcmp(id, "NPHI", 4) == 0 || memcmp(id, "NPHJ", 4) == 0 || // PS1 ASA
memcmp(id, "UCAS", 4) == 0 || memcmp(id, "ULAS", 4) == 0 || // PSP ASA
memcmp(id, "NPHG", 4) == 0 || memcmp(id, "NPHH", 4) == 0 || // PSP ASA
memcmp(id, "NPHZ", 4) == 0 || // PSP ASA
memcmp(id, "PCSD", 4) == 0 || memcmp(id, "PCSH", 4) == 0 || // PSV ASA
memcmp(id, "NPQA", 4) == 0) { // PSM ASA
return "ASA";
}
else if (memcmp(id, "NPJI", 4) == 0 || memcmp(id, "NPJJ", 4) == 0 || // PS1 JPN
memcmp(id, "UCJM", 4) == 0 || memcmp(id, "ULJM", 4) == 0 || // PSP JPN
memcmp(id, "UCJS", 4) == 0 || memcmp(id, "ULJS", 4) == 0 || // PSP JPN
memcmp(id, "UCJB", 4) == 0 || memcmp(id, "NPJG", 4) == 0 || // PSP JPN
memcmp(id, "NPJH", 4) == 0 || // PSP JPN
memcmp(id, "PCSC", 4) == 0 || memcmp(id, "PCSG", 4) == 0 || // PSV JPN
memcmp(id, "NPPA", 4) == 0) { // PSM JPN
return "JPN";
}
else if (memcmp(id, "NPUF", 4) == 0 || memcmp(id, "NPUI", 4) == 0 || // PS1 USA
memcmp(id, "NPUJ", 4) == 0 || // PS1 USA
memcmp(id, "UCUS", 4) == 0 || memcmp(id, "ULUS", 4) == 0 || // PSP USA
memcmp(id, "NPUG", 4) == 0 || memcmp(id, "NPUH", 4) == 0 || // PSP USA
memcmp(id, "NPUX", 4) == 0 || memcmp(id, "NPUZ", 4) == 0 || // PSP USA
memcmp(id, "PCSA", 4) == 0 || memcmp(id, "PCSE", 4) == 0 || // PSV USA
memcmp(id, "NPNA", 4) == 0) { // PSM USA
return "USA";
}
else if (memcmp(id, "UCKS", 4) == 0 || memcmp(id, "ULKS", 4) == 0) { // PSP KOR
return "KOR";
}
else if (memcmp(id, "PCSI", 4) == 0 || memcmp(id, "NPXS", 4) == 0) { // PSV INT
return "INT";
}
else {
return "UNK";
}
}
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("-d|--decrypt Always decrypt PSP DLC/EDAT files\n");
sys_output("PSM only options:\n");
sys_output("-a|--android-psm Extract into PSM for Android 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_PS3 // PKG type 1
} 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 ddlc = 0;
int bgdl = 1;
int android = 0;
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], "-d") == 0 || strcmp(argv[i], "--decrypt") == 0)
{
ddlc = 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], "-a") == 0 || strcmp(argv[i], "--android-psm") == 0)
{
android = 1;
}
else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
{
sys_output("pkg2zip v"VER"\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 v"VER"\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)
if (get32be(pkg_header) != 0x7f504b47) // do not check for extended header
{
sys_error("ERROR: not a pkg file\n");
}
// https://www.psdevwiki.com/ps3/PKG_files#Header
uint16_t hdr_type = get16be(pkg_header + 6);
uint64_t meta_offset = get32be(pkg_header + 8); // why uint64_t?
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 == 1)
{
type = PKG_TYPE_PS3;
}
else 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\n", 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) && (hdr_type == 1)) // PKG_TYPE_PS3
{
memcpy(main_key, pkg_ps3_key, sizeof(main_key));
aes128_init(&ps3_key, pkg_ps3_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 discid[10];
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_PS3) {
// there is no PARAM.SFO inside
id = (char*)pkg_header + 0x37;
sprintf(title, "%s", id);
}
else 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);
// read discid from PARAM.SFO in EBOOT.PBP
find_pbp_sfo(&key, &ps3_key, iv, pkg, pkg_size, enc_offset, items_offset, item_count, discid);
id = discid;
if(strcmp(id, "") == 0)
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, NULL);
rif_size = 512;
}
else // Vita APP, DLC or PATCH
{
parse_sfo(pkg, sfo_offset, sfo_size, category, title, content, min_version, pkg_version, NULL);
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] [%s] [PSX]%s", title, id, get_region(id), ext);
if (verbose)
{
sys_output("[*] unpacking PSX\n");
}
}
else if (type == PKG_TYPE_PS3)
{
snprintf(root, sizeof(root), "%s [%.9s] [%s] [PSX]%s", title, id, get_region(id), ext);
if (verbose)
{
sys_output("[*] unpacking PS3 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 %i\n", type);
}
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)
{
if (zipped)
sys_output("[*] creating '%s' archive\n", root);
else
sys_output("[*] unpacking '%s' to directory\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 if (type == PKG_TYPE_PS3)
{
snprintf(root, sizeof(root), "pspemu/PSP/GAME");
}
else
{
assert(0);
sys_error("ERROR: unsupported type %i\n", type);
}
char path[1024];
sys_output_progress_init(pkg_size);
char rw_folder[1024];
char ro_folder[1024];
if(type == PKG_TYPE_VITA_PSM) {
if(android) {
snprintf(rw_folder, sizeof(rw_folder) - 1, "%s", root);
snprintf(ro_folder, sizeof(ro_folder) - 1, "%s", root);
}
else {
snprintf(rw_folder, sizeof(rw_folder) - 1, "%s/RW", root);
snprintf(ro_folder, sizeof(ro_folder) - 1, "%s/RO", root);
}
}
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/%s", ro_folder, 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_PS3) {
char game[10]; // ABCD12345
strncpy(game, &name[0], 9);
game[9] = '\0';
if (strstr(name, "DOCUMENT.DAT") != NULL) {
sprintf(path, "pspemu/PSP/GAME/%s/DOCUMENT.DAT", game);
} else if (strstr(name, "EBOOT.PBP") != NULL) {
sprintf(path, "pspemu/PSP/GAME/%s", game);
out_add_folder(path);
sprintf(path, "pspemu/PSP/GAME/%s/KEYS.BIN", game);
unpack_keys_bin(path, item_key, iv, pkg, enc_offset, data_offset, data_size);
sprintf(path, "pspemu/PSP/GAME/%s/EBOOT.PBP", game);
} else {
continue;
}
}
else 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);
if (!pbp || ddlc)
{
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)
{
if (!pbp || ddlc)
{
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/%s", ro_folder, 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)
{
if (zipped)
sys_output("[*] creating completed\n");
else
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 %s/License\n", ro_folder);
}
snprintf(path, sizeof(path), "%s/License", ro_folder);
out_add_folder(path);
if (verbose)
{
sys_output("[*] creating %s/License/FAKE.rif\n", ro_folder);
}
snprintf(path, sizeof(path), "%s/License/FAKE.rif", ro_folder);
}
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 %s\n", rw_folder);
}
snprintf(path, sizeof(path), "%s", rw_folder);
out_add_folder(path);
if (verbose)
{
sys_output("[*] creating %s/Documents\n", rw_folder);
}
snprintf(path, sizeof(path), "%s/Documents", rw_folder);
out_add_folder(path);
if (verbose)
{
sys_output("[*] creating %s/Temp\n", rw_folder);
}
snprintf(path, sizeof(path), "%s/Temp", rw_folder);
out_add_folder(path);
if (verbose)
{
sys_output("[*] creating %s/System\n", rw_folder);
}
snprintf(path, sizeof(path), "%s/System", rw_folder);
out_add_folder(path);
if(!android){
if (verbose)
{
sys_output("[*] creating %s/System/content_id\n", rw_folder);
}
snprintf(path, sizeof(path), "%s/System/content_id", rw_folder);
out_begin_file(path, 0);
out_write(pkg_header + 0x30, 0x30);
out_end_file();
}
if (verbose)
{
sys_output("[*] creating %s/System/pm.dat\n", rw_folder);
}
snprintf(path, sizeof(path), "%s/System/pm.dat", rw_folder);
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();
}
================================================
FILE: 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);
}
}
================================================
FILE: 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);
================================================
FILE: 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;
}
}
================================================
FILE: 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;
}
================================================
FILE: 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);
================================================
FILE: 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;
}
================================================
FILE: 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);
}
}
================================================
FILE: 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);
================================================
FILE: 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
gitextract_0natt280/ ├── .appveyor.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build.cmd ├── build32.cmd ├── makefile ├── miniz_tdef.c ├── miniz_tdef.h ├── pkg2zip.c ├── pkg2zip_aes.c ├── pkg2zip_aes.h ├── pkg2zip_aes_x86.c ├── pkg2zip_crc32.c ├── pkg2zip_crc32.h ├── pkg2zip_crc32_x86.c ├── pkg2zip_out.c ├── pkg2zip_out.h ├── pkg2zip_psp.c ├── pkg2zip_psp.h ├── pkg2zip_sys.c ├── pkg2zip_sys.h ├── pkg2zip_utils.h ├── pkg2zip_zip.c ├── pkg2zip_zip.h ├── pkg2zip_zrif.c ├── pkg2zip_zrif.h ├── puff.c ├── puff.h ├── rif2zrif.py └── zrif2rif.py
SYMBOL INDEX (180 symbols across 17 files)
FILE: miniz_tdef.c
type tdefl_sym_freq (line 97) | typedef struct
function tdefl_sym_freq (line 101) | static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym...
function tdefl_calculate_minimum_redundancy (line 135) | static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n)
function tdefl_huffman_enforce_max_code_size (line 195) | static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int cod...
function tdefl_optimize_huffman_table (line 219) | static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_...
function tdefl_start_dynamic_block (line 338) | static void tdefl_start_dynamic_block(tdefl_compressor *d)
function tdefl_start_static_block (line 425) | static void tdefl_start_static_block(tdefl_compressor *d)
function mz_bool (line 450) | static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
function mz_bool (line 544) | static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
function mz_bool (line 592) | static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_...
function tdefl_flush_block (line 601) | static int tdefl_flush_block(tdefl_compressor *d, int flush)
function MZ_FORCEINLINE (line 731) | static MZ_FORCEINLINE mz_uint16 TDEFL_READ_UNALIGNED_WORD(const void* p)
function MZ_FORCEINLINE (line 736) | static MZ_FORCEINLINE mz_uint32 TDEFL_READ_UNALIGNED_DWORD(const void* p)
function MZ_FORCEINLINE (line 741) | static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint...
function MZ_FORCEINLINE (line 794) | static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint...
function mz_bool (line 840) | static mz_bool tdefl_compress_fast(tdefl_compressor *d)
function MZ_FORCEINLINE (line 1010) | static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_...
function MZ_FORCEINLINE (line 1023) | static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_ui...
function mz_bool (line 1053) | static mz_bool tdefl_compress_normal(tdefl_compressor *d)
function tdefl_status (line 1198) | static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d)
function tdefl_status (line 1219) | tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, si...
function tdefl_status (line 1287) | tdefl_status tdefl_init(tdefl_compressor *d, int flags)
function mz_uint (line 1321) | mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bi...
function mz_uint32 (line 1341) | mz_uint32 mz_adler32(mz_uint32 adler, const unsigned char *ptr, size_t b...
FILE: miniz_tdef.h
type mz_uint8 (line 9) | typedef uint8_t mz_uint8;
type mz_int16 (line 10) | typedef int16_t mz_int16;
type mz_uint16 (line 11) | typedef uint16_t mz_uint16;
type mz_uint32 (line 12) | typedef uint32_t mz_uint32;
type mz_uint (line 13) | typedef uint32_t mz_uint;
type mz_int64 (line 14) | typedef int64_t mz_int64;
type mz_uint64 (line 15) | typedef uint64_t mz_uint64;
type mz_bool (line 16) | typedef int mz_bool;
type tdefl_status (line 98) | typedef enum
type tdefl_flush (line 107) | typedef enum
type tdefl_compressor (line 116) | typedef struct
FILE: pkg2zip.c
function parse_sfo_content (line 34) | static void parse_sfo_content(const uint8_t* sfo, uint32_t sfo_size, cha...
function parse_sfo (line 189) | static void parse_sfo(sys_file f, uint64_t sfo_offset, uint32_t sfo_size...
function find_psp_sfo (line 205) | static void find_psp_sfo(const aes128_key* key, const aes128_key* ps3_ke...
function find_pbp_sfo (line 257) | static void find_pbp_sfo(const aes128_key* key, const aes128_key* ps3_ke...
function print_help (line 377) | void print_help(char* bin_name)
type pkg_type (line 397) | typedef enum {
function main (line 409) | int main(int argc, char* argv[])
FILE: pkg2zip_aes.c
function get_cpuid (line 11) | static void get_cpuid(uint32_t level, uint32_t* arr)
function get_cpuid (line 20) | static void get_cpuid(uint32_t level, uint32_t* arr)
function aes128_supported_x86 (line 30) | static int aes128_supported_x86()
function byte32 (line 171) | static uint8_t byte32(uint32_t x, int n)
function ror32 (line 176) | static uint32_t ror32(uint32_t x, int n)
function setup_mix (line 181) | static uint32_t setup_mix(uint32_t x)
function setup_mix2 (line 186) | static uint32_t setup_mix2(uint32_t x)
function aes128_init (line 191) | void aes128_init(aes128_key* ctx, const uint8_t* key)
function aes128_init_dec (line 219) | void aes128_init_dec(aes128_key* ctx, const uint8_t* key)
function aes128_encrypt (line 256) | static void aes128_encrypt(const aes128_key* ctx, const uint8_t* input, ...
function aes128_decrypt (line 295) | static void aes128_decrypt(const aes128_key* ctx, const uint8_t* input, ...
function aes128_ecb_encrypt (line 333) | void aes128_ecb_encrypt(const aes128_key* ctx, const uint8_t* input, uin...
function aes128_ecb_decrypt (line 345) | void aes128_ecb_decrypt(const aes128_key* ctx, const uint8_t* input, uin...
function ctr_add (line 357) | static void ctr_add(uint8_t* counter, uint64_t n)
function aes128_ctr_xor (line 367) | void aes128_ctr_xor(const aes128_key* context, const uint8_t* iv, uint64...
type aes128_cmac_ctx (line 408) | typedef struct {
function aes128_cmac_process (line 415) | static void aes128_cmac_process(const aes128_key* ctx, uint8_t* block, c...
function aes128_cmac_init (line 436) | static void aes128_cmac_init(aes128_cmac_ctx* ctx, const uint8_t* key)
function aes128_cmac_update (line 443) | static void aes128_cmac_update(aes128_cmac_ctx* ctx, const uint8_t* buff...
function cmac_gfmul (line 474) | static void cmac_gfmul(uint8_t* block)
function aes128_cmac_done (line 487) | static void aes128_cmac_done(aes128_cmac_ctx* ctx, uint8_t* mac)
function aes128_cmac (line 510) | void aes128_cmac(const uint8_t* key, const uint8_t* buffer, uint32_t siz...
function aes128_psp_decrypt (line 518) | void aes128_psp_decrypt(const aes128_key* ctx, const uint8_t* iv, uint32...
FILE: pkg2zip_aes.h
type aes128_key (line 5) | typedef struct aes128_key {
FILE: pkg2zip_aes_x86.c
function aes128_init_x86 (line 22) | void aes128_init_x86(aes128_key* ctx, const uint8_t* key)
function aes128_init_dec_x86 (line 40) | void aes128_init_dec_x86(aes128_key* ctx, const uint8_t* key)
function __m128i (line 56) | static __m128i aes128_encrypt_x86(__m128i input, const __m128i* key)
function __m128i (line 71) | static __m128i aes128_decrypt_x86(__m128i input, const __m128i* key)
function aes128_ecb_encrypt_x86 (line 86) | void aes128_ecb_encrypt_x86(const aes128_key* ctx, const uint8_t* input,...
function aes128_ecb_decrypt_x86 (line 93) | void aes128_ecb_decrypt_x86(const aes128_key* ctx, const uint8_t* input,...
function __m128i (line 100) | static __m128i ctr_increment(__m128i counter)
function aes128_ctr_xor_x86 (line 108) | void aes128_ctr_xor_x86(const aes128_key* ctx, const uint8_t* iv, uint8_...
function aes128_cmac_process_x86 (line 139) | void aes128_cmac_process_x86(const aes128_key* ctx, uint8_t* block, cons...
function aes128_psp_decrypt_x86 (line 154) | void aes128_psp_decrypt_x86(const aes128_key* ctx, const uint8_t* prev, ...
FILE: pkg2zip_crc32.c
function get_cpuid (line 12) | static void get_cpuid(uint32_t level, uint32_t* arr)
function get_cpuid (line 21) | static void get_cpuid(uint32_t level, uint32_t* arr)
function crc32_supported_x86 (line 31) | static int crc32_supported_x86()
function crc32_init (line 197) | void crc32_init(crc32_ctx* ctx)
function crc32_update (line 209) | void crc32_update(crc32_ctx* ctx, const void* buffer, size_t size)
function crc32_done (line 250) | uint32_t crc32_done(crc32_ctx* ctx)
function crc32_gfmulv (line 262) | static uint32_t crc32_gfmulv(const uint32_t* m, uint32_t v)
function crc32_gfsq (line 277) | static void crc32_gfsq(const uint32_t* m, uint32_t* r)
function crc32_combine (line 285) | uint32_t crc32_combine(uint32_t a, uint32_t b, uint32_t blen)
FILE: pkg2zip_crc32.h
type crc32_ctx (line 5) | typedef struct {
FILE: pkg2zip_crc32_x86.c
function crc32_init_x86 (line 166) | void crc32_init_x86(crc32_ctx* ctx)
function crc32_update_x86 (line 177) | void crc32_update_x86(crc32_ctx* ctx, const void* buffer, size_t size)
function crc32_done_x86 (line 283) | uint32_t crc32_done_x86(crc32_ctx* ctx)
FILE: pkg2zip_out.c
function out_begin (line 11) | void out_begin(const char* name, int zipped)
function out_end (line 20) | void out_end(void)
function out_add_folder (line 28) | void out_add_folder(const char* path)
function out_add_parent (line 40) | void out_add_parent(const char* path)
function out_begin_file (line 58) | uint64_t out_begin_file(const char* name, int compress)
function out_end_file (line 72) | void out_end_file(void)
function out_write (line 84) | void out_write(const void* buffer, uint32_t size)
function out_write_at (line 97) | void out_write_at(uint64_t offset, const void* buffer, uint32_t size)
function out_set_offset (line 109) | void out_set_offset(uint64_t offset)
function out_zip_get_crc32 (line 122) | uint32_t out_zip_get_crc32(void)
function out_zip_set_crc32 (line 131) | void out_zip_set_crc32(uint32_t crc)
FILE: pkg2zip_psp.c
type lzrc_decode (line 25) | typedef struct {
function rc_init (line 49) | static void rc_init(lzrc_decode* rc, void* out, int out_len, const void*...
function normalize (line 76) | static void normalize(lzrc_decode* rc)
function rc_bit (line 86) | static int rc_bit(lzrc_decode* rc, uint8_t *prob)
function rc_bittree (line 109) | static int rc_bittree(lzrc_decode* rc, uint8_t *probs, int limit)
function rc_number (line 122) | static int rc_number(lzrc_decode* rc, uint8_t *prob, uint32_t n)
function lzrc_decompress (line 170) | static int lzrc_decompress(void* out, int out_len, const void* in, int i...
function init_psp_decrypt (line 284) | static void init_psp_decrypt(aes128_key* key, uint8_t* iv, int eboot, co...
function init_psx_keys (line 314) | static void init_psx_keys(uint8_t* iv, const uint8_t* mac, const uint8_t...
function unpack_psp_eboot (line 331) | void unpack_psp_eboot(const char* path, const aes128_key* pkg_key, const...
function unpack_psp_key (line 558) | void unpack_psp_key(const char* path, const aes128_key* pkg_key, const u...
function unpack_psp_edat (line 605) | void unpack_psp_edat(const char* path, const aes128_key* pkg_key, const ...
function unpack_keys_bin (line 675) | void unpack_keys_bin(const char* path, const aes128_key* pkg_key, const ...
function get_psp_theme_title (line 746) | void get_psp_theme_title(char* title, const aes128_key* pkg_key, const u...
FILE: pkg2zip_sys.c
function sys_output_init (line 20) | void sys_output_init(void)
function sys_output_done (line 30) | void sys_output_done(void)
function sys_output (line 35) | void sys_output(const char* msg, ...)
function sys_error (line 56) | void sys_error(const char* msg, ...)
function sys_mkdir_real (line 83) | static void sys_mkdir_real(const char* path)
function sys_file (line 97) | sys_file sys_open(const char* fname, uint64_t* size)
function sys_file (line 118) | sys_file sys_create(const char* fname)
function sys_close (line 132) | void sys_close(sys_file file)
function sys_read (line 140) | void sys_read(sys_file file, uint64_t offset, void* buffer, uint32_t size)
function sys_write (line 153) | void sys_write(sys_file file, uint64_t offset, const void* buffer, uint3...
function sys_output_init (line 177) | void sys_output_init(void)
function sys_output_done (line 182) | void sys_output_done(void)
function sys_output (line 186) | void sys_output(const char* msg, ...)
function sys_error (line 194) | void sys_error(const char* msg, ...)
function sys_mkdir_real (line 204) | static void sys_mkdir_real(const char* path)
function sys_file (line 215) | sys_file sys_open(const char* fname, uint64_t* size)
function sys_file (line 233) | sys_file sys_create(const char* fname)
function sys_close (line 244) | void sys_close(sys_file file)
function sys_read (line 252) | void sys_read(sys_file file, uint64_t offset, void* buffer, uint32_t size)
function sys_write (line 261) | void sys_write(sys_file file, uint64_t offset, const void* buffer, uint3...
function sys_mkdir (line 272) | void sys_mkdir(const char* path)
function sys_vstrncat (line 313) | void sys_vstrncat(char* dst, size_t n, const char* format, ...)
function sys_output_progress_init (line 328) | void sys_output_progress_init(uint64_t size)
function sys_output_progress (line 334) | void sys_output_progress(uint64_t progress)
function sys_test_dir (line 349) | int sys_test_dir(const char* const path)
FILE: pkg2zip_utils.h
function min32 (line 14) | static inline uint32_t min32(uint32_t a, uint32_t b)
function min64 (line 19) | static inline uint64_t min64(uint64_t a, uint64_t b)
function get16le (line 24) | static inline uint16_t get16le(const uint8_t* bytes)
function get32le (line 29) | static inline uint32_t get32le(const uint8_t* bytes)
function get64le (line 34) | static inline uint64_t get64le(const uint8_t* bytes)
function get16be (line 46) | static inline uint16_t get16be(const uint8_t* bytes)
function get32be (line 51) | static inline uint32_t get32be(const uint8_t* bytes)
function get64be (line 56) | static inline uint64_t get64be(const uint8_t* bytes)
function set16le (line 68) | static inline void set16le(uint8_t* bytes, uint16_t x)
function set32le (line 74) | static inline void set32le(uint8_t* bytes, uint32_t x)
function set64le (line 82) | static inline void set64le(uint8_t* bytes, uint64_t x)
function set16be (line 94) | static inline void set16be(uint8_t* bytes, uint16_t x)
function set32be (line 100) | static inline void set32be(uint8_t* bytes, uint32_t x)
function set64be (line 108) | static inline void set64be(uint8_t* bytes, uint64_t x)
FILE: pkg2zip_zip.c
type zip_file (line 35) | struct zip_file
function zip_file (line 44) | static zip_file* zip_new_file(zip* z)
function zip_create (line 56) | void zip_create(zip* z, const char* name)
function zip_add_folder (line 72) | void zip_add_folder(zip* z, const char* name)
function zip_begin_file (line 112) | uint64_t zip_begin_file(zip* z, const char* name, int compress)
function zip_write_file (line 159) | void zip_write_file(zip* z, const void* data, uint32_t size)
function zip_end_file (line 193) | void zip_end_file(zip* z)
function zip_close (line 239) | void zip_close(zip* z)
function zip_write_file_at (line 411) | void zip_write_file_at(zip* z, uint64_t offset, const void* data, uint32...
function zip_set_offset (line 423) | void zip_set_offset(zip* z, uint64_t offset)
function zip_set_crc32 (line 428) | void zip_set_crc32(zip* z, uint32_t crc)
function zip_get_crc32 (line 434) | uint32_t zip_get_crc32(zip* z)
FILE: pkg2zip_zip.h
type zip_file (line 12) | typedef struct zip_file zip_file;
type zip (line 14) | typedef struct {
FILE: pkg2zip_zrif.c
function base64_decode (line 66) | static uint32_t base64_decode(const char* in, uint8_t* out)
function zlib_inflate (line 106) | static uint32_t zlib_inflate(const uint8_t* in, uint32_t inlen, uint8_t*...
function zrif_decode (line 162) | void zrif_decode(const char* str, uint8_t* rif, uint32_t rif_size)
FILE: puff.c
type state (line 20) | struct state {
function local (line 37) | local int bits(struct state *s, int need)
function local (line 58) | local int stored(struct state *s)
type huffman (line 93) | struct huffman {
function local (line 98) | local int decode(struct state *s, const struct huffman *h)
function local (line 142) | local int construct(struct huffman *h, const short *length, int n)
function local (line 183) | local int codes(struct state *s,
function local (line 259) | local int fixed(struct state *s)
function local (line 301) | local int dynamic(struct state *s)
function puff (line 385) | int puff(unsigned long dictlen, // length of custom dictionary
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (279K chars).
[
{
"path": ".appveyor.yml",
"chars": 518,
"preview": "version: '#{build}'\nskip_tags: true\n\nbuild: off\ndeploy: off\n\nenvironment:\n matrix:\n\n - APPVEYOR_BUILD_WORKER_IMAGE: "
},
{
"path": ".gitignore",
"chars": 46,
"preview": "pkg2zip\npkg2zip.exe\n*.d\n*.o\n*.obj\n*.pdb\n*.zip\n"
},
{
"path": ".travis.yml",
"chars": 263,
"preview": "language: c\n\nmatrix:\n include:\n\n - os: linux\n dist: trusty\n sudo: false\n compiler: gcc\n\n - os: lin"
},
{
"path": "LICENSE",
"chars": 1210,
"preview": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, c"
},
{
"path": "README.md",
"chars": 6181,
"preview": "# pkg2zip\n\n[![Travis CI Build Status][img_travis]][travis] [![AppVeyor Build Status][img_appveyor]][appveyor] [![Downloa"
},
{
"path": "build.cmd",
"chars": 414,
"preview": "@echo off\n\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\Common7\\Tools\\VsDevCmd.bat\" -arch=amd64 -"
},
{
"path": "build32.cmd",
"chars": 410,
"preview": "@echo off\n\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\Common7\\Tools\\VsDevCmd.bat\" -arch=x86 -ho"
},
{
"path": "makefile",
"chars": 1144,
"preview": "ifeq ($(OS),Windows_NT)\n RM := del /q\n EXE := .exe\nelse\n EXE :=\nendif\n\nDESTDIR =\nPREFIX = /usr/local\nBINDIR = $(PREFI"
},
{
"path": "miniz_tdef.c",
"chars": 61602,
"preview": "#include \"miniz_tdef.h\"\n\n#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i4"
},
{
"path": "miniz_tdef.h",
"chars": 7039,
"preview": "#pragma once\n\n// public domain code from https://github.com/richgel999/miniz/tree/42c29103c304a6e9201d000c96c31cd3031efc"
},
{
"path": "pkg2zip.c",
"chars": 48017,
"preview": "#include \"pkg2zip_aes.h\"\n#include \"pkg2zip_zip.h\"\n#include \"pkg2zip_out.h\"\n#include \"pkg2zip_psp.h\"\n#include \"pkg2zip_ut"
},
{
"path": "pkg2zip_aes.c",
"chars": 23412,
"preview": "#include \"pkg2zip_aes.h\"\n#include \"pkg2zip_utils.h\"\n\n#include <assert.h>\n#include <string.h>\n\n#if defined(_MSC_VER)\n#def"
},
{
"path": "pkg2zip_aes.h",
"chars": 727,
"preview": "#pragma once\n\n#include \"pkg2zip_utils.h\"\n\ntypedef struct aes128_key {\n uint32_t PKG_ALIGN(16) key[44];\n} aes128_key;\n"
},
{
"path": "pkg2zip_aes_x86.c",
"chars": 6006,
"preview": "#include \"pkg2zip_aes.h\"\n\n#include <string.h>\n#include <wmmintrin.h> // AESNI\n#include <tmmintrin.h> // SSSE3\n\n#define A"
},
{
"path": "pkg2zip_crc32.c",
"chars": 17026,
"preview": "#include \"pkg2zip_crc32.h\"\n#include \"pkg2zip_utils.h\"\n\n#ifdef __linux__\n#include <endian.h>\n#endif\n\n#if defined(_MSC_VER"
},
{
"path": "pkg2zip_crc32.h",
"chars": 448,
"preview": "#pragma once\n\n#include \"pkg2zip_utils.h\"\n\ntypedef struct {\n uint32_t PKG_ALIGN(16) crc[4 * 5];\n} crc32_ctx;\n\nvoid crc"
},
{
"path": "pkg2zip_crc32_x86.c",
"chars": 13325,
"preview": "#include \"pkg2zip_crc32.h\"\n\n#include <wmmintrin.h> // PCLMUL\n#include <tmmintrin.h> // SSSE3\n#include <smmintrin.h> // S"
},
{
"path": "pkg2zip_out.c",
"chars": 2248,
"preview": "#include \"pkg2zip_out.h\"\n#include \"pkg2zip_sys.h\"\n#include \"pkg2zip_zip.h\"\n#include <stdio.h>\n\nstatic zip out_zip;\nstati"
},
{
"path": "pkg2zip_out.h",
"chars": 569,
"preview": "#pragma once\n\n#include <stdint.h>\n\nvoid out_begin(const char* name, int zipped);\nvoid out_end(void);\nvoid out_add_folder"
},
{
"path": "pkg2zip_psp.c",
"chars": 25056,
"preview": "#include \"pkg2zip_psp.h\"\n#include \"pkg2zip_out.h\"\n#include \"pkg2zip_crc32.h\"\n#include \"pkg2zip_utils.h\"\n#include \"miniz_"
},
{
"path": "pkg2zip_psp.h",
"chars": 879,
"preview": "#include \"pkg2zip_aes.h\"\n#include \"pkg2zip_sys.h\"\n\nvoid unpack_psp_eboot(const char* path, const aes128_key* pkg_key, co"
},
{
"path": "pkg2zip_sys.c",
"chars": 7660,
"preview": "#include \"pkg2zip_sys.h\"\n#include \"pkg2zip_utils.h\"\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include"
},
{
"path": "pkg2zip_sys.h",
"chars": 891,
"preview": "#pragma once\n\n#include \"pkg2zip_utils.h\"\n\n// correctly outputs utf8 string\nvoid sys_output_init(void);\nvoid sys_output_d"
},
{
"path": "pkg2zip_utils.h",
"chars": 2890,
"preview": "#pragma once\n\n#include <stdint.h>\n#include <stddef.h>\n\n#if defined(_MSC_VER)\n# define NORETURN __declspec(noreturn)\n# "
},
{
"path": "pkg2zip_zip.c",
"chars": 12945,
"preview": "#if defined(__MINGW32__) && !defined(__x86_64__)\n# define _USE_32BIT_TIME_T\n# define __CRT__NO_INLINE\n#endif\n\n#include"
},
{
"path": "pkg2zip_zip.h",
"chars": 1029,
"preview": "#pragma once\n\n#include \"pkg2zip_sys.h\"\n#include \"pkg2zip_crc32.h\"\n#include \"miniz_tdef.h\"\n\n#include <stddef.h>\n#include "
},
{
"path": "pkg2zip_zrif.c",
"chars": 7341,
"preview": "#include \"pkg2zip_zrif.h\"\n#include \"pkg2zip_utils.h\"\n#include \"pkg2zip_sys.h\"\n#include \"miniz_tdef.h\"\n#include \"puff.h\"\n"
},
{
"path": "pkg2zip_zrif.h",
"chars": 103,
"preview": "#pragma once\n\n#include <stdint.h>\n\nvoid zrif_decode(const char* str, uint8_t* rif, uint32_t rif_size);\n"
},
{
"path": "puff.c",
"chars": 16285,
"preview": "/*\n * puff.c\n * Copyright (C) 2002-2013 Mark Adler\n * For conditions of distribution and use, see copyright notice in pu"
},
{
"path": "puff.h",
"chars": 1588,
"preview": "/* puff.h\n Copyright (C) 2002-2013 Mark Adler, all rights reserved\n version 2.3, 21 Jan 2013\n\n This software is provi"
},
{
"path": "rif2zrif.py",
"chars": 645,
"preview": "#!/usr/bin/env python3\n\nimport sys\nimport zlib\nimport base64\n\nzrif_dict = list(zlib.decompress(base64.b64decode(\n b\"eNp"
},
{
"path": "zrif2rif.py",
"chars": 593,
"preview": "#!/usr/bin/env python3\n\nimport sys\nimport zlib\nimport base64\n\nzrif_dict = list(zlib.decompress(base64.b64decode(\n b\"eNp"
}
]
About this extraction
This page contains the full source code of the lusid1/pkg2zip GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (262.2 KB), approximately 97.3k tokens, and a symbol index with 180 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.