aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2024-06-12 16:44:21 +0800
committerPo Lu2024-06-12 16:44:21 +0800
commit02e70821b3800a082aec215a9ab8adbfafe9ad76 (patch)
tree87daf46f3c3efadaaa93ea859f48541bfe7e6b34 /src
parentf543ec18f44fa64d06e1ab45e1484326f8451ebe (diff)
downloademacs-02e70821b3800a082aec215a9ab8adbfafe9ad76.tar.gz
emacs-02e70821b3800a082aec215a9ab8adbfafe9ad76.zip
Restore functionality on Android 2.2
* java/Makefile.in (install_temp): Do not compress directory-tree and generate such files in a special format that stores file sizes. * lib-src/asset-directory-tool.c (struct directory_tree): New field st_size. (need_file_size): New variable. (main_1, main_2, main): Write file sizes before sibling offsets if `--api-8' is specified. * src/android-asset.h (struct android_asset_manager): New field open. (struct android_asset): New field name. (AAssetManager_fromJava): Load AssetManager#open. (AAssetManager_open): If a directory tree has already been loaded, search for a matching asset and load its size thence, to avoid the requirement of an AssetFileDescriptor. (AAsset_close): Don't assume asset->fd exists. Release asset->name. (AAsset_getLength): Likewise. (android_asset_create_stream): If asset->name exists, call AssetManager#open, in order to open compressed files. * src/androidvfs.c (OLD_ANDROID_ASSETS): Define to 1 on API 8. (android_extract_long, android_scan_directory_tree): Mark arguments as const. Adjust offsets when OLD_ANDROID_ASSETS. (android_is_directory, android_init_assets, android_afs_readdir): Likewise. * src/lread.c (lread_fstat): Define to sys_fstat, not fstat.
Diffstat (limited to 'src')
-rw-r--r--src/android-asset.h128
-rw-r--r--src/androidvfs.c62
-rw-r--r--src/lread.c2
3 files changed, 148 insertions, 44 deletions
diff --git a/src/android-asset.h b/src/android-asset.h
index a6b5aa3366c..273ab1fa734 100644
--- a/src/android-asset.h
+++ b/src/android-asset.h
@@ -19,6 +19,17 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20#include <android/log.h> 20#include <android/log.h>
21 21
22
23
24/* Forward declarations. */
25
26static const char *directory_tree;
27
28static const char *android_scan_directory_tree (const char *, size_t *);
29static unsigned int android_extract_long (const char *);
30
31
32
22/* This file contains an emulation of the Android asset manager API 33/* This file contains an emulation of the Android asset manager API
23 used on builds for Android 2.2. It is included by android.c 34 used on builds for Android 2.2. It is included by android.c
24 whenever appropriate. 35 whenever appropriate.
@@ -34,6 +45,7 @@ struct android_asset_manager
34 /* Asset manager class and functions. */ 45 /* Asset manager class and functions. */
35 jclass class; 46 jclass class;
36 jmethodID open_fd; 47 jmethodID open_fd;
48 jmethodID open;
37 49
38 /* Asset file descriptor class and functions. */ 50 /* Asset file descriptor class and functions. */
39 jclass fd_class; 51 jclass fd_class;
@@ -63,6 +75,9 @@ struct android_asset
63 /* The asset file descriptor and input stream. */ 75 /* The asset file descriptor and input stream. */
64 jobject fd, stream; 76 jobject fd, stream;
65 77
78 /* Alternatively, the name of the file. */
79 jstring name;
80
66 /* The mode. */ 81 /* The mode. */
67 int mode; 82 int mode;
68}; 83};
@@ -98,6 +113,12 @@ AAssetManager_fromJava (JNIEnv *env, jobject java_manager)
98 = (*env)->GetMethodID (env, manager->class, "openFd", 113 = (*env)->GetMethodID (env, manager->class, "openFd",
99 "(Ljava/lang/String;)" 114 "(Ljava/lang/String;)"
100 "Landroid/content/res/AssetFileDescriptor;"); 115 "Landroid/content/res/AssetFileDescriptor;");
116 assert (manager->open_fd);
117
118 manager->open
119 = (*env)->GetMethodID (env, manager->class, "open",
120 "(Ljava/lang/String;)"
121 "Ljava/io/InputStream;");
101 assert (manager->open); 122 assert (manager->open);
102 123
103 manager->fd_class 124 manager->fd_class
@@ -168,6 +189,8 @@ AAssetManager_open (AAssetManager *manager, const char *c_name,
168 jobject desc; 189 jobject desc;
169 jstring name; 190 jstring name;
170 AAsset *asset; 191 AAsset *asset;
192 const char *asset_dir;
193 jlong st_size = -1;
171 194
172 /* Push a local frame. */ 195 /* Push a local frame. */
173 asset = NULL; 196 asset = NULL;
@@ -177,53 +200,86 @@ AAssetManager_open (AAssetManager *manager, const char *c_name,
177 if ((*(manager->env))->ExceptionCheck (manager->env)) 200 if ((*(manager->env))->ExceptionCheck (manager->env))
178 goto fail; 201 goto fail;
179 202
180 /* Encoding issues can be ignored for now as there are only ASCII 203 /* If the directory tree has been initialized, it is possible to avoid
181 file names in Emacs. */ 204 opening an AssetFileDescriptor and thereby access compressed
205 assets, without sacrificing the possibility of reading the file
206 size. */
207 if (directory_tree)
208 {
209 /* Search for a matching asset. */
210 asset_dir = android_scan_directory_tree (c_name, NULL);
211 if (!asset_dir)
212 goto fail;
213
214 /* Extract the size of the asset from this directory. */
215 st_size = android_extract_long (asset_dir - 8);
216 }
217
218 /* Encoding issues can be ignored for the time being as there are only
219 ASCII file names in Emacs. */
182 name = (*(manager->env))->NewStringUTF (manager->env, c_name); 220 name = (*(manager->env))->NewStringUTF (manager->env, c_name);
183 221
184 if (!name) 222 if (!name)
185 goto fail; 223 goto fail;
186 224
187 /* Now try to open an ``AssetFileDescriptor''. */ 225 /* If st_size has been set, it ought to be possible to open an input
188 desc = (*(manager->env))->CallObjectMethod (manager->env, 226 stream directly upon the first attempt to read from the asset,
189 manager->asset_manager, 227 sidestepping the intermediate AssetFileDescriptor. */
190 manager->open_fd,
191 name);
192 228
193 if (!desc) 229 desc = NULL;
194 goto fail; 230
231 if (st_size < 0)
232 /* Otherwise attempt to open an ``AssetFileDescriptor''. */
233 desc = (*(manager->env))->CallObjectMethod (manager->env,
234 manager->asset_manager,
235 manager->open_fd,
236 name);
195 237
196 /* Allocate the asset. */ 238 /* Allocate the asset. */
197 asset = calloc (1, sizeof *asset); 239 asset = calloc (1, sizeof *asset);
198 240
199 if (!asset) 241 if (!asset)
242 goto fail;
243
244 if (desc)
200 { 245 {
201 (*(manager->env))->CallVoidMethod (manager->env, 246 /* Pop the local frame and return desc. */
202 desc, 247 desc = (*(manager->env))->NewGlobalRef (manager->env, desc);
203 manager->close);
204 goto fail;
205 }
206 248
207 /* Pop the local frame and return desc. */ 249 if (!desc)
208 desc = (*(manager->env))->NewGlobalRef (manager->env, desc); 250 goto fail;
209 251
210 if (!desc) 252 /* Will be released by PopLocalFrame. */
211 goto fail; 253 name = NULL;
254 }
255 else /* if (name) */
256 {
257 /* Pop the local frame and return name. */
258 name = (*(manager->env))->NewGlobalRef (manager->env, name);
259
260 if (!name)
261 goto fail;
262 }
212 263
213 (*(manager->env))->PopLocalFrame (manager->env, NULL); 264 (*(manager->env))->PopLocalFrame (manager->env, NULL);
214 265
215 asset->manager = manager; 266 asset->manager = manager;
216 asset->length = -1; 267 asset->length = st_size;
217 asset->fd = desc; 268 asset->fd = desc;
269 asset->name = name;
218 asset->mode = mode; 270 asset->mode = mode;
219 271
220 return asset; 272 return asset;
221 273
222 fail: 274 fail:
275 if (desc)
276 (*(manager->env))->CallVoidMethod (manager->env,
277 desc,
278 manager->close);
279
223 (*(manager->env))->ExceptionClear (manager->env); 280 (*(manager->env))->ExceptionClear (manager->env);
224 (*(manager->env))->PopLocalFrame (manager->env, NULL); 281 (*(manager->env))->PopLocalFrame (manager->env, NULL);
225 free (asset); 282 free (asset);
226
227 return NULL; 283 return NULL;
228} 284}
229 285
@@ -234,11 +290,14 @@ AAsset_close (AAsset *asset)
234 290
235 env = asset->manager->env; 291 env = asset->manager->env;
236 292
237 (*env)->CallVoidMethod (asset->manager->env, 293 if (asset->fd)
238 asset->fd, 294 {
239 asset->manager->close); 295 (*env)->CallVoidMethod (asset->manager->env,
240 (*env)->DeleteGlobalRef (asset->manager->env, 296 asset->fd,
241 asset->fd); 297 asset->manager->close);
298 (*env)->DeleteGlobalRef (asset->manager->env,
299 asset->fd);
300 }
242 301
243 if (asset->stream) 302 if (asset->stream)
244 { 303 {
@@ -249,6 +308,10 @@ AAsset_close (AAsset *asset)
249 asset->stream); 308 asset->stream);
250 } 309 }
251 310
311 if (asset->name)
312 (*env)->DeleteGlobalRef (asset->manager->env,
313 asset->name);
314
252 free (asset); 315 free (asset);
253} 316}
254 317
@@ -264,10 +327,17 @@ android_asset_create_stream (AAsset *asset)
264 jobject stream; 327 jobject stream;
265 JNIEnv *env; 328 JNIEnv *env;
266 329
330 assert (asset->fd || asset->name);
331
267 env = asset->manager->env; 332 env = asset->manager->env;
268 stream 333
269 = (*env)->CallObjectMethod (env, asset->fd, 334 if (asset->name)
270 asset->manager->create_input_stream); 335 stream = (*env)->CallObjectMethod (env, asset->manager->asset_manager,
336 asset->manager->open, asset->name);
337 else
338 stream
339 = (*env)->CallObjectMethod (env, asset->fd,
340 asset->manager->create_input_stream);
271 341
272 if (!stream) 342 if (!stream)
273 { 343 {
@@ -380,6 +450,8 @@ AAsset_getLength (AAsset *asset)
380 450
381 if (asset->length != -1) 451 if (asset->length != -1)
382 return asset->length; 452 return asset->length;
453 if (!asset->fd)
454 return 0;
383 455
384 env = asset->manager->env; 456 env = asset->manager->env;
385 asset->length 457 asset->length
diff --git a/src/androidvfs.c b/src/androidvfs.c
index c0bd86e54b8..d28a74918f6 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -46,8 +46,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
46#if __ANDROID_API__ >= 9 46#if __ANDROID_API__ >= 9
47#include <android/asset_manager.h> 47#include <android/asset_manager.h>
48#include <android/asset_manager_jni.h> 48#include <android/asset_manager_jni.h>
49#define OLD_ANDROID_ASSETS 0
49#else /* __ANDROID_API__ < 9 */ 50#else /* __ANDROID_API__ < 9 */
50#include "android-asset.h" 51#include "android-asset.h"
52#define OLD_ANDROID_ASSETS 1
51#endif /* __ANDROID_API__ >= 9 */ 53#endif /* __ANDROID_API__ >= 9 */
52 54
53#include <android/log.h> 55#include <android/log.h>
@@ -1001,7 +1003,7 @@ static AAssetManager *asset_manager;
1001/* Read an unaligned (32-bit) long from the address POINTER. */ 1003/* Read an unaligned (32-bit) long from the address POINTER. */
1002 1004
1003static unsigned int 1005static unsigned int
1004android_extract_long (char *pointer) 1006android_extract_long (const char *pointer)
1005{ 1007{
1006 unsigned int number; 1008 unsigned int number;
1007 1009
@@ -1022,16 +1024,20 @@ android_extract_long (char *pointer)
1022 directory. */ 1024 directory. */
1023 1025
1024static const char * 1026static const char *
1025android_scan_directory_tree (char *file, size_t *limit_return) 1027android_scan_directory_tree (const char *file, size_t *limit_return)
1026{ 1028{
1027 char *token, *saveptr, *copy, *start, *max, *limit; 1029 char *token, *saveptr, *copy, *start, *max, *limit;
1028 size_t token_length, ntokens, i, len; 1030 size_t token_length, ntokens, i, len;
1029 char *tokens[10]; 1031 char *tokens[20];
1030 1032
1031 USE_SAFE_ALLOCA; 1033 USE_SAFE_ALLOCA;
1032 1034
1033 /* Skip past the 5 byte header. */ 1035 /* Skip past the 5 or 9 byte header. */
1036#if !OLD_ANDROID_ASSETS
1034 start = (char *) directory_tree + 5; 1037 start = (char *) directory_tree + 5;
1038#else /* OLD_ANDROID_ASSETS */
1039 start = (char *) directory_tree + 9;
1040#endif /* OLD_ANDROID_ASSETS */
1035 1041
1036 /* Figure out the current limit. */ 1042 /* Figure out the current limit. */
1037 limit = (char *) directory_tree + directory_tree_size; 1043 limit = (char *) directory_tree + directory_tree_size;
@@ -1098,9 +1104,9 @@ android_scan_directory_tree (char *file, size_t *limit_return)
1098 { 1104 {
1099 /* They probably match. Find the NULL byte. It must be 1105 /* They probably match. Find the NULL byte. It must be
1100 either one byte past start + token_length, with the last 1106 either one byte past start + token_length, with the last
1101 byte a trailing slash (indicating that it is a 1107 byte a trailing slash (indicating that it is a directory),
1102 directory), or just start + token_length. Return 4 bytes 1108 or just start + token_length. Return 4 or 8 bytes past the
1103 past the next NULL byte. */ 1109 next NULL byte. */
1104 1110
1105 max = memchr (start, 0, limit - start); 1111 max = memchr (start, 0, limit - start);
1106 1112
@@ -1113,13 +1119,14 @@ android_scan_directory_tree (char *file, size_t *limit_return)
1113 last token. Otherwise, set it as start and the limit as 1119 last token. Otherwise, set it as start and the limit as
1114 start + the offset and continue the loop. */ 1120 start + the offset and continue the loop. */
1115 1121
1116 if (max && max + 5 <= limit) 1122 if (max && max + (OLD_ANDROID_ASSETS ? 9 : 5) <= limit)
1117 { 1123 {
1118 if (i < ntokens - 1) 1124 if (i < ntokens - 1)
1119 { 1125 {
1120 start = max + 5; 1126 start = max + (OLD_ANDROID_ASSETS ? 9 : 5);
1121 limit = ((char *) directory_tree 1127 limit = ((char *) directory_tree
1122 + android_extract_long (max + 1)); 1128 + android_extract_long (max + (OLD_ANDROID_ASSETS
1129 ? 5 : 1)));
1123 1130
1124 /* Make sure limit is still in range. */ 1131 /* Make sure limit is still in range. */
1125 if (limit > directory_tree + directory_tree_size 1132 if (limit > directory_tree + directory_tree_size
@@ -1137,10 +1144,12 @@ android_scan_directory_tree (char *file, size_t *limit_return)
1137 { 1144 {
1138 /* Figure out the limit. */ 1145 /* Figure out the limit. */
1139 if (limit_return) 1146 if (limit_return)
1140 *limit_return = android_extract_long (max + 1); 1147 *limit_return
1148 = android_extract_long (max + (OLD_ANDROID_ASSETS
1149 ? 5 : 1));
1141 1150
1142 /* Go to the end of this file. */ 1151 /* Go to the end of this file. */
1143 max += 5; 1152 max += (OLD_ANDROID_ASSETS ? 9 : 5);
1144 } 1153 }
1145 1154
1146 SAFE_FREE (); 1155 SAFE_FREE ();
@@ -1161,11 +1170,12 @@ android_scan_directory_tree (char *file, size_t *limit_return)
1161 1170
1162 start = memchr (start, 0, limit - start); 1171 start = memchr (start, 0, limit - start);
1163 1172
1164 if (!start || start + 5 > limit) 1173 if (!start || start + (OLD_ANDROID_ASSETS ? 9 : 5) > limit)
1165 goto fail; 1174 goto fail;
1166 1175
1167 start = ((char *) directory_tree 1176 start = ((char *) directory_tree
1168 + android_extract_long (start + 1)); 1177 + android_extract_long (start
1178 + (OLD_ANDROID_ASSETS ? 5 : 1)));
1169 1179
1170 /* Make sure start is still in bounds. */ 1180 /* Make sure start is still in bounds. */
1171 1181
@@ -1192,13 +1202,20 @@ android_is_directory (const char *dir)
1192{ 1202{
1193 /* If the directory is the directory tree, then it is a 1203 /* If the directory is the directory tree, then it is a
1194 directory. */ 1204 directory. */
1195 if (dir == directory_tree + 5) 1205 if (dir == directory_tree + (OLD_ANDROID_ASSETS ? 9 : 5))
1196 return true; 1206 return true;
1197 1207
1208#if !OLD_ANDROID_ASSETS
1198 /* Otherwise, look 5 bytes behind. If it is `/', then it is a 1209 /* Otherwise, look 5 bytes behind. If it is `/', then it is a
1199 directory. */ 1210 directory. */
1200 return (dir - 6 >= directory_tree 1211 return (dir - 6 >= directory_tree
1201 && *(dir - 6) == '/'); 1212 && *(dir - 6) == '/');
1213#else /* OLD_ANDROID_ASSETS */
1214 /* Otherwise, look 9 bytes behind. If it is `/', then it is a
1215 directory. */
1216 return (dir - 10 >= directory_tree
1217 && *(dir - 10) == '/');
1218#endif /* OLD_ANDROID_ASSETS */
1202} 1219}
1203 1220
1204/* Initialize asset retrieval. ENV should be a JNI environment for 1221/* Initialize asset retrieval. ENV should be a JNI environment for
@@ -1232,6 +1249,7 @@ android_init_assets (JNIEnv *env, jobject manager)
1232 /* Now figure out how big the directory tree is, and compare the 1249 /* Now figure out how big the directory tree is, and compare the
1233 first few bytes. */ 1250 first few bytes. */
1234 directory_tree_size = AAsset_getLength (asset); 1251 directory_tree_size = AAsset_getLength (asset);
1252#if !OLD_ANDROID_ASSETS
1235 if (directory_tree_size < 5 1253 if (directory_tree_size < 5
1236 || memcmp (directory_tree, "EMACS", 5)) 1254 || memcmp (directory_tree, "EMACS", 5))
1237 { 1255 {
@@ -1239,6 +1257,15 @@ android_init_assets (JNIEnv *env, jobject manager)
1239 "Directory tree has bad magic"); 1257 "Directory tree has bad magic");
1240 emacs_abort (); 1258 emacs_abort ();
1241 } 1259 }
1260#else /* OLD_ANDROID_ASSETS */
1261 if (directory_tree_size < 9
1262 || memcmp (directory_tree, "EMACS____", 9))
1263 {
1264 __android_log_print (ANDROID_LOG_FATAL, __func__,
1265 "Directory tree has bad magic");
1266 emacs_abort ();
1267 }
1268#endif /* OLD_ANDROID_ASSETS */
1242 1269
1243 /* Hold a VM reference to the asset manager to prevent the native 1270 /* Hold a VM reference to the asset manager to prevent the native
1244 object from being deleted. */ 1271 object from being deleted. */
@@ -2287,8 +2314,13 @@ android_afs_readdir (struct android_vdir *vdir)
2287 dirent.d_type = DT_REG; 2314 dirent.d_type = DT_REG;
2288 2315
2289 /* Forward dir->asset_dir to the file past last. */ 2316 /* Forward dir->asset_dir to the file past last. */
2317#if !OLD_ANDROID_ASSETS
2290 dir->asset_dir = ((char *) directory_tree 2318 dir->asset_dir = ((char *) directory_tree
2291 + android_extract_long ((char *) last)); 2319 + android_extract_long ((char *) last));
2320#else /* OLD_ANDROID_ASSETS */
2321 dir->asset_dir = ((char *) directory_tree
2322 + android_extract_long ((char *) last + 4));
2323#endif /* OLD_ANDROID_ASSETS */
2292 2324
2293 return &dirent; 2325 return &dirent;
2294} 2326}
diff --git a/src/lread.c b/src/lread.c
index f5c79a8c0ea..1bc5b0c993d 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -69,7 +69,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
69#define lread_fd_cmp(n) (fd == (n)) 69#define lread_fd_cmp(n) (fd == (n))
70#define lread_fd_p (fd >= 0) 70#define lread_fd_p (fd >= 0)
71#define lread_close emacs_close 71#define lread_close emacs_close
72#define lread_fstat fstat 72#define lread_fstat sys_fstat
73#define lread_read_quit emacs_read_quit 73#define lread_read_quit emacs_read_quit
74#define lread_lseek lseek 74#define lread_lseek lseek
75 75