aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2024-03-23 15:37:43 +0800
committerPo Lu2024-03-23 15:37:43 +0800
commite39cb515a108682b520e499c334a600ee634fbf6 (patch)
treedd246df15bd19360d665a6a85a5df470d783ef49 /src
parent7e32e8392ab77f9df08a1f11831cbba2242d721f (diff)
downloademacs-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.h5
-rw-r--r--src/androidvfs.c137
-rw-r--r--src/emacs.c1
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);
461extern void init_sfntfont_android (void); 461extern void init_sfntfont_android (void);
462extern void syms_of_sfntfont_android (void); 462extern 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 *,
473extern void init_androidselect (void); 473extern void init_androidselect (void);
474extern void syms_of_androidselect (void); 474extern void syms_of_androidselect (void);
475 475
476/* Defined in androidvfs.c. */
477extern 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
259verify (NIL_IS_ZERO); /* special_coding_system above. */
260
253enum android_vnode_type 261enum 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 =
6531static struct android_special_vnode special_vnodes[] = 6557static 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
6573static Lisp_Object
6574android_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
6537static struct android_vnode * 6589static struct android_vnode *
6538android_root_name (struct android_vnode *vnode, char *name, 6590android_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
7708void
7709syms_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 */