| 1 | module os |
| 2 | |
| 3 | #include <android/asset_manager.h> |
| 4 | #include <android/asset_manager_jni.h> |
| 5 | #include <android/native_activity.h> |
| 6 | |
| 7 | pub enum AssetMode { |
| 8 | buffer = C.AASSET_MODE_BUFFER // Caller plans to ask for a read-only buffer with all data. |
| 9 | random = C.AASSET_MODE_RANDOM // Read chunks, and seek forward and backward. |
| 10 | streaming = C.AASSET_MODE_STREAMING // Read sequentially, with an occasional forward seek. |
| 11 | unknown = C.AASSET_MODE_UNKNOWN // No specific information about how data will be accessed. |
| 12 | } |
| 13 | |
| 14 | // See https://developer.android.com/ndk/reference/struct/a-native-activity for more info. |
| 15 | pub struct C.ANativeActivity { |
| 16 | pub: |
| 17 | assetManager &AssetManager = unsafe { nil } // Pointer to the Asset Manager instance for the application. |
| 18 | clazz voidptr // (jobject) The NativeActivity object handle. |
| 19 | env voidptr // (JNIEnv *) JNI context for the main thread of the app. |
| 20 | externalDataPath &char // Path to this application's external (removable/mountable) data directory. |
| 21 | instance voidptr // This is the native instance of the application. |
| 22 | internalDataPath &char // Path to this application's internal data directory. |
| 23 | obbPath &char // Available starting with Honeycomb: path to the directory containing the application's OBB files (if any). |
| 24 | sdkVersion int // The platform's SDK version code. |
| 25 | vm voidptr // (JavaVM *) The global handle on the process's Java VM. |
| 26 | } |
| 27 | |
| 28 | // NativeActivity defines the native side of an android.app.NativeActivity. |
| 29 | pub type NativeActivity = C.ANativeActivity |
| 30 | |
| 31 | pub struct C.AAssetManager { |
| 32 | } |
| 33 | |
| 34 | // AssetManager provides access to an application's raw assets by creating Asset objects. |
| 35 | pub type AssetManager = C.AAssetManager |
| 36 | |
| 37 | fn C.AAssetManager_open(&C.AAssetManager, &char, i32) &C.AAsset |
| 38 | |
| 39 | // open opens an Android `Asset`. |
| 40 | pub fn (am &AssetManager) open(filename string, mode AssetMode) !&Asset { |
| 41 | asset := C.AAssetManager_open(am, filename.str, int(mode)) |
| 42 | if isnil(asset) { |
| 43 | return error('file `${filename}` not found') |
| 44 | } |
| 45 | return asset |
| 46 | } |
| 47 | |
| 48 | pub struct C.AAsset { |
| 49 | } |
| 50 | |
| 51 | pub type Asset = C.AAsset |
| 52 | |
| 53 | fn C.AAsset_getBuffer(&C.AAsset) voidptr |
| 54 | |
| 55 | // get_buffer returns a pointer to a buffer holding the entire contents of the asset. |
| 56 | pub fn (a &Asset) get_buffer() voidptr { |
| 57 | return C.AAsset_getBuffer(a) |
| 58 | } |
| 59 | |
| 60 | fn C.AAsset_getLength(&C.AAsset) i32 |
| 61 | |
| 62 | // get_length returns the total size of the asset data. |
| 63 | pub fn (a &Asset) get_length() int { |
| 64 | return C.AAsset_getLength(a) |
| 65 | } |
| 66 | |
| 67 | fn C.AAsset_getLength64(&C.AAsset) i64 |
| 68 | |
| 69 | // get_length_64 returns the total size of the asset data using a 64-bit number instead of 32-bit as `get_length`. |
| 70 | pub fn (a &Asset) get_length_64() i64 { |
| 71 | return C.AAsset_getLength64(a) |
| 72 | } |
| 73 | |
| 74 | fn C.AAsset_read(&C.AAsset, voidptr, usize) i32 |
| 75 | |
| 76 | // read attempts to read 'count' bytes of data from the current offset. |
| 77 | // read returns the number of bytes read, zero on EOF, or < 0 on error. |
| 78 | pub fn (a &Asset) read(buffer voidptr, count usize) int { |
| 79 | return C.AAsset_read(a, buffer, count) |
| 80 | } |
| 81 | |
| 82 | fn C.AAsset_close(&C.AAsset) |
| 83 | |
| 84 | // close closes the asset, freeing all associated resources. |
| 85 | pub fn (a &Asset) close() { |
| 86 | C.AAsset_close(a) |
| 87 | } |
| 88 | |
| 89 | // read_apk_asset returns all the data located at `path`. |
| 90 | // `path` is expected to be relative to the APK/AAB `assets` directory. |
| 91 | pub fn read_apk_asset(path string) ![]u8 { |
| 92 | $if apk { |
| 93 | act := &NativeActivity(C.sapp_android_get_native_activity()) |
| 94 | if isnil(act) { |
| 95 | return error('could not get reference to Android activity') |
| 96 | } |
| 97 | asset_manager := act.assetManager |
| 98 | asset := asset_manager.open(path, .streaming)! |
| 99 | len := asset.get_length() |
| 100 | buf := []u8{len: len} |
| 101 | for { |
| 102 | if asset.read(buf.data, usize(len)) > 0 { |
| 103 | break |
| 104 | } |
| 105 | } |
| 106 | asset.close() |
| 107 | return buf |
| 108 | } $else { |
| 109 | return error(@FN + ' can only be used with APK/AAB packaged Android apps') |
| 110 | } |
| 111 | } |
| 112 | |