• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2001-2004 Unicode, Inc.
3  *
4  * Disclaimer
5  *
6  * This source code is provided as is by Unicode, Inc. No claims are
7  * made as to fitness for any particular purpose. No warranties of any
8  * kind are expressed or implied. The recipient agrees to determine
9  * applicability of information provided. If this file has been
10  * purchased on magnetic or optical media from Unicode, Inc., the
11  * sole remedy for any claim will be exchange of defective media
12  * within 90 days of receipt.
13  *
14  * Limitations on Rights to Redistribute This Code
15  *
16  * Unicode, Inc. hereby grants the right to freely use the information
17  * supplied in this file in the creation of products supporting the
18  * Unicode Standard, and to make copies of this file in any form
19  * for internal or external distribution as long as this notice
20  * remains attached.
21  */
22 
23 /* ---------------------------------------------------------------------
24 
25     Conversions between UTF32, UTF-16, and UTF-8. Source code file.
26     Author: Mark E. Davis, 1994.
27     Rev History: Rick McGowan, fixes & updates May 2001.
28     Sept 2001: fixed const & error conditions per
29 	mods suggested by S. Parent & A. Lillich.
30     June 2002: Tim Dodd added detection and handling of incomplete
31 	source sequences, enhanced error detection, added casts
32 	to eliminate compiler warnings.
33     July 2003: slight mods to back out aggressive FFFE detection.
34     Jan 2004: updated switches in from-UTF8 conversions.
35     Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
36 
37     See the header file "ConvertUTF.h" for complete documentation.
38 
39 ------------------------------------------------------------------------ */
40 
41 
42 #include "antlr3convertutf.h"
43 
44 #ifdef CVTUTF_DEBUG
45 #include <stdio.h>
46 #endif
47 
48 
49 
50 /* --------------------------------------------------------------------- */
51 
ConvertUTF32toUTF16(const UTF32 ** sourceStart,const UTF32 * sourceEnd,UTF16 ** targetStart,UTF16 * targetEnd,ConversionFlags flags)52 ConversionResult ConvertUTF32toUTF16 (
53 	const UTF32** sourceStart, const UTF32* sourceEnd,
54 	UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
55     ConversionResult result = conversionOK;
56     const UTF32* source = *sourceStart;
57     UTF16* target = *targetStart;
58     while (source < sourceEnd) {
59 	UTF32 ch;
60 	if (target >= targetEnd) {
61 	    result = targetExhausted; break;
62 	}
63 	ch = *source++;
64 	if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
65 	    /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
66 	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
67 		if (flags == strictConversion) {
68 		    --source; /* return to the illegal value itself */
69 		    result = sourceIllegal;
70 		    break;
71 		} else {
72 		    *target++ = UNI_REPLACEMENT_CHAR;
73 		}
74 	    } else {
75 		*target++ = (UTF16)ch; /* normal case */
76 	    }
77 	} else if (ch > UNI_MAX_LEGAL_UTF32) {
78 	    if (flags == strictConversion) {
79 		result = sourceIllegal;
80 	    } else {
81 		*target++ = UNI_REPLACEMENT_CHAR;
82 	    }
83 	} else {
84 	    /* target is a character in range 0xFFFF - 0x10FFFF. */
85 	    if (target + 1 >= targetEnd) {
86 		--source; /* Back up source pointer! */
87 		result = targetExhausted; break;
88 	    }
89 	    ch -= halfBase;
90 	    *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
91 	    *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
92 	}
93     }
94     *sourceStart = source;
95     *targetStart = target;
96     return result;
97 }
98 
99 /* --------------------------------------------------------------------- */
100 
ConvertUTF16toUTF32(const UTF16 ** sourceStart,const UTF16 * sourceEnd,UTF32 ** targetStart,UTF32 * targetEnd,ConversionFlags flags)101 ConversionResult ConvertUTF16toUTF32 (
102 	const UTF16** sourceStart, const UTF16* sourceEnd,
103 	UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
104     ConversionResult result = conversionOK;
105     const UTF16* source = *sourceStart;
106     UTF32* target = *targetStart;
107     UTF32 ch, ch2;
108     while (source < sourceEnd) {
109 	const UTF16* oldSource = source; /*  In case we have to back up because of target overflow. */
110 	ch = *source++;
111 	/* If we have a surrogate pair, convert to UTF32 first. */
112 	if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
113 	    /* If the 16 bits following the high surrogate are in the source buffer... */
114 	    if (source < sourceEnd) {
115 		ch2 = *source;
116 		/* If it's a low surrogate, convert to UTF32. */
117 		if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
118 		    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
119 			+ (ch2 - UNI_SUR_LOW_START) + halfBase;
120 		    ++source;
121 		} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
122 		    --source; /* return to the illegal value itself */
123 		    result = sourceIllegal;
124 		    break;
125 		}
126 	    } else { /* We don't have the 16 bits following the high surrogate. */
127 		--source; /* return to the high surrogate */
128 		result = sourceExhausted;
129 		break;
130 	    }
131 	} else if (flags == strictConversion) {
132 	    /* UTF-16 surrogate values are illegal in UTF-32 */
133 	    if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
134 		--source; /* return to the illegal value itself */
135 		result = sourceIllegal;
136 		break;
137 	    }
138 	}
139 	if (target >= targetEnd) {
140 	    source = oldSource; /* Back up source pointer! */
141 	    result = targetExhausted; break;
142 	}
143 	*target++ = ch;
144     }
145     *sourceStart = source;
146     *targetStart = target;
147 #ifdef CVTUTF_DEBUG
148 if (result == sourceIllegal) {
149     ANTLR3_FPRINTF(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
150     fflush(stderr);
151 }
152 #endif
153     return result;
154 }
155 
156 /* --------------------------------------------------------------------- */
157 
158 /*
159  * Index into the table below with the first byte of a UTF-8 sequence to
160  * get the number of trailing bytes that are supposed to follow it.
161  * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
162  * left as-is for anyone who may want to do such conversion, which was
163  * allowed in earlier algorithms.
164  */
165 static const char trailingBytesForUTF8[256] = {
166     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
167     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
168     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
169     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
170     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
171     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
172     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
173     2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
174 };
175 
176 /*
177  * Magic values subtracted from a buffer value during UTF8 conversion.
178  * This table contains as many values as there might be trailing bytes
179  * in a UTF-8 sequence.
180  */
181 static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
182 		     0x03C82080UL, 0xFA082080UL, 0x82082080UL };
183 
184 /*
185  * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
186  * into the first byte, depending on how many bytes follow.  There are
187  * as many entries in this table as there are UTF-8 sequence types.
188  * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
189  * for *legal* UTF-8 will be 4 or fewer bytes total.
190  */
191 static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
192 
193 /* --------------------------------------------------------------------- */
194 
195 /* The interface converts a whole buffer to avoid function-call overhead.
196  * Constants have been gathered. Loops & conditionals have been removed as
197  * much as possible for efficiency, in favor of drop-through switches.
198  * (See "Note A" at the bottom of the file for equivalent code.)
199  * If your compiler supports it, the "isLegalUTF8" call can be turned
200  * into an inline function.
201  */
202 
203 /* --------------------------------------------------------------------- */
204 
ConvertUTF16toUTF8(const UTF16 ** sourceStart,const UTF16 * sourceEnd,UTF8 ** targetStart,UTF8 * targetEnd,ConversionFlags flags)205 ConversionResult ConvertUTF16toUTF8 (
206 	const UTF16** sourceStart, const UTF16* sourceEnd,
207 	UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
208     ConversionResult result = conversionOK;
209     const UTF16* source = *sourceStart;
210     UTF8* target = *targetStart;
211     while (source < sourceEnd) {
212 	UTF32 ch;
213 	unsigned short bytesToWrite = 0;
214 	const UTF32 byteMask = 0xBF;
215 	const UTF32 byteMark = 0x80;
216 	const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
217 	ch = *source++;
218 	/* If we have a surrogate pair, convert to UTF32 first. */
219 	if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
220 	    /* If the 16 bits following the high surrogate are in the source buffer... */
221 	    if (source < sourceEnd) {
222 		UTF32 ch2 = *source;
223 		/* If it's a low surrogate, convert to UTF32. */
224 		if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
225 		    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
226 			+ (ch2 - UNI_SUR_LOW_START) + halfBase;
227 		    ++source;
228 		} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
229 		    --source; /* return to the illegal value itself */
230 		    result = sourceIllegal;
231 		    break;
232 		}
233 	    } else { /* We don't have the 16 bits following the high surrogate. */
234 		--source; /* return to the high surrogate */
235 		result = sourceExhausted;
236 		break;
237 	    }
238         } else if (flags == strictConversion) {
239 	    /* UTF-16 surrogate values are illegal in UTF-32 */
240 	    if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
241 		--source; /* return to the illegal value itself */
242 		result = sourceIllegal;
243 		break;
244 	    }
245 	}
246 	/* Figure out how many bytes the result will require */
247 	if (ch < (UTF32)0x80) {	     bytesToWrite = 1;
248 	} else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
249 	} else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
250 	} else if (ch < (UTF32)0x110000) {  bytesToWrite = 4;
251 	} else {			    bytesToWrite = 3;
252 					    ch = UNI_REPLACEMENT_CHAR;
253 	}
254 
255 	target += bytesToWrite;
256 	if (target > targetEnd) {
257 	    source = oldSource; /* Back up source pointer! */
258 	    target -= bytesToWrite; result = targetExhausted; break;
259 	}
260 	switch (bytesToWrite) { /* note: everything falls through. */
261 	    case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
262 	    case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
263 	    case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
264 	    case 1: *--target =  (UTF8)(ch | firstByteMark[bytesToWrite]);
265 	}
266 	target += bytesToWrite;
267     }
268     *sourceStart = source;
269     *targetStart = target;
270     return result;
271 }
272 
273 /* --------------------------------------------------------------------- */
274 
275 /*
276  * Utility routine to tell whether a sequence of bytes is legal UTF-8.
277  * This must be called with the length pre-determined by the first byte.
278  * If not calling this from ConvertUTF8to*, then the length can be set by:
279  *  length = trailingBytesForUTF8[*source]+1;
280  * and the sequence is illegal right away if there aren't that many bytes
281  * available.
282  * If presented with a length > 4, this returns false.  The Unicode
283  * definition of UTF-8 goes up to 4-byte sequences.
284  */
285 
286 static ANTLR3_BOOLEAN
isLegalUTF8(const UTF8 * source,int length)287 isLegalUTF8(const UTF8 *source, int length) {
288     UTF8 a;
289     const UTF8 *srcptr = source+length;
290     switch (length) {
291     default: return ANTLR3_FALSE;
292 	/* Everything else falls through when "true"... */
293     case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return ANTLR3_FALSE;
294     case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return ANTLR3_FALSE;
295     case 2: if ((a = (*--srcptr)) > 0xBF) return ANTLR3_FALSE;
296 
297 	switch (*source) {
298 	    /* no fall-through in this inner switch */
299 	    case 0xE0: if (a < 0xA0) return ANTLR3_FALSE; break;
300 	    case 0xED: if (a > 0x9F) return ANTLR3_FALSE; break;
301 	    case 0xF0: if (a < 0x90) return ANTLR3_FALSE; break;
302 	    case 0xF4: if (a > 0x8F) return ANTLR3_FALSE; break;
303 	    default:   if (a < 0x80) return ANTLR3_FALSE;
304 	}
305 
306     case 1: if (*source >= 0x80 && *source < 0xC2) return ANTLR3_FALSE;
307     }
308     if (*source > 0xF4) return ANTLR3_FALSE;
309     return ANTLR3_TRUE;
310 }
311 
312 /* --------------------------------------------------------------------- */
313 
314 /*
315  * Exported function to return whether a UTF-8 sequence is legal or not.
316  * This is not used here; it's just exported.
317  */
318 ANTLR3_BOOLEAN
isLegalUTF8Sequence(const UTF8 * source,const UTF8 * sourceEnd)319 isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
320     int length = trailingBytesForUTF8[*source]+1;
321     if (source+length > sourceEnd) {
322 	return ANTLR3_FALSE;
323     }
324     return isLegalUTF8(source, length);
325 }
326 
327 /* --------------------------------------------------------------------- */
328 
ConvertUTF8toUTF16(const UTF8 ** sourceStart,const UTF8 * sourceEnd,UTF16 ** targetStart,UTF16 * targetEnd,ConversionFlags flags)329 ConversionResult ConvertUTF8toUTF16 (
330 	const UTF8** sourceStart, const UTF8* sourceEnd,
331 	UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
332     ConversionResult result = conversionOK;
333     const UTF8* source = *sourceStart;
334     UTF16* target = *targetStart;
335     while (source < sourceEnd) {
336 	UTF32 ch = 0;
337 	unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
338 	if (source + extraBytesToRead >= sourceEnd) {
339 	    result = sourceExhausted; break;
340 	}
341 	/* Do this check whether lenient or strict */
342 	if (! isLegalUTF8(source, extraBytesToRead+1)) {
343 	    result = sourceIllegal;
344 	    break;
345 	}
346 	/*
347 	 * The cases all fall through. See "Note A" below.
348 	 */
349 	switch (extraBytesToRead) {
350 	    case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
351 	    case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
352 	    case 3: ch += *source++; ch <<= 6;
353 	    case 2: ch += *source++; ch <<= 6;
354 	    case 1: ch += *source++; ch <<= 6;
355 	    case 0: ch += *source++;
356 	}
357 	ch -= offsetsFromUTF8[extraBytesToRead];
358 
359 	if (target >= targetEnd) {
360 	    source -= (extraBytesToRead+1); /* Back up source pointer! */
361 	    result = targetExhausted; break;
362 	}
363 	if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
364 	    /* UTF-16 surrogate values are illegal in UTF-32 */
365 	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
366 		if (flags == strictConversion) {
367 		    source -= (extraBytesToRead+1); /* return to the illegal value itself */
368 		    result = sourceIllegal;
369 		    break;
370 		} else {
371 		    *target++ = UNI_REPLACEMENT_CHAR;
372 		}
373 	    } else {
374 		*target++ = (UTF16)ch; /* normal case */
375 	    }
376 	} else if (ch > UNI_MAX_UTF16) {
377 	    if (flags == strictConversion) {
378 		result = sourceIllegal;
379 		source -= (extraBytesToRead+1); /* return to the start */
380 		break; /* Bail out; shouldn't continue */
381 	    } else {
382 		*target++ = UNI_REPLACEMENT_CHAR;
383 	    }
384 	} else {
385 	    /* target is a character in range 0xFFFF - 0x10FFFF. */
386 	    if (target + 1 >= targetEnd) {
387 		source -= (extraBytesToRead+1); /* Back up source pointer! */
388 		result = targetExhausted; break;
389 	    }
390 	    ch -= halfBase;
391 	    *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
392 	    *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
393 	}
394     }
395     *sourceStart = source;
396     *targetStart = target;
397     return result;
398 }
399 
400 /* --------------------------------------------------------------------- */
401 
ConvertUTF32toUTF8(const UTF32 ** sourceStart,const UTF32 * sourceEnd,UTF8 ** targetStart,UTF8 * targetEnd,ConversionFlags flags)402 ConversionResult ConvertUTF32toUTF8 (
403 	const UTF32** sourceStart, const UTF32* sourceEnd,
404 	UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
405     ConversionResult result = conversionOK;
406     const UTF32* source = *sourceStart;
407     UTF8* target = *targetStart;
408     while (source < sourceEnd) {
409 	UTF32 ch;
410 	unsigned short bytesToWrite = 0;
411 	const UTF32 byteMask = 0xBF;
412 	const UTF32 byteMark = 0x80;
413 	ch = *source++;
414 	if (flags == strictConversion ) {
415 	    /* UTF-16 surrogate values are illegal in UTF-32 */
416 	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
417 		--source; /* return to the illegal value itself */
418 		result = sourceIllegal;
419 		break;
420 	    }
421 	}
422 	/*
423 	 * Figure out how many bytes the result will require. Turn any
424 	 * illegally large UTF32 things (> Plane 17) into replacement chars.
425 	 */
426 	if (ch < (UTF32)0x80) {	     bytesToWrite = 1;
427 	} else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
428 	} else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
429 	} else if (ch <= UNI_MAX_LEGAL_UTF32) {  bytesToWrite = 4;
430 	} else {			    bytesToWrite = 3;
431 					    ch = UNI_REPLACEMENT_CHAR;
432 					    result = sourceIllegal;
433 	}
434 
435 	target += bytesToWrite;
436 	if (target > targetEnd) {
437 	    --source; /* Back up source pointer! */
438 	    target -= bytesToWrite; result = targetExhausted; break;
439 	}
440 	switch (bytesToWrite) { /* note: everything falls through. */
441 	    case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
442 	    case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
443 	    case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
444 	    case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
445 	}
446 	target += bytesToWrite;
447     }
448     *sourceStart = source;
449     *targetStart = target;
450     return result;
451 }
452 
453 /* --------------------------------------------------------------------- */
454 
ConvertUTF8toUTF32(const UTF8 ** sourceStart,const UTF8 * sourceEnd,UTF32 ** targetStart,UTF32 * targetEnd,ConversionFlags flags)455 ConversionResult ConvertUTF8toUTF32 (
456 	const UTF8** sourceStart, const UTF8* sourceEnd,
457 	UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
458     ConversionResult result = conversionOK;
459     const UTF8* source = *sourceStart;
460     UTF32* target = *targetStart;
461     while (source < sourceEnd) {
462 	UTF32 ch = 0;
463 	unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
464 	if (source + extraBytesToRead >= sourceEnd) {
465 	    result = sourceExhausted; break;
466 	}
467 	/* Do this check whether lenient or strict */
468 	if (! isLegalUTF8(source, extraBytesToRead+1)) {
469 	    result = sourceIllegal;
470 	    break;
471 	}
472 	/*
473 	 * The cases all fall through. See "Note A" below.
474 	 */
475 	switch (extraBytesToRead) {
476 	    case 5: ch += *source++; ch <<= 6;
477 	    case 4: ch += *source++; ch <<= 6;
478 	    case 3: ch += *source++; ch <<= 6;
479 	    case 2: ch += *source++; ch <<= 6;
480 	    case 1: ch += *source++; ch <<= 6;
481 	    case 0: ch += *source++;
482 	}
483 	ch -= offsetsFromUTF8[extraBytesToRead];
484 
485 	if (target >= targetEnd) {
486 	    source -= (extraBytesToRead+1); /* Back up the source pointer! */
487 	    result = targetExhausted; break;
488 	}
489 	if (ch <= UNI_MAX_LEGAL_UTF32) {
490 	    /*
491 	     * UTF-16 surrogate values are illegal in UTF-32, and anything
492 	     * over Plane 17 (> 0x10FFFF) is illegal.
493 	     */
494 	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
495 		if (flags == strictConversion) {
496 		    source -= (extraBytesToRead+1); /* return to the illegal value itself */
497 		    result = sourceIllegal;
498 		    break;
499 		} else {
500 		    *target++ = UNI_REPLACEMENT_CHAR;
501 		}
502 	    } else {
503 		*target++ = ch;
504 	    }
505 	} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
506 	    result = sourceIllegal;
507 	    *target++ = UNI_REPLACEMENT_CHAR;
508 	}
509     }
510     *sourceStart = source;
511     *targetStart = target;
512     return result;
513 }
514 
515 /* ---------------------------------------------------------------------
516 
517     Note A.
518     The fall-through switches in UTF-8 reading code save a
519     temp variable, some decrements & conditionals.  The switches
520     are equivalent to the following loop:
521 	{
522 	    int tmpBytesToRead = extraBytesToRead+1;
523 	    do {
524 		ch += *source++;
525 		--tmpBytesToRead;
526 		if (tmpBytesToRead) ch <<= 6;
527 	    } while (tmpBytesToRead > 0);
528 	}
529     In UTF-8 writing code, the switches on "bytesToWrite" are
530     similarly unrolled loops.
531 
532    --------------------------------------------------------------------- */
533