diff --git a/CHANGELOG.md b/CHANGELOG.md index cd784fb..a8be77c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # CheatRunner — Changelog -## v0.17 +## v0.17.1 + +- **Added: support for 13.60 firmware** — rebuilt against the latest ps5-payload-sdk. + +
+v0.17 - **Fixed: the trainer/cheat menu, Settings page, and Support/donate popup could silently fail to appear on some PS5 firmwares** (reported on 4.03) — the "Cheat menu loaded" toast would show, but the menu itself never appeared, same for Settings and Support. Root cause, confirmed against that firmware's actual WebKit source: every full-screen overlay in the dashboard positioned itself with the CSS `inset` shorthand, which is gated behind WebKit's `CSSLogicalEnabled` runtime flag — off by default in this build. With `inset` silently dropped, the overlay never got a `top`/`right`/`bottom`/`left`, so it had no size or position to render at, regardless of `display`/`visibility`/`opacity`. (Two earlier attempts in this same release — switching `display:none` to `visibility`/`opacity`, then adding a `transition` — treated it as a compositing/paint timing issue and didn't address this.) Replaced `inset` with explicit `top`/`right`/`bottom`/`left` everywhere it was used for positioning (the three overlays, plus several decorative background/glow/shimmer effects that had the same silent failure but went unnoticed since they're cosmetic). Confirmed fixed on the reporting user's PS5. - **Fixed: the Settings page's ON/OFF toggle switches were too cramped for the text**, and the green "ON" fill sat slightly off-center — a CSS math bug on every toggle switch in the app, not just Settings. @@ -16,6 +21,8 @@ - **Added an "Enable hotkey" switch in Settings → Hotkey, off by default.** On some firmwares (seen on 4.xx) the hook can still crash SceShellUI despite the fix above — the rest of CheatRunner works fully with it off; turn it on once you've confirmed it's stable on your firmware. - **Fixed a garbled "…" character** ("Search settings…", the health panel's "Loading…") showing as mojibake on the PS5 browser — replaced with plain periods. +
+
v0.16 diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 8fab0b6..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,194 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) - -project(CheatRunnerPayload C CXX) -set(CHEATRUNNER_VERSION "0.17") - -# Embed CheatRunner.png as a C byte array (cheatrunner_png.h in build dir). -# If the asset is missing, generate a tiny fallback icon so builds still work. -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CheatRunner.png") - file(READ "${CMAKE_CURRENT_SOURCE_DIR}/CheatRunner.png" _CR_PNG_HEX HEX) - string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," _CR_PNG_BYTES "${_CR_PNG_HEX}") - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cheatrunner_png.h" - "static const unsigned char g_cheatrunner_png[] = {${_CR_PNG_BYTES}};\n" - ) -else() - message(WARNING "CheatRunner.png missing; generating fallback cheatrunner_png.h") - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cheatrunner_png.h" - "static const unsigned char g_cheatrunner_png[] = {" - "0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A," - "0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x01," - "0x00,0x00,0x00,0x01,0x08,0x06,0x00,0x00,0x00,0x1F,0x15,0xC4," - "0x89,0x00,0x00,0x00,0x0D,0x49,0x44,0x41,0x54,0x78,0x9C,0x63," - "0x00,0x01,0x00,0x00,0x05,0x00,0x01,0x0D,0x0A,0x2D,0xB4,0x00," - "0x00,0x00,0x00,0x49,0x45,0x4E,0x44,0xAE,0x42,0x60,0x82};\n" - ) -endif() - -# Embed dist/CheatRunner.pkg as a C byte array (cheatrunner_tile_pkg.h). -# Build the PKG first with: cd pkg-source && ./build-pkg.sh -# If absent the auto-install feature is compiled out but everything else works. -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/dist/CheatRunner.pkg") - file(READ "${CMAKE_CURRENT_SOURCE_DIR}/dist/CheatRunner.pkg" _PKG_HEX HEX) - string(LENGTH "${_PKG_HEX}" _PKG_HEX_LEN) - math(EXPR _PKG_LEN "${_PKG_HEX_LEN} / 2") - string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," _PKG_BYTES "${_PKG_HEX}") - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cheatrunner_tile_pkg.h" - "static const unsigned char g_cheatrunner_tile_pkg[] = {${_PKG_BYTES}};\n" - "static const size_t g_cheatrunner_tile_pkg_len = ${_PKG_LEN}u;\n" - ) - set(_HAVE_TILE_PKG ON) - message(STATUS "CheatRunner tile PKG: embedding ${_PKG_LEN} bytes from dist/CheatRunner.pkg") -else() - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cheatrunner_tile_pkg.h" - "/* dist/CheatRunner.pkg not present at configure time — auto-install disabled */\n" - ) - set(_HAVE_TILE_PKG OFF) - message(STATUS "CheatRunner tile PKG: dist/CheatRunner.pkg not found — auto-install disabled (run pkg-source/build-pkg.sh first)") -endif() - -# Gzip-compress the dashboard assets at build time on the host (real zlib, -# not available in the target SDK) and embed the finished bytes — the PS5 -# binary just serves them, it never compresses anything itself. -# find_package(Python3) instead of a hardcoded "python3" command: on Windows -# python3.exe is often a Microsoft Store app-execution-alias stub, not a real -# interpreter, while the actual install is reachable as "python"/"py". -find_package(Python3 COMPONENTS Interpreter REQUIRED) - -foreach(_ASSET html css js) - execute_process( - COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tools/gen_gzip_header.py" - "${CMAKE_CURRENT_SOURCE_DIR}/src/dashboard_${_ASSET}.inc" - "${CMAKE_CURRENT_BINARY_DIR}/dashboard_${_ASSET}_gz.h" - "g_dashboard_${_ASSET}_gz" - RESULT_VARIABLE _GZ_RC - ) - if(NOT _GZ_RC EQUAL 0) - message(FATAL_ERROR "Failed to gzip-compress dashboard_${_ASSET}.inc for embedding") - endif() -endforeach() - -file(GLOB CHEATRUNNER_SRC CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c" - "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" -) - -# --- Hotkey injected payload ------------------------------------------------ -# A separate PIE executable, built as its own target then embedded into -# CheatRunner.elf as a byte array and written into SceShellUI via elfldr_exec. -add_executable(cr_getdata_payload - src/payload/cr_getdata_payload.c - src/payload/cr_detour.c - src/payload/hde64.c -) -set_target_properties(cr_getdata_payload PROPERTIES - OUTPUT_NAME cr_getdata_payload.elf - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/payload" -) -target_include_directories(cr_getdata_payload PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/src" - "${CMAKE_CURRENT_SOURCE_DIR}/src/payload" -) -target_compile_options(cr_getdata_payload PRIVATE -fPIE -Wall -Wextra -O2) -target_link_options(cr_getdata_payload PRIVATE "-Wl,--allow-multiple-definition") -target_link_libraries(cr_getdata_payload PRIVATE kernel_sys) -if(CMAKE_STRIP) - add_custom_command(TARGET cr_getdata_payload POST_BUILD - COMMAND ${CMAKE_STRIP} --strip-all $ - ) -endif() - -set(_GETDATA_BLOB_HEADER "${CMAKE_CURRENT_BINARY_DIR}/cr_getdata_payload_blob.h") -add_custom_command( - OUTPUT "${_GETDATA_BLOB_HEADER}" - COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tools/gen_blob_header.py" - "$" - "${_GETDATA_BLOB_HEADER}" - "g_cr_getdata_payload_elf" - DEPENDS cr_getdata_payload - COMMENT "Embedding cr_getdata_payload.elf as a byte array" -) -add_custom_target(cr_getdata_payload_blob DEPENDS "${_GETDATA_BLOB_HEADER}") - -add_executable(CheatRunner - ${CHEATRUNNER_SRC} - src/third_party/cJSON.c - src/third_party/stb_impl.c - src/third_party/mc4/aes.c - src/third_party/mc4/base64.c - src/third_party/mc4/mc4decrypter.c -) - -set_target_properties(CheatRunner PROPERTIES - OUTPUT_NAME CheatRunner.elf -) - -add_dependencies(CheatRunner cr_getdata_payload_blob) - -target_include_directories(CheatRunner PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") -target_include_directories(CheatRunner PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") -target_compile_options(CheatRunner PRIVATE -Wall -Wextra -O2) -target_compile_definitions(CheatRunner PRIVATE CHEATRUNNER_VERSION="${CHEATRUNNER_VERSION}") -target_link_options(CheatRunner PRIVATE "-Wl,--allow-multiple-definition") -target_compile_definitions(CheatRunner PRIVATE CHEATRUNNER_HAVE_BROWSER_OPEN=1) - -set(CHEATRUNNER_LIBS - kernel_sys - SceSystemService - SceUserService - SceAppInstUtil - SceHttp - SceSsl - SceNet - ScePad - pthread -) - -# ps5-payload-sdk exposes sceLncUtil* through libSceSystemService. -# Do not link -lSceLncUtil: many SDK bundles do not ship a separate library, -# but libSceSystemService contains the needed stubs. -target_compile_definitions(CheatRunner PRIVATE - CHEATRUNNER_HAVE_SCE_LNCUTIL=1 - CHEATRUNNER_HAVE_SCE_USER_LIST=1 -) -if(_HAVE_TILE_PKG) - target_compile_definitions(CheatRunner PRIVATE CHEATRUNNER_HAVE_TILE_PKG=1) -endif() -message(STATUS "Using sceLncUtil* symbols from SceSystemService") -message(STATUS "sceUserServiceGetLoginUserIdList: enabled") - -# SQLite-backed app.db scanner (primary game list, falls back to folder scan). -# -# The ps5-payload-sdk does not ship libsqlite3. To enable: -# 1. Download the amalgamation from https://sqlite.org/download.html -# (sqlite-amalgamation-*.zip → sqlite3.c + sqlite3.h) -# 2. Place both files in src/third_party/ -# 3. Re-run cmake with -DCHEATRUNNER_SQLITE_BUNDLED=ON -# (or flip the option(... OFF) below to ON before configuring) -# -option(CHEATRUNNER_SQLITE_BUNDLED "Bundle sqlite3 amalgamation (src/third_party/sqlite3.c)" OFF) -if(CHEATRUNNER_SQLITE_BUNDLED) - if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/third_party/sqlite3.c") - message(FATAL_ERROR "CHEATRUNNER_SQLITE_BUNDLED=ON but src/third_party/sqlite3.c not found. " - "Download the amalgamation from https://sqlite.org/download.html") - endif() - target_sources(CheatRunner PRIVATE src/third_party/sqlite3.c) - target_compile_definitions(CheatRunner PRIVATE - CHEATRUNNER_HAVE_SQLITE_APPDB=1 - SQLITE_THREADSAFE=0 - SQLITE_DEFAULT_MEMSTATUS=0 - SQLITE_OMIT_LOAD_EXTENSION - ) - message(STATUS "app.db scanner: SQLite bundled from src/third_party/sqlite3.c") -else() - message(STATUS "app.db scanner: disabled (folder fallback only) — see CMakeLists.txt to enable") -endif() - -target_link_libraries(CheatRunner PRIVATE ${CHEATRUNNER_LIBS}) - -if(CMAKE_STRIP) - add_custom_command(TARGET CheatRunner POST_BUILD - COMMAND ${CMAKE_STRIP} --strip-all $ - ) -endif() diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9c162ad --- /dev/null +++ b/Makefile @@ -0,0 +1,129 @@ +# Standalone Makefile for CheatRunner.elf — compiles directly with the PS5 +# payload SDK toolchain. +# +# Usage: +# make # build build-make/CheatRunner.elf +# make clean +# make SQLITE=1 # force-enable bundled sqlite3 (auto-detected otherwise) +# make SQLITE=0 # force-disable it +# PS5_PAYLOAD_SDK=/path/to/sdk make + +VERSION := 0.17.1 + +BUILD_DIR := build-make +GENDIR := $(BUILD_DIR)/gen +OBJDIR := $(BUILD_DIR)/obj +ELF := $(BUILD_DIR)/CheatRunner.elf + +# ---------------------------------------------------------------- SDK resolve +PS5_PAYLOAD_SDK ?= +SDK_ROOT := $(patsubst %/toolchain/prospero.cmake,%,$(firstword \ + $(wildcard $(PS5_PAYLOAD_SDK)/toolchain/prospero.cmake) \ + $(wildcard ../../ps5-payload-sdk/toolchain/prospero.cmake) \ + $(wildcard ps5-payload-sdk/toolchain/prospero.cmake) \ + $(wildcard /opt/ps5-payload-sdk/toolchain/prospero.cmake))) + +ifeq ($(SDK_ROOT),) +$(error PS5 payload SDK not found. Set PS5_PAYLOAD_SDK, or place it at ../../ps5-payload-sdk, ./ps5-payload-sdk, or /opt/ps5-payload-sdk) +endif + +CC := $(SDK_ROOT)/bin/prospero-clang +CXX := $(SDK_ROOT)/bin/prospero-clang++ +STRIP := $(SDK_ROOT)/bin/prospero-strip + +# ---------------------------------------------------------------- sources +SRC_C := $(wildcard src/*.c) \ + src/third_party/cJSON.c \ + src/third_party/stb_impl.c \ + src/third_party/mc4/aes.c \ + src/third_party/mc4/base64.c \ + src/third_party/mc4/mc4decrypter.c +SRC_CPP := $(wildcard src/*.cpp) + +SQLITE ?= $(if $(and $(wildcard src/third_party/sqlite3.c),$(wildcard src/third_party/sqlite3.h)),1,0) +ifeq ($(SQLITE),1) +SRC_C += src/third_party/sqlite3.c +endif + +OBJ_C := $(patsubst src/%.c,$(OBJDIR)/%.o,$(SRC_C)) +OBJ_CPP := $(patsubst src/%.cpp,$(OBJDIR)/%.o,$(SRC_CPP)) +OBJS := $(OBJ_C) $(OBJ_CPP) + +# ---------------------------------------------------------------- generated headers +PNG_SRC := $(wildcard CheatRunner.png) +PKG_SRC := $(wildcard dist/CheatRunner.pkg) +HAVE_TILE_PKG := $(if $(PKG_SRC),1,0) + +PAYLOAD_ELF := $(BUILD_DIR)/payload/cr_getdata_payload.elf +PAYLOAD_SRC := src/payload/cr_getdata_payload.c src/payload/cr_detour.c src/payload/hde64.c + +GEN_HEADERS := $(GENDIR)/cr_getdata_payload_blob.h $(GENDIR)/cheatrunner_png.h $(GENDIR)/cheatrunner_tile_pkg.h \ + $(GENDIR)/dashboard_html_gz.h $(GENDIR)/dashboard_css_gz.h $(GENDIR)/dashboard_js_gz.h + +# ---------------------------------------------------------------- flags +DEFINES := -DCHEATRUNNER_VERSION=\"$(VERSION)\" \ + -DCHEATRUNNER_HAVE_BROWSER_OPEN=1 \ + -DCHEATRUNNER_HAVE_SCE_LNCUTIL=1 \ + -DCHEATRUNNER_HAVE_SCE_USER_LIST=1 +ifeq ($(HAVE_TILE_PKG),1) +DEFINES += -DCHEATRUNNER_HAVE_TILE_PKG=1 +endif +ifeq ($(SQLITE),1) +DEFINES += -DCHEATRUNNER_HAVE_SQLITE_APPDB=1 -DSQLITE_THREADSAFE=0 \ + -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_OMIT_LOAD_EXTENSION +endif + +INCLUDES := -I$(GENDIR) -Isrc +CFLAGS := -fPIE -Wall -Wextra -O2 $(INCLUDES) $(DEFINES) +CXXFLAGS := $(CFLAGS) +LDFLAGS := -Wl,--allow-multiple-definition +LIBS := -lkernel_sys -lSceSystemService -lSceUserService -lSceAppInstUtil \ + -lSceHttp -lSceSsl -lSceNet -lScePad -lpthread + +.PHONY: all clean + +all: $(ELF) + +$(ELF): $(OBJS) | $(BUILD_DIR) + $(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + @if [ -x "$(STRIP)" ]; then $(STRIP) --strip-all $@; fi + +$(OBJDIR)/%.o: src/%.c $(GEN_HEADERS) + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c $< -o $@ + +$(OBJDIR)/%.o: src/%.cpp $(GEN_HEADERS) + @mkdir -p $(dir $@) + $(CXX) $(CXXFLAGS) -c $< -o $@ + +# Hotkey payload: built as its own PIE ELF, then embedded into CheatRunner.elf +$(PAYLOAD_ELF): $(PAYLOAD_SRC) | $(BUILD_DIR) + @mkdir -p $(dir $@) + $(CC) -fPIE -Wall -Wextra -O2 -Isrc -Isrc/payload $(LDFLAGS) -o $@ $(PAYLOAD_SRC) -lkernel_sys + @if [ -x "$(STRIP)" ]; then $(STRIP) --strip-all $@; fi + +$(GENDIR)/cr_getdata_payload_blob.h: $(PAYLOAD_ELF) tools/gen_blob_header.py | $(GENDIR) + python3 tools/gen_blob_header.py $< $@ g_cr_getdata_payload_elf + +$(GENDIR)/cheatrunner_png.h: $(PNG_SRC) | $(GENDIR) + @if [ -f CheatRunner.png ]; then \ + python3 -c "d=open('CheatRunner.png','rb').read(); open('$@','w').write('static const unsigned char g_cheatrunner_png[] = {'+','.join(str(b) for b in d)+'};\n')"; \ + else \ + printf '%s\n' 'static const unsigned char g_cheatrunner_png[] = {0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,0x0D,0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x06,0x00,0x00,0x00,0x1F,0x15,0xC4,0x89,0x00,0x00,0x00,0x0D,0x49,0x44,0x41,0x54,0x78,0x9C,0x63,0x00,0x01,0x00,0x00,0x05,0x00,0x01,0x0D,0x0A,0x2D,0xB4,0x00,0x00,0x00,0x00,0x49,0x45,0x4E,0x44,0xAE,0x42,0x60,0x82};' > $@; \ + fi + +$(GENDIR)/cheatrunner_tile_pkg.h: $(PKG_SRC) | $(GENDIR) + @if [ -f dist/CheatRunner.pkg ]; then \ + python3 -c "d=open('dist/CheatRunner.pkg','rb').read(); open('$@','w').write('static const unsigned char g_cheatrunner_tile_pkg[] = {'+','.join(str(b) for b in d)+'};\nstatic const unsigned long g_cheatrunner_tile_pkg_len = %du;\n'%len(d))"; \ + else \ + printf '/* dist/CheatRunner.pkg not present -- auto-install disabled */\n' > $@; \ + fi + +$(GENDIR)/dashboard_%_gz.h: src/dashboard_%.inc tools/gen_gzip_header.py | $(GENDIR) + python3 tools/gen_gzip_header.py $< $@ g_dashboard_$*_gz + +$(GENDIR) $(BUILD_DIR): + @mkdir -p $@ + +clean: + rm -rf $(BUILD_DIR) diff --git a/README.md b/README.md index 50da003..2d87325 100644 --- a/README.md +++ b/README.md @@ -281,7 +281,7 @@ Recommended project layout: CheatRunner/ ├── CheatRunnerPayload/ │ ├── src/ -│ ├── CMakeLists.txt +│ ├── Makefile │ └── build-cheatrunner.ps1 └── PS5-Payload-dev/ └── sdk-master/ diff --git a/src/cr_api.c b/src/cr_api.c index 173a1ca..7cf83d1 100644 --- a/src/cr_api.c +++ b/src/cr_api.c @@ -64,7 +64,7 @@ #endif #ifndef CHEATRUNNER_VERSION -#define CHEATRUNNER_VERSION "0.17" +#define CHEATRUNNER_VERSION "0.17.1" #endif #define MAX_GAMES CR_APPDB_MAX_GAMES diff --git a/src/cr_api_dashboard.c b/src/cr_api_dashboard.c index 5b882c7..58be70d 100644 --- a/src/cr_api_dashboard.c +++ b/src/cr_api_dashboard.c @@ -53,7 +53,7 @@ cr_api_dashboard_handle(int fd, const char *method, const char *path, if (!strcmp(path, "/cache.appcache")) { static const char appcache[] = "CACHE MANIFEST\n" - "# CheatRunner v0.17\n" + "# CheatRunner v0.17.1\n" "# Build: " __DATE__ " " __TIME__ "\n" "\n" "CACHE:\n" diff --git a/src/main.c b/src/main.c index 17d2919..669fc88 100644 --- a/src/main.c +++ b/src/main.c @@ -30,7 +30,7 @@ #include "cr_tile_pkg.h" #ifndef CHEATRUNNER_VERSION -#define CHEATRUNNER_VERSION "0.17" +#define CHEATRUNNER_VERSION "0.17.1" #endif /* Async-signal-safe crash handler: writes a one-line entry to the crash log diff --git a/tools/gen_blob_header.py b/tools/gen_blob_header.py new file mode 100644 index 0000000..d081047 --- /dev/null +++ b/tools/gen_blob_header.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# Build-time helper: embeds a binary file as a static C byte array. +# +# Usage: gen_blob_header.py + +import sys + + +def main(): + blob_path, header_path, array_name = sys.argv[1:4] + with open(blob_path, "rb") as f: + data = f.read() + + with open(header_path, "w") as f: + f.write("static const unsigned char %s[] = {\n" % array_name) + for i in range(0, len(data), 20): + f.write(",".join(str(b) for b in data[i:i + 20])) + f.write(",\n") + f.write("};\n") + + +if __name__ == "__main__": + main() diff --git a/tools/gen_gzip_header.py b/tools/gen_gzip_header.py new file mode 100644 index 0000000..c394be2 --- /dev/null +++ b/tools/gen_gzip_header.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# Build-time helper: extracts a dashboard .inc asset's exact byte content by +# compiling and running it through the host C compiler (so C string-escape +# parsing is never reimplemented by hand), gzip-compresses it, and writes a +# header with the compressed bytes as a static C array. +# +# Usage: gen_gzip_header.py + +import gzip +import os +import subprocess +import sys +import tempfile + + +def extract_raw_bytes(inc_path): + inc_dir = os.path.dirname(os.path.abspath(inc_path)) + inc_name = os.path.basename(inc_path) + with tempfile.TemporaryDirectory() as td: + src = os.path.join(td, "dump.c") + exe = os.path.join(td, "dump") + with open(src, "w") as f: + f.write('#include \n') + f.write('static const char DATA[] =\n#include "%s"\n;\n' % inc_name) + f.write('int main(void) { fwrite(DATA, 1, sizeof(DATA) - 1, stdout); return 0; }\n') + subprocess.run(["cc", "-I", inc_dir, src, "-o", exe], check=True) + return subprocess.run([exe], check=True, stdout=subprocess.PIPE).stdout + + +def main(): + inc_path, header_path, array_name = sys.argv[1:4] + raw = extract_raw_bytes(inc_path) + gz = gzip.compress(raw, compresslevel=9, mtime=0) + + with open(header_path, "w") as f: + f.write("static const unsigned char %s[] = {\n" % array_name) + for i in range(0, len(gz), 20): + f.write(",".join(str(b) for b in gz[i:i + 20])) + f.write(",\n") + f.write("};\n") + f.write("static const unsigned long %s_len = %dul;\n" % (array_name, len(gz))) + f.write("static const unsigned long %s_raw_len = %dul;\n" % (array_name, len(raw))) + + +if __name__ == "__main__": + main()