├── .gitignore ├── .gitattributes ├── custom_songs.png ├── livearea ├── beat.png ├── bg0.png ├── conf.png ├── icon0.png ├── pic0.png └── template.xml ├── screenshots ├── game.png ├── game2.png ├── game3.png └── game4.png ├── shaders ├── 1.glsl ├── 0.glsl ├── 2.glsl └── 3.glsl ├── loader ├── config.h ├── dialog.h ├── main.h ├── sha1.h ├── so_util.h ├── sha1.c ├── dialog.c ├── ctype_patch.c ├── bass_reimpl.h ├── bass_reimpl.cpp ├── so_util.c └── main.c ├── CMakeLists.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /custom_songs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rinnegatamante/hazard-vita/HEAD/custom_songs.png -------------------------------------------------------------------------------- /livearea/beat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rinnegatamante/hazard-vita/HEAD/livearea/beat.png -------------------------------------------------------------------------------- /livearea/bg0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rinnegatamante/hazard-vita/HEAD/livearea/bg0.png -------------------------------------------------------------------------------- /livearea/conf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rinnegatamante/hazard-vita/HEAD/livearea/conf.png -------------------------------------------------------------------------------- /livearea/icon0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rinnegatamante/hazard-vita/HEAD/livearea/icon0.png -------------------------------------------------------------------------------- /livearea/pic0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rinnegatamante/hazard-vita/HEAD/livearea/pic0.png -------------------------------------------------------------------------------- /screenshots/game.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rinnegatamante/hazard-vita/HEAD/screenshots/game.png -------------------------------------------------------------------------------- /screenshots/game2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rinnegatamante/hazard-vita/HEAD/screenshots/game2.png -------------------------------------------------------------------------------- /screenshots/game3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rinnegatamante/hazard-vita/HEAD/screenshots/game3.png -------------------------------------------------------------------------------- /screenshots/game4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rinnegatamante/hazard-vita/HEAD/screenshots/game4.png -------------------------------------------------------------------------------- /shaders/1.glsl: -------------------------------------------------------------------------------- 1 | 2 | uniform sampler2D _texture; 3 | 4 | void main( 5 | float2 texCoord : TEXCOORD0, 6 | float4 colour : COLOR, 7 | float4 out gl_FragColor : COLOR 8 | ) { 9 | float4 tex = tex2D(_texture, texCoord); 10 | gl_FragColor = tex * colour; 11 | } 12 | -------------------------------------------------------------------------------- /loader/config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H__ 2 | #define __CONFIG_H__ 3 | 4 | //#define DEBUG 5 | 6 | #define LOAD_ADDRESS 0x98000000 7 | 8 | #define MEMORY_NEWLIB_MB 256 9 | #define MEMORY_VITAGL_THRESHOLD_MB 8 10 | 11 | #define SCREEN_W 960 12 | #define SCREEN_H 544 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /loader/dialog.h: -------------------------------------------------------------------------------- 1 | #ifndef __DIALOG_H__ 2 | #define __DIALOG_H__ 3 | 4 | int init_ime_dialog(const char *title, const char *initial_text); 5 | char *get_ime_dialog_result(void); 6 | 7 | int init_msg_dialog(const char *msg); 8 | int get_msg_dialog_result(void); 9 | 10 | void fatal_error(const char *fmt, ...) __attribute__((noreturn)); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /shaders/0.glsl: -------------------------------------------------------------------------------- 1 | 2 | void main( 3 | float2 in_Vertex, 4 | float2 in_TexCoord, 5 | float4 in_Colour, 6 | float4 out colour : COLOR, 7 | float2 out texCoord : TEXCOORD0, 8 | float4 out gl_Position : POSITION 9 | ) { 10 | // pass colour and text coord to fragment shader 11 | colour = in_Colour; 12 | texCoord = in_TexCoord; 13 | 14 | // set vertex position 15 | gl_Position = float4(in_Vertex, 0.0, 1.0); 16 | } 17 | -------------------------------------------------------------------------------- /livearea/template.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bg0.png 6 | 7 | 8 | 9 | beat.png 10 | 11 | 12 | 13 | 14 | psla:-custom 15 | conf.png 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /loader/main.h: -------------------------------------------------------------------------------- 1 | #ifndef __MAIN_H__ 2 | #define __MAIN_H__ 3 | 4 | #include 5 | #include "config.h" 6 | #include "so_util.h" 7 | 8 | extern so_module fahrenheit_mod; 9 | 10 | int debugPrintf(char *text, ...); 11 | 12 | int ret0(); 13 | 14 | int sceKernelChangeThreadCpuAffinityMask(SceUID thid, int cpuAffinityMask); 15 | 16 | SceUID _vshKernelSearchModuleByName(const char *, const void *); 17 | 18 | extern SceTouchPanelInfo panelInfoFront, panelInfoBack; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /shaders/2.glsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | void main( 4 | float2 in_Vertex, 5 | float4 in_Colour, 6 | float2 in_TexCoord, 7 | float in_Rotation, 8 | float2 in_Velocity, 9 | float in_specularPower, 10 | float in_blurPower, 11 | float3 in_replaceColour, 12 | float4 out colour : COLOR, 13 | float4 out texCoords : TEXCOORD0, 14 | float4 out texCoords2 : TEXCOORD1, 15 | float4 out texCoords3 : TEXCOORD2, 16 | float4 out gl_Position : POSITION 17 | ) { 18 | // pass colour and text coord to fragment shader 19 | colour = in_Colour; 20 | 21 | texCoords.xy = in_TexCoord; 22 | texCoords.zw = in_Velocity; 23 | 24 | texCoords2.xyz = in_replaceColour; 25 | texCoords2.w = in_Rotation; 26 | 27 | texCoords3.xy = in_Vertex; 28 | texCoords3.z = in_specularPower; 29 | texCoords3.w = in_blurPower; 30 | 31 | // set vertex position 32 | gl_Position = float4(in_Vertex, 0.0, 1.0); 33 | } 34 | -------------------------------------------------------------------------------- /loader/sha1.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha1.h 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Defines the API for the corresponding SHA1 implementation. 7 | *********************************************************************/ 8 | 9 | #ifndef SHA1_H 10 | #define SHA1_H 11 | 12 | /*************************** HEADER FILES ***************************/ 13 | #include 14 | 15 | /****************************** MACROS ******************************/ 16 | #define SHA1_BLOCK_SIZE 20 // SHA1 outputs a 20 byte digest 17 | 18 | /**************************** DATA TYPES ****************************/ 19 | typedef unsigned char BYTE; // 8-bit byte 20 | typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines 21 | 22 | typedef struct { 23 | BYTE data[64]; 24 | WORD datalen; 25 | unsigned long long bitlen; 26 | WORD state[5]; 27 | WORD k[4]; 28 | } SHA1_CTX; 29 | 30 | /*********************** FUNCTION DECLARATIONS **********************/ 31 | void sha1_init(SHA1_CTX *ctx); 32 | void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len); 33 | void sha1_final(SHA1_CTX *ctx, BYTE hash[]); 34 | 35 | #endif // SHA1_H 36 | -------------------------------------------------------------------------------- /loader/so_util.h: -------------------------------------------------------------------------------- 1 | #ifndef __SO_UTIL_H__ 2 | #define __SO_UTIL_H__ 3 | 4 | #include "elf.h" 5 | 6 | #define ALIGN_MEM(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) 7 | #define MAX_DATA_SEG 4 8 | 9 | typedef struct { 10 | uintptr_t addr; 11 | uintptr_t thumb_addr; 12 | uint32_t orig_instr[2]; 13 | uint32_t patch_instr[2]; 14 | } so_hook; 15 | 16 | typedef struct so_module { 17 | struct so_module *next; 18 | 19 | SceUID patch_blockid, text_blockid, data_blockid[MAX_DATA_SEG]; 20 | uintptr_t patch_base, patch_head, cave_base, cave_head, text_base, data_base[MAX_DATA_SEG]; 21 | size_t patch_size, cave_size, text_size, data_size[MAX_DATA_SEG]; 22 | int n_data; 23 | 24 | Elf32_Ehdr *ehdr; 25 | Elf32_Phdr *phdr; 26 | Elf32_Shdr *shdr; 27 | 28 | Elf32_Dyn *dynamic; 29 | Elf32_Sym *dynsym; 30 | Elf32_Rel *reldyn; 31 | Elf32_Rel *relplt; 32 | 33 | int (** init_array)(void); 34 | uint32_t *hash; 35 | 36 | int num_dynamic; 37 | int num_dynsym; 38 | int num_reldyn; 39 | int num_relplt; 40 | int num_init_array; 41 | 42 | char *soname; 43 | char *shstr; 44 | char *dynstr; 45 | } so_module; 46 | 47 | typedef struct { 48 | char *symbol; 49 | uintptr_t func; 50 | } so_default_dynlib; 51 | 52 | so_hook hook_thumb(uintptr_t addr, uintptr_t dst); 53 | so_hook hook_arm(uintptr_t addr, uintptr_t dst); 54 | so_hook hook_addr(uintptr_t addr, uintptr_t dst); 55 | 56 | void so_flush_caches(so_module *mod); 57 | int so_file_load(so_module *mod, const char *filename, uintptr_t load_addr); 58 | int so_mem_load(so_module *mod, void * buffer, size_t so_size, uintptr_t load_addr); 59 | int so_relocate(so_module *mod); 60 | int so_resolve(so_module *mod, so_default_dynlib *default_dynlib, int size_default_dynlib, int default_dynlib_only); 61 | int so_resolve_with_dummy(so_module *mod, so_default_dynlib *default_dynlib, int size_default_dynlib, int default_dynlib_only); 62 | void so_symbol_fix_ldmia(so_module *mod, const char *symbol); 63 | void so_initialize(so_module *mod); 64 | uintptr_t so_symbol(so_module *mod, const char *symbol); 65 | 66 | #define SO_CONTINUE(type, h, ...) ({ \ 67 | kuKernelCpuUnrestrictedMemcpy((void *)h.addr, h.orig_instr, sizeof(h.orig_instr)); \ 68 | kuKernelFlushCaches((void *)h.addr, sizeof(h.orig_instr)); \ 69 | type r = h.thumb_addr ? ((type(*)())h.thumb_addr)(__VA_ARGS__) : ((type(*)())h.addr)(__VA_ARGS__); \ 70 | kuKernelCpuUnrestrictedMemcpy((void *)h.addr, h.patch_instr, sizeof(h.patch_instr)); \ 71 | kuKernelFlushCaches((void *)h.addr, sizeof(h.patch_instr)); \ 72 | r; \ 73 | }) 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) 4 | if(DEFINED ENV{VITASDK}) 5 | set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file") 6 | else() 7 | message(FATAL_ERROR "Please define VITASDK to point to your SDK path!") 8 | endif() 9 | endif() 10 | 11 | project(hazard C CXX) 12 | include("${VITASDK}/share/vita.cmake" REQUIRED) 13 | set(VITA_APP_NAME "Beat Hazard 2") 14 | set(VITA_TITLEID "BTHAZARD2") 15 | set(VITA_MKSFOEX_FLAGS "-d ATTRIBUTE2=4") 16 | 17 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wl,-q,--wrap,memcpy,--wrap,memmove,--wrap,memset,--allow-multiple-definition -D_GNU_SOURCE -Wall -O3 -fdiagnostics-color=always -fno-optimize-sibling-calls -mfloat-abi=softfp") 18 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -Wno-write-strings -fpermissive -fno-rtti") 19 | 20 | add_executable(hazard 21 | loader/main.c 22 | loader/dialog.c 23 | loader/so_util.c 24 | loader/sha1.c 25 | loader/ctype_patch.c 26 | loader/bass_reimpl.cpp 27 | ) 28 | 29 | target_link_libraries(hazard 30 | -Wl,--whole-archive pthread -Wl,--no-whole-archive 31 | SDL2_mixer 32 | SDL2_image 33 | SDL2_ttf 34 | SDL2_net 35 | freetype 36 | soloud_static 37 | SDL2 38 | png 39 | webp 40 | jpeg 41 | mikmod 42 | z 43 | m 44 | stdc++ 45 | opensles 46 | sndfile 47 | vorbis 48 | vorbisenc 49 | vorbisfile 50 | ogg 51 | FLAC 52 | openal 53 | imgui 54 | vitaGL 55 | vitashark 56 | SceShaccCgExt 57 | mathneon 58 | mpg123 59 | taihen_stub 60 | kubridge_stub 61 | SceNet_stub 62 | SceNetCtl_stub 63 | SceAppMgr_stub 64 | SceAppUtil_stub 65 | SceAudio_stub 66 | SceAudioIn_stub 67 | SceCtrl_stub 68 | SceCommonDialog_stub 69 | SceDisplay_stub 70 | SceFios2_stub 71 | SceGxm_stub 72 | SceIme_stub 73 | SceLibcBridge_stub 74 | SceShaccCg_stub 75 | SceSysmodule_stub 76 | ScePower_stub 77 | SceTouch_stub 78 | SceMotion_stub 79 | SceHid_stub 80 | SceVshBridge_stub 81 | SceKernelDmacmgr_stub 82 | ) 83 | 84 | vita_create_self(eboot.bin hazard UNSAFE) 85 | vita_create_vpk(hazard.vpk ${VITA_TITLEID} eboot.bin 86 | VERSION ${VITA_VERSION} 87 | NAME ${VITA_APP_NAME} 88 | FILE ${CMAKE_SOURCE_DIR}/livearea/icon0.png sce_sys/icon0.png 89 | ${CMAKE_SOURCE_DIR}/livearea/pic0.png sce_sys/pic0.png 90 | ${CMAKE_SOURCE_DIR}/livearea/bg0.png sce_sys/livearea/contents/bg0.png 91 | ${CMAKE_SOURCE_DIR}/livearea/beat.png sce_sys/livearea/contents/beat.png 92 | ${CMAKE_SOURCE_DIR}/livearea/conf.png sce_sys/livearea/contents/conf.png 93 | ${CMAKE_SOURCE_DIR}/livearea/template.xml sce_sys/livearea/contents/template.xml 94 | ${CMAKE_SOURCE_DIR}/shaders shaders 95 | ) 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Beat Hazard 2 Vita 2 | 3 |

4 | 5 | This is a wrapper/port of Beat Hazard 2 for the *PS Vita*. 6 | 7 | The port works by loading the official Android ARMv7 executable in memory, resolving its imports with native functions and patching it in order to properly run. 8 | By doing so, it's basically as if we emulate a minimalist Android environment in which we run natively the executable as it is. 9 | 10 | ## Changelog 11 | 12 | ### v1.0 13 | 14 | - Initial Release. 15 | 16 | ## Setup Instructions (For End Users) 17 | 18 | - Install [kubridge](https://github.com/TheOfficialFloW/kubridge/releases/) and [FdFix](https://github.com/TheOfficialFloW/FdFix/releases/) by copying `kubridge.skprx` and `fd_fix.skprx` to your taiHEN plugins folder (usually `ux0:tai`) and adding two entries to your `config.txt` under `*KERNEL`: 19 | 20 | ``` 21 | *KERNEL 22 | ux0:tai/kubridge.skprx 23 | ux0:tai/fd_fix.skprx 24 | ``` 25 | 26 | **Note** Don't install fd_fix.skprx if you're using rePatch plugin 27 | 28 | - **Optional**: Install [PSVshell](https://github.com/Electry/PSVshell/releases) to overclock your device to 500Mhz. 29 | - Install `libshacccg.suprx`, if you don't have it already, by following [this guide](https://samilops2.gitbook.io/vita-troubleshooting-guide/shader-compiler/extract-libshacccg.suprx). 30 | - Install the vpk from Release tab. 31 | - Obtain your copy of *Beat Hazard 2* legally for Android in form of an `.apk` file. 32 | - Open the apk with your zip explorer and extract the files `libc++_shared.so`, `libSDL2_ttf.so`, `libtags.so` and `libmain.so` from the `lib/armeabi-v7a` folder to `ux0:data/hazard`. 33 | - Extract the `assets` folder from inside the apk to `ux0:data/hazard`. 34 | 35 | ## How to use custom songs 36 | 37 | Beat Hazard 2 features support for custom songs. On the Vita port, songs in `.wav`, `.mp3`, `.flac` and `.ogg` formats are supported. 38 | 39 | Songs must be placed in `ux0:data/hazard/songs` and an additional metadata file can be added named as `filename_of_the_song.format.txt`. In this file, two parameters can be written: 40 | ``` 41 | artist=Name of the artist 42 | title=Name of the song 43 | ``` 44 | Those will define respectively what the game will use as Artist name and Song Title. If this file is not provided, Artist will be set as `Unknown` and Song Title will be set to the name of the song file stripped from its format. 45 | 46 | In order to categorize songs by Albums, you can create subfolders inside the `songs` folder with the name of the album in question and place inside that the songs of said album. 47 | Here is a practical example: 48 | 49 | In this example, the song in question will be shown in the game as:
50 | Artist: Dragonforce
51 | Title: Reason to Live
52 | Album: Ultra Beatdown 53 | 54 | ## Build Instructions (For Developers) 55 | 56 | In order to build the loader, you'll need a [vitasdk](https://github.com/vitasdk) build fully compiled with softfp usage. 57 | You can find a precompiled version here: https://github.com/vitasdk/buildscripts/actions/runs/1102643776. 58 | Additionally, you'll need these libraries to be compiled as well with `-mfloat-abi=softfp` added to their CFLAGS: 59 | 60 | - [SDL2_vitagl](https://github.com/Northfear/SDL/tree/vitagl) 61 | 62 | - [libmathneon](https://github.com/Rinnegatamante/math-neon) 63 | 64 | - ```bash 65 | make install 66 | ``` 67 | 68 | - [vitaShaRK](https://github.com/Rinnegatamante/vitaShaRK) 69 | 70 | - ```bash 71 | make install 72 | ``` 73 | 74 | - [kubridge](https://github.com/TheOfficialFloW/kubridge) 75 | 76 | - ```bash 77 | mkdir build && cd build 78 | cmake .. && make install 79 | ``` 80 | 81 | - [vitaGL](https://github.com/Rinnegatamante/vitaGL) 82 | 83 | - ````bash 84 | make SOFTFP_ABI=1 NO_DEBUG=1 install 85 | ```` 86 | 87 | After all these requirements are met, you can compile the loader with the following commands: 88 | 89 | ```bash 90 | mkdir build && cd build 91 | cmake .. && make 92 | ``` 93 | 94 | ## Credits 95 | 96 | - TheFloW for the original .so loader. 97 | - CatoTheYounger for the screenshots and for testing the homebrew. 98 | - Northfear for the SDL2 fork with vitaGL as backend. 99 | - Once13one for the Livearea assets. 100 | -------------------------------------------------------------------------------- /loader/sha1.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha1.c 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Implementation of the SHA1 hashing algorithm. 7 | Algorithm specification can be found here: 8 | * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf 9 | This implementation uses little endian byte order. 10 | *********************************************************************/ 11 | 12 | /*************************** HEADER FILES ***************************/ 13 | #include 14 | #include 15 | #include "sha1.h" 16 | 17 | /****************************** MACROS ******************************/ 18 | #define ROTLEFT(a, b) ((a << b) | (a >> (32 - b))) 19 | 20 | /*********************** FUNCTION DEFINITIONS ***********************/ 21 | void sha1_transform(SHA1_CTX *ctx, const BYTE data[]) 22 | { 23 | WORD a, b, c, d, e, i, j, t, m[80]; 24 | 25 | for (i = 0, j = 0; i < 16; ++i, j += 4) 26 | m[i] = (data[j] << 24) + (data[j + 1] << 16) + (data[j + 2] << 8) + (data[j + 3]); 27 | for ( ; i < 80; ++i) { 28 | m[i] = (m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16]); 29 | m[i] = (m[i] << 1) | (m[i] >> 31); 30 | } 31 | 32 | a = ctx->state[0]; 33 | b = ctx->state[1]; 34 | c = ctx->state[2]; 35 | d = ctx->state[3]; 36 | e = ctx->state[4]; 37 | 38 | for (i = 0; i < 20; ++i) { 39 | t = ROTLEFT(a, 5) + ((b & c) ^ (~b & d)) + e + ctx->k[0] + m[i]; 40 | e = d; 41 | d = c; 42 | c = ROTLEFT(b, 30); 43 | b = a; 44 | a = t; 45 | } 46 | for ( ; i < 40; ++i) { 47 | t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[1] + m[i]; 48 | e = d; 49 | d = c; 50 | c = ROTLEFT(b, 30); 51 | b = a; 52 | a = t; 53 | } 54 | for ( ; i < 60; ++i) { 55 | t = ROTLEFT(a, 5) + ((b & c) ^ (b & d) ^ (c & d)) + e + ctx->k[2] + m[i]; 56 | e = d; 57 | d = c; 58 | c = ROTLEFT(b, 30); 59 | b = a; 60 | a = t; 61 | } 62 | for ( ; i < 80; ++i) { 63 | t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[3] + m[i]; 64 | e = d; 65 | d = c; 66 | c = ROTLEFT(b, 30); 67 | b = a; 68 | a = t; 69 | } 70 | 71 | ctx->state[0] += a; 72 | ctx->state[1] += b; 73 | ctx->state[2] += c; 74 | ctx->state[3] += d; 75 | ctx->state[4] += e; 76 | } 77 | 78 | void sha1_init(SHA1_CTX *ctx) 79 | { 80 | ctx->datalen = 0; 81 | ctx->bitlen = 0; 82 | ctx->state[0] = 0x67452301; 83 | ctx->state[1] = 0xEFCDAB89; 84 | ctx->state[2] = 0x98BADCFE; 85 | ctx->state[3] = 0x10325476; 86 | ctx->state[4] = 0xc3d2e1f0; 87 | ctx->k[0] = 0x5a827999; 88 | ctx->k[1] = 0x6ed9eba1; 89 | ctx->k[2] = 0x8f1bbcdc; 90 | ctx->k[3] = 0xca62c1d6; 91 | } 92 | 93 | void sha1_update(SHA1_CTX *ctx, const BYTE data[], size_t len) 94 | { 95 | size_t i; 96 | 97 | for (i = 0; i < len; ++i) { 98 | ctx->data[ctx->datalen] = data[i]; 99 | ctx->datalen++; 100 | if (ctx->datalen == 64) { 101 | sha1_transform(ctx, ctx->data); 102 | ctx->bitlen += 512; 103 | ctx->datalen = 0; 104 | } 105 | } 106 | } 107 | 108 | void sha1_final(SHA1_CTX *ctx, BYTE hash[]) 109 | { 110 | WORD i; 111 | 112 | i = ctx->datalen; 113 | 114 | // Pad whatever data is left in the buffer. 115 | if (ctx->datalen < 56) { 116 | ctx->data[i++] = 0x80; 117 | while (i < 56) 118 | ctx->data[i++] = 0x00; 119 | } 120 | else { 121 | ctx->data[i++] = 0x80; 122 | while (i < 64) 123 | ctx->data[i++] = 0x00; 124 | sha1_transform(ctx, ctx->data); 125 | memset(ctx->data, 0, 56); 126 | } 127 | 128 | // Append to the padding the total message's length in bits and transform. 129 | ctx->bitlen += ctx->datalen * 8; 130 | ctx->data[63] = ctx->bitlen; 131 | ctx->data[62] = ctx->bitlen >> 8; 132 | ctx->data[61] = ctx->bitlen >> 16; 133 | ctx->data[60] = ctx->bitlen >> 24; 134 | ctx->data[59] = ctx->bitlen >> 32; 135 | ctx->data[58] = ctx->bitlen >> 40; 136 | ctx->data[57] = ctx->bitlen >> 48; 137 | ctx->data[56] = ctx->bitlen >> 56; 138 | sha1_transform(ctx, ctx->data); 139 | 140 | // Since this implementation uses little endian byte ordering and MD uses big endian, 141 | // reverse all the bytes when copying the final state to the output hash. 142 | for (i = 0; i < 4; ++i) { 143 | hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; 144 | hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; 145 | hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; 146 | hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; 147 | hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /loader/dialog.c: -------------------------------------------------------------------------------- 1 | /* dialog.c -- common dialog for error messages and cheats input 2 | * 3 | * Copyright (C) 2021 fgsfds, Andy Nguyen 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "main.h" 19 | #include "dialog.h" 20 | 21 | static uint16_t ime_title_utf16[SCE_IME_DIALOG_MAX_TITLE_LENGTH]; 22 | static uint16_t ime_initial_text_utf16[SCE_IME_DIALOG_MAX_TEXT_LENGTH]; 23 | static uint16_t ime_input_text_utf16[SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1]; 24 | static uint8_t ime_input_text_utf8[SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1]; 25 | 26 | void utf16_to_utf8(const uint16_t *src, uint8_t *dst) { 27 | for (int i = 0; src[i]; i++) { 28 | if ((src[i] & 0xFF80) == 0) { 29 | *(dst++) = src[i] & 0xFF; 30 | } else if((src[i] & 0xF800) == 0) { 31 | *(dst++) = ((src[i] >> 6) & 0xFF) | 0xC0; 32 | *(dst++) = (src[i] & 0x3F) | 0x80; 33 | } else if((src[i] & 0xFC00) == 0xD800 && (src[i + 1] & 0xFC00) == 0xDC00) { 34 | *(dst++) = (((src[i] + 64) >> 8) & 0x3) | 0xF0; 35 | *(dst++) = (((src[i] >> 2) + 16) & 0x3F) | 0x80; 36 | *(dst++) = ((src[i] >> 4) & 0x30) | 0x80 | ((src[i + 1] << 2) & 0xF); 37 | *(dst++) = (src[i + 1] & 0x3F) | 0x80; 38 | i += 1; 39 | } else { 40 | *(dst++) = ((src[i] >> 12) & 0xF) | 0xE0; 41 | *(dst++) = ((src[i] >> 6) & 0x3F) | 0x80; 42 | *(dst++) = (src[i] & 0x3F) | 0x80; 43 | } 44 | } 45 | 46 | *dst = '\0'; 47 | } 48 | 49 | void utf8_to_utf16(const uint8_t *src, uint16_t *dst) { 50 | for (int i = 0; src[i];) { 51 | if ((src[i] & 0xE0) == 0xE0) { 52 | *(dst++) = ((src[i] & 0x0F) << 12) | ((src[i + 1] & 0x3F) << 6) | (src[i + 2] & 0x3F); 53 | i += 3; 54 | } else if ((src[i] & 0xC0) == 0xC0) { 55 | *(dst++) = ((src[i] & 0x1F) << 6) | (src[i + 1] & 0x3F); 56 | i += 2; 57 | } else { 58 | *(dst++) = src[i]; 59 | i += 1; 60 | } 61 | } 62 | 63 | *dst = '\0'; 64 | } 65 | 66 | int init_ime_dialog(const char *title, const char *initial_text) { 67 | memset(ime_title_utf16, 0, sizeof(ime_title_utf16)); 68 | memset(ime_initial_text_utf16, 0, sizeof(ime_initial_text_utf16)); 69 | memset(ime_input_text_utf16, 0, sizeof(ime_input_text_utf16)); 70 | memset(ime_input_text_utf8, 0, sizeof(ime_input_text_utf8)); 71 | 72 | utf8_to_utf16((uint8_t *)title, ime_title_utf16); 73 | utf8_to_utf16((uint8_t *)initial_text, ime_initial_text_utf16); 74 | 75 | SceImeDialogParam param; 76 | sceImeDialogParamInit(¶m); 77 | 78 | param.supportedLanguages = 0x0001FFFF; 79 | param.languagesForced = SCE_TRUE; 80 | param.type = SCE_IME_TYPE_BASIC_LATIN; 81 | param.title = ime_title_utf16; 82 | param.maxTextLength = SCE_IME_DIALOG_MAX_TEXT_LENGTH; 83 | param.initialText = ime_initial_text_utf16; 84 | param.inputTextBuffer = ime_input_text_utf16; 85 | 86 | return sceImeDialogInit(¶m); 87 | } 88 | 89 | char *get_ime_dialog_result(void) { 90 | if (sceImeDialogGetStatus() != SCE_COMMON_DIALOG_STATUS_FINISHED) 91 | return NULL; 92 | 93 | SceImeDialogResult result; 94 | memset(&result, 0, sizeof(SceImeDialogResult)); 95 | sceImeDialogGetResult(&result); 96 | if (result.button == SCE_IME_DIALOG_BUTTON_ENTER) 97 | utf16_to_utf8(ime_input_text_utf16, ime_input_text_utf8); 98 | sceImeDialogTerm(); 99 | // For some reason analog stick stops working after ime 100 | sceCtrlSetSamplingModeExt(SCE_CTRL_MODE_ANALOG_WIDE); 101 | 102 | return (char *)ime_input_text_utf8; 103 | } 104 | 105 | int init_msg_dialog(const char *msg) { 106 | SceMsgDialogUserMessageParam msg_param; 107 | memset(&msg_param, 0, sizeof(msg_param)); 108 | msg_param.buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_OK; 109 | msg_param.msg = (SceChar8 *)msg; 110 | 111 | SceMsgDialogParam param; 112 | sceMsgDialogParamInit(¶m); 113 | _sceCommonDialogSetMagicNumber(¶m.commonParam); 114 | param.mode = SCE_MSG_DIALOG_MODE_USER_MSG; 115 | param.userMsgParam = &msg_param; 116 | 117 | return sceMsgDialogInit(¶m); 118 | } 119 | 120 | int get_msg_dialog_result(void) { 121 | if (sceMsgDialogGetStatus() != SCE_COMMON_DIALOG_STATUS_FINISHED) 122 | return 0; 123 | sceMsgDialogTerm(); 124 | return 1; 125 | } 126 | 127 | void fatal_error(const char *fmt, ...) { 128 | va_list list; 129 | char string[512]; 130 | 131 | va_start(list, fmt); 132 | vsnprintf(string, sizeof(string), fmt, list); 133 | va_end(list); 134 | 135 | vglInit(0); 136 | 137 | printf("%s\n", string); 138 | init_msg_dialog(string); 139 | 140 | while (!get_msg_dialog_result()) 141 | vglSwapBuffers(GL_TRUE); 142 | 143 | sceKernelExitProcess(0); 144 | while (1); 145 | } 146 | -------------------------------------------------------------------------------- /loader/ctype_patch.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const char __BIONIC_ctype_[257] = {0, 5 | _C, _C, _C, _C, _C, _C, _C, _C, 6 | _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, 7 | _C, _C, _C, _C, _C, _C, _C, _C, 8 | _C, _C, _C, _C, _C, _C, _C, _C, 9 | _S|_B, _P, _P, _P, _P, _P, _P, _P, 10 | _P, _P, _P, _P, _P, _P, _P, _P, 11 | _N, _N, _N, _N, _N, _N, _N, _N, 12 | _N, _N, _P, _P, _P, _P, _P, _P, 13 | _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, 14 | _U, _U, _U, _U, _U, _U, _U, _U, 15 | _U, _U, _U, _U, _U, _U, _U, _U, 16 | _U, _U, _U, _P, _P, _P, _P, _P, 17 | _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, 18 | _L, _L, _L, _L, _L, _L, _L, _L, 19 | _L, _L, _L, _L, _L, _L, _L, _L, 20 | _L, _L, _L, _P, _P, _P, _P, _C, 21 | 0, 0, 0, 0, 0, 0, 0, 0, 22 | 0, 0, 0, 0, 0, 0, 0, 0, 23 | 0, 0, 0, 0, 0, 0, 0, 0, 24 | 0, 0, 0, 0, 0, 0, 0, 0, 25 | 0, 0, 0, 0, 0, 0, 0, 0, 26 | 0, 0, 0, 0, 0, 0, 0, 0, 27 | 0, 0, 0, 0, 0, 0, 0, 0, 28 | 0, 0, 0, 0, 0, 0, 0, 0, 29 | 0, 0, 0, 0, 0, 0, 0, 0, 30 | 0, 0, 0, 0, 0, 0, 0, 0, 31 | 0, 0, 0, 0, 0, 0, 0, 0, 32 | 0, 0, 0, 0, 0, 0, 0, 0, 33 | 0, 0, 0, 0, 0, 0, 0, 0, 34 | 0, 0, 0, 0, 0, 0, 0, 0, 35 | 0, 0, 0, 0, 0, 0, 0, 0, 36 | 0, 0, 0, 0, 0, 0, 0, 0 37 | }; 38 | 39 | const short __BIONIC_tolower_tab_[257] = {EOF, 40 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 41 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 42 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 43 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 44 | 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 45 | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 46 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 47 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 48 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 49 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 50 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 51 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 52 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 53 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 54 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 55 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 56 | }; 57 | 58 | const short __BIONIC_toupper_tab_[257] = {EOF, 59 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 60 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 61 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 62 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 63 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 64 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 65 | 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 66 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 67 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 68 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 69 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 70 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 71 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 72 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 73 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 74 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 75 | }; 76 | 77 | const char *BIONIC_ctype_ = &__BIONIC_ctype_[0]; 78 | const short *BIONIC_tolower_tab_ = &__BIONIC_tolower_tab_[0]; 79 | const short *BIONIC_toupper_tab_ = &__BIONIC_toupper_tab_[0]; 80 | -------------------------------------------------------------------------------- /loader/bass_reimpl.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | extern "C" { 3 | #endif 4 | 5 | // BASS_ChannelGetData flags 6 | #define BASS_DATA_AVAILABLE 0 // query how much data is buffered 7 | #define BASS_DATA_NOREMOVE 0x10000000 // flag: don't remove data from recording buffer 8 | #define BASS_DATA_FIXED 0x20000000 // unused 9 | #define BASS_DATA_FLOAT 0x40000000 // flag: return floating-point sample data 10 | #define BASS_DATA_FFT256 0x80000000 // 256 sample FFT 11 | #define BASS_DATA_FFT512 0x80000001 // 512 FFT 12 | #define BASS_DATA_FFT1024 0x80000002 // 1024 FFT 13 | #define BASS_DATA_FFT2048 0x80000003 // 2048 FFT 14 | #define BASS_DATA_FFT4096 0x80000004 // 4096 FFT 15 | #define BASS_DATA_FFT8192 0x80000005 // 8192 FFT 16 | #define BASS_DATA_FFT16384 0x80000006 // 16384 FFT 17 | #define BASS_DATA_FFT32768 0x80000007 // 32768 FFT 18 | #define BASS_DATA_FFT_INDIVIDUAL 0x10 // FFT flag: FFT for each channel, else all combined 19 | #define BASS_DATA_FFT_NOWINDOW 0x20 // FFT flag: no Hanning window 20 | #define BASS_DATA_FFT_REMOVEDC 0x40 // FFT flag: pre-remove DC bias 21 | #define BASS_DATA_FFT_COMPLEX 0x80 // FFT flag: return complex data 22 | #define BASS_DATA_FFT_NYQUIST 0x100 // FFT flag: return extra Nyquist value 23 | 24 | #define BASS_ATTRIB_FREQ 1 25 | #define BASS_ATTRIB_VOL 2 26 | #define BASS_ATTRIB_PAN 3 27 | #define BASS_ATTRIB_EAXMIX 4 28 | #define BASS_ATTRIB_NOBUFFER 5 29 | #define BASS_ATTRIB_VBR 6 30 | #define BASS_ATTRIB_CPU 7 31 | #define BASS_ATTRIB_SRC 8 32 | #define BASS_ATTRIB_NET_RESUME 9 33 | #define BASS_ATTRIB_SCANINFO 10 34 | #define BASS_ATTRIB_NORAMP 11 35 | #define BASS_ATTRIB_BITRATE 12 36 | #define BASS_ATTRIB_BUFFER 13 37 | #define BASS_ATTRIB_GRANULE 14 38 | #define BASS_ATTRIB_USER 15 39 | #define BASS_ATTRIB_TAIL 16 40 | #define BASS_ATTRIB_PUSH_LIMIT 17 41 | #define BASS_ATTRIB_DOWNLOADPROC 18 42 | #define BASS_ATTRIB_VOLDSP 19 43 | #define BASS_ATTRIB_VOLDSP_PRIORITY 20 44 | #define BASS_ATTRIB_MUSIC_AMPLIFY 0x100 45 | #define BASS_ATTRIB_MUSIC_PANSEP 0x101 46 | #define BASS_ATTRIB_MUSIC_PSCALER 0x102 47 | #define BASS_ATTRIB_MUSIC_BPM 0x103 48 | #define BASS_ATTRIB_MUSIC_SPEED 0x104 49 | #define BASS_ATTRIB_MUSIC_VOL_GLOBAL 0x105 50 | #define BASS_ATTRIB_MUSIC_ACTIVE 0x106 51 | #define BASS_ATTRIB_MUSIC_VOL_CHAN 0x200 // + channel # 52 | #define BASS_ATTRIB_MUSIC_VOL_INST 0x300 // + instrument # 53 | 54 | #define BASS_ACTIVE_STOPPED 0 55 | #define BASS_ACTIVE_PLAYING 1 56 | #define BASS_ACTIVE_STALLED 2 57 | #define BASS_ACTIVE_PAUSED 3 58 | #define BASS_ACTIVE_PAUSED_DEVICE 4 59 | 60 | #define BASS_CONFIG_BUFFER 0 61 | #define BASS_CONFIG_UPDATEPERIOD 1 62 | #define BASS_CONFIG_GVOL_SAMPLE 4 63 | #define BASS_CONFIG_GVOL_STREAM 5 64 | #define BASS_CONFIG_GVOL_MUSIC 6 65 | #define BASS_CONFIG_CURVE_VOL 7 66 | #define BASS_CONFIG_CURVE_PAN 8 67 | #define BASS_CONFIG_FLOATDSP 9 68 | #define BASS_CONFIG_3DALGORITHM 10 69 | #define BASS_CONFIG_NET_TIMEOUT 11 70 | #define BASS_CONFIG_NET_BUFFER 12 71 | #define BASS_CONFIG_PAUSE_NOPLAY 13 72 | #define BASS_CONFIG_NET_PREBUF 15 73 | #define BASS_CONFIG_NET_PASSIVE 18 74 | #define BASS_CONFIG_REC_BUFFER 19 75 | #define BASS_CONFIG_NET_PLAYLIST 21 76 | #define BASS_CONFIG_MUSIC_VIRTUAL 22 77 | #define BASS_CONFIG_VERIFY 23 78 | #define BASS_CONFIG_UPDATETHREADS 24 79 | #define BASS_CONFIG_DEV_BUFFER 27 80 | #define BASS_CONFIG_REC_LOOPBACK 28 81 | #define BASS_CONFIG_VISTA_TRUEPOS 30 82 | #define BASS_CONFIG_IOS_SESSION 34 83 | #define BASS_CONFIG_IOS_MIXAUDIO 34 84 | #define BASS_CONFIG_DEV_DEFAULT 36 85 | #define BASS_CONFIG_NET_READTIMEOUT 37 86 | #define BASS_CONFIG_VISTA_SPEAKERS 38 87 | #define BASS_CONFIG_IOS_SPEAKER 39 88 | #define BASS_CONFIG_MF_DISABLE 40 89 | #define BASS_CONFIG_HANDLES 41 90 | #define BASS_CONFIG_UNICODE 42 91 | #define BASS_CONFIG_SRC 43 92 | #define BASS_CONFIG_SRC_SAMPLE 44 93 | #define BASS_CONFIG_ASYNCFILE_BUFFER 45 94 | #define BASS_CONFIG_OGG_PRESCAN 47 95 | #define BASS_CONFIG_MF_VIDEO 48 96 | #define BASS_CONFIG_AIRPLAY 49 97 | #define BASS_CONFIG_DEV_NONSTOP 50 98 | #define BASS_CONFIG_IOS_NOCATEGORY 51 99 | #define BASS_CONFIG_VERIFY_NET 52 100 | #define BASS_CONFIG_DEV_PERIOD 53 101 | #define BASS_CONFIG_FLOAT 54 102 | #define BASS_CONFIG_NET_SEEK 56 103 | #define BASS_CONFIG_AM_DISABLE 58 104 | #define BASS_CONFIG_NET_PLAYLIST_DEPTH 59 105 | #define BASS_CONFIG_NET_PREBUF_WAIT 60 106 | #define BASS_CONFIG_ANDROID_SESSIONID 62 107 | #define BASS_CONFIG_WASAPI_PERSIST 65 108 | #define BASS_CONFIG_REC_WASAPI 66 109 | #define BASS_CONFIG_ANDROID_AAUDIO 67 110 | #define BASS_CONFIG_SAMPLE_ONEHANDLE 69 111 | #define BASS_CONFIG_NET_META 71 112 | #define BASS_CONFIG_NET_RESTRATE 72 113 | #define BASS_CONFIG_REC_DEFAULT 73 114 | #define BASS_CONFIG_NORAMP 74 115 | 116 | #define BASS_CTYPE_SAMPLE 1 117 | #define BASS_CTYPE_RECORD 2 118 | #define BASS_CTYPE_STREAM 0x10000 119 | #define BASS_CTYPE_STREAM_VORBIS 0x10002 120 | #define BASS_CTYPE_STREAM_OGG 0x10002 121 | #define BASS_CTYPE_STREAM_MP1 0x10003 122 | #define BASS_CTYPE_STREAM_MP2 0x10004 123 | #define BASS_CTYPE_STREAM_MP3 0x10005 124 | #define BASS_CTYPE_STREAM_AIFF 0x10006 125 | #define BASS_CTYPE_STREAM_CA 0x10007 126 | #define BASS_CTYPE_STREAM_MF 0x10008 127 | #define BASS_CTYPE_STREAM_AM 0x10009 128 | #define BASS_CTYPE_STREAM_SAMPLE 0x1000a 129 | #define BASS_CTYPE_STREAM_DUMMY 0x18000 130 | #define BASS_CTYPE_STREAM_DEVICE 0x18001 131 | #define BASS_CTYPE_STREAM_WAV 0x40000 // WAVE flag (LOWORD=codec) 132 | #define BASS_CTYPE_STREAM_WAV_PCM 0x50001 133 | #define BASS_CTYPE_STREAM_WAV_FLOAT 0x50003 134 | #define BASS_CTYPE_MUSIC_MOD 0x20000 135 | #define BASS_CTYPE_MUSIC_MTM 0x20001 136 | #define BASS_CTYPE_MUSIC_S3M 0x20002 137 | #define BASS_CTYPE_MUSIC_XM 0x20003 138 | #define BASS_CTYPE_MUSIC_IT 0x20004 139 | #define BASS_CTYPE_MUSIC_MO3 0x00100 140 | 141 | #define BASS_STREAM_PRESCAN 0x20000 // scan file for accurate seeking and length 142 | #define BASS_STREAM_AUTOFREE 0x40000 // automatically free the stream when it stops/ends 143 | #define BASS_STREAM_RESTRATE 0x80000 // restrict the download rate of internet file stream 144 | #define BASS_STREAM_BLOCK 0x100000 // download internet file stream in small blocks 145 | #define BASS_STREAM_DECODE 0x200000 // don't play the stream, only decode 146 | #define BASS_STREAM_STATUS 0x800000 // give server status info (HTTP/ICY tags) in DOWNLOADPROC 147 | 148 | typedef struct { 149 | uint32_t freq; 150 | float volume; 151 | float pan; 152 | uint32_t flags; 153 | uint32_t length; 154 | uint32_t max; 155 | uint32_t origres; 156 | uint32_t chans; 157 | uint32_t mingap; 158 | uint32_t mode3d; 159 | float mindist; 160 | float maxdist; 161 | uint32_t iangle; 162 | uint32_t oangle; 163 | float outvol; 164 | uint32_t vam; 165 | uint32_t priority; 166 | } BASS_SAMPLE; 167 | 168 | typedef struct { 169 | uint32_t freq; 170 | uint32_t chans; 171 | uint32_t flags; 172 | uint32_t ctype; 173 | uint32_t origres; 174 | void *plugin; 175 | void *sample; 176 | char *filename; 177 | } BASS_CHANNELINFO; 178 | 179 | typedef struct { 180 | uint32_t tick; 181 | uint32_t duration; 182 | void *handle; 183 | void *handle2; 184 | uint32_t play_handle; 185 | BASS_SAMPLE info; 186 | BASS_CHANNELINFO info2; 187 | } BASS_internal_sample; 188 | 189 | const void *BASS_GetConfigPtr(uint32_t option); 190 | uint32_t BASS_GetVersion(); 191 | int BASS_Init(int device, uint32_t freq, uint32_t flags, int win, void *clsid); 192 | uint32_t BASS_GetDevice(); 193 | int BASS_SetDevice(uint32_t device); 194 | int BASS_SetConfig(uint32_t option, uint32_t value); 195 | BASS_internal_sample *BASS_SampleLoad(uint32_t mem, void *file, uint64_t offset, uint32_t length, uint32_t max, uint32_t flags); 196 | BASS_internal_sample *BASS_StreamCreateFile(uint32_t mem, void *file, uint64_t offset, uint64_t length, uint32_t flags); 197 | uint32_t BASS_SampleGetInfo(BASS_internal_sample *handle, BASS_SAMPLE *info); 198 | uint32_t BASS_ChannelGetInfo(BASS_internal_sample *handle, BASS_CHANNELINFO *info); 199 | uint32_t BASS_SampleGetChannel(BASS_internal_sample *handle, uint32_t flags); 200 | uint32_t BASS_ChannelSetAttribute(BASS_internal_sample *handle, uint32_t attrib, float value); 201 | uint32_t BASS_ChannelPlay(BASS_internal_sample *handle, uint32_t restart); 202 | uint32_t BASS_ChannelIsActive(BASS_internal_sample *handle); 203 | uint32_t BASS_ChannelGetData(BASS_internal_sample *handle, void *buffer, uint32_t length); 204 | uint32_t BASS_ChannelGetLength(BASS_internal_sample *handle, uint32_t mode); 205 | double BASS_ChannelBytes2Seconds(BASS_internal_sample *handle, uint64_t pos); 206 | uint64_t BASS_ChannelGetPosition(BASS_internal_sample *handle, uint32_t mode); 207 | uint32_t BASS_ChannelStop(BASS_internal_sample *handle); 208 | int BASS_ChannelPause(BASS_internal_sample *handle); 209 | 210 | int Song_GetTotalDuration(const char *file); 211 | 212 | #ifdef __cplusplus 213 | } 214 | #endif 215 | -------------------------------------------------------------------------------- /loader/bass_reimpl.cpp: -------------------------------------------------------------------------------- 1 | /* bass_reimpl.c -- Minimalistic libBASS reimplementation 2 | * 3 | * Copyright (C) 2023 Rinnegatamante 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "soloud.h" 15 | #include "soloud_wavstream.h" 16 | #include "soloud_wav.h" 17 | #include "soloud_bus.h" 18 | #include "bass_reimpl.h" 19 | 20 | SoLoud::Soloud soloud; 21 | #define min(a, b) (a) < (b) ? (a) : (b) 22 | 23 | extern "C" { 24 | 25 | const void *BASS_GetConfigPtr(uint32_t option) { 26 | return NULL; 27 | } 28 | 29 | uint32_t BASS_GetVersion() { 30 | return 0x2040000; 31 | } 32 | 33 | int BASS_Init(int device, uint32_t freq, uint32_t flags, int win, void *clsid) { 34 | soloud.init(SoLoud::Soloud::CLIP_ROUNDOFF); 35 | return 1; 36 | } 37 | 38 | uint32_t BASS_GetDevice() { 39 | return 0; 40 | } 41 | 42 | int BASS_SetDevice(uint32_t device) { 43 | return 1; 44 | } 45 | 46 | int BASS_SetConfig(uint32_t option, uint32_t value) { 47 | switch (option) { 48 | default: 49 | //printf("BASS_SetConfig(%u, %u)\n", option, value); 50 | break; 51 | } 52 | return 1; 53 | } 54 | 55 | BASS_internal_sample *BASS_SampleLoad(uint32_t mem, void *file, uint64_t offset, uint32_t length, uint32_t max, uint32_t flags) { 56 | //printf("BASS_SampleLoad(%x, %x, %llu, %u, %u, %u)\n", mem, file, offset, length, max, flags); 57 | BASS_internal_sample *res = (BASS_internal_sample *)malloc(sizeof(BASS_internal_sample)); 58 | res->play_handle = NULL; 59 | auto *w = new SoLoud::Wav; 60 | if (mem) { 61 | w->loadMem(file, length, true, false); 62 | } else { 63 | w->load(file); 64 | } 65 | res->handle = (void *)w; 66 | res->handle2 = NULL; 67 | w->setSingleInstance(1); 68 | sceClibMemset(&res->info, 0, sizeof(BASS_SAMPLE)); 69 | res->info.freq = 44100; 70 | res->info.volume = 1.0f; 71 | res->info.pan = 0.0f; 72 | res->info.flags = 0; 73 | res->info.length = length; 74 | res->info.max = max; 75 | res->info.origres = 0; 76 | res->info.chans = 2; 77 | res->info.mingap = 0; 78 | res->info.mode3d = 2; 79 | res->info2.freq = 44100; 80 | res->info2.chans = 2; 81 | res->info2.flags = 0; 82 | res->info2.ctype = BASS_CTYPE_SAMPLE; 83 | res->info2.origres = 0; 84 | res->info2.plugin = NULL; 85 | res->info2.sample = NULL; 86 | res->info2.filename = NULL; 87 | return res; 88 | } 89 | 90 | BASS_internal_sample *BASS_StreamCreateFile(uint32_t mem, void *file, uint64_t offset, uint64_t length, uint32_t flags) { 91 | //printf("BASS_StreamCreateFile(%x, %x, %llu, %llu, %u)\n", mem, file, offset, length, flags); 92 | BASS_internal_sample *res = (BASS_internal_sample *)malloc(sizeof(BASS_internal_sample)); 93 | res->play_handle = NULL; 94 | if (mem) { 95 | auto *w = new SoLoud::WavStream; 96 | w->loadMem(file, length, false, false); 97 | res->duration = w->getLength(); 98 | res->handle2 = (void *)w; 99 | } else { 100 | auto *w = new SoLoud::WavStream; 101 | int r = w->load(file); 102 | if (r) { 103 | printf("Error while opening %s (0x%x)\n", file, r); 104 | } 105 | res->duration = w->getLength() - 1; 106 | res->handle2 = (void *)w; 107 | } 108 | auto *b = new SoLoud::Bus; 109 | b->setVisualizationEnable(true); 110 | soloud.play(*b); 111 | res->handle = (void *)b; 112 | sceClibMemset(&res->info, 0, sizeof(BASS_SAMPLE)); 113 | res->info.freq = 44100; 114 | res->info.volume = 1.0f; 115 | res->info.pan = 0.0f; 116 | res->info.flags = 0; 117 | res->info.length = length; 118 | res->info.max = 0; 119 | res->info.origres = 0; 120 | res->info.chans = 2; 121 | res->info.mingap = 0; 122 | res->info.mode3d = 2; 123 | res->info2.freq = 44100; 124 | res->info2.chans = 2; 125 | res->info2.flags = 0; 126 | res->info2.ctype = BASS_CTYPE_STREAM; 127 | res->info2.origres = 0; 128 | res->info2.plugin = NULL; 129 | res->info2.sample = NULL; 130 | res->info2.filename = NULL; 131 | return res; 132 | } 133 | 134 | uint32_t BASS_SampleGetInfo(BASS_internal_sample *handle, BASS_SAMPLE *info) { 135 | sceClibMemcpy(info, &handle->info, sizeof(BASS_SAMPLE)); 136 | return 1; 137 | } 138 | 139 | uint32_t BASS_ChannelGetInfo(BASS_internal_sample *handle, BASS_CHANNELINFO *info) { 140 | sceClibMemcpy(info, &handle->info2, sizeof(BASS_CHANNELINFO)); 141 | return 1; 142 | } 143 | 144 | uint32_t BASS_SampleGetChannel(BASS_internal_sample *handle, uint32_t flags) { 145 | //printf("BASS_SampleGetChannel(%x, %u)\n", handle, flags); 146 | return handle; 147 | } 148 | 149 | 150 | 151 | uint32_t BASS_ChannelSetAttribute(BASS_internal_sample *handle, uint32_t attrib, float value) { 152 | //printf("BASS_ChannelSetAttribute(%x, %u, %f)\n", handle, attrib, value); 153 | if (!handle->handle2) { 154 | auto *w = (SoLoud::Wav *)handle->handle; 155 | switch (attrib) { 156 | case BASS_ATTRIB_PAN: 157 | handle->info.pan = value; 158 | break; 159 | case BASS_ATTRIB_VOL: 160 | handle->info.volume = value; 161 | w->setVolume(value); 162 | break; 163 | default: 164 | break; 165 | } 166 | } else { 167 | switch (attrib) { 168 | case BASS_ATTRIB_PAN: 169 | handle->info.pan = value; 170 | break; 171 | case BASS_ATTRIB_VOL: 172 | handle->info.volume = value; 173 | break; 174 | default: 175 | break; 176 | } 177 | } 178 | return 1; 179 | } 180 | 181 | uint32_t BASS_ChannelPlay(BASS_internal_sample *handle, uint32_t restart) { 182 | if (!handle->handle2) { 183 | //printf("BASS_ChannelPlay(%x, %x) Wav\n", handle, restart); 184 | auto *w = (SoLoud::Wav *)handle->handle; 185 | handle->play_handle = soloud.play(*w, handle->info.volume, handle->info.pan); 186 | handle->tick = sceKernelGetProcessTimeWide(); 187 | } else { 188 | //printf("BASS_ChannelPlay(%x, %x) WavStream\n", handle, restart); 189 | auto *w = (SoLoud::WavStream *)handle->handle2; 190 | if (handle->play_handle) { 191 | soloud.setPause(handle->play_handle, 0); 192 | handle->tick = sceKernelGetProcessTimeWide() - handle->tick; 193 | handle->info.freq = handle->info2.freq = soloud.getSamplerate(handle->play_handle); 194 | } else { 195 | auto *b = (SoLoud::Bus *)handle->handle; 196 | handle->play_handle = b->play(*w, handle->info.volume, handle->info.pan); 197 | handle->tick = sceKernelGetProcessTimeWide(); 198 | handle->info.freq = handle->info2.freq = soloud.getSamplerate(handle->play_handle); 199 | } 200 | } 201 | return 1; 202 | } 203 | 204 | uint32_t BASS_ChannelIsActive(BASS_internal_sample *handle) { 205 | return (sceKernelGetProcessTimeWide() - handle->tick) / 1000000 < handle->duration ? BASS_ACTIVE_PLAYING : BASS_ACTIVE_STOPPED; 206 | } 207 | 208 | // Hardcoded to Beat Hazard 2 requirements and tuned down since it seems FFT output range from Soloud is different from libBASS one 209 | uint32_t BASS_ChannelGetData(BASS_internal_sample *handle, void *buffer, uint32_t length) { 210 | float *fft; 211 | float *fbuffer = (float *)buffer; 212 | auto *b = (SoLoud::Bus *)handle->handle; 213 | switch (length) { 214 | case BASS_DATA_FFT2048: 215 | //printf("GetData BASS_DATA_FFT2048\n"); 216 | fft = b->calcFFT(); 217 | for (int i = 0; i < 256; i++) { 218 | fbuffer[i] = fft[i] / 32.0f; // FIXME: Without this normalization, FFT is way higher than expected 219 | } 220 | sceClibMemcpy(fbuffer + 256, fbuffer, 256 * sizeof(float)); 221 | //sceClibMemset(fbuffer + 256, 0, 256 * sizeof(float)); 222 | return 0x800; 223 | default: 224 | //printf("GetData %x\n", length); 225 | fft = b->getWave(); 226 | sceClibMemcpy(fbuffer, fft, 256 * sizeof(float)); 227 | sceClibMemcpy(fbuffer + 256, fft, 256 * sizeof(float)); 228 | sceClibMemcpy(fbuffer + 512, fbuffer, 512 * sizeof(float)); 229 | sceClibMemcpy(fbuffer + 1024, fbuffer, 1024 * sizeof(float)); 230 | return 0x2000; 231 | } 232 | return -1; 233 | } 234 | 235 | uint32_t BASS_ChannelGetLength(BASS_internal_sample *handle, uint32_t mode) { 236 | return handle->info.length; 237 | } 238 | 239 | double BASS_ChannelBytes2Seconds(BASS_internal_sample *handle, uint64_t pos) { 240 | //printf("Byte2Seconds %x %llu\n", handle->handle, pos); 241 | return pos == handle->info.length ? handle->duration : min((float)(sceKernelGetProcessTimeWide() - handle->tick) / 1000000.0f, handle->duration); 242 | } 243 | 244 | uint64_t BASS_ChannelGetPosition(BASS_internal_sample *handle, uint32_t mode) { 245 | if (!handle->handle2) 246 | return 0; 247 | return 1; 248 | } 249 | 250 | uint32_t BASS_ChannelStop(BASS_internal_sample *h) { 251 | if (!h->handle2) { 252 | soloud.stop(h->play_handle); 253 | auto *w = (SoLoud::Wav *)h->handle; 254 | delete w; 255 | free(h); 256 | } else { 257 | auto *b = (SoLoud::Bus *)h->handle; 258 | auto *w = (SoLoud::WavStream *)h->handle2; 259 | b->stop(); 260 | delete b; 261 | delete w; 262 | free(h); 263 | } 264 | return 1; 265 | } 266 | 267 | int BASS_ChannelPause(BASS_internal_sample *handle) { 268 | //printf("BASS_ChannelPause(%x)\n", handle); 269 | soloud.setPause(handle->play_handle, 1); 270 | handle->tick = sceKernelGetProcessTimeWide() - handle->tick; 271 | return 1; 272 | } 273 | 274 | int Song_GetTotalDuration(const char *file) { 275 | SoLoud::WavStream m; 276 | m.load(file); 277 | return m.getLength() - 1; 278 | } 279 | 280 | }; 281 | -------------------------------------------------------------------------------- /shaders/3.glsl: -------------------------------------------------------------------------------- 1 | 2 | uniform sampler2D _texture; 3 | uniform sampler2D normalMap; 4 | 5 | // lights 6 | 7 | //values used for shading algorithm... 8 | uniform int numLights; 9 | uniform float3 lightPos[50]; //light position, normalized 10 | uniform float4 lightColour[50]; //light RGBA -- alpha is intensity 11 | uniform float lightSize[50]; 12 | 13 | uniform float4 ambientColour; //ambient RGBA -- alpha is intensity 14 | uniform float screenScaleY; // so we can adjust the light to the correct aspect ratio 15 | 16 | // ------------------------------------------------------------------------------ 17 | // ------------------------------------------------------------------------------ 18 | float3 rgb2hsv(float3 c) 19 | { 20 | float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); 21 | float4 p = c.g < c.b ? float4(c.bg, K.wz) : float4(c.gb, K.xy); 22 | float4 q = c.r < p.x ? float4(p.xyw, c.r) : float4(c.r, p.yzx); 23 | 24 | float d = q.x - min(q.w, q.y); 25 | float e = 1.0e-10; 26 | return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); 27 | } 28 | 29 | // ------------------------------------------------------------------------------ 30 | // ------------------------------------------------------------------------------ 31 | float3 hsv2rgb(float3 c) 32 | { 33 | float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); 34 | float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); 35 | return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); 36 | } 37 | 38 | // ------------------------------------------------------------------------------ 39 | // ------------------------------------------------------------------------------ 40 | float4 doReplaceColour(float4 c, float3 replaceColour) 41 | { 42 | if(c.a > 0.0) 43 | { 44 | if(replaceColour.x != 0.0 || replaceColour.y != 0.0 || replaceColour.z != 0.0) 45 | { 46 | float4 h; 47 | h.a = c.a; 48 | h.rgb = rgb2hsv(c.rgb); 49 | 50 | if(h.y > 0.3) // if saturation is over threshold 51 | { 52 | if(h.x > 0.95 || h.x <= 0.1) // if hue is red(ish) 53 | { 54 | h.x += replaceColour.x; 55 | h.y *= replaceColour.y; 56 | h.z *= replaceColour.z; 57 | c.rgb = hsv2rgb(h.rgb); 58 | } 59 | } 60 | } 61 | } 62 | 63 | return c; 64 | } 65 | 66 | // ------------------------------------------------------------------------------ 67 | // ------------------------------------------------------------------------------ 68 | float2 rotate2D(float2 v, float s, float c) 69 | { 70 | float2 r; 71 | r.x = v.x*c - v.y*s; 72 | r.y = v.x*s + v.y*c; 73 | 74 | return r; 75 | } 76 | 77 | // ------------------------------------------------------------------------------ 78 | // ------------------------------------------------------------------------------ 79 | void motionBlur( 80 | float3 ambient, 81 | float s, 82 | float c, 83 | float4 inout gl_FragColor, 84 | float4 inout bluredNormal, 85 | float2 inout gVelocity, 86 | float blurPower, 87 | float2 texCoord, 88 | float4 colour, 89 | float3 replaceColour 90 | ) { 91 | float4 diffuseColour; 92 | float3 finalColour; 93 | float2 blurTexCoord; 94 | float steps; 95 | float n; 96 | 97 | // adjust velocity for screen aspect ratio 98 | gVelocity.y *= screenScaleY; 99 | gVelocity *= blurPower * 200.0; 100 | 101 | if(length(gVelocity) > 10.0) 102 | { 103 | gVelocity = normalize(gVelocity); 104 | gVelocity *= 10.0; 105 | } 106 | 107 | steps = length(gVelocity) * 1.5; // blur factor! 108 | steps = min(15.0, steps); 109 | 110 | if(steps <= 1.0) 111 | { 112 | bluredNormal = tex2D(normalMap, texCoord); // Blurred normal is just normal map 113 | 114 | diffuseColour = tex2D(_texture, texCoord); 115 | 116 | // replace colour test - works quite well 117 | diffuseColour = doReplaceColour(diffuseColour, replaceColour); 118 | 119 | finalColour.rgb = ambient.rgb * diffuseColour.rgb; 120 | gl_FragColor = colour * float4(finalColour, diffuseColour.a); 121 | return; 122 | } 123 | 124 | // rotate light for sprite rotation 125 | gVelocity = rotate2D(gVelocity, s, c); 126 | 127 | gVelocity.y *= -1.0; // flip Y 128 | gVelocity /= 4000.0; 129 | 130 | blurTexCoord = texCoord; 131 | blurTexCoord -= gVelocity * steps/2.0; 132 | 133 | steps = floor(steps); 134 | for(n=0.0; n lightsize * 0.3) 209 | { 210 | // add falloff for last 30% of radius 211 | dist = lightsize - dist; 212 | dist *= 1.0 / (lightsize * (1.0 - 0.3)); 213 | } 214 | else 215 | dist = 1.0; 216 | } 217 | else 218 | dist = 0.0; 219 | 220 | 221 | // ===== apply lighting 222 | ff = gl_FragColor.a; 223 | 224 | // make light pos relative to normal map 225 | lightPosTmp.xy -= gPixelPos.xy; 226 | lightPosTmp = normalize(lightPosTmp); 227 | 228 | // rotate light for sprite rotation 229 | lightPosTmp.xy = rotate2D(lightPosTmp.xy, s, c); 230 | 231 | //Pre-multiply light colour with intensity 232 | //Then perform "N dot L" to determine our diffuse term 233 | f = max(dot(N, lightPosTmp), 0.0); 234 | diffuse = (lightColour[i].rgb * lightColour[i].a * 3.0) * f; 235 | 236 | // calc specular highlight 237 | if(dot(N, lightPosTmp) < 0.0) // light source on the wrong side? 238 | { 239 | specularReflection = 0.0; // float3(0.0, 0.0, 0.0); // no specular reflection 240 | } 241 | else // light source on the right side 242 | { 243 | reflectDir = reflect(-lightPosTmp, N); 244 | specularReflection = pow(max(dot(viewDir, reflectDir), 0.0), 16.0); 245 | } 246 | 247 | // calc final colour 248 | finalColour = diffuseColour.rgb * diffuse * dist * ff; 249 | finalColour += specularReflection * specDist * length(lightColour[i].rgb) * specularPower; 250 | gl_FragColor += colour * float4(finalColour, diffuseColour.a); 251 | gl_FragColor.a = ff; 252 | } 253 | } 254 | 255 | // ------------------------------------------------------------------------------ 256 | // ------------------------------------------------------------------------------ 257 | void main( 258 | float4 colour : COLOR, 259 | float4 texCoords : TEXCOORD0, 260 | float4 texCoords2 : TEXCOORD1, 261 | float4 texCoords3 : TEXCOORD2, 262 | float4 out gl_FragColor : COLOR 263 | ) { 264 | float2 texCoord = texCoords.xy; 265 | float2 velocity = texCoords.zw; 266 | 267 | float3 replaceColour = texCoords2.xyz; 268 | float rotation = texCoords2.w; 269 | 270 | float2 pixelPos = texCoords3.xy; 271 | float specularPower = texCoords3.z; 272 | float blurPower = texCoords3.w; 273 | 274 | float4 diffuseColour; 275 | 276 | // fast draw on mobile if no lights and no blur 277 | if(numLights == 0 && blurPower == 0.0) 278 | { 279 | // write normal pixel 280 | diffuseColour = tex2D(_texture, texCoord); 281 | 282 | // replace colour test - works quite well 283 | if(diffuseColour.a > 0.0) 284 | { 285 | if(replaceColour.x != 0.0 || replaceColour.y != 0.0 || replaceColour.z != 0.0) 286 | diffuseColour = doReplaceColour(diffuseColour, replaceColour); 287 | } 288 | gl_FragColor = colour * diffuseColour; 289 | return; 290 | } 291 | 292 | 293 | gl_FragColor = float4(0.0, 0.0, 0.0, 0.0); 294 | float4 bluredNormal = float4(0.0, 0.0, 0.0, 0.0); 295 | 296 | // init globals 297 | float2 gVelocity = velocity; 298 | float2 gPixelPos = pixelPos; 299 | 300 | // ----- Normal Map 301 | float3 finalColour; 302 | float3 ambient; 303 | 304 | // for rotation later 305 | float s = sin(rotation); 306 | float c = cos(rotation); 307 | 308 | // calc ambient colour 309 | ambient = ambientColour.rgb * ambientColour.a * 3.0; 310 | 311 | // apply motion blur 312 | if(gVelocity.x * blurPower != 0.0 || gVelocity.y * blurPower != 0.0) 313 | { 314 | motionBlur(ambient, s, c, gl_FragColor, bluredNormal, gVelocity, blurPower, texCoord, colour, replaceColour); 315 | } 316 | else 317 | { 318 | // write normal pixel 319 | diffuseColour = tex2D(_texture, texCoord); 320 | 321 | // replace colour test - works quite well 322 | diffuseColour = doReplaceColour(diffuseColour, replaceColour); 323 | 324 | finalColour.rgb = ambient.rgb * diffuseColour.rgb; 325 | gl_FragColor = colour * float4(finalColour, diffuseColour.a); 326 | 327 | bluredNormal = tex2D(normalMap, texCoord); // Blurred normal is just normal map 328 | } 329 | 330 | // early out for black shadows 331 | if(gl_FragColor.r == 0.0 && gl_FragColor.g == 0.0 && gl_FragColor.b == 0.0 && gl_FragColor.a < 0.5) 332 | return; 333 | 334 | // early out 335 | if(gl_FragColor.a == 0.0) 336 | return; 337 | 338 | // adjust pixel pos for screen aspect ratio 339 | gPixelPos.y *= screenScaleY; 340 | 341 | //RGB of our normal map 342 | float3 normalColour = bluredNormal.rgb;// texture2D(normalMap, texCoord).rgb; 343 | 344 | //normalize our floattors 345 | float3 N = normalize(normalColour * 2.0 - 1.0); 346 | 347 | // now apply lighting 348 | if(numLights > 0) 349 | doLights(N, s, c, gPixelPos, gl_FragColor, specularPower, colour); 350 | } 351 | 352 | -------------------------------------------------------------------------------- /loader/so_util.c: -------------------------------------------------------------------------------- 1 | /* so_util.c -- utils to load and hook .so modules 2 | * 3 | * Copyright (C) 2021 Andy Nguyen 4 | * 5 | * This software may be modified and distributed under the terms 6 | * of the MIT license. See the LICENSE file for details. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "main.h" 17 | #include "dialog.h" 18 | #include "so_util.h" 19 | 20 | #ifndef SCE_KERNEL_MEMBLOCK_TYPE_USER_RX 21 | #define SCE_KERNEL_MEMBLOCK_TYPE_USER_RX (0x0C20D050) 22 | #endif 23 | 24 | typedef struct b_enc { 25 | union { 26 | struct __attribute__((__packed__)) { 27 | int imm24: 24; 28 | unsigned int l: 1; // Branch with Link flag 29 | unsigned int enc: 3; // 0b101 30 | unsigned int cond: 4; // 0b1110 31 | } bits; 32 | uint32_t raw; 33 | }; 34 | } b_enc; 35 | 36 | typedef struct ldst_enc { 37 | union { 38 | struct __attribute__((__packed__)) { 39 | int imm12: 12; 40 | unsigned int rt: 4; // Source/Destination register 41 | unsigned int rn: 4; // Base register 42 | unsigned int bit20_1: 1; // 0: store to memory, 1: load from memory 43 | unsigned int w: 1; // 0: no write-back, 1: write address into base 44 | unsigned int b: 1; // 0: word, 1: byte 45 | unsigned int u: 1; // 0: subtract offset from base, 1: add to base 46 | unsigned int p: 1; // 0: post indexing, 1: pre indexing 47 | unsigned int enc: 3; 48 | unsigned int cond: 4; 49 | } bits; 50 | uint32_t raw; 51 | }; 52 | } ldst_enc; 53 | 54 | #define B_RANGE ((1 << 24) - 1) 55 | #define B_OFFSET(x) (x + 8) // branch jumps into addr - 8, so range is biased forward 56 | #define B(PC, DEST) ((b_enc){.bits = {.cond = 0b1110, .enc = 0b101, .l = 0, .imm24 = (((intptr_t)DEST-(intptr_t)PC) / 4) - 2}}) 57 | #define LDR_OFFS(RT, RN, IMM) ((ldst_enc){.bits = {.cond = 0b1110, .enc = 0b010, .p = 1, .u = (IMM >= 0), .b = 0, .w = 0, .bit20_1 = 1, .rn = RN, .rt = RT, .imm12 = (IMM >= 0) ? IMM : -IMM}}) 58 | 59 | #define PATCH_SZ 0x10000 //64 KB-ish arenas 60 | static so_module *head = NULL, *tail = NULL; 61 | 62 | so_hook hook_thumb(uintptr_t addr, uintptr_t dst) { 63 | so_hook h; 64 | printf("THUMB HOOK\n"); 65 | if (addr == 0) 66 | return; 67 | h.thumb_addr = addr; 68 | addr &= ~1; 69 | if (addr & 2) { 70 | uint16_t nop = 0xbf00; 71 | kuKernelCpuUnrestrictedMemcpy((void *)addr, &nop, sizeof(nop)); 72 | addr += 2; 73 | printf("THUMB UNALIGNED\n"); 74 | } 75 | 76 | h.addr = addr; 77 | h.patch_instr[0] = 0xf000f8df; // LDR PC, [PC] 78 | h.patch_instr[1] = dst; 79 | kuKernelCpuUnrestrictedMemcpy(&h.orig_instr, (void *)addr, sizeof(h.orig_instr)); 80 | kuKernelCpuUnrestrictedMemcpy((void *)addr, h.patch_instr, sizeof(h.patch_instr)); 81 | 82 | return h; 83 | } 84 | 85 | so_hook hook_arm(uintptr_t addr, uintptr_t dst) { 86 | printf("ARM HOOK\n"); 87 | if (addr == 0) 88 | return; 89 | uint32_t hook[2]; 90 | so_hook h; 91 | h.thumb_addr = 0; 92 | h.addr = addr; 93 | h.patch_instr[0] = 0xe51ff004; // LDR PC, [PC, #-0x4] 94 | h.patch_instr[1] = dst; 95 | kuKernelCpuUnrestrictedMemcpy(&h.orig_instr, (void *)addr, sizeof(h.orig_instr)); 96 | kuKernelCpuUnrestrictedMemcpy((void *)addr, h.patch_instr, sizeof(h.patch_instr)); 97 | 98 | return h; 99 | } 100 | 101 | so_hook hook_addr(uintptr_t addr, uintptr_t dst) { 102 | if (addr == 0) 103 | return; 104 | if (addr & 1) 105 | return hook_thumb(addr, dst); 106 | else 107 | return hook_arm(addr, dst); 108 | } 109 | 110 | void so_flush_caches(so_module *mod) { 111 | kuKernelFlushCaches((void *)mod->text_base, mod->text_size); 112 | } 113 | 114 | int _so_load(so_module *mod, SceUID so_blockid, void *so_data, uintptr_t load_addr) { 115 | int res = 0; 116 | uintptr_t data_addr = 0; 117 | 118 | if (memcmp(so_data, ELFMAG, SELFMAG) != 0) { 119 | res = -1; 120 | goto err_free_so; 121 | } 122 | 123 | mod->ehdr = (Elf32_Ehdr *)so_data; 124 | mod->phdr = (Elf32_Phdr *)((uintptr_t)so_data + mod->ehdr->e_phoff); 125 | mod->shdr = (Elf32_Shdr *)((uintptr_t)so_data + mod->ehdr->e_shoff); 126 | 127 | mod->shstr = (char *)((uintptr_t)so_data + mod->shdr[mod->ehdr->e_shstrndx].sh_offset); 128 | 129 | for (int i = 0; i < mod->ehdr->e_phnum; i++) { 130 | if (mod->phdr[i].p_type == PT_LOAD) { 131 | void *prog_data; 132 | size_t prog_size; 133 | 134 | if ((mod->phdr[i].p_flags & PF_X) == PF_X) { 135 | // Allocate arena for code patches, trampolines, etc 136 | // Sits exactly under the desired allocation space 137 | mod->patch_size = ALIGN_MEM(PATCH_SZ, mod->phdr[i].p_align); 138 | SceKernelAllocMemBlockKernelOpt opt; 139 | memset(&opt, 0, sizeof(SceKernelAllocMemBlockKernelOpt)); 140 | opt.size = sizeof(SceKernelAllocMemBlockKernelOpt); 141 | opt.attr = 0x1; 142 | opt.field_C = (SceUInt32)load_addr - mod->patch_size; 143 | res = mod->patch_blockid = kuKernelAllocMemBlock("rx_block", SCE_KERNEL_MEMBLOCK_TYPE_USER_RX, mod->patch_size, &opt); 144 | if (res < 0) 145 | goto err_free_so; 146 | 147 | sceKernelGetMemBlockBase(mod->patch_blockid, &mod->patch_base); 148 | mod->patch_head = mod->patch_base; 149 | 150 | prog_size = ALIGN_MEM(mod->phdr[i].p_memsz, mod->phdr[i].p_align); 151 | memset(&opt, 0, sizeof(SceKernelAllocMemBlockKernelOpt)); 152 | opt.size = sizeof(SceKernelAllocMemBlockKernelOpt); 153 | opt.attr = 0x1; 154 | opt.field_C = (SceUInt32)load_addr; 155 | res = mod->text_blockid = kuKernelAllocMemBlock("rx_block", SCE_KERNEL_MEMBLOCK_TYPE_USER_RX, prog_size, &opt); 156 | if (res < 0) 157 | goto err_free_so; 158 | 159 | sceKernelGetMemBlockBase(mod->text_blockid, &prog_data); 160 | 161 | mod->phdr[i].p_vaddr += (Elf32_Addr)prog_data; 162 | 163 | mod->text_base = mod->phdr[i].p_vaddr; 164 | mod->text_size = mod->phdr[i].p_memsz; 165 | 166 | // Use the .text segment padding as a code cave 167 | // Word-align it to make it simpler for instruction arena allocation 168 | mod->cave_size = ALIGN_MEM(prog_size - mod->phdr[i].p_memsz, 0x4); 169 | mod->cave_base = mod->cave_head = prog_data + mod->phdr[i].p_memsz; 170 | mod->cave_base = ALIGN_MEM(mod->cave_base, 0x4); 171 | mod->cave_head = mod->cave_base; 172 | printf("code cave: %d bytes (@0x%08X).\n", mod->cave_size, mod->cave_base); 173 | 174 | data_addr = (uintptr_t)prog_data + prog_size; 175 | } else { 176 | if (data_addr == 0) 177 | goto err_free_so; 178 | 179 | if (mod->n_data >= MAX_DATA_SEG) 180 | goto err_free_data; 181 | 182 | prog_size = ALIGN_MEM(mod->phdr[i].p_memsz + mod->phdr[i].p_vaddr - (data_addr - mod->text_base), mod->phdr[i].p_align); 183 | 184 | SceKernelAllocMemBlockKernelOpt opt; 185 | memset(&opt, 0, sizeof(SceKernelAllocMemBlockKernelOpt)); 186 | opt.size = sizeof(SceKernelAllocMemBlockKernelOpt); 187 | opt.attr = 0x1; 188 | opt.field_C = (SceUInt32)data_addr; 189 | res = mod->data_blockid[mod->n_data] = kuKernelAllocMemBlock("rw_block", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW, prog_size, &opt); 190 | if (res < 0) 191 | goto err_free_text; 192 | 193 | sceKernelGetMemBlockBase(mod->data_blockid[mod->n_data], &prog_data); 194 | data_addr = (uintptr_t)prog_data + prog_size; 195 | 196 | mod->phdr[i].p_vaddr += (Elf32_Addr)mod->text_base; 197 | 198 | mod->data_base[mod->n_data] = mod->phdr[i].p_vaddr; 199 | mod->data_size[mod->n_data] = mod->phdr[i].p_memsz; 200 | mod->n_data++; 201 | } 202 | 203 | char *zero = malloc(prog_size - mod->phdr[i].p_filesz); 204 | memset(zero, 0, prog_size - mod->phdr[i].p_filesz); 205 | kuKernelCpuUnrestrictedMemcpy(prog_data + mod->phdr[i].p_filesz, zero, prog_size - mod->phdr[i].p_filesz); 206 | free(zero); 207 | 208 | kuKernelCpuUnrestrictedMemcpy((void *)mod->phdr[i].p_vaddr, (void *)((uintptr_t)so_data + mod->phdr[i].p_offset), mod->phdr[i].p_filesz); 209 | } 210 | } 211 | 212 | for (int i = 0; i < mod->ehdr->e_shnum; i++) { 213 | char *sh_name = mod->shstr + mod->shdr[i].sh_name; 214 | uintptr_t sh_addr = mod->text_base + mod->shdr[i].sh_addr; 215 | size_t sh_size = mod->shdr[i].sh_size; 216 | if (strcmp(sh_name, ".dynamic") == 0) { 217 | mod->dynamic = (Elf32_Dyn *)sh_addr; 218 | mod->num_dynamic = sh_size / sizeof(Elf32_Dyn); 219 | } else if (strcmp(sh_name, ".dynstr") == 0) { 220 | mod->dynstr = (char *)sh_addr; 221 | } else if (strcmp(sh_name, ".dynsym") == 0) { 222 | mod->dynsym = (Elf32_Sym *)sh_addr; 223 | mod->num_dynsym = sh_size / sizeof(Elf32_Sym); 224 | } else if (strcmp(sh_name, ".rel.dyn") == 0) { 225 | mod->reldyn = (Elf32_Rel *)sh_addr; 226 | mod->num_reldyn = sh_size / sizeof(Elf32_Rel); 227 | } else if (strcmp(sh_name, ".rel.plt") == 0) { 228 | mod->relplt = (Elf32_Rel *)sh_addr; 229 | mod->num_relplt = sh_size / sizeof(Elf32_Rel); 230 | } else if (strcmp(sh_name, ".init_array") == 0) { 231 | mod->init_array = (void *)sh_addr; 232 | mod->num_init_array = sh_size / sizeof(void *); 233 | } else if (strcmp(sh_name, ".hash") == 0) { 234 | mod->hash = (void *)sh_addr; 235 | } 236 | } 237 | 238 | if (mod->dynamic == NULL || 239 | mod->dynstr == NULL || 240 | mod->dynsym == NULL || 241 | mod->reldyn == NULL || 242 | mod->relplt == NULL) { 243 | res = -2; 244 | goto err_free_data; 245 | } 246 | 247 | for (int i = 0; i < mod->num_dynamic; i++) { 248 | switch (mod->dynamic[i].d_tag) { 249 | case DT_SONAME: 250 | mod->soname = mod->dynstr + mod->dynamic[i].d_un.d_ptr; 251 | break; 252 | default: 253 | break; 254 | } 255 | } 256 | 257 | sceKernelFreeMemBlock(so_blockid); 258 | 259 | if (!head && !tail) { 260 | head = mod; 261 | tail = mod; 262 | } else { 263 | tail->next = mod; 264 | tail = mod; 265 | } 266 | 267 | return 0; 268 | 269 | err_free_data: 270 | for (int i = 0; i < mod->n_data; i++) 271 | sceKernelFreeMemBlock(mod->data_blockid[i]); 272 | err_free_text: 273 | sceKernelFreeMemBlock(mod->text_blockid); 274 | err_free_so: 275 | sceKernelFreeMemBlock(so_blockid); 276 | 277 | return res; 278 | } 279 | 280 | int so_mem_load(so_module *mod, void *buffer, size_t so_size, uintptr_t load_addr) { 281 | SceUID so_blockid; 282 | void *so_data; 283 | 284 | memset(mod, 0, sizeof(so_module)); 285 | 286 | so_blockid = sceKernelAllocMemBlock("so block", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW, (so_size + 0xfff) & ~0xfff, NULL); 287 | if (so_blockid < 0) 288 | return so_blockid; 289 | 290 | sceKernelGetMemBlockBase(so_blockid, &so_data); 291 | sceClibMemcpy(so_data, buffer, so_size); 292 | 293 | return _so_load(mod, so_blockid, so_data, load_addr); 294 | } 295 | 296 | int so_file_load(so_module *mod, const char *filename, uintptr_t load_addr) { 297 | SceUID so_blockid; 298 | void *so_data; 299 | 300 | memset(mod, 0, sizeof(so_module)); 301 | 302 | SceUID fd = sceIoOpen(filename, SCE_O_RDONLY, 0); 303 | if (fd < 0) 304 | return fd; 305 | 306 | size_t so_size = sceIoLseek(fd, 0, SCE_SEEK_END); 307 | sceIoLseek(fd, 0, SCE_SEEK_SET); 308 | 309 | so_blockid = sceKernelAllocMemBlock("so block", SCE_KERNEL_MEMBLOCK_TYPE_USER_RW, (so_size + 0xfff) & ~0xfff, NULL); 310 | if (so_blockid < 0) 311 | return so_blockid; 312 | 313 | sceKernelGetMemBlockBase(so_blockid, &so_data); 314 | 315 | sceIoRead(fd, so_data, so_size); 316 | sceIoClose(fd); 317 | 318 | return _so_load(mod, so_blockid, so_data, load_addr); 319 | } 320 | 321 | int so_relocate(so_module *mod) { 322 | for (int i = 0; i < mod->num_reldyn + mod->num_relplt; i++) { 323 | Elf32_Rel *rel = i < mod->num_reldyn ? &mod->reldyn[i] : &mod->relplt[i - mod->num_reldyn]; 324 | Elf32_Sym *sym = &mod->dynsym[ELF32_R_SYM(rel->r_info)]; 325 | uintptr_t *ptr = (uintptr_t *)(mod->text_base + rel->r_offset); 326 | 327 | int type = ELF32_R_TYPE(rel->r_info); 328 | switch (type) { 329 | case R_ARM_ABS32: 330 | if (sym->st_shndx != SHN_UNDEF) 331 | *ptr += mod->text_base + sym->st_value; 332 | break; 333 | case R_ARM_RELATIVE: 334 | *ptr += mod->text_base; 335 | break; 336 | case R_ARM_GLOB_DAT: 337 | case R_ARM_JUMP_SLOT: 338 | { 339 | if (sym->st_shndx != SHN_UNDEF) 340 | *ptr = mod->text_base + sym->st_value; 341 | break; 342 | } 343 | default: 344 | fatal_error("Error unknown relocation type %x\n", type); 345 | break; 346 | } 347 | } 348 | 349 | return 0; 350 | } 351 | 352 | uintptr_t so_resolve_link(so_module *mod, const char *symbol) { 353 | for (int i = 0; i < mod->num_dynamic; i++) { 354 | switch (mod->dynamic[i].d_tag) { 355 | case DT_NEEDED: 356 | { 357 | so_module *curr = head; 358 | while (curr) { 359 | if (curr != mod && strcmp(curr->soname, mod->dynstr + mod->dynamic[i].d_un.d_ptr) == 0) { 360 | uintptr_t link = so_symbol(curr, symbol); 361 | if (link) 362 | return link; 363 | } 364 | curr = curr->next; 365 | } 366 | 367 | break; 368 | } 369 | default: 370 | break; 371 | } 372 | } 373 | 374 | return 0; 375 | } 376 | 377 | void reloc_err(uintptr_t got0) 378 | { 379 | // Find to which module this missing symbol belongs 380 | int found = 0; 381 | so_module *curr = head; 382 | while (curr && !found) { 383 | for (int i = 0; i < curr->n_data; i++) 384 | if ((got0 >= curr->data_base[i]) && (got0 <= (uintptr_t)(curr->data_base[i] + curr->data_size[i]))) 385 | found = 1; 386 | 387 | if (!found) 388 | curr = curr->next; 389 | } 390 | 391 | if (curr) { 392 | // Attempt to find symbol name and then display error 393 | for (int i = 0; i < curr->num_reldyn + curr->num_relplt; i++) { 394 | Elf32_Rel *rel = i < curr->num_reldyn ? &curr->reldyn[i] : &curr->relplt[i - curr->num_reldyn]; 395 | Elf32_Sym *sym = &curr->dynsym[ELF32_R_SYM(rel->r_info)]; 396 | uintptr_t *ptr = (uintptr_t *)(curr->text_base + rel->r_offset); 397 | 398 | int type = ELF32_R_TYPE(rel->r_info); 399 | switch (type) { 400 | case R_ARM_JUMP_SLOT: 401 | { 402 | if (got0 == (uintptr_t)ptr) { 403 | fatal_error("Unknown symbol \"%s\" (%p).\n", curr->dynstr + sym->st_name, (void*)got0); 404 | } 405 | break; 406 | } 407 | } 408 | } 409 | } 410 | 411 | // Ooops, this shouldn't have happened. 412 | fatal_error("Unknown symbol \"???\" (%p).\n", (void*)got0); 413 | } 414 | 415 | __attribute__((naked)) void plt0_stub() 416 | { 417 | register uintptr_t got0 asm("r12"); 418 | reloc_err(got0); 419 | } 420 | 421 | int so_resolve(so_module *mod, so_default_dynlib *default_dynlib, int size_default_dynlib, int default_dynlib_only) { 422 | for (int i = 0; i < mod->num_reldyn + mod->num_relplt; i++) { 423 | Elf32_Rel *rel = i < mod->num_reldyn ? &mod->reldyn[i] : &mod->relplt[i - mod->num_reldyn]; 424 | Elf32_Sym *sym = &mod->dynsym[ELF32_R_SYM(rel->r_info)]; 425 | uintptr_t *ptr = (uintptr_t *)(mod->text_base + rel->r_offset); 426 | 427 | int type = ELF32_R_TYPE(rel->r_info); 428 | switch (type) { 429 | case R_ARM_ABS32: 430 | case R_ARM_GLOB_DAT: 431 | case R_ARM_JUMP_SLOT: 432 | { 433 | if (sym->st_shndx == SHN_UNDEF) { 434 | int resolved = 0; 435 | if (!default_dynlib_only) { 436 | uintptr_t link = so_resolve_link(mod, mod->dynstr + sym->st_name); 437 | if (link) { 438 | // debugPrintf("Resolved from dependencies: %s\n", mod->dynstr + sym->st_name); 439 | if (type == R_ARM_ABS32) 440 | *ptr += link; 441 | else 442 | *ptr = link; 443 | resolved = 1; 444 | } 445 | } 446 | 447 | for (int j = 0; j < size_default_dynlib / sizeof(so_default_dynlib); j++) { 448 | if (strcmp(mod->dynstr + sym->st_name, default_dynlib[j].symbol) == 0) { 449 | *ptr = default_dynlib[j].func; 450 | resolved = 1; 451 | break; 452 | } 453 | } 454 | 455 | if (!resolved) { 456 | void *f = vglGetProcAddress(mod->dynstr + sym->st_name); 457 | if (f) { 458 | *ptr = f; 459 | resolved = 1; 460 | break; 461 | } 462 | } 463 | 464 | if (!resolved) { 465 | if (type == R_ARM_JUMP_SLOT) { 466 | printf("Unresolved import: %s\n", mod->dynstr + sym->st_name); 467 | *ptr = (uintptr_t)&plt0_stub; 468 | } 469 | else { 470 | //printf("Unresolved import: %s\n", mod->dynstr + sym->st_name); 471 | } 472 | } 473 | } 474 | 475 | break; 476 | } 477 | default: 478 | break; 479 | } 480 | } 481 | 482 | return 0; 483 | } 484 | 485 | int so_resolve_with_dummy(so_module *mod, so_default_dynlib *default_dynlib, int size_default_dynlib, int default_dynlib_only) { 486 | for (int i = 0; i < mod->num_reldyn + mod->num_relplt; i++) { 487 | Elf32_Rel *rel = i < mod->num_reldyn ? &mod->reldyn[i] : &mod->relplt[i - mod->num_reldyn]; 488 | Elf32_Sym *sym = &mod->dynsym[ELF32_R_SYM(rel->r_info)]; 489 | uintptr_t *ptr = (uintptr_t *)(mod->text_base + rel->r_offset); 490 | 491 | int type = ELF32_R_TYPE(rel->r_info); 492 | switch (type) { 493 | case R_ARM_ABS32: 494 | case R_ARM_GLOB_DAT: 495 | case R_ARM_JUMP_SLOT: 496 | { 497 | if (sym->st_shndx == SHN_UNDEF) { 498 | for (int j = 0; j < size_default_dynlib / sizeof(so_default_dynlib); j++) { 499 | if (strcmp(mod->dynstr + sym->st_name, default_dynlib[j].symbol) == 0) { 500 | *ptr = &ret0; 501 | break; 502 | } 503 | } 504 | } 505 | 506 | break; 507 | } 508 | default: 509 | break; 510 | } 511 | } 512 | 513 | return 0; 514 | } 515 | 516 | void so_initialize(so_module *mod) { 517 | for (int i = 0; i < mod->num_init_array; i++) { 518 | if (mod->init_array[i]) 519 | mod->init_array[i](); 520 | } 521 | } 522 | 523 | uint32_t so_hash(const uint8_t *name) { 524 | uint64_t h = 0, g; 525 | while (*name) { 526 | h = (h << 4) + *name++; 527 | if ((g = (h & 0xf0000000)) != 0) 528 | h ^= g >> 24; 529 | h &= 0x0fffffff; 530 | } 531 | return h; 532 | } 533 | 534 | static int so_symbol_index(so_module *mod, const char *symbol) 535 | { 536 | if (mod->hash) { 537 | uint32_t hash = so_hash((const uint8_t *)symbol); 538 | uint32_t nbucket = mod->hash[0]; 539 | uint32_t *bucket = &mod->hash[2]; 540 | uint32_t *chain = &bucket[nbucket]; 541 | for (int i = bucket[hash % nbucket]; i; i = chain[i]) { 542 | if (mod->dynsym[i].st_shndx == SHN_UNDEF) 543 | continue; 544 | if (mod->dynsym[i].st_info != SHN_UNDEF && strcmp(mod->dynstr + mod->dynsym[i].st_name, symbol) == 0) 545 | return i; 546 | } 547 | } 548 | 549 | for (int i = 0; i < mod->num_dynsym; i++) { 550 | if (mod->dynsym[i].st_shndx == SHN_UNDEF) 551 | continue; 552 | if (mod->dynsym[i].st_info != SHN_UNDEF && strcmp(mod->dynstr + mod->dynsym[i].st_name, symbol) == 0) 553 | return i; 554 | } 555 | 556 | return -1; 557 | } 558 | 559 | /* 560 | * alloc_arena: allocates space on either patch or cave arenas, 561 | * range: maximum range from allocation to dst (ignored if NULL) 562 | * dst: destination address 563 | */ 564 | static uintptr_t so_alloc_arena(so_module *so, uintptr_t range, uintptr_t dst, size_t sz) { 565 | // Is address in range? 566 | #define inrange(lsr, gtr, range) \ 567 | (((uintptr_t)(range) == (uintptr_t)NULL) || ((uintptr_t)(range) >= ((uintptr_t)(gtr) - (uintptr_t)(lsr)))) 568 | // Space left on block 569 | #define blkavail(type) (so->type##_size - (so->type##_head - so->type##_base)) 570 | 571 | // keep allocations 4-byte aligned for simplicity 572 | sz = ALIGN_MEM(sz, 4); 573 | 574 | if (sz <= (blkavail(patch)) && inrange(so->patch_base, dst, range)) { 575 | so->patch_head += sz; 576 | return (so->patch_head - sz); 577 | } else if (sz <= (blkavail(cave)) && inrange(dst, so->cave_base, range)) { 578 | so->cave_head += sz; 579 | return (so->cave_head - sz); 580 | } 581 | 582 | return (uintptr_t)NULL; 583 | } 584 | 585 | static void trampoline_ldm(so_module *mod, uint32_t *dst) { 586 | uint32_t trampoline[1]; 587 | uint32_t funct[20] = {0xFAFAFAFA}; 588 | uint32_t *ptr = funct; 589 | 590 | int cur = 0; 591 | int baseReg = ((*dst) >> 16) & 0xF; 592 | int bitMask = (*dst) & 0xFFFF; 593 | 594 | uint32_t stored = NULL; 595 | for (int i = 0; i < 16; i++) { 596 | if (bitMask & (1 << i)) { 597 | // If the register we're reading the offset from is the same as the one we're writing, 598 | // delay it to the very end so that the base pointer ins't clobbered 599 | if (baseReg == i) 600 | stored = LDR_OFFS(i, baseReg, cur).raw; 601 | else 602 | *ptr++ = LDR_OFFS(i, baseReg, cur).raw; 603 | cur += 4; 604 | } 605 | } 606 | 607 | // Perform the delayed load if needed 608 | if (stored) { 609 | *ptr++ = stored; 610 | } 611 | 612 | *ptr++ = 0xe51ff004; // LDR PC, [PC, -0x4] ; jmp to [dst+0x4] 613 | *ptr++ = dst+1; // .dword <...> ; [dst+0x4] 614 | 615 | size_t trampoline_sz = ((uintptr_t)ptr - (uintptr_t)&funct[0]); 616 | uintptr_t patch_addr = so_alloc_arena(mod, B_RANGE, B_OFFSET(dst), trampoline_sz); 617 | 618 | if (!patch_addr) { 619 | fatal_error("Failed to patch LDMIA at 0x%08X, unable to allocate space.\n", dst); 620 | } 621 | 622 | // Create sign extended relative address rel_addr 623 | trampoline[0] = B(dst, patch_addr).raw; 624 | 625 | kuKernelCpuUnrestrictedMemcpy((void*)patch_addr, funct, trampoline_sz); 626 | kuKernelCpuUnrestrictedMemcpy(dst, trampoline, sizeof(trampoline)); 627 | } 628 | 629 | uintptr_t so_symbol(so_module *mod, const char *symbol) { 630 | int index = so_symbol_index(mod, symbol); 631 | if (index == -1) 632 | return NULL; 633 | 634 | return mod->text_base + mod->dynsym[index].st_value; 635 | } 636 | 637 | void so_symbol_fix_ldmia(so_module *mod, const char *symbol) { 638 | // This is meant to work around crashes due to unaligned accesses (SIGBUS :/) due to certain 639 | // kernels not having the fault trap enabled, e.g. certain RK3326 Odroid Go Advance clone distros. 640 | // TODO:: Maybe enable this only with a config flag? maybe with a list of known broken functions? 641 | // Known to trigger on GM:S's "_Z11Shader_LoadPhjS_" - if it starts happening on other places, 642 | // might be worth enabling it globally. 643 | 644 | int idx = so_symbol_index(mod, symbol); 645 | if (idx == -1) 646 | return; 647 | 648 | uintptr_t st_addr = mod->text_base + mod->dynsym[idx].st_value; 649 | for (uintptr_t addr = st_addr; addr < st_addr + mod->dynsym[idx].st_size; addr+=4) { 650 | uint32_t inst = *(uint32_t*)(addr); 651 | 652 | //Is this an LDMIA instruction with a R0-R12 base register? 653 | if (((inst & 0xFFF00000) == 0xE8900000) && (((inst >> 16) & 0xF) < 13) ) { 654 | debugPrintf("Found possibly misaligned LDMIA on 0x%08X, trying to fix it... (instr: 0x%08X, to 0x%08X)\n", addr, *(uint32_t*)addr, mod->patch_head); 655 | trampoline_ldm(mod, addr); 656 | } 657 | } 658 | } 659 | -------------------------------------------------------------------------------- /loader/main.c: -------------------------------------------------------------------------------- 1 | /* main.c -- Beat Hazard 2 .so loader 2 | * 3 | * Copyright (C) 2021 Andy Nguyen 4 | * Copyright (C) 2023 Rinnegatamante 5 | * 6 | * This software may be modified and distributed under the terms 7 | * of the MIT license. See the LICENSE file for details. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "main.h" 43 | #include "config.h" 44 | #include "dialog.h" 45 | #include "so_util.h" 46 | #include "sha1.h" 47 | 48 | #include "bass_reimpl.h" 49 | 50 | #ifdef ENABLE_DEBUG 51 | #define dlog printf 52 | #else 53 | #define dlog 54 | #endif 55 | 56 | extern const char *BIONIC_ctype_; 57 | extern const short *BIONIC_tolower_tab_; 58 | extern const short *BIONIC_toupper_tab_; 59 | 60 | static char data_path[256]; 61 | 62 | static char fake_vm[0x1000]; 63 | static char fake_env[0x1000]; 64 | 65 | int framecap = 0; 66 | 67 | int file_exists(const char *path) { 68 | SceIoStat stat; 69 | return sceIoGetstat(path, &stat) >= 0; 70 | } 71 | 72 | int _newlib_heap_size_user = MEMORY_NEWLIB_MB * 1024 * 1024; 73 | 74 | unsigned int _pthread_stack_default_user = 1 * 1024 * 1024; 75 | 76 | so_module hazard_mod, cpp_mod, tags_mod, ttf_mod; 77 | 78 | void *__wrap_memcpy(void *dest, const void *src, size_t n) { 79 | return sceClibMemcpy(dest, src, n); 80 | } 81 | 82 | void *__wrap_memmove(void *dest, const void *src, size_t n) { 83 | return sceClibMemmove(dest, src, n); 84 | } 85 | 86 | int ret4() { return 4; } 87 | 88 | void *__wrap_memset(void *s, int c, size_t n) { 89 | return sceClibMemset(s, c, n); 90 | } 91 | 92 | char *getcwd_hook(char *buf, size_t size) { 93 | strcpy(buf, data_path); 94 | return buf; 95 | } 96 | 97 | int posix_memalign(void **memptr, size_t alignment, size_t size) { 98 | *memptr = memalign(alignment, size); 99 | return 0; 100 | } 101 | 102 | int debugPrintf(char *text, ...) { 103 | #ifdef ENABLE_DEBUG 104 | va_list list; 105 | static char string[0x8000]; 106 | 107 | va_start(list, text); 108 | vsprintf(string, text, list); 109 | va_end(list); 110 | 111 | SceUID fd = sceIoOpen("ux0:data/hazard_log.txt", SCE_O_WRONLY | SCE_O_CREAT | SCE_O_APPEND, 0777); 112 | if (fd >= 0) { 113 | sceIoWrite(fd, string, strlen(string)); 114 | sceIoClose(fd); 115 | } 116 | #endif 117 | return 0; 118 | } 119 | 120 | int __android_log_print(int prio, const char *tag, const char *fmt, ...) { 121 | #ifdef ENABLE_DEBUG 122 | va_list list; 123 | static char string[0x8000]; 124 | 125 | va_start(list, fmt); 126 | vsprintf(string, fmt, list); 127 | va_end(list); 128 | 129 | printf("[LOG] %s: %s\n", tag, string); 130 | #endif 131 | return 0; 132 | } 133 | 134 | int __android_log_write(int prio, const char *tag, const char *fmt, ...) { 135 | #ifdef ENABLE_DEBUG 136 | va_list list; 137 | static char string[0x8000]; 138 | 139 | va_start(list, fmt); 140 | vsprintf(string, fmt, list); 141 | va_end(list); 142 | 143 | printf("[LOGW] %s: %s\n", tag, string); 144 | #endif 145 | return 0; 146 | } 147 | 148 | int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list list) { 149 | #ifdef ENABLE_DEBUG 150 | static char string[0x8000]; 151 | 152 | vsprintf(string, fmt, list); 153 | va_end(list); 154 | 155 | printf("[LOGV] %s: %s\n", tag, string); 156 | #endif 157 | return 0; 158 | } 159 | 160 | int ret0(void) { 161 | return 0; 162 | } 163 | 164 | int ret1(void) { 165 | return 1; 166 | } 167 | 168 | int pthread_mutex_init_fake(pthread_mutex_t **uid, const pthread_mutexattr_t *mutexattr) { 169 | pthread_mutex_t *m = calloc(1, sizeof(pthread_mutex_t)); 170 | if (!m) 171 | return -1; 172 | 173 | const int recursive = (mutexattr && *(const int *)mutexattr == 1); 174 | *m = recursive ? PTHREAD_RECURSIVE_MUTEX_INITIALIZER : PTHREAD_MUTEX_INITIALIZER; 175 | 176 | int ret = pthread_mutex_init(m, mutexattr); 177 | if (ret < 0) { 178 | free(m); 179 | return -1; 180 | } 181 | 182 | *uid = m; 183 | 184 | return 0; 185 | } 186 | 187 | int pthread_mutex_destroy_fake(pthread_mutex_t **uid) { 188 | if (uid && *uid && (uintptr_t)*uid > 0x8000) { 189 | pthread_mutex_destroy(*uid); 190 | free(*uid); 191 | *uid = NULL; 192 | } 193 | return 0; 194 | } 195 | 196 | int pthread_mutex_lock_fake(pthread_mutex_t **uid) { 197 | int ret = 0; 198 | if (!*uid) { 199 | ret = pthread_mutex_init_fake(uid, NULL); 200 | } else if ((uintptr_t)*uid == 0x4000) { 201 | pthread_mutexattr_t attr; 202 | pthread_mutexattr_init(&attr); 203 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 204 | ret = pthread_mutex_init_fake(uid, &attr); 205 | pthread_mutexattr_destroy(&attr); 206 | } else if ((uintptr_t)*uid == 0x8000) { 207 | pthread_mutexattr_t attr; 208 | pthread_mutexattr_init(&attr); 209 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); 210 | ret = pthread_mutex_init_fake(uid, &attr); 211 | pthread_mutexattr_destroy(&attr); 212 | } 213 | if (ret < 0) 214 | return ret; 215 | return pthread_mutex_lock(*uid); 216 | } 217 | 218 | int pthread_mutex_trylock_fake(pthread_mutex_t **uid) { 219 | int ret = 0; 220 | if (!*uid) { 221 | ret = pthread_mutex_init_fake(uid, NULL); 222 | } else if ((uintptr_t)*uid == 0x4000) { 223 | pthread_mutexattr_t attr; 224 | pthread_mutexattr_init(&attr); 225 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 226 | ret = pthread_mutex_init_fake(uid, &attr); 227 | pthread_mutexattr_destroy(&attr); 228 | } else if ((uintptr_t)*uid == 0x8000) { 229 | pthread_mutexattr_t attr; 230 | pthread_mutexattr_init(&attr); 231 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); 232 | ret = pthread_mutex_init_fake(uid, &attr); 233 | pthread_mutexattr_destroy(&attr); 234 | } 235 | if (ret < 0) 236 | return ret; 237 | return pthread_mutex_trylock(*uid); 238 | } 239 | 240 | int pthread_mutex_unlock_fake(pthread_mutex_t **uid) { 241 | int ret = 0; 242 | if (!*uid) { 243 | ret = pthread_mutex_init_fake(uid, NULL); 244 | } else if ((uintptr_t)*uid == 0x4000) { 245 | pthread_mutexattr_t attr; 246 | pthread_mutexattr_init(&attr); 247 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 248 | ret = pthread_mutex_init_fake(uid, &attr); 249 | pthread_mutexattr_destroy(&attr); 250 | } else if ((uintptr_t)*uid == 0x8000) { 251 | pthread_mutexattr_t attr; 252 | pthread_mutexattr_init(&attr); 253 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); 254 | ret = pthread_mutex_init_fake(uid, &attr); 255 | pthread_mutexattr_destroy(&attr); 256 | } 257 | if (ret < 0) 258 | return ret; 259 | return pthread_mutex_unlock(*uid); 260 | } 261 | 262 | int pthread_cond_init_fake(pthread_cond_t **cnd, const int *condattr) { 263 | pthread_cond_t *c = calloc(1, sizeof(pthread_cond_t)); 264 | if (!c) 265 | return -1; 266 | 267 | *c = PTHREAD_COND_INITIALIZER; 268 | 269 | int ret = pthread_cond_init(c, NULL); 270 | if (ret < 0) { 271 | free(c); 272 | return -1; 273 | } 274 | 275 | *cnd = c; 276 | 277 | return 0; 278 | } 279 | 280 | int pthread_cond_broadcast_fake(pthread_cond_t **cnd) { 281 | if (!*cnd) { 282 | if (pthread_cond_init_fake(cnd, NULL) < 0) 283 | return -1; 284 | } 285 | return pthread_cond_broadcast(*cnd); 286 | } 287 | 288 | int pthread_cond_signal_fake(pthread_cond_t **cnd) { 289 | if (!*cnd) { 290 | if (pthread_cond_init_fake(cnd, NULL) < 0) 291 | return -1; 292 | } 293 | return pthread_cond_signal(*cnd); 294 | } 295 | 296 | int pthread_cond_destroy_fake(pthread_cond_t **cnd) { 297 | if (cnd && *cnd) { 298 | pthread_cond_destroy(*cnd); 299 | free(*cnd); 300 | *cnd = NULL; 301 | } 302 | return 0; 303 | } 304 | 305 | int pthread_cond_wait_fake(pthread_cond_t **cnd, pthread_mutex_t **mtx) { 306 | if (!*cnd) { 307 | if (pthread_cond_init_fake(cnd, NULL) < 0) 308 | return -1; 309 | } 310 | return pthread_cond_wait(*cnd, *mtx); 311 | } 312 | 313 | int pthread_cond_timedwait_fake(pthread_cond_t **cnd, pthread_mutex_t **mtx, const struct timespec *t) { 314 | if (!*cnd) { 315 | if (pthread_cond_init_fake(cnd, NULL) < 0) 316 | return -1; 317 | } 318 | return pthread_cond_timedwait(*cnd, *mtx, t); 319 | } 320 | 321 | int clock_gettime_hook(int clk_id, struct timespec *t) { 322 | struct timeval now; 323 | int rv = gettimeofday(&now, NULL); 324 | if (rv) 325 | return rv; 326 | t->tv_sec = now.tv_sec; 327 | t->tv_nsec = now.tv_usec * 1000; 328 | 329 | return 0; 330 | } 331 | 332 | int pthread_cond_timedwait_relative_np_fake(pthread_cond_t **cnd, pthread_mutex_t **mtx, struct timespec *ts) { 333 | if (!*cnd) { 334 | if (pthread_cond_init_fake(cnd, NULL) < 0) 335 | return -1; 336 | } 337 | 338 | if (ts != NULL) { 339 | struct timespec ct; 340 | clock_gettime_hook(0, &ct); 341 | ts->tv_sec += ct.tv_sec; 342 | ts->tv_nsec += ct.tv_nsec; 343 | } 344 | 345 | pthread_cond_timedwait(*cnd, *mtx, ts); // FIXME 346 | return 0; 347 | } 348 | 349 | int pthread_create_fake(pthread_t *thread, const void *unused, void *entry, void *arg) { 350 | return pthread_create(thread, NULL, entry, arg); 351 | } 352 | 353 | int pthread_once_fake(volatile int *once_control, void (*init_routine)(void)) { 354 | if (!once_control || !init_routine) 355 | return -1; 356 | if (__sync_lock_test_and_set(once_control, 1) == 0) 357 | (*init_routine)(); 358 | return 0; 359 | } 360 | 361 | int GetCurrentThreadId(void) { 362 | return sceKernelGetThreadId(); 363 | } 364 | 365 | extern void *__aeabi_ldiv0; 366 | 367 | int GetEnv(void *vm, void **env, int r2) { 368 | *env = fake_env; 369 | return 0; 370 | } 371 | 372 | void throw_exc(char **str, void *a, int b) { 373 | printf("throwing %s\n", *str); 374 | } 375 | 376 | FILE *fopen_hook(char *fname, char *mode) { 377 | FILE *f; 378 | char real_fname[256]; 379 | printf("fopen(%s,%s)\n", fname, mode); 380 | if (strncmp(fname, "ux0:", 4)) { 381 | sprintf(real_fname, "%sassets/%s", data_path, fname); 382 | f = fopen(real_fname, mode); 383 | } else { 384 | f = fopen(fname, mode); 385 | } 386 | return f; 387 | } 388 | 389 | int open_hook(const char *fname, int flags, mode_t mode) { 390 | int f; 391 | char real_fname[256]; 392 | printf("open(%s)\n", fname); 393 | if (strncmp(fname, "ux0:", 4)) { 394 | sprintf(real_fname, "%sassets/%s", data_path, fname); 395 | f = open(real_fname, flags, mode); 396 | } else { 397 | f = open(fname, flags, mode); 398 | } 399 | return f; 400 | } 401 | 402 | FILE *android_fopen(char *fname, char *type, int a3) { 403 | return fopen_hook(fname, type); 404 | } 405 | 406 | int debugMsg(int a1, int a2, const char *fmt, ...) { 407 | va_list list; 408 | static char string[0x8000]; 409 | 410 | va_start(list, fmt); 411 | vsprintf(string, fmt, list); 412 | va_end(list); 413 | 414 | printf("[DMSG] %s\n", string); 415 | } 416 | 417 | int showWebPage(void *this, char *url) { 418 | SceAppUtilWebBrowserParam param = {0}; 419 | param.str = url; 420 | param.strlen = strlen(url); 421 | param.launchMode = 1; 422 | sceAppUtilLaunchWebBrowser(¶m); 423 | return 0; 424 | } 425 | 426 | void patch_game(void) { 427 | char *androidProvider = (char *)so_symbol(&hazard_mod, "androidProvider"); 428 | if (androidProvider) 429 | sprintf(androidProvider, "%s - PSVita v.1.0", androidProvider); 430 | 431 | hook_addr(so_symbol(&hazard_mod, "_ZN16CplatformAndroid16misc_showWebPageEPc"), (uintptr_t)&showWebPage); 432 | 433 | hook_addr(so_symbol(&hazard_mod, "_ZN15CachievementMgr20checkAllAchievementsEv"), (uintptr_t)&ret0); // Stack smashes 434 | 435 | //hook_addr(so_symbol(&hazard_mod, "_ZN9CdebugMsg7printffE9EdebugMsgPKcz"), (uintptr_t)&debugMsg); 436 | hook_addr(so_symbol(&hazard_mod, "_ZN16CplatformAndroid31httpPost_postToGoogleAnalyiticsEPNSt6__ndk112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE"), (uintptr_t)&ret0); 437 | } 438 | 439 | extern void *__aeabi_atexit; 440 | extern void *__aeabi_ddiv; 441 | extern void *__aeabi_dmul; 442 | extern void *__aeabi_dadd; 443 | extern void *__aeabi_i2d; 444 | extern void *__aeabi_idiv; 445 | extern void *__aeabi_idivmod; 446 | extern void *__aeabi_ldivmod; 447 | extern void *__aeabi_uidiv; 448 | extern void *__aeabi_uidivmod; 449 | extern void *__aeabi_uldivmod; 450 | extern void *__cxa_atexit; 451 | extern void *__cxa_finalize; 452 | extern void *__cxa_call_unexpected; 453 | extern void *__gnu_unwind_frame; 454 | extern void *__stack_chk_fail; 455 | int open(const char *pathname, int flags); 456 | 457 | static int __stack_chk_guard_fake = 0x42424242; 458 | 459 | static FILE __sF_fake[0x1000][3]; 460 | 461 | int stat_hook(const char *pathname, void *statbuf) { 462 | //dlog("stat(%s)\n", pathname); 463 | struct stat st; 464 | int res = stat(pathname, &st); 465 | if (res == 0) 466 | *(uint64_t *)(statbuf + 0x30) = st.st_size; 467 | return res; 468 | } 469 | 470 | void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { 471 | return memalign(length, 0x1000); 472 | } 473 | 474 | int munmap(void *addr, size_t length) { 475 | free(addr); 476 | return 0; 477 | } 478 | 479 | int fstat_hook(int fd, void *statbuf) { 480 | struct stat st; 481 | int res = fstat(fd, &st); 482 | if (res == 0) 483 | *(uint64_t *)(statbuf + 0x30) = st.st_size; 484 | return res; 485 | } 486 | 487 | extern void *__cxa_guard_acquire; 488 | extern void *__cxa_guard_release; 489 | 490 | void *sceClibMemclr(void *dst, SceSize len) { 491 | return sceClibMemset(dst, 0, len); 492 | } 493 | 494 | void *sceClibMemset2(void *dst, SceSize len, int ch) { 495 | return sceClibMemset(dst, ch, len); 496 | } 497 | 498 | void *Android_JNI_GetEnv() { 499 | return fake_env; 500 | } 501 | 502 | char *SDL_AndroidGetExternalStoragePath() { 503 | return data_path; 504 | } 505 | 506 | char *SDL_AndroidGetInternalStoragePath() { 507 | return data_path; 508 | } 509 | 510 | int g_SDL_BufferGeometry_w; 511 | int g_SDL_BufferGeometry_h; 512 | 513 | void abort_hook() { 514 | //dlog("ABORT CALLED!!!\n"); 515 | uint8_t *p = NULL; 516 | p[0] = 1; 517 | } 518 | 519 | int ret99() { 520 | return 99; 521 | } 522 | 523 | int chdir_hook(const char *path) { 524 | return 0; 525 | } 526 | 527 | GLint glGetUniformLocation_fake(GLuint program, const GLchar *name) { 528 | if (!strcmp(name, "texture")) 529 | return glGetUniformLocation(program, "_texture"); 530 | return glGetUniformLocation(program, name); 531 | } 532 | 533 | void glShaderSource_fake(GLuint shader, GLsizei count, const GLchar **string, const GLint *length) { 534 | static int idx = 0; 535 | char fname[256]; 536 | sprintf(fname, "app0:shaders/%d.glsl", idx++); 537 | FILE *f = fopen(fname, "rb"); 538 | if (!f) { 539 | f = fopen(fname, "wb"); 540 | fwrite(*string, 1, strlen(*string), f); 541 | fclose(f); 542 | sprintf(fname, "ux0:data/hazard/%d.glsl", (idx - 1) % 2); 543 | f = fopen(fname, "rb"); 544 | } 545 | fseek(f, 0, SEEK_END); 546 | GLint len = ftell(f); 547 | fseek(f, 0, SEEK_SET); 548 | char *shd_src = (char *)malloc(len + 1); 549 | fread(shd_src, 1, len, f); 550 | fclose(f); 551 | shd_src[len] = 0; 552 | glShaderSource(shader, 1, &shd_src, NULL); 553 | free(shd_src); 554 | } 555 | 556 | static so_default_dynlib gl_hook[] = { 557 | {"glPixelStorei", (uintptr_t)&ret0}, 558 | {"glShaderSource", (uintptr_t)&glShaderSource_fake}, 559 | }; 560 | static size_t gl_numhook = sizeof(gl_hook) / sizeof(*gl_hook); 561 | 562 | void *SDL_GL_GetProcAddress_fake(const char *symbol) { 563 | dlog("looking for symbol %s\n", symbol); 564 | for (size_t i = 0; i < gl_numhook; ++i) { 565 | if (!strcmp(symbol, gl_hook[i].symbol)) { 566 | return (void *)gl_hook[i].func; 567 | } 568 | } 569 | void *r = vglGetProcAddress(symbol); 570 | if (!r) { 571 | dlog("Cannot find symbol %s\n", symbol); 572 | } 573 | return r; 574 | } 575 | 576 | #define SCE_ERRNO_MASK 0xFF 577 | 578 | #define DT_DIR 4 579 | #define DT_REG 8 580 | 581 | struct android_dirent { 582 | char pad[18]; 583 | unsigned char d_type; 584 | char d_name[256]; 585 | }; 586 | 587 | typedef struct { 588 | SceUID uid; 589 | struct android_dirent dir; 590 | } android_DIR; 591 | 592 | int closedir_fake(android_DIR *dirp) { 593 | if (!dirp || dirp->uid < 0) { 594 | errno = EBADF; 595 | return -1; 596 | } 597 | 598 | int res = sceIoDclose(dirp->uid); 599 | dirp->uid = -1; 600 | 601 | free(dirp); 602 | 603 | if (res < 0) { 604 | errno = res & SCE_ERRNO_MASK; 605 | return -1; 606 | } 607 | 608 | errno = 0; 609 | return 0; 610 | } 611 | 612 | android_DIR *opendir_fake(const char *dirname) { 613 | printf("opendir(%s)\n", dirname); 614 | SceUID uid = sceIoDopen(dirname); 615 | 616 | if (uid < 0) { 617 | errno = uid & SCE_ERRNO_MASK; 618 | return NULL; 619 | } 620 | 621 | android_DIR *dirp = calloc(1, sizeof(android_DIR)); 622 | 623 | if (!dirp) { 624 | sceIoDclose(uid); 625 | errno = ENOMEM; 626 | return NULL; 627 | } 628 | 629 | dirp->uid = uid; 630 | 631 | errno = 0; 632 | return dirp; 633 | } 634 | 635 | struct android_dirent *readdir_fake(android_DIR *dirp) { 636 | if (!dirp) { 637 | errno = EBADF; 638 | return NULL; 639 | } 640 | 641 | SceIoDirent sce_dir; 642 | int res = sceIoDread(dirp->uid, &sce_dir); 643 | 644 | if (res < 0) { 645 | errno = res & SCE_ERRNO_MASK; 646 | return NULL; 647 | } 648 | 649 | if (res == 0) { 650 | errno = 0; 651 | return NULL; 652 | } 653 | 654 | dirp->dir.d_type = SCE_S_ISDIR(sce_dir.d_stat.st_mode) ? DT_DIR : DT_REG; 655 | strcpy(dirp->dir.d_name, sce_dir.d_name); 656 | return &dirp->dir; 657 | } 658 | 659 | SDL_Surface *IMG_Load_hook(const char *file) { 660 | char real_fname[256]; 661 | printf("loading %s\n", file); 662 | if (strncmp(file, "ux0:", 4)) { 663 | sprintf(real_fname, "%s/assets/%s", data_path, file); 664 | return IMG_Load(real_fname); 665 | } 666 | return IMG_Load(file); 667 | } 668 | 669 | SDL_RWops *SDL_RWFromFile_hook(const char *fname, const char *mode) { 670 | SDL_RWops *f; 671 | char real_fname[256]; 672 | //printf("SDL_RWFromFile(%s,%s)\n", fname, mode); 673 | /*if (strncmp(fname, "ux0:", 4)) { 674 | sprintf(real_fname, "%s/assets/%s", data_path, fname); 675 | printf("SDL_RWFromFile patched to %s\n", real_fname); 676 | f = SDL_RWFromFile(real_fname, mode); 677 | } else*/ { 678 | f = SDL_RWFromFile(fname, mode); 679 | } 680 | return f; 681 | } 682 | 683 | Mix_Music *Mix_LoadMUS_hook(const char *fname) { 684 | Mix_Music *f; 685 | char real_fname[256]; 686 | printf("Mix_LoadMUS(%s)\n", fname); 687 | if (strncmp(fname, "ux0:", 4)) { 688 | sprintf(real_fname, "%s/assets/%s", data_path, fname); 689 | f = Mix_LoadMUS(real_fname); 690 | } else { 691 | f = Mix_LoadMUS(fname); 692 | } 693 | return f; 694 | } 695 | 696 | int Mix_OpenAudio_hook(int frequency, Uint16 format, int channels, int chunksize) { 697 | return Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 1024); 698 | } 699 | 700 | extern void SDL_ResetKeyboard(void); 701 | 702 | size_t __strlen_chk(const char *s, size_t s_len) { 703 | return strlen(s); 704 | } 705 | 706 | SDL_Window *SDL_CreateWindow_hook(const char *title, int x, int y, int w, int h, Uint32 flags) { 707 | return SDL_CreateWindow("hazard", 0, 0, SCREEN_W, SCREEN_H, flags); 708 | } 709 | 710 | uint64_t lseek64(int fd, uint64_t offset, int whence) { 711 | return lseek(fd, offset, whence); 712 | } 713 | 714 | char *SDL_GetBasePath_hook() { 715 | void *ret = malloc(256); 716 | sprintf(ret, "%s/assets/", data_path); 717 | printf("SDL_GetBasePath\n"); 718 | return ret; 719 | } 720 | 721 | void SDL_GetVersion_fake(SDL_version *ver){ 722 | ver->major = 2; 723 | ver->minor = 0; 724 | ver->patch = 10; 725 | } 726 | 727 | const char *SDL_JoystickName_fake(SDL_Joystick *joystick) { 728 | return "Totally PS4 Controller ( ͡° ͜ʖ ͡°)"; 729 | } 730 | 731 | char *glGetString_fake(GLenum cap) { 732 | eglSwapInterval(0, framecap ? 2 : 1); 733 | return glGetString(cap); 734 | } 735 | 736 | static so_default_dynlib default_dynlib[] = { 737 | { "glGetString", (uintptr_t)&glGetString_fake}, 738 | { "glShaderSource", (uintptr_t)&glShaderSource_fake}, 739 | { "glGetUniformLocation", (uintptr_t)&glGetUniformLocation_fake}, 740 | { "BASS_GetConfigPtr", (uintptr_t)&BASS_GetConfigPtr}, 741 | { "BASS_GetConfigPtr", (uintptr_t)&BASS_GetConfigPtr}, 742 | { "BASS_GetVersion", (uintptr_t)&BASS_GetVersion}, 743 | { "BASS_Init", (uintptr_t)&BASS_Init}, 744 | { "BASS_GetDevice", (uintptr_t)&BASS_GetDevice}, 745 | { "BASS_SetDevice", (uintptr_t)&BASS_SetDevice}, 746 | { "BASS_SetConfig", (uintptr_t)&BASS_SetConfig}, 747 | { "BASS_SampleLoad", (uintptr_t)&BASS_SampleLoad}, 748 | { "BASS_SampleGetChannel", (uintptr_t)&BASS_SampleGetChannel}, 749 | { "BASS_SampleGetInfo", (uintptr_t)&BASS_SampleGetInfo}, 750 | { "BASS_ChannelSetAttribute", (uintptr_t)&BASS_ChannelSetAttribute}, 751 | { "BASS_ChannelPlay", (uintptr_t)&BASS_ChannelPlay}, 752 | { "BASS_ChannelGetInfo", (uintptr_t)&BASS_ChannelGetInfo}, 753 | { "BASS_StreamCreateFile", (uintptr_t)&BASS_StreamCreateFile}, 754 | { "BASS_ChannelIsActive", (uintptr_t)&BASS_ChannelIsActive}, 755 | { "BASS_ChannelGetData", (uintptr_t)&BASS_ChannelGetData}, 756 | { "BASS_ChannelGetLength", (uintptr_t)&BASS_ChannelGetLength}, 757 | { "BASS_ChannelBytes2Seconds", (uintptr_t)&BASS_ChannelBytes2Seconds}, 758 | { "BASS_ChannelGetPosition", (uintptr_t)&BASS_ChannelGetPosition}, 759 | { "BASS_ChannelStop", (uintptr_t)&BASS_ChannelStop}, 760 | { "BASS_ChannelPause", (uintptr_t)&BASS_ChannelPause}, 761 | { "SDL_GetPlatform", (uintptr_t)&SDL_GetPlatform}, 762 | { "sincosf", (uintptr_t)&sincosf }, 763 | { "opendir", (uintptr_t)&opendir_fake }, 764 | { "readdir", (uintptr_t)&readdir_fake }, 765 | { "closedir", (uintptr_t)&closedir_fake }, 766 | { "g_SDL_BufferGeometry_w", (uintptr_t)&g_SDL_BufferGeometry_w }, 767 | { "g_SDL_BufferGeometry_h", (uintptr_t)&g_SDL_BufferGeometry_h }, 768 | { "__aeabi_memclr", (uintptr_t)&sceClibMemclr }, 769 | { "__aeabi_memclr4", (uintptr_t)&sceClibMemclr }, 770 | { "__aeabi_memclr8", (uintptr_t)&sceClibMemclr }, 771 | { "__aeabi_memcpy4", (uintptr_t)&sceClibMemcpy }, 772 | { "__aeabi_memcpy8", (uintptr_t)&sceClibMemcpy }, 773 | { "__aeabi_memmove4", (uintptr_t)&sceClibMemmove }, 774 | { "__aeabi_memmove8", (uintptr_t)&sceClibMemmove }, 775 | { "__aeabi_memcpy", (uintptr_t)&sceClibMemcpy }, 776 | { "__aeabi_memmove", (uintptr_t)&sceClibMemmove }, 777 | { "__aeabi_memset", (uintptr_t)&sceClibMemset2 }, 778 | { "__aeabi_memset4", (uintptr_t)&sceClibMemset2 }, 779 | { "__aeabi_memset8", (uintptr_t)&sceClibMemset2 }, 780 | { "__aeabi_atexit", (uintptr_t)&__aeabi_atexit }, 781 | { "__aeabi_uidiv", (uintptr_t)&__aeabi_uidiv }, 782 | { "__aeabi_uidivmod", (uintptr_t)&__aeabi_uidivmod }, 783 | { "__aeabi_ldivmod", (uintptr_t)&__aeabi_ldivmod }, 784 | { "__aeabi_idivmod", (uintptr_t)&__aeabi_idivmod }, 785 | { "__aeabi_idiv", (uintptr_t)&__aeabi_idiv }, 786 | { "__aeabi_ddiv", (uintptr_t)&__aeabi_ddiv }, 787 | { "__aeabi_dmul", (uintptr_t)&__aeabi_dmul }, 788 | { "__aeabi_dadd", (uintptr_t)&__aeabi_dadd }, 789 | { "__aeabi_i2d", (uintptr_t)&__aeabi_i2d }, 790 | { "__android_log_print", (uintptr_t)&__android_log_print }, 791 | { "__android_log_vprint", (uintptr_t)&__android_log_vprint }, 792 | { "__android_log_write", (uintptr_t)&__android_log_write }, 793 | { "__cxa_atexit", (uintptr_t)&__cxa_atexit }, 794 | { "__cxa_call_unexpected", (uintptr_t)&__cxa_call_unexpected }, 795 | { "__cxa_guard_acquire", (uintptr_t)&__cxa_guard_acquire }, 796 | { "__cxa_guard_release", (uintptr_t)&__cxa_guard_release }, 797 | { "__cxa_finalize", (uintptr_t)&__cxa_finalize }, 798 | { "__errno", (uintptr_t)&__errno }, 799 | { "__strlen_chk", (uintptr_t)&__strlen_chk }, 800 | { "__gnu_unwind_frame", (uintptr_t)&__gnu_unwind_frame }, 801 | { "__gnu_Unwind_Find_exidx", (uintptr_t)&ret0 }, 802 | { "dl_unwind_find_exidx", (uintptr_t)&ret0 }, 803 | { "__sF", (uintptr_t)&__sF_fake }, 804 | { "__stack_chk_fail", (uintptr_t)&__stack_chk_fail }, 805 | { "__stack_chk_guard", (uintptr_t)&__stack_chk_guard_fake }, 806 | { "_ctype_", (uintptr_t)&BIONIC_ctype_}, 807 | { "_tolower_tab_", (uintptr_t)&BIONIC_tolower_tab_}, 808 | { "_toupper_tab_", (uintptr_t)&BIONIC_toupper_tab_}, 809 | { "abort", (uintptr_t)&abort_hook }, 810 | { "access", (uintptr_t)&access }, 811 | { "acos", (uintptr_t)&acos }, 812 | { "acosh", (uintptr_t)&acosh }, 813 | { "asctime", (uintptr_t)&asctime }, 814 | { "acosf", (uintptr_t)&acosf }, 815 | { "asin", (uintptr_t)&asin }, 816 | { "asinh", (uintptr_t)&asinh }, 817 | { "asinf", (uintptr_t)&asinf }, 818 | { "atan", (uintptr_t)&atan }, 819 | { "atanh", (uintptr_t)&atanh }, 820 | { "atan2", (uintptr_t)&atan2 }, 821 | { "atan2f", (uintptr_t)&atan2f }, 822 | { "atanf", (uintptr_t)&atanf }, 823 | { "atoi", (uintptr_t)&atoi }, 824 | { "atol", (uintptr_t)&atol }, 825 | { "atoll", (uintptr_t)&atoll }, 826 | { "basename", (uintptr_t)&basename }, 827 | // { "bind", (uintptr_t)&bind }, 828 | { "bsd_signal", (uintptr_t)&ret0 }, 829 | { "bsearch", (uintptr_t)&bsearch }, 830 | { "btowc", (uintptr_t)&btowc }, 831 | { "calloc", (uintptr_t)&calloc }, 832 | { "ceil", (uintptr_t)&ceil }, 833 | { "ceilf", (uintptr_t)&ceilf }, 834 | { "chdir", (uintptr_t)&chdir_hook }, 835 | { "clearerr", (uintptr_t)&clearerr }, 836 | { "clock", (uintptr_t)&clock }, 837 | { "clock_gettime", (uintptr_t)&clock_gettime_hook }, 838 | { "close", (uintptr_t)&close }, 839 | { "cos", (uintptr_t)&cos }, 840 | { "cosf", (uintptr_t)&cosf }, 841 | { "cosh", (uintptr_t)&cosh }, 842 | { "crc32", (uintptr_t)&crc32 }, 843 | { "deflate", (uintptr_t)&deflate }, 844 | { "deflateEnd", (uintptr_t)&deflateEnd }, 845 | { "deflateInit_", (uintptr_t)&deflateInit_ }, 846 | { "deflateInit2_", (uintptr_t)&deflateInit2_ }, 847 | { "deflateReset", (uintptr_t)&deflateReset }, 848 | { "dlopen", (uintptr_t)&ret0 }, 849 | // { "dlsym", (uintptr_t)&dlsym_hook }, 850 | { "exit", (uintptr_t)&exit }, 851 | { "exp", (uintptr_t)&exp }, 852 | { "exp2", (uintptr_t)&exp2 }, 853 | { "expf", (uintptr_t)&expf }, 854 | { "fabsf", (uintptr_t)&fabsf }, 855 | { "fclose", (uintptr_t)&fclose }, 856 | { "fcntl", (uintptr_t)&ret0 }, 857 | // { "fdopen", (uintptr_t)&fdopen }, 858 | { "ferror", (uintptr_t)&ferror }, 859 | { "fflush", (uintptr_t)&fflush }, 860 | // { "fgets", (uintptr_t)&fgets }, 861 | { "floor", (uintptr_t)&floor }, 862 | { "fileno", (uintptr_t)&fileno }, 863 | { "floorf", (uintptr_t)&floorf }, 864 | { "fmod", (uintptr_t)&fmod }, 865 | { "fmodf", (uintptr_t)&fmodf }, 866 | { "fopen", (uintptr_t)&fopen_hook }, 867 | { "open", (uintptr_t)&open_hook }, 868 | { "fprintf", (uintptr_t)&fprintf }, 869 | { "fputc", (uintptr_t)&fputc }, 870 | // { "fputwc", (uintptr_t)&fputwc }, 871 | // { "fputs", (uintptr_t)&fputs }, 872 | { "fread", (uintptr_t)&fread }, 873 | { "free", (uintptr_t)&free }, 874 | { "frexp", (uintptr_t)&frexp }, 875 | { "frexpf", (uintptr_t)&frexpf }, 876 | // { "fscanf", (uintptr_t)&fscanf }, 877 | { "fseek", (uintptr_t)&fseek }, 878 | { "fseeko", (uintptr_t)&fseeko }, 879 | { "fstat", (uintptr_t)&fstat_hook }, 880 | { "ftell", (uintptr_t)&ftell }, 881 | { "ftello", (uintptr_t)&ftello }, 882 | // { "ftruncate", (uintptr_t)&ftruncate }, 883 | { "fwrite", (uintptr_t)&fwrite }, 884 | { "getc", (uintptr_t)&getc }, 885 | { "getpid", (uintptr_t)&ret0 }, 886 | { "getcwd", (uintptr_t)&getcwd_hook }, 887 | { "getenv", (uintptr_t)&ret0 }, 888 | { "getwc", (uintptr_t)&getwc }, 889 | { "gettimeofday", (uintptr_t)&gettimeofday }, 890 | { "gzopen", (uintptr_t)&gzopen }, 891 | { "inflate", (uintptr_t)&inflate }, 892 | { "inflateEnd", (uintptr_t)&inflateEnd }, 893 | { "inflateInit_", (uintptr_t)&inflateInit_ }, 894 | { "inflateInit2_", (uintptr_t)&inflateInit2_ }, 895 | { "inflateReset", (uintptr_t)&inflateReset }, 896 | { "isascii", (uintptr_t)&isascii }, 897 | { "isalnum", (uintptr_t)&isalnum }, 898 | { "isalpha", (uintptr_t)&isalpha }, 899 | { "iscntrl", (uintptr_t)&iscntrl }, 900 | { "isdigit", (uintptr_t)&isdigit }, 901 | { "islower", (uintptr_t)&islower }, 902 | { "ispunct", (uintptr_t)&ispunct }, 903 | { "isprint", (uintptr_t)&isprint }, 904 | { "isspace", (uintptr_t)&isspace }, 905 | { "isupper", (uintptr_t)&isupper }, 906 | { "iswalpha", (uintptr_t)&iswalpha }, 907 | { "iswcntrl", (uintptr_t)&iswcntrl }, 908 | { "iswctype", (uintptr_t)&iswctype }, 909 | { "iswdigit", (uintptr_t)&iswdigit }, 910 | { "iswdigit", (uintptr_t)&iswdigit }, 911 | { "iswlower", (uintptr_t)&iswlower }, 912 | { "iswprint", (uintptr_t)&iswprint }, 913 | { "iswpunct", (uintptr_t)&iswpunct }, 914 | { "iswspace", (uintptr_t)&iswspace }, 915 | { "iswupper", (uintptr_t)&iswupper }, 916 | { "iswxdigit", (uintptr_t)&iswxdigit }, 917 | { "isxdigit", (uintptr_t)&isxdigit }, 918 | { "ldexp", (uintptr_t)&ldexp }, 919 | { "ldexpf", (uintptr_t)&ldexpf }, 920 | // { "listen", (uintptr_t)&listen }, 921 | { "localtime", (uintptr_t)&localtime }, 922 | { "localtime_r", (uintptr_t)&localtime_r }, 923 | { "log", (uintptr_t)&log }, 924 | { "logf", (uintptr_t)&logf }, 925 | { "log10", (uintptr_t)&log10 }, 926 | { "log10f", (uintptr_t)&log10f }, 927 | { "longjmp", (uintptr_t)&longjmp }, 928 | { "lrand48", (uintptr_t)&lrand48 }, 929 | { "lrint", (uintptr_t)&lrint }, 930 | { "lrintf", (uintptr_t)&lrintf }, 931 | { "lseek", (uintptr_t)&lseek }, 932 | { "lseek64", (uintptr_t)&lseek64 }, 933 | { "malloc", (uintptr_t)&malloc }, 934 | { "mbrtowc", (uintptr_t)&mbrtowc }, 935 | { "memalign", (uintptr_t)&memalign }, 936 | { "memchr", (uintptr_t)&sceClibMemchr }, 937 | { "memcmp", (uintptr_t)&memcmp }, 938 | { "memcpy", (uintptr_t)&sceClibMemcpy }, 939 | { "memmove", (uintptr_t)&sceClibMemmove }, 940 | { "memset", (uintptr_t)&sceClibMemset }, 941 | { "mkdir", (uintptr_t)&mkdir }, 942 | // { "mmap", (uintptr_t)&mmap}, 943 | // { "munmap", (uintptr_t)&munmap}, 944 | { "modf", (uintptr_t)&modf }, 945 | { "modff", (uintptr_t)&modff }, 946 | // { "poll", (uintptr_t)&poll }, 947 | { "pow", (uintptr_t)&pow }, 948 | { "powf", (uintptr_t)&powf }, 949 | { "printf", (uintptr_t)&printf }, 950 | { "pthread_attr_destroy", (uintptr_t)&ret0 }, 951 | { "pthread_attr_init", (uintptr_t)&ret0 }, 952 | { "pthread_attr_setdetachstate", (uintptr_t)&ret0 }, 953 | { "pthread_attr_setstacksize", (uintptr_t)&ret0 }, 954 | { "pthread_cond_init", (uintptr_t)&pthread_cond_init_fake}, 955 | { "pthread_cond_broadcast", (uintptr_t)&pthread_cond_broadcast_fake}, 956 | { "pthread_cond_wait", (uintptr_t)&pthread_cond_wait_fake}, 957 | { "pthread_cond_signal", (uintptr_t)&pthread_cond_signal_fake}, 958 | { "pthread_cond_destroy", (uintptr_t)&pthread_cond_destroy_fake}, 959 | { "pthread_cond_timedwait", (uintptr_t)&pthread_cond_timedwait_fake}, 960 | { "pthread_cond_timedwait_relative_np", (uintptr_t)&pthread_cond_timedwait_relative_np_fake}, // FIXME 961 | { "pthread_create", (uintptr_t)&pthread_create_fake }, 962 | { "pthread_getschedparam", (uintptr_t)&pthread_getschedparam }, 963 | { "pthread_getspecific", (uintptr_t)&pthread_getspecific }, 964 | { "pthread_key_create", (uintptr_t)&pthread_key_create }, 965 | { "pthread_key_delete", (uintptr_t)&pthread_key_delete }, 966 | { "pthread_mutex_destroy", (uintptr_t)&pthread_mutex_destroy_fake }, 967 | { "pthread_mutex_init", (uintptr_t)&pthread_mutex_init_fake }, 968 | { "pthread_mutex_trylock", (uintptr_t)&pthread_mutex_trylock_fake }, 969 | { "pthread_mutex_lock", (uintptr_t)&pthread_mutex_lock_fake }, 970 | { "pthread_mutex_unlock", (uintptr_t)&pthread_mutex_unlock_fake }, 971 | { "pthread_mutexattr_destroy", (uintptr_t)&pthread_mutexattr_destroy}, 972 | { "pthread_mutexattr_init", (uintptr_t)&pthread_mutexattr_init}, 973 | { "pthread_mutexattr_settype", (uintptr_t)&pthread_mutexattr_settype}, 974 | { "pthread_once", (uintptr_t)&pthread_once_fake }, 975 | { "pthread_self", (uintptr_t)&pthread_self }, 976 | { "pthread_setname_np", (uintptr_t)&ret0 }, 977 | { "pthread_getschedparam", (uintptr_t)&pthread_getschedparam }, 978 | { "pthread_setschedparam", (uintptr_t)&pthread_setschedparam }, 979 | { "pthread_setspecific", (uintptr_t)&pthread_setspecific }, 980 | { "sched_get_priority_min", (uintptr_t)&ret0 }, 981 | { "sched_get_priority_max", (uintptr_t)&ret99 }, 982 | { "putc", (uintptr_t)&putc }, 983 | { "puts", (uintptr_t)&puts }, 984 | { "putwc", (uintptr_t)&putwc }, 985 | { "qsort", (uintptr_t)&qsort }, 986 | { "rand", (uintptr_t)&rand }, 987 | { "read", (uintptr_t)&read }, 988 | { "realpath", (uintptr_t)&realpath }, 989 | { "realloc", (uintptr_t)&realloc }, 990 | // { "recv", (uintptr_t)&recv }, 991 | { "roundf", (uintptr_t)&roundf }, 992 | { "rint", (uintptr_t)&rint }, 993 | { "rintf", (uintptr_t)&rintf }, 994 | // { "send", (uintptr_t)&send }, 995 | // { "sendto", (uintptr_t)&sendto }, 996 | { "setenv", (uintptr_t)&ret0 }, 997 | { "setjmp", (uintptr_t)&setjmp }, 998 | { "setlocale", (uintptr_t)&ret0 }, 999 | // { "setsockopt", (uintptr_t)&setsockopt }, 1000 | { "setvbuf", (uintptr_t)&setvbuf }, 1001 | { "sin", (uintptr_t)&sin }, 1002 | { "sinf", (uintptr_t)&sinf }, 1003 | { "sinh", (uintptr_t)&sinh }, 1004 | //{ "sincos", (uintptr_t)&sincos }, 1005 | { "snprintf", (uintptr_t)&snprintf }, 1006 | // { "socket", (uintptr_t)&socket }, 1007 | { "sprintf", (uintptr_t)&sprintf }, 1008 | { "sqrt", (uintptr_t)&sqrt }, 1009 | { "sqrtf", (uintptr_t)&sqrtf }, 1010 | { "srand", (uintptr_t)&srand }, 1011 | { "srand48", (uintptr_t)&srand48 }, 1012 | { "sscanf", (uintptr_t)&sscanf }, 1013 | { "stat", (uintptr_t)&stat_hook }, 1014 | { "strcasecmp", (uintptr_t)&strcasecmp }, 1015 | { "strcasestr", (uintptr_t)&strstr }, 1016 | { "strcat", (uintptr_t)&strcat }, 1017 | { "strchr", (uintptr_t)&strchr }, 1018 | { "strcmp", (uintptr_t)&sceClibStrcmp }, 1019 | { "strcoll", (uintptr_t)&strcoll }, 1020 | { "strcpy", (uintptr_t)&strcpy }, 1021 | { "strcspn", (uintptr_t)&strcspn }, 1022 | { "strdup", (uintptr_t)&strdup }, 1023 | { "strerror", (uintptr_t)&strerror }, 1024 | { "strftime", (uintptr_t)&strftime }, 1025 | { "strlcpy", (uintptr_t)&strlcpy }, 1026 | { "strlen", (uintptr_t)&strlen }, 1027 | { "strncasecmp", (uintptr_t)&sceClibStrncasecmp }, 1028 | { "strncat", (uintptr_t)&sceClibStrncat }, 1029 | { "strncmp", (uintptr_t)&sceClibStrncmp }, 1030 | { "strncpy", (uintptr_t)&sceClibStrncpy }, 1031 | { "strpbrk", (uintptr_t)&strpbrk }, 1032 | { "strrchr", (uintptr_t)&sceClibStrrchr }, 1033 | { "strstr", (uintptr_t)&sceClibStrstr }, 1034 | { "strtod", (uintptr_t)&strtod }, 1035 | { "strtol", (uintptr_t)&strtol }, 1036 | { "strtoul", (uintptr_t)&strtoul }, 1037 | { "strtoll", (uintptr_t)&strtoll }, 1038 | { "strtoull", (uintptr_t)&strtoull }, 1039 | { "strxfrm", (uintptr_t)&strxfrm }, 1040 | { "sysconf", (uintptr_t)&ret0 }, 1041 | { "tan", (uintptr_t)&tan }, 1042 | { "tanf", (uintptr_t)&tanf }, 1043 | { "tanh", (uintptr_t)&tanh }, 1044 | { "time", (uintptr_t)&time }, 1045 | { "tolower", (uintptr_t)&tolower }, 1046 | { "toupper", (uintptr_t)&toupper }, 1047 | { "towlower", (uintptr_t)&towlower }, 1048 | { "towupper", (uintptr_t)&towupper }, 1049 | { "ungetc", (uintptr_t)&ungetc }, 1050 | { "ungetwc", (uintptr_t)&ungetwc }, 1051 | { "usleep", (uintptr_t)&usleep }, 1052 | { "vfprintf", (uintptr_t)&vfprintf }, 1053 | { "vprintf", (uintptr_t)&vprintf }, 1054 | { "vsnprintf", (uintptr_t)&vsnprintf }, 1055 | { "vsprintf", (uintptr_t)&vsprintf }, 1056 | { "vswprintf", (uintptr_t)&vswprintf }, 1057 | { "wcrtomb", (uintptr_t)&wcrtomb }, 1058 | { "wcscoll", (uintptr_t)&wcscoll }, 1059 | { "wcscmp", (uintptr_t)&wcscmp }, 1060 | { "wcsncpy", (uintptr_t)&wcsncpy }, 1061 | { "wcsftime", (uintptr_t)&wcsftime }, 1062 | { "wcslen", (uintptr_t)&wcslen }, 1063 | { "wcsxfrm", (uintptr_t)&wcsxfrm }, 1064 | { "wctob", (uintptr_t)&wctob }, 1065 | { "wctype", (uintptr_t)&wctype }, 1066 | { "wmemchr", (uintptr_t)&wmemchr }, 1067 | { "wmemcmp", (uintptr_t)&wmemcmp }, 1068 | { "wmemcpy", (uintptr_t)&wmemcpy }, 1069 | { "wmemmove", (uintptr_t)&wmemmove }, 1070 | { "wmemset", (uintptr_t)&wmemset }, 1071 | { "write", (uintptr_t)&write }, 1072 | // { "writev", (uintptr_t)&writev }, 1073 | { "unlink", (uintptr_t)&unlink }, 1074 | { "SDL_AndroidGetActivityClass", (uintptr_t)&ret0 }, 1075 | { "SDL_IsTextInputActive", (uintptr_t)&SDL_IsTextInputActive }, 1076 | { "SDL_GameControllerEventState", (uintptr_t)&SDL_GameControllerEventState }, 1077 | { "SDL_WarpMouseInWindow", (uintptr_t)&SDL_WarpMouseInWindow }, 1078 | { "SDL_AndroidGetExternalStoragePath", (uintptr_t)&SDL_AndroidGetExternalStoragePath }, 1079 | { "SDL_AndroidGetInternalStoragePath", (uintptr_t)&SDL_AndroidGetInternalStoragePath }, 1080 | { "SDL_Android_Init", (uintptr_t)&ret1 }, 1081 | { "SDL_AddTimer", (uintptr_t)&SDL_AddTimer }, 1082 | { "SDL_CondSignal", (uintptr_t)&SDL_CondSignal }, 1083 | { "SDL_CondWait", (uintptr_t)&SDL_CondWait }, 1084 | { "SDL_ConvertSurfaceFormat", (uintptr_t)&SDL_ConvertSurfaceFormat }, 1085 | { "SDL_CreateCond", (uintptr_t)&SDL_CreateCond }, 1086 | { "SDL_CreateMutex", (uintptr_t)&SDL_CreateMutex }, 1087 | { "SDL_CreateRenderer", (uintptr_t)&SDL_CreateRenderer }, 1088 | { "SDL_CreateRGBSurface", (uintptr_t)&SDL_CreateRGBSurface }, 1089 | { "SDL_CreateTexture", (uintptr_t)&SDL_CreateTexture }, 1090 | { "SDL_CreateTextureFromSurface", (uintptr_t)&SDL_CreateTextureFromSurface }, 1091 | { "SDL_CreateThread", (uintptr_t)&SDL_CreateThread }, 1092 | { "SDL_CreateWindow", (uintptr_t)&SDL_CreateWindow_hook }, 1093 | { "SDL_Delay", (uintptr_t)&SDL_Delay }, 1094 | { "SDL_DestroyMutex", (uintptr_t)&SDL_DestroyMutex }, 1095 | { "SDL_DestroyRenderer", (uintptr_t)&SDL_DestroyRenderer }, 1096 | { "SDL_DestroyTexture", (uintptr_t)&SDL_DestroyTexture }, 1097 | { "SDL_DestroyWindow", (uintptr_t)&SDL_DestroyWindow }, 1098 | { "SDL_FillRect", (uintptr_t)&SDL_FillRect }, 1099 | { "SDL_FreeSurface", (uintptr_t)&SDL_FreeSurface }, 1100 | { "SDL_GetCurrentDisplayMode", (uintptr_t)&SDL_GetCurrentDisplayMode }, 1101 | { "SDL_GetDisplayMode", (uintptr_t)&SDL_GetDisplayMode }, 1102 | { "SDL_GetError", (uintptr_t)&SDL_GetError }, 1103 | { "SDL_GetModState", (uintptr_t)&SDL_GetModState }, 1104 | { "SDL_GetMouseState", (uintptr_t)&SDL_GetMouseState }, 1105 | { "SDL_GetRGBA", (uintptr_t)&SDL_GetRGBA }, 1106 | { "SDL_GameControllerAddMappingsFromRW", (uintptr_t)&SDL_GameControllerAddMappingsFromRW }, 1107 | { "SDL_GetNumDisplayModes", (uintptr_t)&SDL_GetNumDisplayModes }, 1108 | { "SDL_GetRendererInfo", (uintptr_t)&SDL_GetRendererInfo }, 1109 | { "SDL_GetTextureBlendMode", (uintptr_t)&SDL_GetTextureBlendMode }, 1110 | { "SDL_GetPrefPath", (uintptr_t)&SDL_GetPrefPath }, 1111 | { "SDL_GetTextureColorMod", (uintptr_t)&SDL_GetTextureColorMod }, 1112 | { "SDL_GetTicks", (uintptr_t)&SDL_GetTicks }, 1113 | { "SDL_GetVersion", (uintptr_t)&SDL_GetVersion_fake }, 1114 | { "SDL_GL_BindTexture", (uintptr_t)&SDL_GL_BindTexture }, 1115 | { "SDL_GL_GetCurrentContext", (uintptr_t)&SDL_GL_GetCurrentContext }, 1116 | { "SDL_GL_MakeCurrent", (uintptr_t)&SDL_GL_MakeCurrent }, 1117 | { "SDL_GL_SetAttribute", (uintptr_t)&SDL_GL_SetAttribute }, 1118 | { "SDL_Init", (uintptr_t)&SDL_Init }, 1119 | { "SDL_InitSubSystem", (uintptr_t)&SDL_InitSubSystem }, 1120 | { "SDL_IntersectRect", (uintptr_t)&SDL_IntersectRect }, 1121 | { "SDL_LockMutex", (uintptr_t)&SDL_LockMutex }, 1122 | { "SDL_LockSurface", (uintptr_t)&SDL_LockSurface }, 1123 | { "SDL_Log", (uintptr_t)&ret0 }, 1124 | { "SDL_LogError", (uintptr_t)&ret0 }, 1125 | { "SDL_LogSetPriority", (uintptr_t)&ret0 }, 1126 | { "SDL_MapRGB", (uintptr_t)&SDL_MapRGB }, 1127 | { "SDL_JoystickInstanceID", (uintptr_t)&SDL_JoystickInstanceID }, 1128 | { "SDL_GameControllerGetAxis", (uintptr_t)&SDL_GameControllerGetAxis }, 1129 | { "SDL_MinimizeWindow", (uintptr_t)&SDL_MinimizeWindow }, 1130 | { "SDL_PeepEvents", (uintptr_t)&SDL_PeepEvents }, 1131 | { "SDL_PumpEvents", (uintptr_t)&SDL_PumpEvents }, 1132 | { "SDL_PushEvent", (uintptr_t)&SDL_PushEvent }, 1133 | { "SDL_PollEvent", (uintptr_t)&SDL_PollEvent }, 1134 | { "SDL_QueryTexture", (uintptr_t)&SDL_QueryTexture }, 1135 | { "SDL_Quit", (uintptr_t)&SDL_Quit }, 1136 | { "SDL_RemoveTimer", (uintptr_t)&SDL_RemoveTimer }, 1137 | { "SDL_RenderClear", (uintptr_t)&SDL_RenderClear }, 1138 | { "SDL_RenderCopy", (uintptr_t)&SDL_RenderCopy }, 1139 | { "SDL_RenderFillRect", (uintptr_t)&SDL_RenderFillRect }, 1140 | { "SDL_RenderPresent", (uintptr_t)&SDL_RenderPresent }, 1141 | { "SDL_RWFromFile", (uintptr_t)&SDL_RWFromFile_hook }, 1142 | { "SDL_RWread", (uintptr_t)&SDL_RWread }, 1143 | { "SDL_RWwrite", (uintptr_t)&SDL_RWwrite }, 1144 | { "SDL_RWclose", (uintptr_t)&SDL_RWclose }, 1145 | { "SDL_RWsize", (uintptr_t)&SDL_RWsize }, 1146 | { "SDL_RWFromMem", (uintptr_t)&SDL_RWFromMem }, 1147 | { "SDL_SetColorKey", (uintptr_t)&SDL_SetColorKey }, 1148 | { "SDL_SetEventFilter", (uintptr_t)&SDL_SetEventFilter }, 1149 | { "SDL_SetHint", (uintptr_t)&SDL_SetHint }, 1150 | { "SDL_SetMainReady_REAL", (uintptr_t)&SDL_SetMainReady }, 1151 | { "SDL_SetRenderDrawBlendMode", (uintptr_t)&SDL_SetRenderDrawBlendMode }, 1152 | { "SDL_SetRenderDrawColor", (uintptr_t)&SDL_SetRenderDrawColor }, 1153 | { "SDL_SetRenderTarget", (uintptr_t)&SDL_SetRenderTarget }, 1154 | { "SDL_SetTextureBlendMode", (uintptr_t)&SDL_SetTextureBlendMode }, 1155 | { "SDL_SetTextureColorMod", (uintptr_t)&SDL_SetTextureColorMod }, 1156 | { "SDL_ShowCursor", (uintptr_t)&SDL_ShowCursor }, 1157 | { "SDL_ShowSimpleMessageBox", (uintptr_t)&SDL_ShowSimpleMessageBox }, 1158 | { "SDL_StartTextInput", (uintptr_t)&SDL_StartTextInput }, 1159 | { "SDL_StopTextInput", (uintptr_t)&SDL_StopTextInput }, 1160 | { "SDL_strdup", (uintptr_t)&SDL_strdup }, 1161 | { "SDL_UnlockMutex", (uintptr_t)&SDL_UnlockMutex }, 1162 | { "SDL_UnlockSurface", (uintptr_t)&SDL_UnlockSurface }, 1163 | { "SDL_UpdateTexture", (uintptr_t)&SDL_UpdateTexture }, 1164 | { "SDL_UpperBlit", (uintptr_t)&SDL_UpperBlit }, 1165 | { "SDL_WaitThread", (uintptr_t)&SDL_WaitThread }, 1166 | { "SDL_GetKeyFromScancode", (uintptr_t)&SDL_GetKeyFromScancode }, 1167 | { "SDL_GetNumVideoDisplays", (uintptr_t)&SDL_GetNumVideoDisplays }, 1168 | { "SDL_GetDisplayBounds", (uintptr_t)&SDL_GetDisplayBounds }, 1169 | { "SDL_UnionRect", (uintptr_t)&SDL_UnionRect }, 1170 | { "SDL_GetKeyboardFocus", (uintptr_t)&SDL_GetKeyboardFocus }, 1171 | { "SDL_GetRelativeMouseMode", (uintptr_t)&SDL_GetRelativeMouseMode }, 1172 | { "SDL_NumJoysticks", (uintptr_t)&SDL_NumJoysticks }, 1173 | { "SDL_GL_GetDrawableSize", (uintptr_t)&SDL_GL_GetDrawableSize }, 1174 | { "SDL_GameControllerOpen", (uintptr_t)&SDL_GameControllerOpen }, 1175 | { "SDL_GameControllerGetJoystick", (uintptr_t)&SDL_GameControllerGetJoystick }, 1176 | { "SDL_HapticOpenFromJoystick", (uintptr_t)&SDL_HapticOpenFromJoystick }, 1177 | { "SDL_GetPerformanceFrequency", (uintptr_t)&SDL_GetPerformanceFrequency }, 1178 | { "SDL_GetPerformanceCounter", (uintptr_t)&SDL_GetPerformanceCounter }, 1179 | { "SDL_GetMouseFocus", (uintptr_t)&SDL_GetMouseFocus }, 1180 | { "SDL_ShowMessageBox", (uintptr_t)&SDL_ShowMessageBox }, 1181 | { "SDL_RaiseWindow", (uintptr_t)&SDL_RaiseWindow }, 1182 | { "SDL_GL_GetAttribute", (uintptr_t)&SDL_GL_GetAttribute }, 1183 | { "SDL_GL_CreateContext", (uintptr_t)&SDL_GL_CreateContext }, 1184 | { "SDL_GL_GetProcAddress", (uintptr_t)&SDL_GL_GetProcAddress_fake }, 1185 | { "SDL_GL_DeleteContext", (uintptr_t)&SDL_GL_DeleteContext }, 1186 | { "SDL_GetDesktopDisplayMode", (uintptr_t)&SDL_GetDesktopDisplayMode }, 1187 | { "SDL_SetWindowData", (uintptr_t)&SDL_SetWindowData }, 1188 | { "SDL_GetWindowFlags", (uintptr_t)&SDL_GetWindowFlags }, 1189 | { "SDL_GetWindowSize", (uintptr_t)&SDL_GetWindowSize }, 1190 | { "SDL_GetWindowDisplayIndex", (uintptr_t)&SDL_GetWindowDisplayIndex }, 1191 | { "SDL_SetWindowFullscreen", (uintptr_t)&SDL_SetWindowFullscreen }, 1192 | { "SDL_SetWindowSize", (uintptr_t)&SDL_SetWindowSize }, 1193 | { "SDL_SetWindowPosition", (uintptr_t)&SDL_SetWindowPosition }, 1194 | { "SDL_GL_GetCurrentWindow", (uintptr_t)&SDL_GL_GetCurrentWindow }, 1195 | { "SDL_GetWindowData", (uintptr_t)&SDL_GetWindowData }, 1196 | { "SDL_GetWindowTitle", (uintptr_t)&SDL_GetWindowTitle }, 1197 | { "SDL_ResetKeyboard", (uintptr_t)&SDL_ResetKeyboard }, 1198 | { "SDL_SetWindowTitle", (uintptr_t)&SDL_SetWindowTitle }, 1199 | { "SDL_GetWindowPosition", (uintptr_t)&SDL_GetWindowPosition }, 1200 | { "SDL_GL_SetSwapInterval", (uintptr_t)&ret0 }, 1201 | { "SDL_IsGameController", (uintptr_t)&SDL_IsGameController }, 1202 | { "SDL_JoystickGetDeviceGUID", (uintptr_t)&SDL_JoystickGetDeviceGUID }, 1203 | { "SDL_GameControllerNameForIndex", (uintptr_t)&SDL_GameControllerNameForIndex }, 1204 | { "SDL_GetWindowFromID", (uintptr_t)&SDL_GetWindowFromID }, 1205 | { "SDL_GL_SwapWindow", (uintptr_t)&SDL_GL_SwapWindow }, 1206 | { "SDL_SetMainReady", (uintptr_t)&SDL_SetMainReady }, 1207 | { "SDL_NumAccelerometers", (uintptr_t)&ret0 }, 1208 | { "SDL_AndroidGetJNIEnv", (uintptr_t)&Android_JNI_GetEnv }, 1209 | { "Android_JNI_GetEnv", (uintptr_t)&Android_JNI_GetEnv }, 1210 | { "SDL_RWFromConstMem", (uintptr_t)&SDL_RWFromConstMem }, 1211 | { "SDL_ConvertSurface", (uintptr_t)&SDL_ConvertSurface }, 1212 | { "SDL_SetError", (uintptr_t)&SDL_SetError }, 1213 | { "SDL_MapRGBA", (uintptr_t)&SDL_MapRGBA }, 1214 | { "SDL_EventState", (uintptr_t)&SDL_EventState }, 1215 | { "SDL_SetSurfaceBlendMode", (uintptr_t)&SDL_SetSurfaceBlendMode }, 1216 | { "SDL_UpperBlitScaled", (uintptr_t)&SDL_UpperBlitScaled }, 1217 | { "SDL_FreeRW", (uintptr_t)&SDL_FreeRW }, 1218 | { "SDL_GetKeyboardState", (uintptr_t)&SDL_GetKeyboardState }, 1219 | { "SDL_JoystickNumAxes", (uintptr_t)&ret4 }, 1220 | { "SDL_JoystickUpdate", (uintptr_t)&SDL_JoystickUpdate }, 1221 | { "SDL_JoystickGetAxis", (uintptr_t)&SDL_JoystickGetAxis }, 1222 | { "SDL_JoystickGetButton", (uintptr_t)&SDL_JoystickGetButton }, 1223 | { "SDL_GetScancodeFromKey", (uintptr_t)&SDL_GetScancodeFromKey }, 1224 | { "SDL_GetKeyName", (uintptr_t)&SDL_GetKeyName }, 1225 | { "SDL_GetScancodeName", (uintptr_t)&SDL_GetScancodeName }, 1226 | { "SDL_JoystickGetHat", (uintptr_t)&SDL_JoystickGetHat }, 1227 | { "SDL_JoystickClose", (uintptr_t)&SDL_JoystickClose }, 1228 | { "SDL_JoystickOpen", (uintptr_t)&SDL_JoystickOpen }, 1229 | { "SDL_JoystickEventState", (uintptr_t)&SDL_JoystickEventState }, 1230 | { "SDL_LogSetAllPriority", (uintptr_t)&SDL_LogSetAllPriority }, 1231 | { "SDL_LogMessageV", (uintptr_t)&SDL_LogMessageV }, 1232 | { "SDL_RWtell", (uintptr_t)&SDL_RWtell }, 1233 | { "SDL_AndroidGetActivity", (uintptr_t)&ret0 }, 1234 | { "SDL_free", (uintptr_t)&SDL_free }, 1235 | { "SDL_AtomicAdd", (uintptr_t)&SDL_AtomicAdd }, 1236 | { "SDL_AtomicSet", (uintptr_t)&SDL_AtomicSet }, 1237 | { "SDL_CreateSystemCursor", (uintptr_t)&SDL_CreateSystemCursor }, 1238 | { "SDL_OpenAudio", (uintptr_t)&SDL_OpenAudio }, 1239 | { "SDL_CloseAudio", (uintptr_t)&SDL_CloseAudio }, 1240 | { "SDL_PauseAudio", (uintptr_t)&SDL_PauseAudio }, 1241 | { "SDL_CreateCursor", (uintptr_t)&SDL_CreateCursor }, 1242 | { "SDL_SetCursor", (uintptr_t)&SDL_SetCursor }, 1243 | { "SDL_GameControllerClose", (uintptr_t)&SDL_GameControllerClose }, 1244 | { "SDL_FreeCursor", (uintptr_t)&SDL_FreeCursor }, 1245 | { "SDL_CreateColorCursor", (uintptr_t)&SDL_CreateColorCursor }, 1246 | { "IMG_Init", (uintptr_t)&IMG_Init }, 1247 | { "IMG_Quit", (uintptr_t)&IMG_Quit }, 1248 | { "Mix_PauseMusic", (uintptr_t)&Mix_PauseMusic }, 1249 | { "Mix_ResumeMusic", (uintptr_t)&Mix_ResumeMusic }, 1250 | { "Mix_VolumeMusic", (uintptr_t)&Mix_VolumeMusic }, 1251 | { "Mix_LoadMUS", (uintptr_t)&Mix_LoadMUS_hook }, 1252 | { "Mix_PlayMusic", (uintptr_t)&Mix_PlayMusic }, 1253 | { "Mix_FreeMusic", (uintptr_t)&ret0 }, // FIXME 1254 | { "Mix_RewindMusic", (uintptr_t)&Mix_RewindMusic }, 1255 | { "Mix_SetMusicPosition", (uintptr_t)&Mix_SetMusicPosition }, 1256 | { "Mix_CloseAudio", (uintptr_t)&Mix_CloseAudio }, 1257 | { "Mix_OpenAudio", (uintptr_t)&Mix_OpenAudio_hook }, 1258 | { "Mix_RegisterEffect", (uintptr_t)&Mix_RegisterEffect }, 1259 | { "Mix_Resume", (uintptr_t)&Mix_Resume }, 1260 | { "Mix_AllocateChannels", (uintptr_t)&Mix_AllocateChannels }, 1261 | { "Mix_ChannelFinished", (uintptr_t)&Mix_ChannelFinished }, 1262 | { "Mix_LoadWAV_RW", (uintptr_t)&Mix_LoadWAV_RW }, 1263 | { "Mix_FreeChunk", (uintptr_t)&Mix_FreeChunk }, 1264 | { "Mix_PausedMusic", (uintptr_t)&Mix_PausedMusic }, 1265 | { "Mix_Paused", (uintptr_t)&Mix_Paused }, 1266 | { "Mix_PlayingMusic", (uintptr_t)&Mix_PlayingMusic }, 1267 | { "Mix_Playing", (uintptr_t)&Mix_Playing }, 1268 | { "Mix_Volume", (uintptr_t)&Mix_Volume }, 1269 | { "Mix_SetDistance", (uintptr_t)&Mix_SetDistance }, 1270 | { "Mix_SetPanning", (uintptr_t)&Mix_SetPanning }, 1271 | { "Mix_QuerySpec", (uintptr_t)&Mix_QuerySpec }, 1272 | { "Mix_UnregisterEffect", (uintptr_t)&Mix_UnregisterEffect }, 1273 | { "Mix_HaltMusic", (uintptr_t)&Mix_HaltMusic }, 1274 | { "Mix_HaltChannel", (uintptr_t)&Mix_HaltChannel }, 1275 | { "Mix_LoadMUS_RW", (uintptr_t)&Mix_LoadMUS_RW }, 1276 | { "Mix_PlayChannelTimed", (uintptr_t)&Mix_PlayChannelTimed }, 1277 | { "Mix_Pause", (uintptr_t)&Mix_Pause }, 1278 | { "Mix_Init", (uintptr_t)&Mix_Init }, 1279 | /*{ "TTF_Quit", (uintptr_t)&TTF_Quit }, 1280 | { "TTF_Init", (uintptr_t)&TTF_Init }, 1281 | { "TTF_RenderText_Blended", (uintptr_t)&TTF_RenderText_Blended }, 1282 | { "TTF_OpenFontRW", (uintptr_t)&TTF_OpenFontRW }, 1283 | { "TTF_SetFontOutline", (uintptr_t)&TTF_SetFontOutline }, 1284 | { "TTF_CloseFont", (uintptr_t)&TTF_CloseFont }, 1285 | { "TTF_GlyphIsProvided", (uintptr_t)&TTF_GlyphIsProvided },*/ 1286 | { "IMG_Load", (uintptr_t)&IMG_Load_hook }, 1287 | { "IMG_Load_RW", (uintptr_t)&IMG_Load_RW }, 1288 | { "raise", (uintptr_t)&raise }, 1289 | { "posix_memalign", (uintptr_t)&posix_memalign }, 1290 | { "swprintf", (uintptr_t)&swprintf }, 1291 | { "wcscpy", (uintptr_t)&wcscpy }, 1292 | { "wcscat", (uintptr_t)&wcscat }, 1293 | { "wcstombs", (uintptr_t)&wcstombs }, 1294 | { "wcsstr", (uintptr_t)&wcsstr }, 1295 | { "compress", (uintptr_t)&compress }, 1296 | { "uncompress", (uintptr_t)&uncompress }, 1297 | { "atof", (uintptr_t)&atof }, 1298 | { "SDLNet_FreePacket", (uintptr_t)&SDLNet_FreePacket }, 1299 | { "SDLNet_Quit", (uintptr_t)&SDLNet_Quit }, 1300 | { "SDLNet_GetError", (uintptr_t)&SDLNet_GetError }, 1301 | { "SDLNet_Init", (uintptr_t)&SDLNet_Init }, 1302 | { "SDLNet_AllocPacket", (uintptr_t)&SDLNet_AllocPacket }, 1303 | { "SDLNet_UDP_Recv", (uintptr_t)&SDLNet_UDP_Recv }, 1304 | { "SDLNet_UDP_Send", (uintptr_t)&SDLNet_UDP_Send }, 1305 | { "SDLNet_GetLocalAddresses", (uintptr_t)&SDLNet_GetLocalAddresses }, 1306 | { "SDLNet_UDP_Close", (uintptr_t)&SDLNet_UDP_Close }, 1307 | { "SDLNet_ResolveHost", (uintptr_t)&SDLNet_ResolveHost }, 1308 | { "SDLNet_UDP_Open", (uintptr_t)&SDLNet_UDP_Open }, 1309 | { "remove", (uintptr_t)&remove }, 1310 | { "IMG_SavePNG", (uintptr_t)&IMG_SavePNG }, 1311 | { "SDL_DetachThread", (uintptr_t)&SDL_DetachThread }, 1312 | /*{ "TTF_SetFontHinting", (uintptr_t)&TTF_SetFontHinting }, 1313 | { "TTF_FontHeight", (uintptr_t)&TTF_FontHeight }, 1314 | { "TTF_FontAscent", (uintptr_t)&TTF_FontAscent }, 1315 | { "TTF_FontDescent", (uintptr_t)&TTF_FontDescent }, 1316 | { "TTF_SizeUTF8", (uintptr_t)&TTF_SizeUTF8 }, 1317 | { "TTF_SizeText", (uintptr_t)&TTF_SizeText }, 1318 | { "TTF_SetFontStyle", (uintptr_t)&TTF_SetFontStyle }, 1319 | { "TTF_RenderUTF8_Blended", (uintptr_t)&TTF_RenderUTF8_Blended },*/ 1320 | { "SDL_strlen", (uintptr_t)&SDL_strlen }, 1321 | { "SDL_LogDebug", (uintptr_t)&SDL_LogDebug }, 1322 | { "SDL_HasEvents", (uintptr_t)&SDL_HasEvents }, 1323 | { "SDL_RWseek", (uintptr_t)&SDL_RWseek }, 1324 | { "SDL_JoystickNameForIndex", (uintptr_t)&SDL_JoystickNameForIndex }, 1325 | { "SDL_JoystickNumButtons", (uintptr_t)&SDL_JoystickNumButtons }, 1326 | { "SDL_JoystickGetGUID", (uintptr_t)&SDL_JoystickGetGUID }, 1327 | { "SDL_JoystickGetGUIDString", (uintptr_t)&SDL_JoystickGetGUIDString }, 1328 | { "SDL_JoystickNumHats", (uintptr_t)&SDL_JoystickNumHats }, 1329 | { "SDL_JoystickNumBalls", (uintptr_t)&SDL_JoystickNumBalls }, 1330 | { "SDL_JoystickName", (uintptr_t)&SDL_JoystickName_fake }, 1331 | { "SDL_GetNumRenderDrivers", (uintptr_t)&SDL_GetNumRenderDrivers }, 1332 | { "SDL_GetRenderDriverInfo", (uintptr_t)&SDL_GetRenderDriverInfo }, 1333 | { "SDL_GetNumVideoDrivers", (uintptr_t)&SDL_GetNumVideoDrivers }, 1334 | { "SDL_GetVideoDriver", (uintptr_t)&SDL_GetVideoDriver }, 1335 | { "SDL_GetBasePath", (uintptr_t)&SDL_GetBasePath_hook }, 1336 | { "SDL_RenderReadPixels", (uintptr_t)&SDL_RenderReadPixels }, 1337 | { "SDL_CreateRGBSurfaceFrom", (uintptr_t)&SDL_CreateRGBSurfaceFrom }, 1338 | { "SDL_SetWindowBordered", (uintptr_t)&SDL_SetWindowBordered }, 1339 | { "SDL_RestoreWindow", (uintptr_t)&SDL_RestoreWindow }, 1340 | { "SDL_sqrt", (uintptr_t)&SDL_sqrt }, 1341 | { "SDL_ThreadID", (uintptr_t)&SDL_ThreadID }, 1342 | }; 1343 | static size_t numhooks = sizeof(default_dynlib) / sizeof(*default_dynlib); 1344 | 1345 | int check_kubridge(void) { 1346 | int search_unk[2]; 1347 | return _vshKernelSearchModuleByName("kubridge", search_unk); 1348 | } 1349 | 1350 | enum MethodIDs { 1351 | UNKNOWN = 0, 1352 | INIT, 1353 | MISC_GET_COUNTRY_CODE, 1354 | HTTP_POST_GET_USER_AGENT_STRING, 1355 | PUSH_NOTE_GET_FIREBASE_TOKEN, 1356 | CREATE_UUID, 1357 | MUSIC_GET_NUM_TRACKS, 1358 | MUSIC_GET_TRACK_ALBUM_IDX, 1359 | MUSIC_GET_TRACK_ARTIST_IDX, 1360 | MUSIC_GET_TRACK_TITLE_IDX, 1361 | MUSIC_GET_TRACK_DURATION_IDX, 1362 | MUSIC_GET_TRACK_PATH_IDX, 1363 | } MethodIDs; 1364 | 1365 | typedef struct { 1366 | char *name; 1367 | enum MethodIDs id; 1368 | } NameToMethodID; 1369 | 1370 | static NameToMethodID name_to_method_ids[] = { 1371 | { "", INIT }, 1372 | { "misc_getCountryCode", MISC_GET_COUNTRY_CODE }, 1373 | { "httpPost_getUserAgentString", HTTP_POST_GET_USER_AGENT_STRING }, 1374 | { "pushNote_getFirebaseToken", PUSH_NOTE_GET_FIREBASE_TOKEN }, 1375 | { "createUUID", CREATE_UUID }, 1376 | { "music_getNumTracks", MUSIC_GET_NUM_TRACKS }, 1377 | { "music_getTrackAlbumIdx", MUSIC_GET_TRACK_ALBUM_IDX }, 1378 | { "music_getTrackArtistIdx", MUSIC_GET_TRACK_ARTIST_IDX }, 1379 | { "music_getTrackTitleIdx", MUSIC_GET_TRACK_TITLE_IDX }, 1380 | { "music_getTrackDurationIdx", MUSIC_GET_TRACK_DURATION_IDX }, 1381 | { "music_getTrackPathIdx", MUSIC_GET_TRACK_PATH_IDX }, 1382 | }; 1383 | 1384 | int GetMethodID(void *env, void *class, const char *name, const char *sig) { 1385 | printf("GetMethodID: %s\n", name); 1386 | 1387 | for (int i = 0; i < sizeof(name_to_method_ids) / sizeof(NameToMethodID); i++) { 1388 | if (strcmp(name, name_to_method_ids[i].name) == 0) { 1389 | return name_to_method_ids[i].id; 1390 | } 1391 | } 1392 | 1393 | return UNKNOWN; 1394 | } 1395 | 1396 | int GetStaticMethodID(void *env, void *class, const char *name, const char *sig) { 1397 | printf("GetStaticMethodID: %s\n", name); 1398 | 1399 | for (int i = 0; i < sizeof(name_to_method_ids) / sizeof(NameToMethodID); i++) { 1400 | if (strcmp(name, name_to_method_ids[i].name) == 0) 1401 | return name_to_method_ids[i].id; 1402 | } 1403 | 1404 | return UNKNOWN; 1405 | } 1406 | 1407 | void CallStaticVoidMethodV(void *env, void *obj, int methodID, uintptr_t *args) { 1408 | } 1409 | 1410 | int CallStaticBooleanMethodV(void *env, void *obj, int methodID, uintptr_t *args) { 1411 | switch (methodID) { 1412 | default: 1413 | return 0; 1414 | } 1415 | } 1416 | 1417 | int CallStaticIntMethodV(void *env, void *obj, int methodID, uintptr_t *args) { 1418 | switch (methodID) { 1419 | default: 1420 | return 0; 1421 | } 1422 | } 1423 | 1424 | int64_t CallStaticLongMethodV(void *env, void *obj, int methodID, uintptr_t *args) { 1425 | switch (methodID) { 1426 | default: 1427 | return 0; 1428 | } 1429 | } 1430 | 1431 | uint64_t CallLongMethodV(void *env, void *obj, int methodID, uintptr_t *args) { 1432 | return -1; 1433 | } 1434 | 1435 | void *FindClass(void) { 1436 | return (void *)0x41414141; 1437 | } 1438 | 1439 | void *NewGlobalRef(void *env, char *str) { 1440 | return (void *)0x42424242; 1441 | } 1442 | 1443 | void DeleteGlobalRef(void *env, char *str) { 1444 | } 1445 | 1446 | void *NewObjectV(void *env, void *clazz, int methodID, uintptr_t args) { 1447 | return (void *)0x43434343; 1448 | } 1449 | 1450 | void *GetObjectClass(void *env, void *obj) { 1451 | return (void *)0x44444444; 1452 | } 1453 | 1454 | char *NewStringUTF(void *env, char *bytes) { 1455 | return bytes; 1456 | } 1457 | 1458 | char *GetStringUTFChars(void *env, char *string, int *isCopy) { 1459 | return string; 1460 | } 1461 | 1462 | size_t GetStringUTFLength(void *env, char *string) { 1463 | return strlen(string); 1464 | } 1465 | 1466 | int GetJavaVM(void *env, void **vm) { 1467 | *vm = fake_vm; 1468 | return 0; 1469 | } 1470 | 1471 | int GetFieldID(void *env, void *clazz, const char *name, const char *sig) { 1472 | return 0; 1473 | } 1474 | 1475 | int GetBooleanField(void *env, void *obj, int fieldID) { 1476 | return 1; 1477 | } 1478 | 1479 | void *GetObjectArrayElement(void *env, uint8_t *obj, int idx) { 1480 | int res_idx = 4; 1481 | for (int i = 0; i < idx; i++) { 1482 | res_idx += strlen(&obj[res_idx]) + 1; 1483 | } 1484 | printf("GetObjectArrayElement(%d): %s (idx: %d)\n", idx, &obj[res_idx], res_idx); 1485 | return &obj[res_idx]; 1486 | } 1487 | 1488 | int CallBooleanMethodV(void *env, void *obj, int methodID, uintptr_t *args) { 1489 | switch (methodID) { 1490 | default: 1491 | return 0; 1492 | } 1493 | } 1494 | 1495 | typedef struct { 1496 | char title[128]; 1497 | char artist[128]; 1498 | char album[128]; 1499 | char fname[256]; 1500 | int duration; 1501 | void *next; 1502 | } song; 1503 | song *songs = NULL; 1504 | uint8_t songs_scanned = 0; 1505 | int song_idx = 0; 1506 | 1507 | void load_metadata(const char *fname, song *s) { 1508 | char buffer[256]; 1509 | char identifier[64]; 1510 | 1511 | FILE *config = fopen(fname, "r"); 1512 | 1513 | if (config) { 1514 | while (EOF != fscanf(config, "%[^=]=%[^\n]\n", identifier, buffer)) { 1515 | if (strcmp("title", identifier) == 0) { 1516 | strcpy(s->title, buffer); 1517 | if (s->title[strlen(s->title) - 1] == '\r' || s->title[strlen(s->title) - 1] == '\n') 1518 | s->title[strlen(s->title) - 1] = 0; 1519 | } else if (strcmp("artist", identifier) == 0) { 1520 | strcpy(s->artist, buffer); 1521 | if (s->artist[strlen(s->artist) - 1] == '\r' || s->artist[strlen(s->artist) - 1] == '\n') 1522 | s->artist[strlen(s->artist) - 1] = 0; 1523 | } 1524 | } 1525 | fclose(config); 1526 | } 1527 | 1528 | if (strlen(s->artist) < 2) 1529 | sprintf(s->artist, "Unknown"); 1530 | } 1531 | 1532 | void populateSongs(const char *dir, const char *album) { 1533 | SceUID fd = sceIoDopen(dir); 1534 | SceIoDirent g_dir; 1535 | char fname[256]; 1536 | while (sceIoDread(fd, &g_dir) > 0) { 1537 | if (SCE_S_ISDIR(g_dir.d_stat.st_mode)) { 1538 | sprintf(fname, "%s/%s", dir, g_dir.d_name); 1539 | populateSongs(fname, g_dir.d_name); 1540 | } else { 1541 | if (!strcmp(&g_dir.d_name[strlen(g_dir.d_name) - 4], ".ogg") || 1542 | !strcmp(&g_dir.d_name[strlen(g_dir.d_name) - 4], ".wav") || 1543 | !strcmp(&g_dir.d_name[strlen(g_dir.d_name) - 5], ".flac") || 1544 | !strcmp(&g_dir.d_name[strlen(g_dir.d_name) - 4], ".mp3")) { 1545 | song *s = &songs[song_idx++]; 1546 | sceClibMemset(s, 0, sizeof(song)); 1547 | sprintf(s->fname, "%s/%s", dir, g_dir.d_name); 1548 | s->duration = Song_GetTotalDuration(s->fname) * 1000; 1549 | sprintf(fname, "%s/%s.txt", dir, g_dir.d_name); 1550 | load_metadata(fname, s); 1551 | if (strlen(s->title) < 2) { 1552 | sprintf(s->title, g_dir.d_name); 1553 | s->title[strlen(s->title) - 4] = 0; 1554 | } 1555 | strcpy(s->album, album ? album : "Unknown"); 1556 | } 1557 | } 1558 | } 1559 | sceIoDclose(fd); 1560 | } 1561 | 1562 | int countSongs(const char *dir, int master) { 1563 | int res = 0; 1564 | SceUID fd = sceIoDopen(dir); 1565 | SceIoDirent g_dir; 1566 | while (sceIoDread(fd, &g_dir) > 0) { 1567 | if (SCE_S_ISDIR(g_dir.d_stat.st_mode)) { 1568 | char fname[256]; 1569 | sprintf(fname, "%s/%s", dir, g_dir.d_name); 1570 | res += countSongs(fname, 0); 1571 | } else { 1572 | if (!strcmp(&g_dir.d_name[strlen(g_dir.d_name) - 4], ".ogg") || 1573 | !strcmp(&g_dir.d_name[strlen(g_dir.d_name) - 4], ".wav") || 1574 | !strcmp(&g_dir.d_name[strlen(g_dir.d_name) - 5], ".flac") || 1575 | !strcmp(&g_dir.d_name[strlen(g_dir.d_name) - 4], ".mp3")) { 1576 | res++; 1577 | } 1578 | } 1579 | } 1580 | sceIoDclose(fd); 1581 | if (!songs_scanned && master) { 1582 | songs = (song *)malloc(sizeof(song) * res); 1583 | populateSongs(dir, NULL); 1584 | songs_scanned = 1; 1585 | } 1586 | return res; 1587 | } 1588 | 1589 | char duration[32]; 1590 | void *CallObjectMethodV(void *env, void *obj, int methodID, uintptr_t *args) { 1591 | switch (methodID) { 1592 | case MISC_GET_COUNTRY_CODE: 1593 | return "en"; 1594 | case HTTP_POST_GET_USER_AGENT_STRING: 1595 | return "PSVita"; 1596 | case PUSH_NOTE_GET_FIREBASE_TOKEN: 1597 | return "FirebaseToken"; 1598 | case CREATE_UUID: 1599 | return "Rinnegatamante"; 1600 | case MUSIC_GET_TRACK_ALBUM_IDX: 1601 | return songs[*(int *)args].album; 1602 | case MUSIC_GET_TRACK_ARTIST_IDX: 1603 | return songs[*(int *)args].artist; 1604 | case MUSIC_GET_TRACK_DURATION_IDX: 1605 | sprintf(duration, "%d", songs[*(int *)args].duration); 1606 | return duration; 1607 | case MUSIC_GET_TRACK_PATH_IDX: 1608 | return songs[*(int *)args].fname; 1609 | case MUSIC_GET_TRACK_TITLE_IDX: 1610 | return songs[*(int *)args].title; 1611 | default: 1612 | return NULL; 1613 | } 1614 | } 1615 | 1616 | int CallIntMethodV(void *env, void *obj, int methodID, uintptr_t *args) { 1617 | switch (methodID) { 1618 | case MUSIC_GET_NUM_TRACKS: 1619 | return countSongs("ux0:data/hazard/songs", 1); 1620 | default: 1621 | return 0; 1622 | } 1623 | } 1624 | 1625 | void CallVoidMethodV(void *env, void *obj, int methodID, uintptr_t *args) { 1626 | switch (methodID) { 1627 | default: 1628 | break; 1629 | } 1630 | } 1631 | 1632 | int GetStaticFieldID(void *env, void *clazz, const char *name, const char *sig) { 1633 | return 0; 1634 | } 1635 | 1636 | void *GetStaticObjectField(void *env, void *clazz, int fieldID) { 1637 | switch (fieldID) { 1638 | default: 1639 | return NULL; 1640 | } 1641 | } 1642 | 1643 | void GetStringUTFRegion(void *env, char *str, size_t start, size_t len, char *buf) { 1644 | sceClibMemcpy(buf, &str[start], len); 1645 | buf[len] = 0; 1646 | } 1647 | 1648 | void *CallStaticObjectMethodV(void *env, void *obj, int methodID, uintptr_t *args) { 1649 | return NULL; 1650 | } 1651 | 1652 | int GetIntField(void *env, void *obj, int fieldID) { return 0; } 1653 | 1654 | float GetFloatField(void *env, void *obj, int fieldID) { 1655 | switch (fieldID) { 1656 | default: 1657 | return 0.0f; 1658 | } 1659 | } 1660 | 1661 | float CallStaticFloatMethodV(void *env, void *obj, int methodID, uintptr_t *args) { 1662 | switch (methodID) { 1663 | default: 1664 | if (methodID != UNKNOWN) { 1665 | dlog("CallStaticDoubleMethodV(%d)\n", methodID); 1666 | } 1667 | return 0; 1668 | } 1669 | } 1670 | 1671 | int GetArrayLength(void *env, void *array) { 1672 | printf("GetArrayLength returned %d\n", *(int *)array); 1673 | return *(int *)array; 1674 | } 1675 | 1676 | void push_fake_input(int pressed, int button) { 1677 | SDL_Event e; 1678 | e.jbutton.which = 0; 1679 | e.jbutton.button = button; 1680 | 1681 | if (pressed) { 1682 | e.jbutton.type = SDL_JOYBUTTONDOWN; 1683 | e.jbutton.state = SDL_PRESSED; 1684 | } else { 1685 | e.jbutton.type = SDL_JOYBUTTONUP; 1686 | e.jbutton.state = SDL_RELEASED; 1687 | } 1688 | 1689 | SDL_PushEvent(&e); 1690 | } 1691 | 1692 | void *ctrl_thread(void *argp) { 1693 | int backTouchState[4] = {0, 0, 0, 0}; // R3 (15), R2 (13), L3 (14), L2 (12) 1694 | int rear_mapping[4] = {15, 13, 14, 12}; 1695 | 1696 | uint32_t old_buttons = 0, current_buttons = 0, pressed_buttons = 0, released_buttons = 0; 1697 | 1698 | while (1) { 1699 | SceTouchData touch; 1700 | 1701 | int currTouch[4] = {0, 0, 0, 0}; 1702 | sceTouchPeek(SCE_TOUCH_PORT_BACK, &touch, 1); 1703 | for (int i = 0; i < touch.reportNum; i++) { 1704 | int x = touch.report[i].x; 1705 | int y = touch.report[i].y; 1706 | if (x > 960) { 1707 | if (y > 544) { 1708 | if (!backTouchState[0]) { 1709 | push_fake_input(1, 15); 1710 | backTouchState[0] = 1; 1711 | } 1712 | currTouch[0] = 1; 1713 | } else { 1714 | if (!backTouchState[1]) { 1715 | push_fake_input(1, 13); 1716 | backTouchState[1] = 1; 1717 | } 1718 | currTouch[1] = 1; 1719 | } 1720 | } else { 1721 | if (y > 544) { 1722 | if (!backTouchState[2]) { 1723 | push_fake_input(1, 14); 1724 | backTouchState[2] = 1; 1725 | } 1726 | currTouch[2] = 1; 1727 | } else { 1728 | if (!backTouchState[3]) { 1729 | push_fake_input(1, 12); 1730 | backTouchState[3] = 1; 1731 | } 1732 | currTouch[3] = 1; 1733 | } 1734 | } 1735 | } 1736 | for (int i = 0; i < 4; i++) { 1737 | if (!currTouch[i] && backTouchState[i]) { 1738 | backTouchState[i] = 0; 1739 | push_fake_input(0, rear_mapping[i]); 1740 | } 1741 | } 1742 | 1743 | sceKernelDelayThread(1000); 1744 | } 1745 | 1746 | return 0; 1747 | } 1748 | 1749 | /*int crasher(unsigned int argc, void *argv) { 1750 | uint32_t *nullptr = NULL; 1751 | for (;;) { 1752 | SceCtrlData pad; 1753 | sceCtrlPeekBufferPositive(0, &pad, 1); 1754 | if (pad.buttons & SCE_CTRL_SELECT) *nullptr = 0; 1755 | sceKernelDelayThread(100); 1756 | } 1757 | }*/ 1758 | 1759 | int main(int argc, char *argv[]) { 1760 | //sceSysmoduleLoadModule(SCE_SYSMODULE_RAZOR_CAPTURE); 1761 | //SceUID crasher_thread = sceKernelCreateThread("crasher", crasher, 0x40, 0x1000, 0, 0, NULL); 1762 | //sceKernelStartThread(crasher_thread, 0, NULL); 1763 | 1764 | SceAppUtilInitParam init_param = {0}; 1765 | SceAppUtilBootParam boot_param = {0}; 1766 | sceAppUtilInit(&init_param, &boot_param); 1767 | SceAppUtilAppEventParam eventParam; 1768 | sceClibMemset(&eventParam, 0, sizeof(SceAppUtilAppEventParam)); 1769 | sceAppUtilReceiveAppEvent(&eventParam); 1770 | if (eventParam.type == 0x05) { 1771 | char buffer[2048]; 1772 | sceAppUtilAppEventParseLiveArea(&eventParam, buffer); 1773 | if (strstr(buffer, "custom")) 1774 | framecap = 1; 1775 | } 1776 | 1777 | sceTouchSetSamplingState(SCE_TOUCH_PORT_FRONT, SCE_TOUCH_SAMPLING_STATE_START); 1778 | sceTouchSetSamplingState(SCE_TOUCH_PORT_BACK, SCE_TOUCH_SAMPLING_STATE_START); 1779 | 1780 | scePowerSetArmClockFrequency(444); 1781 | scePowerSetBusClockFrequency(222); 1782 | scePowerSetGpuClockFrequency(222); 1783 | scePowerSetGpuXbarClockFrequency(166); 1784 | 1785 | if (check_kubridge() < 0) 1786 | fatal_error("Error kubridge.skprx is not installed."); 1787 | 1788 | if (!file_exists("ur0:/data/libshacccg.suprx") && !file_exists("ur0:/data/external/libshacccg.suprx")) 1789 | fatal_error("Error libshacccg.suprx is not installed."); 1790 | 1791 | char fname[256]; 1792 | sprintf(data_path, "ux0:data/hazard"); 1793 | 1794 | printf("Loading libc++_shared\n"); 1795 | sprintf(fname, "%s/libc++_shared.so", data_path); 1796 | if (so_file_load(&cpp_mod, fname, LOAD_ADDRESS + 0x1000000) < 0) 1797 | fatal_error("Error could not load %s.", fname); 1798 | so_relocate(&cpp_mod); 1799 | so_resolve(&cpp_mod, default_dynlib, sizeof(default_dynlib), 0); 1800 | so_flush_caches(&cpp_mod); 1801 | so_initialize(&cpp_mod); 1802 | 1803 | printf("Loading libtags\n"); 1804 | sprintf(fname, "%s/libtags.so", data_path); 1805 | if (so_file_load(&tags_mod, fname, LOAD_ADDRESS + 0x2000000) < 0) 1806 | fatal_error("Error could not load %s.", fname); 1807 | so_relocate(&tags_mod); 1808 | so_resolve(&tags_mod, default_dynlib, sizeof(default_dynlib), 0); 1809 | so_flush_caches(&tags_mod); 1810 | so_initialize(&tags_mod); 1811 | 1812 | printf("Loading libSDL2_ttf\n"); 1813 | sprintf(fname, "%s/libSDL2_ttf.so", data_path); 1814 | if (so_file_load(&ttf_mod, fname, LOAD_ADDRESS + 0x3000000) < 0) 1815 | fatal_error("Error could not load %s.", fname); 1816 | so_relocate(&ttf_mod); 1817 | so_resolve(&ttf_mod, default_dynlib, sizeof(default_dynlib), 0); 1818 | so_flush_caches(&ttf_mod); 1819 | so_initialize(&ttf_mod); 1820 | 1821 | printf("Loading libmain\n"); 1822 | sprintf(fname, "%s/libmain.so", data_path); 1823 | if (so_file_load(&hazard_mod, fname, LOAD_ADDRESS) < 0) 1824 | fatal_error("Error could not load %s.", fname); 1825 | so_relocate(&hazard_mod); 1826 | so_resolve(&hazard_mod, default_dynlib, sizeof(default_dynlib), 0); 1827 | 1828 | sceIoMkdir("ux0:data/hazard/songs", 0777); 1829 | 1830 | vglInitExtended(0, SCREEN_W, SCREEN_H, MEMORY_VITAGL_THRESHOLD_MB * 1024 * 1024, SCE_GXM_MULTISAMPLE_4X); 1831 | 1832 | patch_game(); 1833 | so_flush_caches(&hazard_mod); 1834 | so_initialize(&hazard_mod); 1835 | 1836 | memset(fake_vm, 'A', sizeof(fake_vm)); 1837 | *(uintptr_t *)(fake_vm + 0x00) = (uintptr_t)fake_vm; // just point to itself... 1838 | *(uintptr_t *)(fake_vm + 0x10) = (uintptr_t)ret0; 1839 | *(uintptr_t *)(fake_vm + 0x14) = (uintptr_t)ret0; 1840 | *(uintptr_t *)(fake_vm + 0x18) = (uintptr_t)GetEnv; 1841 | 1842 | memset(fake_env, 'A', sizeof(fake_env)); 1843 | *(uintptr_t *)(fake_env + 0x00) = (uintptr_t)fake_env; // just point to itself... 1844 | *(uintptr_t *)(fake_env + 0x18) = (uintptr_t)FindClass; 1845 | *(uintptr_t *)(fake_env + 0x4C) = (uintptr_t)ret0; // PushLocalFrame 1846 | *(uintptr_t *)(fake_env + 0x50) = (uintptr_t)ret0; // PopLocalFrame 1847 | *(uintptr_t *)(fake_env + 0x54) = (uintptr_t)NewGlobalRef; 1848 | *(uintptr_t *)(fake_env + 0x58) = (uintptr_t)DeleteGlobalRef; 1849 | *(uintptr_t *)(fake_env + 0x5C) = (uintptr_t)ret0; // DeleteLocalRef 1850 | *(uintptr_t *)(fake_env + 0x74) = (uintptr_t)NewObjectV; 1851 | *(uintptr_t *)(fake_env + 0x7C) = (uintptr_t)GetObjectClass; 1852 | *(uintptr_t *)(fake_env + 0x84) = (uintptr_t)GetMethodID; 1853 | *(uintptr_t *)(fake_env + 0x8C) = (uintptr_t)CallObjectMethodV; 1854 | *(uintptr_t *)(fake_env + 0x98) = (uintptr_t)CallBooleanMethodV; 1855 | *(uintptr_t *)(fake_env + 0xC8) = (uintptr_t)CallIntMethodV; 1856 | *(uintptr_t *)(fake_env + 0xD4) = (uintptr_t)CallLongMethodV; 1857 | *(uintptr_t *)(fake_env + 0xF8) = (uintptr_t)CallVoidMethodV; 1858 | *(uintptr_t *)(fake_env + 0x178) = (uintptr_t)GetFieldID; 1859 | *(uintptr_t *)(fake_env + 0x17C) = (uintptr_t)GetBooleanField; 1860 | *(uintptr_t *)(fake_env + 0x190) = (uintptr_t)GetIntField; 1861 | *(uintptr_t *)(fake_env + 0x198) = (uintptr_t)GetFloatField; 1862 | *(uintptr_t *)(fake_env + 0x1C4) = (uintptr_t)GetStaticMethodID; 1863 | *(uintptr_t *)(fake_env + 0x1CC) = (uintptr_t)CallStaticObjectMethodV; 1864 | *(uintptr_t *)(fake_env + 0x1D8) = (uintptr_t)CallStaticBooleanMethodV; 1865 | *(uintptr_t *)(fake_env + 0x208) = (uintptr_t)CallStaticIntMethodV; 1866 | *(uintptr_t *)(fake_env + 0x21C) = (uintptr_t)CallStaticLongMethodV; 1867 | *(uintptr_t *)(fake_env + 0x220) = (uintptr_t)CallStaticFloatMethodV; 1868 | *(uintptr_t *)(fake_env + 0x238) = (uintptr_t)CallStaticVoidMethodV; 1869 | *(uintptr_t *)(fake_env + 0x240) = (uintptr_t)GetStaticFieldID; 1870 | *(uintptr_t *)(fake_env + 0x244) = (uintptr_t)GetStaticObjectField; 1871 | *(uintptr_t *)(fake_env + 0x29C) = (uintptr_t)NewStringUTF; 1872 | *(uintptr_t *)(fake_env + 0x2A0) = (uintptr_t)GetStringUTFLength; 1873 | *(uintptr_t *)(fake_env + 0x2A4) = (uintptr_t)GetStringUTFChars; 1874 | *(uintptr_t *)(fake_env + 0x2A8) = (uintptr_t)ret0; // ReleaseStringUTFChars 1875 | *(uintptr_t *)(fake_env + 0x2AC) = (uintptr_t)GetArrayLength; 1876 | *(uintptr_t *)(fake_env + 0x2B4) = (uintptr_t)GetObjectArrayElement; 1877 | *(uintptr_t *)(fake_env + 0x35C) = (uintptr_t)ret0; // RegisterNatives 1878 | *(uintptr_t *)(fake_env + 0x36C) = (uintptr_t)GetJavaVM; 1879 | *(uintptr_t *)(fake_env + 0x374) = (uintptr_t)GetStringUTFRegion; 1880 | 1881 | // Disabling rearpad 1882 | SDL_setenv("VITA_DISABLE_TOUCH_BACK", "1", 1); 1883 | 1884 | // Starting thread for backtouch to mimic physical controls 1885 | pthread_t t; 1886 | pthread_attr_t attr; 1887 | pthread_attr_init(&attr); 1888 | pthread_create(&t, &attr, ctrl_thread, NULL); 1889 | 1890 | int (*SDL_main)() = (void *) so_symbol(&hazard_mod, "SDL_main"); 1891 | 1892 | SDL_main(); 1893 | 1894 | return 0; 1895 | } 1896 | --------------------------------------------------------------------------------