mirror of
https://github.com/masscollaborationlabs/emacs.git
synced 2025-07-03 19:03:24 +00:00
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.
This commit is contained in:
parent
f543ec18f4
commit
02e70821b3
5 changed files with 230 additions and 75 deletions
|
@ -258,7 +258,8 @@ install_temp: $(CROSS_BINS) $(CROSS_LIBS) $(RESOURCE_FILES)
|
||||||
{ hostname; date +%s; } > install_temp/assets/build_info
|
{ hostname; date +%s; } > install_temp/assets/build_info
|
||||||
# Produce the file index.
|
# Produce the file index.
|
||||||
$(AM_V_SILENT) $(libsrc)/asset-directory-tool \
|
$(AM_V_SILENT) $(libsrc)/asset-directory-tool \
|
||||||
install_temp/assets install_temp/assets/directory-tree
|
install_temp/assets install_temp/assets/directory-tree\
|
||||||
|
$(if $(ANDROID_SDK_8_OR_EARLIER),--api-8)
|
||||||
# If the package targets Android 2.2, move compressable and
|
# If the package targets Android 2.2, move compressable and
|
||||||
# non-compressable assets to separate directories.
|
# non-compressable assets to separate directories.
|
||||||
$(AM_V_SILENT) \
|
$(AM_V_SILENT) \
|
||||||
|
@ -266,6 +267,7 @@ install_temp: $(CROSS_BINS) $(CROSS_LIBS) $(RESOURCE_FILES)
|
||||||
echo "Moving large and gzipped files to separate directories...">&2;\
|
echo "Moving large and gzipped files to separate directories...">&2;\
|
||||||
mkdir -p install_temp/assets_raw; \
|
mkdir -p install_temp/assets_raw; \
|
||||||
cd install_temp/assets; \
|
cd install_temp/assets; \
|
||||||
|
mv directory-tree ../assets_raw; \
|
||||||
find . \( -size +1536 -o -size 1536 \) \
|
find . \( -size +1536 -o -size 1536 \) \
|
||||||
\( \! -name '*.gz' \) -type f > files.txt; \
|
\( \! -name '*.gz' \) -type f > files.txt; \
|
||||||
tar cf ../assets_raw/largefiles.tar -T files.txt; \
|
tar cf ../assets_raw/largefiles.tar -T files.txt; \
|
||||||
|
|
|
@ -20,6 +20,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <verify.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <byteswap.h>
|
#include <byteswap.h>
|
||||||
|
@ -35,17 +36,19 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
application package.
|
application package.
|
||||||
|
|
||||||
Such a file records the layout of the `assets' directory in the
|
Such a file records the layout of the `assets' directory in the
|
||||||
package. Emacs records this information itself and uses it in the
|
package, and, in packages targeting Android 2.2, the size of each of
|
||||||
Android emulation of readdir, because the system asset manager APIs
|
its members. Emacs records this information itself and uses it in
|
||||||
are routinely buggy, and are often unable to locate directories or
|
the Android emulation of readdir, because the system asset manager
|
||||||
files.
|
APIs are often unable to locate directories or files, or provide
|
||||||
|
corresponding metadata.
|
||||||
|
|
||||||
The file is packed, with no data alignment guarantees made. The
|
The file is packed, with no data alignment guarantees made. The file
|
||||||
file starts with the bytes "EMACS", following which is the name of
|
starts with the bytes "EMACS", or EMACS____ on Android 2.2, following
|
||||||
the first file or directory, a NULL byte and an unsigned int
|
which is the name of the first file or directory, a NULL byte, an
|
||||||
indicating the offset from the start of the file to the start of
|
unsigned int holding its size (on Android 2.2), and an unsigned int
|
||||||
the next sibling. Following that is a list of subdirectories or
|
indicating the offset from the start of the file to the start of the
|
||||||
files in the same format. The long is stored LSB first.
|
next sibling. Following that is a list of subdirectories or files in
|
||||||
|
the same format. The long is stored LSB first.
|
||||||
|
|
||||||
Directories can be distinguished from ordinary files through the
|
Directories can be distinguished from ordinary files through the
|
||||||
last bytes of their file names (immediately previous to their
|
last bytes of their file names (immediately previous to their
|
||||||
|
@ -62,10 +65,19 @@ struct directory_tree
|
||||||
/* The name of this directory or file. */
|
/* The name of this directory or file. */
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
|
/* st_size of this entry. */
|
||||||
|
off_t st_size;
|
||||||
|
|
||||||
/* Subdirectories and files inside this directory. */
|
/* Subdirectories and files inside this directory. */
|
||||||
struct directory_tree *children, *next;
|
struct directory_tree *children, *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Whether the size of each entry should be prepended to the start
|
||||||
|
pointer. */
|
||||||
|
static bool need_file_size;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Exit with EXIT_FAILURE, after printing a description of a failing
|
/* Exit with EXIT_FAILURE, after printing a description of a failing
|
||||||
function WHAT along with the details of the error. */
|
function WHAT along with the details of the error. */
|
||||||
|
|
||||||
|
@ -138,11 +150,14 @@ main_1 (DIR *dir, struct directory_tree *parent)
|
||||||
last = &this->next;
|
last = &this->next;
|
||||||
this->name = xmalloc (length + 2);
|
this->name = xmalloc (length + 2);
|
||||||
strcpy (this->name, dirent->d_name);
|
strcpy (this->name, dirent->d_name);
|
||||||
|
this->st_size = 0;
|
||||||
|
|
||||||
/* Now record the offset to the end of this directory. This
|
/* Now record the offset to the end of this directory. This
|
||||||
is length + 1, for the file name, and 5 more bytes for
|
is length + 1, for the file name, 5 more bytes for the
|
||||||
the trailing NULL and long. */
|
trailing NULL and long, and 4 further bytes if a file size
|
||||||
this->offset = parent->offset + length + 6;
|
is required. */
|
||||||
|
this->offset = (parent->offset
|
||||||
|
+ length + 6 + (need_file_size ? 4 : 0));
|
||||||
|
|
||||||
/* Terminate that with a slash and trailing NULL byte. */
|
/* Terminate that with a slash and trailing NULL byte. */
|
||||||
this->name[length] = '/';
|
this->name[length] = '/';
|
||||||
|
@ -175,11 +190,22 @@ main_1 (DIR *dir, struct directory_tree *parent)
|
||||||
*last = this;
|
*last = this;
|
||||||
last = &this->next;
|
last = &this->next;
|
||||||
this->name = xmalloc (length + 1);
|
this->name = xmalloc (length + 1);
|
||||||
|
this->st_size = statb.st_size;
|
||||||
strcpy (this->name, dirent->d_name);
|
strcpy (this->name, dirent->d_name);
|
||||||
|
|
||||||
/* This is one byte shorter because there is no trailing
|
if (this->st_size >= 0x1ffffff)
|
||||||
|
{
|
||||||
|
fprintf (stderr,
|
||||||
|
"asset-directory-tool: file size exceeds maximum"
|
||||||
|
" representable in a directory-tree: %s\n",
|
||||||
|
dirent->d_name);
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is one byte the shorter because there is no trailing
|
||||||
slash. */
|
slash. */
|
||||||
this->offset = parent->offset + length + 5;
|
this->offset = (parent->offset + length + 5
|
||||||
|
+ (need_file_size ? 4 : 0));
|
||||||
parent->offset = this->offset;
|
parent->offset = this->offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,7 +220,7 @@ main_2 (int fd, struct directory_tree *tree, size_t *offset)
|
||||||
{
|
{
|
||||||
ssize_t size;
|
ssize_t size;
|
||||||
struct directory_tree *child;
|
struct directory_tree *child;
|
||||||
unsigned int output;
|
unsigned int output[2];
|
||||||
|
|
||||||
/* Write tree->name with the trailing NULL byte. */
|
/* Write tree->name with the trailing NULL byte. */
|
||||||
size = strlen (tree->name) + 1;
|
size = strlen (tree->name) + 1;
|
||||||
|
@ -203,13 +229,26 @@ main_2 (int fd, struct directory_tree *tree, size_t *offset)
|
||||||
|
|
||||||
/* Write the offset. */
|
/* Write the offset. */
|
||||||
#ifdef WORDS_BIGENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
output = bswap_32 (tree->offset);
|
output[1] = bswap_32 (tree->offset);
|
||||||
#else
|
output[0] = bswap_32 ((unsigned int) tree->st_size);
|
||||||
output = tree->offset;
|
#else /* !WORDS_BIGENDIAN */
|
||||||
#endif
|
output[1] = tree->offset;
|
||||||
if (write (fd, &output, 4) < 1)
|
output[0] = (unsigned int) tree->st_size;
|
||||||
croak ("write");
|
#endif /* !WORDS_BIGENDIAN */
|
||||||
size += 4;
|
|
||||||
|
verify (sizeof output == 8 && sizeof output[0] == 4);
|
||||||
|
if (!need_file_size)
|
||||||
|
{
|
||||||
|
if (write (fd, output + 1, 4) < 1)
|
||||||
|
croak ("write");
|
||||||
|
size += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (write (fd, output, 8) < 1)
|
||||||
|
croak ("write");
|
||||||
|
size += 8;
|
||||||
|
}
|
||||||
|
|
||||||
/* Now update offset. */
|
/* Now update offset. */
|
||||||
*offset += size;
|
*offset += size;
|
||||||
|
@ -240,13 +279,16 @@ main (int argc, char **argv)
|
||||||
struct directory_tree tree;
|
struct directory_tree tree;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
|
|
||||||
if (argc != 3)
|
if (argc != 3 && argc != 4)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "usage: %s directory output-file\n",
|
fprintf (stderr, "usage: %s directory output-file "
|
||||||
argv[0]);
|
"[--api-8]\n", argv[0]);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (argc == 4 && !strcmp (argv[3], "--api-8"))
|
||||||
|
need_file_size = true;
|
||||||
|
|
||||||
fd = open (argv[2], O_CREAT | O_TRUNC | O_RDWR,
|
fd = open (argv[2], O_CREAT | O_TRUNC | O_RDWR,
|
||||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||||
|
|
||||||
|
@ -272,16 +314,23 @@ main (int argc, char **argv)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* And a further 4 bytes of padding if need_file_size. */
|
||||||
|
if (need_file_size && write (fd, "____", 4) < 4)
|
||||||
|
{
|
||||||
|
perror ("write");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Now iterate through children of INDIR, building the directory
|
/* Now iterate through children of INDIR, building the directory
|
||||||
tree. */
|
tree. */
|
||||||
tree.offset = 5;
|
tree.offset = 5 + (need_file_size ? 4 : 0);
|
||||||
tree.children = NULL;
|
tree.children = NULL;
|
||||||
|
|
||||||
main_1 (indir, &tree);
|
main_1 (indir, &tree);
|
||||||
closedir (indir);
|
closedir (indir);
|
||||||
|
|
||||||
/* Finally, write the directory tree to the output file. */
|
/* Finally, write the directory tree to the output file. */
|
||||||
offset = 5;
|
offset = 5 + (need_file_size ? 4 : 0);
|
||||||
for (; tree.children; tree.children = tree.children->next)
|
for (; tree.children; tree.children = tree.children->next)
|
||||||
main_2 (fd, tree.children, &offset);
|
main_2 (fd, tree.children, &offset);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,17 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Forward declarations. */
|
||||||
|
|
||||||
|
static const char *directory_tree;
|
||||||
|
|
||||||
|
static const char *android_scan_directory_tree (const char *, size_t *);
|
||||||
|
static unsigned int android_extract_long (const char *);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* This file contains an emulation of the Android asset manager API
|
/* This file contains an emulation of the Android asset manager API
|
||||||
used on builds for Android 2.2. It is included by android.c
|
used on builds for Android 2.2. It is included by android.c
|
||||||
whenever appropriate.
|
whenever appropriate.
|
||||||
|
@ -34,6 +45,7 @@ struct android_asset_manager
|
||||||
/* Asset manager class and functions. */
|
/* Asset manager class and functions. */
|
||||||
jclass class;
|
jclass class;
|
||||||
jmethodID open_fd;
|
jmethodID open_fd;
|
||||||
|
jmethodID open;
|
||||||
|
|
||||||
/* Asset file descriptor class and functions. */
|
/* Asset file descriptor class and functions. */
|
||||||
jclass fd_class;
|
jclass fd_class;
|
||||||
|
@ -63,6 +75,9 @@ struct android_asset
|
||||||
/* The asset file descriptor and input stream. */
|
/* The asset file descriptor and input stream. */
|
||||||
jobject fd, stream;
|
jobject fd, stream;
|
||||||
|
|
||||||
|
/* Alternatively, the name of the file. */
|
||||||
|
jstring name;
|
||||||
|
|
||||||
/* The mode. */
|
/* The mode. */
|
||||||
int mode;
|
int mode;
|
||||||
};
|
};
|
||||||
|
@ -98,6 +113,12 @@ AAssetManager_fromJava (JNIEnv *env, jobject java_manager)
|
||||||
= (*env)->GetMethodID (env, manager->class, "openFd",
|
= (*env)->GetMethodID (env, manager->class, "openFd",
|
||||||
"(Ljava/lang/String;)"
|
"(Ljava/lang/String;)"
|
||||||
"Landroid/content/res/AssetFileDescriptor;");
|
"Landroid/content/res/AssetFileDescriptor;");
|
||||||
|
assert (manager->open_fd);
|
||||||
|
|
||||||
|
manager->open
|
||||||
|
= (*env)->GetMethodID (env, manager->class, "open",
|
||||||
|
"(Ljava/lang/String;)"
|
||||||
|
"Ljava/io/InputStream;");
|
||||||
assert (manager->open);
|
assert (manager->open);
|
||||||
|
|
||||||
manager->fd_class
|
manager->fd_class
|
||||||
|
@ -168,6 +189,8 @@ AAssetManager_open (AAssetManager *manager, const char *c_name,
|
||||||
jobject desc;
|
jobject desc;
|
||||||
jstring name;
|
jstring name;
|
||||||
AAsset *asset;
|
AAsset *asset;
|
||||||
|
const char *asset_dir;
|
||||||
|
jlong st_size = -1;
|
||||||
|
|
||||||
/* Push a local frame. */
|
/* Push a local frame. */
|
||||||
asset = NULL;
|
asset = NULL;
|
||||||
|
@ -177,53 +200,86 @@ AAssetManager_open (AAssetManager *manager, const char *c_name,
|
||||||
if ((*(manager->env))->ExceptionCheck (manager->env))
|
if ((*(manager->env))->ExceptionCheck (manager->env))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* Encoding issues can be ignored for now as there are only ASCII
|
/* If the directory tree has been initialized, it is possible to avoid
|
||||||
file names in Emacs. */
|
opening an AssetFileDescriptor and thereby access compressed
|
||||||
|
assets, without sacrificing the possibility of reading the file
|
||||||
|
size. */
|
||||||
|
if (directory_tree)
|
||||||
|
{
|
||||||
|
/* Search for a matching asset. */
|
||||||
|
asset_dir = android_scan_directory_tree (c_name, NULL);
|
||||||
|
if (!asset_dir)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* Extract the size of the asset from this directory. */
|
||||||
|
st_size = android_extract_long (asset_dir - 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encoding issues can be ignored for the time being as there are only
|
||||||
|
ASCII file names in Emacs. */
|
||||||
name = (*(manager->env))->NewStringUTF (manager->env, c_name);
|
name = (*(manager->env))->NewStringUTF (manager->env, c_name);
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* Now try to open an ``AssetFileDescriptor''. */
|
/* If st_size has been set, it ought to be possible to open an input
|
||||||
desc = (*(manager->env))->CallObjectMethod (manager->env,
|
stream directly upon the first attempt to read from the asset,
|
||||||
manager->asset_manager,
|
sidestepping the intermediate AssetFileDescriptor. */
|
||||||
manager->open_fd,
|
|
||||||
name);
|
|
||||||
|
|
||||||
if (!desc)
|
desc = NULL;
|
||||||
goto fail;
|
|
||||||
|
if (st_size < 0)
|
||||||
|
/* Otherwise attempt to open an ``AssetFileDescriptor''. */
|
||||||
|
desc = (*(manager->env))->CallObjectMethod (manager->env,
|
||||||
|
manager->asset_manager,
|
||||||
|
manager->open_fd,
|
||||||
|
name);
|
||||||
|
|
||||||
/* Allocate the asset. */
|
/* Allocate the asset. */
|
||||||
asset = calloc (1, sizeof *asset);
|
asset = calloc (1, sizeof *asset);
|
||||||
|
|
||||||
if (!asset)
|
if (!asset)
|
||||||
{
|
|
||||||
(*(manager->env))->CallVoidMethod (manager->env,
|
|
||||||
desc,
|
|
||||||
manager->close);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pop the local frame and return desc. */
|
|
||||||
desc = (*(manager->env))->NewGlobalRef (manager->env, desc);
|
|
||||||
|
|
||||||
if (!desc)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
if (desc)
|
||||||
|
{
|
||||||
|
/* Pop the local frame and return desc. */
|
||||||
|
desc = (*(manager->env))->NewGlobalRef (manager->env, desc);
|
||||||
|
|
||||||
|
if (!desc)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* Will be released by PopLocalFrame. */
|
||||||
|
name = NULL;
|
||||||
|
}
|
||||||
|
else /* if (name) */
|
||||||
|
{
|
||||||
|
/* Pop the local frame and return name. */
|
||||||
|
name = (*(manager->env))->NewGlobalRef (manager->env, name);
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
(*(manager->env))->PopLocalFrame (manager->env, NULL);
|
(*(manager->env))->PopLocalFrame (manager->env, NULL);
|
||||||
|
|
||||||
asset->manager = manager;
|
asset->manager = manager;
|
||||||
asset->length = -1;
|
asset->length = st_size;
|
||||||
asset->fd = desc;
|
asset->fd = desc;
|
||||||
|
asset->name = name;
|
||||||
asset->mode = mode;
|
asset->mode = mode;
|
||||||
|
|
||||||
return asset;
|
return asset;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
if (desc)
|
||||||
|
(*(manager->env))->CallVoidMethod (manager->env,
|
||||||
|
desc,
|
||||||
|
manager->close);
|
||||||
|
|
||||||
(*(manager->env))->ExceptionClear (manager->env);
|
(*(manager->env))->ExceptionClear (manager->env);
|
||||||
(*(manager->env))->PopLocalFrame (manager->env, NULL);
|
(*(manager->env))->PopLocalFrame (manager->env, NULL);
|
||||||
free (asset);
|
free (asset);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,11 +290,14 @@ AAsset_close (AAsset *asset)
|
||||||
|
|
||||||
env = asset->manager->env;
|
env = asset->manager->env;
|
||||||
|
|
||||||
(*env)->CallVoidMethod (asset->manager->env,
|
if (asset->fd)
|
||||||
asset->fd,
|
{
|
||||||
asset->manager->close);
|
(*env)->CallVoidMethod (asset->manager->env,
|
||||||
(*env)->DeleteGlobalRef (asset->manager->env,
|
asset->fd,
|
||||||
asset->fd);
|
asset->manager->close);
|
||||||
|
(*env)->DeleteGlobalRef (asset->manager->env,
|
||||||
|
asset->fd);
|
||||||
|
}
|
||||||
|
|
||||||
if (asset->stream)
|
if (asset->stream)
|
||||||
{
|
{
|
||||||
|
@ -249,6 +308,10 @@ AAsset_close (AAsset *asset)
|
||||||
asset->stream);
|
asset->stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (asset->name)
|
||||||
|
(*env)->DeleteGlobalRef (asset->manager->env,
|
||||||
|
asset->name);
|
||||||
|
|
||||||
free (asset);
|
free (asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,10 +327,17 @@ android_asset_create_stream (AAsset *asset)
|
||||||
jobject stream;
|
jobject stream;
|
||||||
JNIEnv *env;
|
JNIEnv *env;
|
||||||
|
|
||||||
|
assert (asset->fd || asset->name);
|
||||||
|
|
||||||
env = asset->manager->env;
|
env = asset->manager->env;
|
||||||
stream
|
|
||||||
= (*env)->CallObjectMethod (env, asset->fd,
|
if (asset->name)
|
||||||
asset->manager->create_input_stream);
|
stream = (*env)->CallObjectMethod (env, asset->manager->asset_manager,
|
||||||
|
asset->manager->open, asset->name);
|
||||||
|
else
|
||||||
|
stream
|
||||||
|
= (*env)->CallObjectMethod (env, asset->fd,
|
||||||
|
asset->manager->create_input_stream);
|
||||||
|
|
||||||
if (!stream)
|
if (!stream)
|
||||||
{
|
{
|
||||||
|
@ -380,6 +450,8 @@ AAsset_getLength (AAsset *asset)
|
||||||
|
|
||||||
if (asset->length != -1)
|
if (asset->length != -1)
|
||||||
return asset->length;
|
return asset->length;
|
||||||
|
if (!asset->fd)
|
||||||
|
return 0;
|
||||||
|
|
||||||
env = asset->manager->env;
|
env = asset->manager->env;
|
||||||
asset->length
|
asset->length
|
||||||
|
|
|
@ -46,8 +46,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
#if __ANDROID_API__ >= 9
|
#if __ANDROID_API__ >= 9
|
||||||
#include <android/asset_manager.h>
|
#include <android/asset_manager.h>
|
||||||
#include <android/asset_manager_jni.h>
|
#include <android/asset_manager_jni.h>
|
||||||
|
#define OLD_ANDROID_ASSETS 0
|
||||||
#else /* __ANDROID_API__ < 9 */
|
#else /* __ANDROID_API__ < 9 */
|
||||||
#include "android-asset.h"
|
#include "android-asset.h"
|
||||||
|
#define OLD_ANDROID_ASSETS 1
|
||||||
#endif /* __ANDROID_API__ >= 9 */
|
#endif /* __ANDROID_API__ >= 9 */
|
||||||
|
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
@ -1001,7 +1003,7 @@ static AAssetManager *asset_manager;
|
||||||
/* Read an unaligned (32-bit) long from the address POINTER. */
|
/* Read an unaligned (32-bit) long from the address POINTER. */
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
android_extract_long (char *pointer)
|
android_extract_long (const char *pointer)
|
||||||
{
|
{
|
||||||
unsigned int number;
|
unsigned int number;
|
||||||
|
|
||||||
|
@ -1022,16 +1024,20 @@ android_extract_long (char *pointer)
|
||||||
directory. */
|
directory. */
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
android_scan_directory_tree (char *file, size_t *limit_return)
|
android_scan_directory_tree (const char *file, size_t *limit_return)
|
||||||
{
|
{
|
||||||
char *token, *saveptr, *copy, *start, *max, *limit;
|
char *token, *saveptr, *copy, *start, *max, *limit;
|
||||||
size_t token_length, ntokens, i, len;
|
size_t token_length, ntokens, i, len;
|
||||||
char *tokens[10];
|
char *tokens[20];
|
||||||
|
|
||||||
USE_SAFE_ALLOCA;
|
USE_SAFE_ALLOCA;
|
||||||
|
|
||||||
/* Skip past the 5 byte header. */
|
/* Skip past the 5 or 9 byte header. */
|
||||||
|
#if !OLD_ANDROID_ASSETS
|
||||||
start = (char *) directory_tree + 5;
|
start = (char *) directory_tree + 5;
|
||||||
|
#else /* OLD_ANDROID_ASSETS */
|
||||||
|
start = (char *) directory_tree + 9;
|
||||||
|
#endif /* OLD_ANDROID_ASSETS */
|
||||||
|
|
||||||
/* Figure out the current limit. */
|
/* Figure out the current limit. */
|
||||||
limit = (char *) directory_tree + directory_tree_size;
|
limit = (char *) directory_tree + directory_tree_size;
|
||||||
|
@ -1098,9 +1104,9 @@ android_scan_directory_tree (char *file, size_t *limit_return)
|
||||||
{
|
{
|
||||||
/* They probably match. Find the NULL byte. It must be
|
/* They probably match. Find the NULL byte. It must be
|
||||||
either one byte past start + token_length, with the last
|
either one byte past start + token_length, with the last
|
||||||
byte a trailing slash (indicating that it is a
|
byte a trailing slash (indicating that it is a directory),
|
||||||
directory), or just start + token_length. Return 4 bytes
|
or just start + token_length. Return 4 or 8 bytes past the
|
||||||
past the next NULL byte. */
|
next NULL byte. */
|
||||||
|
|
||||||
max = memchr (start, 0, limit - start);
|
max = memchr (start, 0, limit - start);
|
||||||
|
|
||||||
|
@ -1113,13 +1119,14 @@ android_scan_directory_tree (char *file, size_t *limit_return)
|
||||||
last token. Otherwise, set it as start and the limit as
|
last token. Otherwise, set it as start and the limit as
|
||||||
start + the offset and continue the loop. */
|
start + the offset and continue the loop. */
|
||||||
|
|
||||||
if (max && max + 5 <= limit)
|
if (max && max + (OLD_ANDROID_ASSETS ? 9 : 5) <= limit)
|
||||||
{
|
{
|
||||||
if (i < ntokens - 1)
|
if (i < ntokens - 1)
|
||||||
{
|
{
|
||||||
start = max + 5;
|
start = max + (OLD_ANDROID_ASSETS ? 9 : 5);
|
||||||
limit = ((char *) directory_tree
|
limit = ((char *) directory_tree
|
||||||
+ android_extract_long (max + 1));
|
+ android_extract_long (max + (OLD_ANDROID_ASSETS
|
||||||
|
? 5 : 1)));
|
||||||
|
|
||||||
/* Make sure limit is still in range. */
|
/* Make sure limit is still in range. */
|
||||||
if (limit > directory_tree + directory_tree_size
|
if (limit > directory_tree + directory_tree_size
|
||||||
|
@ -1137,10 +1144,12 @@ android_scan_directory_tree (char *file, size_t *limit_return)
|
||||||
{
|
{
|
||||||
/* Figure out the limit. */
|
/* Figure out the limit. */
|
||||||
if (limit_return)
|
if (limit_return)
|
||||||
*limit_return = android_extract_long (max + 1);
|
*limit_return
|
||||||
|
= android_extract_long (max + (OLD_ANDROID_ASSETS
|
||||||
|
? 5 : 1));
|
||||||
|
|
||||||
/* Go to the end of this file. */
|
/* Go to the end of this file. */
|
||||||
max += 5;
|
max += (OLD_ANDROID_ASSETS ? 9 : 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
SAFE_FREE ();
|
SAFE_FREE ();
|
||||||
|
@ -1161,11 +1170,12 @@ android_scan_directory_tree (char *file, size_t *limit_return)
|
||||||
|
|
||||||
start = memchr (start, 0, limit - start);
|
start = memchr (start, 0, limit - start);
|
||||||
|
|
||||||
if (!start || start + 5 > limit)
|
if (!start || start + (OLD_ANDROID_ASSETS ? 9 : 5) > limit)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
start = ((char *) directory_tree
|
start = ((char *) directory_tree
|
||||||
+ android_extract_long (start + 1));
|
+ android_extract_long (start
|
||||||
|
+ (OLD_ANDROID_ASSETS ? 5 : 1)));
|
||||||
|
|
||||||
/* Make sure start is still in bounds. */
|
/* Make sure start is still in bounds. */
|
||||||
|
|
||||||
|
@ -1192,13 +1202,20 @@ android_is_directory (const char *dir)
|
||||||
{
|
{
|
||||||
/* If the directory is the directory tree, then it is a
|
/* If the directory is the directory tree, then it is a
|
||||||
directory. */
|
directory. */
|
||||||
if (dir == directory_tree + 5)
|
if (dir == directory_tree + (OLD_ANDROID_ASSETS ? 9 : 5))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
#if !OLD_ANDROID_ASSETS
|
||||||
/* Otherwise, look 5 bytes behind. If it is `/', then it is a
|
/* Otherwise, look 5 bytes behind. If it is `/', then it is a
|
||||||
directory. */
|
directory. */
|
||||||
return (dir - 6 >= directory_tree
|
return (dir - 6 >= directory_tree
|
||||||
&& *(dir - 6) == '/');
|
&& *(dir - 6) == '/');
|
||||||
|
#else /* OLD_ANDROID_ASSETS */
|
||||||
|
/* Otherwise, look 9 bytes behind. If it is `/', then it is a
|
||||||
|
directory. */
|
||||||
|
return (dir - 10 >= directory_tree
|
||||||
|
&& *(dir - 10) == '/');
|
||||||
|
#endif /* OLD_ANDROID_ASSETS */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize asset retrieval. ENV should be a JNI environment for
|
/* Initialize asset retrieval. ENV should be a JNI environment for
|
||||||
|
@ -1232,6 +1249,7 @@ android_init_assets (JNIEnv *env, jobject manager)
|
||||||
/* Now figure out how big the directory tree is, and compare the
|
/* Now figure out how big the directory tree is, and compare the
|
||||||
first few bytes. */
|
first few bytes. */
|
||||||
directory_tree_size = AAsset_getLength (asset);
|
directory_tree_size = AAsset_getLength (asset);
|
||||||
|
#if !OLD_ANDROID_ASSETS
|
||||||
if (directory_tree_size < 5
|
if (directory_tree_size < 5
|
||||||
|| memcmp (directory_tree, "EMACS", 5))
|
|| memcmp (directory_tree, "EMACS", 5))
|
||||||
{
|
{
|
||||||
|
@ -1239,6 +1257,15 @@ android_init_assets (JNIEnv *env, jobject manager)
|
||||||
"Directory tree has bad magic");
|
"Directory tree has bad magic");
|
||||||
emacs_abort ();
|
emacs_abort ();
|
||||||
}
|
}
|
||||||
|
#else /* OLD_ANDROID_ASSETS */
|
||||||
|
if (directory_tree_size < 9
|
||||||
|
|| memcmp (directory_tree, "EMACS____", 9))
|
||||||
|
{
|
||||||
|
__android_log_print (ANDROID_LOG_FATAL, __func__,
|
||||||
|
"Directory tree has bad magic");
|
||||||
|
emacs_abort ();
|
||||||
|
}
|
||||||
|
#endif /* OLD_ANDROID_ASSETS */
|
||||||
|
|
||||||
/* Hold a VM reference to the asset manager to prevent the native
|
/* Hold a VM reference to the asset manager to prevent the native
|
||||||
object from being deleted. */
|
object from being deleted. */
|
||||||
|
@ -2287,8 +2314,13 @@ android_afs_readdir (struct android_vdir *vdir)
|
||||||
dirent.d_type = DT_REG;
|
dirent.d_type = DT_REG;
|
||||||
|
|
||||||
/* Forward dir->asset_dir to the file past last. */
|
/* Forward dir->asset_dir to the file past last. */
|
||||||
|
#if !OLD_ANDROID_ASSETS
|
||||||
dir->asset_dir = ((char *) directory_tree
|
dir->asset_dir = ((char *) directory_tree
|
||||||
+ android_extract_long ((char *) last));
|
+ android_extract_long ((char *) last));
|
||||||
|
#else /* OLD_ANDROID_ASSETS */
|
||||||
|
dir->asset_dir = ((char *) directory_tree
|
||||||
|
+ android_extract_long ((char *) last + 4));
|
||||||
|
#endif /* OLD_ANDROID_ASSETS */
|
||||||
|
|
||||||
return &dirent;
|
return &dirent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
#define lread_fd_cmp(n) (fd == (n))
|
#define lread_fd_cmp(n) (fd == (n))
|
||||||
#define lread_fd_p (fd >= 0)
|
#define lread_fd_p (fd >= 0)
|
||||||
#define lread_close emacs_close
|
#define lread_close emacs_close
|
||||||
#define lread_fstat fstat
|
#define lread_fstat sys_fstat
|
||||||
#define lread_read_quit emacs_read_quit
|
#define lread_read_quit emacs_read_quit
|
||||||
#define lread_lseek lseek
|
#define lread_lseek lseek
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue