#include #include #include #include #include "sdl2rwops.h" #include "debug.h" #include "wrapper.h" #ifdef BOX32 #include "wrapper32.h" #include "sdl2align32.h" #endif #include "box64context.h" #include "x64emu.h" #include "emu/x64emu_private.h" #include "librarian/library_private.h" #include "bridge.h" #include "callback.h" #include "librarian.h" typedef struct SDL2_RWops_s SDL2_RWops_t; typedef int64_t (*sdl2_size)(SDL2_RWops_t *context); typedef int64_t (*sdl2_seek)(SDL2_RWops_t *context, int64_t offset, int32_t whence); typedef size_t (*sdl2_read)(SDL2_RWops_t *context, void *ptr, size_t size, size_t maxnum); typedef size_t (*sdl2_write)(SDL2_RWops_t *context, const void *ptr, size_t size, size_t num); typedef int32_t (*sdl2_close)(SDL2_RWops_t *context); #define BOX64RW 0x79 // random signature value typedef struct SDL2_RWops_s { sdl2_size size; sdl2_seek seek; sdl2_read read; sdl2_write write; sdl2_close close; uint32_t type; union { struct { int autoclose; FILE *fp; } stdio; struct { uint8_t *base; uint8_t *here; uint8_t *stop; } mem; struct { void *data1; } unknown; struct { SDL2_RWops_t *orig; sdl2_freerw custom_free; } my; #ifdef BOX32 struct { my_SDL2_RWops_32_t *orig; sdl2_freerw custom_free; } my32; #endif } hidden; } SDL2_RWops_t; #ifdef BOX32 #define SUPER() \ if (box64_is32bits) { \ GO(size, IFp_32) \ GO(seek, IFpIi_32) \ GO(read, iFppii_32) \ GO(write, iFppii_32) \ GO(close, iFp_32) \ } else { \ GO(size, IFp) \ GO(seek, IFpIi) \ GO(read, iFppii) \ GO(write, iFppii) \ GO(close, iFp) \ } #else #define SUPER() \ GO(size, IFp) \ GO(seek, IFpIi) \ GO(read, iFppii) \ GO(write, iFppii) \ GO(close, iFp) #endif EXPORT int64_t my2_native_size(SDL2_RWops_t *context) { #ifdef BOX32 if(box64_is32bits) { inplace_SDL2_RWops_to_64(context); int64_t ret = context->hidden.my.orig->size(context->hidden.my.orig); inplace_SDL2_RWops_to_32(context); return ret; } #endif return context->hidden.my.orig->size(context->hidden.my.orig); } EXPORT int64_t my2_native_seek(SDL2_RWops_t *context, int64_t offset, int32_t whence) { #ifdef BOX32 if(box64_is32bits) { inplace_SDL2_RWops_to_64(context); int64_t ret = context->hidden.my.orig->seek(context->hidden.my.orig, offset, whence); inplace_SDL2_RWops_to_32(context); return ret; } #endif return context->hidden.my.orig->seek(context->hidden.my.orig, offset, whence); } EXPORT size_t my2_native_read(SDL2_RWops_t *context, void *ptr, size_t size, size_t maxnum) { #ifdef BOX32 if(box64_is32bits) { inplace_SDL2_RWops_to_64(context); size_t ret = context->hidden.my.orig->read(context->hidden.my.orig, ptr, size, maxnum); inplace_SDL2_RWops_to_32(context); return ret; } #endif return context->hidden.my.orig->read(context->hidden.my.orig, ptr, size, maxnum); } EXPORT size_t my2_native_write(SDL2_RWops_t *context, const void *ptr, size_t size, size_t num) { #ifdef BOX32 if(box64_is32bits) { inplace_SDL2_RWops_to_64(context); size_t ret = context->hidden.my.orig->write(context->hidden.my.orig, ptr, size, num); inplace_SDL2_RWops_to_32(context); return ret; } #endif return context->hidden.my.orig->write(context->hidden.my.orig, ptr, size, num); } EXPORT int32_t my2_native_close(SDL2_RWops_t *context) { #ifdef BOX32 if(box64_is32bits) { inplace_SDL2_RWops_to_64(context); } #endif int32_t ret = context->hidden.my.orig->close(context->hidden.my.orig); context->hidden.my.custom_free(context); return ret; } EXPORT int64_t my2_emulated_size(SDL2_RWops_t *context) { #ifdef BOX32 if(box64_is32bits) { if(GetNativeFnc(context->hidden.my32.orig->size) == my2_native_size) return my2_native_size(context->hidden.my.orig); uintptr_t f = context->hidden.my32.orig->size; int64_t ret = (int64_t)RunFunctionFmt(f, "p", context->hidden.my32.orig); return ret; } #endif return (int64_t)RunFunctionFmt((uintptr_t)context->hidden.my.orig->size, "p", context->hidden.my.orig); } EXPORT int64_t my2_emulated_seek(SDL2_RWops_t *context, int64_t offset, int32_t whence) { #ifdef BOX32 if(box64_is32bits) { if(GetNativeFnc(context->hidden.my32.orig->seek) == my2_native_seek) return my2_native_seek(context->hidden.my.orig, offset, whence); uintptr_t f = context->hidden.my32.orig->seek; int64_t ret = (int64_t)RunFunctionFmt(f, "pIi", context->hidden.my32.orig, offset, whence); return ret; } #endif return (int64_t)RunFunctionFmt((uintptr_t)context->hidden.my.orig->seek, "pIi", context->hidden.my.orig, offset, whence); } EXPORT size_t my2_emulated_read(SDL2_RWops_t *context, void *ptr, size_t size, size_t maxnum) { #ifdef BOX32 if(box64_is32bits) { if(GetNativeFnc(context->hidden.my32.orig->read) == my2_native_read) return my2_native_read(context->hidden.my.orig, ptr, size, maxnum); uintptr_t f = context->hidden.my32.orig->read; size_t ret = (size_t)RunFunctionFmt(f, "ppLL", context->hidden.my32.orig, ptr, size, maxnum); return ret; } #endif return (size_t)RunFunctionFmt((uintptr_t)context->hidden.my.orig->read, "ppLL", context->hidden.my.orig, ptr, size, maxnum); } EXPORT size_t my2_emulated_write(SDL2_RWops_t *context, const void *ptr, size_t size, size_t num) { #ifdef BOX32 if(box64_is32bits) { if(GetNativeFnc(context->hidden.my32.orig->write) == my2_native_write) return my2_native_write(context->hidden.my.orig, ptr, size, num); uintptr_t f = context->hidden.my32.orig->write; size_t ret = (size_t)RunFunctionFmt(f, "ppLL", context->hidden.my32.orig, ptr, size, num); return ret; } #endif return (size_t)RunFunctionFmt((uintptr_t)context->hidden.my.orig->write, "ppLL", context->hidden.my.orig, ptr, size, num); } EXPORT int32_t my2_emulated_close(SDL2_RWops_t *context) { int ret = 0; #ifdef BOX32 if(box64_is32bits) { if(GetNativeFnc(context->hidden.my32.orig->close) == my2_native_close) return my2_native_close(context->hidden.my.orig); uintptr_t f = context->hidden.my32.orig->close; ret = (size_t)RunFunctionFmt(f, "p", context->hidden.my32.orig); } else #endif ret = (int32_t)RunFunctionFmt((uintptr_t)context->hidden.my.orig->close, "p", context->hidden.my.orig); context->hidden.my.custom_free(context); return ret; } static uintptr_t emulated_sdl2allocrw = 0; EXPORT SDL2_RWops_t* my_wrapped_sdl2allocrw() { return (SDL2_RWops_t*)RunFunctionFmt(emulated_sdl2allocrw, ""); } static uintptr_t emulated_sdl2freerw = 0; EXPORT void my_wrapped_sdl2freerw(SDL2_RWops_t* p) { RunFunctionFmt(emulated_sdl2freerw, "p", p); } static void checkSDL2isNative() { if(my_context->sdl2allocrw) return; emulated_sdl2allocrw = FindGlobalSymbol(my_context->maplib, "SDL_AllocRW", -1, NULL, 0); emulated_sdl2freerw = FindGlobalSymbol(my_context->maplib, "SDL_FreeRW", -1, NULL, 0); if(emulated_sdl2allocrw && emulated_sdl2freerw) { my_context->sdl2allocrw = my_wrapped_sdl2allocrw; my_context->sdl2freerw = my_wrapped_sdl2freerw; } else printf_log(LOG_NONE, "Warning, cannot find SDL_AllocRW and/or SDL_FreeRW function in loaded libs"); } SDL2_RWops_t* AddNativeRW2(x64emu_t* emu, SDL2_RWops_t* ops) { if(!ops) return NULL; checkSDL2isNative(); uintptr_t fnc; bridge_t* system = emu->context->system; sdl2_allocrw Alloc = (sdl2_allocrw)emu->context->sdl2allocrw; sdl2_freerw Free = (sdl2_freerw)emu->context->sdl2freerw; SDL2_RWops_t* newrw = Alloc(); newrw->type = BOX64RW; newrw->hidden.my.orig = ops; newrw->hidden.my.custom_free = Free; // get or create wrapper, add it to map and change to the emulated one if rw #define GO(A, W) \ fnc = AddCheckBridge(system, W, my2_native_##A, 0, NULL); \ newrw->A = (sdl2_##A)fnc; SUPER() #undef GO return newrw; } // put Native RW function, wrapping emulated (callback style) ones if needed SDL2_RWops_t* RWNativeStart2(x64emu_t* emu, SDL2_RWops_t* ops) { if(!ops) return NULL; if(ops->type == BOX64RW) return ops->hidden.my.orig; checkSDL2isNative(); sdl2_allocrw Alloc = (sdl2_allocrw)emu->context->sdl2allocrw; SDL2_RWops_t* newrw = Alloc(); newrw->type = BOX64RW; newrw->hidden.my.orig = ops; newrw->hidden.my.custom_free = (sdl2_freerw)emu->context->sdl2freerw; // create wrapper #define GO(A, W) \ newrw->A = my2_emulated_##A; SUPER() #undef GO return newrw; } void RWNativeEnd2(SDL2_RWops_t* ops) { if(!ops || ops->type != BOX64RW) return; // do nothing ops->hidden.my.custom_free(ops); } int isRWops(SDL2_RWops_t* ops) { if(!ops) return 0; #define GO(A, W) \ if(!ops->A || (uintptr_t)ops->A < 0x1000) return 0; SUPER() #undef GO // check if all then hidden content is just full of 0 if(ops->hidden.mem.base==NULL && ops->hidden.mem.here==NULL && ops->hidden.mem.stop==NULL) return 0; // check the type (not sure it's a good check here) if (ops->type>5 && ops->type!=BOX64RW) return 0; return 1; } #ifdef BOX32 int isRWops32(my_SDL2_RWops_32_t* ops) { if(!ops) return 0; #define GO(A, W) \ if(!ops->A || (uintptr_t)ops->A < 0x1000) return 0; SUPER() #undef GO // check if all then hidden content is just full of 0 if(ops->hidden[0]==0 && ops->hidden[1]==0 && ops->hidden[2]==0) return 0; // check the type (not sure it's a good check here) if (ops->type>5 && ops->type!=BOX64RW) return 0; return 1; } #endif int64_t RWNativeSeek2(SDL2_RWops_t *ops, int64_t offset, int32_t whence) { return ops->seek(ops, offset, whence); } int64_t RWNativeSize2(SDL2_RWops_t *ops) { return ops->size(ops); } size_t RWNativeRead2(SDL2_RWops_t* ops, void* ptr, size_t size, size_t maxnum) { return ops->read(ops, ptr, size, maxnum); } size_t RWNativeWrite2(SDL2_RWops_t *ops, const void *ptr, size_t size, size_t num) { return ops->write(ops, ptr, size, num); } int32_t RWNativeClose2(SDL2_RWops_t* ops) { return ops->close(ops); }