1*c8dee2aaSAndroid Build Coastguard Worker // Copyright 2018 Google LLC.
2*c8dee2aaSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3*c8dee2aaSAndroid Build Coastguard Worker
4*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkUTF.h"
5*c8dee2aaSAndroid Build Coastguard Worker
6*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTFitsIn.h"
7*c8dee2aaSAndroid Build Coastguard Worker
left_shift(int32_t value,int32_t shift)8*c8dee2aaSAndroid Build Coastguard Worker static constexpr inline int32_t left_shift(int32_t value, int32_t shift) {
9*c8dee2aaSAndroid Build Coastguard Worker return (int32_t) ((uint32_t) value << shift);
10*c8dee2aaSAndroid Build Coastguard Worker }
11*c8dee2aaSAndroid Build Coastguard Worker
is_align2(T x)12*c8dee2aaSAndroid Build Coastguard Worker template <typename T> static constexpr bool is_align2(T x) { return 0 == (x & 1); }
13*c8dee2aaSAndroid Build Coastguard Worker
is_align4(T x)14*c8dee2aaSAndroid Build Coastguard Worker template <typename T> static constexpr bool is_align4(T x) { return 0 == (x & 3); }
15*c8dee2aaSAndroid Build Coastguard Worker
utf16_is_high_surrogate(uint16_t c)16*c8dee2aaSAndroid Build Coastguard Worker static constexpr inline bool utf16_is_high_surrogate(uint16_t c) { return (c & 0xFC00) == 0xD800; }
17*c8dee2aaSAndroid Build Coastguard Worker
utf16_is_low_surrogate(uint16_t c)18*c8dee2aaSAndroid Build Coastguard Worker static constexpr inline bool utf16_is_low_surrogate(uint16_t c) { return (c & 0xFC00) == 0xDC00; }
19*c8dee2aaSAndroid Build Coastguard Worker
20*c8dee2aaSAndroid Build Coastguard Worker /** @returns -1 iff invalid UTF8 byte,
21*c8dee2aaSAndroid Build Coastguard Worker 0 iff UTF8 continuation byte,
22*c8dee2aaSAndroid Build Coastguard Worker 1 iff ASCII byte,
23*c8dee2aaSAndroid Build Coastguard Worker 2 iff leading byte of 2-byte sequence,
24*c8dee2aaSAndroid Build Coastguard Worker 3 iff leading byte of 3-byte sequence, and
25*c8dee2aaSAndroid Build Coastguard Worker 4 iff leading byte of 4-byte sequence.
26*c8dee2aaSAndroid Build Coastguard Worker I.e.: if return value > 0, then gives length of sequence.
27*c8dee2aaSAndroid Build Coastguard Worker */
utf8_byte_type(uint8_t c)28*c8dee2aaSAndroid Build Coastguard Worker static int utf8_byte_type(uint8_t c) {
29*c8dee2aaSAndroid Build Coastguard Worker if (c < 0x80) {
30*c8dee2aaSAndroid Build Coastguard Worker return 1;
31*c8dee2aaSAndroid Build Coastguard Worker } else if (c < 0xC0) {
32*c8dee2aaSAndroid Build Coastguard Worker return 0;
33*c8dee2aaSAndroid Build Coastguard Worker } else if (c >= 0xF5 || (c & 0xFE) == 0xC0) { // "octet values c0, c1, f5 to ff never appear"
34*c8dee2aaSAndroid Build Coastguard Worker return -1;
35*c8dee2aaSAndroid Build Coastguard Worker } else {
36*c8dee2aaSAndroid Build Coastguard Worker int value = (((0xe5 << 24) >> ((unsigned)c >> 4 << 1)) & 3) + 1;
37*c8dee2aaSAndroid Build Coastguard Worker // assert(value >= 2 && value <=4);
38*c8dee2aaSAndroid Build Coastguard Worker return value;
39*c8dee2aaSAndroid Build Coastguard Worker }
40*c8dee2aaSAndroid Build Coastguard Worker }
utf8_type_is_valid_leading_byte(int type)41*c8dee2aaSAndroid Build Coastguard Worker static bool utf8_type_is_valid_leading_byte(int type) { return type > 0; }
42*c8dee2aaSAndroid Build Coastguard Worker
utf8_byte_is_continuation(uint8_t c)43*c8dee2aaSAndroid Build Coastguard Worker static bool utf8_byte_is_continuation(uint8_t c) { return utf8_byte_type(c) == 0; }
44*c8dee2aaSAndroid Build Coastguard Worker
45*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
46*c8dee2aaSAndroid Build Coastguard Worker
CountUTF8(const char * utf8,size_t byteLength)47*c8dee2aaSAndroid Build Coastguard Worker int SkUTF::CountUTF8(const char* utf8, size_t byteLength) {
48*c8dee2aaSAndroid Build Coastguard Worker if (!utf8 && byteLength) {
49*c8dee2aaSAndroid Build Coastguard Worker return -1;
50*c8dee2aaSAndroid Build Coastguard Worker }
51*c8dee2aaSAndroid Build Coastguard Worker int count = 0;
52*c8dee2aaSAndroid Build Coastguard Worker const char* stop = utf8 + byteLength;
53*c8dee2aaSAndroid Build Coastguard Worker while (utf8 < stop) {
54*c8dee2aaSAndroid Build Coastguard Worker int type = utf8_byte_type(*(const uint8_t*)utf8);
55*c8dee2aaSAndroid Build Coastguard Worker if (!utf8_type_is_valid_leading_byte(type) || utf8 + type > stop) {
56*c8dee2aaSAndroid Build Coastguard Worker return -1; // Sequence extends beyond end.
57*c8dee2aaSAndroid Build Coastguard Worker }
58*c8dee2aaSAndroid Build Coastguard Worker while(type-- > 1) {
59*c8dee2aaSAndroid Build Coastguard Worker ++utf8;
60*c8dee2aaSAndroid Build Coastguard Worker if (!utf8_byte_is_continuation(*(const uint8_t*)utf8)) {
61*c8dee2aaSAndroid Build Coastguard Worker return -1;
62*c8dee2aaSAndroid Build Coastguard Worker }
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker ++utf8;
65*c8dee2aaSAndroid Build Coastguard Worker ++count;
66*c8dee2aaSAndroid Build Coastguard Worker }
67*c8dee2aaSAndroid Build Coastguard Worker return count;
68*c8dee2aaSAndroid Build Coastguard Worker }
69*c8dee2aaSAndroid Build Coastguard Worker
CountUTF16(const uint16_t * utf16,size_t byteLength)70*c8dee2aaSAndroid Build Coastguard Worker int SkUTF::CountUTF16(const uint16_t* utf16, size_t byteLength) {
71*c8dee2aaSAndroid Build Coastguard Worker if (!utf16 || !is_align2(intptr_t(utf16)) || !is_align2(byteLength)) {
72*c8dee2aaSAndroid Build Coastguard Worker return -1;
73*c8dee2aaSAndroid Build Coastguard Worker }
74*c8dee2aaSAndroid Build Coastguard Worker const uint16_t* src = (const uint16_t*)utf16;
75*c8dee2aaSAndroid Build Coastguard Worker const uint16_t* stop = src + (byteLength >> 1);
76*c8dee2aaSAndroid Build Coastguard Worker int count = 0;
77*c8dee2aaSAndroid Build Coastguard Worker while (src < stop) {
78*c8dee2aaSAndroid Build Coastguard Worker unsigned c = *src++;
79*c8dee2aaSAndroid Build Coastguard Worker if (utf16_is_low_surrogate(c)) {
80*c8dee2aaSAndroid Build Coastguard Worker return -1;
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker if (utf16_is_high_surrogate(c)) {
83*c8dee2aaSAndroid Build Coastguard Worker if (src >= stop) {
84*c8dee2aaSAndroid Build Coastguard Worker return -1;
85*c8dee2aaSAndroid Build Coastguard Worker }
86*c8dee2aaSAndroid Build Coastguard Worker c = *src++;
87*c8dee2aaSAndroid Build Coastguard Worker if (!utf16_is_low_surrogate(c)) {
88*c8dee2aaSAndroid Build Coastguard Worker return -1;
89*c8dee2aaSAndroid Build Coastguard Worker }
90*c8dee2aaSAndroid Build Coastguard Worker }
91*c8dee2aaSAndroid Build Coastguard Worker count += 1;
92*c8dee2aaSAndroid Build Coastguard Worker }
93*c8dee2aaSAndroid Build Coastguard Worker return count;
94*c8dee2aaSAndroid Build Coastguard Worker }
95*c8dee2aaSAndroid Build Coastguard Worker
CountUTF32(const int32_t * utf32,size_t byteLength)96*c8dee2aaSAndroid Build Coastguard Worker int SkUTF::CountUTF32(const int32_t* utf32, size_t byteLength) {
97*c8dee2aaSAndroid Build Coastguard Worker if (!is_align4(intptr_t(utf32)) || !is_align4(byteLength) || !SkTFitsIn<int>(byteLength >> 2)) {
98*c8dee2aaSAndroid Build Coastguard Worker return -1;
99*c8dee2aaSAndroid Build Coastguard Worker }
100*c8dee2aaSAndroid Build Coastguard Worker const uint32_t kInvalidUnicharMask = 0xFF000000; // unichar fits in 24 bits
101*c8dee2aaSAndroid Build Coastguard Worker const uint32_t* ptr = (const uint32_t*)utf32;
102*c8dee2aaSAndroid Build Coastguard Worker const uint32_t* stop = ptr + (byteLength >> 2);
103*c8dee2aaSAndroid Build Coastguard Worker while (ptr < stop) {
104*c8dee2aaSAndroid Build Coastguard Worker if (*ptr & kInvalidUnicharMask) {
105*c8dee2aaSAndroid Build Coastguard Worker return -1;
106*c8dee2aaSAndroid Build Coastguard Worker }
107*c8dee2aaSAndroid Build Coastguard Worker ptr += 1;
108*c8dee2aaSAndroid Build Coastguard Worker }
109*c8dee2aaSAndroid Build Coastguard Worker return (int)(byteLength >> 2);
110*c8dee2aaSAndroid Build Coastguard Worker }
111*c8dee2aaSAndroid Build Coastguard Worker
112*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
next_fail(const T ** ptr,const T * end)113*c8dee2aaSAndroid Build Coastguard Worker static SkUnichar next_fail(const T** ptr, const T* end) {
114*c8dee2aaSAndroid Build Coastguard Worker *ptr = end;
115*c8dee2aaSAndroid Build Coastguard Worker return -1;
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker
NextUTF8(const char ** ptr,const char * end)118*c8dee2aaSAndroid Build Coastguard Worker SkUnichar SkUTF::NextUTF8(const char** ptr, const char* end) {
119*c8dee2aaSAndroid Build Coastguard Worker if (!ptr || !end ) {
120*c8dee2aaSAndroid Build Coastguard Worker return -1;
121*c8dee2aaSAndroid Build Coastguard Worker }
122*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* p = (const uint8_t*)*ptr;
123*c8dee2aaSAndroid Build Coastguard Worker if (!p || p >= (const uint8_t*)end) {
124*c8dee2aaSAndroid Build Coastguard Worker return next_fail(ptr, end);
125*c8dee2aaSAndroid Build Coastguard Worker }
126*c8dee2aaSAndroid Build Coastguard Worker int c = *p;
127*c8dee2aaSAndroid Build Coastguard Worker int hic = c << 24;
128*c8dee2aaSAndroid Build Coastguard Worker
129*c8dee2aaSAndroid Build Coastguard Worker if (!utf8_type_is_valid_leading_byte(utf8_byte_type(c))) {
130*c8dee2aaSAndroid Build Coastguard Worker return next_fail(ptr, end);
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker if (hic < 0) {
133*c8dee2aaSAndroid Build Coastguard Worker uint32_t mask = (uint32_t)~0x3F;
134*c8dee2aaSAndroid Build Coastguard Worker hic = left_shift(hic, 1);
135*c8dee2aaSAndroid Build Coastguard Worker do {
136*c8dee2aaSAndroid Build Coastguard Worker ++p;
137*c8dee2aaSAndroid Build Coastguard Worker if (p >= (const uint8_t*)end) {
138*c8dee2aaSAndroid Build Coastguard Worker return next_fail(ptr, end);
139*c8dee2aaSAndroid Build Coastguard Worker }
140*c8dee2aaSAndroid Build Coastguard Worker // check before reading off end of array.
141*c8dee2aaSAndroid Build Coastguard Worker uint8_t nextByte = *p;
142*c8dee2aaSAndroid Build Coastguard Worker if (!utf8_byte_is_continuation(nextByte)) {
143*c8dee2aaSAndroid Build Coastguard Worker return next_fail(ptr, end);
144*c8dee2aaSAndroid Build Coastguard Worker }
145*c8dee2aaSAndroid Build Coastguard Worker c = (c << 6) | (nextByte & 0x3F);
146*c8dee2aaSAndroid Build Coastguard Worker mask <<= 5;
147*c8dee2aaSAndroid Build Coastguard Worker } while ((hic = left_shift(hic, 1)) < 0);
148*c8dee2aaSAndroid Build Coastguard Worker c &= ~mask;
149*c8dee2aaSAndroid Build Coastguard Worker }
150*c8dee2aaSAndroid Build Coastguard Worker *ptr = (const char*)p + 1;
151*c8dee2aaSAndroid Build Coastguard Worker return c;
152*c8dee2aaSAndroid Build Coastguard Worker }
153*c8dee2aaSAndroid Build Coastguard Worker
NextUTF8WithReplacement(const char ** ptr,const char * end)154*c8dee2aaSAndroid Build Coastguard Worker SkUnichar SkUTF::NextUTF8WithReplacement(const char** ptr, const char* end) {
155*c8dee2aaSAndroid Build Coastguard Worker SkUnichar val = SkUTF::NextUTF8(ptr, end);
156*c8dee2aaSAndroid Build Coastguard Worker return val < 0 ? 0xFFFD : val;
157*c8dee2aaSAndroid Build Coastguard Worker }
158*c8dee2aaSAndroid Build Coastguard Worker
NextUTF16(const uint16_t ** ptr,const uint16_t * end)159*c8dee2aaSAndroid Build Coastguard Worker SkUnichar SkUTF::NextUTF16(const uint16_t** ptr, const uint16_t* end) {
160*c8dee2aaSAndroid Build Coastguard Worker if (!ptr || !end ) {
161*c8dee2aaSAndroid Build Coastguard Worker return -1;
162*c8dee2aaSAndroid Build Coastguard Worker }
163*c8dee2aaSAndroid Build Coastguard Worker const uint16_t* src = *ptr;
164*c8dee2aaSAndroid Build Coastguard Worker if (!src || src + 1 > end || !is_align2(intptr_t(src))) {
165*c8dee2aaSAndroid Build Coastguard Worker return next_fail(ptr, end);
166*c8dee2aaSAndroid Build Coastguard Worker }
167*c8dee2aaSAndroid Build Coastguard Worker uint16_t c = *src++;
168*c8dee2aaSAndroid Build Coastguard Worker SkUnichar result = c;
169*c8dee2aaSAndroid Build Coastguard Worker if (utf16_is_low_surrogate(c)) {
170*c8dee2aaSAndroid Build Coastguard Worker return next_fail(ptr, end); // srcPtr should never point at low surrogate.
171*c8dee2aaSAndroid Build Coastguard Worker }
172*c8dee2aaSAndroid Build Coastguard Worker if (utf16_is_high_surrogate(c)) {
173*c8dee2aaSAndroid Build Coastguard Worker if (src + 1 > end) {
174*c8dee2aaSAndroid Build Coastguard Worker return next_fail(ptr, end); // Truncated string.
175*c8dee2aaSAndroid Build Coastguard Worker }
176*c8dee2aaSAndroid Build Coastguard Worker uint16_t low = *src++;
177*c8dee2aaSAndroid Build Coastguard Worker if (!utf16_is_low_surrogate(low)) {
178*c8dee2aaSAndroid Build Coastguard Worker return next_fail(ptr, end);
179*c8dee2aaSAndroid Build Coastguard Worker }
180*c8dee2aaSAndroid Build Coastguard Worker /*
181*c8dee2aaSAndroid Build Coastguard Worker [paraphrased from wikipedia]
182*c8dee2aaSAndroid Build Coastguard Worker Take the high surrogate and subtract 0xD800, then multiply by 0x400.
183*c8dee2aaSAndroid Build Coastguard Worker Take the low surrogate and subtract 0xDC00. Add these two results
184*c8dee2aaSAndroid Build Coastguard Worker together, and finally add 0x10000 to get the final decoded codepoint.
185*c8dee2aaSAndroid Build Coastguard Worker
186*c8dee2aaSAndroid Build Coastguard Worker unicode = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000
187*c8dee2aaSAndroid Build Coastguard Worker unicode = (high * 0x400) - (0xD800 * 0x400) + low - 0xDC00 + 0x10000
188*c8dee2aaSAndroid Build Coastguard Worker unicode = (high << 10) - (0xD800 << 10) + low - 0xDC00 + 0x10000
189*c8dee2aaSAndroid Build Coastguard Worker unicode = (high << 10) + low - ((0xD800 << 10) + 0xDC00 - 0x10000)
190*c8dee2aaSAndroid Build Coastguard Worker */
191*c8dee2aaSAndroid Build Coastguard Worker result = (result << 10) + (SkUnichar)low - ((0xD800 << 10) + 0xDC00 - 0x10000);
192*c8dee2aaSAndroid Build Coastguard Worker }
193*c8dee2aaSAndroid Build Coastguard Worker *ptr = src;
194*c8dee2aaSAndroid Build Coastguard Worker return result;
195*c8dee2aaSAndroid Build Coastguard Worker }
196*c8dee2aaSAndroid Build Coastguard Worker
NextUTF32(const int32_t ** ptr,const int32_t * end)197*c8dee2aaSAndroid Build Coastguard Worker SkUnichar SkUTF::NextUTF32(const int32_t** ptr, const int32_t* end) {
198*c8dee2aaSAndroid Build Coastguard Worker if (!ptr || !end ) {
199*c8dee2aaSAndroid Build Coastguard Worker return -1;
200*c8dee2aaSAndroid Build Coastguard Worker }
201*c8dee2aaSAndroid Build Coastguard Worker const int32_t* s = *ptr;
202*c8dee2aaSAndroid Build Coastguard Worker if (!s || s + 1 > end || !is_align4(intptr_t(s))) {
203*c8dee2aaSAndroid Build Coastguard Worker return next_fail(ptr, end);
204*c8dee2aaSAndroid Build Coastguard Worker }
205*c8dee2aaSAndroid Build Coastguard Worker int32_t value = *s;
206*c8dee2aaSAndroid Build Coastguard Worker const uint32_t kInvalidUnicharMask = 0xFF000000; // unichar fits in 24 bits
207*c8dee2aaSAndroid Build Coastguard Worker if (value & kInvalidUnicharMask) {
208*c8dee2aaSAndroid Build Coastguard Worker return next_fail(ptr, end);
209*c8dee2aaSAndroid Build Coastguard Worker }
210*c8dee2aaSAndroid Build Coastguard Worker *ptr = s + 1;
211*c8dee2aaSAndroid Build Coastguard Worker return value;
212*c8dee2aaSAndroid Build Coastguard Worker }
213*c8dee2aaSAndroid Build Coastguard Worker
ToUTF8(SkUnichar uni,char utf8[SkUTF::kMaxBytesInUTF8Sequence])214*c8dee2aaSAndroid Build Coastguard Worker size_t SkUTF::ToUTF8(SkUnichar uni, char utf8[SkUTF::kMaxBytesInUTF8Sequence]) {
215*c8dee2aaSAndroid Build Coastguard Worker if ((uint32_t)uni > 0x10FFFF) {
216*c8dee2aaSAndroid Build Coastguard Worker return 0;
217*c8dee2aaSAndroid Build Coastguard Worker }
218*c8dee2aaSAndroid Build Coastguard Worker if (uni <= 127) {
219*c8dee2aaSAndroid Build Coastguard Worker if (utf8) {
220*c8dee2aaSAndroid Build Coastguard Worker *utf8 = (char)uni;
221*c8dee2aaSAndroid Build Coastguard Worker }
222*c8dee2aaSAndroid Build Coastguard Worker return 1;
223*c8dee2aaSAndroid Build Coastguard Worker }
224*c8dee2aaSAndroid Build Coastguard Worker char tmp[4];
225*c8dee2aaSAndroid Build Coastguard Worker char* p = tmp;
226*c8dee2aaSAndroid Build Coastguard Worker size_t count = 1;
227*c8dee2aaSAndroid Build Coastguard Worker while (uni > 0x7F >> count) {
228*c8dee2aaSAndroid Build Coastguard Worker *p++ = (char)(0x80 | (uni & 0x3F));
229*c8dee2aaSAndroid Build Coastguard Worker uni >>= 6;
230*c8dee2aaSAndroid Build Coastguard Worker count += 1;
231*c8dee2aaSAndroid Build Coastguard Worker }
232*c8dee2aaSAndroid Build Coastguard Worker if (utf8) {
233*c8dee2aaSAndroid Build Coastguard Worker p = tmp;
234*c8dee2aaSAndroid Build Coastguard Worker utf8 += count;
235*c8dee2aaSAndroid Build Coastguard Worker while (p < tmp + count - 1) {
236*c8dee2aaSAndroid Build Coastguard Worker *--utf8 = *p++;
237*c8dee2aaSAndroid Build Coastguard Worker }
238*c8dee2aaSAndroid Build Coastguard Worker *--utf8 = (char)(~(0xFF >> count) | uni);
239*c8dee2aaSAndroid Build Coastguard Worker }
240*c8dee2aaSAndroid Build Coastguard Worker return count;
241*c8dee2aaSAndroid Build Coastguard Worker }
242*c8dee2aaSAndroid Build Coastguard Worker
ToUTF16(SkUnichar uni,uint16_t utf16[2])243*c8dee2aaSAndroid Build Coastguard Worker size_t SkUTF::ToUTF16(SkUnichar uni, uint16_t utf16[2]) {
244*c8dee2aaSAndroid Build Coastguard Worker if ((uint32_t)uni > 0x10FFFF) {
245*c8dee2aaSAndroid Build Coastguard Worker return 0;
246*c8dee2aaSAndroid Build Coastguard Worker }
247*c8dee2aaSAndroid Build Coastguard Worker int extra = (uni > 0xFFFF);
248*c8dee2aaSAndroid Build Coastguard Worker if (utf16) {
249*c8dee2aaSAndroid Build Coastguard Worker if (extra) {
250*c8dee2aaSAndroid Build Coastguard Worker utf16[0] = (uint16_t)((0xD800 - 64) + (uni >> 10));
251*c8dee2aaSAndroid Build Coastguard Worker utf16[1] = (uint16_t)(0xDC00 | (uni & 0x3FF));
252*c8dee2aaSAndroid Build Coastguard Worker } else {
253*c8dee2aaSAndroid Build Coastguard Worker utf16[0] = (uint16_t)uni;
254*c8dee2aaSAndroid Build Coastguard Worker }
255*c8dee2aaSAndroid Build Coastguard Worker }
256*c8dee2aaSAndroid Build Coastguard Worker return 1 + extra;
257*c8dee2aaSAndroid Build Coastguard Worker }
258*c8dee2aaSAndroid Build Coastguard Worker
UTF8ToUTF16(uint16_t dst[],int dstCapacity,const char src[],size_t srcByteLength)259*c8dee2aaSAndroid Build Coastguard Worker int SkUTF::UTF8ToUTF16(uint16_t dst[], int dstCapacity, const char src[], size_t srcByteLength) {
260*c8dee2aaSAndroid Build Coastguard Worker if (!dst) {
261*c8dee2aaSAndroid Build Coastguard Worker dstCapacity = 0;
262*c8dee2aaSAndroid Build Coastguard Worker }
263*c8dee2aaSAndroid Build Coastguard Worker
264*c8dee2aaSAndroid Build Coastguard Worker int dstLength = 0;
265*c8dee2aaSAndroid Build Coastguard Worker uint16_t* endDst = dst + dstCapacity;
266*c8dee2aaSAndroid Build Coastguard Worker const char* endSrc = src + srcByteLength;
267*c8dee2aaSAndroid Build Coastguard Worker while (src < endSrc) {
268*c8dee2aaSAndroid Build Coastguard Worker SkUnichar uni = NextUTF8(&src, endSrc);
269*c8dee2aaSAndroid Build Coastguard Worker if (uni < 0) {
270*c8dee2aaSAndroid Build Coastguard Worker return -1;
271*c8dee2aaSAndroid Build Coastguard Worker }
272*c8dee2aaSAndroid Build Coastguard Worker
273*c8dee2aaSAndroid Build Coastguard Worker uint16_t utf16[2];
274*c8dee2aaSAndroid Build Coastguard Worker size_t count = ToUTF16(uni, utf16);
275*c8dee2aaSAndroid Build Coastguard Worker if (count == 0) {
276*c8dee2aaSAndroid Build Coastguard Worker return -1;
277*c8dee2aaSAndroid Build Coastguard Worker }
278*c8dee2aaSAndroid Build Coastguard Worker dstLength += count;
279*c8dee2aaSAndroid Build Coastguard Worker
280*c8dee2aaSAndroid Build Coastguard Worker if (dst) {
281*c8dee2aaSAndroid Build Coastguard Worker uint16_t* elems = utf16;
282*c8dee2aaSAndroid Build Coastguard Worker while (dst < endDst && count > 0) {
283*c8dee2aaSAndroid Build Coastguard Worker *dst++ = *elems++;
284*c8dee2aaSAndroid Build Coastguard Worker count -= 1;
285*c8dee2aaSAndroid Build Coastguard Worker }
286*c8dee2aaSAndroid Build Coastguard Worker }
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker return dstLength;
289*c8dee2aaSAndroid Build Coastguard Worker }
290*c8dee2aaSAndroid Build Coastguard Worker
UTF16ToUTF8(char dst[],int dstCapacity,const uint16_t src[],size_t srcLength)291*c8dee2aaSAndroid Build Coastguard Worker int SkUTF::UTF16ToUTF8(char dst[], int dstCapacity, const uint16_t src[], size_t srcLength) {
292*c8dee2aaSAndroid Build Coastguard Worker if (!dst) {
293*c8dee2aaSAndroid Build Coastguard Worker dstCapacity = 0;
294*c8dee2aaSAndroid Build Coastguard Worker }
295*c8dee2aaSAndroid Build Coastguard Worker
296*c8dee2aaSAndroid Build Coastguard Worker int dstLength = 0;
297*c8dee2aaSAndroid Build Coastguard Worker const char* endDst = dst + dstCapacity;
298*c8dee2aaSAndroid Build Coastguard Worker const uint16_t* endSrc = src + srcLength;
299*c8dee2aaSAndroid Build Coastguard Worker while (src < endSrc) {
300*c8dee2aaSAndroid Build Coastguard Worker SkUnichar uni = NextUTF16(&src, endSrc);
301*c8dee2aaSAndroid Build Coastguard Worker if (uni < 0) {
302*c8dee2aaSAndroid Build Coastguard Worker return -1;
303*c8dee2aaSAndroid Build Coastguard Worker }
304*c8dee2aaSAndroid Build Coastguard Worker
305*c8dee2aaSAndroid Build Coastguard Worker char utf8[SkUTF::kMaxBytesInUTF8Sequence];
306*c8dee2aaSAndroid Build Coastguard Worker size_t count = ToUTF8(uni, utf8);
307*c8dee2aaSAndroid Build Coastguard Worker if (count == 0) {
308*c8dee2aaSAndroid Build Coastguard Worker return -1;
309*c8dee2aaSAndroid Build Coastguard Worker }
310*c8dee2aaSAndroid Build Coastguard Worker dstLength += count;
311*c8dee2aaSAndroid Build Coastguard Worker
312*c8dee2aaSAndroid Build Coastguard Worker if (dst) {
313*c8dee2aaSAndroid Build Coastguard Worker const char* elems = utf8;
314*c8dee2aaSAndroid Build Coastguard Worker while (dst < endDst && count > 0) {
315*c8dee2aaSAndroid Build Coastguard Worker *dst++ = *elems++;
316*c8dee2aaSAndroid Build Coastguard Worker count -= 1;
317*c8dee2aaSAndroid Build Coastguard Worker }
318*c8dee2aaSAndroid Build Coastguard Worker }
319*c8dee2aaSAndroid Build Coastguard Worker }
320*c8dee2aaSAndroid Build Coastguard Worker return dstLength;
321*c8dee2aaSAndroid Build Coastguard Worker }
322