1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "core_jni_helpers.h"
18 #include "nativehelper/scoped_primitive_array.h"
19
20 namespace android {
21
android_util_CharsetUtils_toModifiedUtf8Bytes(JNIEnv * env,jobject clazz,jstring src,jint srcLen,jlong dest,jint destOff,jint destLen)22 static jint android_util_CharsetUtils_toModifiedUtf8Bytes(JNIEnv *env, jobject clazz,
23 jstring src, jint srcLen, jlong dest, jint destOff, jint destLen) {
24 char *destPtr = reinterpret_cast<char*>(dest);
25
26 // Quickly check if destination has plenty of room for worst-case
27 // 4-bytes-per-char encoded size
28 const size_t worstLen = (srcLen * 4);
29 if (destOff >= 0 && destOff + worstLen < destLen) {
30 env->GetStringUTFRegion(src, 0, srcLen, destPtr + destOff);
31 return strlen(destPtr + destOff + srcLen) + srcLen;
32 }
33
34 // String still might fit in destination, but we need to measure
35 // its actual encoded size to be sure
36 const size_t encodedLen = env->GetStringUTFLength(src);
37 if (destOff >= 0 && destOff + encodedLen < destLen) {
38 env->GetStringUTFRegion(src, 0, srcLen, destPtr + destOff);
39 return encodedLen;
40 }
41
42 return -encodedLen;
43 }
44
android_util_CharsetUtils_fromModifiedUtf8Bytes(JNIEnv * env,jobject clazz,jlong src,jint srcOff,jint srcLen)45 static jstring android_util_CharsetUtils_fromModifiedUtf8Bytes(JNIEnv *env, jobject clazz,
46 jlong src, jint srcOff, jint srcLen) {
47 char *srcPtr = reinterpret_cast<char*>(src);
48
49 // This is funky, but we need to temporarily swap a null byte so that
50 // JNI knows where the string ends; we'll put it back, we promise
51 char tmp = srcPtr[srcOff + srcLen];
52 srcPtr[srcOff + srcLen] = '\0';
53 jstring res = env->NewStringUTF(srcPtr + srcOff);
54 srcPtr[srcOff + srcLen] = tmp;
55 return res;
56 }
57
58 static const JNINativeMethod methods[] = {
59 // @FastNative
60 {"toModifiedUtf8Bytes", "(Ljava/lang/String;IJII)I",
61 (void*)android_util_CharsetUtils_toModifiedUtf8Bytes},
62 // @FastNative
63 {"fromModifiedUtf8Bytes", "(JII)Ljava/lang/String;",
64 (void*)android_util_CharsetUtils_fromModifiedUtf8Bytes},
65 };
66
register_android_util_CharsetUtils(JNIEnv * env)67 int register_android_util_CharsetUtils(JNIEnv *env) {
68 return RegisterMethodsOrDie(env, "android/util/CharsetUtils", methods, NELEM(methods));
69 }
70
71 }
72