ro: add missing fixes

This commit is contained in:
hexkyz
2026-09-25 01:33:40 +01:00
parent 788546f476
commit 2ae182bd5d
2 changed files with 56 additions and 46 deletions

View File

@@ -40,29 +40,31 @@ namespace ams::util {
/* It's similar to the official lz4frame code, but has additional constraints and uses static work buffers. */
/* Evaluate if we should use lz4frame instead and implement matching frame compression. */
int DecompressLZ4Frame(size_t* out_size, void *dst, size_t dst_size, const void *src, size_t src_size, void *src_work, size_t src_work_size, void *dst_work, size_t dst_work_size) {
const u8 *src_buffer = reinterpret_cast<const u8 *>(src);
u8 *dst_buffer = reinterpret_cast<u8 *>(dst);
/* Destination buffer must be behind source buffer. */
if (dst > src) {
if (dst_buffer > src_buffer) {
std::memset(dst, 0, dst_size);
return -1;
}
const char *src_end = static_cast<const char *>(src) + src_size;
const char *dst_end = static_cast<const char *>(dst) + dst_size;
if ((src_end != dst_end) || (src_work_size != 0x10000) || (dst_work_size != 0x10000)) {
/* Size checks. */
if (((src_buffer + src_size) != (dst_buffer + dst_size)) || (src_work_size != 0x10000) || (dst_work_size != 0x10000)) {
std::memset(dst, 0, dst_size);
return -1;
}
/* Source size must at least include one frame header. */
if (src_size < 7) {
std::memset(dst, 0, dst_size);
return -2;
}
const uint32_t magic = *reinterpret_cast<const uint32_t *>(src);
const uint8_t flg = *reinterpret_cast<const uint8_t *>(src) + 4;
const uint8_t bd = *reinterpret_cast<const uint8_t *>(src) + 5;
const uint8_t header_checksum = *reinterpret_cast<const uint8_t *>(src) + 6;
const u32 magic = *reinterpret_cast<const u32 *>(src_buffer);
const u8 flg = src_buffer[4];
const u8 bd = src_buffer[5];
const u8 header_checksum = src_buffer[6];
/* Check for LZ4F_MAGICNUMBER, validate flags and block size. */
if ((magic != 0x184D2204) || ((flg & 1) != 0) || (flg != 0x60) || (bd != 0x40)) {
@@ -73,8 +75,8 @@ namespace ams::util {
/* TODO: Implement header checksum validation. This requires xxhash, do we want to have xxhash in util? */
AMS_UNUSED(header_checksum);
uint32_t src_pos = 7; /* Skip the header. */
uint32_t dst_pos = 0;
u32 src_pos = 7; /* Skip the header. */
u32 dst_pos = 0;
/* Destination size is too small. */
if (dst_size < src_pos) {
@@ -89,17 +91,17 @@ namespace ams::util {
return -4;
}
const char* src_data_block = reinterpret_cast<const char *>(src) + src_pos;
char* dst_data_block = reinterpret_cast<char *>(dst) + dst_pos;
src_buffer += src_pos;
dst_buffer += dst_pos;
const uint32_t block_header = *reinterpret_cast<const uint32_t *>(src_data_block);
const u32 block_header = *reinterpret_cast<const u32 *>(src_buffer);
/* We've reached the end. */
if (!block_header) {
break;
}
const uint32_t block_size = block_header & 0x7FFFFFFF;
const u32 block_size = block_header & 0x7FFFFFFF;
/* Block size is invalid. */
if (block_size > 0x10000) {
@@ -108,20 +110,20 @@ namespace ams::util {
}
/* Advance the data block. */
src_data_block += sizeof(block_header);
src_buffer += sizeof(block_header);
/* Block size is invalid. */
if ((dst_end - src_data_block) < block_size) {
if (((dst_buffer + dst_size) - src_buffer) < block_size) {
std::memset(dst, 0, dst_size);
return -4;
}
/* Copy the data block to the source work buffer. */
std::memcpy(static_cast<char *>(src_work), src_data_block, block_size);
std::memcpy(static_cast<u8 *>(src_work), src_buffer, block_size);
if ((block_header & 0x80000000) != 0) {
/* Block size is invalid. */
if ((dst_end - dst_data_block) < block_size) {
if (dst_size < block_size) {
std::memset(dst, 0, dst_size);
return -4;
}
@@ -136,10 +138,10 @@ namespace ams::util {
}
/* This is a raw block, copy it. */
std::memmove(dst_data_block, src_data_block, block_size);
std::memmove(dst_buffer, src_buffer, block_size);
} else {
/* This is a compressed block, decompress it. */
int decompressed_size = LZ4_decompress_safe(reinterpret_cast<const char *>(src_work), reinterpret_cast<char *>(dst_work), static_cast<int>(src_work_size), static_cast<int>(dst_work_size));
int decompressed_size = LZ4_decompress_safe(reinterpret_cast<const char *>(src_work), reinterpret_cast<char *>(dst_work), static_cast<int>(block_size), 0x10000);
/* Decompressed size is invalid. */
if (decompressed_size < 1) {
@@ -148,7 +150,7 @@ namespace ams::util {
}
/* Decompressed size is invalid. */
if ((dst_end - dst_data_block) < decompressed_size) {
if (dst_size < static_cast<size_t>(decompressed_size)) {
std::memset(dst, 0, dst_size);
return -4;
}
@@ -163,7 +165,7 @@ namespace ams::util {
}
/* Copy the decompressed data back. */
std::memcpy(dst_data_block, static_cast<char *>(dst_work), decompressed_size);
std::memcpy(dst_buffer, static_cast<u8 *>(dst_work), decompressed_size);
}
/* We've exceeded the destination's size. */