/* * Thin C wrapper around mspack's LZX decompressor for use from Rust FFI. * This provides a simple buffer-to-buffer decompression function. */ #include #include #include #include /* Stub for xenia_log (referenced by lzxd.c debug macros) */ void xenia_log(const char *fmt, ...) { (void)fmt; } /* Pull in mspack headers from xenia's third_party */ #define HAVE_CONFIG_H #include "config.h" #include "mspack.h" #include "system.h" #include "lzx.h" /* Memory-backed file for mspack I/O */ typedef struct { struct mspack_system sys; void *buffer; off_t buffer_size; off_t offset; } mspack_memory_file; static struct mspack_file *mem_open(struct mspack_system *self, const char *fn, int mode) { (void)self; (void)fn; (void)mode; return NULL; } static void mem_close(struct mspack_file *file) { (void)file; } static int mem_read(struct mspack_file *file, void *buffer, int chars) { mspack_memory_file *memfile = (mspack_memory_file *)file; off_t remaining = memfile->buffer_size - memfile->offset; off_t total = (off_t)chars < remaining ? (off_t)chars : remaining; memcpy(buffer, (uint8_t *)memfile->buffer + memfile->offset, total); memfile->offset += total; return (int)total; } static int mem_write(struct mspack_file *file, void *buffer, int chars) { mspack_memory_file *memfile = (mspack_memory_file *)file; off_t remaining = memfile->buffer_size - memfile->offset; off_t total = (off_t)chars < remaining ? (off_t)chars : remaining; memcpy((uint8_t *)memfile->buffer + memfile->offset, buffer, total); memfile->offset += total; return (int)total; } static int mem_seek(struct mspack_file *file, off_t offset, int mode) { (void)file; (void)offset; (void)mode; return -1; } static off_t mem_tell(struct mspack_file *file) { (void)file; return 0; } static void mem_msg(struct mspack_file *file, const char *format, ...) { (void)file; (void)format; } static void *mem_alloc(struct mspack_system *self, size_t bytes) { (void)self; return calloc(bytes, 1); } static void mem_free(void *ptr) { free(ptr); } static void mem_copy(void *src, void *dest, size_t bytes) { memcpy(dest, src, bytes); } /* * Decompress LZX data from a memory buffer. * Returns 0 on success, non-zero on error. */ int xenia_lzx_decompress( const void *lzx_data, uint32_t lzx_len, void *dest, uint32_t dest_len, uint32_t window_size) { /* Calculate window_bits from window_size (find the bit position) */ uint32_t window_bits = 0; uint32_t tmp = window_size; while (tmp > 1) { tmp >>= 1; window_bits++; } if ((1u << window_bits) != window_size || window_bits < 15 || window_bits > 21) { return 1; } /* Set up mspack memory system */ struct mspack_system sys; memset(&sys, 0, sizeof(sys)); sys.open = mem_open; sys.close = mem_close; sys.read = mem_read; sys.write = mem_write; sys.seek = mem_seek; sys.tell = mem_tell; sys.message = mem_msg; sys.alloc = mem_alloc; sys.free = mem_free; sys.copy = mem_copy; mspack_memory_file src_file; memset(&src_file, 0, sizeof(src_file)); src_file.buffer = (void *)lzx_data; src_file.buffer_size = (off_t)lzx_len; src_file.offset = 0; mspack_memory_file dst_file; memset(&dst_file, 0, sizeof(dst_file)); dst_file.buffer = dest; dst_file.buffer_size = (off_t)dest_len; dst_file.offset = 0; struct lzxd_stream *lzxd = lzxd_init( &sys, (struct mspack_file *)&src_file, (struct mspack_file *)&dst_file, (int)window_bits, 0, /* reset_interval: 0 = never reset */ 0x8000, /* input_buffer_size */ (off_t)dest_len, 0 /* is_delta */ ); if (!lzxd) { return 2; } int result = lzxd_decompress(lzxd, (off_t)dest_len); lzxd_free(lzxd); return result; }