diff options
| author | Po Lu | 2024-06-12 16:44:21 +0800 |
|---|---|---|
| committer | Po Lu | 2024-06-12 16:44:21 +0800 |
| commit | 02e70821b3800a082aec215a9ab8adbfafe9ad76 (patch) | |
| tree | 87daf46f3c3efadaaa93ea859f48541bfe7e6b34 | |
| parent | f543ec18f44fa64d06e1ab45e1484326f8451ebe (diff) | |
| download | emacs-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.
| -rw-r--r-- | java/Makefile.in | 4 | ||||
| -rw-r--r-- | lib-src/asset-directory-tool.c | 107 | ||||
| -rw-r--r-- | src/android-asset.h | 128 | ||||
| -rw-r--r-- | src/androidvfs.c | 62 | ||||
| -rw-r--r-- | src/lread.c | 2 |
5 files changed, 229 insertions, 74 deletions
diff --git a/java/Makefile.in b/java/Makefile.in index fd076c089ff..8cc2235b9f3 100644 --- a/java/Makefile.in +++ b/java/Makefile.in | |||
| @@ -258,7 +258,8 @@ install_temp: $(CROSS_BINS) $(CROSS_LIBS) $(RESOURCE_FILES) | |||
| 258 | { hostname; date +%s; } > install_temp/assets/build_info | 258 | { hostname; date +%s; } > install_temp/assets/build_info |
| 259 | # Produce the file index. | 259 | # Produce the file index. |
| 260 | $(AM_V_SILENT) $(libsrc)/asset-directory-tool \ | 260 | $(AM_V_SILENT) $(libsrc)/asset-directory-tool \ |
| 261 | install_temp/assets install_temp/assets/directory-tree | 261 | install_temp/assets install_temp/assets/directory-tree\ |
| 262 | $(if $(ANDROID_SDK_8_OR_EARLIER),--api-8) | ||
| 262 | # If the package targets Android 2.2, move compressable and | 263 | # If the package targets Android 2.2, move compressable and |
| 263 | # non-compressable assets to separate directories. | 264 | # non-compressable assets to separate directories. |
| 264 | $(AM_V_SILENT) \ | 265 | $(AM_V_SILENT) \ |
| @@ -266,6 +267,7 @@ install_temp: $(CROSS_BINS) $(CROSS_LIBS) $(RESOURCE_FILES) | |||
| 266 | echo "Moving large and gzipped files to separate directories...">&2;\ | 267 | echo "Moving large and gzipped files to separate directories...">&2;\ |
| 267 | mkdir -p install_temp/assets_raw; \ | 268 | mkdir -p install_temp/assets_raw; \ |
| 268 | cd install_temp/assets; \ | 269 | cd install_temp/assets; \ |
| 270 | mv directory-tree ../assets_raw; \ | ||
| 269 | find . \( -size +1536 -o -size 1536 \) \ | 271 | find . \( -size +1536 -o -size 1536 \) \ |
| 270 | \( \! -name '*.gz' \) -type f > files.txt; \ | 272 | \( \! -name '*.gz' \) -type f > files.txt; \ |
| 271 | tar cf ../assets_raw/largefiles.tar -T files.txt; \ | 273 | tar cf ../assets_raw/largefiles.tar -T files.txt; \ |
diff --git a/lib-src/asset-directory-tool.c b/lib-src/asset-directory-tool.c index 31735586193..23f4655448c 100644 --- a/lib-src/asset-directory-tool.c +++ b/lib-src/asset-directory-tool.c | |||
| @@ -20,6 +20,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 20 | #include <config.h> | 20 | #include <config.h> |
| 21 | 21 | ||
| 22 | #include <stdio.h> | 22 | #include <stdio.h> |
| 23 | #include <verify.h> | ||
| 23 | #include <fcntl.h> | 24 | #include <fcntl.h> |
| 24 | #include <errno.h> | 25 | #include <errno.h> |
| 25 | #include <byteswap.h> | 26 | #include <byteswap.h> |
| @@ -35,17 +36,19 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 35 | application package. | 36 | application package. |
| 36 | 37 | ||
| 37 | Such a file records the layout of the `assets' directory in the | 38 | Such a file records the layout of the `assets' directory in the |
| 38 | package. Emacs records this information itself and uses it in the | 39 | package, and, in packages targeting Android 2.2, the size of each of |
| 39 | Android emulation of readdir, because the system asset manager APIs | 40 | its members. Emacs records this information itself and uses it in |
| 40 | are routinely buggy, and are often unable to locate directories or | 41 | the Android emulation of readdir, because the system asset manager |
| 41 | files. | 42 | APIs are often unable to locate directories or files, or provide |
| 42 | 43 | corresponding metadata. | |
| 43 | The file is packed, with no data alignment guarantees made. The | 44 | |
| 44 | file starts with the bytes "EMACS", following which is the name of | 45 | The file is packed, with no data alignment guarantees made. The file |
| 45 | the first file or directory, a NULL byte and an unsigned int | 46 | starts with the bytes "EMACS", or EMACS____ on Android 2.2, following |
| 46 | indicating the offset from the start of the file to the start of | 47 | which is the name of the first file or directory, a NULL byte, an |
| 47 | the next sibling. Following that is a list of subdirectories or | 48 | unsigned int holding its size (on Android 2.2), and an unsigned int |
| 48 | files in the same format. The long is stored LSB first. | 49 | indicating the offset from the start of the file to the start of the |
| 50 | next sibling. Following that is a list of subdirectories or files in | ||
| 51 | the same format. The long is stored LSB first. | ||
| 49 | 52 | ||
| 50 | Directories can be distinguished from ordinary files through the | 53 | Directories can be distinguished from ordinary files through the |
| 51 | last bytes of their file names (immediately previous to their | 54 | last bytes of their file names (immediately previous to their |
| @@ -62,10 +65,19 @@ struct directory_tree | |||
| 62 | /* The name of this directory or file. */ | 65 | /* The name of this directory or file. */ |
| 63 | char *name; | 66 | char *name; |
| 64 | 67 | ||
| 68 | /* st_size of this entry. */ | ||
| 69 | off_t st_size; | ||
| 70 | |||
| 65 | /* Subdirectories and files inside this directory. */ | 71 | /* Subdirectories and files inside this directory. */ |
| 66 | struct directory_tree *children, *next; | 72 | struct directory_tree *children, *next; |
| 67 | }; | 73 | }; |
| 68 | 74 | ||
| 75 | /* Whether the size of each entry should be prepended to the start | ||
| 76 | pointer. */ | ||
| 77 | static bool need_file_size; | ||
| 78 | |||
| 79 | |||
| 80 | |||
| 69 | /* Exit with EXIT_FAILURE, after printing a description of a failing | 81 | /* Exit with EXIT_FAILURE, after printing a description of a failing |
| 70 | function WHAT along with the details of the error. */ | 82 | function WHAT along with the details of the error. */ |
| 71 | 83 | ||
| @@ -138,11 +150,14 @@ main_1 (DIR *dir, struct directory_tree *parent) | |||
| 138 | last = &this->next; | 150 | last = &this->next; |
| 139 | this->name = xmalloc (length + 2); | 151 | this->name = xmalloc (length + 2); |
| 140 | strcpy (this->name, dirent->d_name); | 152 | strcpy (this->name, dirent->d_name); |
| 153 | this->st_size = 0; | ||
| 141 | 154 | ||
| 142 | /* Now record the offset to the end of this directory. This | 155 | /* Now record the offset to the end of this directory. This |
| 143 | is length + 1, for the file name, and 5 more bytes for | 156 | is length + 1, for the file name, 5 more bytes for the |
| 144 | the trailing NULL and long. */ | 157 | trailing NULL and long, and 4 further bytes if a file size |
| 145 | this->offset = parent->offset + length + 6; | 158 | is required. */ |
| 159 | this->offset = (parent->offset | ||
| 160 | + length + 6 + (need_file_size ? 4 : 0)); | ||
| 146 | 161 | ||
| 147 | /* Terminate that with a slash and trailing NULL byte. */ | 162 | /* Terminate that with a slash and trailing NULL byte. */ |
| 148 | this->name[length] = '/'; | 163 | this->name[length] = '/'; |
| @@ -175,11 +190,22 @@ main_1 (DIR *dir, struct directory_tree *parent) | |||
| 175 | *last = this; | 190 | *last = this; |
| 176 | last = &this->next; | 191 | last = &this->next; |
| 177 | this->name = xmalloc (length + 1); | 192 | this->name = xmalloc (length + 1); |
| 193 | this->st_size = statb.st_size; | ||
| 178 | strcpy (this->name, dirent->d_name); | 194 | strcpy (this->name, dirent->d_name); |
| 179 | 195 | ||
| 180 | /* This is one byte shorter because there is no trailing | 196 | if (this->st_size >= 0x1ffffff) |
| 197 | { | ||
| 198 | fprintf (stderr, | ||
| 199 | "asset-directory-tool: file size exceeds maximum" | ||
| 200 | " representable in a directory-tree: %s\n", | ||
| 201 | dirent->d_name); | ||
| 202 | exit (EXIT_FAILURE); | ||
| 203 | } | ||
| 204 | |||
| 205 | /* This is one byte the shorter because there is no trailing | ||
| 181 | slash. */ | 206 | slash. */ |
| 182 | this->offset = parent->offset + length + 5; | 207 | this->offset = (parent->offset + length + 5 |
| 208 | + (need_file_size ? 4 : 0)); | ||
| 183 | parent->offset = this->offset; | 209 | parent->offset = this->offset; |
| 184 | } | 210 | } |
| 185 | } | 211 | } |
| @@ -194,7 +220,7 @@ main_2 (int fd, struct directory_tree *tree, size_t *offset) | |||
| 194 | { | 220 | { |
| 195 | ssize_t size; | 221 | ssize_t size; |
| 196 | struct directory_tree *child; | 222 | struct directory_tree *child; |
| 197 | unsigned int output; | 223 | unsigned int output[2]; |
| 198 | 224 | ||
| 199 | /* Write tree->name with the trailing NULL byte. */ | 225 | /* Write tree->name with the trailing NULL byte. */ |
| 200 | size = strlen (tree->name) + 1; | 226 | size = strlen (tree->name) + 1; |
| @@ -203,13 +229,26 @@ main_2 (int fd, struct directory_tree *tree, size_t *offset) | |||
| 203 | 229 | ||
| 204 | /* Write the offset. */ | 230 | /* Write the offset. */ |
| 205 | #ifdef WORDS_BIGENDIAN | 231 | #ifdef WORDS_BIGENDIAN |
| 206 | output = bswap_32 (tree->offset); | 232 | output[1] = bswap_32 (tree->offset); |
| 207 | #else | 233 | output[0] = bswap_32 ((unsigned int) tree->st_size); |
| 208 | output = tree->offset; | 234 | #else /* !WORDS_BIGENDIAN */ |
| 209 | #endif | 235 | output[1] = tree->offset; |
| 210 | if (write (fd, &output, 4) < 1) | 236 | output[0] = (unsigned int) tree->st_size; |
| 211 | croak ("write"); | 237 | #endif /* !WORDS_BIGENDIAN */ |
| 212 | size += 4; | 238 | |
| 239 | verify (sizeof output == 8 && sizeof output[0] == 4); | ||
| 240 | if (!need_file_size) | ||
| 241 | { | ||
| 242 | if (write (fd, output + 1, 4) < 1) | ||
| 243 | croak ("write"); | ||
| 244 | size += 4; | ||
| 245 | } | ||
| 246 | else | ||
| 247 | { | ||
| 248 | if (write (fd, output, 8) < 1) | ||
| 249 | croak ("write"); | ||
| 250 | size += 8; | ||
| 251 | } | ||
| 213 | 252 | ||
| 214 | /* Now update offset. */ | 253 | /* Now update offset. */ |
| 215 | *offset += size; | 254 | *offset += size; |
| @@ -240,13 +279,16 @@ main (int argc, char **argv) | |||
| 240 | struct directory_tree tree; | 279 | struct directory_tree tree; |
| 241 | size_t offset; | 280 | size_t offset; |
| 242 | 281 | ||
| 243 | if (argc != 3) | 282 | if (argc != 3 && argc != 4) |
| 244 | { | 283 | { |
| 245 | fprintf (stderr, "usage: %s directory output-file\n", | 284 | fprintf (stderr, "usage: %s directory output-file " |
| 246 | argv[0]); | 285 | "[--api-8]\n", argv[0]); |
| 247 | return EXIT_FAILURE; | 286 | return EXIT_FAILURE; |
| 248 | } | 287 | } |
| 249 | 288 | ||
| 289 | if (argc == 4 && !strcmp (argv[3], "--api-8")) | ||
| 290 | need_file_size = true; | ||
| 291 | |||
| 250 | fd = open (argv[2], O_CREAT | O_TRUNC | O_RDWR, | 292 | fd = open (argv[2], O_CREAT | O_TRUNC | O_RDWR, |
| 251 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); | 293 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); |
| 252 | 294 | ||
| @@ -272,16 +314,23 @@ main (int argc, char **argv) | |||
| 272 | return EXIT_FAILURE; | 314 | return EXIT_FAILURE; |
| 273 | } | 315 | } |
| 274 | 316 | ||
| 317 | /* And a further 4 bytes of padding if need_file_size. */ | ||
| 318 | if (need_file_size && write (fd, "____", 4) < 4) | ||
| 319 | { | ||
| 320 | perror ("write"); | ||
| 321 | return EXIT_FAILURE; | ||
| 322 | } | ||
| 323 | |||
| 275 | /* Now iterate through children of INDIR, building the directory | 324 | /* Now iterate through children of INDIR, building the directory |
| 276 | tree. */ | 325 | tree. */ |
| 277 | tree.offset = 5; | 326 | tree.offset = 5 + (need_file_size ? 4 : 0); |
| 278 | tree.children = NULL; | 327 | tree.children = NULL; |
| 279 | 328 | ||
| 280 | main_1 (indir, &tree); | 329 | main_1 (indir, &tree); |
| 281 | closedir (indir); | 330 | closedir (indir); |
| 282 | 331 | ||
| 283 | /* Finally, write the directory tree to the output file. */ | 332 | /* Finally, write the directory tree to the output file. */ |
| 284 | offset = 5; | 333 | offset = 5 + (need_file_size ? 4 : 0); |
| 285 | for (; tree.children; tree.children = tree.children->next) | 334 | for (; tree.children; tree.children = tree.children->next) |
| 286 | main_2 (fd, tree.children, &offset); | 335 | main_2 (fd, tree.children, &offset); |
| 287 | 336 | ||
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 | |||
| 26 | static const char *directory_tree; | ||
| 27 | |||
| 28 | static const char *android_scan_directory_tree (const char *, size_t *); | ||
| 29 | static 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 | ||
| 1003 | static unsigned int | 1005 | static unsigned int |
| 1004 | android_extract_long (char *pointer) | 1006 | android_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 | ||
| 1024 | static const char * | 1026 | static const char * |
| 1025 | android_scan_directory_tree (char *file, size_t *limit_return) | 1027 | android_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 | ||