Some checks failed
Orchestrator / Commit Message Validation (push) Has been skipped
Orchestrator / Lint (push) Successful in 2m5s
Orchestrator / Windows (x86-64) (push) Failing after 6m13s
Orchestrator / Linux (x86-64) (push) Failing after 20m59s
Orchestrator / Create Release (push) Has been skipped
Major additions to the xenia-rs Rust port: - CPU: ~170 new PPC opcode implementations (FPU, VMX128, 64-bit ALU, load/store variants) - XEX: Full LZX (normal) decompression pipeline with AES-128-CBC decryption via mspack FFI - XEX: Parse file format info, import libraries, and security info AES key from headers - VFS: Rewrite XISO disc image to use seek-based I/O (handles 7GB+ images without loading into memory) - App: Auto-detect ISO files and extract default.xex for all CLI commands - App: Add `info` and `browse` CLI subcommands - Kernel: Expand HLE exports from 14 to 40 stubs (memory, threading, TLS, I/O, video) - Memory: Add bounds checking on all guest memory accesses to prevent segfaults - Types: Add Vec128 array-based accessors (from_u32x4_array, from_f32x4_array, etc.) Tested against Project Sylpheed (USA) disc image - all four CLI commands (browse, info, disasm, exec) work correctly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
144 lines
3.9 KiB
C
144 lines
3.9 KiB
C
/*
|
|
* Thin C wrapper around mspack's LZX decompressor for use from Rust FFI.
|
|
* This provides a simple buffer-to-buffer decompression function.
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
/* 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;
|
|
}
|