1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 **********************************************************************
5 * Copyright (C) 2002-2016, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 **********************************************************************
8 * file name: ucnv_u8.c
9 * encoding: UTF-8
10 * tab size: 8 (not used)
11 * indentation:4
12 *
13 * created on: 2002jul01
14 * created by: Markus W. Scherer
15 *
16 * UTF-8 converter implementation. Used to be in ucnv_utf.c.
17 *
18 * Also, CESU-8 implementation, see UTR 26.
19 * The CESU-8 converter uses all the same functions as the
20 * UTF-8 converter, with a branch for converting supplementary code points.
21 */
22
23 #include "unicode/utypes.h"
24
25 #if !UCONFIG_NO_CONVERSION
26
27 #include "unicode/ucnv.h"
28 #include "unicode/utf.h"
29 #include "unicode/utf8.h"
30 #include "unicode/utf16.h"
31 #include "uassert.h"
32 #include "ucnv_bld.h"
33 #include "ucnv_cnv.h"
34 #include "cmemory.h"
35 #include "ustr_imp.h"
36
37 /* Prototypes --------------------------------------------------------------- */
38
39 /* Keep these here to make finicky compilers happy */
40
41 U_CFUNC void ucnv_fromUnicode_UTF8(UConverterFromUnicodeArgs *args,
42 UErrorCode *err);
43 U_CFUNC void ucnv_fromUnicode_UTF8_OFFSETS_LOGIC(UConverterFromUnicodeArgs *args,
44 UErrorCode *err);
45
46
47 /* UTF-8 -------------------------------------------------------------------- */
48
49 #define MAXIMUM_UCS2 0x0000FFFF
50
51 static const uint32_t offsetsFromUTF8[5] = {0,
52 (uint32_t) 0x00000000, (uint32_t) 0x00003080, (uint32_t) 0x000E2080,
53 (uint32_t) 0x03C82080
54 };
55
hasCESU8Data(const UConverter * cnv)56 static UBool hasCESU8Data(const UConverter *cnv)
57 {
58 #if UCONFIG_ONLY_HTML_CONVERSION
59 return FALSE;
60 #else
61 return (UBool)(cnv->sharedData == &_CESU8Data);
62 #endif
63 }
64 U_CDECL_BEGIN
ucnv_toUnicode_UTF8(UConverterToUnicodeArgs * args,UErrorCode * err)65 static void U_CALLCONV ucnv_toUnicode_UTF8 (UConverterToUnicodeArgs * args,
66 UErrorCode * err)
67 {
68 UConverter *cnv = args->converter;
69 const unsigned char *mySource = (unsigned char *) args->source;
70 UChar *myTarget = args->target;
71 const unsigned char *sourceLimit = (unsigned char *) args->sourceLimit;
72 const UChar *targetLimit = args->targetLimit;
73 unsigned char *toUBytes = cnv->toUBytes;
74 UBool isCESU8 = hasCESU8Data(cnv);
75 uint32_t ch, ch2 = 0;
76 int32_t i, inBytes;
77
78 /* Restore size of current sequence */
79 if (cnv->toULength > 0 && myTarget < targetLimit)
80 {
81 inBytes = cnv->mode; /* restore # of bytes to consume */
82 i = cnv->toULength; /* restore # of bytes consumed */
83 cnv->toULength = 0;
84
85 ch = cnv->toUnicodeStatus;/*Stores the previously calculated ch from a previous call*/
86 cnv->toUnicodeStatus = 0;
87 goto morebytes;
88 }
89
90
91 while (mySource < sourceLimit && myTarget < targetLimit)
92 {
93 ch = *(mySource++);
94 if (U8_IS_SINGLE(ch)) /* Simple case */
95 {
96 *(myTarget++) = (UChar) ch;
97 }
98 else
99 {
100 /* store the first char */
101 toUBytes[0] = (char)ch;
102 inBytes = U8_COUNT_BYTES_NON_ASCII(ch); /* lookup current sequence length */
103 i = 1;
104
105 morebytes:
106 while (i < inBytes)
107 {
108 if (mySource < sourceLimit)
109 {
110 toUBytes[i] = (char) (ch2 = *mySource);
111 if (!icu::UTF8::isValidTrail(ch, static_cast<uint8_t>(ch2), i, inBytes) &&
112 !(isCESU8 && i == 1 && ch == 0xed && U8_IS_TRAIL(ch2)))
113 {
114 break; /* i < inBytes */
115 }
116 ch = (ch << 6) + ch2;
117 ++mySource;
118 i++;
119 }
120 else
121 {
122 /* stores a partially calculated target*/
123 cnv->toUnicodeStatus = ch;
124 cnv->mode = inBytes;
125 cnv->toULength = (int8_t) i;
126 goto donefornow;
127 }
128 }
129
130 // In CESU-8, only surrogates, not supplementary code points, are encoded directly.
131 if (i == inBytes && (!isCESU8 || i <= 3))
132 {
133 /* Remove the accumulated high bits */
134 ch -= offsetsFromUTF8[inBytes];
135
136 /* Normal valid byte when the loop has not prematurely terminated (i < inBytes) */
137 if (ch <= MAXIMUM_UCS2)
138 {
139 /* fits in 16 bits */
140 *(myTarget++) = (UChar) ch;
141 }
142 else
143 {
144 /* write out the surrogates */
145 *(myTarget++) = U16_LEAD(ch);
146 ch = U16_TRAIL(ch);
147 if (myTarget < targetLimit)
148 {
149 *(myTarget++) = (UChar)ch;
150 }
151 else
152 {
153 /* Put in overflow buffer (not handled here) */
154 cnv->UCharErrorBuffer[0] = (UChar) ch;
155 cnv->UCharErrorBufferLength = 1;
156 *err = U_BUFFER_OVERFLOW_ERROR;
157 break;
158 }
159 }
160 }
161 else
162 {
163 cnv->toULength = (int8_t)i;
164 *err = U_ILLEGAL_CHAR_FOUND;
165 break;
166 }
167 }
168 }
169
170 donefornow:
171 if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
172 {
173 /* End of target buffer */
174 *err = U_BUFFER_OVERFLOW_ERROR;
175 }
176
177 args->target = myTarget;
178 args->source = (const char *) mySource;
179 }
180
ucnv_toUnicode_UTF8_OFFSETS_LOGIC(UConverterToUnicodeArgs * args,UErrorCode * err)181 static void U_CALLCONV ucnv_toUnicode_UTF8_OFFSETS_LOGIC (UConverterToUnicodeArgs * args,
182 UErrorCode * err)
183 {
184 UConverter *cnv = args->converter;
185 const unsigned char *mySource = (unsigned char *) args->source;
186 UChar *myTarget = args->target;
187 int32_t *myOffsets = args->offsets;
188 int32_t offsetNum = 0;
189 const unsigned char *sourceLimit = (unsigned char *) args->sourceLimit;
190 const UChar *targetLimit = args->targetLimit;
191 unsigned char *toUBytes = cnv->toUBytes;
192 UBool isCESU8 = hasCESU8Data(cnv);
193 uint32_t ch, ch2 = 0;
194 int32_t i, inBytes;
195
196 /* Restore size of current sequence */
197 if (cnv->toULength > 0 && myTarget < targetLimit)
198 {
199 inBytes = cnv->mode; /* restore # of bytes to consume */
200 i = cnv->toULength; /* restore # of bytes consumed */
201 cnv->toULength = 0;
202
203 ch = cnv->toUnicodeStatus;/*Stores the previously calculated ch from a previous call*/
204 cnv->toUnicodeStatus = 0;
205 goto morebytes;
206 }
207
208 while (mySource < sourceLimit && myTarget < targetLimit)
209 {
210 ch = *(mySource++);
211 if (U8_IS_SINGLE(ch)) /* Simple case */
212 {
213 *(myTarget++) = (UChar) ch;
214 *(myOffsets++) = offsetNum++;
215 }
216 else
217 {
218 toUBytes[0] = (char)ch;
219 inBytes = U8_COUNT_BYTES_NON_ASCII(ch);
220 i = 1;
221
222 morebytes:
223 while (i < inBytes)
224 {
225 if (mySource < sourceLimit)
226 {
227 toUBytes[i] = (char) (ch2 = *mySource);
228 if (!icu::UTF8::isValidTrail(ch, static_cast<uint8_t>(ch2), i, inBytes) &&
229 !(isCESU8 && i == 1 && ch == 0xed && U8_IS_TRAIL(ch2)))
230 {
231 break; /* i < inBytes */
232 }
233 ch = (ch << 6) + ch2;
234 ++mySource;
235 i++;
236 }
237 else
238 {
239 cnv->toUnicodeStatus = ch;
240 cnv->mode = inBytes;
241 cnv->toULength = (int8_t)i;
242 goto donefornow;
243 }
244 }
245
246 // In CESU-8, only surrogates, not supplementary code points, are encoded directly.
247 if (i == inBytes && (!isCESU8 || i <= 3))
248 {
249 /* Remove the accumulated high bits */
250 ch -= offsetsFromUTF8[inBytes];
251
252 /* Normal valid byte when the loop has not prematurely terminated (i < inBytes) */
253 if (ch <= MAXIMUM_UCS2)
254 {
255 /* fits in 16 bits */
256 *(myTarget++) = (UChar) ch;
257 *(myOffsets++) = offsetNum;
258 }
259 else
260 {
261 /* write out the surrogates */
262 *(myTarget++) = U16_LEAD(ch);
263 *(myOffsets++) = offsetNum;
264 ch = U16_TRAIL(ch);
265 if (myTarget < targetLimit)
266 {
267 *(myTarget++) = (UChar)ch;
268 *(myOffsets++) = offsetNum;
269 }
270 else
271 {
272 cnv->UCharErrorBuffer[0] = (UChar) ch;
273 cnv->UCharErrorBufferLength = 1;
274 *err = U_BUFFER_OVERFLOW_ERROR;
275 }
276 }
277 offsetNum += i;
278 }
279 else
280 {
281 cnv->toULength = (int8_t)i;
282 *err = U_ILLEGAL_CHAR_FOUND;
283 break;
284 }
285 }
286 }
287
288 donefornow:
289 if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
290 { /* End of target buffer */
291 *err = U_BUFFER_OVERFLOW_ERROR;
292 }
293
294 args->target = myTarget;
295 args->source = (const char *) mySource;
296 args->offsets = myOffsets;
297 }
298 U_CDECL_END
299
ucnv_fromUnicode_UTF8(UConverterFromUnicodeArgs * args,UErrorCode * err)300 U_CFUNC void U_CALLCONV ucnv_fromUnicode_UTF8 (UConverterFromUnicodeArgs * args,
301 UErrorCode * err)
302 {
303 UConverter *cnv = args->converter;
304 const UChar *mySource = args->source;
305 const UChar *sourceLimit = args->sourceLimit;
306 uint8_t *myTarget = (uint8_t *) args->target;
307 const uint8_t *targetLimit = (uint8_t *) args->targetLimit;
308 uint8_t *tempPtr;
309 UChar32 ch;
310 uint8_t tempBuf[4];
311 int32_t indexToWrite;
312 UBool isNotCESU8 = !hasCESU8Data(cnv);
313
314 if (cnv->fromUChar32 && myTarget < targetLimit)
315 {
316 ch = cnv->fromUChar32;
317 cnv->fromUChar32 = 0;
318 goto lowsurrogate;
319 }
320
321 while (mySource < sourceLimit && myTarget < targetLimit)
322 {
323 ch = *(mySource++);
324
325 if (ch < 0x80) /* Single byte */
326 {
327 *(myTarget++) = (uint8_t) ch;
328 }
329 else if (ch < 0x800) /* Double byte */
330 {
331 *(myTarget++) = (uint8_t) ((ch >> 6) | 0xc0);
332 if (myTarget < targetLimit)
333 {
334 *(myTarget++) = (uint8_t) ((ch & 0x3f) | 0x80);
335 }
336 else
337 {
338 cnv->charErrorBuffer[0] = (uint8_t) ((ch & 0x3f) | 0x80);
339 cnv->charErrorBufferLength = 1;
340 *err = U_BUFFER_OVERFLOW_ERROR;
341 }
342 }
343 else {
344 /* Check for surrogates */
345 if(U16_IS_SURROGATE(ch) && isNotCESU8) {
346 lowsurrogate:
347 if (mySource < sourceLimit) {
348 /* test both code units */
349 if(U16_IS_SURROGATE_LEAD(ch) && U16_IS_TRAIL(*mySource)) {
350 /* convert and consume this supplementary code point */
351 ch=U16_GET_SUPPLEMENTARY(ch, *mySource);
352 ++mySource;
353 /* exit this condition tree */
354 }
355 else {
356 /* this is an unpaired trail or lead code unit */
357 /* callback(illegal) */
358 cnv->fromUChar32 = ch;
359 *err = U_ILLEGAL_CHAR_FOUND;
360 break;
361 }
362 }
363 else {
364 /* no more input */
365 cnv->fromUChar32 = ch;
366 break;
367 }
368 }
369
370 /* Do we write the buffer directly for speed,
371 or do we have to be careful about target buffer space? */
372 tempPtr = (((targetLimit - myTarget) >= 4) ? myTarget : tempBuf);
373
374 if (ch <= MAXIMUM_UCS2) {
375 indexToWrite = 2;
376 tempPtr[0] = (uint8_t) ((ch >> 12) | 0xe0);
377 }
378 else {
379 indexToWrite = 3;
380 tempPtr[0] = (uint8_t) ((ch >> 18) | 0xf0);
381 tempPtr[1] = (uint8_t) (((ch >> 12) & 0x3f) | 0x80);
382 }
383 tempPtr[indexToWrite-1] = (uint8_t) (((ch >> 6) & 0x3f) | 0x80);
384 tempPtr[indexToWrite] = (uint8_t) ((ch & 0x3f) | 0x80);
385
386 if (tempPtr == myTarget) {
387 /* There was enough space to write the codepoint directly. */
388 myTarget += (indexToWrite + 1);
389 }
390 else {
391 /* We might run out of room soon. Write it slowly. */
392 for (; tempPtr <= (tempBuf + indexToWrite); tempPtr++) {
393 if (myTarget < targetLimit) {
394 *(myTarget++) = *tempPtr;
395 }
396 else {
397 cnv->charErrorBuffer[cnv->charErrorBufferLength++] = *tempPtr;
398 *err = U_BUFFER_OVERFLOW_ERROR;
399 }
400 }
401 }
402 }
403 }
404
405 if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
406 {
407 *err = U_BUFFER_OVERFLOW_ERROR;
408 }
409
410 args->target = (char *) myTarget;
411 args->source = mySource;
412 }
413
ucnv_fromUnicode_UTF8_OFFSETS_LOGIC(UConverterFromUnicodeArgs * args,UErrorCode * err)414 U_CFUNC void U_CALLCONV ucnv_fromUnicode_UTF8_OFFSETS_LOGIC (UConverterFromUnicodeArgs * args,
415 UErrorCode * err)
416 {
417 UConverter *cnv = args->converter;
418 const UChar *mySource = args->source;
419 int32_t *myOffsets = args->offsets;
420 const UChar *sourceLimit = args->sourceLimit;
421 uint8_t *myTarget = (uint8_t *) args->target;
422 const uint8_t *targetLimit = (uint8_t *) args->targetLimit;
423 uint8_t *tempPtr;
424 UChar32 ch;
425 int32_t offsetNum, nextSourceIndex;
426 int32_t indexToWrite;
427 uint8_t tempBuf[4];
428 UBool isNotCESU8 = !hasCESU8Data(cnv);
429
430 if (cnv->fromUChar32 && myTarget < targetLimit)
431 {
432 ch = cnv->fromUChar32;
433 cnv->fromUChar32 = 0;
434 offsetNum = -1;
435 nextSourceIndex = 0;
436 goto lowsurrogate;
437 } else {
438 offsetNum = 0;
439 }
440
441 while (mySource < sourceLimit && myTarget < targetLimit)
442 {
443 ch = *(mySource++);
444
445 if (ch < 0x80) /* Single byte */
446 {
447 *(myOffsets++) = offsetNum++;
448 *(myTarget++) = (char) ch;
449 }
450 else if (ch < 0x800) /* Double byte */
451 {
452 *(myOffsets++) = offsetNum;
453 *(myTarget++) = (uint8_t) ((ch >> 6) | 0xc0);
454 if (myTarget < targetLimit)
455 {
456 *(myOffsets++) = offsetNum++;
457 *(myTarget++) = (uint8_t) ((ch & 0x3f) | 0x80);
458 }
459 else
460 {
461 cnv->charErrorBuffer[0] = (uint8_t) ((ch & 0x3f) | 0x80);
462 cnv->charErrorBufferLength = 1;
463 *err = U_BUFFER_OVERFLOW_ERROR;
464 }
465 }
466 else
467 /* Check for surrogates */
468 {
469 nextSourceIndex = offsetNum + 1;
470
471 if(U16_IS_SURROGATE(ch) && isNotCESU8) {
472 lowsurrogate:
473 if (mySource < sourceLimit) {
474 /* test both code units */
475 if(U16_IS_SURROGATE_LEAD(ch) && U16_IS_TRAIL(*mySource)) {
476 /* convert and consume this supplementary code point */
477 ch=U16_GET_SUPPLEMENTARY(ch, *mySource);
478 ++mySource;
479 ++nextSourceIndex;
480 /* exit this condition tree */
481 }
482 else {
483 /* this is an unpaired trail or lead code unit */
484 /* callback(illegal) */
485 cnv->fromUChar32 = ch;
486 *err = U_ILLEGAL_CHAR_FOUND;
487 break;
488 }
489 }
490 else {
491 /* no more input */
492 cnv->fromUChar32 = ch;
493 break;
494 }
495 }
496
497 /* Do we write the buffer directly for speed,
498 or do we have to be careful about target buffer space? */
499 tempPtr = (((targetLimit - myTarget) >= 4) ? myTarget : tempBuf);
500
501 if (ch <= MAXIMUM_UCS2) {
502 indexToWrite = 2;
503 tempPtr[0] = (uint8_t) ((ch >> 12) | 0xe0);
504 }
505 else {
506 indexToWrite = 3;
507 tempPtr[0] = (uint8_t) ((ch >> 18) | 0xf0);
508 tempPtr[1] = (uint8_t) (((ch >> 12) & 0x3f) | 0x80);
509 }
510 tempPtr[indexToWrite-1] = (uint8_t) (((ch >> 6) & 0x3f) | 0x80);
511 tempPtr[indexToWrite] = (uint8_t) ((ch & 0x3f) | 0x80);
512
513 if (tempPtr == myTarget) {
514 /* There was enough space to write the codepoint directly. */
515 myTarget += (indexToWrite + 1);
516 myOffsets[0] = offsetNum;
517 myOffsets[1] = offsetNum;
518 myOffsets[2] = offsetNum;
519 if (indexToWrite >= 3) {
520 myOffsets[3] = offsetNum;
521 }
522 myOffsets += (indexToWrite + 1);
523 }
524 else {
525 /* We might run out of room soon. Write it slowly. */
526 for (; tempPtr <= (tempBuf + indexToWrite); tempPtr++) {
527 if (myTarget < targetLimit)
528 {
529 *(myOffsets++) = offsetNum;
530 *(myTarget++) = *tempPtr;
531 }
532 else
533 {
534 cnv->charErrorBuffer[cnv->charErrorBufferLength++] = *tempPtr;
535 *err = U_BUFFER_OVERFLOW_ERROR;
536 }
537 }
538 }
539 offsetNum = nextSourceIndex;
540 }
541 }
542
543 if (mySource < sourceLimit && myTarget >= targetLimit && U_SUCCESS(*err))
544 {
545 *err = U_BUFFER_OVERFLOW_ERROR;
546 }
547
548 args->target = (char *) myTarget;
549 args->source = mySource;
550 args->offsets = myOffsets;
551 }
552
553 U_CDECL_BEGIN
ucnv_getNextUChar_UTF8(UConverterToUnicodeArgs * args,UErrorCode * err)554 static UChar32 U_CALLCONV ucnv_getNextUChar_UTF8(UConverterToUnicodeArgs *args,
555 UErrorCode *err) {
556 UConverter *cnv;
557 const uint8_t *sourceInitial;
558 const uint8_t *source;
559 uint8_t myByte;
560 UChar32 ch;
561 int8_t i;
562
563 /* UTF-8 only here, the framework handles CESU-8 to combine surrogate pairs */
564
565 cnv = args->converter;
566 sourceInitial = source = (const uint8_t *)args->source;
567 if (source >= (const uint8_t *)args->sourceLimit)
568 {
569 /* no input */
570 *err = U_INDEX_OUTOFBOUNDS_ERROR;
571 return 0xffff;
572 }
573
574 myByte = (uint8_t)*(source++);
575 if (U8_IS_SINGLE(myByte))
576 {
577 args->source = (const char *)source;
578 return (UChar32)myByte;
579 }
580
581 uint16_t countTrailBytes = U8_COUNT_TRAIL_BYTES(myByte);
582 if (countTrailBytes == 0) {
583 cnv->toUBytes[0] = myByte;
584 cnv->toULength = 1;
585 *err = U_ILLEGAL_CHAR_FOUND;
586 args->source = (const char *)source;
587 return 0xffff;
588 }
589
590 /*The byte sequence is longer than the buffer area passed*/
591 if (((const char *)source + countTrailBytes) > args->sourceLimit)
592 {
593 /* check if all of the remaining bytes are trail bytes */
594 uint16_t extraBytesToWrite = countTrailBytes + 1;
595 cnv->toUBytes[0] = myByte;
596 i = 1;
597 *err = U_TRUNCATED_CHAR_FOUND;
598 while(source < (const uint8_t *)args->sourceLimit) {
599 uint8_t b = *source;
600 if(icu::UTF8::isValidTrail(myByte, b, i, extraBytesToWrite)) {
601 cnv->toUBytes[i++] = b;
602 ++source;
603 } else {
604 /* error even before we run out of input */
605 *err = U_ILLEGAL_CHAR_FOUND;
606 break;
607 }
608 }
609 cnv->toULength = i;
610 args->source = (const char *)source;
611 return 0xffff;
612 }
613
614 ch = myByte << 6;
615 if(countTrailBytes == 2) {
616 uint8_t t1 = *source, t2;
617 if(U8_IS_VALID_LEAD3_AND_T1(myByte, t1) && U8_IS_TRAIL(t2 = *++source)) {
618 args->source = (const char *)(source + 1);
619 return (((ch + t1) << 6) + t2) - offsetsFromUTF8[3];
620 }
621 } else if(countTrailBytes == 1) {
622 uint8_t t1 = *source;
623 if(U8_IS_TRAIL(t1)) {
624 args->source = (const char *)(source + 1);
625 return (ch + t1) - offsetsFromUTF8[2];
626 }
627 } else { // countTrailBytes == 3
628 uint8_t t1 = *source, t2, t3;
629 if(U8_IS_VALID_LEAD4_AND_T1(myByte, t1) && U8_IS_TRAIL(t2 = *++source) &&
630 U8_IS_TRAIL(t3 = *++source)) {
631 args->source = (const char *)(source + 1);
632 return (((((ch + t1) << 6) + t2) << 6) + t3) - offsetsFromUTF8[4];
633 }
634 }
635 args->source = (const char *)source;
636
637 for(i = 0; sourceInitial < source; ++i) {
638 cnv->toUBytes[i] = *sourceInitial++;
639 }
640 cnv->toULength = i;
641 *err = U_ILLEGAL_CHAR_FOUND;
642 return 0xffff;
643 }
644 U_CDECL_END
645
646 /* UTF-8-from-UTF-8 conversion functions ------------------------------------ */
647
648 U_CDECL_BEGIN
649 /* "Convert" UTF-8 to UTF-8: Validate and copy. Modified from ucnv_DBCSFromUTF8(). */
650 static void U_CALLCONV
ucnv_UTF8FromUTF8(UConverterFromUnicodeArgs * pFromUArgs,UConverterToUnicodeArgs * pToUArgs,UErrorCode * pErrorCode)651 ucnv_UTF8FromUTF8(UConverterFromUnicodeArgs *pFromUArgs,
652 UConverterToUnicodeArgs *pToUArgs,
653 UErrorCode *pErrorCode) {
654 UConverter *utf8;
655 const uint8_t *source, *sourceLimit;
656 uint8_t *target;
657 int32_t targetCapacity;
658 int32_t count;
659
660 int8_t oldToULength, toULength, toULimit;
661
662 UChar32 c;
663 uint8_t b, t1, t2;
664
665 /* set up the local pointers */
666 utf8=pToUArgs->converter;
667 source=(uint8_t *)pToUArgs->source;
668 sourceLimit=(uint8_t *)pToUArgs->sourceLimit;
669 target=(uint8_t *)pFromUArgs->target;
670 targetCapacity=(int32_t)(pFromUArgs->targetLimit-pFromUArgs->target);
671
672 /* get the converter state from the UTF-8 UConverter */
673 if(utf8->toULength > 0) {
674 toULength=oldToULength=utf8->toULength;
675 toULimit=(int8_t)utf8->mode;
676 c=(UChar32)utf8->toUnicodeStatus;
677 } else {
678 toULength=oldToULength=toULimit=0;
679 c = 0;
680 }
681
682 count=(int32_t)(sourceLimit-source)+oldToULength;
683 if(count<toULimit) {
684 /*
685 * Not enough input to complete the partial character.
686 * Jump to moreBytes below - it will not output to target.
687 */
688 } else if(targetCapacity<toULimit) {
689 /*
690 * Not enough target capacity to output the partial character.
691 * Let the standard converter handle this.
692 */
693 *pErrorCode=U_USING_DEFAULT_WARNING;
694 return;
695 } else {
696 // Use a single counter for source and target, counting the minimum of
697 // the source length and the target capacity.
698 // Let the standard converter handle edge cases.
699 if(count>targetCapacity) {
700 count=targetCapacity;
701 }
702
703 // The conversion loop checks count>0 only once per character.
704 // If the buffer ends with a truncated sequence,
705 // then we reduce the count to stop before that,
706 // and collect the remaining bytes after the conversion loop.
707
708 // Do not go back into the bytes that will be read for finishing a partial
709 // sequence from the previous buffer.
710 int32_t length=count-toULength;
711 U8_TRUNCATE_IF_INCOMPLETE(source, 0, length);
712 count=toULength+length;
713 }
714
715 if(c!=0) {
716 utf8->toUnicodeStatus=0;
717 utf8->toULength=0;
718 goto moreBytes;
719 /* See note in ucnv_SBCSFromUTF8() about this goto. */
720 }
721
722 /* conversion loop */
723 while(count>0) {
724 b=*source++;
725 if(U8_IS_SINGLE(b)) {
726 /* convert ASCII */
727 *target++=b;
728 --count;
729 continue;
730 } else {
731 if(b>=0xe0) {
732 if( /* handle U+0800..U+FFFF inline */
733 b<0xf0 &&
734 U8_IS_VALID_LEAD3_AND_T1(b, t1=source[0]) &&
735 U8_IS_TRAIL(t2=source[1])
736 ) {
737 source+=2;
738 *target++=b;
739 *target++=t1;
740 *target++=t2;
741 count-=3;
742 continue;
743 }
744 } else {
745 if( /* handle U+0080..U+07FF inline */
746 b>=0xc2 &&
747 U8_IS_TRAIL(t1=*source)
748 ) {
749 ++source;
750 *target++=b;
751 *target++=t1;
752 count-=2;
753 continue;
754 }
755 }
756
757 /* handle "complicated" and error cases, and continuing partial characters */
758 oldToULength=0;
759 toULength=1;
760 toULimit=U8_COUNT_BYTES_NON_ASCII(b);
761 c=b;
762 moreBytes:
763 while(toULength<toULimit) {
764 if(source<sourceLimit) {
765 b=*source;
766 if(icu::UTF8::isValidTrail(c, b, toULength, toULimit)) {
767 ++source;
768 ++toULength;
769 c=(c<<6)+b;
770 } else {
771 break; /* sequence too short, stop with toULength<toULimit */
772 }
773 } else {
774 /* store the partial UTF-8 character, compatible with the regular UTF-8 converter */
775 source-=(toULength-oldToULength);
776 while(oldToULength<toULength) {
777 utf8->toUBytes[oldToULength++]=*source++;
778 }
779 utf8->toUnicodeStatus=c;
780 utf8->toULength=toULength;
781 utf8->mode=toULimit;
782 pToUArgs->source=(char *)source;
783 pFromUArgs->target=(char *)target;
784 return;
785 }
786 }
787
788 if(toULength!=toULimit) {
789 /* error handling: illegal UTF-8 byte sequence */
790 source-=(toULength-oldToULength);
791 while(oldToULength<toULength) {
792 utf8->toUBytes[oldToULength++]=*source++;
793 }
794 utf8->toULength=toULength;
795 pToUArgs->source=(char *)source;
796 pFromUArgs->target=(char *)target;
797 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
798 return;
799 }
800
801 /* copy the legal byte sequence to the target */
802 {
803 int8_t i;
804
805 for(i=0; i<oldToULength; ++i) {
806 *target++=utf8->toUBytes[i];
807 }
808 source-=(toULength-oldToULength);
809 for(; i<toULength; ++i) {
810 *target++=*source++;
811 }
812 count-=toULength;
813 }
814 }
815 }
816 U_ASSERT(count>=0);
817
818 if(U_SUCCESS(*pErrorCode) && source<sourceLimit) {
819 if(target==(const uint8_t *)pFromUArgs->targetLimit) {
820 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
821 } else {
822 b=*source;
823 toULimit=U8_COUNT_BYTES(b);
824 if(toULimit>(sourceLimit-source)) {
825 /* collect a truncated byte sequence */
826 toULength=0;
827 c=b;
828 for(;;) {
829 utf8->toUBytes[toULength++]=b;
830 if(++source==sourceLimit) {
831 /* partial byte sequence at end of source */
832 utf8->toUnicodeStatus=c;
833 utf8->toULength=toULength;
834 utf8->mode=toULimit;
835 break;
836 } else if(!icu::UTF8::isValidTrail(c, b=*source, toULength, toULimit)) {
837 utf8->toULength=toULength;
838 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
839 break;
840 }
841 c=(c<<6)+b;
842 }
843 } else {
844 /* partial-sequence target overflow: fall back to the pivoting implementation */
845 *pErrorCode=U_USING_DEFAULT_WARNING;
846 }
847 }
848 }
849
850 /* write back the updated pointers */
851 pToUArgs->source=(char *)source;
852 pFromUArgs->target=(char *)target;
853 }
854
855 U_CDECL_END
856
857 /* UTF-8 converter data ----------------------------------------------------- */
858
859 static const UConverterImpl _UTF8Impl={
860 UCNV_UTF8,
861
862 NULL,
863 NULL,
864
865 NULL,
866 NULL,
867 NULL,
868
869 ucnv_toUnicode_UTF8,
870 ucnv_toUnicode_UTF8_OFFSETS_LOGIC,
871 ucnv_fromUnicode_UTF8,
872 ucnv_fromUnicode_UTF8_OFFSETS_LOGIC,
873 ucnv_getNextUChar_UTF8,
874
875 NULL,
876 NULL,
877 NULL,
878 NULL,
879 ucnv_getNonSurrogateUnicodeSet,
880
881 ucnv_UTF8FromUTF8,
882 ucnv_UTF8FromUTF8
883 };
884
885 /* The 1208 CCSID refers to any version of Unicode of UTF-8 */
886 static const UConverterStaticData _UTF8StaticData={
887 sizeof(UConverterStaticData),
888 "UTF-8",
889 1208, UCNV_IBM, UCNV_UTF8,
890 1, 3, /* max 3 bytes per UChar from UTF-8 (4 bytes from surrogate _pair_) */
891 { 0xef, 0xbf, 0xbd, 0 },3,FALSE,FALSE,
892 0,
893 0,
894 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
895 };
896
897
898 const UConverterSharedData _UTF8Data=
899 UCNV_IMMUTABLE_SHARED_DATA_INITIALIZER(&_UTF8StaticData, &_UTF8Impl);
900
901 /* CESU-8 converter data ---------------------------------------------------- */
902
903 static const UConverterImpl _CESU8Impl={
904 UCNV_CESU8,
905
906 NULL,
907 NULL,
908
909 NULL,
910 NULL,
911 NULL,
912
913 ucnv_toUnicode_UTF8,
914 ucnv_toUnicode_UTF8_OFFSETS_LOGIC,
915 ucnv_fromUnicode_UTF8,
916 ucnv_fromUnicode_UTF8_OFFSETS_LOGIC,
917 NULL,
918
919 NULL,
920 NULL,
921 NULL,
922 NULL,
923 ucnv_getCompleteUnicodeSet,
924
925 NULL,
926 NULL
927 };
928
929 static const UConverterStaticData _CESU8StaticData={
930 sizeof(UConverterStaticData),
931 "CESU-8",
932 9400, /* CCSID for CESU-8 */
933 UCNV_UNKNOWN, UCNV_CESU8, 1, 3,
934 { 0xef, 0xbf, 0xbd, 0 },3,FALSE,FALSE,
935 0,
936 0,
937 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
938 };
939
940
941 const UConverterSharedData _CESU8Data=
942 UCNV_IMMUTABLE_SHARED_DATA_INITIALIZER(&_CESU8StaticData, &_CESU8Impl);
943
944 #endif
945