summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes2017-11-10 12:22:07 -0600
committerElliott Hughes2017-11-10 15:18:10 -0600
commit8e9aeb9053695a14539653093937158d15385ca6 (patch)
treeb02f7ad2149812eea2cb2802b7f238856b66619c /libcutils/strdup16to8.cpp
parent6707ef139d9786887649e3e3c2e3e251a95dc96d (diff)
downloadplatform-system-core-8e9aeb9053695a14539653093937158d15385ca6.tar.gz
platform-system-core-8e9aeb9053695a14539653093937158d15385ca6.tar.xz
platform-system-core-8e9aeb9053695a14539653093937158d15385ca6.zip
Move libcutils source to C++.
Just the minimial changes to get this to actually build, because otherwise we always bog down trying to rewrite everything (when the real answer is usually "stop using libcutils, it's awful"). This doesn't move a handful of files: two are basically just BSD libc source, a couple have outstanding code reviews, and one can be deleted (but I'll do that in a separate change). I'm also skipping the presubmit hooks because otherwise clang-format wants to reformat everything. I'll follow up with that... Bug: N/A Test: builds Change-Id: I06403f465b67c8e493bad466dd76b1151eed5993
Diffstat (limited to 'libcutils/strdup16to8.cpp')
-rw-r--r--libcutils/strdup16to8.cpp168
1 files changed, 168 insertions, 0 deletions
diff --git a/libcutils/strdup16to8.cpp b/libcutils/strdup16to8.cpp
new file mode 100644
index 000000000..d89181e14
--- /dev/null
+++ b/libcutils/strdup16to8.cpp
@@ -0,0 +1,168 @@
1/* libs/cutils/strdup16to8.c
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include <cutils/jstring.h>
19
20#include <assert.h>
21#include <limits.h> /* for SIZE_MAX */
22#include <stdlib.h>
23
24
25/**
26 * Given a UTF-16 string, compute the length of the corresponding UTF-8
27 * string in bytes.
28 */
29extern size_t strnlen16to8(const char16_t* utf16Str, size_t len)
30{
31 size_t utf8Len = 0;
32
33 /* A small note on integer overflow. The result can
34 * potentially be as big as 3*len, which will overflow
35 * for len > SIZE_MAX/3.
36 *
37 * Moreover, the result of a strnlen16to8 is typically used
38 * to allocate a destination buffer to strncpy16to8 which
39 * requires one more byte to terminate the UTF-8 copy, and
40 * this is generally done by careless users by incrementing
41 * the result without checking for integer overflows, e.g.:
42 *
43 * dst = malloc(strnlen16to8(utf16,len)+1)
44 *
45 * Due to this, the following code will try to detect
46 * overflows, and never return more than (SIZE_MAX-1)
47 * when it detects one. A careless user will try to malloc
48 * SIZE_MAX bytes, which will return NULL which can at least
49 * be detected appropriately.
50 *
51 * As far as I know, this function is only used by strndup16(),
52 * but better be safe than sorry.
53 */
54
55 /* Fast path for the usual case where 3*len is < SIZE_MAX-1.
56 */
57 if (len < (SIZE_MAX-1)/3) {
58 while (len != 0) {
59 len--;
60 unsigned int uic = *utf16Str++;
61
62 if (uic > 0x07ff)
63 utf8Len += 3;
64 else if (uic > 0x7f || uic == 0)
65 utf8Len += 2;
66 else
67 utf8Len++;
68 }
69 return utf8Len;
70 }
71
72 /* The slower but paranoid version */
73 while (len != 0) {
74 len--;
75 unsigned int uic = *utf16Str++;
76 size_t utf8Cur = utf8Len;
77
78 if (uic > 0x07ff)
79 utf8Len += 3;
80 else if (uic > 0x7f || uic == 0)
81 utf8Len += 2;
82 else
83 utf8Len++;
84
85 if (utf8Len < utf8Cur) /* overflow detected */
86 return SIZE_MAX-1;
87 }
88
89 /* don't return SIZE_MAX to avoid common user bug */
90 if (utf8Len == SIZE_MAX)
91 utf8Len = SIZE_MAX-1;
92
93 return utf8Len;
94}
95
96
97/**
98 * Convert a Java-Style UTF-16 string + length to a JNI-Style UTF-8 string.
99 *
100 * This basically means: embedded \0's in the UTF-16 string are encoded
101 * as "0xc0 0x80"
102 *
103 * Make sure you allocate "utf8Str" with the result of strlen16to8() + 1,
104 * not just "len".
105 *
106 * Please note, a terminated \0 is always added, so your result will always
107 * be "strlen16to8() + 1" bytes long.
108 */
109extern char* strncpy16to8(char* utf8Str, const char16_t* utf16Str, size_t len)
110{
111 char* utf8cur = utf8Str;
112
113 /* Note on overflows: We assume the user did check the result of
114 * strnlen16to8() properly or at a minimum checked the result of
115 * its malloc(SIZE_MAX) in case of overflow.
116 */
117 while (len != 0) {
118 len--;
119 unsigned int uic = *utf16Str++;
120
121 if (uic > 0x07ff) {
122 *utf8cur++ = (uic >> 12) | 0xe0;
123 *utf8cur++ = ((uic >> 6) & 0x3f) | 0x80;
124 *utf8cur++ = (uic & 0x3f) | 0x80;
125 } else if (uic > 0x7f || uic == 0) {
126 *utf8cur++ = (uic >> 6) | 0xc0;
127 *utf8cur++ = (uic & 0x3f) | 0x80;
128 } else {
129 *utf8cur++ = uic;
130
131 if (uic == 0) {
132 break;
133 }
134 }
135 }
136
137 *utf8cur = '\0';
138
139 return utf8Str;
140}
141
142/**
143 * Convert a UTF-16 string to UTF-8.
144 *
145 */
146char * strndup16to8 (const char16_t* s, size_t n)
147{
148 if (s == NULL) {
149 return NULL;
150 }
151
152 size_t len = strnlen16to8(s, n);
153
154 /* We are paranoid, and we check for SIZE_MAX-1
155 * too since it is an overflow value for our
156 * strnlen16to8 implementation.
157 */
158 if (len >= SIZE_MAX-1)
159 return NULL;
160
161 char* ret = static_cast<char*>(malloc(len + 1));
162 if (ret == NULL)
163 return NULL;
164
165 strncpy16to8 (ret, s, n);
166
167 return ret;
168}