diff options
| author | Po Lu | 2024-03-23 15:37:43 +0800 |
|---|---|---|
| committer | Po Lu | 2024-03-23 15:37:43 +0800 |
| commit | e39cb515a108682b520e499c334a600ee634fbf6 (patch) | |
| tree | dd246df15bd19360d665a6a85a5df470d783ef49 /src | |
| parent | 7e32e8392ab77f9df08a1f11831cbba2242d721f (diff) | |
| download | emacs-e39cb515a108682b520e499c334a600ee634fbf6.tar.gz emacs-e39cb515a108682b520e499c334a600ee634fbf6.zip | |
Correctly handle non-BMP characters in Android content file names
* lisp/term/android-win.el (android-encode-jni)
(android-decode-jni, android-jni): New coding system, for
Android file names and runtime data.
* src/androidterm.h (syms_of_androidvfs): New function.
* src/androidvfs.c (struct android_special_vnode): New field
special_coding_system.
(android_saf_tree_readdir): Decode the file name using the
android-jni coding system.
(special_vnodes): <contents>: Specify a file name coding system.
(android_vfs_convert_name): New function.
(android_root_name): If a special coding system be specified for
a special vnode, convert components to it before invoking its
name function.
(syms_of_androidvfs): New symbol Qandroid_jni.
* src/emacs.c (android_emacs_init): Call syms_of_androidvfs.
Diffstat (limited to 'src')
| -rw-r--r-- | src/androidterm.h | 5 | ||||
| -rw-r--r-- | src/androidvfs.c | 137 | ||||
| -rw-r--r-- | src/emacs.c | 1 |
3 files changed, 126 insertions, 17 deletions
diff --git a/src/androidterm.h b/src/androidterm.h index ca6929bef0e..fd4cc99f641 100644 --- a/src/androidterm.h +++ b/src/androidterm.h | |||
| @@ -461,7 +461,7 @@ extern void sfntfont_android_shrink_scanline_buffer (void); | |||
| 461 | extern void init_sfntfont_android (void); | 461 | extern void init_sfntfont_android (void); |
| 462 | extern void syms_of_sfntfont_android (void); | 462 | extern void syms_of_sfntfont_android (void); |
| 463 | 463 | ||
| 464 | /* Defined in androidselect.c */ | 464 | /* Defined in androidselect.c. */ |
| 465 | 465 | ||
| 466 | #ifndef ANDROID_STUBIFY | 466 | #ifndef ANDROID_STUBIFY |
| 467 | 467 | ||
| @@ -473,6 +473,9 @@ extern void android_notification_action (struct android_notification_event *, | |||
| 473 | extern void init_androidselect (void); | 473 | extern void init_androidselect (void); |
| 474 | extern void syms_of_androidselect (void); | 474 | extern void syms_of_androidselect (void); |
| 475 | 475 | ||
| 476 | /* Defined in androidvfs.c. */ | ||
| 477 | extern void syms_of_androidvfs (void); | ||
| 478 | |||
| 476 | #endif | 479 | #endif |
| 477 | 480 | ||
| 478 | 481 | ||
diff --git a/src/androidvfs.c b/src/androidvfs.c index 9e3d5cab8cf..6a9ddb33c56 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c | |||
| @@ -38,8 +38,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 38 | #include <linux/ashmem.h> | 38 | #include <linux/ashmem.h> |
| 39 | 39 | ||
| 40 | #include "android.h" | 40 | #include "android.h" |
| 41 | #include "androidterm.h" | ||
| 41 | #include "systime.h" | 42 | #include "systime.h" |
| 42 | #include "blockinput.h" | 43 | #include "blockinput.h" |
| 44 | #include "coding.h" | ||
| 43 | 45 | ||
| 44 | #if __ANDROID_API__ >= 9 | 46 | #if __ANDROID_API__ >= 9 |
| 45 | #include <android/asset_manager.h> | 47 | #include <android/asset_manager.h> |
| @@ -248,8 +250,14 @@ struct android_special_vnode | |||
| 248 | /* Function called to create the initial vnode from the rest of the | 250 | /* Function called to create the initial vnode from the rest of the |
| 249 | component. */ | 251 | component. */ |
| 250 | struct android_vnode *(*initial) (char *, size_t); | 252 | struct android_vnode *(*initial) (char *, size_t); |
| 253 | |||
| 254 | /* If non-nil, an encoding system into which file name buffers are to | ||
| 255 | be re-encoded before being handed to VFS functions. */ | ||
| 256 | Lisp_Object special_coding_system; | ||
| 251 | }; | 257 | }; |
| 252 | 258 | ||
| 259 | verify (NIL_IS_ZERO); /* special_coding_system above. */ | ||
| 260 | |||
| 253 | enum android_vnode_type | 261 | enum android_vnode_type |
| 254 | { | 262 | { |
| 255 | ANDROID_VNODE_UNIX, | 263 | ANDROID_VNODE_UNIX, |
| @@ -3867,7 +3875,8 @@ android_saf_root_readdir (struct android_vdir *vdir) | |||
| 3867 | NULL); | 3875 | NULL); |
| 3868 | android_exception_check_nonnull ((void *) chars, string); | 3876 | android_exception_check_nonnull ((void *) chars, string); |
| 3869 | 3877 | ||
| 3870 | /* Figure out how large it is, and then resize dirent to fit. */ | 3878 | /* Figure out how large it is, and then resize dirent to fit--this |
| 3879 | string is always ASCII. */ | ||
| 3871 | length = strlen (chars) + 1; | 3880 | length = strlen (chars) + 1; |
| 3872 | size = offsetof (struct dirent, d_name) + length; | 3881 | size = offsetof (struct dirent, d_name) + length; |
| 3873 | dirent = xrealloc (dirent, size); | 3882 | dirent = xrealloc (dirent, size); |
| @@ -5479,6 +5488,7 @@ android_saf_tree_readdir (struct android_vdir *vdir) | |||
| 5479 | jmethodID method; | 5488 | jmethodID method; |
| 5480 | size_t length, size; | 5489 | size_t length, size; |
| 5481 | const char *chars; | 5490 | const char *chars; |
| 5491 | struct coding_system coding; | ||
| 5482 | 5492 | ||
| 5483 | dir = (struct android_saf_tree_vdir *) vdir; | 5493 | dir = (struct android_saf_tree_vdir *) vdir; |
| 5484 | 5494 | ||
| @@ -5526,9 +5536,25 @@ android_saf_tree_readdir (struct android_vdir *vdir) | |||
| 5526 | NULL); | 5536 | NULL); |
| 5527 | android_exception_check_nonnull ((void *) chars, d_name); | 5537 | android_exception_check_nonnull ((void *) chars, d_name); |
| 5528 | 5538 | ||
| 5529 | /* Figure out how large it is, and then resize dirent to fit. */ | 5539 | /* Decode this JNI string into utf-8-emacs; see |
| 5540 | android_vfs_convert_name for considerations regarding coding | ||
| 5541 | systems. */ | ||
| 5542 | length = strlen (chars); | ||
| 5543 | setup_coding_system (Qandroid_jni, &coding); | ||
| 5544 | coding.mode |= CODING_MODE_LAST_BLOCK; | ||
| 5545 | coding.source = (const unsigned char *) chars; | ||
| 5546 | coding.dst_bytes = 0; | ||
| 5547 | coding.destination = NULL; | ||
| 5548 | decode_coding_object (&coding, Qnil, 0, 0, length, length, Qnil); | ||
| 5549 | |||
| 5550 | /* Release the string data and the local reference to STRING. */ | ||
| 5551 | (*android_java_env)->ReleaseStringUTFChars (android_java_env, | ||
| 5552 | (jstring) d_name, | ||
| 5553 | chars); | ||
| 5554 | |||
| 5555 | /* Resize dirent to accommodate the decoded text. */ | ||
| 5530 | length = strlen (chars) + 1; | 5556 | length = strlen (chars) + 1; |
| 5531 | size = offsetof (struct dirent, d_name) + length; | 5557 | size = offsetof (struct dirent, d_name) + 1 + coding.produced; |
| 5532 | dirent = xrealloc (dirent, size); | 5558 | dirent = xrealloc (dirent, size); |
| 5533 | 5559 | ||
| 5534 | /* Clear dirent. */ | 5560 | /* Clear dirent. */ |
| @@ -5540,12 +5566,12 @@ android_saf_tree_readdir (struct android_vdir *vdir) | |||
| 5540 | dirent->d_off = 0; | 5566 | dirent->d_off = 0; |
| 5541 | dirent->d_reclen = size; | 5567 | dirent->d_reclen = size; |
| 5542 | dirent->d_type = d_type ? DT_DIR : DT_UNKNOWN; | 5568 | dirent->d_type = d_type ? DT_DIR : DT_UNKNOWN; |
| 5543 | strcpy (dirent->d_name, chars); | 5569 | memcpy (dirent->d_name, coding.destination, coding.produced); |
| 5570 | dirent->d_name[coding.produced] = '\0'; | ||
| 5571 | |||
| 5572 | /* Free the coding system destination buffer. */ | ||
| 5573 | xfree (coding.destination); | ||
| 5544 | 5574 | ||
| 5545 | /* Release the string data and the local reference to STRING. */ | ||
| 5546 | (*android_java_env)->ReleaseStringUTFChars (android_java_env, | ||
| 5547 | (jstring) d_name, | ||
| 5548 | chars); | ||
| 5549 | ANDROID_DELETE_LOCAL_REF (d_name); | 5575 | ANDROID_DELETE_LOCAL_REF (d_name); |
| 5550 | return dirent; | 5576 | return dirent; |
| 5551 | } | 5577 | } |
| @@ -6531,9 +6557,35 @@ static struct android_vops root_vfs_ops = | |||
| 6531 | static struct android_special_vnode special_vnodes[] = | 6557 | static struct android_special_vnode special_vnodes[] = |
| 6532 | { | 6558 | { |
| 6533 | { "assets", 6, android_afs_initial, }, | 6559 | { "assets", 6, android_afs_initial, }, |
| 6534 | { "content", 7, android_content_initial, }, | 6560 | { "content", 7, android_content_initial, |
| 6561 | LISPSYM_INITIALLY (Qandroid_jni), }, | ||
| 6535 | }; | 6562 | }; |
| 6536 | 6563 | ||
| 6564 | /* Convert the file name NAME from Emacs's internal character encoding | ||
| 6565 | to CODING, and return a Lisp string with the data so produced. | ||
| 6566 | |||
| 6567 | Calling this function creates an implicit assumption that | ||
| 6568 | file-name-coding-system is compatible with utf-8-emacs, which is not | ||
| 6569 | unacceptable as users with cause to modify file-name-coding-system | ||
| 6570 | should be aware and prepared for consequences towards files stored on | ||
| 6571 | different filesystems, including virtual ones. */ | ||
| 6572 | |||
| 6573 | static Lisp_Object | ||
| 6574 | android_vfs_convert_name (const char *name, Lisp_Object coding) | ||
| 6575 | { | ||
| 6576 | Lisp_Object src_coding, name1; | ||
| 6577 | |||
| 6578 | src_coding = Qutf_8_emacs; | ||
| 6579 | |||
| 6580 | /* Convert the contents of the buffer after BUFFER_END | ||
| 6581 | from the file name coding system to | ||
| 6582 | special->special_coding_system. */ | ||
| 6583 | AUTO_STRING (file_name, name); | ||
| 6584 | name1 = code_convert_string_norecord (file_name, src_coding, false); | ||
| 6585 | name1 = code_convert_string (name1, coding, Qt, true, true, true); | ||
| 6586 | return name1; | ||
| 6587 | } | ||
| 6588 | |||
| 6537 | static struct android_vnode * | 6589 | static struct android_vnode * |
| 6538 | android_root_name (struct android_vnode *vnode, char *name, | 6590 | android_root_name (struct android_vnode *vnode, char *name, |
| 6539 | size_t length) | 6591 | size_t length) |
| @@ -6541,6 +6593,8 @@ android_root_name (struct android_vnode *vnode, char *name, | |||
| 6541 | char *component_end; | 6593 | char *component_end; |
| 6542 | struct android_special_vnode *special; | 6594 | struct android_special_vnode *special; |
| 6543 | size_t i; | 6595 | size_t i; |
| 6596 | Lisp_Object file_name; | ||
| 6597 | struct android_vnode *vp; | ||
| 6544 | 6598 | ||
| 6545 | /* Skip any leading separator in NAME. */ | 6599 | /* Skip any leading separator in NAME. */ |
| 6546 | 6600 | ||
| @@ -6567,8 +6621,29 @@ android_root_name (struct android_vnode *vnode, char *name, | |||
| 6567 | 6621 | ||
| 6568 | if (component_end - name == special->length | 6622 | if (component_end - name == special->length |
| 6569 | && !memcmp (special->name, name, special->length)) | 6623 | && !memcmp (special->name, name, special->length)) |
| 6570 | return (*special->initial) (component_end, | 6624 | { |
| 6571 | length - special->length); | 6625 | if (!NILP (special->special_coding_system)) |
| 6626 | { | ||
| 6627 | USE_SAFE_ALLOCA; | ||
| 6628 | |||
| 6629 | file_name | ||
| 6630 | = android_vfs_convert_name (component_end, | ||
| 6631 | special->special_coding_system); | ||
| 6632 | |||
| 6633 | /* Allocate a buffer and copy file_name into the same. */ | ||
| 6634 | length = SBYTES (file_name) + 1; | ||
| 6635 | name = SAFE_ALLOCA (length + 1); | ||
| 6636 | |||
| 6637 | /* Copy the trailing NULL byte also. */ | ||
| 6638 | memcpy (name, SDATA (file_name), length); | ||
| 6639 | vp = (*special->initial) (name, length - 1); | ||
| 6640 | SAFE_FREE (); | ||
| 6641 | return vp; | ||
| 6642 | } | ||
| 6643 | |||
| 6644 | return (*special->initial) (component_end, | ||
| 6645 | length - special->length); | ||
| 6646 | } | ||
| 6572 | 6647 | ||
| 6573 | /* Detect the case where a special is named with a trailing | 6648 | /* Detect the case where a special is named with a trailing |
| 6574 | directory separator. */ | 6649 | directory separator. */ |
| @@ -6576,9 +6651,30 @@ android_root_name (struct android_vnode *vnode, char *name, | |||
| 6576 | if (component_end - name == special->length + 1 | 6651 | if (component_end - name == special->length + 1 |
| 6577 | && !memcmp (special->name, name, special->length) | 6652 | && !memcmp (special->name, name, special->length) |
| 6578 | && name[special->length] == '/') | 6653 | && name[special->length] == '/') |
| 6579 | /* Make sure to include the directory separator. */ | 6654 | { |
| 6580 | return (*special->initial) (component_end - 1, | 6655 | if (!NILP (special->special_coding_system)) |
| 6581 | length - special->length); | 6656 | { |
| 6657 | USE_SAFE_ALLOCA; | ||
| 6658 | |||
| 6659 | file_name | ||
| 6660 | = android_vfs_convert_name (component_end - 1, | ||
| 6661 | special->special_coding_system); | ||
| 6662 | |||
| 6663 | /* Allocate a buffer and copy file_name into the same. */ | ||
| 6664 | length = SBYTES (file_name) + 1; | ||
| 6665 | name = SAFE_ALLOCA (length + 1); | ||
| 6666 | |||
| 6667 | /* Copy the trailing NULL byte also. */ | ||
| 6668 | memcpy (name, SDATA (file_name), length); | ||
| 6669 | vp = (*special->initial) (name, length - 1); | ||
| 6670 | SAFE_FREE (); | ||
| 6671 | return vp; | ||
| 6672 | } | ||
| 6673 | |||
| 6674 | /* Make sure to include the directory separator. */ | ||
| 6675 | return (*special->initial) (component_end - 1, | ||
| 6676 | length - special->length); | ||
| 6677 | } | ||
| 6582 | } | 6678 | } |
| 6583 | 6679 | ||
| 6584 | /* Otherwise, continue searching for a vnode normally. */ | 6680 | /* Otherwise, continue searching for a vnode normally. */ |
| @@ -6589,8 +6685,9 @@ android_root_name (struct android_vnode *vnode, char *name, | |||
| 6589 | 6685 | ||
| 6590 | /* File system lookup. */ | 6686 | /* File system lookup. */ |
| 6591 | 6687 | ||
| 6592 | /* Look up the vnode that designates NAME, a file name that is at | 6688 | /* Look up the vnode that designates NAME, a file name that is at least |
| 6593 | least N bytes. | 6689 | N bytes, converting between different file name coding systems as |
| 6690 | necessary. | ||
| 6594 | 6691 | ||
| 6595 | NAME may be either an absolute file name or a name relative to the | 6692 | NAME may be either an absolute file name or a name relative to the |
| 6596 | current working directory. It must not be longer than EMACS_PATH_MAX | 6693 | current working directory. It must not be longer than EMACS_PATH_MAX |
| @@ -7605,3 +7702,11 @@ android_closedir (struct android_vdir *dirp) | |||
| 7605 | { | 7702 | { |
| 7606 | return (*dirp->closedir) (dirp); | 7703 | return (*dirp->closedir) (dirp); |
| 7607 | } | 7704 | } |
| 7705 | |||
| 7706 | |||
| 7707 | |||
| 7708 | void | ||
| 7709 | syms_of_androidvfs (void) | ||
| 7710 | { | ||
| 7711 | DEFSYM (Qandroid_jni, "android-jni"); | ||
| 7712 | } | ||
diff --git a/src/emacs.c b/src/emacs.c index f4bfb9a6bbd..87f12d3fa86 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -2444,6 +2444,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 2444 | #if !defined ANDROID_STUBIFY | 2444 | #if !defined ANDROID_STUBIFY |
| 2445 | syms_of_androidfont (); | 2445 | syms_of_androidfont (); |
| 2446 | syms_of_androidselect (); | 2446 | syms_of_androidselect (); |
| 2447 | syms_of_androidvfs (); | ||
| 2447 | syms_of_sfntfont (); | 2448 | syms_of_sfntfont (); |
| 2448 | syms_of_sfntfont_android (); | 2449 | syms_of_sfntfont_android (); |
| 2449 | #endif /* !ANDROID_STUBIFY */ | 2450 | #endif /* !ANDROID_STUBIFY */ |