Files
ppsspp/Core/Util/KL4E.h
T
Henrik RydgårdandClaude Opus 5 917cb1b0fc Implement KL4E/KL3E decompression, so firmware modules that use it can load
KL4E is Sony's second compression scheme for ~PSP modules, alongside gzip:
LZ77 tokens where every bit is arithmetic-coded, structurally close to LZMA.
PPSSPP could detect it but not decode it, so any module packed with it failed
to load at all - the loader reached the gzip path and bailed there.

Which scheme a compressed module uses is now decided by the payload's own
magic rather than assuming gzip. On a 6.61 flash0 dump this takes the kd/
modules that load from 126 to 129 of 129; libmp3.prx, libaac.prx and
libmp4.prx were the ones affected, and libmp3.prx decompresses to exactly the
elf_size its PRX header declares.

Two bounds problems in the format are fixed rather than reproduced: the match
copy is unchecked against the output buffer on real hardware, so a crafted
stream can write up to 255 bytes past it, and a long enough distance code
indexes copyDistProbs out of range. Input reads are bounded too - the format
carries no length and trusts the stream to terminate itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 11:06:17 -06:00

42 lines
1.9 KiB
C

// Copyright (c) 2026- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include <cstddef>
#include "Common/CommonTypes.h"
// KL4E / KL3E - Sony's LZ77-with-arithmetic-coding scheme for compressed PSP executables, the
// alternative to gzip inside a ~PSP module. KL3E is the same bitstream with one constant changed.
//
// See docs/KL4E.md for the format.
// Decompresses one KL4E/KL3E stream. `in` points at the five-byte stream header, i.e. *past* the
// four-byte "KL4E"/"KL3E" magic. `inSize` bounds reads so a truncated file can't run off the end.
//
// Returns the number of bytes written, or a negative PSP error code:
// SCE_KERNEL_ERROR_INVALID_SIZE (0x80000104) output didn't fit
// SCE_KERNEL_ERROR_INVALID_FORMAT (0x80000108) stream is malformed
//
// If `end` is non-null it receives a pointer just past the last input byte consumed. (The PSP's
// own routine reports the last byte consumed for stored streams and one past for compressed ones;
// this is deliberately consistent instead, since nothing in PPSSPP depends on the quirk.)
int DecompressKL4E(u8 *out, int outSize, const u8 *in, size_t inSize, const u8 **end, bool isKL3E);
// True if the buffer starts with a "KL4E" or "KL3E" magic. Sets *isKL3E when it does.
bool IsKL4EMagic(const u8 *data, size_t size, bool *isKL3E);