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