diff options
| author | Po Lu | 2023-07-27 21:59:58 +0800 |
|---|---|---|
| committer | Po Lu | 2023-07-27 21:59:58 +0800 |
| commit | de0e0939f01a747b8201e06bda5cd50dfa95187f (patch) | |
| tree | 20e23c8b0539169ef9f88a561165e7ae90eecc79 | |
| parent | 4e754817b56c80b1a8c9cf4a9ae811d8217347a4 (diff) | |
| download | emacs-de0e0939f01a747b8201e06bda5cd50dfa95187f.tar.gz emacs-de0e0939f01a747b8201e06bda5cd50dfa95187f.zip | |
Update Android port
* doc/emacs/android.texi (Android Document Providers): Improve
wording of paragraph clarifying limits on subprocesses.
* java/org/gnu/emacs/EmacsService.java (getDocumentTrees): Use
Java standard US-ASCII coding standard instead of the
undocumented ``ASCII'' alias.
(decodeFileName): Remove unused function.
(documentIdFromName):
* src/android.c (android_init_emacs_service): Take a String for
NAME instead of a byte array.
* src/androidvfs.c (android_verify_jni_string): New function.
(android_document_id_from_name): Verify that STRING is a valid
Modified UTF-8 string.
| -rw-r--r-- | doc/emacs/android.texi | 11 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsService.java | 34 | ||||
| -rw-r--r-- | src/android.c | 3 | ||||
| -rw-r--r-- | src/androidvfs.c | 75 |
4 files changed, 85 insertions, 38 deletions
diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index 1f32fdfc1d2..b86c71cea49 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi | |||
| @@ -298,11 +298,12 @@ subsequently made available within a new directory named | |||
| 298 | a unique identifier assigned to the directory by the document | 298 | a unique identifier assigned to the directory by the document |
| 299 | provider. | 299 | provider. |
| 300 | 300 | ||
| 301 | Because these directories do not exist within the Unix file-system, | 301 | The same limitations applied to the @file{/assets} directory |
| 302 | sub-processes cannot be created within them, just as with the | 302 | (@pxref{Android File System}) are applied when creating sub-processes |
| 303 | @file{/assets} directory (@pxref{Android File System}.) In addition, | 303 | within those directories, because they do not exist within the Unix |
| 304 | although Emacs can normally write and create files inside these | 304 | file-system. In addition, although Emacs can normally write and |
| 305 | directories, it cannot create symlinks or hard links. | 305 | create files inside these directories, it cannot create symlinks or |
| 306 | hard links. | ||
| 306 | 307 | ||
| 307 | @c TODO: fix this! | 308 | @c TODO: fix this! |
| 308 | Since document providers are allowed to perform expensive network | 309 | Since document providers are allowed to perform expensive network |
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java index 6059439551f..bc62e050345 100644 --- a/java/org/gnu/emacs/EmacsService.java +++ b/java/org/gnu/emacs/EmacsService.java | |||
| @@ -1282,7 +1282,7 @@ public final class EmacsService extends Service | |||
| 1282 | 1282 | ||
| 1283 | try | 1283 | try |
| 1284 | { | 1284 | { |
| 1285 | providerName = new String (provider, "ASCII"); | 1285 | providerName = new String (provider, "US-ASCII"); |
| 1286 | } | 1286 | } |
| 1287 | catch (UnsupportedEncodingException exception) | 1287 | catch (UnsupportedEncodingException exception) |
| 1288 | { | 1288 | { |
| @@ -1306,24 +1306,6 @@ public final class EmacsService extends Service | |||
| 1306 | return treeList.toArray (new String[0]); | 1306 | return treeList.toArray (new String[0]); |
| 1307 | } | 1307 | } |
| 1308 | 1308 | ||
| 1309 | /* Decode the specified STRING into a String object using the UTF-8 | ||
| 1310 | format. If an exception is thrown, return null. */ | ||
| 1311 | |||
| 1312 | private String | ||
| 1313 | decodeFileName (byte[] string) | ||
| 1314 | { | ||
| 1315 | try | ||
| 1316 | { | ||
| 1317 | return new String (string, "UTF-8"); | ||
| 1318 | } | ||
| 1319 | catch (Exception e) /* UnsupportedEncodingException, etc. */ | ||
| 1320 | { | ||
| 1321 | ;; | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | return null; | ||
| 1325 | } | ||
| 1326 | |||
| 1327 | /* Find the document ID of the file within TREE_URI designated by | 1309 | /* Find the document ID of the file within TREE_URI designated by |
| 1328 | NAME. | 1310 | NAME. |
| 1329 | 1311 | ||
| @@ -1342,11 +1324,10 @@ public final class EmacsService extends Service | |||
| 1342 | If the designated file can't be located, return -1. */ | 1324 | If the designated file can't be located, return -1. */ |
| 1343 | 1325 | ||
| 1344 | private int | 1326 | private int |
| 1345 | documentIdFromName (String tree_uri, byte name[], | 1327 | documentIdFromName (String tree_uri, String name, String[] id_return) |
| 1346 | String[] id_return) | ||
| 1347 | { | 1328 | { |
| 1348 | Uri uri, treeUri; | 1329 | Uri uri, treeUri; |
| 1349 | String nameString, id, type; | 1330 | String id, type; |
| 1350 | String[] components, projection; | 1331 | String[] components, projection; |
| 1351 | Cursor cursor; | 1332 | Cursor cursor; |
| 1352 | int column; | 1333 | int column; |
| @@ -1360,11 +1341,8 @@ public final class EmacsService extends Service | |||
| 1360 | /* Parse the URI identifying the tree first. */ | 1341 | /* Parse the URI identifying the tree first. */ |
| 1361 | uri = Uri.parse (tree_uri); | 1342 | uri = Uri.parse (tree_uri); |
| 1362 | 1343 | ||
| 1363 | /* Next, decode NAME. */ | ||
| 1364 | nameString = decodeFileName (name); | ||
| 1365 | |||
| 1366 | /* Now, split NAME into its individual components. */ | 1344 | /* Now, split NAME into its individual components. */ |
| 1367 | components = nameString.split ("/"); | 1345 | components = name.split ("/"); |
| 1368 | 1346 | ||
| 1369 | /* Set id and type to the value at the root of the tree. */ | 1347 | /* Set id and type to the value at the root of the tree. */ |
| 1370 | type = id = null; | 1348 | type = id = null; |
| @@ -1462,7 +1440,7 @@ public final class EmacsService extends Service | |||
| 1462 | 1440 | ||
| 1463 | try | 1441 | try |
| 1464 | { | 1442 | { |
| 1465 | nameString = cursor.getString (column); | 1443 | name = cursor.getString (column); |
| 1466 | } | 1444 | } |
| 1467 | catch (Exception exception) | 1445 | catch (Exception exception) |
| 1468 | { | 1446 | { |
| @@ -1473,7 +1451,7 @@ public final class EmacsService extends Service | |||
| 1473 | /* Break out of the loop only once a matching component is | 1451 | /* Break out of the loop only once a matching component is |
| 1474 | found. */ | 1452 | found. */ |
| 1475 | 1453 | ||
| 1476 | if (nameString.equals (component)) | 1454 | if (name.equals (component)) |
| 1477 | break; | 1455 | break; |
| 1478 | } | 1456 | } |
| 1479 | 1457 | ||
diff --git a/src/android.c b/src/android.c index d8b264a8491..098fa6c383d 100644 --- a/src/android.c +++ b/src/android.c | |||
| @@ -1556,7 +1556,8 @@ android_init_emacs_service (void) | |||
| 1556 | FIND_METHOD (get_document_trees, "getDocumentTrees", | 1556 | FIND_METHOD (get_document_trees, "getDocumentTrees", |
| 1557 | "([B)[Ljava/lang/String;"); | 1557 | "([B)[Ljava/lang/String;"); |
| 1558 | FIND_METHOD (document_id_from_name, "documentIdFromName", | 1558 | FIND_METHOD (document_id_from_name, "documentIdFromName", |
| 1559 | "(Ljava/lang/String;[B[Ljava/lang/String;)I"); | 1559 | "(Ljava/lang/String;Ljava/lang/String;" |
| 1560 | "[Ljava/lang/String;)I"); | ||
| 1560 | FIND_METHOD (get_tree_uri, "getTreeUri", | 1561 | FIND_METHOD (get_tree_uri, "getTreeUri", |
| 1561 | "(Ljava/lang/String;Ljava/lang/String;)" | 1562 | "(Ljava/lang/String;Ljava/lang/String;)" |
| 1562 | "Ljava/lang/String;"); | 1563 | "Ljava/lang/String;"); |
diff --git a/src/androidvfs.c b/src/androidvfs.c index bab3977ed5a..c174c35f02b 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c | |||
| @@ -3936,6 +3936,66 @@ static struct android_vops saf_new_vfs_ops; | |||
| 3936 | /* Chain of all open SAF directory streams. */ | 3936 | /* Chain of all open SAF directory streams. */ |
| 3937 | static struct android_saf_tree_vdir *all_saf_tree_vdirs; | 3937 | static struct android_saf_tree_vdir *all_saf_tree_vdirs; |
| 3938 | 3938 | ||
| 3939 | /* Verify that the specified NULL-terminated STRING is a valid JNI | ||
| 3940 | ``UTF-8'' string. Return 0 if so, 1 otherwise. | ||
| 3941 | |||
| 3942 | The native coding system used by the JVM to store strings derives | ||
| 3943 | from UTF-8, but deviates from it in two aspects in an attempt to | ||
| 3944 | better represent the UCS-16 based Java String format, and to let | ||
| 3945 | strings contain NULL characters while remaining valid C strings: | ||
| 3946 | NULL bytes are encoded as two-byte sequences, and Unicode surrogate | ||
| 3947 | pairs encoded as two-byte sequences are prefered to four-byte | ||
| 3948 | sequences when encoding characters above the BMP. */ | ||
| 3949 | |||
| 3950 | static int | ||
| 3951 | android_verify_jni_string (const char *name) | ||
| 3952 | { | ||
| 3953 | const unsigned char *chars; | ||
| 3954 | |||
| 3955 | chars = (unsigned char *) name; | ||
| 3956 | while (*chars) | ||
| 3957 | { | ||
| 3958 | /* Switch on the high 4 bits. */ | ||
| 3959 | |||
| 3960 | switch (*chars++ >> 4) | ||
| 3961 | { | ||
| 3962 | case 0 ... 7: | ||
| 3963 | /* The 8th bit is clean, so this is a regular C | ||
| 3964 | character. */ | ||
| 3965 | break; | ||
| 3966 | |||
| 3967 | case 8 ... 0xb: | ||
| 3968 | /* Invalid starting byte! */ | ||
| 3969 | return 1; | ||
| 3970 | |||
| 3971 | case 0xf: | ||
| 3972 | /* The start of a four byte sequence. These aren't allowed | ||
| 3973 | in Java. */ | ||
| 3974 | return 1; | ||
| 3975 | |||
| 3976 | case 0xe: | ||
| 3977 | /* The start of a three byte sequence. Verify that its | ||
| 3978 | continued. */ | ||
| 3979 | |||
| 3980 | if ((*chars++ & 0xc0) != 0x80) | ||
| 3981 | return 1; | ||
| 3982 | |||
| 3983 | FALLTHROUGH; | ||
| 3984 | |||
| 3985 | case 0xc ... 0xd: | ||
| 3986 | /* The start of a two byte sequence. Verify that the | ||
| 3987 | next byte exists and has its high bit set. */ | ||
| 3988 | |||
| 3989 | if ((*chars++ & 0xc0) != 0x80) | ||
| 3990 | return 1; | ||
| 3991 | |||
| 3992 | break; | ||
| 3993 | } | ||
| 3994 | } | ||
| 3995 | |||
| 3996 | return 0; | ||
| 3997 | } | ||
| 3998 | |||
| 3939 | /* Find the document ID of the file within TREE_URI designated by | 3999 | /* Find the document ID of the file within TREE_URI designated by |
| 3940 | NAME. | 4000 | NAME. |
| 3941 | 4001 | ||
| @@ -3943,6 +4003,9 @@ static struct android_saf_tree_vdir *all_saf_tree_vdirs; | |||
| 3943 | individual files. Each constituent component prior to the last | 4003 | individual files. Each constituent component prior to the last |
| 3944 | must name a directory file within TREE_URI. | 4004 | must name a directory file within TREE_URI. |
| 3945 | 4005 | ||
| 4006 | If NAME is not correct for the Java ``modified UTF-8'' coding | ||
| 4007 | system, return -1. | ||
| 4008 | |||
| 3946 | Upon success, return 0 or 1 (contingent upon whether or not the | 4009 | Upon success, return 0 or 1 (contingent upon whether or not the |
| 3947 | last component within NAME is a directory) and place the document | 4010 | last component within NAME is a directory) and place the document |
| 3948 | ID of the named file in ID. | 4011 | ID of the named file in ID. |
| @@ -3965,6 +4028,12 @@ android_document_id_from_name (const char *tree_uri, char *name, | |||
| 3965 | jmethodID method; | 4028 | jmethodID method; |
| 3966 | const char *doc_id; | 4029 | const char *doc_id; |
| 3967 | 4030 | ||
| 4031 | /* Verify the format of NAME. Don't allow creating files that | ||
| 4032 | contain characters that can't be encoded in Java. */ | ||
| 4033 | |||
| 4034 | if (android_verify_jni_string (name)) | ||
| 4035 | return -1; | ||
| 4036 | |||
| 3968 | /* First, create the array that will hold the result. */ | 4037 | /* First, create the array that will hold the result. */ |
| 3969 | result = (*android_java_env)->NewObjectArray (android_java_env, 1, | 4038 | result = (*android_java_env)->NewObjectArray (android_java_env, 1, |
| 3970 | java_string_class, | 4039 | java_string_class, |
| @@ -3972,11 +4041,9 @@ android_document_id_from_name (const char *tree_uri, char *name, | |||
| 3972 | android_exception_check (); | 4041 | android_exception_check (); |
| 3973 | 4042 | ||
| 3974 | /* Next, create the string for the tree URI and name. */ | 4043 | /* Next, create the string for the tree URI and name. */ |
| 3975 | length = strlen (name); | 4044 | java_name = (*android_java_env)->NewStringUTF (android_java_env, |
| 3976 | java_name = (*android_java_env)->NewByteArray (android_java_env, length); | 4045 | name); |
| 3977 | android_exception_check_1 (result); | 4046 | android_exception_check_1 (result); |
| 3978 | (*android_java_env)->SetByteArrayRegion (android_java_env, java_name, | ||
| 3979 | 0, length, (jbyte *) name); | ||
| 3980 | uri = (*android_java_env)->NewStringUTF (android_java_env, tree_uri); | 4047 | uri = (*android_java_env)->NewStringUTF (android_java_env, tree_uri); |
| 3981 | android_exception_check_2 (result, java_name); | 4048 | android_exception_check_2 (result, java_name); |
| 3982 | 4049 | ||