diff --git a/core/libs/prx/libSceAjm.native/CMakeLists.txt b/core/libs/prx/libSceAjm.native/CMakeLists.txt index a231a1529..0119f36b9 100644 --- a/core/libs/prx/libSceAjm.native/CMakeLists.txt +++ b/core/libs/prx/libSceAjm.native/CMakeLists.txt @@ -1,6 +1,9 @@ enable_language(C) set(LIBATRAC9_DIR ${CMAKE_SOURCE_DIR}/3rdparty/LibAtrac9/C/src) +set(LIBATRAC9_PATCHED_DIR ${CMAKE_CURRENT_BINARY_DIR}/atrac9) +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${LIBATRAC9_DIR}/unpack.c) +include(${CMAKE_CURRENT_SOURCE_DIR}/PatchLibAtrac9.cmake) add_library(atrac9 STATIC EXCLUDE_FROM_ALL ${LIBATRAC9_DIR}/band_extension.c ${LIBATRAC9_DIR}/bit_allocation.c @@ -13,9 +16,10 @@ add_library(atrac9 STATIC EXCLUDE_FROM_ALL ${LIBATRAC9_DIR}/quantization.c ${LIBATRAC9_DIR}/scale_factors.c ${LIBATRAC9_DIR}/tables.c - ${LIBATRAC9_DIR}/unpack.c + ${LIBATRAC9_PATCHED_DIR}/unpack.c ${LIBATRAC9_DIR}/utility.c ) +target_include_directories(atrac9 PRIVATE ${LIBATRAC9_DIR}) set_target_properties(atrac9 PROPERTIES POSITION_INDEPENDENT_CODE ON) add_library(libSceAjm.native SHARED EXCLUDE_FROM_ALL @@ -31,6 +35,16 @@ target_link_libraries(libSceAjm.native PRIVATE atrac9 ffmpeg libc libkernel) configure_windows_unwind(libSceAjm.native) if(BUILD_TESTING) + add_test_executable(atrac9_gradient_tests tests/Atrac9Gradient.c ${LIBATRAC9_DIR}/bit_reader.c) + target_include_directories(atrac9_gradient_tests PRIVATE ${LIBATRAC9_PATCHED_DIR} ${LIBATRAC9_DIR}) + target_compile_options(atrac9_gradient_tests PRIVATE -ffunction-sections -fdata-sections) + if(APPLE) + target_link_options(atrac9_gradient_tests PRIVATE LINKER:-dead_strip) + else() + target_link_options(atrac9_gradient_tests PRIVATE LINKER:--gc-sections) + endif() + add_test(NAME atrac9_gradient COMMAND atrac9_gradient_tests) + add_test_executable(guest_ajm_tests ${LIBS_INCLUDE_DIR}/tests/GuestAjm.cpp) target_include_directories(guest_ajm_tests PRIVATE ${LIBS_INCLUDE_DIR}) target_link_libraries(guest_ajm_tests PRIVATE libSceAjm.native libc) diff --git a/core/libs/prx/libSceAjm.native/PatchLibAtrac9.cmake b/core/libs/prx/libSceAjm.native/PatchLibAtrac9.cmake new file mode 100644 index 000000000..e795b3fba --- /dev/null +++ b/core/libs/prx/libSceAjm.native/PatchLibAtrac9.cmake @@ -0,0 +1,10 @@ +file(READ ${LIBATRAC9_DIR}/unpack.c libatrac9Unpack) +set(libatrac9OldGuard "block->GradientEndUnit < 0 || block->GradientEndUnit >= 48") +set(libatrac9NewGuard "block->GradientEndUnit < 0 || block->GradientEndUnit > 31") +string(FIND "${libatrac9Unpack}" "${libatrac9OldGuard}" libatrac9GuardPosition) +if(libatrac9GuardPosition EQUAL -1) + message(FATAL_ERROR "LibAtrac9 gradient guard has changed; review the local bounds fix") +endif() +string(REPLACE "${libatrac9OldGuard}" "${libatrac9NewGuard}" libatrac9Unpack "${libatrac9Unpack}") +file(MAKE_DIRECTORY ${LIBATRAC9_PATCHED_DIR}) +file(WRITE ${LIBATRAC9_PATCHED_DIR}/unpack.c "${libatrac9Unpack}") diff --git a/core/libs/prx/libSceAjm.native/tests/Atrac9Gradient.c b/core/libs/prx/libSceAjm.native/tests/Atrac9Gradient.c new file mode 100644 index 000000000..5ad7595aa --- /dev/null +++ b/core/libs/prx/libSceAjm.native/tests/Atrac9Gradient.c @@ -0,0 +1,36 @@ +#include "unpack.c" +#include + +static void WriteBits(unsigned char* data, int* position, int value, int width) +{ + for (int bit = width - 1; bit >= 0; --bit) + { + int offset = (*position)++; + data[offset / 8] |= (unsigned char)(((value >> bit) & 1) << (7 - offset % 8)); + } +} + +static At9Status GradientStatus(int endUnit) +{ + unsigned char data[4] = {0}; + int position = 0; + WriteBits(data, &position, 0, 2); + WriteBits(data, &position, 0, 6); + WriteBits(data, &position, endUnit - 1, 6); + WriteBits(data, &position, 0, 5); + WriteBits(data, &position, 0, 5); + WriteBits(data, &position, 0, 4); + + Block block = {0}; + BitReaderCxt reader; + InitBitReaderCxt(&reader, data, sizeof(data)); + return ReadGradientParams(&block, &reader); +} + +int main(void) +{ + if (GradientStatus(31) != ERR_SUCCESS) return EXIT_FAILURE; + if (GradientStatus(32) != ERR_UNPACK_GRAD_END_UNIT_OOB) return EXIT_FAILURE; + if (GradientStatus(47) != ERR_UNPACK_GRAD_END_UNIT_OOB) return EXIT_FAILURE; + return EXIT_SUCCESS; +}