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 | 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 | 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, int) &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 | 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) int |
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 |
70 | // a 64-bit number insted of 32-bit as `get_length`. |
71 | pub fn (a &Asset) get_length_64() i64 { |
72 | return C.AAsset_getLength64(a) |
73 | } |
74 | |
75 | fn C.AAsset_read(&C.AAsset, voidptr, usize) int |
76 | |
77 | // read attempts to read 'count' bytes of data from the current offset. |
78 | // read returns the number of bytes read, zero on EOF, or < 0 on error. |
79 | pub fn (a &Asset) read(buffer voidptr, count usize) int { |
80 | return C.AAsset_read(a, buffer, count) |
81 | } |
82 | |
83 | fn C.AAsset_close(&C.AAsset) |
84 | |
85 | // close closes the asset, freeing all associated resources. |
86 | pub fn (a &Asset) close() { |
87 | C.AAsset_close(a) |
88 | } |
89 | |
90 | // read_apk_asset returns all the data located at `path`. |
91 | // `path` is expected to be relative to the APK/AAB `assets` directory. |
92 | pub fn read_apk_asset(path string) ![]u8 { |
93 | $if apk { |
94 | act := &NativeActivity(C.sapp_android_get_native_activity()) |
95 | if isnil(act) { |
96 | return error('could not get reference to Android activity') |
97 | } |
98 | asset_manager := act.assetManager |
99 | asset := asset_manager.open(path, .streaming)! |
100 | len := asset.get_length() |
101 | buf := []u8{len: len} |
102 | for { |
103 | if asset.read(buf.data, usize(len)) > 0 { |
104 | break |
105 | } |
106 | } |
107 | asset.close() |
108 | return buf |
109 | } $else { |
110 | return error(@FN + ' can only be used with APK/AAB packaged Android apps') |
111 | } |
112 | } |