├── .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 |
--------------------------------------------------------------------------------