xref: /aosp_15_r20/external/skia/src/base/SkUTF.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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