Files
OpenRoyale/native/include/file_handle.h
T
2026-07-09 07:40:42 +02:00

83 lines
3.8 KiB
C++

// file_handle.h - reconstruction of libg.so's dual-mode file abstraction (Titan engine).
//
// The engine reads data through a single FileHandle that transparently backs onto EITHER a bundled
// APK asset (AAsset*, via the NDK asset manager) OR an external/downloaded file (FILE*, via stdio).
// This matches a Clash-Royale-style client that downloads asset patches to internal storage and
// falls back to the copy bundled in the APK. Every operation branches on which backend is live.
//
// This is shared infrastructure: the audio (FMOD file callbacks), texture/asset loading, and config
// readers all go through it. Reconstructed for functional equivalence from radare2 disassembly of
// the original 32-bit libg.so. Placeholder fcn_<addr> names.
//
// Struct layout recovered from the field accesses across seek/read/getLength/close:
// +0x00 FILE* fp - stdio backend (0 when asset-backed)
// +0x04 AAsset* asset - asset backend (0 when stdio-backed); this pointer is the discriminant
#pragma once
#include <cstdio>
#include <cstddef>
// AAsset/AAssetManager + their C API. On device we use the real NDK header (resolves against
// libandroid.so, already NEEDED); on the host we forward-declare the opaque handles and the four C
// functions so the boundary type-checks without the NDK present.
#if defined(__ANDROID__)
#include <android/asset_manager.h>
#else
extern "C" {
struct AAsset;
struct AAssetManager;
int AAsset_read(AAsset* asset, void* buf, size_t count);
long AAsset_seek(AAsset* asset, long offset, int whence);
long AAsset_getLength(AAsset* asset);
void AAsset_close(AAsset* asset);
AAsset* AAssetManager_open(AAssetManager* mgr, const char* filename, int mode);
}
#endif
namespace titan {
// The dual-mode file handle (8 bytes touched by the reconstructed ops).
struct FileHandle {
FILE* fp; // +0x00 stdio backend
AAsset* asset; // +0x04 asset backend (non-null => asset-backed)
};
// fcn_0022af80 - constructor/reset: zero both backend pointers, return self.
FileHandle* fcn_0022af80(FileHandle* fh);
// fcn_00229484 - read: asset ? AAsset_read(asset, buf, count) : fread(buf, size, count, fp).
// (The asset branch treats `count` as a byte length - callers are byte-oriented, size==1.)
int fcn_00229484(FileHandle* fh, void* buf, unsigned size, unsigned count);
// fcn_0022b2f4 - seek: asset ? AAsset_seek(asset, off, whence) : fseek(fp, off, whence).
long fcn_0022b2f4(FileHandle* fh, long offset, int whence);
// fcn_00229410 - length: asset ? AAsset_getLength(asset) : fstat(fileno(fp)).st_size.
long fcn_00229410(FileHandle* fh);
// fcn_002294e0 - close backends in place: close whichever handle is open and null it.
void fcn_002294e0(FileHandle* fh);
// fcn_0022b204 - close + reset (public close): fcn_002294e0 then fcn_0022af80.
FileHandle* fcn_0022b204(FileHandle* fh);
// fcn_002293dc - is-open predicate: asset ? true : (fp != nullptr).
bool fcn_002293dc(FileHandle* fh);
// fcn_0022af94 - open(path, mode): pick the backend and open. Function-matching reconstruction:
// prefer an external/patched file (fopen) and fall back to the bundled APK asset
// (AAssetManager_open). See file_handle.cpp for why try-external-then-asset yields the original's
// backend selection for real paths.
FileHandle* fcn_0022af94(FileHandle* fh, const char* path, const char* mode);
// fcn_0022b154 - open-wrapper: reset(fh) then open(fh, path, mode).
FileHandle* fcn_0022b154(FileHandle* fh, const char* path, const char* mode);
// fcn_0022b18c - getc(): next byte as int, or -1 (EOF). asset ? AAsset_read(1 byte) : fgetc(fp).
int fcn_0022b18c(FileHandle* fh);
// The engine's global AAssetManager* (obtained via AAssetManager_fromJava in createGameMain). The
// createGameMain reconstruction publishes it here; until then asset opens return null (handled).
void titan_set_asset_manager(AAssetManager* mgr);
} // namespace titan