]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/ucnvscsu.c
ICU-551.30.tar.gz
[apple/icu.git] / icuSources / common / ucnvscsu.c
CommitLineData
b75a7d8f
A
1/*
2******************************************************************************
3*
b331163b 4* Copyright (C) 2000-2015, International Business Machines
b75a7d8f
A
5* Corporation and others. All Rights Reserved.
6*
7******************************************************************************
8* file name: ucnvscsu.c
9* encoding: US-ASCII
10* tab size: 8 (not used)
11* indentation:4
12*
13* created on: 2000nov18
14* created by: Markus W. Scherer
15*
16* This is an implementation of the Standard Compression Scheme for Unicode
17* as defined in http://www.unicode.org/unicode/reports/tr6/ .
18* Reserved commands and window settings are treated as illegal sequences and
19* will result in callback calls.
20*/
21
22#include "unicode/utypes.h"
374ca955 23
b331163b 24#if !UCONFIG_NO_CONVERSION && !UCONFIG_ONLY_HTML_CONVERSION
374ca955 25
b75a7d8f
A
26#include "unicode/ucnv.h"
27#include "unicode/ucnv_cb.h"
4388f060 28#include "unicode/utf16.h"
b75a7d8f
A
29#include "ucnv_bld.h"
30#include "ucnv_cnv.h"
31#include "cmemory.h"
32
33/* SCSU definitions --------------------------------------------------------- */
34
35/* SCSU command byte values */
36enum {
37 SQ0=0x01, /* Quote from window pair 0 */
38 SQ7=0x08, /* Quote from window pair 7 */
39 SDX=0x0B, /* Define a window as extended */
40 Srs=0x0C, /* reserved */
41 SQU=0x0E, /* Quote a single Unicode character */
42 SCU=0x0F, /* Change to Unicode mode */
43 SC0=0x10, /* Select window 0 */
44 SC7=0x17, /* Select window 7 */
45 SD0=0x18, /* Define and select window 0 */
46 SD7=0x1F, /* Define and select window 7 */
47
48 UC0=0xE0, /* Select window 0 */
49 UC7=0xE7, /* Select window 7 */
50 UD0=0xE8, /* Define and select window 0 */
51 UD7=0xEF, /* Define and select window 7 */
52 UQU=0xF0, /* Quote a single Unicode character */
53 UDX=0xF1, /* Define a Window as extended */
54 Urs=0xF2 /* reserved */
55};
56
57enum {
58 /*
59 * Unicode code points from 3400 to E000 are not adressible by
60 * dynamic window, since in these areas no short run alphabets are
61 * found. Therefore add gapOffset to all values from gapThreshold.
62 */
63 gapThreshold=0x68,
64 gapOffset=0xAC00,
65
66 /* values between reservedStart and fixedThreshold are reserved */
67 reservedStart=0xA8,
68
69 /* use table of predefined fixed offsets for values from fixedThreshold */
70 fixedThreshold=0xF9
71};
72
73/* constant offsets for the 8 static windows */
74static const uint32_t staticOffsets[8]={
75 0x0000, /* ASCII for quoted tags */
76 0x0080, /* Latin - 1 Supplement (for access to punctuation) */
77 0x0100, /* Latin Extended-A */
78 0x0300, /* Combining Diacritical Marks */
79 0x2000, /* General Punctuation */
80 0x2080, /* Currency Symbols */
81 0x2100, /* Letterlike Symbols and Number Forms */
82 0x3000 /* CJK Symbols and punctuation */
83};
84
85/* initial offsets for the 8 dynamic (sliding) windows */
86static const uint32_t initialDynamicOffsets[8]={
87 0x0080, /* Latin-1 */
88 0x00C0, /* Latin Extended A */
89 0x0400, /* Cyrillic */
90 0x0600, /* Arabic */
91 0x0900, /* Devanagari */
92 0x3040, /* Hiragana */
93 0x30A0, /* Katakana */
94 0xFF00 /* Fullwidth ASCII */
95};
96
97/* Table of fixed predefined Offsets */
98static const uint32_t fixedOffsets[]={
99 /* 0xF9 */ 0x00C0, /* Latin-1 Letters + half of Latin Extended A */
100 /* 0xFA */ 0x0250, /* IPA extensions */
101 /* 0xFB */ 0x0370, /* Greek */
102 /* 0xFC */ 0x0530, /* Armenian */
103 /* 0xFD */ 0x3040, /* Hiragana */
104 /* 0xFE */ 0x30A0, /* Katakana */
105 /* 0xFF */ 0xFF60 /* Halfwidth Katakana */
106};
107
108/* state values */
109enum {
110 readCommand,
111 quotePairOne,
112 quotePairTwo,
113 quoteOne,
114 definePairOne,
115 definePairTwo,
116 defineOne
117};
118
119typedef struct SCSUData {
120 /* dynamic window offsets, intitialize to default values from initialDynamicOffsets */
121 uint32_t toUDynamicOffsets[8];
122 uint32_t fromUDynamicOffsets[8];
123
124 /* state machine state - toUnicode */
125 UBool toUIsSingleByteMode;
126 uint8_t toUState;
127 int8_t toUQuoteWindow, toUDynamicWindow;
128 uint8_t toUByteOne;
129 uint8_t toUPadding[3];
130
131 /* state machine state - fromUnicode */
132 UBool fromUIsSingleByteMode;
133 int8_t fromUDynamicWindow;
134
135 /*
136 * windowUse[] keeps track of the use of the dynamic windows:
137 * At nextWindowUseIndex there is the least recently used window,
138 * and the following windows (in a wrapping manner) are more and more
139 * recently used.
140 * At nextWindowUseIndex-1 there is the most recently used window.
141 */
142 uint8_t locale;
143 int8_t nextWindowUseIndex;
144 int8_t windowUse[8];
145} SCSUData;
146
147static const int8_t initialWindowUse[8]={ 7, 0, 3, 2, 4, 5, 6, 1 };
148static const int8_t initialWindowUse_ja[8]={ 3, 2, 4, 1, 0, 7, 5, 6 };
149
150enum {
151 lGeneric, l_ja
152};
153
154/* SCSU setup functions ----------------------------------------------------- */
155
156static void
157_SCSUReset(UConverter *cnv, UConverterResetChoice choice) {
158 SCSUData *scsu=(SCSUData *)cnv->extraInfo;
159
160 if(choice<=UCNV_RESET_TO_UNICODE) {
161 /* reset toUnicode */
162 uprv_memcpy(scsu->toUDynamicOffsets, initialDynamicOffsets, 32);
163
164 scsu->toUIsSingleByteMode=TRUE;
165 scsu->toUState=readCommand;
166 scsu->toUQuoteWindow=scsu->toUDynamicWindow=0;
167 scsu->toUByteOne=0;
168
169 cnv->toULength=0;
170 }
171 if(choice!=UCNV_RESET_TO_UNICODE) {
172 /* reset fromUnicode */
173 uprv_memcpy(scsu->fromUDynamicOffsets, initialDynamicOffsets, 32);
174
175 scsu->fromUIsSingleByteMode=TRUE;
176 scsu->fromUDynamicWindow=0;
177
178 scsu->nextWindowUseIndex=0;
179 switch(scsu->locale) {
180 case l_ja:
181 uprv_memcpy(scsu->windowUse, initialWindowUse_ja, 8);
182 break;
183 default:
184 uprv_memcpy(scsu->windowUse, initialWindowUse, 8);
185 break;
186 }
187
374ca955 188 cnv->fromUChar32=0;
b75a7d8f
A
189 }
190}
191
192static void
193_SCSUOpen(UConverter *cnv,
729e4ab9 194 UConverterLoadArgs *pArgs,
b75a7d8f 195 UErrorCode *pErrorCode) {
729e4ab9
A
196 const char *locale=pArgs->locale;
197 if(pArgs->onlyTestIsLoadable) {
198 return;
199 }
b75a7d8f
A
200 cnv->extraInfo=uprv_malloc(sizeof(SCSUData));
201 if(cnv->extraInfo!=NULL) {
202 if(locale!=NULL && locale[0]=='j' && locale[1]=='a' && (locale[2]==0 || locale[2]=='_')) {
203 ((SCSUData *)cnv->extraInfo)->locale=l_ja;
204 } else {
205 ((SCSUData *)cnv->extraInfo)->locale=lGeneric;
206 }
207 _SCSUReset(cnv, UCNV_RESET_BOTH);
208 } else {
209 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
210 }
73c04bcf
A
211
212 /* Set the substitution character U+fffd as a Unicode string. */
213 cnv->subUChars[0]=0xfffd;
214 cnv->subCharLen=-1;
b75a7d8f
A
215}
216
217static void
218_SCSUClose(UConverter *cnv) {
219 if(cnv->extraInfo!=NULL) {
220 if(!cnv->isExtraLocal) {
221 uprv_free(cnv->extraInfo);
222 }
223 cnv->extraInfo=NULL;
224 }
225}
226
227/* SCSU-to-Unicode conversion functions ------------------------------------- */
228
b75a7d8f
A
229static void
230_SCSUToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
231 UErrorCode *pErrorCode) {
232 UConverter *cnv;
233 SCSUData *scsu;
234 const uint8_t *source, *sourceLimit;
235 UChar *target;
236 const UChar *targetLimit;
237 int32_t *offsets;
238 UBool isSingleByteMode;
239 uint8_t state, byteOne;
240 int8_t quoteWindow, dynamicWindow;
241
242 int32_t sourceIndex, nextSourceIndex;
243
244 uint8_t b;
245
246 /* set up the local pointers */
247 cnv=pArgs->converter;
248 scsu=(SCSUData *)cnv->extraInfo;
249
250 source=(const uint8_t *)pArgs->source;
251 sourceLimit=(const uint8_t *)pArgs->sourceLimit;
252 target=pArgs->target;
253 targetLimit=pArgs->targetLimit;
254 offsets=pArgs->offsets;
255
256 /* get the state machine state */
257 isSingleByteMode=scsu->toUIsSingleByteMode;
258 state=scsu->toUState;
259 quoteWindow=scsu->toUQuoteWindow;
260 dynamicWindow=scsu->toUDynamicWindow;
261 byteOne=scsu->toUByteOne;
262
263 /* sourceIndex=-1 if the current character began in the previous buffer */
264 sourceIndex=state==readCommand ? 0 : -1;
265 nextSourceIndex=0;
266
267 /*
268 * conversion "loop"
269 *
270 * For performance, this is not a normal C loop.
271 * Instead, there are two code blocks for the two SCSU modes.
272 * The function branches to either one, and a change of the mode is done with a goto to
273 * the other branch.
274 *
275 * Each branch has two conventional loops:
276 * - a fast-path loop for the most common codes in the mode
277 * - a loop for all other codes in the mode
278 * When the fast-path runs into a code that it cannot handle, its loop ends and it
279 * runs into the following loop to handle the other codes.
280 * The end of the input or output buffer is also handled by the slower loop.
281 * The slow loop jumps (goto) to the fast-path loop again as soon as possible.
282 *
374ca955
A
283 * The callback handling is done by returning with an error code.
284 * The conversion framework actually calls the callback function.
b75a7d8f 285 */
b75a7d8f
A
286 if(isSingleByteMode) {
287 /* fast path for single-byte mode */
288 if(state==readCommand) {
289fastSingle:
290 while(source<sourceLimit && target<targetLimit && (b=*source)>=0x20) {
291 ++source;
292 ++nextSourceIndex;
293 if(b<=0x7f) {
294 /* write US-ASCII graphic character or DEL */
295 *target++=(UChar)b;
296 if(offsets!=NULL) {
297 *offsets++=sourceIndex;
298 }
299 } else {
300 /* write from dynamic window */
301 uint32_t c=scsu->toUDynamicOffsets[dynamicWindow]+(b&0x7f);
302 if(c<=0xffff) {
303 *target++=(UChar)c;
304 if(offsets!=NULL) {
305 *offsets++=sourceIndex;
306 }
307 } else {
308 /* output surrogate pair */
309 *target++=(UChar)(0xd7c0+(c>>10));
310 if(target<targetLimit) {
311 *target++=(UChar)(0xdc00|(c&0x3ff));
312 if(offsets!=NULL) {
313 *offsets++=sourceIndex;
314 *offsets++=sourceIndex;
315 }
316 } else {
317 /* target overflow */
318 if(offsets!=NULL) {
319 *offsets++=sourceIndex;
320 }
321 cnv->UCharErrorBuffer[0]=(UChar)(0xdc00|(c&0x3ff));
322 cnv->UCharErrorBufferLength=1;
323 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
324 goto endloop;
325 }
326 }
327 }
328 sourceIndex=nextSourceIndex;
329 }
330 }
331
332 /* normal state machine for single-byte mode, minus handling for what fastSingle covers */
333singleByteMode:
334 while(source<sourceLimit) {
335 if(target>=targetLimit) {
336 /* target is full */
337 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
338 break;
339 }
340 b=*source++;
341 ++nextSourceIndex;
342 switch(state) {
343 case readCommand:
344 /* redundant conditions are commented out */
345 /* here: b<0x20 because otherwise we would be in fastSingle */
346 if((1UL<<b)&0x2601 /* binary 0010 0110 0000 0001, check for b==0xd || b==0xa || b==9 || b==0 */) {
347 /* CR/LF/TAB/NUL */
348 *target++=(UChar)b;
349 if(offsets!=NULL) {
350 *offsets++=sourceIndex;
351 }
352 sourceIndex=nextSourceIndex;
353 goto fastSingle;
354 } else if(SC0<=b) {
355 if(b<=SC7) {
356 dynamicWindow=(int8_t)(b-SC0);
357 sourceIndex=nextSourceIndex;
358 goto fastSingle;
359 } else /* if(SD0<=b && b<=SD7) */ {
360 dynamicWindow=(int8_t)(b-SD0);
361 state=defineOne;
362 }
363 } else if(/* SQ0<=b && */ b<=SQ7) {
364 quoteWindow=(int8_t)(b-SQ0);
365 state=quoteOne;
366 } else if(b==SDX) {
367 state=definePairOne;
368 } else if(b==SQU) {
369 state=quotePairOne;
370 } else if(b==SCU) {
371 sourceIndex=nextSourceIndex;
372 isSingleByteMode=FALSE;
373 goto fastUnicode;
374 } else /* Srs */ {
375 /* callback(illegal) */
374ca955
A
376 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
377 cnv->toUBytes[0]=b;
378 cnv->toULength=1;
379 goto endloop;
b75a7d8f 380 }
374ca955
A
381
382 /* store the first byte of a multibyte sequence in toUBytes[] */
383 cnv->toUBytes[0]=b;
384 cnv->toULength=1;
b75a7d8f
A
385 break;
386 case quotePairOne:
387 byteOne=b;
374ca955
A
388 cnv->toUBytes[1]=b;
389 cnv->toULength=2;
b75a7d8f
A
390 state=quotePairTwo;
391 break;
392 case quotePairTwo:
393 *target++=(UChar)((byteOne<<8)|b);
394 if(offsets!=NULL) {
395 *offsets++=sourceIndex;
396 }
397 sourceIndex=nextSourceIndex;
398 state=readCommand;
399 goto fastSingle;
400 case quoteOne:
401 if(b<0x80) {
402 /* all static offsets are in the BMP */
403 *target++=(UChar)(staticOffsets[quoteWindow]+b);
404 if(offsets!=NULL) {
405 *offsets++=sourceIndex;
406 }
407 } else {
408 /* write from dynamic window */
409 uint32_t c=scsu->toUDynamicOffsets[quoteWindow]+(b&0x7f);
410 if(c<=0xffff) {
411 *target++=(UChar)c;
412 if(offsets!=NULL) {
413 *offsets++=sourceIndex;
414 }
415 } else {
416 /* output surrogate pair */
417 *target++=(UChar)(0xd7c0+(c>>10));
418 if(target<targetLimit) {
419 *target++=(UChar)(0xdc00|(c&0x3ff));
420 if(offsets!=NULL) {
421 *offsets++=sourceIndex;
422 *offsets++=sourceIndex;
423 }
424 } else {
425 /* target overflow */
426 if(offsets!=NULL) {
427 *offsets++=sourceIndex;
428 }
429 cnv->UCharErrorBuffer[0]=(UChar)(0xdc00|(c&0x3ff));
430 cnv->UCharErrorBufferLength=1;
431 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
432 goto endloop;
433 }
434 }
435 }
436 sourceIndex=nextSourceIndex;
437 state=readCommand;
438 goto fastSingle;
439 case definePairOne:
440 dynamicWindow=(int8_t)((b>>5)&7);
441 byteOne=(uint8_t)(b&0x1f);
374ca955
A
442 cnv->toUBytes[1]=b;
443 cnv->toULength=2;
b75a7d8f
A
444 state=definePairTwo;
445 break;
446 case definePairTwo:
447 scsu->toUDynamicOffsets[dynamicWindow]=0x10000+(byteOne<<15UL | b<<7UL);
448 sourceIndex=nextSourceIndex;
449 state=readCommand;
450 goto fastSingle;
451 case defineOne:
452 if(b==0) {
453 /* callback(illegal): Reserved window offset value 0 */
374ca955
A
454 cnv->toUBytes[1]=b;
455 cnv->toULength=2;
456 goto endloop;
b75a7d8f
A
457 } else if(b<gapThreshold) {
458 scsu->toUDynamicOffsets[dynamicWindow]=b<<7UL;
459 } else if((uint8_t)(b-gapThreshold)<(reservedStart-gapThreshold)) {
460 scsu->toUDynamicOffsets[dynamicWindow]=(b<<7UL)+gapOffset;
461 } else if(b>=fixedThreshold) {
462 scsu->toUDynamicOffsets[dynamicWindow]=fixedOffsets[b-fixedThreshold];
463 } else {
464 /* callback(illegal): Reserved window offset value 0xa8..0xf8 */
374ca955
A
465 cnv->toUBytes[1]=b;
466 cnv->toULength=2;
467 goto endloop;
b75a7d8f
A
468 }
469 sourceIndex=nextSourceIndex;
470 state=readCommand;
471 goto fastSingle;
472 }
473 }
474 } else {
475 /* fast path for Unicode mode */
476 if(state==readCommand) {
477fastUnicode:
478 while(source+1<sourceLimit && target<targetLimit && (uint8_t)((b=*source)-UC0)>(Urs-UC0)) {
479 *target++=(UChar)((b<<8)|source[1]);
480 if(offsets!=NULL) {
481 *offsets++=sourceIndex;
482 }
483 sourceIndex=nextSourceIndex;
484 nextSourceIndex+=2;
485 source+=2;
486 }
487 }
488
489 /* normal state machine for Unicode mode */
490/* unicodeByteMode: */
491 while(source<sourceLimit) {
492 if(target>=targetLimit) {
493 /* target is full */
494 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
495 break;
496 }
497 b=*source++;
498 ++nextSourceIndex;
499 switch(state) {
500 case readCommand:
501 if((uint8_t)(b-UC0)>(Urs-UC0)) {
502 byteOne=b;
374ca955
A
503 cnv->toUBytes[0]=b;
504 cnv->toULength=1;
b75a7d8f
A
505 state=quotePairTwo;
506 } else if(/* UC0<=b && */ b<=UC7) {
507 dynamicWindow=(int8_t)(b-UC0);
508 sourceIndex=nextSourceIndex;
509 isSingleByteMode=TRUE;
510 goto fastSingle;
511 } else if(/* UD0<=b && */ b<=UD7) {
512 dynamicWindow=(int8_t)(b-UD0);
513 isSingleByteMode=TRUE;
374ca955
A
514 cnv->toUBytes[0]=b;
515 cnv->toULength=1;
b75a7d8f
A
516 state=defineOne;
517 goto singleByteMode;
518 } else if(b==UDX) {
519 isSingleByteMode=TRUE;
374ca955
A
520 cnv->toUBytes[0]=b;
521 cnv->toULength=1;
b75a7d8f
A
522 state=definePairOne;
523 goto singleByteMode;
524 } else if(b==UQU) {
374ca955
A
525 cnv->toUBytes[0]=b;
526 cnv->toULength=1;
b75a7d8f
A
527 state=quotePairOne;
528 } else /* Urs */ {
529 /* callback(illegal) */
374ca955
A
530 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
531 cnv->toUBytes[0]=b;
532 cnv->toULength=1;
533 goto endloop;
b75a7d8f
A
534 }
535 break;
536 case quotePairOne:
537 byteOne=b;
374ca955
A
538 cnv->toUBytes[1]=b;
539 cnv->toULength=2;
b75a7d8f
A
540 state=quotePairTwo;
541 break;
542 case quotePairTwo:
543 *target++=(UChar)((byteOne<<8)|b);
544 if(offsets!=NULL) {
545 *offsets++=sourceIndex;
546 }
547 sourceIndex=nextSourceIndex;
548 state=readCommand;
549 goto fastUnicode;
550 }
551 }
552 }
553endloop:
554
374ca955
A
555 /* set the converter state back into UConverter */
556 if(U_FAILURE(*pErrorCode) && *pErrorCode!=U_BUFFER_OVERFLOW_ERROR) {
557 /* reset to deal with the next character */
558 state=readCommand;
559 } else if(state==readCommand) {
560 /* not in a multi-byte sequence, reset toULength */
561 cnv->toULength=0;
b75a7d8f 562 }
374ca955
A
563 scsu->toUIsSingleByteMode=isSingleByteMode;
564 scsu->toUState=state;
565 scsu->toUQuoteWindow=quoteWindow;
566 scsu->toUDynamicWindow=dynamicWindow;
567 scsu->toUByteOne=byteOne;
b75a7d8f 568
b75a7d8f
A
569 /* write back the updated pointers */
570 pArgs->source=(const char *)source;
571 pArgs->target=target;
572 pArgs->offsets=offsets;
573 return;
b75a7d8f
A
574}
575
576/*
577 * Identical to _SCSUToUnicodeWithOffsets but without offset handling.
578 * If a change is made in the original function, then either
579 * change this function the same way or
580 * re-copy the original function and remove the variables
581 * offsets, sourceIndex, and nextSourceIndex.
582 */
583static void
584_SCSUToUnicode(UConverterToUnicodeArgs *pArgs,
585 UErrorCode *pErrorCode) {
586 UConverter *cnv;
587 SCSUData *scsu;
588 const uint8_t *source, *sourceLimit;
589 UChar *target;
590 const UChar *targetLimit;
b75a7d8f
A
591 UBool isSingleByteMode;
592 uint8_t state, byteOne;
593 int8_t quoteWindow, dynamicWindow;
594
595 uint8_t b;
596
597 /* set up the local pointers */
598 cnv=pArgs->converter;
599 scsu=(SCSUData *)cnv->extraInfo;
600
601 source=(const uint8_t *)pArgs->source;
602 sourceLimit=(const uint8_t *)pArgs->sourceLimit;
603 target=pArgs->target;
604 targetLimit=pArgs->targetLimit;
605
606 /* get the state machine state */
607 isSingleByteMode=scsu->toUIsSingleByteMode;
608 state=scsu->toUState;
609 quoteWindow=scsu->toUQuoteWindow;
610 dynamicWindow=scsu->toUDynamicWindow;
611 byteOne=scsu->toUByteOne;
612
613 /*
614 * conversion "loop"
615 *
616 * For performance, this is not a normal C loop.
617 * Instead, there are two code blocks for the two SCSU modes.
618 * The function branches to either one, and a change of the mode is done with a goto to
619 * the other branch.
620 *
621 * Each branch has two conventional loops:
622 * - a fast-path loop for the most common codes in the mode
623 * - a loop for all other codes in the mode
624 * When the fast-path runs into a code that it cannot handle, its loop ends and it
625 * runs into the following loop to handle the other codes.
626 * The end of the input or output buffer is also handled by the slower loop.
627 * The slow loop jumps (goto) to the fast-path loop again as soon as possible.
628 *
374ca955
A
629 * The callback handling is done by returning with an error code.
630 * The conversion framework actually calls the callback function.
b75a7d8f 631 */
b75a7d8f
A
632 if(isSingleByteMode) {
633 /* fast path for single-byte mode */
634 if(state==readCommand) {
635fastSingle:
636 while(source<sourceLimit && target<targetLimit && (b=*source)>=0x20) {
637 ++source;
638 if(b<=0x7f) {
639 /* write US-ASCII graphic character or DEL */
640 *target++=(UChar)b;
641 } else {
642 /* write from dynamic window */
643 uint32_t c=scsu->toUDynamicOffsets[dynamicWindow]+(b&0x7f);
644 if(c<=0xffff) {
645 *target++=(UChar)c;
646 } else {
647 /* output surrogate pair */
648 *target++=(UChar)(0xd7c0+(c>>10));
649 if(target<targetLimit) {
650 *target++=(UChar)(0xdc00|(c&0x3ff));
651 } else {
652 /* target overflow */
653 cnv->UCharErrorBuffer[0]=(UChar)(0xdc00|(c&0x3ff));
654 cnv->UCharErrorBufferLength=1;
655 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
656 goto endloop;
657 }
658 }
659 }
660 }
661 }
662
663 /* normal state machine for single-byte mode, minus handling for what fastSingle covers */
664singleByteMode:
665 while(source<sourceLimit) {
666 if(target>=targetLimit) {
667 /* target is full */
668 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
669 break;
670 }
671 b=*source++;
672 switch(state) {
673 case readCommand:
674 /* redundant conditions are commented out */
675 /* here: b<0x20 because otherwise we would be in fastSingle */
676 if((1UL<<b)&0x2601 /* binary 0010 0110 0000 0001, check for b==0xd || b==0xa || b==9 || b==0 */) {
677 /* CR/LF/TAB/NUL */
678 *target++=(UChar)b;
679 goto fastSingle;
680 } else if(SC0<=b) {
681 if(b<=SC7) {
682 dynamicWindow=(int8_t)(b-SC0);
683 goto fastSingle;
684 } else /* if(SD0<=b && b<=SD7) */ {
685 dynamicWindow=(int8_t)(b-SD0);
686 state=defineOne;
687 }
688 } else if(/* SQ0<=b && */ b<=SQ7) {
689 quoteWindow=(int8_t)(b-SQ0);
690 state=quoteOne;
691 } else if(b==SDX) {
692 state=definePairOne;
693 } else if(b==SQU) {
694 state=quotePairOne;
695 } else if(b==SCU) {
696 isSingleByteMode=FALSE;
697 goto fastUnicode;
698 } else /* Srs */ {
699 /* callback(illegal) */
374ca955
A
700 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
701 cnv->toUBytes[0]=b;
702 cnv->toULength=1;
703 goto endloop;
b75a7d8f 704 }
374ca955
A
705
706 /* store the first byte of a multibyte sequence in toUBytes[] */
707 cnv->toUBytes[0]=b;
708 cnv->toULength=1;
b75a7d8f
A
709 break;
710 case quotePairOne:
711 byteOne=b;
374ca955
A
712 cnv->toUBytes[1]=b;
713 cnv->toULength=2;
b75a7d8f
A
714 state=quotePairTwo;
715 break;
716 case quotePairTwo:
717 *target++=(UChar)((byteOne<<8)|b);
718 state=readCommand;
719 goto fastSingle;
720 case quoteOne:
721 if(b<0x80) {
722 /* all static offsets are in the BMP */
723 *target++=(UChar)(staticOffsets[quoteWindow]+b);
724 } else {
725 /* write from dynamic window */
726 uint32_t c=scsu->toUDynamicOffsets[quoteWindow]+(b&0x7f);
727 if(c<=0xffff) {
728 *target++=(UChar)c;
729 } else {
730 /* output surrogate pair */
731 *target++=(UChar)(0xd7c0+(c>>10));
732 if(target<targetLimit) {
733 *target++=(UChar)(0xdc00|(c&0x3ff));
734 } else {
735 /* target overflow */
736 cnv->UCharErrorBuffer[0]=(UChar)(0xdc00|(c&0x3ff));
737 cnv->UCharErrorBufferLength=1;
738 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
739 goto endloop;
740 }
741 }
742 }
743 state=readCommand;
744 goto fastSingle;
745 case definePairOne:
746 dynamicWindow=(int8_t)((b>>5)&7);
747 byteOne=(uint8_t)(b&0x1f);
374ca955
A
748 cnv->toUBytes[1]=b;
749 cnv->toULength=2;
b75a7d8f
A
750 state=definePairTwo;
751 break;
752 case definePairTwo:
753 scsu->toUDynamicOffsets[dynamicWindow]=0x10000+(byteOne<<15UL | b<<7UL);
754 state=readCommand;
755 goto fastSingle;
756 case defineOne:
757 if(b==0) {
758 /* callback(illegal): Reserved window offset value 0 */
374ca955
A
759 cnv->toUBytes[1]=b;
760 cnv->toULength=2;
761 goto endloop;
b75a7d8f
A
762 } else if(b<gapThreshold) {
763 scsu->toUDynamicOffsets[dynamicWindow]=b<<7UL;
764 } else if((uint8_t)(b-gapThreshold)<(reservedStart-gapThreshold)) {
765 scsu->toUDynamicOffsets[dynamicWindow]=(b<<7UL)+gapOffset;
766 } else if(b>=fixedThreshold) {
767 scsu->toUDynamicOffsets[dynamicWindow]=fixedOffsets[b-fixedThreshold];
768 } else {
769 /* callback(illegal): Reserved window offset value 0xa8..0xf8 */
374ca955
A
770 cnv->toUBytes[1]=b;
771 cnv->toULength=2;
772 goto endloop;
b75a7d8f
A
773 }
774 state=readCommand;
775 goto fastSingle;
776 }
777 }
778 } else {
779 /* fast path for Unicode mode */
780 if(state==readCommand) {
781fastUnicode:
782 while(source+1<sourceLimit && target<targetLimit && (uint8_t)((b=*source)-UC0)>(Urs-UC0)) {
783 *target++=(UChar)((b<<8)|source[1]);
784 source+=2;
785 }
786 }
787
788 /* normal state machine for Unicode mode */
789/* unicodeByteMode: */
790 while(source<sourceLimit) {
791 if(target>=targetLimit) {
792 /* target is full */
793 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
794 break;
795 }
796 b=*source++;
797 switch(state) {
798 case readCommand:
799 if((uint8_t)(b-UC0)>(Urs-UC0)) {
800 byteOne=b;
374ca955
A
801 cnv->toUBytes[0]=b;
802 cnv->toULength=1;
b75a7d8f
A
803 state=quotePairTwo;
804 } else if(/* UC0<=b && */ b<=UC7) {
805 dynamicWindow=(int8_t)(b-UC0);
806 isSingleByteMode=TRUE;
807 goto fastSingle;
808 } else if(/* UD0<=b && */ b<=UD7) {
809 dynamicWindow=(int8_t)(b-UD0);
810 isSingleByteMode=TRUE;
374ca955
A
811 cnv->toUBytes[0]=b;
812 cnv->toULength=1;
b75a7d8f
A
813 state=defineOne;
814 goto singleByteMode;
815 } else if(b==UDX) {
816 isSingleByteMode=TRUE;
374ca955
A
817 cnv->toUBytes[0]=b;
818 cnv->toULength=1;
b75a7d8f
A
819 state=definePairOne;
820 goto singleByteMode;
821 } else if(b==UQU) {
374ca955
A
822 cnv->toUBytes[0]=b;
823 cnv->toULength=1;
b75a7d8f
A
824 state=quotePairOne;
825 } else /* Urs */ {
826 /* callback(illegal) */
374ca955
A
827 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
828 cnv->toUBytes[0]=b;
829 cnv->toULength=1;
830 goto endloop;
b75a7d8f
A
831 }
832 break;
833 case quotePairOne:
834 byteOne=b;
374ca955
A
835 cnv->toUBytes[1]=b;
836 cnv->toULength=2;
b75a7d8f
A
837 state=quotePairTwo;
838 break;
839 case quotePairTwo:
840 *target++=(UChar)((byteOne<<8)|b);
841 state=readCommand;
842 goto fastUnicode;
843 }
844 }
845 }
846endloop:
847
374ca955
A
848 /* set the converter state back into UConverter */
849 if(U_FAILURE(*pErrorCode) && *pErrorCode!=U_BUFFER_OVERFLOW_ERROR) {
850 /* reset to deal with the next character */
851 state=readCommand;
852 } else if(state==readCommand) {
853 /* not in a multi-byte sequence, reset toULength */
854 cnv->toULength=0;
b75a7d8f 855 }
374ca955
A
856 scsu->toUIsSingleByteMode=isSingleByteMode;
857 scsu->toUState=state;
858 scsu->toUQuoteWindow=quoteWindow;
859 scsu->toUDynamicWindow=dynamicWindow;
860 scsu->toUByteOne=byteOne;
b75a7d8f 861
b75a7d8f
A
862 /* write back the updated pointers */
863 pArgs->source=(const char *)source;
864 pArgs->target=target;
865 return;
b75a7d8f
A
866}
867
868/* SCSU-from-Unicode conversion functions ----------------------------------- */
869
870/*
871 * This SCSU Encoder is fairly simple but uses all SCSU commands to achieve
872 * reasonable results. The lookahead is minimal.
873 * Many cases are simple:
874 * A character fits directly into the current mode, a dynamic or static window,
875 * or is not compressible. These cases are tested first.
876 * Real compression heuristics are applied to the rest, in code branches for
877 * single/Unicode mode and BMP/supplementary code points.
878 * The heuristics used here are extremely simple.
879 */
880
881/* get the number of the window that this character is in, or -1 */
882static int8_t
883getWindow(const uint32_t offsets[8], uint32_t c) {
884 int i;
885 for(i=0; i<8; ++i) {
886 if((uint32_t)(c-offsets[i])<=0x7f) {
887 return (int8_t)(i);
888 }
889 }
890 return -1;
891}
892
893/* is the character in the dynamic window starting at the offset, or in the direct-encoded range? */
894static UBool
895isInOffsetWindowOrDirect(uint32_t offset, uint32_t c) {
896 return (UBool)(c<=offset+0x7f &&
897 (c>=offset || (c<=0x7f &&
898 (c>=0x20 || (1UL<<c)&0x2601))));
899 /* binary 0010 0110 0000 0001,
900 check for b==0xd || b==0xa || b==9 || b==0 */
901}
902
903/*
904 * getNextDynamicWindow returns the next dynamic window to be redefined
905 */
906static int8_t
907getNextDynamicWindow(SCSUData *scsu) {
908 int8_t window=scsu->windowUse[scsu->nextWindowUseIndex];
909 if(++scsu->nextWindowUseIndex==8) {
910 scsu->nextWindowUseIndex=0;
911 }
912 return window;
913}
914
915/*
916 * useDynamicWindow() adjusts
917 * windowUse[] and nextWindowUseIndex for the algorithm to choose
918 * the next dynamic window to be defined;
919 * a subclass may override it and provide its own algorithm.
920 */
921static void
922useDynamicWindow(SCSUData *scsu, int8_t window) {
923 /*
924 * move the existing window, which just became the most recently used one,
925 * up in windowUse[] to nextWindowUseIndex-1
926 */
927
928 /* first, find the index of the window - backwards to favor the more recently used windows */
929 int i, j;
930
931 i=scsu->nextWindowUseIndex;
932 do {
933 if(--i<0) {
934 i=7;
935 }
936 } while(scsu->windowUse[i]!=window);
937
938 /* now copy each windowUse[i+1] to [i] */
939 j=i+1;
940 if(j==8) {
941 j=0;
942 }
943 while(j!=scsu->nextWindowUseIndex) {
944 scsu->windowUse[i]=scsu->windowUse[j];
945 i=j;
946 if(++j==8) { j=0; }
947 }
948
949 /* finally, set the window into the most recently used index */
950 scsu->windowUse[i]=window;
951}
952
953/*
954 * calculate the offset and the code for a dynamic window that contains the character
955 * takes fixed offsets into account
956 * the offset of the window is stored in the offset variable,
957 * the code is returned
958 *
959 * return offset code: -1 none <=0xff code for SDn/UDn else code for SDX/UDX, subtract 0x200 to get the true code
960 */
961static int
962getDynamicOffset(uint32_t c, uint32_t *pOffset) {
963 int i;
964
965 for(i=0; i<7; ++i) {
966 if((uint32_t)(c-fixedOffsets[i])<=0x7f) {
967 *pOffset=fixedOffsets[i];
968 return 0xf9+i;
969 }
970 }
971
972 if(c<0x80) {
973 /* No dynamic window for US-ASCII. */
974 return -1;
975 } else if(c<0x3400 ||
976 (uint32_t)(c-0x10000)<(0x14000-0x10000) ||
977 (uint32_t)(c-0x1d000)<=(0x1ffff-0x1d000)
978 ) {
979 /* This character is in a code range for a "small", i.e., reasonably windowable, script. */
980 *pOffset=c&0x7fffff80;
981 return (int)(c>>7);
982 } else if(0xe000<=c && c!=0xfeff && c<0xfff0) {
983 /* For these characters we need to take the gapOffset into account. */
984 *pOffset=c&0x7fffff80;
985 return (int)((c-gapOffset)>>7);
986 } else {
987 return -1;
988 }
989}
990
991/*
992 * Idea for compression:
993 * - save SCSUData and other state before really starting work
994 * - at endloop, see if compression could be better with just unicode mode
995 * - don't do this if a callback has been called
996 * - if unicode mode would be smaller, then override the results with it - may need SCU at the beginning
997 * - different buffer handling!
998 *
999 * Drawback or need for corrective handling:
1000 * it is desirable to encode U+feff as SQU fe ff for the SCSU signature, and
1001 * it is desirable to start a document in US-ASCII/Latin-1 for as long as possible
1002 * not only for compression but also for HTML/XML documents with following charset/encoding announcers.
1003 *
1004 * How to achieve both?
1005 * - Only replace the result after an SDX or SCU?
1006 */
1007
1008static void
1009_SCSUFromUnicodeWithOffsets(UConverterFromUnicodeArgs *pArgs,
1010 UErrorCode *pErrorCode) {
1011 UConverter *cnv;
1012 SCSUData *scsu;
1013 const UChar *source, *sourceLimit;
1014 uint8_t *target;
1015 int32_t targetCapacity;
1016 int32_t *offsets;
1017
1018 UBool isSingleByteMode;
1019 uint8_t dynamicWindow;
1020 uint32_t currentOffset;
1021
1022 uint32_t c, delta;
1023
1024 int32_t sourceIndex, nextSourceIndex;
1025
b75a7d8f
A
1026 int32_t length;
1027
1028 /* variables for compression heuristics */
1029 uint32_t offset;
1030 UChar lead, trail;
1031 int code;
1032 int8_t window;
1033
1034 /* set up the local pointers */
1035 cnv=pArgs->converter;
1036 scsu=(SCSUData *)cnv->extraInfo;
1037
1038 /* set up the local pointers */
1039 source=pArgs->source;
1040 sourceLimit=pArgs->sourceLimit;
1041 target=(uint8_t *)pArgs->target;
1042 targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
1043 offsets=pArgs->offsets;
1044
1045 /* get the state machine state */
1046 isSingleByteMode=scsu->fromUIsSingleByteMode;
1047 dynamicWindow=scsu->fromUDynamicWindow;
1048 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
1049
374ca955 1050 c=cnv->fromUChar32;
b75a7d8f
A
1051
1052 /* sourceIndex=-1 if the current character began in the previous buffer */
1053 sourceIndex= c==0 ? 0 : -1;
1054 nextSourceIndex=0;
1055
1056 /* similar conversion "loop" as in toUnicode */
1057loop:
1058 if(isSingleByteMode) {
1059 if(c!=0 && targetCapacity>0) {
1060 goto getTrailSingle;
1061 }
1062
1063 /* state machine for single-byte mode */
1064/* singleByteMode: */
1065 while(source<sourceLimit) {
1066 if(targetCapacity<=0) {
1067 /* target is full */
1068 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
1069 break;
1070 }
1071 c=*source++;
1072 ++nextSourceIndex;
1073
1074 if((c-0x20)<=0x5f) {
1075 /* pass US-ASCII graphic character through */
1076 *target++=(uint8_t)c;
1077 if(offsets!=NULL) {
1078 *offsets++=sourceIndex;
1079 }
1080 --targetCapacity;
1081 } else if(c<0x20) {
1082 if((1UL<<c)&0x2601 /* binary 0010 0110 0000 0001, check for b==0xd || b==0xa || b==9 || b==0 */) {
1083 /* CR/LF/TAB/NUL */
1084 *target++=(uint8_t)c;
1085 if(offsets!=NULL) {
1086 *offsets++=sourceIndex;
1087 }
1088 --targetCapacity;
1089 } else {
1090 /* quote C0 control character */
1091 c|=SQ0<<8;
1092 length=2;
1093 goto outputBytes;
1094 }
1095 } else if((delta=c-currentOffset)<=0x7f) {
1096 /* use the current dynamic window */
1097 *target++=(uint8_t)(delta|0x80);
1098 if(offsets!=NULL) {
1099 *offsets++=sourceIndex;
1100 }
1101 --targetCapacity;
4388f060
A
1102 } else if(U16_IS_SURROGATE(c)) {
1103 if(U16_IS_SURROGATE_LEAD(c)) {
b75a7d8f
A
1104getTrailSingle:
1105 lead=(UChar)c;
1106 if(source<sourceLimit) {
1107 /* test the following code unit */
1108 trail=*source;
4388f060 1109 if(U16_IS_TRAIL(trail)) {
b75a7d8f
A
1110 ++source;
1111 ++nextSourceIndex;
4388f060 1112 c=U16_GET_SUPPLEMENTARY(c, trail);
b75a7d8f
A
1113 /* convert this surrogate code point */
1114 /* exit this condition tree */
1115 } else {
1116 /* this is an unmatched lead code unit (1st surrogate) */
1117 /* callback(illegal) */
374ca955
A
1118 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
1119 goto endloop;
b75a7d8f
A
1120 }
1121 } else {
1122 /* no more input */
1123 break;
1124 }
1125 } else {
1126 /* this is an unmatched trail code unit (2nd surrogate) */
1127 /* callback(illegal) */
374ca955
A
1128 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
1129 goto endloop;
b75a7d8f
A
1130 }
1131
1132 /* compress supplementary character U+10000..U+10ffff */
1133 if((delta=c-currentOffset)<=0x7f) {
1134 /* use the current dynamic window */
1135 *target++=(uint8_t)(delta|0x80);
1136 if(offsets!=NULL) {
1137 *offsets++=sourceIndex;
1138 }
1139 --targetCapacity;
1140 } else if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
1141 /* there is a dynamic window that contains this character, change to it */
1142 dynamicWindow=window;
1143 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
1144 useDynamicWindow(scsu, dynamicWindow);
1145 c=((uint32_t)(SC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
1146 length=2;
1147 goto outputBytes;
1148 } else if((code=getDynamicOffset(c, &offset))>=0) {
1149 /* might check if there are more characters in this window to come */
1150 /* define an extended window with this character */
1151 code-=0x200;
1152 dynamicWindow=getNextDynamicWindow(scsu);
1153 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
1154 useDynamicWindow(scsu, dynamicWindow);
1155 c=((uint32_t)SDX<<24)|((uint32_t)dynamicWindow<<21)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
1156 length=4;
1157 goto outputBytes;
1158 } else {
1159 /* change to Unicode mode and output this (lead, trail) pair */
1160 isSingleByteMode=FALSE;
1161 *target++=(uint8_t)SCU;
1162 if(offsets!=NULL) {
1163 *offsets++=sourceIndex;
1164 }
1165 --targetCapacity;
1166 c=((uint32_t)lead<<16)|trail;
1167 length=4;
1168 goto outputBytes;
1169 }
1170 } else if(c<0xa0) {
1171 /* quote C1 control character */
1172 c=(c&0x7f)|(SQ0+1)<<8; /* SQ0+1==SQ1 */
1173 length=2;
1174 goto outputBytes;
1175 } else if(c==0xfeff || c>=0xfff0) {
1176 /* quote signature character=byte order mark and specials */
1177 c|=SQU<<16;
1178 length=3;
1179 goto outputBytes;
1180 } else {
1181 /* compress all other BMP characters */
1182 if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
1183 /* there is a window defined that contains this character - switch to it or quote from it? */
1184 if(source>=sourceLimit || isInOffsetWindowOrDirect(scsu->fromUDynamicOffsets[window], *source)) {
1185 /* change to dynamic window */
1186 dynamicWindow=window;
1187 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
1188 useDynamicWindow(scsu, dynamicWindow);
1189 c=((uint32_t)(SC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
1190 length=2;
1191 goto outputBytes;
1192 } else {
1193 /* quote from dynamic window */
1194 c=((uint32_t)(SQ0+window)<<8)|(c-scsu->fromUDynamicOffsets[window])|0x80;
1195 length=2;
1196 goto outputBytes;
1197 }
1198 } else if((window=getWindow(staticOffsets, c))>=0) {
1199 /* quote from static window */
1200 c=((uint32_t)(SQ0+window)<<8)|(c-staticOffsets[window]);
1201 length=2;
1202 goto outputBytes;
1203 } else if((code=getDynamicOffset(c, &offset))>=0) {
1204 /* define a dynamic window with this character */
1205 dynamicWindow=getNextDynamicWindow(scsu);
1206 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
1207 useDynamicWindow(scsu, dynamicWindow);
1208 c=((uint32_t)(SD0+dynamicWindow)<<16)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
1209 length=3;
1210 goto outputBytes;
1211 } else if((uint32_t)(c-0x3400)<(0xd800-0x3400) &&
1212 (source>=sourceLimit || (uint32_t)(*source-0x3400)<(0xd800-0x3400))
1213 ) {
1214 /*
1215 * this character is not compressible (a BMP ideograph or similar);
1216 * switch to Unicode mode if this is the last character in the block
1217 * or there is at least one more ideograph following immediately
1218 */
1219 isSingleByteMode=FALSE;
1220 c|=SCU<<16;
1221 length=3;
1222 goto outputBytes;
1223 } else {
1224 /* quote Unicode */
1225 c|=SQU<<16;
1226 length=3;
1227 goto outputBytes;
1228 }
1229 }
1230
1231 /* normal end of conversion: prepare for a new character */
1232 c=0;
1233 sourceIndex=nextSourceIndex;
1234 }
1235 } else {
1236 if(c!=0 && targetCapacity>0) {
1237 goto getTrailUnicode;
1238 }
1239
1240 /* state machine for Unicode mode */
1241/* unicodeByteMode: */
1242 while(source<sourceLimit) {
1243 if(targetCapacity<=0) {
1244 /* target is full */
1245 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
1246 break;
1247 }
1248 c=*source++;
1249 ++nextSourceIndex;
1250
1251 if((uint32_t)(c-0x3400)<(0xd800-0x3400)) {
1252 /* not compressible, write character directly */
1253 if(targetCapacity>=2) {
1254 *target++=(uint8_t)(c>>8);
1255 *target++=(uint8_t)c;
1256 if(offsets!=NULL) {
1257 *offsets++=sourceIndex;
1258 *offsets++=sourceIndex;
1259 }
1260 targetCapacity-=2;
1261 } else {
1262 length=2;
1263 goto outputBytes;
1264 }
1265 } else if((uint32_t)(c-0x3400)>=(0xf300-0x3400) /* c<0x3400 || c>=0xf300 */) {
1266 /* compress BMP character if the following one is not an uncompressible ideograph */
1267 if(!(source<sourceLimit && (uint32_t)(*source-0x3400)<(0xd800-0x3400))) {
1268 if(((uint32_t)(c-0x30)<10 || (uint32_t)(c-0x61)<26 || (uint32_t)(c-0x41)<26)) {
1269 /* ASCII digit or letter */
1270 isSingleByteMode=TRUE;
1271 c|=((uint32_t)(UC0+dynamicWindow)<<8)|c;
1272 length=2;
1273 goto outputBytes;
1274 } else if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
1275 /* there is a dynamic window that contains this character, change to it */
1276 isSingleByteMode=TRUE;
1277 dynamicWindow=window;
1278 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
1279 useDynamicWindow(scsu, dynamicWindow);
1280 c=((uint32_t)(UC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
1281 length=2;
1282 goto outputBytes;
1283 } else if((code=getDynamicOffset(c, &offset))>=0) {
1284 /* define a dynamic window with this character */
1285 isSingleByteMode=TRUE;
1286 dynamicWindow=getNextDynamicWindow(scsu);
1287 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
1288 useDynamicWindow(scsu, dynamicWindow);
1289 c=((uint32_t)(UD0+dynamicWindow)<<16)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
1290 length=3;
1291 goto outputBytes;
1292 }
1293 }
1294
1295 /* don't know how to compress this character, just write it directly */
1296 length=2;
1297 goto outputBytes;
1298 } else if(c<0xe000) {
1299 /* c is a surrogate */
4388f060 1300 if(U16_IS_SURROGATE_LEAD(c)) {
b75a7d8f
A
1301getTrailUnicode:
1302 lead=(UChar)c;
1303 if(source<sourceLimit) {
1304 /* test the following code unit */
1305 trail=*source;
4388f060 1306 if(U16_IS_TRAIL(trail)) {
b75a7d8f
A
1307 ++source;
1308 ++nextSourceIndex;
4388f060 1309 c=U16_GET_SUPPLEMENTARY(c, trail);
b75a7d8f
A
1310 /* convert this surrogate code point */
1311 /* exit this condition tree */
1312 } else {
1313 /* this is an unmatched lead code unit (1st surrogate) */
1314 /* callback(illegal) */
374ca955
A
1315 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
1316 goto endloop;
b75a7d8f
A
1317 }
1318 } else {
1319 /* no more input */
1320 break;
1321 }
1322 } else {
1323 /* this is an unmatched trail code unit (2nd surrogate) */
1324 /* callback(illegal) */
374ca955
A
1325 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
1326 goto endloop;
b75a7d8f
A
1327 }
1328
1329 /* compress supplementary character */
1330 if( (window=getWindow(scsu->fromUDynamicOffsets, c))>=0 &&
1331 !(source<sourceLimit && (uint32_t)(*source-0x3400)<(0xd800-0x3400))
1332 ) {
1333 /*
1334 * there is a dynamic window that contains this character and
1335 * the following character is not uncompressible,
1336 * change to the window
1337 */
1338 isSingleByteMode=TRUE;
1339 dynamicWindow=window;
1340 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
1341 useDynamicWindow(scsu, dynamicWindow);
1342 c=((uint32_t)(UC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
1343 length=2;
1344 goto outputBytes;
1345 } else if(source<sourceLimit && lead==*source && /* too lazy to check trail in same window as source[1] */
1346 (code=getDynamicOffset(c, &offset))>=0
1347 ) {
1348 /* two supplementary characters in (probably) the same window - define an extended one */
1349 isSingleByteMode=TRUE;
1350 code-=0x200;
1351 dynamicWindow=getNextDynamicWindow(scsu);
1352 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
1353 useDynamicWindow(scsu, dynamicWindow);
1354 c=((uint32_t)UDX<<24)|((uint32_t)dynamicWindow<<21)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
1355 length=4;
1356 goto outputBytes;
1357 } else {
1358 /* don't know how to compress this character, just write it directly */
1359 c=((uint32_t)lead<<16)|trail;
1360 length=4;
1361 goto outputBytes;
1362 }
1363 } else /* 0xe000<=c<0xf300 */ {
1364 /* quote to avoid SCSU tags */
1365 c|=UQU<<16;
1366 length=3;
1367 goto outputBytes;
1368 }
1369
1370 /* normal end of conversion: prepare for a new character */
1371 c=0;
1372 sourceIndex=nextSourceIndex;
1373 }
1374 }
1375endloop:
1376
374ca955
A
1377 /* set the converter state back into UConverter */
1378 scsu->fromUIsSingleByteMode=isSingleByteMode;
1379 scsu->fromUDynamicWindow=dynamicWindow;
b75a7d8f 1380
374ca955 1381 cnv->fromUChar32=c;
b75a7d8f 1382
b75a7d8f
A
1383 /* write back the updated pointers */
1384 pArgs->source=source;
1385 pArgs->target=(char *)target;
1386 pArgs->offsets=offsets;
1387 return;
1388
1389outputBytes:
1390 /* write the output character bytes from c and length [code copied from ucnvmbcs.c] */
1391 /* from the first if in the loop we know that targetCapacity>0 */
1392 if(length<=targetCapacity) {
1393 if(offsets==NULL) {
1394 switch(length) {
1395 /* each branch falls through to the next one */
1396 case 4:
1397 *target++=(uint8_t)(c>>24);
4388f060 1398 case 3: /*fall through*/
b75a7d8f 1399 *target++=(uint8_t)(c>>16);
4388f060 1400 case 2: /*fall through*/
b75a7d8f 1401 *target++=(uint8_t)(c>>8);
4388f060 1402 case 1: /*fall through*/
b75a7d8f
A
1403 *target++=(uint8_t)c;
1404 default:
1405 /* will never occur */
1406 break;
1407 }
1408 } else {
1409 switch(length) {
1410 /* each branch falls through to the next one */
1411 case 4:
1412 *target++=(uint8_t)(c>>24);
1413 *offsets++=sourceIndex;
4388f060 1414 case 3: /*fall through*/
b75a7d8f
A
1415 *target++=(uint8_t)(c>>16);
1416 *offsets++=sourceIndex;
4388f060 1417 case 2: /*fall through*/
b75a7d8f
A
1418 *target++=(uint8_t)(c>>8);
1419 *offsets++=sourceIndex;
4388f060 1420 case 1: /*fall through*/
b75a7d8f
A
1421 *target++=(uint8_t)c;
1422 *offsets++=sourceIndex;
1423 default:
1424 /* will never occur */
1425 break;
1426 }
1427 }
1428 targetCapacity-=length;
1429
1430 /* normal end of conversion: prepare for a new character */
1431 c=0;
1432 sourceIndex=nextSourceIndex;
1433 goto loop;
1434 } else {
1435 uint8_t *p;
1436
1437 /*
1438 * We actually do this backwards here:
1439 * In order to save an intermediate variable, we output
1440 * first to the overflow buffer what does not fit into the
1441 * regular target.
1442 */
73c04bcf
A
1443 /* we know that 0<=targetCapacity<length<=4 */
1444 /* targetCapacity==0 when SCU+supplementary where SCU used up targetCapacity==1 */
b75a7d8f
A
1445 length-=targetCapacity;
1446 p=(uint8_t *)cnv->charErrorBuffer;
1447 switch(length) {
1448 /* each branch falls through to the next one */
73c04bcf
A
1449 case 4:
1450 *p++=(uint8_t)(c>>24);
4388f060 1451 case 3: /*fall through*/
b75a7d8f 1452 *p++=(uint8_t)(c>>16);
4388f060 1453 case 2: /*fall through*/
b75a7d8f 1454 *p++=(uint8_t)(c>>8);
4388f060 1455 case 1: /*fall through*/
b75a7d8f
A
1456 *p=(uint8_t)c;
1457 default:
1458 /* will never occur */
1459 break;
1460 }
1461 cnv->charErrorBufferLength=(int8_t)length;
1462
1463 /* now output what fits into the regular target */
1464 c>>=8*length; /* length was reduced by targetCapacity */
1465 switch(targetCapacity) {
1466 /* each branch falls through to the next one */
1467 case 3:
1468 *target++=(uint8_t)(c>>16);
1469 if(offsets!=NULL) {
1470 *offsets++=sourceIndex;
1471 }
4388f060 1472 case 2: /*fall through*/
b75a7d8f
A
1473 *target++=(uint8_t)(c>>8);
1474 if(offsets!=NULL) {
1475 *offsets++=sourceIndex;
1476 }
4388f060 1477 case 1: /*fall through*/
b75a7d8f
A
1478 *target++=(uint8_t)c;
1479 if(offsets!=NULL) {
1480 *offsets++=sourceIndex;
1481 }
1482 default:
b75a7d8f
A
1483 break;
1484 }
1485
1486 /* target overflow */
1487 targetCapacity=0;
1488 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
1489 c=0;
1490 goto endloop;
1491 }
b75a7d8f
A
1492}
1493
1494/*
1495 * Identical to _SCSUFromUnicodeWithOffsets but without offset handling.
1496 * If a change is made in the original function, then either
1497 * change this function the same way or
1498 * re-copy the original function and remove the variables
1499 * offsets, sourceIndex, and nextSourceIndex.
1500 */
1501static void
1502_SCSUFromUnicode(UConverterFromUnicodeArgs *pArgs,
1503 UErrorCode *pErrorCode) {
1504 UConverter *cnv;
1505 SCSUData *scsu;
1506 const UChar *source, *sourceLimit;
1507 uint8_t *target;
1508 int32_t targetCapacity;
1509
1510 UBool isSingleByteMode;
1511 uint8_t dynamicWindow;
1512 uint32_t currentOffset;
1513
1514 uint32_t c, delta;
1515
b75a7d8f
A
1516 int32_t length;
1517
1518 /* variables for compression heuristics */
1519 uint32_t offset;
1520 UChar lead, trail;
1521 int code;
1522 int8_t window;
1523
1524 /* set up the local pointers */
1525 cnv=pArgs->converter;
1526 scsu=(SCSUData *)cnv->extraInfo;
1527
1528 /* set up the local pointers */
1529 source=pArgs->source;
1530 sourceLimit=pArgs->sourceLimit;
1531 target=(uint8_t *)pArgs->target;
1532 targetCapacity=(int32_t)(pArgs->targetLimit-pArgs->target);
1533
1534 /* get the state machine state */
1535 isSingleByteMode=scsu->fromUIsSingleByteMode;
1536 dynamicWindow=scsu->fromUDynamicWindow;
1537 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
1538
374ca955 1539 c=cnv->fromUChar32;
b75a7d8f
A
1540
1541 /* similar conversion "loop" as in toUnicode */
1542loop:
1543 if(isSingleByteMode) {
1544 if(c!=0 && targetCapacity>0) {
1545 goto getTrailSingle;
1546 }
1547
1548 /* state machine for single-byte mode */
1549/* singleByteMode: */
1550 while(source<sourceLimit) {
1551 if(targetCapacity<=0) {
1552 /* target is full */
1553 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
1554 break;
1555 }
1556 c=*source++;
1557
1558 if((c-0x20)<=0x5f) {
1559 /* pass US-ASCII graphic character through */
1560 *target++=(uint8_t)c;
1561 --targetCapacity;
1562 } else if(c<0x20) {
1563 if((1UL<<c)&0x2601 /* binary 0010 0110 0000 0001, check for b==0xd || b==0xa || b==9 || b==0 */) {
1564 /* CR/LF/TAB/NUL */
1565 *target++=(uint8_t)c;
1566 --targetCapacity;
1567 } else {
1568 /* quote C0 control character */
1569 c|=SQ0<<8;
1570 length=2;
1571 goto outputBytes;
1572 }
1573 } else if((delta=c-currentOffset)<=0x7f) {
1574 /* use the current dynamic window */
1575 *target++=(uint8_t)(delta|0x80);
1576 --targetCapacity;
4388f060
A
1577 } else if(U16_IS_SURROGATE(c)) {
1578 if(U16_IS_SURROGATE_LEAD(c)) {
b75a7d8f
A
1579getTrailSingle:
1580 lead=(UChar)c;
1581 if(source<sourceLimit) {
1582 /* test the following code unit */
1583 trail=*source;
4388f060 1584 if(U16_IS_TRAIL(trail)) {
b75a7d8f 1585 ++source;
4388f060 1586 c=U16_GET_SUPPLEMENTARY(c, trail);
b75a7d8f
A
1587 /* convert this surrogate code point */
1588 /* exit this condition tree */
1589 } else {
1590 /* this is an unmatched lead code unit (1st surrogate) */
1591 /* callback(illegal) */
374ca955
A
1592 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
1593 goto endloop;
b75a7d8f
A
1594 }
1595 } else {
1596 /* no more input */
1597 break;
1598 }
1599 } else {
1600 /* this is an unmatched trail code unit (2nd surrogate) */
1601 /* callback(illegal) */
374ca955
A
1602 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
1603 goto endloop;
b75a7d8f
A
1604 }
1605
1606 /* compress supplementary character U+10000..U+10ffff */
1607 if((delta=c-currentOffset)<=0x7f) {
1608 /* use the current dynamic window */
1609 *target++=(uint8_t)(delta|0x80);
1610 --targetCapacity;
1611 } else if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
1612 /* there is a dynamic window that contains this character, change to it */
1613 dynamicWindow=window;
1614 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
1615 useDynamicWindow(scsu, dynamicWindow);
1616 c=((uint32_t)(SC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
1617 length=2;
1618 goto outputBytes;
1619 } else if((code=getDynamicOffset(c, &offset))>=0) {
1620 /* might check if there are more characters in this window to come */
1621 /* define an extended window with this character */
1622 code-=0x200;
1623 dynamicWindow=getNextDynamicWindow(scsu);
1624 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
1625 useDynamicWindow(scsu, dynamicWindow);
1626 c=((uint32_t)SDX<<24)|((uint32_t)dynamicWindow<<21)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
1627 length=4;
1628 goto outputBytes;
1629 } else {
1630 /* change to Unicode mode and output this (lead, trail) pair */
1631 isSingleByteMode=FALSE;
1632 *target++=(uint8_t)SCU;
1633 --targetCapacity;
1634 c=((uint32_t)lead<<16)|trail;
1635 length=4;
1636 goto outputBytes;
1637 }
1638 } else if(c<0xa0) {
1639 /* quote C1 control character */
1640 c=(c&0x7f)|(SQ0+1)<<8; /* SQ0+1==SQ1 */
1641 length=2;
1642 goto outputBytes;
1643 } else if(c==0xfeff || c>=0xfff0) {
1644 /* quote signature character=byte order mark and specials */
1645 c|=SQU<<16;
1646 length=3;
1647 goto outputBytes;
1648 } else {
1649 /* compress all other BMP characters */
1650 if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
1651 /* there is a window defined that contains this character - switch to it or quote from it? */
1652 if(source>=sourceLimit || isInOffsetWindowOrDirect(scsu->fromUDynamicOffsets[window], *source)) {
1653 /* change to dynamic window */
1654 dynamicWindow=window;
1655 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
1656 useDynamicWindow(scsu, dynamicWindow);
1657 c=((uint32_t)(SC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
1658 length=2;
1659 goto outputBytes;
1660 } else {
1661 /* quote from dynamic window */
1662 c=((uint32_t)(SQ0+window)<<8)|(c-scsu->fromUDynamicOffsets[window])|0x80;
1663 length=2;
1664 goto outputBytes;
1665 }
1666 } else if((window=getWindow(staticOffsets, c))>=0) {
1667 /* quote from static window */
1668 c=((uint32_t)(SQ0+window)<<8)|(c-staticOffsets[window]);
1669 length=2;
1670 goto outputBytes;
1671 } else if((code=getDynamicOffset(c, &offset))>=0) {
1672 /* define a dynamic window with this character */
1673 dynamicWindow=getNextDynamicWindow(scsu);
1674 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
1675 useDynamicWindow(scsu, dynamicWindow);
1676 c=((uint32_t)(SD0+dynamicWindow)<<16)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
1677 length=3;
1678 goto outputBytes;
1679 } else if((uint32_t)(c-0x3400)<(0xd800-0x3400) &&
1680 (source>=sourceLimit || (uint32_t)(*source-0x3400)<(0xd800-0x3400))
1681 ) {
1682 /*
1683 * this character is not compressible (a BMP ideograph or similar);
1684 * switch to Unicode mode if this is the last character in the block
1685 * or there is at least one more ideograph following immediately
1686 */
1687 isSingleByteMode=FALSE;
1688 c|=SCU<<16;
1689 length=3;
1690 goto outputBytes;
1691 } else {
1692 /* quote Unicode */
1693 c|=SQU<<16;
1694 length=3;
1695 goto outputBytes;
1696 }
1697 }
1698
1699 /* normal end of conversion: prepare for a new character */
1700 c=0;
1701 }
1702 } else {
1703 if(c!=0 && targetCapacity>0) {
1704 goto getTrailUnicode;
1705 }
1706
1707 /* state machine for Unicode mode */
1708/* unicodeByteMode: */
1709 while(source<sourceLimit) {
1710 if(targetCapacity<=0) {
1711 /* target is full */
1712 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
1713 break;
1714 }
1715 c=*source++;
1716
1717 if((uint32_t)(c-0x3400)<(0xd800-0x3400)) {
1718 /* not compressible, write character directly */
1719 if(targetCapacity>=2) {
1720 *target++=(uint8_t)(c>>8);
1721 *target++=(uint8_t)c;
1722 targetCapacity-=2;
1723 } else {
1724 length=2;
1725 goto outputBytes;
1726 }
1727 } else if((uint32_t)(c-0x3400)>=(0xf300-0x3400) /* c<0x3400 || c>=0xf300 */) {
1728 /* compress BMP character if the following one is not an uncompressible ideograph */
1729 if(!(source<sourceLimit && (uint32_t)(*source-0x3400)<(0xd800-0x3400))) {
1730 if(((uint32_t)(c-0x30)<10 || (uint32_t)(c-0x61)<26 || (uint32_t)(c-0x41)<26)) {
1731 /* ASCII digit or letter */
1732 isSingleByteMode=TRUE;
1733 c|=((uint32_t)(UC0+dynamicWindow)<<8)|c;
1734 length=2;
1735 goto outputBytes;
1736 } else if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
1737 /* there is a dynamic window that contains this character, change to it */
1738 isSingleByteMode=TRUE;
1739 dynamicWindow=window;
1740 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
1741 useDynamicWindow(scsu, dynamicWindow);
1742 c=((uint32_t)(UC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
1743 length=2;
1744 goto outputBytes;
1745 } else if((code=getDynamicOffset(c, &offset))>=0) {
1746 /* define a dynamic window with this character */
1747 isSingleByteMode=TRUE;
1748 dynamicWindow=getNextDynamicWindow(scsu);
1749 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
1750 useDynamicWindow(scsu, dynamicWindow);
1751 c=((uint32_t)(UD0+dynamicWindow)<<16)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
1752 length=3;
1753 goto outputBytes;
1754 }
1755 }
1756
1757 /* don't know how to compress this character, just write it directly */
1758 length=2;
1759 goto outputBytes;
1760 } else if(c<0xe000) {
1761 /* c is a surrogate */
4388f060 1762 if(U16_IS_SURROGATE_LEAD(c)) {
b75a7d8f
A
1763getTrailUnicode:
1764 lead=(UChar)c;
1765 if(source<sourceLimit) {
1766 /* test the following code unit */
1767 trail=*source;
4388f060 1768 if(U16_IS_TRAIL(trail)) {
b75a7d8f 1769 ++source;
4388f060 1770 c=U16_GET_SUPPLEMENTARY(c, trail);
b75a7d8f
A
1771 /* convert this surrogate code point */
1772 /* exit this condition tree */
1773 } else {
1774 /* this is an unmatched lead code unit (1st surrogate) */
1775 /* callback(illegal) */
374ca955
A
1776 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
1777 goto endloop;
b75a7d8f
A
1778 }
1779 } else {
1780 /* no more input */
1781 break;
1782 }
1783 } else {
1784 /* this is an unmatched trail code unit (2nd surrogate) */
1785 /* callback(illegal) */
374ca955
A
1786 *pErrorCode=U_ILLEGAL_CHAR_FOUND;
1787 goto endloop;
b75a7d8f
A
1788 }
1789
1790 /* compress supplementary character */
1791 if( (window=getWindow(scsu->fromUDynamicOffsets, c))>=0 &&
1792 !(source<sourceLimit && (uint32_t)(*source-0x3400)<(0xd800-0x3400))
1793 ) {
1794 /*
1795 * there is a dynamic window that contains this character and
1796 * the following character is not uncompressible,
1797 * change to the window
1798 */
1799 isSingleByteMode=TRUE;
1800 dynamicWindow=window;
1801 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
1802 useDynamicWindow(scsu, dynamicWindow);
1803 c=((uint32_t)(UC0+dynamicWindow)<<8)|(c-currentOffset)|0x80;
1804 length=2;
1805 goto outputBytes;
1806 } else if(source<sourceLimit && lead==*source && /* too lazy to check trail in same window as source[1] */
1807 (code=getDynamicOffset(c, &offset))>=0
1808 ) {
1809 /* two supplementary characters in (probably) the same window - define an extended one */
1810 isSingleByteMode=TRUE;
1811 code-=0x200;
1812 dynamicWindow=getNextDynamicWindow(scsu);
1813 currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
1814 useDynamicWindow(scsu, dynamicWindow);
1815 c=((uint32_t)UDX<<24)|((uint32_t)dynamicWindow<<21)|((uint32_t)code<<8)|(c-currentOffset)|0x80;
1816 length=4;
1817 goto outputBytes;
1818 } else {
1819 /* don't know how to compress this character, just write it directly */
1820 c=((uint32_t)lead<<16)|trail;
1821 length=4;
1822 goto outputBytes;
1823 }
1824 } else /* 0xe000<=c<0xf300 */ {
1825 /* quote to avoid SCSU tags */
1826 c|=UQU<<16;
1827 length=3;
1828 goto outputBytes;
1829 }
1830
1831 /* normal end of conversion: prepare for a new character */
1832 c=0;
1833 }
1834 }
1835endloop:
1836
374ca955
A
1837 /* set the converter state back into UConverter */
1838 scsu->fromUIsSingleByteMode=isSingleByteMode;
1839 scsu->fromUDynamicWindow=dynamicWindow;
b75a7d8f 1840
374ca955 1841 cnv->fromUChar32=c;
b75a7d8f 1842
b75a7d8f
A
1843 /* write back the updated pointers */
1844 pArgs->source=source;
1845 pArgs->target=(char *)target;
1846 return;
1847
1848outputBytes:
1849 /* write the output character bytes from c and length [code copied from ucnvmbcs.c] */
1850 /* from the first if in the loop we know that targetCapacity>0 */
1851 if(length<=targetCapacity) {
1852 switch(length) {
1853 /* each branch falls through to the next one */
1854 case 4:
1855 *target++=(uint8_t)(c>>24);
4388f060 1856 case 3: /*fall through*/
b75a7d8f 1857 *target++=(uint8_t)(c>>16);
4388f060 1858 case 2: /*fall through*/
b75a7d8f 1859 *target++=(uint8_t)(c>>8);
4388f060 1860 case 1: /*fall through*/
b75a7d8f
A
1861 *target++=(uint8_t)c;
1862 default:
1863 /* will never occur */
1864 break;
1865 }
1866 targetCapacity-=length;
1867
1868 /* normal end of conversion: prepare for a new character */
1869 c=0;
1870 goto loop;
1871 } else {
1872 uint8_t *p;
1873
1874 /*
1875 * We actually do this backwards here:
1876 * In order to save an intermediate variable, we output
1877 * first to the overflow buffer what does not fit into the
1878 * regular target.
1879 */
73c04bcf
A
1880 /* we know that 0<=targetCapacity<length<=4 */
1881 /* targetCapacity==0 when SCU+supplementary where SCU used up targetCapacity==1 */
b75a7d8f
A
1882 length-=targetCapacity;
1883 p=(uint8_t *)cnv->charErrorBuffer;
1884 switch(length) {
1885 /* each branch falls through to the next one */
73c04bcf
A
1886 case 4:
1887 *p++=(uint8_t)(c>>24);
4388f060 1888 case 3: /*fall through*/
b75a7d8f 1889 *p++=(uint8_t)(c>>16);
4388f060 1890 case 2: /*fall through*/
b75a7d8f 1891 *p++=(uint8_t)(c>>8);
4388f060 1892 case 1: /*fall through*/
b75a7d8f
A
1893 *p=(uint8_t)c;
1894 default:
1895 /* will never occur */
1896 break;
1897 }
1898 cnv->charErrorBufferLength=(int8_t)length;
1899
1900 /* now output what fits into the regular target */
1901 c>>=8*length; /* length was reduced by targetCapacity */
1902 switch(targetCapacity) {
1903 /* each branch falls through to the next one */
1904 case 3:
1905 *target++=(uint8_t)(c>>16);
4388f060 1906 case 2: /*fall through*/
b75a7d8f 1907 *target++=(uint8_t)(c>>8);
4388f060 1908 case 1: /*fall through*/
b75a7d8f
A
1909 *target++=(uint8_t)c;
1910 default:
b75a7d8f
A
1911 break;
1912 }
1913
1914 /* target overflow */
1915 targetCapacity=0;
1916 *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
1917 c=0;
1918 goto endloop;
1919 }
b75a7d8f
A
1920}
1921
1922/* miscellaneous ------------------------------------------------------------ */
1923
1924static const char *
1925_SCSUGetName(const UConverter *cnv) {
1926 SCSUData *scsu=(SCSUData *)cnv->extraInfo;
1927
1928 switch(scsu->locale) {
1929 case l_ja:
1930 return "SCSU,locale=ja";
1931 default:
1932 return "SCSU";
1933 }
1934}
1935
b75a7d8f 1936/* structure for SafeClone calculations */
374ca955 1937struct cloneSCSUStruct
b75a7d8f
A
1938{
1939 UConverter cnv;
1940 SCSUData mydata;
1941};
1942
1943static UConverter *
1944_SCSUSafeClone(const UConverter *cnv,
1945 void *stackBuffer,
1946 int32_t *pBufferSize,
1947 UErrorCode *status)
1948{
374ca955
A
1949 struct cloneSCSUStruct * localClone;
1950 int32_t bufferSizeNeeded = sizeof(struct cloneSCSUStruct);
b75a7d8f
A
1951
1952 if (U_FAILURE(*status)){
1953 return 0;
1954 }
1955
1956 if (*pBufferSize == 0){ /* 'preflighting' request - set needed size into *pBufferSize */
1957 *pBufferSize = bufferSizeNeeded;
1958 return 0;
1959 }
1960
374ca955
A
1961 localClone = (struct cloneSCSUStruct *)stackBuffer;
1962 /* ucnv.c/ucnv_safeClone() copied the main UConverter already */
b75a7d8f
A
1963
1964 uprv_memcpy(&localClone->mydata, cnv->extraInfo, sizeof(SCSUData));
1965 localClone->cnv.extraInfo = &localClone->mydata;
1966 localClone->cnv.isExtraLocal = TRUE;
1967
1968 return &localClone->cnv;
1969}
1970
1971
b75a7d8f
A
1972static const UConverterImpl _SCSUImpl={
1973 UCNV_SCSU,
1974
1975 NULL,
1976 NULL,
1977
1978 _SCSUOpen,
1979 _SCSUClose,
1980 _SCSUReset,
1981
1982 _SCSUToUnicode,
1983 _SCSUToUnicodeWithOffsets,
1984 _SCSUFromUnicode,
1985 _SCSUFromUnicodeWithOffsets,
374ca955 1986 NULL,
b75a7d8f
A
1987
1988 NULL,
1989 _SCSUGetName,
73c04bcf 1990 NULL,
b75a7d8f
A
1991 _SCSUSafeClone,
1992 ucnv_getCompleteUnicodeSet
1993};
1994
1995static const UConverterStaticData _SCSUStaticData={
1996 sizeof(UConverterStaticData),
1997 "SCSU",
73c04bcf 1998 1212, /* CCSID for SCSU */
b75a7d8f
A
1999 UCNV_IBM, UCNV_SCSU,
2000 1, 3, /* one UChar generates at least 1 byte and at most 3 bytes */
374ca955 2001 /*
73c04bcf
A
2002 * The subchar here is ignored because _SCSUOpen() sets U+fffd as a Unicode
2003 * substitution string.
374ca955
A
2004 */
2005 { 0x0e, 0xff, 0xfd, 0 }, 3,
b75a7d8f
A
2006 FALSE, FALSE,
2007 0,
2008 0,
2009 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
2010};
2011
2012const UConverterSharedData _SCSUData={
2013 sizeof(UConverterSharedData), ~((uint32_t)0),
2014 NULL, NULL, &_SCSUStaticData, FALSE, &_SCSUImpl,
2015 0
2016};
2017
374ca955 2018#endif