diff --git a/src/xenia/cpu/lzx.cc b/src/xenia/cpu/lzx.cc new file mode 100644 index 000000000..09602f2d1 --- /dev/null +++ b/src/xenia/cpu/lzx.cc @@ -0,0 +1,180 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/cpu/lzx.h" + +#include + +#include "xenia/base/byte_order.h" +#include "xenia/base/logging.h" +#include "xenia/base/math.h" +#include "xenia/base/memory.h" +#include "xenia/kernel/util/xex2_info.h" + +#include "third_party/mspack/lzx.h" +#include "third_party/mspack/mspack.h" + +typedef struct mspack_memory_file_t { + struct mspack_system sys; + void* buffer; + off_t buffer_size; + off_t offset; +} mspack_memory_file; +mspack_memory_file* mspack_memory_open(struct mspack_system* sys, void* buffer, + const size_t buffer_size) { + assert_true(buffer_size < INT_MAX); + if (buffer_size >= INT_MAX) { + return NULL; + } + mspack_memory_file* memfile = + (mspack_memory_file*)calloc(1, sizeof(mspack_memory_file)); + if (!memfile) { + return NULL; + } + memfile->buffer = buffer; + memfile->buffer_size = (off_t)buffer_size; + memfile->offset = 0; + return memfile; +} +void mspack_memory_close(mspack_memory_file* file) { + mspack_memory_file* memfile = (mspack_memory_file*)file; + free(memfile); +} +int mspack_memory_read(struct mspack_file* file, void* buffer, int chars) { + mspack_memory_file* memfile = (mspack_memory_file*)file; + const off_t remaining = memfile->buffer_size - memfile->offset; + const off_t total = std::min(static_cast(chars), remaining); + memcpy(buffer, (uint8_t*)memfile->buffer + memfile->offset, total); + memfile->offset += total; + return (int)total; +} +int mspack_memory_write(struct mspack_file* file, void* buffer, int chars) { + mspack_memory_file* memfile = (mspack_memory_file*)file; + const off_t remaining = memfile->buffer_size - memfile->offset; + const off_t total = std::min(static_cast(chars), remaining); + memcpy((uint8_t*)memfile->buffer + memfile->offset, buffer, total); + memfile->offset += total; + return (int)total; +} +void* mspack_memory_alloc(struct mspack_system* sys, size_t chars) { + return calloc(chars, 1); +} +void mspack_memory_free(void* ptr) { free(ptr); } +void mspack_memory_copy(void* src, void* dest, size_t chars) { + memcpy(dest, src, chars); +} +struct mspack_system* mspack_memory_sys_create() { + struct mspack_system* sys = + (struct mspack_system*)calloc(1, sizeof(struct mspack_system)); + if (!sys) { + return NULL; + } + sys->read = mspack_memory_read; + sys->write = mspack_memory_write; + sys->alloc = mspack_memory_alloc; + sys->free = mspack_memory_free; + sys->copy = mspack_memory_copy; + return sys; +} +void mspack_memory_sys_destroy(struct mspack_system* sys) { free(sys); } + +int lzx_decompress(const void* lzx_data, size_t lzx_len, void* dest, + size_t dest_len, uint32_t window_size, void* window_data, + size_t window_data_len) { + uint32_t window_bits = 0; + uint32_t temp_sz = window_size; + for (size_t m = 0; m < 32; m++, window_bits++) { + temp_sz >>= 1; + if (temp_sz == 0x00000000) { + break; + } + } + + int result_code = 1; + + mspack_system* sys = mspack_memory_sys_create(); + mspack_memory_file* lzxsrc = + mspack_memory_open(sys, (void*)lzx_data, lzx_len); + mspack_memory_file* lzxdst = mspack_memory_open(sys, dest, dest_len); + lzxd_stream* lzxd = + lzxd_init(sys, (struct mspack_file*)lzxsrc, (struct mspack_file*)lzxdst, + window_bits, 0, 0x8000, (off_t)dest_len, 0); + + if (lzxd) { + if (window_data) { + // zero the window and then copy window_data to the end of it + memset(lzxd->window, 0, window_data_len); + memcpy(lzxd->window + (window_size - window_data_len), window_data, + window_data_len); + } + + result_code = lzxd_decompress(lzxd, (off_t)dest_len); + + lzxd_free(lzxd); + lzxd = NULL; + } + if (lzxsrc) { + mspack_memory_close(lzxsrc); + lzxsrc = NULL; + } + if (lzxdst) { + mspack_memory_close(lzxdst); + lzxdst = NULL; + } + if (sys) { + mspack_memory_sys_destroy(sys); + sys = NULL; + } + + return result_code; +} + +int lzxdelta_apply_patch(xe::xex2_delta_patch* patch, size_t patch_len, + uint32_t window_size, void* dest) { + void* patch_end = (char*)patch + patch_len; + auto* cur_patch = patch; + + while (patch_end > cur_patch) { + int patch_sz = -4; // 0 byte patches need us to remove 4 byte from next + // patch addr because of patch_data field + if (cur_patch->compressed_len == 0 && cur_patch->uncompressed_len == 0 && + cur_patch->new_addr == 0 && cur_patch->old_addr == 0) + break; + switch (cur_patch->compressed_len) { + case 0: // fill with 0 + memset((char*)dest + cur_patch->new_addr, 0, + cur_patch->uncompressed_len); + break; + case 1: // copy from old -> new + memcpy((char*)dest + cur_patch->new_addr, + (char*)dest + cur_patch->old_addr, cur_patch->uncompressed_len); + break; + default: // delta patch + patch_sz = + cur_patch->compressed_len - 4; // -4 because of patch_data field + + int result = lzx_decompress( + cur_patch->patch_data, cur_patch->compressed_len, + (char*)dest + cur_patch->new_addr, cur_patch->uncompressed_len, + window_size, (char*)dest + cur_patch->old_addr, + cur_patch->uncompressed_len); + + if (result) { + return result; + } + break; + } + + cur_patch++; + cur_patch = (xe::xex2_delta_patch*)((char*)cur_patch + + patch_sz); // TODO: make this less ugly + } + + return 0; +} diff --git a/src/xenia/cpu/lzx.h b/src/xenia/cpu/lzx.h new file mode 100644 index 000000000..ea47c220f --- /dev/null +++ b/src/xenia/cpu/lzx.h @@ -0,0 +1,29 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_CPU_LZX_H_ +#define XENIA_CPU_LZX_H_ + +#include +#include + +#include "xenia/cpu/module.h" + +namespace xe { +struct xex2_delta_patch; +} // namespace xe + +int lzx_decompress(const void* lzx_data, size_t lzx_len, void* dest, + size_t dest_len, uint32_t window_size, void* window_data, + size_t window_data_len); + +int lzxdelta_apply_patch(xe::xex2_delta_patch* patch, size_t patch_len, + uint32_t window_size, void* dest); + +#endif // XENIA_CPU_XEX_MODULE_H_ diff --git a/src/xenia/cpu/xex_module.cc b/src/xenia/cpu/xex_module.cc index e14d255bd..8f9e0be21 100644 --- a/src/xenia/cpu/xex_module.cc +++ b/src/xenia/cpu/xex_module.cc @@ -17,6 +17,7 @@ #include "xenia/base/memory.h" #include "xenia/cpu/cpu_flags.h" #include "xenia/cpu/export_resolver.h" +#include "xenia/cpu/lzx.h" #include "xenia/cpu/processor.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/xmodule.h" @@ -24,8 +25,6 @@ #include "third_party/crypto/TinySHA1.hpp" #include "third_party/crypto/rijndael-alg-fst.c" #include "third_party/crypto/rijndael-alg-fst.h" -#include "third_party/mspack/lzx.h" -#include "third_party/mspack/mspack.h" #include "third_party/pe/pe_image.h" static const uint8_t xe_xex2_retail_key[16] = { @@ -35,165 +34,6 @@ static const uint8_t xe_xex2_devkit_key[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -typedef struct mspack_memory_file_t { - struct mspack_system sys; - void* buffer; - off_t buffer_size; - off_t offset; -} mspack_memory_file; -mspack_memory_file* mspack_memory_open(struct mspack_system* sys, void* buffer, - const size_t buffer_size) { - assert_true(buffer_size < INT_MAX); - if (buffer_size >= INT_MAX) { - return NULL; - } - mspack_memory_file* memfile = - (mspack_memory_file*)calloc(1, sizeof(mspack_memory_file)); - if (!memfile) { - return NULL; - } - memfile->buffer = buffer; - memfile->buffer_size = (off_t)buffer_size; - memfile->offset = 0; - return memfile; -} -void mspack_memory_close(mspack_memory_file* file) { - mspack_memory_file* memfile = (mspack_memory_file*)file; - free(memfile); -} -int mspack_memory_read(struct mspack_file* file, void* buffer, int chars) { - mspack_memory_file* memfile = (mspack_memory_file*)file; - const off_t remaining = memfile->buffer_size - memfile->offset; - const off_t total = std::min(static_cast(chars), remaining); - memcpy(buffer, (uint8_t*)memfile->buffer + memfile->offset, total); - memfile->offset += total; - return (int)total; -} -int mspack_memory_write(struct mspack_file* file, void* buffer, int chars) { - mspack_memory_file* memfile = (mspack_memory_file*)file; - const off_t remaining = memfile->buffer_size - memfile->offset; - const off_t total = std::min(static_cast(chars), remaining); - memcpy((uint8_t*)memfile->buffer + memfile->offset, buffer, total); - memfile->offset += total; - return (int)total; -} -void* mspack_memory_alloc(struct mspack_system* sys, size_t chars) { - return calloc(chars, 1); -} -void mspack_memory_free(void* ptr) { free(ptr); } -void mspack_memory_copy(void* src, void* dest, size_t chars) { - memcpy(dest, src, chars); -} -struct mspack_system* mspack_memory_sys_create() { - struct mspack_system* sys = - (struct mspack_system*)calloc(1, sizeof(struct mspack_system)); - if (!sys) { - return NULL; - } - sys->read = mspack_memory_read; - sys->write = mspack_memory_write; - sys->alloc = mspack_memory_alloc; - sys->free = mspack_memory_free; - sys->copy = mspack_memory_copy; - return sys; -} -void mspack_memory_sys_destroy(struct mspack_system* sys) { free(sys); } - -int lzx_decompress(const void* lzx_data, size_t lzx_len, void* dest, - size_t dest_len, uint32_t window_size, void* window_data, - size_t window_data_len) { - uint32_t window_bits = 0; - uint32_t temp_sz = window_size; - for (size_t m = 0; m < 32; m++, window_bits++) { - temp_sz >>= 1; - if (temp_sz == 0x00000000) { - break; - } - } - - int result_code = 1; - - mspack_system* sys = mspack_memory_sys_create(); - mspack_memory_file* lzxsrc = - mspack_memory_open(sys, (void*)lzx_data, lzx_len); - mspack_memory_file* lzxdst = mspack_memory_open(sys, dest, dest_len); - lzxd_stream* lzxd = - lzxd_init(sys, (struct mspack_file*)lzxsrc, (struct mspack_file*)lzxdst, - window_bits, 0, 0x8000, (off_t)dest_len, 0); - - if (lzxd) { - if (window_data) { - // zero the window and then copy window_data to the end of it - memset(lzxd->window, 0, window_data_len); - memcpy(lzxd->window + (window_size - window_data_len), window_data, - window_data_len); - } - - result_code = lzxd_decompress(lzxd, (off_t)dest_len); - - lzxd_free(lzxd); - lzxd = NULL; - } - if (lzxsrc) { - mspack_memory_close(lzxsrc); - lzxsrc = NULL; - } - if (lzxdst) { - mspack_memory_close(lzxdst); - lzxdst = NULL; - } - if (sys) { - mspack_memory_sys_destroy(sys); - sys = NULL; - } - - return result_code; -} - -int lzxdelta_apply_patch(xe::xex2_delta_patch* patch, size_t patch_len, - uint32_t window_size, void* dest) { - void* patch_end = (char*)patch + patch_len; - auto* cur_patch = patch; - - while (patch_end > cur_patch) { - int patch_sz = -4; // 0 byte patches need us to remove 4 byte from next - // patch addr because of patch_data field - if (cur_patch->compressed_len == 0 && cur_patch->uncompressed_len == 0 && - cur_patch->new_addr == 0 && cur_patch->old_addr == 0) - break; - switch (cur_patch->compressed_len) { - case 0: // fill with 0 - memset((char*)dest + cur_patch->new_addr, 0, - cur_patch->uncompressed_len); - break; - case 1: // copy from old -> new - memcpy((char*)dest + cur_patch->new_addr, - (char*)dest + cur_patch->old_addr, cur_patch->uncompressed_len); - break; - default: // delta patch - patch_sz = - cur_patch->compressed_len - 4; // -4 because of patch_data field - - int result = lzx_decompress( - cur_patch->patch_data, cur_patch->compressed_len, - (char*)dest + cur_patch->new_addr, cur_patch->uncompressed_len, - window_size, (char*)dest + cur_patch->old_addr, - cur_patch->uncompressed_len); - - if (result) { - return result; - } - break; - } - - cur_patch++; - cur_patch = (xe::xex2_delta_patch*)((char*)cur_patch + - patch_sz); // TODO: make this less ugly - } - - return 0; -} - void aes_decrypt_buffer(const uint8_t* session_key, const uint8_t* input_buffer, const size_t input_size, uint8_t* output_buffer, const size_t output_size) {