]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_8_1_1/main/classes/charset/src/com/ibm/icu/charset/CharsetMBCS.java
Added flags.
[Dictionary.git] / jars / icu4j-4_8_1_1 / main / classes / charset / src / com / ibm / icu / charset / CharsetMBCS.java
1 /**
2  *******************************************************************************
3  * Copyright (C) 2006-2011, International Business Machines Corporation and    *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  *
7  *******************************************************************************
8  */
9 package com.ibm.icu.charset;
10
11 import java.io.BufferedInputStream;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.nio.Buffer;
15 import java.nio.BufferOverflowException;
16 import java.nio.ByteBuffer;
17 import java.nio.CharBuffer;
18 import java.nio.IntBuffer;
19 import java.nio.charset.CharsetDecoder;
20 import java.nio.charset.CharsetEncoder;
21 import java.nio.charset.CoderResult;
22
23 import com.ibm.icu.charset.UConverterSharedData.UConverterType;
24 import com.ibm.icu.impl.ICUData;
25 import com.ibm.icu.impl.ICUResourceBundle;
26 import com.ibm.icu.impl.InvalidFormatException;
27 import com.ibm.icu.lang.UCharacter;
28 import com.ibm.icu.text.UTF16;
29 import com.ibm.icu.text.UnicodeSet;
30
31 class CharsetMBCS extends CharsetICU {
32
33     private byte[] fromUSubstitution = null;
34     UConverterSharedData sharedData = null;
35     private static final int MAX_VERSION_LENGTH = 4;
36     
37     // these variables are used in getUnicodeSet() and may be changed in future
38     // typedef enum UConverterSetFilter {
39       static final int UCNV_SET_FILTER_NONE = 1;
40       static final int UCNV_SET_FILTER_DBCS_ONLY = 2;
41       static final int UCNV_SET_FILTER_2022_CN = 3;
42       static final int UCNV_SET_FILTER_SJIS= 4 ;
43       static final int UCNV_SET_FILTER_GR94DBCS = 5;
44       static final int UCNV_SET_FILTER_HZ = 6;
45       static final int UCNV_SET_FILTER_COUNT = 7;
46    //  } UConverterSetFilter;
47
48     /**
49      * Fallbacks to Unicode are stored outside the normal state table and code point structures in a vector of items of
50      * this type. They are sorted by offset.
51      */
52     final class MBCSToUFallback {
53         int offset;
54         int codePoint;
55     }
56
57     /**
58      * This is the MBCS part of the UConverterTable union (a runtime data structure). It keeps all the per-converter
59      * data and points into the loaded mapping tables.
60      */
61     static final class UConverterMBCSTable {
62         /* toUnicode */
63         short countStates;
64         byte dbcsOnlyState;
65         boolean stateTableOwned;
66         int countToUFallbacks;
67
68         int stateTable[/* countStates */][/* 256 */];
69         int swapLFNLStateTable[/* countStates */][/* 256 */]; /* for swaplfnl */
70         char unicodeCodeUnits[/* countUnicodeResults */];
71         MBCSToUFallback toUFallbacks[/* countToUFallbacks */];
72
73         /* fromUnicode */
74         char fromUnicodeTable[];
75         byte fromUnicodeBytes[];
76         byte swapLFNLFromUnicodeBytes[]; /* for swaplfnl */
77         int fromUBytesLength;
78         short outputType, unicodeMask;
79
80         /* converter name for swaplfnl */
81         String swapLFNLName;
82
83         /* extension data */
84         UConverterSharedData baseSharedData;
85         // int extIndexes[];
86         ByteBuffer extIndexes; // create int[] view etc. as needed
87         
88         CharBuffer mbcsIndex;                     /* for fast conversion from most of BMP to MBCS (utf8Friendly data) */
89         char sbcsIndex[/* SBCS_FAST_LIMIT>>6 */]; /* for fast conversion from low BMP to SBCS (utf8Friendly data) */
90         boolean utf8Friendly;                     /* for utf8Friendly data */
91         char maxFastUChar;                        /* for utf8Friendly data */
92
93         /* roundtrips */
94         long asciiRoundtrips;
95
96         UConverterMBCSTable() {
97             utf8Friendly = false;
98             mbcsIndex = null;
99             sbcsIndex = new char[SBCS_FAST_LIMIT>>6];
100         }
101
102         /*
103          * UConverterMBCSTable(UConverterMBCSTable t) { countStates = t.countStates; dbcsOnlyState = t.dbcsOnlyState;
104          * stateTableOwned = t.stateTableOwned; countToUFallbacks = t.countToUFallbacks; stateTable = t.stateTable;
105          * swapLFNLStateTable = t.swapLFNLStateTable; unicodeCodeUnits = t.unicodeCodeUnits; toUFallbacks =
106          * t.toUFallbacks; fromUnicodeTable = t.fromUnicodeTable; fromUnicodeBytes = t.fromUnicodeBytes;
107          * swapLFNLFromUnicodeBytes = t.swapLFNLFromUnicodeBytes; fromUBytesLength = t.fromUBytesLength; outputType =
108          * t.outputType; unicodeMask = t.unicodeMask; swapLFNLName = t.swapLFNLName; baseSharedData = t.baseSharedData;
109          * extIndexes = t.extIndexes; }
110          */
111     }
112
113     /* Constants used in MBCS data header */
114     // enum {
115         static final int MBCS_OPT_LENGTH_MASK=0x3f;
116         static final int MBCS_OPT_NO_FROM_U=0x40;
117         /*
118          * If any of the following options bits are set,
119          * then the file must be rejected.
120          */
121         static final int MBCS_OPT_INCOMPATIBLE_MASK=0xffc0;
122         /*
123          * Remove bits from this mask as more options are recognized
124          * by all implementations that use this constant.
125          */
126         static final int MBCS_OPT_UNKNOWN_INCOMPATIBLE_MASK=0xff80;
127     // };
128     /* Constants for fast and UTF-8-friendly conversion. */
129     // enum {
130         static final int SBCS_FAST_MAX=0x0fff;               /* maximum code point with UTF-8-friendly SBCS runtime code, see makeconv SBCS_UTF8_MAX */
131         static final int SBCS_FAST_LIMIT=SBCS_FAST_MAX+1;    /* =0x1000 */
132         static final int MBCS_FAST_MAX=0xd7ff;               /* maximum code point with UTF-8-friendly MBCS runtime code, see makeconv MBCS_UTF8_MAX */
133         static final int MBCS_FAST_LIMIT=MBCS_FAST_MAX+1;    /* =0xd800 */
134     // };
135     /**
136      * MBCS data header. See data format description above.
137      */
138     final class MBCSHeader {
139         byte version[/* U_MAX_VERSION_LENGTH */];
140         int countStates, countToUFallbacks, offsetToUCodeUnits, offsetFromUTable, offsetFromUBytes;
141         int flags;
142         int fromUBytesLength;
143         
144         /* new and required in version 5 */
145         int options;
146
147         /* new and optional in version 5; used if options&MBCS_OPT_NO_FROM_U */
148         int fullStage2Length;  /* number of 32-bit units */
149
150         MBCSHeader() {
151             version = new byte[MAX_VERSION_LENGTH];
152         }
153     }
154
155     public CharsetMBCS(String icuCanonicalName, String javaCanonicalName, String[] aliases, String classPath,
156             ClassLoader loader) throws InvalidFormatException {
157         super(icuCanonicalName, javaCanonicalName, aliases);
158         
159         /* See if the icuCanonicalName contains certain option information. */
160         if (icuCanonicalName.indexOf(UConverterConstants.OPTION_SWAP_LFNL_STRING) > -1) {
161             options = UConverterConstants.OPTION_SWAP_LFNL;
162             icuCanonicalName = icuCanonicalName.substring(0, icuCanonicalName.indexOf(UConverterConstants.OPTION_SWAP_LFNL_STRING));
163             super.icuCanonicalName = icuCanonicalName;
164         }
165         
166         // now try to load the data
167         sharedData = loadConverter(1, icuCanonicalName, classPath, loader);
168
169         maxBytesPerChar = sharedData.staticData.maxBytesPerChar;
170         minBytesPerChar = sharedData.staticData.minBytesPerChar;
171         maxCharsPerByte = 1;
172         fromUSubstitution = sharedData.staticData.subChar;
173         subChar = sharedData.staticData.subChar;
174         subCharLen = sharedData.staticData.subCharLen;
175         subChar1 = sharedData.staticData.subChar1;
176         fromUSubstitution = new byte[sharedData.staticData.subCharLen];
177         System.arraycopy(sharedData.staticData.subChar, 0, fromUSubstitution, 0, sharedData.staticData.subCharLen);
178         
179         initializeConverter(options);
180     }
181
182     public CharsetMBCS(String icuCanonicalName, String javaCanonicalName, String[] aliases)
183             throws InvalidFormatException {
184         this(icuCanonicalName, javaCanonicalName, aliases, ICUResourceBundle.ICU_BUNDLE, null);
185     }
186
187     private UConverterSharedData loadConverter(int nestedLoads, String myName, String classPath, ClassLoader loader)
188             throws InvalidFormatException {
189         boolean noFromU = false;
190         // Read converter data from file
191         UConverterStaticData staticData = new UConverterStaticData();
192         UConverterDataReader reader = null;
193         try {
194             String resourceName = classPath + "/" + myName + "." + UConverterSharedData.DATA_TYPE;
195             InputStream i;
196
197             if (loader != null) {
198                 i = ICUData.getRequiredStream(loader, resourceName);
199             } else {
200                 i = ICUData.getRequiredStream(resourceName);
201             }
202             BufferedInputStream b = new BufferedInputStream(i, UConverterConstants.CNV_DATA_BUFFER_SIZE);
203             reader = new UConverterDataReader(b);
204             reader.readStaticData(staticData);
205         } catch (IOException e) {
206             throw new InvalidFormatException();
207         } catch (Exception e) {
208             throw new InvalidFormatException();
209         }
210
211         UConverterSharedData data = null;
212         int type = staticData.conversionType;
213
214         if (type != UConverterSharedData.UConverterType.MBCS
215                 || staticData.structSize != UConverterStaticData.SIZE_OF_UCONVERTER_STATIC_DATA) {
216             throw new InvalidFormatException();
217         }
218
219         data = new UConverterSharedData(1, null, false, 0);
220         data.dataReader = reader;
221         data.staticData = staticData;
222         data.sharedDataCached = false;
223
224         // Load data
225         UConverterMBCSTable mbcsTable = data.mbcs;
226         MBCSHeader header = new MBCSHeader();
227         try {
228             reader.readMBCSHeader(header);
229         } catch (IOException e) {
230             throw new InvalidFormatException();
231         }
232
233         int offset;
234         // int[] extIndexesArray = null;
235         String baseNameString = null;
236         int[][] stateTableArray = null;
237         MBCSToUFallback[] toUFallbacksArray = null;
238         char[] unicodeCodeUnitsArray = null;
239         char[] fromUnicodeTableArray = null;
240         byte[] fromUnicodeBytesArray = null;
241
242         if (header.version[0] == 5 && header.version[1] >= 3 && (header.options & MBCS_OPT_UNKNOWN_INCOMPATIBLE_MASK) == 0) {
243             noFromU = ((header.options & MBCS_OPT_NO_FROM_U) != 0);
244         } else if (header.version[0] != 4) {
245             throw new InvalidFormatException();
246         }
247
248         mbcsTable.outputType = (byte) header.flags;
249
250         /* extension data, header version 4.2 and higher */
251         offset = header.flags >>> 8;
252         // if(offset!=0 && mbcsTable.outputType == MBCS_OUTPUT_EXT_ONLY) {
253         if (mbcsTable.outputType == MBCS_OUTPUT_EXT_ONLY) {
254             try {
255                 baseNameString = reader.readBaseTableName();
256                 if (offset != 0) {
257                     // agljport:commment subtract 32 for sizeof(_MBCSHeader) and length of baseNameString and 1 null
258                     // terminator byte all already read;
259                     mbcsTable.extIndexes = reader.readExtIndexes(offset
260                             - (reader.bytesRead - reader.staticDataBytesRead));
261                 }
262             } catch (IOException e) {
263                 throw new InvalidFormatException();
264             }
265         }
266
267         // agljport:add this would be unnecessary if extIndexes were memory mapped
268         /*
269          * if(mbcsTable.extIndexes != null) {
270          * 
271          * try { //int nbytes = mbcsTable.extIndexes[UConverterExt.UCNV_EXT_TO_U_LENGTH]*4 +
272          * mbcsTable.extIndexes[UConverterExt.UCNV_EXT_TO_U_UCHARS_LENGTH]*2 +
273          * mbcsTable.extIndexes[UConverterExt.UCNV_EXT_FROM_U_LENGTH]*6 +
274          * mbcsTable.extIndexes[UConverterExt.UCNV_EXT_FROM_U_BYTES_LENGTH] +
275          * mbcsTable.extIndexes[UConverterExt.UCNV_EXT_FROM_U_STAGE_12_LENGTH]*2 +
276          * mbcsTable.extIndexes[UConverterExt.UCNV_EXT_FROM_U_STAGE_3_LENGTH]*2 +
277          * mbcsTable.extIndexes[UConverterExt.UCNV_EXT_FROM_U_STAGE_3B_LENGTH]*4; //int nbytes =
278          * mbcsTable.extIndexes[UConverterExt.UCNV_EXT_SIZE] //byte[] extTables = dataReader.readExtTables(nbytes);
279          * //mbcsTable.extTables = ByteBuffer.wrap(extTables); } catch(IOException e) { System.err.println("Caught
280          * IOException: " + e.getMessage()); pErrorCode[0] = UErrorCode.U_INVALID_FORMAT_ERROR; return; } }
281          */
282         if (mbcsTable.outputType == MBCS_OUTPUT_EXT_ONLY) {
283             UConverterSharedData baseSharedData = null;
284             ByteBuffer extIndexes;
285             String baseName;
286
287             /* extension-only file, load the base table and set values appropriately */
288             extIndexes = mbcsTable.extIndexes;
289             if (extIndexes == null) {
290                 /* extension-only file without extension */
291                 throw new InvalidFormatException();
292             }
293
294             if (nestedLoads != 1) {
295                 /* an extension table must not be loaded as a base table */
296                 throw new InvalidFormatException();
297             }
298
299             /* load the base table */
300             baseName = baseNameString;
301             if (baseName.equals(staticData.name)) {
302                 /* forbid loading this same extension-only file */
303                 throw new InvalidFormatException();
304             }
305
306             // agljport:fix args.size=sizeof(UConverterLoadArgs);
307             baseSharedData = loadConverter(2, baseName, classPath, loader);
308
309             if (baseSharedData.staticData.conversionType != UConverterType.MBCS
310                     || baseSharedData.mbcs.baseSharedData != null) {
311                 // agljport:fix ucnv_unload(baseSharedData);
312                 throw new InvalidFormatException();
313             }
314
315             /* copy the base table data */
316             // agljport:comment deep copy in C changes mbcs through local reference mbcsTable; in java we probably don't
317             // need the deep copy so can just make sure mbcs and its local reference both refer to the same new object
318             mbcsTable = data.mbcs = baseSharedData.mbcs;
319
320             /* overwrite values with relevant ones for the extension converter */
321             mbcsTable.baseSharedData = baseSharedData;
322             mbcsTable.extIndexes = extIndexes;
323
324             /*
325              * It would be possible to share the swapLFNL data with a base converter, but the generated name would have
326              * to be different, and the memory would have to be free'd only once. It is easier to just create the data
327              * for the extension converter separately when it is requested.
328              */
329             mbcsTable.swapLFNLStateTable = null;
330             mbcsTable.swapLFNLFromUnicodeBytes = null;
331             mbcsTable.swapLFNLName = null;
332
333             /*
334              * Set a special, runtime-only outputType if the extension converter is a DBCS version of a base converter
335              * that also maps single bytes.
336              */
337             if (staticData.conversionType == UConverterType.DBCS
338                     || (staticData.conversionType == UConverterType.MBCS && staticData.minBytesPerChar >= 2)) {
339
340                 if (baseSharedData.mbcs.outputType == MBCS_OUTPUT_2_SISO) {
341                     /* the base converter is SI/SO-stateful */
342                     int entry;
343
344                     /* get the dbcs state from the state table entry for SO=0x0e */
345                     entry = mbcsTable.stateTable[0][0xe];
346                     if (MBCS_ENTRY_IS_FINAL(entry) && MBCS_ENTRY_FINAL_ACTION(entry) == MBCS_STATE_CHANGE_ONLY
347                             && MBCS_ENTRY_FINAL_STATE(entry) != 0) {
348                         mbcsTable.dbcsOnlyState = (byte) MBCS_ENTRY_FINAL_STATE(entry);
349
350                         mbcsTable.outputType = MBCS_OUTPUT_DBCS_ONLY;
351                     }
352                 } else if (baseSharedData.staticData.conversionType == UConverterType.MBCS
353                         && baseSharedData.staticData.minBytesPerChar == 1
354                         && baseSharedData.staticData.maxBytesPerChar == 2 && mbcsTable.countStates <= 127) {
355
356                     /* non-stateful base converter, need to modify the state table */
357                     int newStateTable[][/* 256 */];
358                     int state[]; // this works because java 2-D array is array of references and we can have state =
359                     // newStateTable[i];
360                     int i, count;
361
362                     /* allocate a new state table and copy the base state table contents */
363                     count = mbcsTable.countStates;
364                     newStateTable = new int[(count + 1) * 1024][256];
365
366                     for (i = 0; i < mbcsTable.stateTable.length; ++i)
367                         System.arraycopy(mbcsTable.stateTable[i], 0, newStateTable[i], 0,
368                                 mbcsTable.stateTable[i].length);
369
370                     /* change all final single-byte entries to go to a new all-illegal state */
371                     state = newStateTable[0];
372                     for (i = 0; i < 256; ++i) {
373                         if (MBCS_ENTRY_IS_FINAL(state[i])) {
374                             state[i] = MBCS_ENTRY_TRANSITION(count, 0);
375                         }
376                     }
377
378                     /* build the new all-illegal state */
379                     state = newStateTable[count];
380                     for (i = 0; i < 256; ++i) {
381                         state[i] = MBCS_ENTRY_FINAL(0, MBCS_STATE_ILLEGAL, 0);
382                     }
383                     mbcsTable.stateTable = newStateTable;
384                     mbcsTable.countStates = (byte) (count + 1);
385                     mbcsTable.stateTableOwned = true;
386
387                     mbcsTable.outputType = MBCS_OUTPUT_DBCS_ONLY;
388                 }
389             }
390
391             /*
392              * unlike below for files with base tables, do not get the unicodeMask from the sharedData; instead, use the
393              * base table's unicodeMask, which we copied in the memcpy above; this is necessary because the static data
394              * unicodeMask, especially the UCNV_HAS_SUPPLEMENTARY flag, is part of the base table data
395              */
396         } else {
397             /* conversion file with a base table; an additional extension table is optional */
398             /* make sure that the output type is known */
399             switch (mbcsTable.outputType) {
400             case MBCS_OUTPUT_1:
401             case MBCS_OUTPUT_2:
402             case MBCS_OUTPUT_3:
403             case MBCS_OUTPUT_4:
404             case MBCS_OUTPUT_3_EUC:
405             case MBCS_OUTPUT_4_EUC:
406             case MBCS_OUTPUT_2_SISO:
407                 /* OK */
408                 break;
409             default:
410                 throw new InvalidFormatException();
411             }
412
413             stateTableArray = new int[header.countStates][256];
414             toUFallbacksArray = new MBCSToUFallback[header.countToUFallbacks];
415             for (int i = 0; i < toUFallbacksArray.length; ++i)
416                 toUFallbacksArray[i] = new MBCSToUFallback();
417             unicodeCodeUnitsArray = new char[(header.offsetFromUTable - header.offsetToUCodeUnits) / 2];
418             fromUnicodeTableArray = new char[(header.offsetFromUBytes - header.offsetFromUTable) / 2];
419             fromUnicodeBytesArray = new byte[header.fromUBytesLength];
420             try {
421                 reader.readMBCSTable(stateTableArray, toUFallbacksArray, unicodeCodeUnitsArray, fromUnicodeTableArray,
422                         fromUnicodeBytesArray);
423             } catch (IOException e) {
424                 throw new InvalidFormatException();
425             }
426
427             mbcsTable.countStates = (byte) header.countStates;
428             mbcsTable.countToUFallbacks = header.countToUFallbacks;
429             mbcsTable.stateTable = stateTableArray;
430             mbcsTable.toUFallbacks = toUFallbacksArray;
431             mbcsTable.unicodeCodeUnits = unicodeCodeUnitsArray;
432
433             mbcsTable.fromUnicodeTable = fromUnicodeTableArray;
434             mbcsTable.fromUnicodeBytes = fromUnicodeBytesArray;
435             mbcsTable.fromUBytesLength = header.fromUBytesLength;
436
437             /*
438              * converter versions 6.1 and up contain a unicodeMask that is used here to select the most efficient
439              * function implementations
440              */
441             // agljport:fix info.size=sizeof(UDataInfo);
442             // agljport:fix udata_getInfo((UDataMemory *)sharedData->dataMemory, &info);
443             // agljport:fix if(info.formatVersion[0]>6 || (info.formatVersion[0]==6 && info.formatVersion[1]>=1)) {
444             /* mask off possible future extensions to be safe */
445             mbcsTable.unicodeMask = (short) (staticData.unicodeMask & 3);
446             // agljport:fix } else {
447             /* for older versions, assume worst case: contains anything possible (prevent over-optimizations) */
448             // agljport:fix mbcsTable->unicodeMask=UCNV_HAS_SUPPLEMENTARY|UCNV_HAS_SURROGATES;
449             // agljport:fix }
450             if (offset != 0) {
451                 try {
452                     // agljport:commment subtract 32 for sizeof(_MBCSHeader) and length of baseNameString and 1 null
453                     // terminator byte all already read;
454                     // int namelen = baseNameString != null? baseNameString.length() + 1: 0;
455                     mbcsTable.extIndexes = reader.readExtIndexes(offset
456                             - (reader.bytesRead - reader.staticDataBytesRead));
457                 } catch (IOException e) {
458                     throw new InvalidFormatException();
459                 }
460             }
461             
462             if (header.version[1] >= 3 && (mbcsTable.unicodeMask & UConverterConstants.HAS_SURROGATES) == 0 &&
463                     (mbcsTable.countStates == 1 ? ((char)header.version[2] >= (SBCS_FAST_MAX>>8)) : ((char)header.version[2] >= (MBCS_FAST_MAX>>8)))) {
464                 mbcsTable.utf8Friendly = true;
465                 
466                 if (mbcsTable.countStates == 1) {
467                     /*
468                      * SBCS: Stage 3 is allocated in 64-entry blocks for U+0000..SBCS_FAST_MAX or higher.
469                      * Build a table with indexes to each block, to be used instaed of
470                      * the regular stage 1/2 table.
471                      */
472                     for (int i = 0; i < (SBCS_FAST_LIMIT>>6); ++i) {
473                         mbcsTable.sbcsIndex[i] = mbcsTable.fromUnicodeTable[mbcsTable.fromUnicodeTable[i>>4]+((i<<2)&0x3c)];
474                     }
475                     /* set SBCS_FAST_MAX to reflect the reach of sbcsIndex[] even if header.version[2]>(SBCS_FAST_MAX>>8) */
476                     mbcsTable.maxFastUChar = SBCS_FAST_MAX;
477                 } else {
478                     /*
479                      * MBCS: Stage 3 is allocated in 64-entry blocks for U+0000..MBCS_FAST_MAX or higher.
480                      * The .cnv file is prebuilt with an additional stage table with indexes to each block.
481                      */
482                     if (noFromU) {
483                         mbcsTable.mbcsIndex = ByteBuffer.wrap(mbcsTable.fromUnicodeBytes).asCharBuffer();
484                     }
485                     mbcsTable.maxFastUChar = (char)((header.version[2]<<8) | 0xff);
486                 }
487             }
488             /* calculate a bit set of 4 ASCII characters per bit that round-trip to ASCII bytes */
489             {
490                 long asciiRoundtrips = 0xffffffff;
491                 for (int i = 0; i < 0x80; ++i) {
492                     if (mbcsTable.stateTable[0][i] != MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, i)) {
493                         asciiRoundtrips&=~((long)1<<(i>>2))&UConverterConstants.UNSIGNED_INT_MASK;
494                     }
495                 }
496                 mbcsTable.asciiRoundtrips = asciiRoundtrips&UConverterConstants.UNSIGNED_INT_MASK;
497             }
498             
499             if (noFromU) {
500                 int stage1Length = (mbcsTable.unicodeMask&UConverterConstants.HAS_SUPPLEMENTARY) != 0 ? 0x440 : 0x40;
501                 int stage2Length = (header.offsetFromUBytes - header.offsetFromUTable)/4 - stage1Length/2;
502                 reconstituteData(mbcsTable, stage1Length, stage2Length, header.fullStage2Length);
503             }
504             if (mbcsTable.outputType == MBCS_OUTPUT_DBCS_ONLY || mbcsTable.outputType == MBCS_OUTPUT_2_SISO) {
505                 /*
506                  * MBCS_OUTPUT_DBCS_ONLY: No SBCS mappings, therefore ASCII does not roundtrip.
507                  * MBCS_OUTPUT_2_SISO: Bypass the ASCII fastpath to handle prevLength correctly.
508                  */
509                 mbcsTable.asciiRoundtrips = 0;
510             }
511         }
512         return data;
513     }
514     
515     private static boolean writeStage3Roundtrip(UConverterMBCSTable mbcsTable, long value, int codePoints[]) {
516         char[] table;
517         byte[] bytes;
518         int stage2;
519         int p;
520         int c;
521         int i, st3;
522         long temp;
523
524         table = mbcsTable.fromUnicodeTable;
525         bytes = mbcsTable.fromUnicodeBytes;
526
527         /* for EUC outputTypes, modify the value like genmbcs.c's transformEUC() */
528         switch(mbcsTable.outputType) {
529         case MBCS_OUTPUT_3_EUC:
530             if(value<=0xffff) {
531                 /* short sequences are stored directly */
532                 /* code set 0 or 1 */
533             } else if(value<=0x8effff) {
534                 /* code set 2 */
535                 value&=0x7fff;
536             } else /* first byte is 0x8f */ {
537                 /* code set 3 */
538                 value&=0xff7f;
539             }
540             break;
541         case MBCS_OUTPUT_4_EUC:
542             if(value<=0xffffff) {
543                 /* short sequences are stored directly */
544                 /* code set 0 or 1 */
545             } else if(value<=0x8effffff) {
546                 /* code set 2 */
547                 value&=0x7fffff;
548             } else /* first byte is 0x8f */ {
549                 /* code set 3 */
550                 value&=0xff7fff;
551             }
552             break;
553         default:
554             break;
555         }
556
557         for(i=0; i<=0x1f; ++value, ++i) {
558             c=codePoints[i];
559             if(c<0) {
560                 continue;
561             }
562
563             /* locate the stage 2 & 3 data */
564             stage2 = table[c>>10] + ((c>>4)&0x3f);
565             st3 = table[stage2*2]<<16|table[stage2*2 + 1];
566             st3 = (int)(char)(st3 * 16 + (c&0xf));
567
568             /* write the codepage bytes into stage 3 */
569             switch(mbcsTable.outputType) {
570             case MBCS_OUTPUT_3:
571             case MBCS_OUTPUT_4_EUC:
572                 p = st3*3;
573                 bytes[p] = (byte)(value>>16);
574                 bytes[p+1] = (byte)(value>>8);
575                 bytes[p+2] = (byte)value;
576                 break;
577             case MBCS_OUTPUT_4:
578                 bytes[st3*4] = (byte)(value >> 24);
579                 bytes[st3*4 + 1] = (byte)(value >> 16);
580                 bytes[st3*4 + 2] = (byte)(value >> 8);
581                 bytes[st3*4 + 3] = (byte)value;
582                 break;
583             default:
584                 /* 2 bytes per character */
585                 bytes[st3*2] = (byte)(value >> 8);
586                 bytes[st3*2 + 1] = (byte)value;
587                 break;
588             }
589
590             /* set the roundtrip flag */
591             temp = (1L<<(16+(c&0xf)));
592             table[stage2*2] |= (char)(temp>>16);
593             table[stage2*2 + 1] |= (char)temp;
594         }
595         return true;
596      }
597     
598     private static void reconstituteData(UConverterMBCSTable mbcsTable, int stage1Length, int stage2Length, int fullStage2Length) {
599         int datalength = stage1Length*2+fullStage2Length*4+mbcsTable.fromUBytesLength;
600         int offset = 0;
601         byte[] stage = new byte[datalength];
602         
603         for (int i = 0; i < stage1Length; ++i) {
604             stage[i*2]   = (byte)(mbcsTable.fromUnicodeTable[i]>>8);
605             stage[i*2+1] = (byte)(mbcsTable.fromUnicodeTable[i]);
606         }
607         
608         offset = ((fullStage2Length - stage2Length) * 4) + (stage1Length * 2);
609         for (int i = 0; i < stage2Length; ++i) {
610             stage[offset + i*4]   = (byte)(mbcsTable.fromUnicodeTable[stage1Length + i*2]>>8);
611             stage[offset + i*4+1] = (byte)(mbcsTable.fromUnicodeTable[stage1Length + i*2]);
612             stage[offset + i*4+2] = (byte)(mbcsTable.fromUnicodeTable[stage1Length + i*2+1]>>8);
613             stage[offset + i*4+3] = (byte)(mbcsTable.fromUnicodeTable[stage1Length + i*2+1]);
614         }
615         
616         /* indexes into stage 2 count from the bottom of the fromUnicodeTable */
617         
618         /* reconsitute the initial part of stage 2 from the mbcsIndex */
619         {
620             int stageUTF8Length=(mbcsTable.maxFastUChar+1)>>6;
621             int stageUTF8Index=0;
622             int st1, st2, st3, i;
623             
624             for (st1 = 0; stageUTF8Index < stageUTF8Length; ++st1) {
625                 st2 = ((char)stage[2*st1]<<8) | stage[2*st1+1];
626                 if (st2 != stage1Length/2) {
627                     /* each stage 2 block has 64 entries corresponding to 16 entries in the mbcsIndex */
628                     for (i = 0; i < 16; ++i) {
629                         st3 = mbcsTable.mbcsIndex.get(stageUTF8Index++);
630                         if (st3 != 0) {
631                             /* a stage 2 entry's index is per stage 3 16-block, not per stage 3 entry */
632                             st3>>=4;
633                             /*
634                              * 4 stage 2 entries point to 4 consecutive stage 3 16-blocks which are
635                              * allocated together as a single 64-block for access from the mbcsIndex
636                              */
637                             stage[4*st2] = (byte)(st3>>24); stage[4*st2+1] = (byte)(st3>>16); stage[4*st2+2] = (byte)(st3>>8); stage[4*st2+3] = (byte)(st3); st2++; st3++;
638                             stage[4*st2] = (byte)(st3>>24); stage[4*st2+1] = (byte)(st3>>16); stage[4*st2+2] = (byte)(st3>>8); stage[4*st2+3] = (byte)(st3); st2++; st3++;
639                             stage[4*st2] = (byte)(st3>>24); stage[4*st2+1] = (byte)(st3>>16); stage[4*st2+2] = (byte)(st3>>8); stage[4*st2+3] = (byte)(st3); st2++; st3++;
640                             stage[4*st2] = (byte)(st3>>24); stage[4*st2+1] = (byte)(st3>>16); stage[4*st2+2] = (byte)(st3>>8); stage[4*st2+3] = (byte)(st3);
641                         } else {
642                             /* no stage 3 block, skip */
643                             st2+=4;
644                         }
645                     }
646                 } else {
647                     /* no stage 2 block, skip */
648                     stageUTF8Index+=16;
649                 }
650             }
651         }
652         
653         char[] stage1 = new char[stage.length/2];
654         for (int i = 0; i < stage1.length; ++i) {
655             stage1[i] = (char)(((stage[i*2])<<8)|(stage[i*2+1] & UConverterConstants.UNSIGNED_BYTE_MASK));
656         }
657         byte[] stage2 = new byte[stage.length - ((stage1Length * 2) + (fullStage2Length * 4))];
658         System.arraycopy(stage, ((stage1Length * 2) + (fullStage2Length * 4)), stage2, 0, stage2.length);
659         
660         mbcsTable.fromUnicodeTable = stage1;
661         mbcsTable.fromUnicodeBytes = stage2;
662         
663         /* reconstitute fromUnicodeBytes with roundtrips from toUnicode data */
664         MBCSEnumToUnicode(mbcsTable);
665     }
666     
667     /*
668      * Internal function enumerating the toUnicode data of an MBCS converter.
669      * Currently only used for reconstituting data for a MBCS_OPT_NO_FROM_U
670      * table, but could also be used for a future getUnicodeSet() option
671      * that includes reverse fallbacks (after updating this function's implementation).
672      * Currently only handles roundtrip mappings.
673      * Does not currently handle extensions.
674      */
675     private static void MBCSEnumToUnicode(UConverterMBCSTable mbcsTable) {
676         /*
677          * Properties for each state, to speed up the enumeration.
678          * Ignorable actions are unassigned/illegal/state-change-only:
679          * They do not lead to mappings.
680          * 
681          * Bits 7..6
682          * 1 direct/initial state (stateful converters have mulitple)
683          * 0 non-initial state with transitions or with nonignorable result actions
684          * -1 final state with only ignorable actions
685          * 
686          * Bits 5..3
687          * The lowest byte value with non-ignorable actions is
688          * value<<5 (rounded down).
689          * 
690          * Bits 2..0:
691          * The highest byte value with non-ignorable actions is
692          * (value<<5)&0x1f (rounded up).
693          */
694         byte stateProps[] = new byte[MBCS_MAX_STATE_COUNT];
695         int state;
696         
697         /* recurse from state 0 and set all stateProps */
698         getStateProp(mbcsTable.stateTable, stateProps, 0);
699         
700         for (state = 0; state < mbcsTable.countStates; ++state) {
701             if (stateProps[state] >= 0x40) {
702                 /* start from each direct state */
703                 enumToU(mbcsTable, stateProps, state, 0, 0);
704             }
705         }
706         
707         
708     }
709     
710     private static boolean enumToU(UConverterMBCSTable mbcsTable, byte stateProps[], int state, int offset, int value) {
711         int[] codePoints = new int[32];
712         int[] row;
713         char[] unicodeCodeUnits;
714         int anyCodePoints;
715         int b, limit;
716         
717         row = mbcsTable.stateTable[state];
718         unicodeCodeUnits = mbcsTable.unicodeCodeUnits;
719         
720         value<<=8;
721         anyCodePoints = -1; /* becomes non-negative if there is a mapping */
722         
723         b = (stateProps[state]&0x38)<<2;
724         if (b == 0 && stateProps[state] >= 0x40) {
725             /* skip byte sequences with leading zeros because they are note stored in the fromUnicode table */
726             codePoints[0] = UConverterConstants.U_SENTINEL;
727             b = 1;
728         }
729         limit = ((stateProps[state]&7)+1)<<5;
730         while (b < limit) {
731             int entry = row[b];
732             if (MBCS_ENTRY_IS_TRANSITION(entry)) {
733                 int nextState = MBCS_ENTRY_TRANSITION_STATE(entry);
734                 if (stateProps[nextState] >= 0) {
735                     /* recurse to a state with non-ignorable actions */
736                     if (!enumToU(mbcsTable, stateProps, nextState, offset+MBCS_ENTRY_TRANSITION_OFFSET(entry), value|b)) {
737                         return false;
738                     }
739                 }
740                 codePoints[b&0x1f] = UConverterConstants.U_SENTINEL;
741             } else {
742                 int c;
743                 int action;
744                 
745                 /*
746                  * An if-else-if chain provides more reliable performance for
747                  * the most common cases compared to a switch.
748                  */
749                 action = MBCS_ENTRY_FINAL_ACTION(entry);
750                 if (action == MBCS_STATE_VALID_DIRECT_16) {
751                     /* output BMP code point */
752                     c = MBCS_ENTRY_FINAL_VALUE_16(entry);
753                 } else if (action == MBCS_STATE_VALID_16) {
754                     int finalOffset = offset+MBCS_ENTRY_FINAL_VALUE_16(entry);
755                     c = unicodeCodeUnits[finalOffset];
756                     if (c < 0xfffe) {
757                         /* output BMP code point */
758                     } else {
759                         c = UConverterConstants.U_SENTINEL;
760                     }
761                 } else if (action == MBCS_STATE_VALID_16_PAIR) {
762                     int finalOffset = offset+MBCS_ENTRY_FINAL_VALUE_16(entry);
763                     c = unicodeCodeUnits[finalOffset++];
764                     if (c < 0xd800) {
765                         /* output BMP code point below 0xd800 */
766                     } else if (c <= 0xdbff) {
767                         /* output roundtrip or fallback supplementary code point */
768                         c = ((c&0x3ff)<<10)+unicodeCodeUnits[finalOffset]+(0x10000-0xdc00);
769                     } else if (c == 0xe000) {
770                         /* output roundtrip BMP code point above 0xd800 or fallback BMP code point */
771                         c = unicodeCodeUnits[finalOffset];
772                     } else {
773                         c = UConverterConstants.U_SENTINEL;
774                     }
775                 } else if (action == MBCS_STATE_VALID_DIRECT_20) {
776                     /* output supplementary code point */
777                     c = MBCS_ENTRY_FINAL_VALUE(entry)+0x10000;
778                 } else {
779                     c = UConverterConstants.U_SENTINEL;
780                 }
781                 
782                 codePoints[b&0x1f] = c;
783                 anyCodePoints&=c;
784             }
785             if (((++b)&0x1f) == 0) {
786                 if(anyCodePoints>=0) {
787                     if(!writeStage3Roundtrip(mbcsTable, value|(b-0x20)&UConverterConstants.UNSIGNED_INT_MASK, codePoints)) {
788                         return false;
789                     }
790                     anyCodePoints=-1;
791                 }
792             }
793         }
794         
795         return true;
796     }
797     
798     /*
799      * Only called if stateProps[state]==-1.
800      * A recursive call may do stateProps[state]|=0x40 if this state is the target of an
801      * MBCS_STATE_CHANGE_ONLY.
802      */
803     private static byte getStateProp(int stateTable[][], byte stateProps[], int state) {
804         int[] row;
805         int min, max, entry, nextState;
806         
807         row = stateTable[state];
808         stateProps[state] = 0;
809         
810         /* find first non-ignorable state */
811         for (min = 0;;++min) {
812             entry = row[min];
813             nextState = MBCS_ENTRY_STATE(entry);
814             if (stateProps[nextState] == -1) {
815                 getStateProp(stateTable, stateProps, nextState);
816             }
817             if (MBCS_ENTRY_IS_TRANSITION(entry)) {
818                 if (stateProps[nextState] >- 0) {
819                     break;
820                 }
821             } else if (MBCS_ENTRY_FINAL_ACTION(entry) < MBCS_STATE_UNASSIGNED) {
822                 break;
823             }
824             if (min == 0xff) {
825                 stateProps[state] = -0x40;  /* (byte)0xc0 */
826                 return stateProps[state];
827             }
828         }
829         stateProps[state]|=(byte)((min>>5)<<3);
830         
831         /* find last non-ignorable state */
832         for (max = 0xff; min < max; --max) {
833             entry = row[max];
834             nextState = MBCS_ENTRY_STATE(entry);
835             if (stateProps[nextState] == -1) {
836                 getStateProp(stateTable, stateProps, nextState);
837             }
838             if (MBCS_ENTRY_IS_TRANSITION(entry)) {
839                 if (stateProps[nextState] >- 0) {
840                     break;
841                 }
842             } else if (MBCS_ENTRY_FINAL_ACTION(entry) < MBCS_STATE_UNASSIGNED) {
843                 break;
844             }
845         }
846         stateProps[state]|=(byte)(max>>5);
847         
848         /* recurse further and collect direct-state information */
849         while (min <= max) {
850             entry = row[min];
851             nextState = MBCS_ENTRY_STATE(entry);
852             if (stateProps[nextState] == -1) {
853                 getStateProp(stateTable, stateProps, nextState);
854             }
855             if (MBCS_ENTRY_IS_TRANSITION(entry)) {
856                 stateProps[nextState]|=0x40;
857                 if (MBCS_ENTRY_FINAL_ACTION(entry) <= MBCS_STATE_FALLBACK_DIRECT_20) {
858                     stateProps[state]|=0x40;
859                 }
860             }
861             ++min;
862         }
863         return stateProps[state];
864     }
865
866     protected void initializeConverter(int myOptions) {
867         UConverterMBCSTable mbcsTable;
868         ByteBuffer extIndexes;
869         short outputType;
870         byte maxBytesPerUChar;
871
872         mbcsTable = sharedData.mbcs;
873         outputType = mbcsTable.outputType;
874
875         if (outputType == MBCS_OUTPUT_DBCS_ONLY) {
876             /* the swaplfnl option does not apply, remove it */
877             this.options = myOptions &= ~UConverterConstants.OPTION_SWAP_LFNL;
878         }
879
880         if ((myOptions & UConverterConstants.OPTION_SWAP_LFNL) != 0) {
881             /* do this because double-checked locking is broken */
882             boolean isCached;
883
884             // agljport:todo umtx_lock(NULL);
885             isCached = mbcsTable.swapLFNLStateTable != null;
886             // agljport:todo umtx_unlock(NULL);
887
888             if (!isCached) {
889                 try {
890                     if (!EBCDICSwapLFNL()) {
891                         /* this option does not apply, remove it */
892                         this.options = myOptions &= ~UConverterConstants.OPTION_SWAP_LFNL;
893                     }
894                 } catch (Exception e) {
895                     /* something went wrong. */
896                     return;
897                 }
898             }
899         }
900
901         if (icuCanonicalName.toLowerCase().indexOf("gb18030") >= 0) {
902             /* set a flag for GB 18030 mode, which changes the callback behavior */
903             this.options |= MBCS_OPTION_GB18030;
904         } else if (icuCanonicalName.toLowerCase().indexOf("keis") >= 0) {
905             this.options |= MBCS_OPTION_KEIS;
906         } else if (icuCanonicalName.toLowerCase().indexOf("jef") >= 0) {
907             this.options |= MBCS_OPTION_JEF;
908         } else if (icuCanonicalName.toLowerCase().indexOf("jips") >= 0) {
909             this.options |= MBCS_OPTION_JIPS;
910         }
911
912         /* fix maxBytesPerUChar depending on outputType and options etc. */
913         if (outputType == MBCS_OUTPUT_2_SISO) {
914             maxBytesPerChar = 3; /* SO+DBCS */
915         }
916
917         extIndexes = mbcsTable.extIndexes;
918         if (extIndexes != null) {
919             maxBytesPerUChar = (byte) GET_MAX_BYTES_PER_UCHAR(extIndexes);
920             if (outputType == MBCS_OUTPUT_2_SISO) {
921                 ++maxBytesPerUChar; /* SO + multiple DBCS */
922             }
923
924             if (maxBytesPerUChar > maxBytesPerChar) {
925                 maxBytesPerChar = maxBytesPerUChar;
926             }
927         }
928     }
929      /* EBCDIC swap LF<->NL--------------------------------------------------------------------------------*/
930      /*
931       * This code modifies a standard EBCDIC<->Unicode mappling table for
932       * OS/390 (z/OS) Unix System Services (Open Edition).
933       * The difference is in the mapping of Line Feed and New Line control codes:
934       * Standard EBDIC maps
935       * 
936       * <U000A> \x25 |0
937       * <U0085> \x15 |0
938       * 
939       * but OS/390 USS EBCDIC swaps the control codes for LF and NL,
940       * mapping
941       * 
942       * <U000A> \x15 |0
943       * <U0085> \x25 |0
944       * 
945       * This code modifies a loaded standard EBCDIC<->Unicode mapping table
946       * by copying it into allocated memory and swapping the LF and NL values.
947       * It allows to support the same EBCDIC charset in both version without
948       * duplicating the entire installed table.
949       */
950     /* standard EBCDIC codes */
951     private static final short EBCDIC_LF = 0x0025;
952     private static final short EBCDIC_NL = 0x0015;
953     
954     /* standard EBCDIC codes with roundtrip flag as stored in Unicode-to-single-byte tables */
955     private static final short EBCDIC_RT_LF = 0x0f25;
956     private static final short EBCDIC_RT_NL = 0x0f15;
957     
958     /* Unicode code points */
959     private static final short U_LF = 0x000A;
960     private static final short U_NL = 0x0085;
961     
962     private boolean EBCDICSwapLFNL() throws Exception {
963         UConverterMBCSTable mbcsTable;
964         
965         char[] table;
966         byte[] results;
967         byte[] bytes;
968         
969         int[][] newStateTable;
970         byte[] newResults;
971         String newName;
972         
973         int stage2Entry;
974 //        int size;
975         int sizeofFromUBytes;
976         
977         mbcsTable = sharedData.mbcs;
978         
979         table = mbcsTable.fromUnicodeTable;
980         bytes = mbcsTable.fromUnicodeBytes;
981         results = bytes;
982         
983         /*
984          * Check that this is an EBCDIC table with SBCS portion -
985          * SBCS or EBCDIC with standard EBCDIC LF and NL mappings.
986          * 
987          * If not, ignore the option Options are always ignored if they do not apply.
988          */
989         if (!((mbcsTable.outputType == MBCS_OUTPUT_1 || mbcsTable.outputType == MBCS_OUTPUT_2_SISO) &&
990               mbcsTable.stateTable[0][EBCDIC_LF] == MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, U_LF) &&
991               mbcsTable.stateTable[0][EBCDIC_NL] == MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, U_NL))) {
992             return false;
993         }
994         
995         if (mbcsTable.outputType == MBCS_OUTPUT_1) {
996             if (!(EBCDIC_RT_LF == MBCS_SINGLE_RESULT_FROM_U(table, results, U_LF) &&
997                   EBCDIC_RT_NL == MBCS_SINGLE_RESULT_FROM_U(table, results, U_NL))) {
998                 return false;
999             }
1000         } else /* MBCS_OUTPUT_2_SISO */ {
1001             stage2Entry = MBCS_STAGE_2_FROM_U(table, U_LF);
1002             if (!(MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, U_LF) &&
1003                   EBCDIC_LF == MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, U_LF))) {
1004                 return false;
1005             }
1006             
1007             stage2Entry = MBCS_STAGE_2_FROM_U(table, U_NL);
1008             if (!(MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, U_NL) &&
1009                   EBCDIC_NL == MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, U_NL))) {
1010                 return false;
1011             }
1012         }
1013         
1014         if (mbcsTable.fromUBytesLength > 0) {
1015             /*
1016              * We _know_ the number of bytes in the fromUnicodeBytes array
1017              * starting with header.version 4.1.
1018              */
1019             sizeofFromUBytes = mbcsTable.fromUBytesLength;
1020         } else {
1021             /*
1022              * Otherwise:
1023              * There used to be code to enumerate the fromUnicode
1024              * trie and find the highest entry, but it was removed in ICU 3.2
1025              * because it was not tested and caused a low code coverage number.
1026              */
1027             throw new Exception("U_INVALID_FORMAT_ERROR");
1028         }
1029         
1030         /*
1031          * The table has an appropriate format.
1032          * Allocate and build
1033          * - a modified to-Unicode state table
1034          * - a modified from-Unicode output array
1035          * - a converter name string with the swap option appended
1036          */
1037 //        size = mbcsTable.countStates * 1024 + sizeofFromUBytes + UConverterConstants.MAX_CONVERTER_NAME_LENGTH + 20;
1038         
1039         /* copy and modify the to-Unicode state table */
1040         newStateTable = new int[mbcsTable.stateTable.length][mbcsTable.stateTable[0].length];
1041         for (int i = 0; i < newStateTable.length; i++) {
1042             System.arraycopy(mbcsTable.stateTable[i], 0, newStateTable[i], 0, newStateTable[i].length);
1043         }
1044         
1045         newStateTable[0][EBCDIC_LF] = MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, U_NL);
1046         newStateTable[0][EBCDIC_NL] = MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, U_LF);
1047         
1048         /* copy and modify the from-Unicode result table */
1049         newResults = new byte[sizeofFromUBytes];
1050         System.arraycopy(bytes, 0, newResults, 0, sizeofFromUBytes);
1051         /* conveniently, the table access macros work on the left side of expressions */
1052         if (mbcsTable.outputType == MBCS_OUTPUT_1) {
1053             MBCS_SINGLE_RESULT_FROM_U_SET(table, newResults, U_LF, EBCDIC_RT_NL);
1054             MBCS_SINGLE_RESULT_FROM_U_SET(table, newResults, U_NL, EBCDIC_RT_LF);
1055         } else /* MBCS_OUTPUT_2_SISO */ {
1056             stage2Entry = MBCS_STAGE_2_FROM_U(table, U_LF);
1057             MBCS_VALUE_2_FROM_STAGE_2_SET(newResults, stage2Entry, U_LF, EBCDIC_NL);
1058             
1059             stage2Entry = MBCS_STAGE_2_FROM_U(table, U_NL);
1060             MBCS_VALUE_2_FROM_STAGE_2_SET(newResults, stage2Entry, U_NL, EBCDIC_LF);
1061         }
1062         
1063         /* set the canonical converter name */
1064         newName = new String(icuCanonicalName);
1065         newName.concat(UConverterConstants.OPTION_SWAP_LFNL_STRING);
1066         
1067         if (mbcsTable.swapLFNLStateTable == null) {
1068             mbcsTable.swapLFNLStateTable = newStateTable;
1069             mbcsTable.swapLFNLFromUnicodeBytes = newResults;
1070             mbcsTable.swapLFNLName = newName;
1071         }
1072         return true;
1073     }
1074
1075     /**
1076      * MBCS output types for conversions from Unicode. These per-converter types determine the storage method in stage 3
1077      * of the lookup table, mostly how many bytes are stored per entry.
1078      */
1079     static final int MBCS_OUTPUT_1 = 0; /* 0 */
1080     static final int MBCS_OUTPUT_2 = MBCS_OUTPUT_1 + 1; /* 1 */
1081     static final int MBCS_OUTPUT_3 = MBCS_OUTPUT_2 + 1; /* 2 */
1082     static final int MBCS_OUTPUT_4 = MBCS_OUTPUT_3 + 1; /* 3 */
1083     static final int MBCS_OUTPUT_3_EUC = 8; /* 8 */
1084     static final int MBCS_OUTPUT_4_EUC = MBCS_OUTPUT_3_EUC + 1; /* 9 */
1085     static final int MBCS_OUTPUT_2_SISO = 12; /* c */
1086     static final int MBCS_OUTPUT_2_HZ = MBCS_OUTPUT_2_SISO + 1; /* d */
1087     static final int MBCS_OUTPUT_EXT_ONLY = MBCS_OUTPUT_2_HZ + 1; /* e */
1088     // static final int MBCS_OUTPUT_COUNT = MBCS_OUTPUT_EXT_ONLY + 1;
1089     static final int MBCS_OUTPUT_DBCS_ONLY = 0xdb; /* runtime-only type for DBCS-only handling of SISO tables */
1090
1091     /* GB 18030 data ------------------------------------------------------------ */
1092
1093     /* helper macros for linear values for GB 18030 four-byte sequences */
1094     private static long LINEAR_18030(long a, long b, long c, long d) {
1095         return ((((a & 0xff) * 10 + (b & 0xff)) * 126L + (c & 0xff)) * 10L + (d & 0xff));
1096     }
1097
1098     private static long LINEAR_18030_BASE = LINEAR_18030(0x81, 0x30, 0x81, 0x30);
1099
1100     private static long LINEAR(long x) {
1101         return LINEAR_18030(x >>> 24, (x >>> 16) & 0xff, (x >>> 8) & 0xff, x & 0xff);
1102     }
1103
1104     /*
1105      * Some ranges of GB 18030 where both the Unicode code points and the GB four-byte sequences are contiguous and are
1106      * handled algorithmically by the special callback functions below. The values are start & end of Unicode & GB
1107      * codes.
1108      * 
1109      * Note that single surrogates are not mapped by GB 18030 as of the re-released mapping tables from 2000-nov-30.
1110      */
1111     private static final long gb18030Ranges[][] = new long[/* 14 */][/* 4 */] {
1112             { 0x10000L, 0x10FFFFL, LINEAR(0x90308130L), LINEAR(0xE3329A35L) },
1113             { 0x9FA6L, 0xD7FFL, LINEAR(0x82358F33L), LINEAR(0x8336C738L) },
1114             { 0x0452L, 0x1E3EL, LINEAR(0x8130D330L), LINEAR(0x8135F436L) },
1115             { 0x1E40L, 0x200FL, LINEAR(0x8135F438L), LINEAR(0x8136A531L) },
1116             { 0xE865L, 0xF92BL, LINEAR(0x8336D030L), LINEAR(0x84308534L) },
1117             { 0x2643L, 0x2E80L, LINEAR(0x8137A839L), LINEAR(0x8138FD38L) },
1118             { 0xFA2AL, 0xFE2FL, LINEAR(0x84309C38L), LINEAR(0x84318537L) },
1119             { 0x3CE1L, 0x4055L, LINEAR(0x8231D438L), LINEAR(0x8232AF32L) },
1120             { 0x361BL, 0x3917L, LINEAR(0x8230A633L), LINEAR(0x8230F237L) },
1121             { 0x49B8L, 0x4C76L, LINEAR(0x8234A131L), LINEAR(0x8234E733L) },
1122             { 0x4160L, 0x4336L, LINEAR(0x8232C937L), LINEAR(0x8232F837L) },
1123             { 0x478EL, 0x4946L, LINEAR(0x8233E838L), LINEAR(0x82349638L) },
1124             { 0x44D7L, 0x464BL, LINEAR(0x8233A339L), LINEAR(0x8233C931L) },
1125             { 0xFFE6L, 0xFFFFL, LINEAR(0x8431A234L), LINEAR(0x8431A439L) } };
1126
1127     /* bit flag for UConverter.options indicating GB 18030 special handling */
1128     private static final int MBCS_OPTION_GB18030 = 0x8000;
1129     
1130     /* bit flag for UConverter.options indicating KEIS,JEF,JIF special handling */ 
1131     private static final int MBCS_OPTION_KEIS = 0x01000;
1132     private static final int MBCS_OPTION_JEF = 0x02000;
1133     private static final int MBCS_OPTION_JIPS = 0x04000; 
1134     
1135     private static enum SISO_Option {
1136         SI,
1137         SO
1138     }
1139     
1140     private static final byte[] KEIS_SO_CHAR = { 0x0A, 0x42 };
1141     private static final byte[] KEIS_SI_CHAR = { 0x0A, 0x41 };
1142     private static final byte JEF_SO_CHAR = 0x28;
1143     private static final byte JEF_SI_CHAR = 0x29;
1144     private static final byte[] JIPS_SO_CHAR = { 0x1A, 0x70 };
1145     private static final byte[] JIPS_SI_CHAR = { 0x1A, 0x71 };
1146     
1147     private static int getSISOBytes(SISO_Option option, int cnvOption, byte[] value) {
1148         int SISOLength = 0;
1149
1150         switch (option) {
1151             case SI:
1152                 if ((cnvOption&MBCS_OPTION_KEIS)!=0) {
1153                     value[0] = KEIS_SI_CHAR[0];
1154                     value[1] = KEIS_SI_CHAR[1];
1155                     SISOLength = 2;
1156                 } else if ((cnvOption&MBCS_OPTION_JEF)!=0) {
1157                     value[0] = JEF_SI_CHAR;
1158                     SISOLength = 1;
1159                 } else if ((cnvOption&MBCS_OPTION_JIPS)!=0) {
1160                     value[0] = JIPS_SI_CHAR[0];
1161                     value[1] = JIPS_SI_CHAR[1];
1162                     SISOLength = 2;
1163                 } else {
1164                     value[0] = UConverterConstants.SI;
1165                     SISOLength = 1;
1166                 }
1167                 break;
1168             case SO:
1169                 if ((cnvOption&MBCS_OPTION_KEIS)!=0) {
1170                     value[0] = KEIS_SO_CHAR[0];
1171                     value[1] = KEIS_SO_CHAR[1];
1172                     SISOLength = 2;
1173                 } else if ((cnvOption&MBCS_OPTION_JEF)!=0) {
1174                     value[0] = JEF_SO_CHAR;
1175                     SISOLength = 1;
1176                 } else if ((cnvOption&MBCS_OPTION_JIPS)!=0) {
1177                     value[0] = JIPS_SO_CHAR[0];
1178                     value[1] = JIPS_SO_CHAR[1];
1179                     SISOLength = 2;
1180                 } else {
1181                     value[0] = UConverterConstants.SO;
1182                     SISOLength = 1;
1183                 }
1184                 break;
1185             default:
1186                 /* Should never happen. */
1187                 break;
1188         }
1189
1190         return SISOLength;
1191     }
1192     // enum {
1193         static final int MBCS_MAX_STATE_COUNT = 128;
1194     // };
1195     /**
1196      * MBCS action codes for conversions to Unicode. These values are in bits 23..20 of the state table entries.
1197      */
1198     static final int MBCS_STATE_VALID_DIRECT_16 = 0;
1199     static final int MBCS_STATE_VALID_DIRECT_20 = MBCS_STATE_VALID_DIRECT_16 + 1;
1200     static final int MBCS_STATE_FALLBACK_DIRECT_16 = MBCS_STATE_VALID_DIRECT_20 + 1;
1201     static final int MBCS_STATE_FALLBACK_DIRECT_20 = MBCS_STATE_FALLBACK_DIRECT_16 + 1;
1202     static final int MBCS_STATE_VALID_16 = MBCS_STATE_FALLBACK_DIRECT_20 + 1;
1203     static final int MBCS_STATE_VALID_16_PAIR = MBCS_STATE_VALID_16 + 1;
1204     static final int MBCS_STATE_UNASSIGNED = MBCS_STATE_VALID_16_PAIR + 1;
1205     static final int MBCS_STATE_ILLEGAL = MBCS_STATE_UNASSIGNED + 1;
1206     static final int MBCS_STATE_CHANGE_ONLY = MBCS_STATE_ILLEGAL + 1;
1207     
1208     static int MBCS_ENTRY_SET_STATE(int entry, int state) { 
1209         return (entry&0x80ffffff)|(state<<24L);
1210     }
1211
1212     static int MBCS_ENTRY_STATE(int entry) {
1213         return (((entry)>>24)&0x7f);
1214     }
1215
1216     /* Methods for state table entries */
1217     static int MBCS_ENTRY_TRANSITION(int state, int offset) {
1218         return (state << 24L) | offset;
1219     }
1220
1221     static int MBCS_ENTRY_FINAL(int state, int action, int value) {
1222         return 0x80000000 | (state << 24L) | (action << 20L) | value;
1223     }
1224
1225     static boolean MBCS_ENTRY_IS_TRANSITION(int entry) {
1226         return (entry) >= 0;
1227     }
1228
1229     static boolean MBCS_ENTRY_IS_FINAL(int entry) {
1230         return (entry) < 0;
1231     }
1232
1233     static int MBCS_ENTRY_TRANSITION_STATE(int entry) {
1234         return ((entry) >>> 24);
1235     }
1236
1237     static int MBCS_ENTRY_TRANSITION_OFFSET(int entry) {
1238         return ((entry) & 0xffffff);
1239     }
1240
1241     static int MBCS_ENTRY_FINAL_STATE(int entry) {
1242         return ((entry) >>> 24) & 0x7f;
1243     }
1244
1245     static boolean MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(int entry) {
1246         return ((entry) < 0x80100000);
1247     }
1248
1249     static int MBCS_ENTRY_FINAL_ACTION(int entry) {
1250         return ((entry) >>> 20) & 0xf;
1251     }
1252
1253     static int MBCS_ENTRY_FINAL_VALUE(int entry) {
1254         return ((entry) & 0xfffff);
1255     }
1256
1257     static char MBCS_ENTRY_FINAL_VALUE_16(int entry) {
1258         return (char) (entry);
1259     }
1260     
1261     static boolean MBCS_IS_ASCII_ROUNDTRIP(int b, long asciiRoundtrips) {
1262         return (((asciiRoundtrips) & (1<<((b)>>2)))!=0);
1263     }
1264     
1265     /**
1266      * This macro version of _MBCSSingleSimpleGetNextUChar() gets a code point from a byte. It works for single-byte,
1267      * single-state codepages that only map to and from BMP code points, and it always returns fallback values.
1268      */
1269     static char MBCS_SINGLE_SIMPLE_GET_NEXT_BMP(UConverterMBCSTable mbcs, final int b) {
1270         return MBCS_ENTRY_FINAL_VALUE_16(mbcs.stateTable[0][b & UConverterConstants.UNSIGNED_BYTE_MASK]);
1271     }
1272
1273     /* single-byte fromUnicode: get the 16-bit result word */
1274     static char MBCS_SINGLE_RESULT_FROM_U(char[] table, byte[] results, int c) {
1275         int i1 = table[c >>> 10] + ((c >>> 4) & 0x3f);
1276         int i = 2 * (table[i1] + (c & 0xf)); // used as index into byte[] array treated as char[] array
1277         return (char) (((results[i] & UConverterConstants.UNSIGNED_BYTE_MASK) << 8) | (results[i + 1] & UConverterConstants.UNSIGNED_BYTE_MASK));
1278     }
1279     
1280     /* single-byte fromUnicode: set the 16-bit result word with newValue*/
1281     static void MBCS_SINGLE_RESULT_FROM_U_SET(char[] table, byte[] results, int c, int newValue) {
1282         int i1 = table[c >>> 10] + ((c >>> 4) & 0x3f);
1283         int i = 2 * (table[i1] + (c & 0xf)); // used as index into byte[] array treated as char[] array
1284         results[i] = (byte)((newValue >> 8) & UConverterConstants.UNSIGNED_BYTE_MASK);
1285         results[i + 1] =  (byte)(newValue & UConverterConstants.UNSIGNED_BYTE_MASK);
1286     }
1287
1288     /* multi-byte fromUnicode: get the 32-bit stage 2 entry */
1289     static int MBCS_STAGE_2_FROM_U(char[] table, int c) {
1290         int i = 2 * (table[(c) >>> 10] + ((c >>> 4) & 0x3f)); // 2x because used as index into char[] array treated as
1291         // int[] array
1292         return ((table[i] & UConverterConstants.UNSIGNED_SHORT_MASK) << 16)
1293                 | (table[i + 1] & UConverterConstants.UNSIGNED_SHORT_MASK);
1294     }
1295
1296     private static boolean MBCS_FROM_U_IS_ROUNDTRIP(int stage2Entry, int c) {
1297         return (((stage2Entry) & (1 << (16 + ((c) & 0xf)))) != 0);
1298     }
1299
1300     static char MBCS_VALUE_2_FROM_STAGE_2(byte[] bytes, int stage2Entry, int c) {
1301         int i = 2 * (16 * ((char) stage2Entry & UConverterConstants.UNSIGNED_SHORT_MASK) + (c & 0xf));
1302         return (char) (((bytes[i] & UConverterConstants.UNSIGNED_BYTE_MASK) << 8) | (bytes[i + 1] & UConverterConstants.UNSIGNED_BYTE_MASK));
1303     }
1304     
1305     static void MBCS_VALUE_2_FROM_STAGE_2_SET(byte[] bytes, int stage2Entry, int c, int newValue) {
1306         int i = 2 * (16 * ((char) stage2Entry & UConverterConstants.UNSIGNED_SHORT_MASK) + (c & 0xf));
1307         bytes[i] = (byte)((newValue >> 8) & UConverterConstants.UNSIGNED_BYTE_MASK);
1308         bytes[i + 1] = (byte)(newValue & UConverterConstants.UNSIGNED_BYTE_MASK);
1309     }
1310
1311     private static int MBCS_VALUE_4_FROM_STAGE_2(byte[] bytes, int stage2Entry, int c) {
1312         int i = 4 * (16 * ((char) stage2Entry & UConverterConstants.UNSIGNED_SHORT_MASK) + (c & 0xf));
1313         return ((bytes[i] & UConverterConstants.UNSIGNED_BYTE_MASK) << 24)
1314                 | ((bytes[i + 1] & UConverterConstants.UNSIGNED_BYTE_MASK) << 16)
1315                 | ((bytes[i + 2] & UConverterConstants.UNSIGNED_BYTE_MASK) << 8)
1316                 | (bytes[i + 3] & UConverterConstants.UNSIGNED_BYTE_MASK);
1317     }
1318
1319     static int MBCS_POINTER_3_FROM_STAGE_2(byte[] bytes, int stage2Entry, int c) {
1320         return ((16 * ((char) (stage2Entry) & UConverterConstants.UNSIGNED_SHORT_MASK) + ((c) & 0xf)) * 3);
1321     }
1322
1323     // ------------UConverterExt-------------------------------------------------------
1324
1325     static final int EXT_INDEXES_LENGTH = 0; /* 0 */
1326
1327     static final int EXT_TO_U_INDEX = EXT_INDEXES_LENGTH + 1; /* 1 */
1328     static final int EXT_TO_U_LENGTH = EXT_TO_U_INDEX + 1;
1329     static final int EXT_TO_U_UCHARS_INDEX = EXT_TO_U_LENGTH + 1;
1330     static final int EXT_TO_U_UCHARS_LENGTH = EXT_TO_U_UCHARS_INDEX + 1;
1331
1332     static final int EXT_FROM_U_UCHARS_INDEX = EXT_TO_U_UCHARS_LENGTH + 1; /* 5 */
1333     static final int EXT_FROM_U_VALUES_INDEX = EXT_FROM_U_UCHARS_INDEX + 1;
1334     static final int EXT_FROM_U_LENGTH = EXT_FROM_U_VALUES_INDEX + 1;
1335     static final int EXT_FROM_U_BYTES_INDEX = EXT_FROM_U_LENGTH + 1;
1336     static final int EXT_FROM_U_BYTES_LENGTH = EXT_FROM_U_BYTES_INDEX + 1;
1337
1338     static final int EXT_FROM_U_STAGE_12_INDEX = EXT_FROM_U_BYTES_LENGTH + 1; /* 10 */
1339     static final int EXT_FROM_U_STAGE_1_LENGTH = EXT_FROM_U_STAGE_12_INDEX + 1;
1340     static final int EXT_FROM_U_STAGE_12_LENGTH = EXT_FROM_U_STAGE_1_LENGTH + 1;
1341     static final int EXT_FROM_U_STAGE_3_INDEX = EXT_FROM_U_STAGE_12_LENGTH + 1;
1342     static final int EXT_FROM_U_STAGE_3_LENGTH = EXT_FROM_U_STAGE_3_INDEX + 1;
1343     static final int EXT_FROM_U_STAGE_3B_INDEX = EXT_FROM_U_STAGE_3_LENGTH + 1;
1344     static final int EXT_FROM_U_STAGE_3B_LENGTH = EXT_FROM_U_STAGE_3B_INDEX + 1;
1345
1346     private static final int EXT_COUNT_BYTES = EXT_FROM_U_STAGE_3B_LENGTH + 1; /* 17 */
1347     // private static final int EXT_COUNT_UCHARS = EXT_COUNT_BYTES + 1;
1348     // private static final int EXT_FLAGS = EXT_COUNT_UCHARS + 1;
1349     //
1350     // private static final int EXT_RESERVED_INDEX = EXT_FLAGS + 1; /* 20, moves with additional indexes */
1351     //
1352     // private static final int EXT_SIZE=31;
1353     // private static final int EXT_INDEXES_MIN_LENGTH=32;
1354
1355     static final int EXT_FROM_U_MAX_DIRECT_LENGTH = 3;
1356
1357     /* toUnicode helpers -------------------------------------------------------- */
1358
1359     private static final int TO_U_BYTE_SHIFT = 24;
1360     private static final int TO_U_VALUE_MASK = 0xffffff;
1361     private static final int TO_U_MIN_CODE_POINT = 0x1f0000;
1362     private static final int TO_U_MAX_CODE_POINT = 0x2fffff;
1363     private static final int TO_U_ROUNDTRIP_FLAG = (1 << 23);
1364     private static final int TO_U_INDEX_MASK = 0x3ffff;
1365     private static final int TO_U_LENGTH_SHIFT = 18;
1366     private static final int TO_U_LENGTH_OFFSET = 12;
1367
1368     /* maximum number of indexed UChars */
1369     static final int MAX_UCHARS = 19;
1370
1371     static int TO_U_GET_BYTE(int word) {
1372         return word >>> TO_U_BYTE_SHIFT;
1373     }
1374
1375     static int TO_U_GET_VALUE(int word) {
1376         return word & TO_U_VALUE_MASK;
1377     }
1378
1379     static boolean TO_U_IS_ROUNDTRIP(int value) {
1380         return (value & TO_U_ROUNDTRIP_FLAG) != 0;
1381     }
1382
1383     static boolean TO_U_IS_PARTIAL(int value) {
1384         return (value & UConverterConstants.UNSIGNED_INT_MASK) < TO_U_MIN_CODE_POINT;
1385     }
1386
1387     static int TO_U_GET_PARTIAL_INDEX(int value) {
1388         return value;
1389     }
1390
1391     static int TO_U_MASK_ROUNDTRIP(int value) {
1392         return value & ~TO_U_ROUNDTRIP_FLAG;
1393     }
1394
1395     private static int TO_U_MAKE_WORD(byte b, int value) {
1396         return ((b & UConverterConstants.UNSIGNED_BYTE_MASK) << TO_U_BYTE_SHIFT) | value;
1397     }
1398
1399     /* use after masking off the roundtrip flag */
1400     static boolean TO_U_IS_CODE_POINT(int value) {
1401         return (value & UConverterConstants.UNSIGNED_INT_MASK) <= TO_U_MAX_CODE_POINT;
1402     }
1403
1404     static int TO_U_GET_CODE_POINT(int value) {
1405         return (int) ((value & UConverterConstants.UNSIGNED_INT_MASK) - TO_U_MIN_CODE_POINT);
1406     }
1407
1408     private static int TO_U_GET_INDEX(int value) {
1409         return value & TO_U_INDEX_MASK;
1410     }
1411
1412     private static int TO_U_GET_LENGTH(int value) {
1413         return (value >>> TO_U_LENGTH_SHIFT) - TO_U_LENGTH_OFFSET;
1414     }
1415
1416     /* fromUnicode helpers ------------------------------------------------------ */
1417
1418     /* most trie constants are shared with ucnvmbcs.h */
1419     private static final int STAGE_2_LEFT_SHIFT = 2;
1420
1421     // private static final int STAGE_3_GRANULARITY = 4;
1422
1423     /* trie access, returns the stage 3 value=index to stage 3b; s1Index=c>>10 */
1424     static int FROM_U(CharBuffer stage12, CharBuffer stage3, int s1Index, int c) {
1425         return stage3.get(((int) stage12.get((stage12.get(s1Index) + ((c >>> 4) & 0x3f))) << STAGE_2_LEFT_SHIFT)
1426                 + (c & 0xf));
1427     }
1428
1429     private static final int FROM_U_LENGTH_SHIFT = 24;
1430     private static final int FROM_U_ROUNDTRIP_FLAG = 1 << 31;
1431     static final int FROM_U_RESERVED_MASK = 0x60000000;
1432     private static final int FROM_U_DATA_MASK = 0xffffff;
1433
1434     /* special value for "no mapping" to <subchar1> (impossible roundtrip to 0 bytes, value 01) */
1435     static final int FROM_U_SUBCHAR1 = 0x80000001;
1436
1437     /* at most 3 bytes in the lower part of the value */
1438     private static final int FROM_U_MAX_DIRECT_LENGTH = 3;
1439
1440     /* maximum number of indexed bytes */
1441     static final int MAX_BYTES = 0x1f;
1442
1443     static boolean FROM_U_IS_PARTIAL(int value) {
1444         return (value >>> FROM_U_LENGTH_SHIFT) == 0;
1445     }
1446
1447     static int FROM_U_GET_PARTIAL_INDEX(int value) {
1448         return value;
1449     }
1450
1451     static boolean FROM_U_IS_ROUNDTRIP(int value) {
1452         return (value & FROM_U_ROUNDTRIP_FLAG) != 0;
1453     }
1454
1455     private static int FROM_U_MASK_ROUNDTRIP(int value) {
1456         return value & ~FROM_U_ROUNDTRIP_FLAG;
1457     }
1458
1459     /* use after masking off the roundtrip flag */
1460     static int FROM_U_GET_LENGTH(int value) {
1461         return (value >>> FROM_U_LENGTH_SHIFT) & MAX_BYTES;
1462     }
1463
1464     /* get bytes or bytes index */
1465     static int FROM_U_GET_DATA(int value) {
1466         return value & FROM_U_DATA_MASK;
1467     }
1468
1469     /* get the pointer to an extension array from indexes[index] */
1470     static Buffer ARRAY(ByteBuffer indexes, int index, Class<?> itemType) {
1471         int oldpos = indexes.position();
1472         Buffer b;
1473
1474         indexes.position(indexes.getInt(index << 2));
1475         if (itemType == int.class)
1476             b = indexes.asIntBuffer();
1477         else if (itemType == char.class)
1478             b = indexes.asCharBuffer();
1479         else if (itemType == short.class)
1480             b = indexes.asShortBuffer();
1481         else
1482             // default or (itemType == byte.class)
1483             b = indexes.slice();
1484         indexes.position(oldpos);
1485         return b;
1486     }
1487
1488     private static int GET_MAX_BYTES_PER_UCHAR(ByteBuffer indexes) {
1489         indexes.position(0);
1490         return indexes.getInt(EXT_COUNT_BYTES) & 0xff;
1491     }
1492
1493     /*
1494      * @return index of the UChar, if found; else <0
1495      */
1496     static int findFromU(CharBuffer fromUSection, int length, char u) {
1497         int i, start, limit;
1498
1499         /* binary search */
1500         start = 0;
1501         limit = length;
1502         for (;;) {
1503             i = limit - start;
1504             if (i <= 1) {
1505                 break; /* done */
1506             }
1507             /* start<limit-1 */
1508
1509             if (i <= 4) {
1510                 /* linear search for the last part */
1511                 if (u <= fromUSection.get(fromUSection.position() + start)) {
1512                     break;
1513                 }
1514                 if (++start < limit && u <= fromUSection.get(fromUSection.position() + start)) {
1515                     break;
1516                 }
1517                 if (++start < limit && u <= fromUSection.get(fromUSection.position() + start)) {
1518                     break;
1519                 }
1520                 /* always break at start==limit-1 */
1521                 ++start;
1522                 break;
1523             }
1524
1525             i = (start + limit) / 2;
1526             if (u < fromUSection.get(fromUSection.position() + i)) {
1527                 limit = i;
1528             } else {
1529                 start = i;
1530             }
1531         }
1532
1533         /* did we really find it? */
1534         if (start < limit && u == fromUSection.get(fromUSection.position() + start)) {
1535             return start;
1536         } else {
1537             return -1; /* not found */
1538         }
1539     }
1540
1541     /*
1542      * @return lookup value for the byte, if found; else 0
1543      */
1544     static int findToU(IntBuffer toUSection, int length, short byt) {
1545         long word0, word;
1546         int i, start, limit;
1547
1548         /* check the input byte against the lowest and highest section bytes */
1549         // agljport:comment instead of receiving a start position parameter for toUSection we'll rely on its position
1550         // property
1551         start = TO_U_GET_BYTE(toUSection.get(toUSection.position()));
1552         limit = TO_U_GET_BYTE(toUSection.get(toUSection.position() + length - 1));
1553         if (byt < start || limit < byt) {
1554             return 0; /* the byte is out of range */
1555         }
1556
1557         if (length == ((limit - start) + 1)) {
1558             /* direct access on a linear array */
1559             return TO_U_GET_VALUE(toUSection.get(toUSection.position() + byt - start)); /* could be 0 */
1560         }
1561
1562         /* word0 is suitable for <=toUSection[] comparison, word for <toUSection[] */
1563         word0 = TO_U_MAKE_WORD((byte) byt, 0) & UConverterConstants.UNSIGNED_INT_MASK;
1564
1565         /*
1566          * Shift byte once instead of each section word and add 0xffffff. We will compare the shifted/added byte
1567          * (bbffffff) against section words which have byte values in the same bit position. If and only if byte bb <
1568          * section byte ss then bbffffff<ssvvvvvv for all v=0..f so we need not mask off the lower 24 bits of each
1569          * section word.
1570          */
1571         word = word0 | TO_U_VALUE_MASK;
1572
1573         /* binary search */
1574         start = 0;
1575         limit = length;
1576         for (;;) {
1577             i = limit - start;
1578             if (i <= 1) {
1579                 break; /* done */
1580             }
1581             /* start<limit-1 */
1582
1583             if (i <= 4) {
1584                 /* linear search for the last part */
1585                 if (word0 <= (toUSection.get(toUSection.position() + start) & UConverterConstants.UNSIGNED_INT_MASK)) {
1586                     break;
1587                 }
1588                 if (++start < limit
1589                         && word0 <= (toUSection.get(toUSection.position() + start) & UConverterConstants.UNSIGNED_INT_MASK)) {
1590                     break;
1591                 }
1592                 if (++start < limit
1593                         && word0 <= (toUSection.get(toUSection.position() + start) & UConverterConstants.UNSIGNED_INT_MASK)) {
1594                     break;
1595                 }
1596                 /* always break at start==limit-1 */
1597                 ++start;
1598                 break;
1599             }
1600
1601             i = (start + limit) / 2;
1602             if (word < (toUSection.get(toUSection.position() + i) & UConverterConstants.UNSIGNED_INT_MASK)) {
1603                 limit = i;
1604             } else {
1605                 start = i;
1606             }
1607         }
1608
1609         /* did we really find it? */
1610         if (start < limit) {
1611             word = (toUSection.get(toUSection.position() + start) & UConverterConstants.UNSIGNED_INT_MASK);
1612             if (byt == TO_U_GET_BYTE((int)word)) {
1613                 return TO_U_GET_VALUE((int) word); /* never 0 */
1614             }
1615         } 
1616         return 0; /* not found */
1617     }
1618
1619     /*
1620      * TRUE if not an SI/SO stateful converter, or if the match length fits with the current converter state
1621      */
1622     static boolean TO_U_VERIFY_SISO_MATCH(byte sisoState, int match) {
1623         return sisoState < 0 || (sisoState == 0) == (match == 1);
1624     }
1625
1626     /*
1627      * get the SI/SO toU state (state 0 is for SBCS, 1 for DBCS), or 1 for DBCS-only, or -1 if the converter is not
1628      * SI/SO stateful
1629      * 
1630      * Note: For SI/SO stateful converters getting here, cnv->mode==0 is equivalent to firstLength==1.
1631      */
1632     private static int SISO_STATE(UConverterSharedData sharedData, int mode) {
1633         return sharedData.mbcs.outputType == MBCS_OUTPUT_2_SISO ? (byte) mode
1634                 : sharedData.mbcs.outputType == MBCS_OUTPUT_DBCS_ONLY ? 1 : -1;
1635     }
1636
1637     class CharsetDecoderMBCS extends CharsetDecoderICU {
1638
1639         CharsetDecoderMBCS(CharsetICU cs) {
1640             super(cs);
1641         }
1642
1643         protected CoderResult decodeLoop(ByteBuffer source, CharBuffer target, IntBuffer offsets, boolean flush) {
1644         /* Just call cnvMBCSToUnicodeWithOffsets() to remove duplicate code. */
1645             return cnvMBCSToUnicodeWithOffsets(source, target, offsets, flush);
1646         }
1647
1648         /*
1649          * continue partial match with new input never called for simple, single-character conversion
1650          */
1651         private CoderResult continueMatchToU(ByteBuffer source, CharBuffer target, IntBuffer offsets, int srcIndex,
1652                 boolean flush) {
1653             CoderResult cr = CoderResult.UNDERFLOW;
1654
1655             int[] value = new int[1];
1656             int match, length;
1657
1658             match = matchToU((byte) SISO_STATE(sharedData, mode), preToUArray, preToUBegin, preToULength, source,
1659                     value, isToUUseFallback(), flush);
1660
1661             if (match > 0) {
1662                 if (match >= preToULength) {
1663                     /* advance src pointer for the consumed input */
1664                     source.position(source.position() + match - preToULength);
1665                     preToULength = 0;
1666                 } else {
1667                     /* the match did not use all of preToU[] - keep the rest for replay */
1668                     length = preToULength - match;
1669                     System.arraycopy(preToUArray, preToUBegin + match, preToUArray, preToUBegin, length);
1670                     preToULength = (byte) -length;
1671                 }
1672
1673                 /* write result */
1674                 cr = writeToU(value[0], target, offsets, srcIndex);
1675             } else if (match < 0) {
1676                 /* save state for partial match */
1677                 int j, sArrayIndex;
1678
1679                 /* just _append_ the newly consumed input to preToU[] */
1680                 sArrayIndex = source.position();
1681                 match = -match;
1682                 for (j = preToULength; j < match; ++j) {
1683                     preToUArray[j] = source.get(sArrayIndex++);
1684                 }
1685                 source.position(sArrayIndex); /* same as *src=srcLimit; because we reached the end of input */
1686                 preToULength = (byte) match;
1687             } else /* match==0 */{
1688                 /*
1689                  * no match
1690                  * 
1691                  * We need to split the previous input into two parts:
1692                  * 
1693                  * 1. The first codepage character is unmappable - that's how we got into trying the extension data in
1694                  * the first place. We need to move it from the preToU buffer to the error buffer, set an error code,
1695                  * and prepare the rest of the previous input for 2.
1696                  * 
1697                  * 2. The rest of the previous input must be converted once we come back from the callback for the first
1698                  * character. At that time, we have to try again from scratch to convert these input characters. The
1699                  * replay will be handled by the ucnv.c conversion code.
1700                  */
1701
1702                 /* move the first codepage character to the error field */
1703                 System.arraycopy(preToUArray, preToUBegin, toUBytesArray, toUBytesBegin, preToUFirstLength);
1704                 toULength = preToUFirstLength;
1705
1706                 /* move the rest up inside the buffer */
1707                 length = preToULength - preToUFirstLength;
1708                 if (length > 0) {
1709                     System.arraycopy(preToUArray, preToUBegin + preToUFirstLength, preToUArray, preToUBegin, length);
1710                 }
1711
1712                 /* mark preToU for replay */
1713                 preToULength = (byte) -length;
1714
1715                 /* set the error code for unassigned */
1716                 cr = CoderResult.unmappableForLength(preToUFirstLength);
1717             }
1718             return cr;
1719         }
1720
1721         /*
1722          * this works like matchFromU() except - the first character is in pre - no trie is used - the returned
1723          * matchLength is not offset by 2
1724          */
1725         private int matchToU(byte sisoState, byte[] preArray, int preArrayBegin, int preLength, ByteBuffer source,
1726                 int[] pMatchValue, boolean isUseFallback, boolean flush) {
1727             ByteBuffer cx = sharedData.mbcs.extIndexes;
1728             IntBuffer toUTable, toUSection;
1729
1730             int value, matchValue, srcLength = 0;
1731             int i, j, index, length, matchLength;
1732             short b;
1733
1734             if (cx == null || cx.asIntBuffer().get(EXT_TO_U_LENGTH) <= 0) {
1735                 return 0; /* no extension data, no match */
1736             }
1737
1738             /* initialize */
1739             toUTable = (IntBuffer) ARRAY(cx, EXT_TO_U_INDEX, int.class);
1740             index = 0;
1741
1742             matchValue = 0;
1743             i = j = matchLength = 0;
1744             if (source != null) { 
1745                 srcLength = source.remaining();
1746             }
1747
1748             if (sisoState == 0) {
1749                 /* SBCS state of an SI/SO stateful converter, look at only exactly 1 byte */
1750                 if (preLength > 1) {
1751                     return 0; /* no match of a DBCS sequence in SBCS mode */
1752                 } else if (preLength == 1) {
1753                     srcLength = 0;
1754                 } else /* preLength==0 */{
1755                     if (srcLength > 1) {
1756                         srcLength = 1;
1757                     }
1758                 }
1759                 flush = true;
1760             }
1761
1762             /* we must not remember fallback matches when not using fallbacks */
1763
1764             /* match input units until there is a full match or the input is consumed */
1765             for (;;) {
1766                 /* go to the next section */
1767                 int oldpos = toUTable.position();
1768                 toUSection = ((IntBuffer) toUTable.position(index)).slice();
1769                 toUTable.position(oldpos);
1770
1771                 /* read first pair of the section */
1772                 value = toUSection.get();
1773                 length = TO_U_GET_BYTE(value);
1774                 value = TO_U_GET_VALUE(value);
1775                 if (value != 0 && (TO_U_IS_ROUNDTRIP(value) || isToUUseFallback(isUseFallback))
1776                         && TO_U_VERIFY_SISO_MATCH(sisoState, i + j)) {
1777                     /* remember longest match so far */
1778                     matchValue = value;
1779                     matchLength = i + j;
1780                 }
1781
1782                 /* match pre[] then src[] */
1783                 if (i < preLength) {
1784                     b = (short) (preArray[preArrayBegin + i++] & UConverterConstants.UNSIGNED_BYTE_MASK);
1785                 } else if (j < srcLength) {
1786                     b = (short) (source.get(source.position() + j++) & UConverterConstants.UNSIGNED_BYTE_MASK);
1787                 } else {
1788                     /* all input consumed, partial match */
1789                     if (flush || (length = (i + j)) > MAX_BYTES) {
1790                         /*
1791                          * end of the entire input stream, stop with the longest match so far or: partial match must not
1792                          * be longer than UCNV_EXT_MAX_BYTES because it must fit into state buffers
1793                          */
1794                         break;
1795                     } else {
1796                         /* continue with more input next time */
1797                         return -length;
1798                     }
1799                 }
1800
1801                 /* search for the current UChar */
1802                 value = findToU(toUSection, length, b);
1803                 if (value == 0) {
1804                     /* no match here, stop with the longest match so far */
1805                     break;
1806                 } else {
1807                     if (TO_U_IS_PARTIAL(value)) {
1808                         /* partial match, continue */
1809                         index = TO_U_GET_PARTIAL_INDEX(value);
1810                     } else {
1811                         if ((TO_U_IS_ROUNDTRIP(value) || isToUUseFallback(isUseFallback)) && TO_U_VERIFY_SISO_MATCH(sisoState, i + j)) {
1812                             /* full match, stop with result */
1813                             matchValue = value;
1814                             matchLength = i + j;
1815                         } else {
1816                             /* full match on fallback not taken, stop with the longest match so far */
1817                         }
1818                         break;
1819                     }
1820                 }
1821             }
1822
1823             if (matchLength == 0) {
1824                 /* no match at all */
1825                 return 0;
1826             }
1827
1828             /* return result */
1829             pMatchValue[0] = TO_U_MASK_ROUNDTRIP(matchValue);
1830             return matchLength;
1831         }
1832
1833         private CoderResult writeToU(int value, CharBuffer target, IntBuffer offsets, int srcIndex) {
1834             ByteBuffer cx = sharedData.mbcs.extIndexes;
1835             /* output the result */
1836             if (TO_U_IS_CODE_POINT(value)) {
1837                 /* output a single code point */
1838                 return toUWriteCodePoint(TO_U_GET_CODE_POINT(value), target, offsets, srcIndex);
1839             } else {
1840                 /* output a string - with correct data we have resultLength>0 */
1841
1842                 char[] a = new char[TO_U_GET_LENGTH(value)];
1843                 CharBuffer cb = ((CharBuffer) ARRAY(cx, EXT_TO_U_UCHARS_INDEX, char.class));
1844                 cb.position(TO_U_GET_INDEX(value));
1845                 cb.get(a, 0, a.length);
1846                 return toUWriteUChars(this, a, 0, a.length, target, offsets, srcIndex);
1847             }
1848         }
1849
1850         private CoderResult toUWriteCodePoint(int c, CharBuffer target, IntBuffer offsets, int sourceIndex) {
1851             CoderResult cr = CoderResult.UNDERFLOW;
1852             int tBeginIndex = target.position();
1853
1854             if (target.hasRemaining()) {
1855                 if (c <= 0xffff) {
1856                     target.put((char) c);
1857                     c = UConverterConstants.U_SENTINEL;
1858                 } else /* c is a supplementary code point */{
1859                     target.put(UTF16.getLeadSurrogate(c));
1860                     c = UTF16.getTrailSurrogate(c);
1861                     if (target.hasRemaining()) {
1862                         target.put((char) c);
1863                         c = UConverterConstants.U_SENTINEL;
1864                     }
1865                 }
1866
1867                 /* write offsets */
1868                 if (offsets != null) {
1869                     offsets.put(sourceIndex);
1870                     if ((tBeginIndex + 1) < target.position()) {
1871                         offsets.put(sourceIndex);
1872                     }
1873                 }
1874             }
1875
1876             /* write overflow from c */
1877             if (c >= 0) {
1878                 charErrorBufferLength = UTF16.append(charErrorBufferArray, 0, c);
1879                 cr = CoderResult.OVERFLOW;
1880             }
1881
1882             return cr;
1883         }
1884
1885         /*
1886          * Input sequence: cnv->toUBytes[0..length[ @return if(U_FAILURE) return the length (toULength, byteIndex) for
1887          * the input else return 0 after output has been written to the target
1888          */
1889         private int toU(int length, ByteBuffer source, CharBuffer target, IntBuffer offsets, int sourceIndex,
1890                 boolean flush, CoderResult[] cr) {
1891             // ByteBuffer cx;
1892
1893             if (sharedData.mbcs.extIndexes != null
1894                     && initialMatchToU(length, source, target, offsets, sourceIndex, flush, cr)) {
1895                 return 0; /* an extension mapping handled the input */
1896             }
1897
1898             /* GB 18030 */
1899             if (length == 4 && (options & MBCS_OPTION_GB18030) != 0) {
1900                 long[] range;
1901                 long linear;
1902                 int i;
1903
1904                 linear = LINEAR_18030(toUBytesArray[0], toUBytesArray[1], toUBytesArray[2], toUBytesArray[3]);
1905                 for (i = 0; i < gb18030Ranges.length; ++i) {
1906                     range = gb18030Ranges[i];
1907                     if (range[2] <= linear && linear <= range[3]) {
1908                         /* found the sequence, output the Unicode code point for it */
1909                         cr[0] = CoderResult.UNDERFLOW;
1910
1911                         /* add the linear difference between the input and start sequences to the start code point */
1912                         linear = range[0] + (linear - range[2]);
1913
1914                         /* output this code point */
1915                         cr[0] = toUWriteCodePoint((int) linear, target, offsets, sourceIndex);
1916
1917                         return 0;
1918                     }
1919                 }
1920             }
1921
1922             /* no mapping */
1923             cr[0] = CoderResult.unmappableForLength(length);
1924             return length;
1925         }
1926
1927         /*
1928          * target<targetLimit; set error code for overflow
1929          */
1930         private boolean initialMatchToU(int firstLength, ByteBuffer source, CharBuffer target, IntBuffer offsets,
1931                 int srcIndex, boolean flush, CoderResult[] cr) {
1932             int[] value = new int[1];
1933             int match = 0;
1934
1935             /* try to match */
1936             match = matchToU((byte) SISO_STATE(sharedData, mode), toUBytesArray, toUBytesBegin, firstLength, source,
1937                     value, isToUUseFallback(), flush);
1938             if (match > 0) {
1939                 /* advance src pointer for the consumed input */
1940                 source.position(source.position() + match - firstLength);
1941
1942                 /* write result to target */
1943                 cr[0] = writeToU(value[0], target, offsets, srcIndex);
1944                 return true;
1945             } else if (match < 0) {
1946                 /* save state for partial match */
1947                 byte[] sArray;
1948                 int sArrayIndex;
1949                 int j;
1950
1951                 /* copy the first code point */
1952                 sArray = toUBytesArray;
1953                 sArrayIndex = toUBytesBegin;
1954                 preToUFirstLength = (byte) firstLength;
1955                 for (j = 0; j < firstLength; ++j) {
1956                     preToUArray[j] = sArray[sArrayIndex++];
1957                 }
1958
1959                 /* now copy the newly consumed input */
1960                 sArrayIndex = source.position();
1961                 match = -match;
1962                 for (; j < match; ++j) {
1963                     preToUArray[j] = source.get(sArrayIndex++);
1964                 }
1965                 source.position(sArrayIndex);
1966                 preToULength = (byte) match;
1967                 return true;
1968             } else /* match==0 no match */{
1969                 return false;
1970             }
1971         }
1972
1973         private int simpleMatchToU(ByteBuffer source, boolean useFallback) {
1974             int[] value = new int[1];
1975             int match;
1976
1977             if (source.remaining() <= 0) {
1978                 return 0xffff;
1979             }
1980
1981             /* try to match */
1982             byte[] sourceArray;
1983             int sourcePosition, sourceLimit;
1984             if (source.isReadOnly()) {
1985                 // source.array() would throw an exception
1986                 sourcePosition = source.position();  // relative to source.array()
1987                 sourceArray = new byte[Math.min(source.remaining(), EXT_MAX_BYTES)];
1988                 source.get(sourceArray).position(sourcePosition);
1989                 sourcePosition = 0;  // relative to sourceArray
1990                 sourceLimit = sourceArray.length;
1991             } else {
1992                 sourceArray = source.array();
1993                 sourcePosition = source.position();
1994                 sourceLimit = source.limit();
1995             }
1996             match = matchToU((byte) -1, sourceArray, sourcePosition, sourceLimit, null, value, useFallback, true);
1997
1998             if (match == source.remaining()) {
1999                 /* write result for simple, single-character conversion */
2000                 if (TO_U_IS_CODE_POINT(value[0])) {
2001                     return TO_U_GET_CODE_POINT(value[0]);
2002                 }
2003             }
2004
2005             /*
2006              * return no match because - match>0 && value points to string: simple conversion cannot handle multiple
2007              * code points - match>0 && match!=length: not all input consumed, forbidden for this function - match==0:
2008              * no match found in the first place - match<0: partial match, not supported for simple conversion (and
2009              * flush==TRUE)
2010              */
2011             return 0xfffe;
2012         }
2013
2014         CoderResult cnvMBCSToUnicodeWithOffsets(ByteBuffer source, CharBuffer target, IntBuffer offsets, boolean flush) {
2015             CoderResult[] cr = { CoderResult.UNDERFLOW };
2016
2017             int sourceArrayIndex, sourceArrayIndexStart;
2018             int stateTable[][/* 256 */];
2019             char[] unicodeCodeUnits;
2020
2021             int offset;
2022             byte state;
2023             int byteIndex;
2024             byte[] bytes;
2025
2026             int sourceIndex, nextSourceIndex;
2027
2028             int entry = 0;
2029             char c;
2030             byte action;
2031
2032             if (preToULength > 0) {
2033                 /*
2034                  * pass sourceIndex=-1 because we continue from an earlier buffer in the future, this may change with
2035                  * continuous offsets
2036                  */
2037                 cr[0] = continueMatchToU(source, target, offsets, -1, flush);
2038
2039                 if (cr[0].isError() || preToULength < 0) {
2040                     return cr[0];
2041                 }
2042             }
2043
2044             if (sharedData.mbcs.countStates == 1) {
2045                 if ((sharedData.mbcs.unicodeMask & UConverterConstants.HAS_SUPPLEMENTARY) == 0) {
2046                     cr[0] = cnvMBCSSingleToBMPWithOffsets(source, target, offsets, flush);
2047                 } else {
2048                     cr[0] = cnvMBCSSingleToUnicodeWithOffsets(source, target, offsets, flush);
2049                 }
2050                 return cr[0];
2051             }
2052
2053             /* set up the local pointers */
2054             sourceArrayIndex = sourceArrayIndexStart = source.position();
2055
2056             if ((options & UConverterConstants.OPTION_SWAP_LFNL) != 0) {
2057                 stateTable = sharedData.mbcs.swapLFNLStateTable;
2058             } else {
2059                 stateTable = sharedData.mbcs.stateTable;
2060             }
2061             unicodeCodeUnits = sharedData.mbcs.unicodeCodeUnits;
2062
2063             /* get the converter state from UConverter */
2064             offset = toUnicodeStatus;
2065             byteIndex = toULength;
2066             bytes = toUBytesArray;
2067
2068             /*
2069              * if we are in the SBCS state for a DBCS-only converter, then load the DBCS state from the MBCS data
2070              * (dbcsOnlyState==0 if it is not a DBCS-only converter)
2071              */
2072             state = (byte)mode;
2073             if (state == 0) {
2074                 state = sharedData.mbcs.dbcsOnlyState;
2075             }
2076
2077             /* sourceIndex=-1 if the current character began in the previous buffer */
2078             sourceIndex = byteIndex == 0 ? 0 : -1;
2079             nextSourceIndex = 0;
2080
2081             /* conversion loop */
2082             while (sourceArrayIndex < source.limit()) {
2083                 /*
2084                  * This following test is to see if available input would overflow the output. It does not catch output
2085                  * of more than one code unit that overflows as a result of a surrogate pair or callback output from the
2086                  * last source byte. Therefore, those situations also test for overflows and will then break the loop,
2087                  * too.
2088                  */
2089                 if (!target.hasRemaining()) {
2090                     /* target is full */
2091                     cr[0] = CoderResult.OVERFLOW;
2092                     break;
2093                 }
2094
2095                 if (byteIndex == 0) {
2096                     /* optimized loop for 1/2-byte input and BMP output */
2097                     // agljport:todo see ucnvmbcs.c for deleted block
2098                     do {
2099                         entry = stateTable[state][source.get(sourceArrayIndex)&UConverterConstants.UNSIGNED_BYTE_MASK];
2100                         if (MBCS_ENTRY_IS_TRANSITION(entry)) {
2101                             state = (byte)MBCS_ENTRY_TRANSITION_STATE(entry);
2102                             offset = MBCS_ENTRY_TRANSITION_OFFSET(entry);
2103                             ++sourceArrayIndex;
2104                             if (sourceArrayIndex < source.limit()
2105                                     && MBCS_ENTRY_IS_FINAL(entry = stateTable[state][source.get(sourceArrayIndex)&UConverterConstants.UNSIGNED_BYTE_MASK])
2106                                     && MBCS_ENTRY_FINAL_ACTION(entry) == MBCS_STATE_VALID_16
2107                                     && (c = unicodeCodeUnits[offset + MBCS_ENTRY_FINAL_VALUE_16(entry)]) < 0xfffe) {
2108                                 ++sourceArrayIndex;
2109                                 target.put(c);
2110                                 if (offsets != null) {
2111                                     offsets.put(sourceIndex);
2112                                     sourceIndex = (nextSourceIndex += 2);
2113                                 }
2114                                 state = (byte)MBCS_ENTRY_FINAL_STATE(entry); /* typically 0 */
2115                                 offset = 0;
2116                             } else {
2117                                 /* set the state and leave the optimized loop */
2118                                 ++nextSourceIndex;
2119                                 bytes[0] = source.get(sourceArrayIndex - 1);
2120                                 byteIndex = 1;
2121                                 break;
2122                             }
2123                         } else {
2124                             if (MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(entry)) {
2125                                 /* output BMP code point */
2126                                 ++sourceArrayIndex;
2127                                 target.put(MBCS_ENTRY_FINAL_VALUE_16(entry));
2128                                 if (offsets != null) {
2129                                     offsets.put(sourceIndex);
2130                                     sourceIndex = ++nextSourceIndex;
2131                                 }
2132                                 state = (byte)MBCS_ENTRY_FINAL_STATE(entry); /* typically 0 */
2133                             } else {
2134                                 /* leave the optimized loop */
2135                                 break;
2136                             }
2137                         }
2138                     } while (sourceArrayIndex < source.limit() && target.hasRemaining());
2139                     /*
2140                      * these tests and break statements could be put inside the loop if C had "break outerLoop" like
2141                      * Java
2142                      */
2143                     if (sourceArrayIndex >= source.limit()) {
2144                         break;
2145                     }
2146                     if (!target.hasRemaining()) {
2147                         /* target is full */
2148                         cr[0] = CoderResult.OVERFLOW;
2149                         break;
2150                     }
2151
2152                     ++nextSourceIndex;
2153                     bytes[byteIndex++] = source.get(sourceArrayIndex++);
2154                 } else /* byteIndex>0 */{
2155                     ++nextSourceIndex;
2156                     entry = stateTable[state][(bytes[byteIndex++] = source.get(sourceArrayIndex++))
2157                             & UConverterConstants.UNSIGNED_BYTE_MASK];
2158                 }
2159
2160                 if (MBCS_ENTRY_IS_TRANSITION(entry)) {
2161                     state = (byte)MBCS_ENTRY_TRANSITION_STATE(entry);
2162                     offset += MBCS_ENTRY_TRANSITION_OFFSET(entry);
2163                     continue;
2164                 }
2165
2166                 /* save the previous state for proper extension mapping with SI/SO-stateful converters */
2167                 mode = state;
2168
2169                 /* set the next state early so that we can reuse the entry variable */
2170                 state = (byte)MBCS_ENTRY_FINAL_STATE(entry); /* typically 0 */
2171
2172                 /*
2173                  * An if-else-if chain provides more reliable performance for the most common cases compared to a
2174                  * switch.
2175                  */
2176                 action = (byte)MBCS_ENTRY_FINAL_ACTION(entry);
2177                 if (action == MBCS_STATE_VALID_16) {
2178                     offset += MBCS_ENTRY_FINAL_VALUE_16(entry);
2179                     c = unicodeCodeUnits[offset];
2180                     if (c < 0xfffe) {
2181                         /* output BMP code point */
2182                         target.put(c);
2183                         if (offsets != null) {
2184                             offsets.put(sourceIndex);
2185                         }
2186                         byteIndex = 0;
2187                     } else if (c == 0xfffe) {
2188                         if (isFallbackUsed() && (entry = getFallback(sharedData.mbcs, offset)) != 0xfffe) {
2189                             /* output fallback BMP code point */
2190                             target.put((char)entry);
2191                             if (offsets != null) {
2192                                 offsets.put(sourceIndex);
2193                             }
2194                             byteIndex = 0;
2195                         }
2196                     } else {
2197                         /* callback(illegal) */
2198                         cr[0] = CoderResult.malformedForLength(byteIndex);
2199                     }
2200                 } else if (action == MBCS_STATE_VALID_DIRECT_16) {
2201                     /* output BMP code point */
2202                     target.put(MBCS_ENTRY_FINAL_VALUE_16(entry));
2203                     if (offsets != null) {
2204                         offsets.put(sourceIndex);
2205                     }
2206                     byteIndex = 0;
2207                 } else if (action == MBCS_STATE_VALID_16_PAIR) {
2208                     offset += MBCS_ENTRY_FINAL_VALUE_16(entry);
2209                     c = unicodeCodeUnits[offset++];
2210                     if (c < 0xd800) {
2211                         /* output BMP code point below 0xd800 */
2212                         target.put(c);
2213                         if (offsets != null) {
2214                             offsets.put(sourceIndex);
2215                         }
2216                         byteIndex = 0;
2217                     } else if (isFallbackUsed() ? c <= 0xdfff : c <= 0xdbff) {
2218                         /* output roundtrip or fallback surrogate pair */
2219                         target.put((char)(c & 0xdbff));
2220                         if (offsets != null) {
2221                             offsets.put(sourceIndex);
2222                         }
2223                         byteIndex = 0;
2224                         if (target.hasRemaining()) {
2225                             target.put(unicodeCodeUnits[offset]);
2226                             if (offsets != null) {
2227                                 offsets.put(sourceIndex);
2228                             }
2229                         } else {
2230                             /* target overflow */
2231                             charErrorBufferArray[0] = unicodeCodeUnits[offset];
2232                             charErrorBufferLength = 1;
2233                             cr[0] = CoderResult.OVERFLOW;
2234
2235                             offset = 0;
2236                             break;
2237                         }
2238                     } else if (isFallbackUsed() ? (c & 0xfffe) == 0xe000 : c == 0xe000) {
2239                         /* output roundtrip BMP code point above 0xd800 or fallback BMP code point */
2240                         target.put(unicodeCodeUnits[offset]);
2241                         if (offsets != null) {
2242                             offsets.put(sourceIndex);
2243                         }
2244                         byteIndex = 0;
2245                     } else if (c == 0xffff) {
2246                         /* callback(illegal) */
2247                         cr[0] = CoderResult.malformedForLength(byteIndex);
2248                     }
2249                 } else if (action == MBCS_STATE_VALID_DIRECT_20
2250                         || (action == MBCS_STATE_FALLBACK_DIRECT_20 && isFallbackUsed())) {
2251                     entry = MBCS_ENTRY_FINAL_VALUE(entry);
2252                     /* output surrogate pair */
2253                     target.put((char)(0xd800 | (char)(entry >> 10)));
2254                     if (offsets != null) {
2255                         offsets.put(sourceIndex);
2256                     }
2257                     byteIndex = 0;
2258                     c = (char)(0xdc00 | (char)(entry & 0x3ff));
2259                     if (target.hasRemaining()) {
2260                         target.put(c);
2261                         if (offsets != null) {
2262                             offsets.put(sourceIndex);
2263                         }
2264                     } else {
2265                         /* target overflow */
2266                         charErrorBufferArray[0] = c;
2267                         charErrorBufferLength = 1;
2268                         cr[0] = CoderResult.OVERFLOW;
2269
2270                         offset = 0;
2271                         break;
2272                     }
2273                 } else if (action == MBCS_STATE_CHANGE_ONLY) {
2274                     /*
2275                      * This serves as a state change without any output. It is useful for reading simple stateful
2276                      * encodings, for example using just Shift-In/Shift-Out codes. The 21 unused bits may later be used
2277                      * for more sophisticated state transitions.
2278                      */
2279                     if (sharedData.mbcs.dbcsOnlyState == 0) {
2280                         byteIndex = 0;
2281                     } else {
2282                         /* SI/SO are illegal for DBCS-only conversion */
2283                         state = (byte)(mode); /* restore the previous state */
2284
2285                         /* callback(illegal) */
2286                         cr[0] = CoderResult.malformedForLength(byteIndex);
2287                     }
2288                 } else if (action == MBCS_STATE_FALLBACK_DIRECT_16) {
2289                     if (isFallbackUsed()) {
2290                         /* output BMP code point */
2291                         target.put(MBCS_ENTRY_FINAL_VALUE_16(entry));
2292                         if (offsets != null) {
2293                             offsets.put(sourceIndex);
2294                         }
2295                         byteIndex = 0;
2296                     }
2297                 } else if (action == MBCS_STATE_UNASSIGNED) {
2298                     /* just fall through */
2299                 } else if (action == MBCS_STATE_ILLEGAL) {
2300                     /* callback(illegal) */
2301                     cr[0] = CoderResult.malformedForLength(byteIndex);
2302                 } else {
2303                     /* reserved, must never occur */
2304                     byteIndex = 0;
2305                 }
2306
2307                 /* end of action codes: prepare for a new character */
2308                 offset = 0;
2309
2310                 if (byteIndex == 0) {
2311                     sourceIndex = nextSourceIndex;
2312                 } else if (cr[0].isError()) {
2313                     /* callback(illegal) */
2314                     if (byteIndex > 1) {
2315                         /*
2316                          * Ticket 5691: consistent illegal sequences:
2317                          * - We include at least the first byte in the illegal sequence.
2318                          * - If any of the non-initial bytes could be the start of a character,
2319                          *   we stop the illegal sequence before the first one of those.
2320                          */
2321                         boolean isDBCSOnly = (sharedData.mbcs.dbcsOnlyState != 0);
2322                         byte i;
2323                         for (i = 1; i < byteIndex && !isSingleOrLead(stateTable, state, isDBCSOnly, (short)(bytes[i] & UConverterConstants.UNSIGNED_BYTE_MASK)); i++) {}
2324                         if (i < byteIndex) {
2325                             byte backOutDistance = (byte)(byteIndex - i);
2326                             int bytesFromThisBuffer = sourceArrayIndex - sourceArrayIndexStart;
2327                             byteIndex = i; /* length of reported illegal byte sequence */
2328                             if (backOutDistance <= bytesFromThisBuffer) {
2329                                 sourceArrayIndex -= backOutDistance;
2330                             } else {
2331                                 /* Back out bytes from the previous buffer: Need to replay them. */
2332                                 this.preToULength = (byte)(bytesFromThisBuffer - backOutDistance);
2333                                 /* preToULength is negative! */
2334                                 for (int n = 0; n < -this.preToULength; n++) {
2335                                     this.preToUArray[n] = bytes[i+n];
2336                                 }
2337                                 sourceArrayIndex = sourceArrayIndexStart;
2338                             }
2339                         }
2340                     }
2341                     break;
2342                 } else /* unassigned sequences indicated with byteIndex>0 */{
2343                     /* try an extension mapping */
2344                     int sourceBeginIndex = sourceArrayIndex;
2345                     source.position(sourceArrayIndex);
2346                     byteIndex = toU(byteIndex, source, target, offsets, sourceIndex, flush, cr);
2347                     sourceArrayIndex = source.position();
2348                     sourceIndex = nextSourceIndex += (sourceArrayIndex - sourceBeginIndex);
2349
2350                     if (cr[0].isError() || cr[0].isOverflow()) {
2351                         /* not mappable or buffer overflow */
2352                         break;
2353                     }
2354                 }
2355             }
2356
2357             /* set the converter state back into UConverter */
2358             toUnicodeStatus = offset;
2359             mode = state;
2360             toULength = byteIndex;
2361
2362             /* write back the updated pointers */
2363             source.position(sourceArrayIndex);
2364
2365             return cr[0];
2366         }
2367         /*
2368          * This version of cnvMBCSSingleToUnicodeWithOffsets() is optimized for single-byte, single-state codepages that
2369          * only map to and from the BMP. In addition to single-byte optimizations, the offset calculations become much
2370          * easier.
2371          */
2372         private CoderResult cnvMBCSSingleToBMPWithOffsets(ByteBuffer source, CharBuffer target, IntBuffer offsets,
2373                 boolean flush) {
2374             CoderResult[] cr = { CoderResult.UNDERFLOW };
2375
2376             int sourceArrayIndex, lastSource;
2377             int targetCapacity, length;
2378             int[][] stateTable;
2379
2380             int sourceIndex;
2381
2382             int entry;
2383             byte action;
2384
2385             /* set up the local pointers */
2386             sourceArrayIndex = source.position();
2387             targetCapacity = target.remaining();
2388
2389             if ((options & UConverterConstants.OPTION_SWAP_LFNL) != 0) {
2390                 stateTable = sharedData.mbcs.swapLFNLStateTable;
2391             } else {
2392                 stateTable = sharedData.mbcs.stateTable;
2393             }
2394
2395             /* sourceIndex=-1 if the current character began in the previous buffer */
2396             sourceIndex = 0;
2397             lastSource = sourceArrayIndex;
2398
2399             /*
2400              * since the conversion here is 1:1 UChar:uint8_t, we need only one counter for the minimum of the
2401              * sourceLength and targetCapacity
2402              */
2403             length = source.remaining();
2404             if (length < targetCapacity) {
2405                 targetCapacity = length;
2406             }
2407
2408             /* conversion loop */
2409             while (targetCapacity > 0 && sourceArrayIndex < source.limit()) {
2410                 entry = stateTable[0][source.get(sourceArrayIndex++) & UConverterConstants.UNSIGNED_BYTE_MASK];
2411                 /* MBCS_ENTRY_IS_FINAL(entry) */
2412
2413                 /* test the most common case first */
2414                 if (MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(entry)) {
2415                     /* output BMP code point */
2416                     target.put(MBCS_ENTRY_FINAL_VALUE_16(entry));
2417                     --targetCapacity;
2418                     continue;
2419                 }
2420
2421                 /*
2422                  * An if-else-if chain provides more reliable performance for the most common cases compared to a
2423                  * switch.
2424                  */
2425                 action = (byte) (MBCS_ENTRY_FINAL_ACTION(entry));
2426                 if (action == MBCS_STATE_FALLBACK_DIRECT_16) {
2427                     if (isFallbackUsed()) {
2428                         /* output BMP code point */
2429                         target.put(MBCS_ENTRY_FINAL_VALUE_16(entry));
2430                         --targetCapacity;
2431                         continue;
2432                     }
2433                 } else if (action == MBCS_STATE_UNASSIGNED) {
2434                     /* just fall through */
2435                 } else if (action == MBCS_STATE_ILLEGAL) {
2436                     /* callback(illegal) */
2437                     cr[0] = CoderResult.malformedForLength(sourceArrayIndex - lastSource);
2438                 } else {
2439                     /* reserved, must never occur */
2440                     continue;
2441                 }
2442
2443                 /* set offsets since the start or the last extension */
2444                 if (offsets != null) {
2445                     int count = sourceArrayIndex - lastSource;
2446
2447                     /* predecrement: do not set the offset for the callback-causing character */
2448                     while (--count > 0) {
2449                         offsets.put(sourceIndex++);
2450                     }
2451                     /* offset and sourceIndex are now set for the current character */
2452                 }
2453
2454                 if (cr[0].isError()) {
2455                     /* callback(illegal) */
2456                     break;
2457                 } else /* unassigned sequences indicated with byteIndex>0 */{
2458                     /* try an extension mapping */
2459                     lastSource = sourceArrayIndex;
2460                     toUBytesArray[0] = source.get(sourceArrayIndex - 1);
2461                     source.position(sourceArrayIndex);
2462                     toULength = toU((byte) 1, source, target, offsets, sourceIndex, flush, cr);
2463                     sourceArrayIndex = source.position();
2464                     sourceIndex += 1 + (sourceArrayIndex - lastSource);
2465
2466                     if (cr[0].isError()) {
2467                         /* not mappable or buffer overflow */
2468                         break;
2469                     }
2470
2471                     /* recalculate the targetCapacity after an extension mapping */
2472                     targetCapacity = target.remaining();
2473                     length = source.remaining();
2474                     if (length < targetCapacity) {
2475                         targetCapacity = length;
2476                     }
2477                 }
2478             }
2479
2480             if (!cr[0].isError() && sourceArrayIndex < source.limit() && !target.hasRemaining()) {
2481                 /* target is full */
2482                 cr[0] = CoderResult.OVERFLOW;
2483             }
2484
2485             /* set offsets since the start or the last callback */
2486             if (offsets != null) {
2487                 int count = sourceArrayIndex - lastSource;
2488                 while (count > 0) {
2489                     offsets.put(sourceIndex++);
2490                     --count;
2491                 }
2492             }
2493
2494             /* write back the updated pointers */
2495             source.position(sourceArrayIndex);
2496
2497             return cr[0];
2498         }
2499
2500         /* This version of cnvMBCSToUnicodeWithOffsets() is optimized for single-byte, single-state codepages. */
2501         private CoderResult cnvMBCSSingleToUnicodeWithOffsets(ByteBuffer source, CharBuffer target, IntBuffer offsets,
2502                 boolean flush) {
2503             CoderResult[] cr = { CoderResult.UNDERFLOW };
2504
2505             int sourceArrayIndex;
2506             int[][] stateTable;
2507
2508             int sourceIndex;
2509
2510             int entry;
2511             char c;
2512             byte action;
2513
2514             /* set up the local pointers */
2515             sourceArrayIndex = source.position();
2516
2517             if ((options & UConverterConstants.OPTION_SWAP_LFNL) != 0) {
2518                 stateTable = sharedData.mbcs.swapLFNLStateTable;
2519             } else {
2520                 stateTable = sharedData.mbcs.stateTable;
2521             }
2522
2523             /* sourceIndex=-1 if the current character began in the previous buffer */
2524             sourceIndex = 0;
2525
2526             /* conversion loop */
2527             while (sourceArrayIndex < source.limit()) {
2528                 /*
2529                  * This following test is to see if available input would overflow the output. It does not catch output
2530                  * of more than one code unit that overflows as a result of a surrogate pair or callback output from the
2531                  * last source byte. Therefore, those situations also test for overflows and will then break the loop,
2532                  * too.
2533                  */
2534                 if (!target.hasRemaining()) {
2535                     /* target is full */
2536                     cr[0] = CoderResult.OVERFLOW;
2537                     break;
2538                 }
2539
2540                 entry = stateTable[0][source.get(sourceArrayIndex++) & UConverterConstants.UNSIGNED_BYTE_MASK];
2541                 /* MBCS_ENTRY_IS_FINAL(entry) */
2542
2543                 /* test the most common case first */
2544                 if (MBCS_ENTRY_FINAL_IS_VALID_DIRECT_16(entry)) {
2545                     /* output BMP code point */
2546                     target.put(MBCS_ENTRY_FINAL_VALUE_16(entry));
2547                     if (offsets != null) {
2548                         offsets.put(sourceIndex);
2549                     }
2550
2551                     /* normal end of action codes: prepare for a new character */
2552                     ++sourceIndex;
2553                     continue;
2554                 }
2555
2556                 /*
2557                  * An if-else-if chain provides more reliable performance for the most common cases compared to a
2558                  * switch.
2559                  */
2560                 action = (byte) (MBCS_ENTRY_FINAL_ACTION(entry));
2561                 if (action == MBCS_STATE_VALID_DIRECT_20
2562                         || (action == MBCS_STATE_FALLBACK_DIRECT_20 && isFallbackUsed())) {
2563
2564                     entry = MBCS_ENTRY_FINAL_VALUE(entry);
2565                     /* output surrogate pair */
2566                     target.put((char) (0xd800 | (char) (entry >>> 10)));
2567                     if (offsets != null) {
2568                         offsets.put(sourceIndex);
2569                     }
2570                     c = (char) (0xdc00 | (char) (entry & 0x3ff));
2571                     if (target.hasRemaining()) {
2572                         target.put(c);
2573                         if (offsets != null) {
2574                             offsets.put(sourceIndex);
2575                         }
2576                     } else {
2577                         /* target overflow */
2578                         charErrorBufferArray[0] = c;
2579                         charErrorBufferLength = 1;
2580                         cr[0] = CoderResult.OVERFLOW;
2581                         break;
2582                     }
2583
2584                     ++sourceIndex;
2585                     continue;
2586                 } else if (action == MBCS_STATE_FALLBACK_DIRECT_16) {
2587                     if (isFallbackUsed()) {
2588                         /* output BMP code point */
2589                         target.put(MBCS_ENTRY_FINAL_VALUE_16(entry));
2590                         if (offsets != null) {
2591                             offsets.put(sourceIndex);
2592                         }
2593
2594                         ++sourceIndex;
2595                         continue;
2596                     }
2597                 } else if (action == MBCS_STATE_UNASSIGNED) {
2598                     /* just fall through */
2599                 } else if (action == MBCS_STATE_ILLEGAL) {
2600                     /* callback(illegal) */
2601                     cr[0] = CoderResult.malformedForLength(1);
2602                 } else {
2603                     /* reserved, must never occur */
2604                     ++sourceIndex;
2605                     continue;
2606                 }
2607
2608                 if (cr[0].isError()) {
2609                     /* callback(illegal) */
2610                     break;
2611                 } else /* unassigned sequences indicated with byteIndex>0 */{
2612                     /* try an extension mapping */
2613                     int sourceBeginIndex = sourceArrayIndex;
2614                     toUBytesArray[0] = source.get(sourceArrayIndex - 1);
2615                     source.position(sourceArrayIndex);
2616                     toULength = toU((byte) 1, source, target, offsets, sourceIndex, flush, cr);
2617                     sourceArrayIndex = source.position();
2618                     sourceIndex += 1 + (sourceArrayIndex - sourceBeginIndex);
2619
2620                     if (cr[0].isError()) {
2621                         /* not mappable or buffer overflow */
2622                         break;
2623                     }
2624                 }
2625             }
2626
2627             /* write back the updated pointers */
2628             source.position(sourceArrayIndex);
2629
2630             return cr[0];
2631         }
2632
2633         private int getFallback(UConverterMBCSTable mbcsTable, int offset) {
2634             MBCSToUFallback[] toUFallbacks;
2635             int i, start, limit;
2636
2637             limit = mbcsTable.countToUFallbacks;
2638             if (limit > 0) {
2639                 /* do a binary search for the fallback mapping */
2640                 toUFallbacks = mbcsTable.toUFallbacks;
2641                 start = 0;
2642                 while (start < limit - 1) {
2643                     i = (start + limit) / 2;
2644                     if (offset < toUFallbacks[i].offset) {
2645                         limit = i;
2646                     } else {
2647                         start = i;
2648                     }
2649                 }
2650
2651                 /* did we really find it? */
2652                 if (offset == toUFallbacks[start].offset) {
2653                     return toUFallbacks[start].codePoint;
2654                 }
2655             }
2656
2657             return 0xfffe;
2658         }
2659
2660         /**
2661          * This is a simple version of _MBCSGetNextUChar() that is used by other converter implementations. It only
2662          * returns an "assigned" result if it consumes the entire input. It does not use state from the converter, nor
2663          * error codes. It does not handle the EBCDIC swaplfnl option (set in UConverter). It handles conversion
2664          * extensions but not GB 18030.
2665          * 
2666          * @return U+fffe unassigned U+ffff illegal otherwise the Unicode code point
2667          */
2668         int simpleGetNextUChar(ByteBuffer source, boolean useFallback) {
2669
2670             // #if 0
2671             // /*
2672             // * Code disabled 2002dec09 (ICU 2.4) because it is not currently used in ICU. markus
2673             // * TODO In future releases, verify that this function is never called for SBCS
2674             // * conversions, i.e., that sharedData->mbcs.countStates==1 is still true.
2675             // * Removal improves code coverage.
2676             // */
2677             // /* use optimized function if possible */
2678             // if(sharedData->mbcs.countStates==1) {
2679             // if(length==1) {
2680             // return ucnv_MBCSSingleSimpleGetNextUChar(sharedData, (uint8_t)*source, useFallback);
2681             // } else {
2682             // return 0xffff; /* illegal: more than a single byte for an SBCS converter */
2683             // }
2684             // }
2685             // #endif
2686
2687             /* set up the local pointers */
2688             int[][] stateTable = sharedData.mbcs.stateTable;
2689             char[] unicodeCodeUnits = sharedData.mbcs.unicodeCodeUnits;
2690
2691             /* converter state */
2692             int offset = 0;
2693             int state = sharedData.mbcs.dbcsOnlyState;
2694
2695             int action;
2696             int entry;
2697             int c;
2698             int i = source.position();
2699             int length = source.limit() - i;
2700
2701             /* conversion loop */
2702             while (true) {
2703                 // entry=stateTable[state][(uint8_t)source[i++]];
2704                 entry = stateTable[state][source.get(i++) & UConverterConstants.UNSIGNED_BYTE_MASK];
2705
2706                 if (MBCS_ENTRY_IS_TRANSITION(entry)) {
2707                     state = MBCS_ENTRY_TRANSITION_STATE(entry);
2708                     offset += MBCS_ENTRY_TRANSITION_OFFSET(entry);
2709
2710                     if (i == source.limit()) {
2711                         return 0xffff; /* truncated character */
2712                     }
2713                 } else {
2714                     /*
2715                      * An if-else-if chain provides more reliable performance for the most common cases compared to a
2716                      * switch.
2717                      */
2718                     action = MBCS_ENTRY_FINAL_ACTION(entry);
2719                     if (action == MBCS_STATE_VALID_16) {
2720                         offset += MBCS_ENTRY_FINAL_VALUE_16(entry);
2721                         c = unicodeCodeUnits[offset];
2722                         if (c != 0xfffe) {
2723                             /* done */
2724                         } else if (isToUUseFallback()) {
2725                             c = getFallback(sharedData.mbcs, offset);
2726                         }
2727                         /* else done with 0xfffe */
2728                     } else if (action == MBCS_STATE_VALID_DIRECT_16) {
2729                         // /* output BMP code point */
2730                         c = MBCS_ENTRY_FINAL_VALUE_16(entry);
2731                     } else if (action == MBCS_STATE_VALID_16_PAIR) {
2732                         offset += MBCS_ENTRY_FINAL_VALUE_16(entry);
2733                         c = unicodeCodeUnits[offset++];
2734                         if (c < 0xd800) {
2735                             /* output BMP code point below 0xd800 */
2736                         } else if (isToUUseFallback() ? c <= 0xdfff : c <= 0xdbff) {
2737                             /* output roundtrip or fallback supplementary code point */
2738                             c = (((c & 0x3ff) << 10) + unicodeCodeUnits[offset] + (0x10000 - 0xdc00));
2739                         } else if (isToUUseFallback() ? (c & 0xfffe) == 0xe000 : c == 0xe000) {
2740                             /* output roundtrip BMP code point above 0xd800 or fallback BMP code point */
2741                             c = unicodeCodeUnits[offset];
2742                         } else if (c == 0xffff) {
2743                             return 0xffff;
2744                         } else {
2745                             c = 0xfffe;
2746                         }
2747                     } else if (action == MBCS_STATE_VALID_DIRECT_20) {
2748                         /* output supplementary code point */
2749                         c = 0x10000 + MBCS_ENTRY_FINAL_VALUE(entry);
2750                     } else if (action == MBCS_STATE_FALLBACK_DIRECT_16) {
2751                         if (!isToUUseFallback(useFallback)) {
2752                             c = 0xfffe;
2753                         } else {
2754                             /* output BMP code point */
2755                             c = MBCS_ENTRY_FINAL_VALUE_16(entry);
2756                         }
2757                     } else if (action == MBCS_STATE_FALLBACK_DIRECT_20) {
2758                         if (!isToUUseFallback(useFallback)) {
2759                             c = 0xfffe;
2760                         } else {
2761                             /* output supplementary code point */
2762                             c = 0x10000 + MBCS_ENTRY_FINAL_VALUE(entry);
2763                         }
2764                     } else if (action == MBCS_STATE_UNASSIGNED) {
2765                         c = 0xfffe;
2766                     } else {
2767                         /*
2768                          * forbid MBCS_STATE_CHANGE_ONLY for this function, and MBCS_STATE_ILLEGAL and reserved action
2769                          * codes
2770                          */
2771                         return 0xffff;
2772                     }
2773                     break;
2774                 }
2775             }
2776
2777             if (i != source.limit()) {
2778                 /* illegal for this function: not all input consumed */
2779                 return 0xffff;
2780             }
2781
2782             if (c == 0xfffe) {
2783                 /* try an extension mapping */
2784                 if (sharedData.mbcs.extIndexes != null) {
2785                     /* Increase the limit for proper handling. Used in LMBCS. */
2786                     if (source.limit() > i + length) {
2787                         source.limit(i + length);
2788                     }
2789                     return simpleMatchToU(source, useFallback);
2790                 }
2791             }
2792
2793             return c;
2794         }
2795         private boolean hasValidTrailBytes(int[][] stateTable, short state) {
2796             int[] row = stateTable[state];
2797             int b, entry;
2798             /* First test for final entries in this state for some commonly valid byte values. */
2799             entry = row[0xa1];
2800             if (!MBCS_ENTRY_IS_TRANSITION(entry) && MBCS_ENTRY_FINAL_ACTION(entry) != MBCS_STATE_ILLEGAL) {
2801                 return true;
2802             }
2803             entry = row[0x41];
2804             if (!MBCS_ENTRY_IS_TRANSITION(entry) && MBCS_ENTRY_FINAL_ACTION(entry) != MBCS_STATE_ILLEGAL) {
2805                 return true;
2806             }
2807             /* Then test for final entries in this state. */
2808             for (b = 0; b <= 0xff; b++) {
2809                 entry = row[b];
2810                 if (!MBCS_ENTRY_IS_TRANSITION(entry) && MBCS_ENTRY_FINAL_ACTION(entry) != MBCS_STATE_ILLEGAL) {
2811                     return true;
2812                 }
2813             }
2814             /* Then recurse for transition entries. */
2815             for (b = 0; b <= 0xff; b++) {
2816                 entry = row[b];
2817                 if (MBCS_ENTRY_IS_TRANSITION(entry) && 
2818                         hasValidTrailBytes(stateTable, (short)(MBCS_ENTRY_TRANSITION_STATE(entry) & UConverterConstants.UNSIGNED_BYTE_MASK))) {
2819                     return true;
2820                 }
2821             }
2822             return false;
2823         }
2824         
2825         private boolean isSingleOrLead(int[][] stateTable, int state, boolean isDBCSOnly, int b) {
2826             int[] row = stateTable[state];
2827             int entry = row[b];
2828             if (MBCS_ENTRY_IS_TRANSITION(entry)) { /* lead byte */
2829                 return hasValidTrailBytes(stateTable, (short)(MBCS_ENTRY_TRANSITION_STATE(entry) & UConverterConstants.UNSIGNED_BYTE_MASK));
2830             } else {
2831                 short action = (short)(MBCS_ENTRY_FINAL_ACTION(entry) & UConverterConstants.UNSIGNED_BYTE_MASK);
2832                 if (action == MBCS_STATE_CHANGE_ONLY && isDBCSOnly) {
2833                     return false;   /* SI/SO are illegal for DBCS-only conversion */
2834                 } else {
2835                     return (action != MBCS_STATE_ILLEGAL);
2836                 }
2837             }
2838         }
2839         
2840
2841     }
2842
2843     class CharsetEncoderMBCS extends CharsetEncoderICU {
2844         private boolean allowReplacementChanges = false;
2845
2846         CharsetEncoderMBCS(CharsetICU cs) {
2847             super(cs, fromUSubstitution);
2848             allowReplacementChanges = true; // allow changes in implReplaceWith
2849             implReset();
2850         }
2851
2852         protected void implReset() {
2853             super.implReset();
2854             preFromUFirstCP = UConverterConstants.U_SENTINEL;
2855         }
2856
2857         @SuppressWarnings("fallthrough")
2858         protected CoderResult encodeLoop(CharBuffer source, ByteBuffer target, IntBuffer offsets, boolean flush) {
2859             CoderResult[] cr = { CoderResult.UNDERFLOW };
2860             // if (!source.hasRemaining() && fromUChar32 == 0)
2861             // return cr[0];
2862
2863             int sourceArrayIndex;
2864             char[] table;
2865             byte[] pArray, bytes;
2866             int pArrayIndex, outputType, c;
2867             int prevSourceIndex, sourceIndex, nextSourceIndex;
2868             int stage2Entry = 0, value = 0, length = 0, prevLength;
2869             short uniMask;
2870             // long asciiRoundtrips;
2871             
2872             byte[] si_value = new byte[2];
2873             byte[] so_value = new byte[2];
2874             int si_value_length = 0, so_value_length = 0;
2875
2876             boolean gotoUnassigned = false;
2877
2878             try {
2879
2880                 if (!flush && preFromUFirstCP >= 0) {
2881                     /*
2882                      * pass sourceIndex=-1 because we continue from an earlier buffer in the future, this may change
2883                      * with continuous offsets
2884                      */
2885                     cr[0] = continueMatchFromU(source, target, offsets, flush, -1);
2886
2887                     if (cr[0].isError() || preFromULength < 0) {
2888                         return cr[0];
2889                     }
2890                 }
2891
2892                 /* use optimized function if possible */
2893                 outputType = sharedData.mbcs.outputType;
2894                 uniMask = sharedData.mbcs.unicodeMask;
2895                 if (outputType == MBCS_OUTPUT_1 && (uniMask & UConverterConstants.HAS_SURROGATES) == 0) {
2896                     if ((uniMask & UConverterConstants.HAS_SUPPLEMENTARY) == 0) {
2897                         cr[0] = cnvMBCSSingleFromBMPWithOffsets(source, target, offsets, flush);
2898                     } else {
2899                         cr[0] = cnvMBCSSingleFromUnicodeWithOffsets(source, target, offsets, flush);
2900                     }
2901                     return cr[0];
2902                 } else if (outputType == MBCS_OUTPUT_2) {
2903                     cr[0] = cnvMBCSDoubleFromUnicodeWithOffsets(source, target, offsets, flush);
2904                     return cr[0];
2905                 }
2906
2907                 table = sharedData.mbcs.fromUnicodeTable;
2908                 sourceArrayIndex = source.position();
2909
2910                 if ((options & UConverterConstants.OPTION_SWAP_LFNL) != 0) {
2911                     bytes = sharedData.mbcs.swapLFNLFromUnicodeBytes;
2912                 } else {
2913                     bytes = sharedData.mbcs.fromUnicodeBytes;
2914                 }
2915
2916                 // asciiRoundtrips = sharedData.mbcs.asciiRoundtrips;
2917
2918                 /* get the converter state from UConverter */
2919                 c = fromUChar32;
2920
2921                 if (outputType == MBCS_OUTPUT_2_SISO) {
2922                     prevLength = fromUnicodeStatus;
2923                     if (prevLength == 0) {
2924                         /* set the real value */
2925                         prevLength = 1;
2926                     }
2927                 } else {
2928                     /* prevent fromUnicodeStatus from being set to something non-0 */
2929                     prevLength = 0;
2930                 }
2931
2932                 /* sourceIndex=-1 if the current character began in the previous buffer */
2933                 prevSourceIndex = -1;
2934                 sourceIndex = c == 0 ? 0 : -1;
2935                 nextSourceIndex = 0;
2936
2937                 /* Get the SI/SO character for the converter */
2938                 si_value_length = getSISOBytes(SISO_Option.SI, options, si_value);
2939                 so_value_length = getSISOBytes(SISO_Option.SO, options, so_value);
2940
2941                 /* conversion loop */
2942                 /*
2943                  * This is another piece of ugly code: A goto into the loop if the converter state contains a first
2944                  * surrogate from the previous function call. It saves me to check in each loop iteration a check of
2945                  * if(c==0) and duplicating the trail-surrogate-handling code in the else branch of that check. I could
2946                  * not find any other way to get around this other than using a function call for the conversion and
2947                  * callback, which would be even more inefficient.
2948                  * 
2949                  * Markus Scherer 2000-jul-19
2950                  */
2951                 boolean doloop = true;
2952                 boolean doread = true;
2953                 if (c != 0 && target.hasRemaining()) {
2954                     if (UTF16.isLeadSurrogate((char) c) && (uniMask & UConverterConstants.HAS_SURROGATES) == 0) {
2955                         // c is a lead surrogate, read another input
2956                         SideEffects x = new SideEffects(c, sourceArrayIndex, sourceIndex, nextSourceIndex,
2957                                 prevSourceIndex, prevLength);
2958                         doloop = getTrail(source, target, uniMask, x, flush, cr);
2959                         doread = x.doread;
2960                         c = x.c;
2961                         sourceArrayIndex = x.sourceArrayIndex;
2962                         sourceIndex = x.sourceIndex;
2963                         nextSourceIndex = x.nextSourceIndex;
2964                         prevSourceIndex = x.prevSourceIndex;
2965                         prevLength = x.prevLength;
2966                     } else {
2967                         // c is not a lead surrogate, do not read another input
2968                         doread = false;
2969                     }
2970                 }
2971
2972                 if (doloop) {
2973                     while (!doread || sourceArrayIndex < source.limit()) {
2974                         /*
2975                          * This following test is to see if available input would overflow the output. It does not catch
2976                          * output of more than one byte that overflows as a result of a multi-byte character or callback
2977                          * output from the last source character. Therefore, those situations also test for overflows
2978                          * and will then break the loop, too.
2979                          */
2980                         if (target.hasRemaining()) {
2981                             /*
2982                              * Get a correct Unicode code point: a single UChar for a BMP code point or a matched
2983                              * surrogate pair for a "supplementary code point".
2984                              */
2985
2986                             if (doread) {
2987                                 // doread might be false only on the first looping
2988
2989                                 c = source.get(sourceArrayIndex++);
2990                                 ++nextSourceIndex;
2991
2992                                 /*
2993                                  * This also tests if the codepage maps single surrogates. If it does, then surrogates
2994                                  * are not paired but mapped separately. Note that in this case unmatched surrogates are
2995                                  * not detected.
2996                                  */
2997                                 if (UTF16.isSurrogate((char) c)
2998                                         && (uniMask & UConverterConstants.HAS_SURROGATES) == 0) {
2999                                     if (UTF16.isLeadSurrogate((char) c)) {
3000                                         // getTrail:
3001                                         SideEffects x = new SideEffects(c, sourceArrayIndex, sourceIndex,
3002                                                 nextSourceIndex, prevSourceIndex, prevLength);
3003                                         doloop = getTrail(source, target, uniMask, x, flush, cr);
3004                                         c = x.c;
3005                                         sourceArrayIndex = x.sourceArrayIndex;
3006                                         sourceIndex = x.sourceIndex;
3007                                         nextSourceIndex = x.nextSourceIndex;
3008                                         prevSourceIndex = x.prevSourceIndex;
3009
3010                                         if (x.doread) {
3011                                             if (doloop)
3012                                                 continue;
3013                                             else
3014                                                 break;
3015                                         }
3016                                     } else {
3017                                         /* this is an unmatched trail code unit (2nd surrogate) */
3018                                         /* callback(illegal) */
3019                                         cr[0] = CoderResult.malformedForLength(1);
3020                                         break;
3021                                     }
3022                                 }
3023                             } else {
3024                                 doread = true;
3025                             }
3026                             /* convert the Unicode code point in c into codepage bytes */
3027
3028                             /*
3029                              * The basic lookup is a triple-stage compact array (trie) lookup. For details see the
3030                              * beginning of this file.
3031                              * 
3032                              * Single-byte codepages are handled with a different data structure by _MBCSSingle...
3033                              * functions.
3034                              * 
3035                              * The result consists of a 32-bit value from stage 2 and a pointer to as many bytes as are
3036                              * stored per character. The pointer points to the character's bytes in stage 3. Bits 15..0
3037                              * of the stage 2 entry contain the stage 3 index for that pointer, while bits 31..16 are
3038                              * flags for which of the 16 characters in the block are roundtrip-assigned.
3039                              * 
3040                              * For 2-byte and 4-byte codepages, the bytes are stored as uint16_t respectively as
3041                              * uint32_t, in the platform encoding. For 3-byte codepages, the bytes are always stored in
3042                              * big-endian order.
3043                              * 
3044                              * For EUC encodings that use only either 0x8e or 0x8f as the first byte of their longest
3045                              * byte sequences, the first two bytes in this third stage indicate with their 7th bits
3046                              * whether these bytes are to be written directly or actually need to be preceeded by one of
3047                              * the two Single-Shift codes. With this, the third stage stores one byte fewer per
3048                              * character than the actual maximum length of EUC byte sequences.
3049                              * 
3050                              * Other than that, leading zero bytes are removed and the other bytes output. A single zero
3051                              * byte may be output if the "assigned" bit in stage 2 was on. The data structure does not
3052                              * support zero byte output as a fallback, and also does not allow output of leading zeros.
3053                              */
3054                             stage2Entry = MBCS_STAGE_2_FROM_U(table, c);
3055
3056                             /* get the bytes and the length for the output */
3057                             switch (outputType) {
3058                             /* This is handled above with the method cnvMBCSDoubleFromUnicodeWithOffsets() */
3059                             /* case MBCS_OUTPUT_2:
3060                                 value = MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, c);
3061                                 if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xff) {
3062                                     length = 1;
3063                                 } else {
3064                                     length = 2;
3065                                 }
3066                                 break; */
3067                             case MBCS_OUTPUT_2_SISO:
3068                                 /* 1/2-byte stateful with Shift-In/Shift-Out */
3069                                 /*
3070                                  * Save the old state in the converter object right here, then change the local
3071                                  * prevLength state variable if necessary. Then, if this character turns out to be
3072                                  * unassigned or a fallback that is not taken, the callback code must not save the new
3073                                  * state in the converter because the new state is for a character that is not output.
3074                                  * However, the callback must still restore the state from the converter in case the
3075                                  * callback function changed it for its output.
3076                                  */
3077                                 fromUnicodeStatus = prevLength; /* save the old state */
3078                                 value = MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, c);
3079                                 if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xff) {
3080                                     if (value == 0 && MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, c) == false) {
3081                                         /* no mapping, leave value==0 */
3082                                         length = 0;
3083                                     } else if (prevLength <= 1) {
3084                                         length = 1;
3085                                     } else {
3086                                         /* change from double-byte mode to single-byte */
3087                                         if (si_value_length == 1) {
3088                                             value|=si_value[0]<<8;
3089                                             length = 2;
3090                                         } else if (si_value_length == 2) {
3091                                             value|=si_value[1]<<8;
3092                                             value|=si_value[0]<<16;
3093                                             length = 3;
3094                                         }
3095                                         prevLength = 1;
3096                                     }
3097                                 } else {
3098                                     if (prevLength == 2) {
3099                                         length = 2;
3100                                     } else {
3101                                         /* change from single-byte mode to double-byte */
3102                                         if (so_value_length == 1) {
3103                                             value|=so_value[0]<<16;
3104                                             length = 3;
3105                                         } else if (so_value_length == 2) {
3106                                             value|=so_value[1]<<16;
3107                                             value|=so_value[0]<<24;
3108                                             length = 4;
3109                                         }
3110                                         prevLength = 2;
3111                                     }
3112                                 }
3113                                 break;
3114                             case MBCS_OUTPUT_DBCS_ONLY:
3115                                 /* table with single-byte results, but only DBCS mappings used */
3116                                 value = MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, c);
3117                                 if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xff) {
3118                                     /* no mapping or SBCS result, not taken for DBCS-only */
3119                                     value = stage2Entry = 0; /* stage2Entry=0 to reset roundtrip flags */
3120                                     length = 0;
3121                                 } else {
3122                                     length = 2;
3123                                 }
3124                                 break;
3125                             case MBCS_OUTPUT_3:
3126                                 pArray = bytes;
3127                                 pArrayIndex = MBCS_POINTER_3_FROM_STAGE_2(bytes, stage2Entry, c);
3128                                 value = ((pArray[pArrayIndex] & UConverterConstants.UNSIGNED_BYTE_MASK) << 16)
3129                                         | ((pArray[pArrayIndex + 1] & UConverterConstants.UNSIGNED_BYTE_MASK) << 8)
3130                                         | (pArray[pArrayIndex + 2] & UConverterConstants.UNSIGNED_BYTE_MASK);
3131                                 if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xff) {
3132                                     length = 1;
3133                                 } else if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xffff) {
3134                                     length = 2;
3135                                 } else {
3136                                     length = 3;
3137                                 }
3138                                 break;
3139                             case MBCS_OUTPUT_4:
3140                                 value = MBCS_VALUE_4_FROM_STAGE_2(bytes, stage2Entry, c);
3141                                 if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xff) {
3142                                     length = 1;
3143                                 } else if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xffff) {
3144                                     length = 2;
3145                                 } else if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xffffff) {
3146                                     length = 3;
3147                                 } else {
3148                                     length = 4;
3149                                 }
3150                                 break;
3151                             case MBCS_OUTPUT_3_EUC:
3152                                 value = MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, c);
3153                                 /* EUC 16-bit fixed-length representation */
3154                                 if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xff) {
3155                                     length = 1;
3156                                 } else if ((value & 0x8000) == 0) {
3157                                     value |= 0x8e8000;
3158                                     length = 3;
3159                                 } else if ((value & 0x80) == 0) {
3160                                     value |= 0x8f0080;
3161                                     length = 3;
3162                                 } else {
3163                                     length = 2;
3164                                 }
3165                                 break;
3166                             case MBCS_OUTPUT_4_EUC:
3167                                 pArray = bytes;
3168                                 pArrayIndex = MBCS_POINTER_3_FROM_STAGE_2(bytes, stage2Entry, c);
3169                                 value = ((pArray[pArrayIndex] & UConverterConstants.UNSIGNED_BYTE_MASK) << 16)
3170                                         | ((pArray[pArrayIndex + 1] & UConverterConstants.UNSIGNED_BYTE_MASK) << 8)
3171                                         | (pArray[pArrayIndex + 2] & UConverterConstants.UNSIGNED_BYTE_MASK);
3172                                 /* EUC 16-bit fixed-length representation applied to the first two bytes */
3173                                 if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xff) {
3174                                     length = 1;
3175                                 } else if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xffff) {
3176                                     length = 2;
3177                                 } else if ((value & 0x800000) == 0) {
3178                                     value |= 0x8e800000;
3179                                     length = 4;
3180                                 } else if ((value & 0x8000) == 0) {
3181                                     value |= 0x8f008000;
3182                                     length = 4;
3183                                 } else {
3184                                     length = 3;
3185                                 }
3186                                 break;
3187                             default:
3188                                 /* must not occur */
3189                                 /*
3190                                  * To avoid compiler warnings that value & length may be used without having been
3191                                  * initialized, we set them here. In reality, this is unreachable code. Not having a
3192                                  * default branch also causes warnings with some compilers.
3193                                  */
3194                                 value = stage2Entry = 0; /* stage2Entry=0 to reset roundtrip flags */
3195                                 length = 0;
3196                                 break;
3197                             }
3198                             
3199                             /* is this code point assigned, or do we use fallbacks? */
3200                             if (gotoUnassigned || (!(MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, c) || (isFromUUseFallback(c) && value != 0)))) {
3201                                 gotoUnassigned = false;
3202                                 /*
3203                                  * We allow a 0 byte output if the "assigned" bit is set for this entry. There is no way
3204                                  * with this data structure for fallback output to be a zero byte.
3205                                  */
3206
3207                                 // unassigned:
3208                                 SideEffects x = new SideEffects(c, sourceArrayIndex, sourceIndex, nextSourceIndex,
3209                                         prevSourceIndex, prevLength);
3210                                 doloop = unassigned(source, target, offsets, x, flush, cr);
3211                                 c = x.c;
3212                                 sourceArrayIndex = x.sourceArrayIndex;
3213                                 sourceIndex = x.sourceIndex;
3214                                 nextSourceIndex = x.nextSourceIndex;
3215                                 prevSourceIndex = x.prevSourceIndex;
3216                                 prevLength = x.prevLength;
3217                                 if (doloop)
3218                                     continue;
3219                                 else
3220                                     break;
3221                             }
3222
3223                             /* write the output character bytes from value and length */
3224                             /* from the first if in the loop we know that targetCapacity>0 */
3225                             if (length <= target.remaining()) {
3226                                 switch (length) {
3227                                 /* each branch falls through to the next one */
3228                                 case 4:
3229                                     target.put((byte) (value >>> 24));
3230                                     if (offsets != null) {
3231                                         offsets.put(sourceIndex);
3232                                     }
3233                                 case 3:
3234                                     target.put((byte) (value >>> 16));
3235                                     if (offsets != null) {
3236                                         offsets.put(sourceIndex);
3237                                     }
3238                                 case 2:
3239                                     target.put((byte) (value >>> 8));
3240                                     if (offsets != null) {
3241                                         offsets.put(sourceIndex);
3242                                     }
3243                                 case 1:
3244                                     target.put((byte) value);
3245                                     if (offsets != null) {
3246                                         offsets.put(sourceIndex);
3247                                     }
3248                                 default:
3249                                     /* will never occur */
3250                                     break;
3251                                 }
3252                             } else {
3253                                 int errorBufferArrayIndex;
3254
3255                                 /*
3256                                  * We actually do this backwards here: In order to save an intermediate variable, we
3257                                  * output first to the overflow buffer what does not fit into the regular target.
3258                                  */
3259                                 /* we know that 1<=targetCapacity<length<=4 */
3260                                 length -= target.remaining();
3261
3262                                 errorBufferArrayIndex = 0;
3263                                 switch (length) {
3264                                 /* each branch falls through to the next one */
3265                                 case 3:
3266                                     errorBuffer[errorBufferArrayIndex++] = (byte) (value >>> 16);
3267                                 case 2:
3268                                     errorBuffer[errorBufferArrayIndex++] = (byte) (value >>> 8);
3269                                 case 1:
3270                                     errorBuffer[errorBufferArrayIndex] = (byte) value;
3271                                 default:
3272                                     /* will never occur */
3273                                     break;
3274                                 }
3275                                 errorBufferLength = (byte) length;
3276
3277                                 /* now output what fits into the regular target */
3278                                 value >>>= 8 * length; /* length was reduced by targetCapacity */
3279                                 switch (target.remaining()) {
3280                                 /* each branch falls through to the next one */
3281                                 case 3:
3282                                     target.put((byte) (value >>> 16));
3283                                     if (offsets != null) {
3284                                         offsets.put(sourceIndex);
3285                                     }
3286                                 case 2:
3287                                     target.put((byte) (value >>> 8));
3288                                     if (offsets != null) {
3289                                         offsets.put(sourceIndex);
3290                                     }
3291                                 case 1:
3292                                     target.put((byte) value);
3293                                     if (offsets != null) {
3294                                         offsets.put(sourceIndex);
3295                                     }
3296                                 default:
3297                                     /* will never occur */
3298                                     break;
3299                                 }
3300
3301                                 /* target overflow */
3302                                 cr[0] = CoderResult.OVERFLOW;
3303                                 c = 0;
3304                                 break;
3305                             }
3306
3307                             /* normal end of conversion: prepare for a new character */
3308                             c = 0;
3309                             if (offsets != null) {
3310                                 prevSourceIndex = sourceIndex;
3311                                 sourceIndex = nextSourceIndex;
3312                             }
3313                             continue;
3314                         } else {
3315                             /* target is full */
3316                             cr[0] = CoderResult.OVERFLOW;
3317                             break;
3318                         }
3319                     }
3320                 }
3321
3322                 /*
3323                  * the end of the input stream and detection of truncated input are handled by the framework, but for
3324                  * EBCDIC_STATEFUL conversion we need to emit an SI at the very end
3325                  * 
3326                  * conditions: successful EBCDIC_STATEFUL in DBCS mode end of input and no truncated input
3327                  */
3328                 if (outputType == MBCS_OUTPUT_2_SISO && prevLength == 2 && flush && sourceArrayIndex >= source.limit()
3329                         && c == 0) {
3330
3331                     /* EBCDIC_STATEFUL ending with DBCS: emit an SI to return the output stream to SBCS */
3332                     if (target.hasRemaining()) {
3333                         target.put(si_value[0]);
3334                         if (si_value_length == 2) {
3335                             if (target.remaining() > 0) {
3336                                 target.put(si_value[1]);
3337                             } else {
3338                                 errorBuffer[0] = si_value[1];
3339                                 errorBufferLength = 1;
3340                                 cr[0] = CoderResult.OVERFLOW;
3341                             }
3342                         }
3343                         if (offsets != null) {
3344                             /* set the last source character's index (sourceIndex points at sourceLimit now) */
3345                             offsets.put(prevSourceIndex);
3346                         }
3347                     } else {
3348                         /* target is full */
3349                         errorBuffer[0] = si_value[0];
3350                         if (si_value_length == 2) {
3351                             errorBuffer[1] = si_value[1];
3352                         }
3353                         errorBufferLength = si_value_length;
3354                         cr[0] = CoderResult.OVERFLOW;
3355                     }
3356                     prevLength = 1; /* we switched into SBCS */
3357                 }
3358
3359                 /* set the converter state back into UConverter */
3360                 fromUChar32 = c;
3361                 fromUnicodeStatus = prevLength;
3362
3363                 source.position(sourceArrayIndex);
3364             } catch (BufferOverflowException ex) {
3365                 cr[0] = CoderResult.OVERFLOW;
3366             }
3367
3368             return cr[0];
3369         }
3370
3371         /*
3372          * This is another simple conversion function for internal use by other conversion implementations. It does not
3373          * use the converter state nor call callbacks. It does not handle the EBCDIC swaplfnl option (set in
3374          * UConverter). It handles conversion extensions but not GB 18030.
3375          * 
3376          * It converts one single Unicode code point into codepage bytes, encoded as one 32-bit value. The function
3377          * returns the number of bytes in *pValue: 1..4 the number of bytes in *pValue 0 unassigned (*pValue undefined)
3378          * -1 illegal (currently not used, *pValue undefined)
3379          * 
3380          * *pValue will contain the resulting bytes with the last byte in bits 7..0, the second to last byte in bits
3381          * 15..8, etc. Currently, the function assumes but does not check that 0<=c<=0x10ffff.
3382          */
3383         int fromUChar32(int c, int[] pValue, boolean isUseFallback) {
3384             // #if 0
3385             // /* #if 0 because this is not currently used in ICU - reduce code, increase code coverage */
3386             // const uint8_t *p;
3387             // #endif
3388
3389             char[] table;
3390             int stage2Entry;
3391             int value;
3392             int length;
3393             int p;
3394
3395             /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
3396             if (c <= 0xffff || ((sharedData.mbcs.unicodeMask & UConverterConstants.HAS_SUPPLEMENTARY) != 0)) {
3397                 table = sharedData.mbcs.fromUnicodeTable;
3398
3399                 /* convert the Unicode code point in c into codepage bytes (same as in _MBCSFromUnicodeWithOffsets) */
3400                 if (sharedData.mbcs.outputType == MBCS_OUTPUT_1) {
3401                     value = MBCS_SINGLE_RESULT_FROM_U(table, sharedData.mbcs.fromUnicodeBytes, c);
3402                     /* is this code point assigned, or do we use fallbacks? */
3403                     if (isUseFallback ? value >= 0x800 : value >= 0xc00) {
3404                         pValue[0] = value & 0xff;
3405                         return 1;
3406                     }
3407                 } else /* outputType!=MBCS_OUTPUT_1 */{
3408                     stage2Entry = MBCS_STAGE_2_FROM_U(table, c);
3409
3410                     /* get the bytes and the length for the output */
3411                     switch (sharedData.mbcs.outputType) {
3412                     case MBCS_OUTPUT_2:
3413                         value = MBCS_VALUE_2_FROM_STAGE_2(sharedData.mbcs.fromUnicodeBytes, stage2Entry, c);
3414                         if (value <= 0xff) {
3415                             length = 1;
3416                         } else {
3417                             length = 2;
3418                         }
3419                         break;
3420                     // #if 0
3421                     // /* #if 0 because this is not currently used in ICU - reduce code, increase code coverage */
3422                     // case MBCS_OUTPUT_DBCS_ONLY:
3423                     // /* table with single-byte results, but only DBCS mappings used */
3424                     // value=MBCS_VALUE_2_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
3425                     // if(value<=0xff) {
3426                     // /* no mapping or SBCS result, not taken for DBCS-only */
3427                     // value=stage2Entry=0; /* stage2Entry=0 to reset roundtrip flags */
3428                     // length=0;
3429                     // } else {
3430                     // length=2;
3431                     // }
3432                     // break;
3433                     case MBCS_OUTPUT_3:
3434                         byte[] bytes = sharedData.mbcs.fromUnicodeBytes;
3435                         p = CharsetMBCS.MBCS_POINTER_3_FROM_STAGE_2(bytes, stage2Entry, c);
3436                         value = ((bytes[p] & UConverterConstants.UNSIGNED_BYTE_MASK)<<16) |
3437                             ((bytes[p+1] & UConverterConstants.UNSIGNED_BYTE_MASK)<<8) |
3438                             (bytes[p+2] & UConverterConstants.UNSIGNED_BYTE_MASK);
3439                         if (value <= 0xff) {
3440                             length = 1;
3441                         } else if (value <= 0xffff) {
3442                             length = 2;
3443                         } else {
3444                             length = 3;
3445                         }
3446                         break;
3447                     // case MBCS_OUTPUT_4:
3448                     // value=MBCS_VALUE_4_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
3449                     // if(value<=0xff) {
3450                     // length=1;
3451                     // } else if(value<=0xffff) {
3452                     // length=2;
3453                     // } else if(value<=0xffffff) {
3454                     // length=3;
3455                     // } else {
3456                     // length=4;
3457                     // }
3458                     // break;
3459                     // case MBCS_OUTPUT_3_EUC:
3460                     // value=MBCS_VALUE_2_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
3461                     // /* EUC 16-bit fixed-length representation */
3462                     // if(value<=0xff) {
3463                     // length=1;
3464                     // } else if((value&0x8000)==0) {
3465                     // value|=0x8e8000;
3466                     // length=3;
3467                     // } else if((value&0x80)==0) {
3468                     // value|=0x8f0080;
3469                     // length=3;
3470                     // } else {
3471                     // length=2;
3472                     // }
3473                     // break;
3474                     // case MBCS_OUTPUT_4_EUC:
3475                     // p=MBCS_POINTER_3_FROM_STAGE_2(sharedData->mbcs.fromUnicodeBytes, stage2Entry, c);
3476                     // value=((uint32_t)*p<<16)|((uint32_t)p[1]<<8)|p[2];
3477                     // /* EUC 16-bit fixed-length representation applied to the first two bytes */
3478                     // if(value<=0xff) {
3479                     // length=1;
3480                     // } else if(value<=0xffff) {
3481                     // length=2;
3482                     // } else if((value&0x800000)==0) {
3483                     // value|=0x8e800000;
3484                     // length=4;
3485                     // } else if((value&0x8000)==0) {
3486                     // value|=0x8f008000;
3487                     // length=4;
3488                     // } else {
3489                     // length=3;
3490                     // }
3491                     // break;
3492                     // #endif
3493                     default:
3494                         /* must not occur */
3495                         return -1;
3496                     }
3497
3498                     /* is this code point assigned, or do we use fallbacks? */
3499                     if (MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, c)
3500                             || (CharsetEncoderICU.isFromUUseFallback(isUseFallback, c) && value != 0)) {
3501                         /*
3502                          * We allow a 0 byte output if the "assigned" bit is set for this entry. There is no way with
3503                          * this data structure for fallback output to be a zero byte.
3504                          */
3505                         /* assigned */
3506                         pValue[0] = value;
3507                         return length;
3508                     }
3509                 }
3510             }
3511
3512             if (sharedData.mbcs.extIndexes != null) {
3513                 length = simpleMatchFromU(c, pValue, isUseFallback);
3514                 return length >= 0 ? length : -length; /* return abs(length); */
3515             }
3516
3517             /* unassigned */
3518             return 0;
3519         }
3520
3521         /*
3522          * continue partial match with new input, requires cnv->preFromUFirstCP>=0 never called for simple,
3523          * single-character conversion
3524          */
3525         private CoderResult continueMatchFromU(CharBuffer source, ByteBuffer target, IntBuffer offsets, boolean flush,
3526                 int srcIndex) {
3527             CoderResult cr = CoderResult.UNDERFLOW;
3528             int[] value = new int[1];
3529             int match;
3530
3531             match = matchFromU(preFromUFirstCP, preFromUArray, preFromUBegin, preFromULength, source, value, useFallback, flush);
3532             if (match >= 2) {
3533                 match -= 2; /* remove 2 for the initial code point */
3534
3535                 if (match >= preFromULength) {
3536                     /* advance src pointer for the consumed input */
3537                     source.position(source.position() + match - preFromULength);
3538                     preFromULength = 0;
3539                 } else {
3540                     /* the match did not use all of preFromU[] - keep the rest for replay */
3541                     int length = preFromULength - match;
3542                     System.arraycopy(preFromUArray, preFromUBegin + match, preFromUArray, preFromUBegin, length);
3543                     preFromULength = (byte) -length;
3544                 }
3545
3546                 /* finish the partial match */
3547                 preFromUFirstCP = UConverterConstants.U_SENTINEL;
3548
3549                 /* write result */
3550                 writeFromU(value[0], target, offsets, srcIndex);
3551             } else if (match < 0) {
3552                 /* save state for partial match */
3553                 int sArrayIndex;
3554                 int j;
3555
3556                 /* just _append_ the newly consumed input to preFromU[] */
3557                 sArrayIndex = source.position();
3558                 match = -match - 2; /* remove 2 for the initial code point */
3559                 for (j = preFromULength; j < match; ++j) {
3560                     preFromUArray[j] = source.get(sArrayIndex++);
3561                 }
3562                 source.position(sArrayIndex); /* same as *src=srcLimit; because we reached the end of input */
3563                 preFromULength = (byte) match;
3564             } else { /* match==0 or 1 */
3565                 /*
3566                  * no match
3567                  * 
3568                  * We need to split the previous input into two parts:
3569                  * 
3570                  * 1. The first code point is unmappable - that's how we got into trying the extension data in the first
3571                  * place. We need to move it from the preFromU buffer to the error buffer, set an error code, and
3572                  * prepare the rest of the previous input for 2.
3573                  * 
3574                  * 2. The rest of the previous input must be converted once we come back from the callback for the first
3575                  * code point. At that time, we have to try again from scratch to convert these input characters. The
3576                  * replay will be handled by the ucnv.c conversion code.
3577                  */
3578
3579                 if (match == 1) {
3580                     /* matched, no mapping but request for <subchar1> */
3581                     useSubChar1 = true;
3582                 }
3583
3584                 /* move the first code point to the error field */
3585                 fromUChar32 = preFromUFirstCP;
3586                 preFromUFirstCP = UConverterConstants.U_SENTINEL;
3587
3588                 /* mark preFromU for replay */
3589                 preFromULength = (byte) -preFromULength;
3590
3591                 /* set the error code for unassigned */
3592                 // TODO: figure out what the unmappable length really should be
3593                 cr = CoderResult.unmappableForLength(1);
3594             }
3595             return cr;
3596         }
3597
3598         /**
3599          * @param cx
3600          *            pointer to extension data; if NULL, returns 0
3601          * @param firstCP
3602          *            the first code point before all the other UChars
3603          * @param pre
3604          *            UChars that must match; !initialMatch: partial match with them
3605          * @param preLength
3606          *            length of pre, >=0
3607          * @param src
3608          *            UChars that can be used to complete a match
3609          * @param srcLength
3610          *            length of src, >=0
3611          * @param pMatchValue
3612          *            [out] output result value for the match from the data structure
3613          * @param useFallback
3614          *            "use fallback" flag, usually from cnv->useFallback
3615          * @param flush
3616          *            TRUE if the end of the input stream is reached
3617          * @return >1: matched, return value=total match length (number of input units matched) 1: matched, no mapping
3618          *         but request for <subchar1> (only for the first code point) 0: no match <0: partial match, return
3619          *         value=negative total match length (partial matches are never returned for flush==TRUE) (partial
3620          *         matches are never returned as being longer than UCNV_EXT_MAX_UCHARS) the matchLength is 2 if only
3621          *         firstCP matched, and >2 if firstCP and further code units matched
3622          */
3623         // static int32_t ucnv_extMatchFromU(const int32_t *cx, UChar32 firstCP, const UChar *pre, int32_t preLength,
3624         // const UChar *src, int32_t srcLength, uint32_t *pMatchValue, UBool useFallback, UBool flush)
3625         private int matchFromU(int firstCP, char[] preArray, int preArrayBegin, int preLength, CharBuffer source,
3626                 int[] pMatchValue, boolean isUseFallback, boolean flush) {
3627             ByteBuffer cx = sharedData.mbcs.extIndexes;
3628
3629             CharBuffer stage12, stage3;
3630             IntBuffer stage3b;
3631
3632             CharBuffer fromUTableUChars, fromUSectionUChars;
3633             IntBuffer fromUTableValues, fromUSectionValues;
3634
3635             int value, matchValue;
3636             int i, j, index, length, matchLength;
3637             char c;
3638
3639             if (cx == null) {
3640                 return 0; /* no extension data, no match */
3641             }
3642
3643             /* trie lookup of firstCP */
3644             index = firstCP >>> 10; /* stage 1 index */
3645             if (index >= cx.asIntBuffer().get(EXT_FROM_U_STAGE_1_LENGTH)) {
3646                 return 0; /* the first code point is outside the trie */
3647             }
3648
3649             stage12 = (CharBuffer) ARRAY(cx, EXT_FROM_U_STAGE_12_INDEX, char.class);
3650             stage3 = (CharBuffer) ARRAY(cx, EXT_FROM_U_STAGE_3_INDEX, char.class);
3651             index = FROM_U(stage12, stage3, index, firstCP);
3652
3653             stage3b = (IntBuffer) ARRAY(cx, EXT_FROM_U_STAGE_3B_INDEX, int.class);
3654             value = stage3b.get(stage3b.position() + index);
3655             if (value == 0) {
3656                 return 0;
3657             }
3658
3659             if (TO_U_IS_PARTIAL(value)) {
3660                 /* partial match, enter the loop below */
3661                 index = FROM_U_GET_PARTIAL_INDEX(value);
3662
3663                 /* initialize */
3664                 fromUTableUChars = (CharBuffer) ARRAY(cx, EXT_FROM_U_UCHARS_INDEX, char.class);
3665                 fromUTableValues = (IntBuffer) ARRAY(cx, EXT_FROM_U_VALUES_INDEX, int.class);
3666
3667                 matchValue = 0;
3668                 i = j = matchLength = 0;
3669
3670                 /* we must not remember fallback matches when not using fallbacks */
3671
3672                 /* match input units until there is a full match or the input is consumed */
3673                 for (;;) {
3674                     /* go to the next section */
3675                     int oldpos = fromUTableUChars.position();
3676                     fromUSectionUChars = ((CharBuffer) fromUTableUChars.position(index)).slice();
3677                     fromUTableUChars.position(oldpos);
3678                     oldpos = fromUTableValues.position();
3679                     fromUSectionValues = ((IntBuffer) fromUTableValues.position(index)).slice();
3680                     fromUTableValues.position(oldpos);
3681
3682                     /* read first pair of the section */
3683                     length = fromUSectionUChars.get();
3684                     value = fromUSectionValues.get();
3685                     if (value != 0 && (FROM_U_IS_ROUNDTRIP(value) || isFromUUseFallback(isUseFallback, firstCP))) {
3686                         /* remember longest match so far */
3687                         matchValue = value;
3688                         matchLength = 2 + i + j;
3689                     }
3690
3691                     /* match pre[] then src[] */
3692                     if (i < preLength) {
3693                         c = preArray[preArrayBegin + i++];
3694                     } else if (source != null && j < source.remaining()) {
3695                         c = source.get(source.position() + j++);
3696                     } else {
3697                         /* all input consumed, partial match */
3698                         if (flush || (length = (i + j)) > MAX_UCHARS) {
3699                             /*
3700                              * end of the entire input stream, stop with the longest match so far or: partial match must
3701                              * not be longer than UCNV_EXT_MAX_UCHARS because it must fit into state buffers
3702                              */
3703                             break;
3704                         } else {
3705                             /* continue with more input next time */
3706                             return -(2 + length);
3707                         }
3708                     }
3709
3710                     /* search for the current UChar */
3711                     index = findFromU(fromUSectionUChars, length, c);
3712                     if (index < 0) {
3713                         /* no match here, stop with the longest match so far */
3714                         break;
3715                     } else {
3716                         value = fromUSectionValues.get(fromUSectionValues.position() + index);
3717                         if (FROM_U_IS_PARTIAL(value)) {
3718                             /* partial match, continue */
3719                             index = FROM_U_GET_PARTIAL_INDEX(value);
3720                         } else {
3721                             if (FROM_U_IS_ROUNDTRIP(value) || isFromUUseFallback(isUseFallback, firstCP)) {
3722                                 /* full match, stop with result */
3723                                 matchValue = value;
3724                                 matchLength = 2 + i + j;
3725                             } else {
3726                                 /* full match on fallback not taken, stop with the longest match so far */
3727                             }
3728                             break;
3729                         }
3730                     }
3731                 }
3732
3733                 if (matchLength == 0) {
3734                     /* no match at all */
3735                     return 0;
3736                 }
3737             } else /* result from firstCP trie lookup */{
3738                 if (FROM_U_IS_ROUNDTRIP(value) || isFromUUseFallback(isUseFallback, firstCP)) {
3739                     /* full match, stop with result */
3740                     matchValue = value;
3741                     matchLength = 2;
3742                 } else {
3743                     /* fallback not taken */
3744                     return 0;
3745                 }
3746             }
3747
3748             if ((matchValue & FROM_U_RESERVED_MASK) != 0) {
3749                 /* do not interpret values with reserved bits used, for forward compatibility */
3750                 return 0;
3751             }
3752
3753             /* return result */
3754             if (matchValue == FROM_U_SUBCHAR1) {
3755                 return 1; /* assert matchLength==2 */
3756             }
3757
3758             pMatchValue[0] = FROM_U_MASK_ROUNDTRIP(matchValue);
3759             return matchLength;
3760         }
3761
3762         private int simpleMatchFromU(int cp, int[] pValue, boolean isUseFallback) {
3763             int[] value = new int[1];
3764             int match; // signed
3765
3766             /* try to match */
3767             match = matchFromU(cp, null, 0, 0, null, value, isUseFallback, true);
3768             if (match >= 2) {
3769                 /* write result for simple, single-character conversion */
3770                 int length;
3771                 boolean isRoundtrip;
3772
3773                 isRoundtrip = FROM_U_IS_ROUNDTRIP(value[0]);
3774                 length = FROM_U_GET_LENGTH(value[0]);
3775                 value[0] = FROM_U_GET_DATA(value[0]);
3776
3777                 if (length <= EXT_FROM_U_MAX_DIRECT_LENGTH) {
3778                     pValue[0] = value[0];
3779                     return isRoundtrip ? length : -length;
3780                     // #if 0 /* not currently used */
3781                     // } else if(length==4) {
3782                     // /* de-serialize a 4-byte result */
3783                     // const uint8_t *result=UCNV_EXT_ARRAY(cx, UCNV_EXT_FROM_U_BYTES_INDEX, uint8_t)+value;
3784                     // *pValue=
3785                     // ((uint32_t)result[0]<<24)|
3786                     // ((uint32_t)result[1]<<16)|
3787                     // ((uint32_t)result[2]<<8)|
3788                     // result[3];
3789                     // return isRoundtrip ? 4 : -4;
3790                     // #endif
3791                 }
3792             }
3793
3794             /*
3795              * return no match because - match>1 && resultLength>4: result too long for simple conversion - match==1: no
3796              * match found, <subchar1> preferred - match==0: no match found in the first place - match<0: partial
3797              * match, not supported for simple conversion (and flush==TRUE)
3798              */
3799             return 0;
3800         }
3801
3802         @SuppressWarnings("fallthrough")
3803         private CoderResult writeFromU(int value, ByteBuffer target, IntBuffer offsets, int srcIndex) {
3804             ByteBuffer cx = sharedData.mbcs.extIndexes;
3805
3806             byte bufferArray[] = new byte[1 + MAX_BYTES];
3807             int bufferArrayIndex = 0;
3808             byte[] resultArray;
3809             int resultArrayIndex;
3810             int length, prevLength;
3811
3812             length = FROM_U_GET_LENGTH(value);
3813             value = FROM_U_GET_DATA(value);
3814
3815             /* output the result */
3816             if (length <= FROM_U_MAX_DIRECT_LENGTH) {
3817                 /*
3818                  * Generate a byte array and then write it below. This is not the fastest possible way, but it should be
3819                  * ok for extension mappings, and it is much simpler. Offset and overflow handling are only done once
3820                  * this way.
3821                  */
3822                 int p = bufferArrayIndex + 1; /* reserve buffer[0] for shiftByte below */
3823                 switch (length) {
3824                 case 3:
3825                     bufferArray[p++] = (byte) (value >>> 16);
3826                 case 2:
3827                     bufferArray[p++] = (byte) (value >>> 8);
3828                 case 1:
3829                     bufferArray[p++] = (byte) value;
3830                 default:
3831                     break; /* will never occur */
3832                 }
3833                 resultArray = bufferArray;
3834                 resultArrayIndex = bufferArrayIndex + 1;
3835             } else {
3836                 byte[] slice = new byte[length];
3837
3838                 ByteBuffer bb = ((ByteBuffer) ARRAY(cx, EXT_FROM_U_BYTES_INDEX, byte.class));
3839                 bb.position(value);
3840                 bb.get(slice, 0, slice.length);
3841
3842                 resultArray = slice;
3843                 resultArrayIndex = 0;
3844             }
3845
3846             /* with correct data we have length>0 */
3847
3848             if ((prevLength = fromUnicodeStatus) != 0) {
3849                 /* handle SI/SO stateful output */
3850                 byte shiftByte;
3851
3852                 if (prevLength > 1 && length == 1) {
3853                     /* change from double-byte mode to single-byte */
3854                     shiftByte = (byte) UConverterConstants.SI;
3855                     fromUnicodeStatus = 1;
3856                 } else if (prevLength == 1 && length > 1) {
3857                     /* change from single-byte mode to double-byte */
3858                     shiftByte = (byte) UConverterConstants.SO;
3859                     fromUnicodeStatus = 2;
3860                 } else {
3861                     shiftByte = 0;
3862                 }
3863
3864                 if (shiftByte != 0) {
3865                     /* prepend the shift byte to the result bytes */
3866                     bufferArray[0] = shiftByte;
3867                     if (resultArray != bufferArray || resultArrayIndex != bufferArrayIndex + 1) {
3868                         System.arraycopy(resultArray, resultArrayIndex, bufferArray, bufferArrayIndex + 1, length);
3869                     }
3870                     resultArray = bufferArray;
3871                     resultArrayIndex = bufferArrayIndex;
3872                     ++length;
3873                 }
3874             }
3875
3876             return fromUWriteBytes(this, resultArray, resultArrayIndex, length, target, offsets, srcIndex);
3877         }
3878
3879         /*
3880          * @return if(U_FAILURE) return the code point for cnv->fromUChar32 else return 0 after output has been written
3881          * to the target
3882          */
3883         private int fromU(int cp_, CharBuffer source, ByteBuffer target, IntBuffer offsets, int sourceIndex,
3884                 int length, boolean flush, CoderResult[] cr) {
3885             // ByteBuffer cx;
3886             long cp = cp_ & UConverterConstants.UNSIGNED_INT_MASK;
3887
3888             useSubChar1 = false;
3889
3890             if (sharedData.mbcs.extIndexes != null
3891                     && initialMatchFromU((int) cp, source, target, offsets, sourceIndex, flush, cr)) {
3892                 return 0; /* an extension mapping handled the input */
3893             }
3894
3895             /* GB 18030 */
3896             if ((options & MBCS_OPTION_GB18030) != 0) {
3897                 long[] range;
3898                 int i;
3899
3900                 for (i = 0; i < gb18030Ranges.length; ++i) {
3901                     range = gb18030Ranges[i];
3902                     if (range[0] <= cp && cp <= range[1]) {
3903                         /* found the Unicode code point, output the four-byte sequence for it */
3904                         long linear;
3905                         byte bytes[] = new byte[4];
3906
3907                         /* get the linear value of the first GB 18030 code in this range */
3908                         linear = range[2] - LINEAR_18030_BASE;
3909
3910                         /* add the offset from the beginning of the range */
3911                         linear += (cp - range[0]);
3912
3913                         bytes[3] = (byte) (0x30 + linear % 10);
3914                         linear /= 10;
3915                         bytes[2] = (byte) (0x81 + linear % 126);
3916                         linear /= 126;
3917                         bytes[1] = (byte) (0x30 + linear % 10);
3918                         linear /= 10;
3919                         bytes[0] = (byte) (0x81 + linear);
3920
3921                         /* output this sequence */
3922                         cr[0] = fromUWriteBytes(this, bytes, 0, 4, target, offsets, sourceIndex);
3923                         return 0;
3924                     }
3925                 }
3926             }
3927
3928             /* no mapping */
3929             cr[0] = CoderResult.unmappableForLength(length);
3930             return (int) cp;
3931         }
3932
3933         /*
3934          * target<targetLimit; set error code for overflow
3935          */
3936         private boolean initialMatchFromU(int cp, CharBuffer source, ByteBuffer target, IntBuffer offsets,
3937                 int srcIndex, boolean flush, CoderResult[] cr) {
3938             int[] value = new int[1];
3939             int match;
3940
3941             /* try to match */
3942             match = matchFromU(cp, null, 0, 0, source, value, useFallback, flush);
3943
3944             /* reject a match if the result is a single byte for DBCS-only */
3945             if (match >= 2
3946                     && !(FROM_U_GET_LENGTH(value[0]) == 1 && sharedData.mbcs.outputType == MBCS_OUTPUT_DBCS_ONLY)) {
3947                 /* advance src pointer for the consumed input */
3948                 source.position(source.position() + match - 2); /* remove 2 for the initial code point */
3949
3950                 /* write result to target */
3951                 cr[0] = writeFromU(value[0], target, offsets, srcIndex);
3952                 return true;
3953             } else if (match < 0) {
3954                 /* save state for partial match */
3955                 int sArrayIndex;
3956                 int j;
3957
3958                 /* copy the first code point */
3959                 preFromUFirstCP = cp;
3960
3961                 /* now copy the newly consumed input */
3962                 sArrayIndex = source.position();
3963                 match = -match - 2; /* remove 2 for the initial code point */
3964                 for (j = 0; j < match; ++j) {
3965                     preFromUArray[j] = source.get(sArrayIndex++);
3966                 }
3967                 source.position(sArrayIndex); /* same as *src=srcLimit; because we reached the end of input */
3968                 preFromULength = (byte) match;
3969                 return true;
3970             } else if (match == 1) {
3971                 /* matched, no mapping but request for <subchar1> */
3972                 useSubChar1 = true;
3973                 return false;
3974             } else /* match==0 no match */{
3975                 return false;
3976             }
3977         }
3978         
3979         CoderResult cnvMBCSFromUnicodeWithOffsets(CharBuffer source, ByteBuffer target, IntBuffer offsets, boolean flush) {
3980             // Just call encodeLoop to remove duplicate code.
3981             return encodeLoop(source, target, offsets, flush);
3982         }
3983
3984         /*
3985          * This version of ucnv_MBCSFromUnicode() is optimized for single-byte codepages that map only to and from the
3986          * BMP. In addition to single-byte/state optimizations, the offset calculations become much easier.
3987          */
3988         private CoderResult cnvMBCSSingleFromBMPWithOffsets(CharBuffer source, ByteBuffer target, IntBuffer offsets,
3989                 boolean flush) {
3990
3991             CoderResult[] cr = { CoderResult.UNDERFLOW };
3992
3993             int sourceArrayIndex, lastSource;
3994             int targetCapacity, length;
3995             char[] table;
3996             byte[] results;
3997
3998             int c, sourceIndex;
3999             char value, minValue;
4000
4001             /* set up the local pointers */
4002             sourceArrayIndex = source.position();
4003             targetCapacity = target.remaining();
4004             table = sharedData.mbcs.fromUnicodeTable;
4005
4006             if ((options & UConverterConstants.OPTION_SWAP_LFNL) != 0) {
4007                 results = sharedData.mbcs.swapLFNLFromUnicodeBytes; // agljport:comment should swapLFNLFromUnicodeBytes
4008                 // be a ByteBuffer so results can be a 16-bit view
4009                 // of it?
4010             } else {
4011                 results = sharedData.mbcs.fromUnicodeBytes; // agljport:comment should swapLFNLFromUnicodeBytes be a
4012                 // ByteBuffer so results can be a 16-bit view of it?
4013             }
4014
4015             if (useFallback) {
4016                 /* use all roundtrip and fallback results */
4017                 minValue = 0x800;
4018             } else {
4019                 /* use only roundtrips and fallbacks from private-use characters */
4020                 minValue = 0xc00;
4021             }
4022
4023             /* get the converter state from UConverter */
4024             c = fromUChar32;
4025
4026             /* sourceIndex=-1 if the current character began in the previous buffer */
4027             sourceIndex = c == 0 ? 0 : -1;
4028             lastSource = sourceArrayIndex;
4029
4030             /*
4031              * since the conversion here is 1:1 UChar:uint8_t, we need only one counter for the minimum of the
4032              * sourceLength and targetCapacity
4033              */
4034             length = source.limit() - sourceArrayIndex;
4035             if (length < targetCapacity) {
4036                 targetCapacity = length;
4037             }
4038
4039             boolean doloop = true;
4040             if (c != 0 && targetCapacity > 0) {
4041                 SideEffectsSingleBMP x = new SideEffectsSingleBMP(c, sourceArrayIndex);
4042                 doloop = getTrailSingleBMP(source, x, cr);
4043                 c = x.c;
4044                 sourceArrayIndex = x.sourceArrayIndex;
4045             }
4046
4047             if (doloop) {
4048                 while (targetCapacity > 0) {
4049                     /*
4050                      * Get a correct Unicode code point: a single UChar for a BMP code point or a matched surrogate pair
4051                      * for a "supplementary code point".
4052                      */
4053                     c = source.get(sourceArrayIndex++);
4054                     /*
4055                      * Do not immediately check for single surrogates: Assume that they are unassigned and check for
4056                      * them in that case. This speeds up the conversion of assigned characters.
4057                      */
4058                     /* convert the Unicode code point in c into codepage bytes */
4059                     value = MBCS_SINGLE_RESULT_FROM_U(table, results, c);
4060
4061                     /* is this code point assigned, or do we use fallbacks? */
4062                     if (value >= minValue) {
4063                         /* assigned, write the output character bytes from value and length */
4064                         /* length==1 */
4065                         /* this is easy because we know that there is enough space */
4066                         target.put((byte) value);
4067                         --targetCapacity;
4068
4069                         /* normal end of conversion: prepare for a new character */
4070                         c = 0;
4071                         continue;
4072                     } else if (!UTF16.isSurrogate((char) c)) {
4073                         /* normal, unassigned BMP character */
4074                     } else if (UTF16.isLeadSurrogate((char) c)) {
4075                         // getTrail:
4076                         SideEffectsSingleBMP x = new SideEffectsSingleBMP(c, sourceArrayIndex);
4077                         doloop = getTrailSingleBMP(source, x, cr);
4078                         c = x.c;
4079                         sourceArrayIndex = x.sourceArrayIndex;
4080                         if (!doloop)
4081                             break;
4082                     } else {
4083                         /* this is an unmatched trail code unit (2nd surrogate) */
4084                         /* callback(illegal) */
4085                         cr[0] = CoderResult.malformedForLength(1);
4086                         break;
4087                     }
4088
4089                     /* c does not have a mapping */
4090
4091                     /* get the number of code units for c to correctly advance sourceIndex */
4092                     length = UTF16.getCharCount(c);
4093
4094                     /* set offsets since the start or the last extension */
4095                     if (offsets != null) {
4096                         int count = sourceArrayIndex - lastSource;
4097
4098                         /* do not set the offset for this character */
4099                         count -= length;
4100
4101                         while (count > 0) {
4102                             offsets.put(sourceIndex++);
4103                             --count;
4104                         }
4105                         /* offsets and sourceIndex are now set for the current character */
4106                     }
4107
4108                     /* try an extension mapping */
4109                     lastSource = sourceArrayIndex;
4110                     source.position(sourceArrayIndex);
4111                     c = fromU(c, source, target, offsets, sourceIndex, length, flush, cr);
4112                     sourceArrayIndex = source.position();
4113                     sourceIndex += length + (sourceArrayIndex - lastSource);
4114                     lastSource = sourceArrayIndex;
4115
4116                     if (cr[0].isError()) {
4117                         /* not mappable or buffer overflow */
4118                         break;
4119                     } else {
4120                         /* a mapping was written to the target, continue */
4121
4122                         /* recalculate the targetCapacity after an extension mapping */
4123                         targetCapacity = target.remaining();
4124                         length = source.limit() - sourceArrayIndex;
4125                         if (length < targetCapacity) {
4126                             targetCapacity = length;
4127                         }
4128                     }
4129                 }
4130             }
4131
4132             if (sourceArrayIndex < source.limit() && !target.hasRemaining()) {
4133                 /* target is full */
4134                 cr[0] = CoderResult.OVERFLOW;
4135             }
4136
4137             /* set offsets since the start or the last callback */
4138             if (offsets != null) {
4139                 int count = sourceArrayIndex - lastSource;
4140                 while (count > 0) {
4141                     offsets.put(sourceIndex++);
4142                     --count;
4143                 }
4144             }
4145
4146             /* set the converter state back into UConverter */
4147             fromUChar32 = c;
4148
4149             /* write back the updated pointers */
4150             source.position(sourceArrayIndex);
4151
4152             return cr[0];
4153         }
4154
4155         /* This version of ucnv_MBCSFromUnicodeWithOffsets() is optimized for single-byte codepages. */
4156         private CoderResult cnvMBCSSingleFromUnicodeWithOffsets(CharBuffer source, ByteBuffer target,
4157                 IntBuffer offsets, boolean flush) {
4158
4159             CoderResult[] cr = { CoderResult.UNDERFLOW };
4160
4161             int sourceArrayIndex;
4162
4163             char[] table;
4164             byte[] results; // agljport:comment results is used to to get 16-bit values out of byte[] array
4165
4166             int c;
4167             int sourceIndex, nextSourceIndex;
4168
4169             char value, minValue;
4170
4171             /* set up the local pointers */
4172             short uniMask;
4173             sourceArrayIndex = source.position();
4174
4175             table = sharedData.mbcs.fromUnicodeTable;
4176
4177             if ((options & UConverterConstants.OPTION_SWAP_LFNL) != 0) {
4178                 results = sharedData.mbcs.swapLFNLFromUnicodeBytes; // agljport:comment should swapLFNLFromUnicodeBytes
4179                 // be a ByteBuffer so results can be a 16-bit view
4180                 // of it?
4181             } else {
4182                 results = sharedData.mbcs.fromUnicodeBytes; // agljport:comment should swapLFNLFromUnicodeBytes be a
4183                 // ByteBuffer so results can be a 16-bit view of it?
4184             }
4185
4186             if (useFallback) {
4187                 /* use all roundtrip and fallback results */
4188                 minValue = 0x800;
4189             } else {
4190                 /* use only roundtrips and fallbacks from private-use characters */
4191                 minValue = 0xc00;
4192             }
4193             // agljport:comment hasSupplementary only used in getTrail block which now simply repeats the mask operation
4194             uniMask = sharedData.mbcs.unicodeMask;
4195
4196             /* get the converter state from UConverter */
4197             c = fromUChar32;
4198
4199             /* sourceIndex=-1 if the current character began in the previous buffer */
4200             sourceIndex = c == 0 ? 0 : -1;
4201             nextSourceIndex = 0;
4202
4203             boolean doloop = true;
4204             boolean doread = true;
4205             if (c != 0 && target.hasRemaining()) {
4206                 if (UTF16.isLeadSurrogate((char) c)) {
4207                     SideEffectsDouble x = new SideEffectsDouble(c, sourceArrayIndex, sourceIndex, nextSourceIndex);
4208                     doloop = getTrailDouble(source, target, uniMask, x, flush, cr);
4209                     doread = x.doread;
4210                     c = x.c;
4211                     sourceArrayIndex = x.sourceArrayIndex;
4212                     sourceIndex = x.sourceIndex;
4213                     nextSourceIndex = x.nextSourceIndex;
4214                 } else {
4215                     doread = false;
4216                 }
4217             }
4218
4219             if (doloop) {
4220                 while (!doread || sourceArrayIndex < source.limit()) {
4221                     /*
4222                      * This following test is to see if available input would overflow the output. It does not catch
4223                      * output of more than one byte that overflows as a result of a multi-byte character or callback
4224                      * output from the last source character. Therefore, those situations also test for overflows and
4225                      * will then break the loop, too.
4226                      */
4227                     if (target.hasRemaining()) {
4228                         /*
4229                          * Get a correct Unicode code point: a single UChar for a BMP code point or a matched surrogate
4230                          * pair for a "supplementary code point".
4231                          */
4232
4233                         if (doread) {
4234                             c = source.get(sourceArrayIndex++);
4235                             ++nextSourceIndex;
4236                             if (UTF16.isSurrogate((char) c)) {
4237                                 if (UTF16.isLeadSurrogate((char) c)) {
4238                                     // getTrail:
4239                                     SideEffectsDouble x = new SideEffectsDouble(c, sourceArrayIndex, sourceIndex,
4240                                             nextSourceIndex);
4241                                     doloop = getTrailDouble(source, target, uniMask, x, flush, cr);
4242                                     c = x.c;
4243                                     sourceArrayIndex = x.sourceArrayIndex;
4244                                     sourceIndex = x.sourceIndex;
4245                                     nextSourceIndex = x.nextSourceIndex;
4246                                     if (x.doread) {
4247                                         if (doloop)
4248                                             continue;
4249                                         else
4250                                             break;
4251                                     }
4252                                 } else {
4253                                     /* this is an unmatched trail code unit (2nd surrogate) */
4254                                     /* callback(illegal) */
4255                                     cr[0] = CoderResult.malformedForLength(1);
4256                                     break;
4257                                 }
4258                             }
4259                         } else {
4260                             doread = true;
4261                         }
4262
4263                         /* convert the Unicode code point in c into codepage bytes */
4264                         value = MBCS_SINGLE_RESULT_FROM_U(table, results, c);
4265
4266                         /* is this code point assigned, or do we use fallbacks? */
4267                         if (value >= minValue) {
4268                             /* assigned, write the output character bytes from value and length */
4269                             /* length==1 */
4270                             /* this is easy because we know that there is enough space */
4271                             target.put((byte) value);
4272                             if (offsets != null) {
4273                                 offsets.put(sourceIndex);
4274                             }
4275
4276                             /* normal end of conversion: prepare for a new character */
4277                             c = 0;
4278                             sourceIndex = nextSourceIndex;
4279                         } else { /* unassigned */
4280                             /* try an extension mapping */
4281                             SideEffectsDouble x = new SideEffectsDouble(c, sourceArrayIndex, sourceIndex,
4282                                     nextSourceIndex);
4283                             doloop = unassignedDouble(source, target, x, flush, cr);
4284                             c = x.c;
4285                             sourceArrayIndex = x.sourceArrayIndex;
4286                             sourceIndex = x.sourceIndex;
4287                             nextSourceIndex = x.nextSourceIndex;
4288                             if (!doloop)
4289                                 break;
4290                         }
4291                     } else {
4292                         /* target is full */
4293                         cr[0] = CoderResult.OVERFLOW;
4294                         break;
4295                     }
4296                 }
4297             }
4298
4299             /* set the converter state back into UConverter */
4300             fromUChar32 = c;
4301
4302             /* write back the updated pointers */
4303             source.position(sourceArrayIndex);
4304
4305             return cr[0];
4306         }
4307
4308         /* This version of ucnv_MBCSFromUnicodeWithOffsets() is optimized for double-byte codepages. */
4309         private CoderResult cnvMBCSDoubleFromUnicodeWithOffsets(CharBuffer source, ByteBuffer target,
4310                 IntBuffer offsets, boolean flush) {
4311             CoderResult[] cr = { CoderResult.UNDERFLOW };
4312
4313             int sourceArrayIndex;
4314
4315             char[] table;
4316             byte[] bytes;
4317
4318             int c, sourceIndex, nextSourceIndex;
4319
4320             int stage2Entry;
4321             int value;
4322             int length;
4323             short uniMask;
4324
4325             /* use optimized function if possible */
4326             uniMask = sharedData.mbcs.unicodeMask;
4327
4328             /* set up the local pointers */
4329             sourceArrayIndex = source.position();
4330
4331             table = sharedData.mbcs.fromUnicodeTable;
4332
4333             if ((options & UConverterConstants.OPTION_SWAP_LFNL) != 0) {
4334                 bytes = sharedData.mbcs.swapLFNLFromUnicodeBytes;
4335             } else {
4336                 bytes = sharedData.mbcs.fromUnicodeBytes;
4337             }
4338
4339             /* get the converter state from UConverter */
4340             c = fromUChar32;
4341
4342             /* sourceIndex=-1 if the current character began in the previous buffer */
4343             sourceIndex = c == 0 ? 0 : -1;
4344             nextSourceIndex = 0;
4345
4346             /* conversion loop */
4347             boolean doloop = true;
4348             boolean doread = true;
4349             if (c != 0 && target.hasRemaining()) {
4350                 if (UTF16.isLeadSurrogate((char) c)) {
4351                     SideEffectsDouble x = new SideEffectsDouble(c, sourceArrayIndex, sourceIndex, nextSourceIndex);
4352                     doloop = getTrailDouble(source, target, uniMask, x, flush, cr);
4353                     doread = x.doread;
4354                     c = x.c;
4355                     sourceArrayIndex = x.sourceArrayIndex;
4356                     sourceIndex = x.sourceIndex;
4357                     nextSourceIndex = x.nextSourceIndex;
4358                 } else {
4359                     doread = false;
4360                 }
4361             }
4362
4363             if (doloop) {
4364                 while (!doread || sourceArrayIndex < source.limit()) {
4365                     /*
4366                      * This following test is to see if available input would overflow the output. It does not catch
4367                      * output of more than one byte that overflows as a result of a multi-byte character or callback
4368                      * output from the last source character. Therefore, those situations also test for overflows and
4369                      * will then break the loop, too.
4370                      */
4371                     if (target.hasRemaining()) {
4372                         if (doread) {
4373                             /*
4374                              * Get a correct Unicode code point: a single UChar for a BMP code point or a matched
4375                              * surrogate pair for a "supplementary code point".
4376                              */
4377                             c = source.get(sourceArrayIndex++);
4378                             ++nextSourceIndex;
4379                             /*
4380                              * This also tests if the codepage maps single surrogates. If it does, then surrogates are
4381                              * not paired but mapped separately. Note that in this case unmatched surrogates are not
4382                              * detected.
4383                              */
4384                             if (UTF16.isSurrogate((char) c) && (uniMask & UConverterConstants.HAS_SURROGATES) == 0) {
4385                                 if (UTF16.isLeadSurrogate((char) c)) {
4386                                     // getTrail:
4387                                     SideEffectsDouble x = new SideEffectsDouble(c, sourceArrayIndex, sourceIndex,
4388                                             nextSourceIndex);
4389                                     doloop = getTrailDouble(source, target, uniMask, x, flush, cr);
4390                                     c = x.c;
4391                                     sourceArrayIndex = x.sourceArrayIndex;
4392                                     sourceIndex = x.sourceIndex;
4393                                     nextSourceIndex = x.nextSourceIndex;
4394
4395                                     if (x.doread) {
4396                                         if (doloop)
4397                                             continue;
4398                                         else
4399                                             break;
4400                                     }
4401                                 } else {
4402                                     /* this is an unmatched trail code unit (2nd surrogate) */
4403                                     /* callback(illegal) */
4404                                     cr[0] = CoderResult.malformedForLength(1);
4405                                     break;
4406                                 }
4407                             }
4408                         } else {
4409                             doread = true;
4410                         }
4411
4412                         /* convert the Unicode code point in c into codepage bytes */
4413                         stage2Entry = MBCS_STAGE_2_FROM_U(table, c);
4414
4415                         /* get the bytes and the length for the output */
4416                         /* MBCS_OUTPUT_2 */
4417                         value = MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, c);
4418                         if ((value & UConverterConstants.UNSIGNED_INT_MASK) <= 0xff) {
4419                             length = 1;
4420                         } else {
4421                             length = 2;
4422                         }
4423
4424                         /* is this code point assigned, or do we use fallbacks? */
4425                         if (!(MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, c) || (isFromUUseFallback(c) && value != 0))) {
4426                             /*
4427                              * We allow a 0 byte output if the "assigned" bit is set for this entry. There is no way
4428                              * with this data structure for fallback output to be a zero byte.
4429                              */
4430
4431                             // unassigned:
4432                             SideEffectsDouble x = new SideEffectsDouble(c, sourceArrayIndex, sourceIndex,
4433                                     nextSourceIndex);
4434
4435                             doloop = unassignedDouble(source, target, x, flush, cr);
4436                             c = x.c;
4437                             sourceArrayIndex = x.sourceArrayIndex;
4438                             sourceIndex = x.sourceIndex;
4439                             nextSourceIndex = x.nextSourceIndex;
4440                             if (doloop)
4441                                 continue;
4442                             else
4443                                 break;
4444                         }
4445
4446                         /* write the output character bytes from value and length */
4447                         /* from the first if in the loop we know that targetCapacity>0 */
4448                         if (length == 1) {
4449                             /* this is easy because we know that there is enough space */
4450                             target.put((byte) value);
4451                             if (offsets != null) {
4452                                 offsets.put(sourceIndex);
4453                             }
4454                         } else /* length==2 */{
4455                             target.put((byte) (value >>> 8));
4456                             if (2 <= target.remaining()) {
4457                                 target.put((byte) value);
4458                                 if (offsets != null) {
4459                                     offsets.put(sourceIndex);
4460                                     offsets.put(sourceIndex);
4461                                 }
4462                             } else {
4463                                 if (offsets != null) {
4464                                     offsets.put(sourceIndex);
4465                                 }
4466                                 errorBuffer[0] = (byte) value;
4467                                 errorBufferLength = 1;
4468
4469                                 /* target overflow */
4470                                 cr[0] = CoderResult.OVERFLOW;
4471                                 c = 0;
4472                                 break;
4473                             }
4474                         }
4475
4476                         /* normal end of conversion: prepare for a new character */
4477                         c = 0;
4478                         sourceIndex = nextSourceIndex;
4479                         continue;
4480                     } else {
4481                         /* target is full */
4482                         cr[0] = CoderResult.OVERFLOW;
4483                         break;
4484                     }
4485                 }
4486             }
4487
4488             /* set the converter state back into UConverter */
4489             fromUChar32 = c;
4490
4491             /* write back the updated pointers */
4492             source.position(sourceArrayIndex);
4493
4494             return cr[0];
4495         }
4496
4497         private final class SideEffectsSingleBMP {
4498             int c, sourceArrayIndex;
4499
4500             SideEffectsSingleBMP(int c_, int sourceArrayIndex_) {
4501                 c = c_;
4502                 sourceArrayIndex = sourceArrayIndex_;
4503             }
4504         }
4505
4506         // function made out of block labeled getTrail in ucnv_MBCSSingleFromUnicodeWithOffsets
4507         // assumes input c is lead surrogate
4508         private final boolean getTrailSingleBMP(CharBuffer source, SideEffectsSingleBMP x, CoderResult[] cr) {
4509             if (x.sourceArrayIndex < source.limit()) {
4510                 /* test the following code unit */
4511                 char trail = source.get(x.sourceArrayIndex);
4512                 if (UTF16.isTrailSurrogate(trail)) {
4513                     ++x.sourceArrayIndex;
4514                     x.c = UCharacter.getCodePoint((char) x.c, trail);
4515                     /* this codepage does not map supplementary code points */
4516                     /* callback(unassigned) */
4517                     cr[0] = CoderResult.unmappableForLength(2);
4518                     return false;
4519                 } else {
4520                     /* this is an unmatched lead code unit (1st surrogate) */
4521                     /* callback(illegal) */
4522                     cr[0] = CoderResult.malformedForLength(1);
4523                     return false;
4524                 }
4525             } else {
4526                 /* no more input */
4527                 return false;
4528             }
4529             // return true;
4530         }
4531
4532         private final class SideEffects {
4533             int c, sourceArrayIndex, sourceIndex, nextSourceIndex, prevSourceIndex, prevLength;
4534             boolean doread = true;
4535
4536             SideEffects(int c_, int sourceArrayIndex_, int sourceIndex_, int nextSourceIndex_, int prevSourceIndex_,
4537                     int prevLength_) {
4538                 c = c_;
4539                 sourceArrayIndex = sourceArrayIndex_;
4540                 sourceIndex = sourceIndex_;
4541                 nextSourceIndex = nextSourceIndex_;
4542                 prevSourceIndex = prevSourceIndex_;
4543                 prevLength = prevLength_;
4544             }
4545         }
4546
4547         // function made out of block labeled getTrail in ucnv_MBCSFromUnicodeWithOffsets
4548         // assumes input c is lead surrogate
4549         private final boolean getTrail(CharBuffer source, ByteBuffer target, int uniMask, SideEffects x,
4550                 boolean flush, CoderResult[] cr) {
4551             if (x.sourceArrayIndex < source.limit()) {
4552                 /* test the following code unit */
4553                 char trail = source.get(x.sourceArrayIndex);
4554                 if (UTF16.isTrailSurrogate(trail)) {
4555                     ++x.sourceArrayIndex;
4556                     ++x.nextSourceIndex;
4557                     /* convert this supplementary code point */
4558                     x.c = UCharacter.getCodePoint((char) x.c, trail);
4559                     if ((uniMask & UConverterConstants.HAS_SUPPLEMENTARY) == 0) {
4560                         /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
4561                         fromUnicodeStatus = x.prevLength; /* save the old state */
4562                         /* callback(unassigned) */
4563                         x.doread = true;
4564                         return unassigned(source, target, null, x, flush, cr);
4565                     } else {
4566                         x.doread = false;
4567                         return true;
4568                     }
4569                 } else {
4570                     /* this is an unmatched lead code unit (1st surrogate) */
4571                     /* callback(illegal) */
4572                     cr[0] = CoderResult.malformedForLength(1);
4573                     return false;
4574                 }
4575             } else {
4576                 /* no more input */
4577                 return false;
4578             }
4579         }
4580
4581         // function made out of block labeled unassigned in ucnv_MBCSFromUnicodeWithOffsets
4582         private final boolean unassigned(CharBuffer source, ByteBuffer target, IntBuffer offsets, SideEffects x,
4583                 boolean flush, CoderResult[] cr) {
4584             /* try an extension mapping */
4585             int sourceBegin = x.sourceArrayIndex;
4586             source.position(x.sourceArrayIndex);
4587             x.c = fromU(x.c, source, target, null, x.sourceIndex, x.nextSourceIndex, flush, cr);
4588             x.sourceArrayIndex = source.position();
4589             x.nextSourceIndex += x.sourceArrayIndex - sourceBegin;
4590             x.prevLength = fromUnicodeStatus;
4591
4592             if (cr[0].isError()) {
4593                 /* not mappable or buffer overflow */
4594                 return false;
4595             } else {
4596                 /* a mapping was written to the target, continue */
4597
4598                 /* recalculate the targetCapacity after an extension mapping */
4599                 // x.targetCapacity=pArgs.targetLimit-x.targetArrayIndex;
4600                 /* normal end of conversion: prepare for a new character */
4601                 if (offsets != null) {
4602                     x.prevSourceIndex = x.sourceIndex;
4603                     x.sourceIndex = x.nextSourceIndex;
4604                 }
4605                 return true;
4606             }
4607         }
4608
4609         private final class SideEffectsDouble {
4610             int c, sourceArrayIndex, sourceIndex, nextSourceIndex;
4611             boolean doread = true;
4612
4613             SideEffectsDouble(int c_, int sourceArrayIndex_, int sourceIndex_, int nextSourceIndex_) {
4614                 c = c_;
4615                 sourceArrayIndex = sourceArrayIndex_;
4616                 sourceIndex = sourceIndex_;
4617                 nextSourceIndex = nextSourceIndex_;
4618             }
4619         }
4620
4621         // function made out of block labeled getTrail in ucnv_MBCSDoubleFromUnicodeWithOffsets
4622         // assumes input c is lead surrogate
4623         private final boolean getTrailDouble(CharBuffer source, ByteBuffer target, int uniMask,
4624                 SideEffectsDouble x, boolean flush, CoderResult[] cr) {
4625             if (x.sourceArrayIndex < source.limit()) {
4626                 /* test the following code unit */
4627                 char trail = source.get(x.sourceArrayIndex);
4628                 if (UTF16.isTrailSurrogate(trail)) {
4629                     ++x.sourceArrayIndex;
4630                     ++x.nextSourceIndex;
4631                     /* convert this supplementary code point */
4632                     x.c = UCharacter.getCodePoint((char) x.c, trail);
4633                     if ((uniMask & UConverterConstants.HAS_SUPPLEMENTARY) == 0) {
4634                         /* BMP-only codepages are stored without stage 1 entries for supplementary code points */
4635                         /* callback(unassigned) */
4636                         x.doread = true;
4637                         return unassignedDouble(source, target, x, flush, cr);
4638                     } else {
4639                         x.doread = false;
4640                         return true;
4641                     }
4642                 } else {
4643                     /* this is an unmatched lead code unit (1st surrogate) */
4644                     /* callback(illegal) */
4645                     cr[0] = CoderResult.malformedForLength(1);
4646                     return false;
4647                 }
4648             } else {
4649                 /* no more input */
4650                 return false;
4651             }
4652         }
4653
4654         // function made out of block labeled unassigned in ucnv_MBCSDoubleFromUnicodeWithOffsets
4655         private final boolean unassignedDouble(CharBuffer source, ByteBuffer target, SideEffectsDouble x,
4656                 boolean flush, CoderResult[] cr) {
4657             /* try an extension mapping */
4658             int sourceBegin = x.sourceArrayIndex;
4659             source.position(x.sourceArrayIndex);
4660             x.c = fromU(x.c, source, target, null, x.sourceIndex, x.nextSourceIndex, flush, cr);
4661             x.sourceArrayIndex = source.position();
4662             x.nextSourceIndex += x.sourceArrayIndex - sourceBegin;
4663
4664             if (cr[0].isError()) {
4665                 /* not mappable or buffer overflow */
4666                 return false;
4667             } else {
4668                 /* a mapping was written to the target, continue */
4669
4670                 /* recalculate the targetCapacity after an extension mapping */
4671                 // x.targetCapacity=pArgs.targetLimit-x.targetArrayIndex;
4672                 /* normal end of conversion: prepare for a new character */
4673                 x.sourceIndex = x.nextSourceIndex;
4674                 return true;
4675             }
4676         }
4677
4678         /**
4679          * Overrides super class method
4680          * 
4681          * @param encoder
4682          * @param source
4683          * @param target
4684          * @param offsets
4685          * @return
4686          */
4687         protected CoderResult cbFromUWriteSub(CharsetEncoderICU encoder, CharBuffer source, ByteBuffer target,
4688                 IntBuffer offsets) {
4689             CharsetMBCS cs = (CharsetMBCS) encoder.charset();
4690             byte[] subchar;
4691             int length;
4692
4693             if (cs.subChar1 != 0
4694                     && (cs.sharedData.mbcs.extIndexes != null ? encoder.useSubChar1
4695                             : (encoder.invalidUCharBuffer[0] <= 0xff))) {
4696                 /*
4697                  * select subChar1 if it is set (not 0) and the unmappable Unicode code point is up to U+00ff (IBM MBCS
4698                  * behavior)
4699                  */
4700                 subchar = new byte[] { cs.subChar1 };
4701                 length = 1;
4702             } else {
4703                 /* select subChar in all other cases */
4704                 subchar = cs.subChar;
4705                 length = cs.subCharLen;
4706             }
4707
4708             /* reset the selector for the next code point */
4709             encoder.useSubChar1 = false;
4710
4711             if (cs.sharedData.mbcs.outputType == MBCS_OUTPUT_2_SISO) {
4712                 byte[] buffer = new byte[4];
4713                 int i = 0;
4714
4715                 /* fromUnicodeStatus contains prevLength */
4716                 switch (length) {
4717                 case 1:
4718                     if (encoder.fromUnicodeStatus == 2) {
4719                         /* DBCS mode and SBCS sub char: change to SBCS */
4720                         encoder.fromUnicodeStatus = 1;
4721                         buffer[i++] = UConverterConstants.SI;
4722                     }
4723                     buffer[i++] = subchar[0];
4724                     break;
4725                 case 2:
4726                     if (encoder.fromUnicodeStatus <= 1) {
4727                         /* SBCS mode and DBCS sub char: change to DBCS */
4728                         encoder.fromUnicodeStatus = 2;
4729                         buffer[i++] = UConverterConstants.SO;
4730                     }
4731                     buffer[i++] = subchar[0];
4732                     buffer[i++] = subchar[1];
4733                     break;
4734                 default:
4735                     throw new IllegalArgumentException();
4736                 }
4737
4738                 subchar = buffer;
4739                 length = i;
4740             }
4741             return CharsetEncoderICU.fromUWriteBytes(encoder, subchar, 0, length, target, offsets, source.position());
4742         }
4743
4744         /**
4745          * Gets called whenever CharsetEncoder.replaceWith gets called. allowReplacementChanges only allows subChar and
4746          * subChar1 to be modified outside construction (since replaceWith is called once during construction).
4747          * 
4748          * @param replacement
4749          *            The replacement for subchar.
4750          */
4751         protected void implReplaceWith(byte[] replacement) {
4752             if (allowReplacementChanges) {
4753                 CharsetMBCS cs = (CharsetMBCS) this.charset();
4754
4755                 System.arraycopy(replacement, 0, cs.subChar, 0, replacement.length);
4756                 cs.subCharLen = (byte) replacement.length;
4757                 cs.subChar1 = 0;
4758             }
4759         }
4760     }
4761
4762     public CharsetDecoder newDecoder() {
4763         return new CharsetDecoderMBCS(this);
4764     }
4765
4766     public CharsetEncoder newEncoder() {
4767         return new CharsetEncoderMBCS(this);
4768     }
4769
4770     @SuppressWarnings("fallthrough")
4771     void MBCSGetFilteredUnicodeSetForUnicode(UConverterSharedData data, UnicodeSet setFillIn, int which, int filter){
4772         UConverterMBCSTable mbcsTable;
4773         char[] table;
4774         char st1,maxStage1, st2;
4775         int st3;
4776         int c ;
4777         
4778         mbcsTable = data.mbcs;
4779         table = mbcsTable.fromUnicodeTable; 
4780         if((mbcsTable.unicodeMask & UConverterConstants.HAS_SUPPLEMENTARY)!=0){
4781             maxStage1 = 0x440;
4782         }
4783         else{
4784             maxStage1 = 0x40;
4785         }
4786         c=0; /* keep track of current code point while enumerating */
4787         
4788         if(mbcsTable.outputType==MBCS_OUTPUT_1){
4789             char stage2, stage3;
4790             char minValue;
4791             CharBuffer results;
4792             results = ByteBuffer.wrap(mbcsTable.fromUnicodeBytes).asCharBuffer();
4793                                    
4794             if(which==ROUNDTRIP_SET) {
4795                 /* use only roundtrips */
4796                 minValue=0xf00;
4797             } else {
4798                 /* use all roundtrip and fallback results */
4799                 minValue=0x800;
4800             }
4801             for(st1=0;st1<maxStage1;++st1){
4802                 st2 = table[st1];
4803                 if(st2>maxStage1){
4804                     stage2 = st2;
4805                     for(st2=0; st2<64; ++st2){
4806                         st3 = table[stage2 + st2];
4807                         if(st3!=0){
4808                             /*read the stage 3 block */
4809                             stage3 = (char)st3;
4810                             do {
4811                                 if(results.get(stage3++)>=minValue){
4812                                      setFillIn.add(c);
4813                                 }
4814                                
4815                             }while((++c&0xf) !=0);
4816                           } else {
4817                             c+= 16; /*empty stage 2 block */
4818                         }
4819                     }
4820                 } else {
4821                     c+=1024; /* empty stage 2 block */
4822                 }
4823             }
4824         } else {
4825             int stage2,stage3;
4826             byte[] bytes;
4827             int st3Multiplier;
4828             int value;
4829             boolean useFallBack;
4830             bytes = mbcsTable.fromUnicodeBytes;
4831             useFallBack = (which == ROUNDTRIP_AND_FALLBACK_SET);
4832             switch(mbcsTable.outputType) {
4833             case MBCS_OUTPUT_3:
4834             case MBCS_OUTPUT_4_EUC:
4835                 st3Multiplier = 3;
4836                 break;
4837             case MBCS_OUTPUT_4:
4838                 st3Multiplier =4;
4839                 break;
4840             default:
4841                 st3Multiplier =2;
4842                 break;
4843             }
4844             //ByteBuffer buffer = (ByteBuffer)charTobyte(table);
4845             
4846             for(st1=0;st1<maxStage1;++st1){
4847                 st2 = table[st1]; 
4848                 if(st2>(maxStage1>>1)){
4849                     stage2 =  st2 ;
4850                     for(st2=0;st2<128;++st2){
4851                         /*read the stage 3 block */
4852                         st3 = table[stage2*2 + st2]<<16;
4853                         st3+=table[stage2*2 + ++st2];
4854                         if(st3!=0){
4855                         //if((st3=table[stage2+st2])!=0){
4856                             stage3 = st3Multiplier*16*(st3&UConverterConstants.UNSIGNED_SHORT_MASK);
4857                             
4858                             /* get the roundtrip flags for the stage 3 block */
4859                             st3>>=16;
4860                             st3 &= UConverterConstants.UNSIGNED_SHORT_MASK;
4861                             switch(filter) {
4862                             case UCNV_SET_FILTER_NONE:
4863                                 do {
4864                                     
4865                                    if((st3&1)!=0){
4866                                         setFillIn.add(c);
4867                                         stage3+=st3Multiplier;
4868                                    }else if (useFallBack) {
4869                                         
4870                                         char b =0;
4871                                         switch(st3Multiplier) {
4872                                         case 4 :
4873                                            
4874                                             b|= ByteBuffer.wrap(bytes).getChar(stage3++);
4875                                            
4876                                         case 3 :
4877                                             
4878                                             b|= ByteBuffer.wrap(bytes).getChar(stage3++);
4879                                            
4880                                         case 2 :
4881                                            
4882                                             b|= ByteBuffer.wrap(bytes).getChar(stage3) | ByteBuffer.wrap(bytes).getChar(stage3+1);
4883                                             stage3+=2;
4884                                         default:
4885                                             break;
4886                                         }
4887                                         if(b!=0) {
4888                                             setFillIn.add(c);
4889                                         }
4890                                     }
4891                                     st3>>=1;
4892                                 }while((++c&0xf)!=0);
4893                                 break;
4894                             case UCNV_SET_FILTER_DBCS_ONLY:
4895                                 /* Ignore single bytes results (<0x100). */
4896                                 do {
4897                                     if(((st3&1) != 0 || useFallBack) && 
4898                                             (UConverterConstants.UNSIGNED_SHORT_MASK & (ByteBuffer.wrap(bytes).getChar(stage3))) >= 0x100){
4899                                         setFillIn.add(c);
4900                                     }
4901                                     st3>>=1;
4902                                     stage3+=2;
4903                                 }while((++c&0xf) != 0);
4904                                break;
4905                             case UCNV_SET_FILTER_2022_CN :
4906                                 /* only add code points that map to CNS 11643 planes 1&2 for non-EXT ISO-2202-CN. */
4907                                 do {
4908                                     if(((st3&1) != 0 || useFallBack) && 
4909                                             ((value= (UConverterConstants.UNSIGNED_BYTE_MASK & (ByteBuffer.wrap(bytes).get(stage3))))==0x81 || value==0x82) ){
4910                                         setFillIn.add(c);
4911                                     }
4912                                     st3>>=1;
4913                                     stage3+=3;
4914                                 }while((++c&0xf)!=0);
4915                                 break;
4916                             case UCNV_SET_FILTER_SJIS:
4917                                 /* only add code points that map tp Shift-JIS codes corrosponding to JIS X 0280. */
4918                                 do{
4919                                     
4920                                     if(((st3&1) != 0 || useFallBack) && (value=(UConverterConstants.UNSIGNED_SHORT_MASK & (ByteBuffer.wrap(bytes).getChar(stage3))))>=0x8140 && value<=0xeffc){
4921                                         setFillIn.add(c);
4922                                     }
4923                                     st3>>=1;
4924                                     stage3+=2;
4925                                 }while((++c&0xf)!=0);
4926                                 break;
4927                             case UCNV_SET_FILTER_GR94DBCS:
4928                                 /* only add code points that maps to ISO 2022 GR 94 DBCS codes*/
4929                                 do {
4930                                     if(((st3&1) != 0 || useFallBack) && 
4931                                             (UConverterConstants.UNSIGNED_SHORT_MASK & ((value=(UConverterConstants.UNSIGNED_SHORT_MASK & (ByteBuffer.wrap(bytes).getChar(stage3))))- 0xa1a1))<=(0xfefe - 0xa1a1) && 
4932                                             (UConverterConstants.UNSIGNED_BYTE_MASK & (value - 0xa1)) <= (0xfe - 0xa1)){
4933                                         setFillIn.add(c);
4934                                     }
4935                                     st3>>=1;
4936                                     stage3+=2;
4937                                 }while((++c&0xf)!=0);
4938                                 break;
4939                             case UCNV_SET_FILTER_HZ:
4940                                 /*Only add code points that are suitable for HZ DBCS*/
4941                                 do {
4942                                     if( ((st3&1) != 0 || useFallBack) && 
4943                                             (UConverterConstants.UNSIGNED_SHORT_MASK & ((value=(UConverterConstants.UNSIGNED_SHORT_MASK & (ByteBuffer.wrap(bytes).getChar(stage3))))-0xa1a1))<=(0xfdfe - 0xa1a1) &&
4944                                             (UConverterConstants.UNSIGNED_BYTE_MASK & (value - 0xa1)) <= (0xfe - 0xa1)){
4945                                         setFillIn.add(c);
4946                                     }
4947                                     st3>>=1;
4948                                     stage3+=2;
4949                                 }while((++c&0xf) != 0);
4950                                 break;
4951                             default:
4952                                 return;
4953                             }
4954                         } else {
4955                             c+=16; /* empty stage 3 block */
4956                         }
4957                     }
4958                 } else {
4959                     c+=1024; /*empty stage2 block */
4960                 }
4961             }
4962         }
4963         extGetUnicodeSet(setFillIn, which, filter, data);
4964     }
4965    
4966     static void extGetUnicodeSetString(ByteBuffer cx,UnicodeSet setFillIn, boolean useFallback, 
4967         int minLength, int c, char s[],int length,int sectionIndex){
4968         CharBuffer fromUSectionUChar;
4969         IntBuffer fromUSectionValues;
4970         fromUSectionUChar = (CharBuffer)ARRAY(cx, EXT_FROM_U_UCHARS_INDEX,char.class );
4971         fromUSectionValues = (IntBuffer)ARRAY(cx, EXT_FROM_U_VALUES_INDEX,int.class );
4972         int fromUSectionUCharIndex = fromUSectionUChar.position()+sectionIndex;
4973         int fromUSectionValuesIndex = fromUSectionValues.position()+sectionIndex;
4974         int value, i, count;
4975         
4976         /* read first pair of the section */
4977        count = fromUSectionUChar.get(fromUSectionUCharIndex++);
4978        value = fromUSectionValues.get(fromUSectionValuesIndex++);
4979        if(value!=0 && (FROM_U_IS_ROUNDTRIP(value) || useFallback) && FROM_U_GET_LENGTH(value)>=minLength) {
4980            if(c>=0){
4981                setFillIn.add(c);
4982            } else {
4983                String normalizedString=""; // String for composite characters 
4984                for(int j=0; j<length;j++){
4985                    normalizedString+=s[j];
4986                }
4987                for(int j=0;j<length;j++){
4988                    setFillIn.add(normalizedString);
4989                }
4990              
4991              }
4992        }
4993        
4994        for(i=0; i<count; ++i){
4995            s[length] = fromUSectionUChar.get(fromUSectionUCharIndex + i);
4996            value = fromUSectionValues.get(fromUSectionValuesIndex + i);
4997            
4998            if(value==0) {
4999                /* no mapping, do nothing */
5000            } else if (FROM_U_IS_PARTIAL(value)) {
5001                extGetUnicodeSetString( cx, setFillIn, useFallback, minLength, UConverterConstants.U_SENTINEL, s, length+1,
5002                        FROM_U_GET_PARTIAL_INDEX(value));
5003            } else if ((useFallback ? (value&FROM_U_RESERVED_MASK)==0:((value&(FROM_U_ROUNDTRIP_FLAG|FROM_U_RESERVED_MASK))==FROM_U_ROUNDTRIP_FLAG)) 
5004                    && FROM_U_GET_LENGTH(value)>=minLength) {
5005                String normalizedString=""; // String for composite characters 
5006                for(int j=0; j<(length+1);j++){
5007                    normalizedString+=s[j];
5008                }
5009              setFillIn.add(normalizedString);
5010            }
5011        }
5012         
5013     }
5014     
5015     
5016     static void extGetUnicodeSet(UnicodeSet setFillIn, int which, int filter, UConverterSharedData Data){
5017         int st1, stage1Length, st2, st3, minLength;
5018         int ps2, ps3;
5019         
5020         CharBuffer stage12, stage3;
5021         int value, length;
5022         IntBuffer stage3b;
5023         boolean useFallback;
5024         char s[] = new char[MAX_UCHARS];
5025         int c;
5026         ByteBuffer cx = Data.mbcs.extIndexes;
5027         if(cx == null){
5028             return;
5029         }
5030         stage12 = (CharBuffer)ARRAY(cx, EXT_FROM_U_STAGE_12_INDEX,char.class );
5031         stage3 = (CharBuffer)ARRAY(cx, EXT_FROM_U_STAGE_3_INDEX,char.class );
5032         stage3b = (IntBuffer)ARRAY(cx, EXT_FROM_U_STAGE_3B_INDEX,int.class );
5033         
5034         stage1Length = cx.asIntBuffer().get(EXT_FROM_U_STAGE_1_LENGTH);
5035         useFallback = (which==ROUNDTRIP_AND_FALLBACK_SET);
5036         
5037         c = 0;
5038         if(filter == UCNV_SET_FILTER_2022_CN) {
5039             minLength = 3;
5040         } else if (Data.mbcs.outputType == MBCS_OUTPUT_DBCS_ONLY || filter != UCNV_SET_FILTER_NONE) {
5041             /* DBCS-only, ignore single-byte results */
5042             minLength = 2;
5043         } else {
5044             minLength = 1;
5045         }
5046         
5047         for(st1=0; st1< stage1Length; ++st1){
5048             st2 = stage12.get(st1);
5049             if(st2>stage1Length) {
5050                 ps2 = st2;
5051                 for(st2=0;st2<64;++st2){
5052                     st3=((int) stage12.get(ps2+st2))<<STAGE_2_LEFT_SHIFT;
5053                     if(st3!= 0){
5054                         ps3 = st3;
5055                         do {
5056                             value = stage3b.get(UConverterConstants.UNSIGNED_SHORT_MASK&stage3.get(ps3++));
5057                             if(value==0){
5058                                 /* no mapping do nothing */
5059                             }else if (FROM_U_IS_PARTIAL(value)){
5060                                 length = 0;
5061                                 length=UTF16.append(s, length, c);
5062                                 extGetUnicodeSetString(cx,setFillIn,useFallback,minLength,c,s,length,FROM_U_GET_PARTIAL_INDEX(value));
5063                             } else if ((useFallback ?  (value&FROM_U_RESERVED_MASK)==0 :((value&(FROM_U_ROUNDTRIP_FLAG|FROM_U_RESERVED_MASK))== FROM_U_ROUNDTRIP_FLAG)) && 
5064                                     FROM_U_GET_LENGTH(value)>=minLength){
5065                                 
5066                                 switch(filter) {
5067                                 case UCNV_SET_FILTER_2022_CN:
5068                                     if(!(FROM_U_GET_LENGTH(value)==3 && FROM_U_GET_DATA(value)<=0x82ffff)){
5069                                         continue;
5070                                     }
5071                                     break;
5072                                 case UCNV_SET_FILTER_SJIS:
5073                                     if(!(FROM_U_GET_LENGTH(value)==2 && (value=FROM_U_GET_DATA(value))>=0x8140 && value<=0xeffc)){
5074                                         continue;
5075                                     }
5076                                     break;
5077                                 case UCNV_SET_FILTER_GR94DBCS:
5078                                     if(!(FROM_U_GET_LENGTH(value)==2 && (UConverterConstants.UNSIGNED_SHORT_MASK & ((value=FROM_U_GET_DATA(value)) - 0xa1a1))<=(0xfefe - 0xa1a1) 
5079                                             && (UConverterConstants.UNSIGNED_BYTE_MASK & (value - 0xa1))<= (0xfe - 0xa1))){
5080                                         
5081                                         continue;
5082                                     }
5083                                     break;
5084                                 case UCNV_SET_FILTER_HZ:
5085                                     if(!(FROM_U_GET_LENGTH(value)==2 && (UConverterConstants.UNSIGNED_SHORT_MASK & ((value=FROM_U_GET_DATA(value)) - 0xa1a1))<=(0xfdfe - 0xa1a1) 
5086                                             && (UConverterConstants.UNSIGNED_BYTE_MASK & (value - 0xa1))<= (0xfe - 0xa1))){
5087                                         continue;
5088                                     }
5089                                     break;
5090                                 default:
5091                                     /*
5092                                      * UCNV_SET_FILTER_NONE,
5093                                      * or UCNV_SET_FILTER_DBCS_ONLY which is handled via minLength
5094                                      */
5095                                     break;
5096                                 }
5097                                 setFillIn.add(c);
5098                               
5099                             }
5100                         }while((++c&0xf) != 0);
5101                       
5102                     } else {
5103                         c+=16;   /* emplty stage3 block */
5104                     }
5105                 }
5106             } else {
5107                 c+=1024;  /* empty stage 2 block*/
5108             }
5109         }
5110     }
5111     
5112     void MBCSGetUnicodeSetForUnicode(UConverterSharedData data, UnicodeSet setFillIn, int which){
5113         MBCSGetFilteredUnicodeSetForUnicode(data, setFillIn, which, 
5114                 this.sharedData.mbcs.outputType==MBCS_OUTPUT_DBCS_ONLY ? UCNV_SET_FILTER_DBCS_ONLY : UCNV_SET_FILTER_NONE );
5115     }
5116     
5117     void getUnicodeSetImpl( UnicodeSet setFillIn, int which){
5118         if((options & MBCS_OPTION_GB18030)!=0){
5119             setFillIn.add(0, 0xd7ff);
5120             setFillIn.add(0xe000, 0x10ffff);
5121         }
5122         else {
5123             this.MBCSGetUnicodeSetForUnicode(sharedData, setFillIn, which);
5124         }
5125     }
5126
5127 }