blob: 8a9717aa1be0dc747fefc9b61614aa402d520e94 [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 2008-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.charset;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.IntBuffer;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.text.UTF16;
import com.ibm.icu.text.UnicodeSet;
/**
* @author krajwade
*
*/
class CharsetSCSU extends CharsetICU{
/* SCSU definitions --------------------------------------------------------- */
/* SCSU command byte values */
//enum {
private static final short SQ0=0x01; /* Quote from window pair 0 */
private static final short SQ7=0x08; /* Quote from window pair 7 */
private static final short SDX=0x0B; /* Define a window as extended */
//private static final short Srs=0x0C; /* reserved */
private static final short SQU=0x0E; /* Quote a single Unicode character */
private static final short SCU=0x0F; /* Change to Unicode mode */
private static final short SC0=0x10; /* Select window 0 */
private static final short SC7=0x17; /* Select window 7 */
private static final short SD0=0x18; /* Define and select window 0 */
//private static final short SD7=0x1F; /* Define and select window 7 */
private static final short UC0=0xE0; /* Select window 0 */
private static final short UC7=0xE7; /* Select window 7 */
private static final short UD0=0xE8; /* Define and select window 0 */
private static final short UD7=0xEF; /* Define and select window 7 */
private static final short UQU=0xF0; /* Quote a single Unicode character */
private static final short UDX=0xF1; /* Define a Window as extended */
private static final short Urs=0xF2; /* reserved */
// };
// enum {
/*
* Unicode code points from 3400 to E000 are not adressible by
* dynamic window, since in these areas no short run alphabets are
* found. Therefore add gapOffset to all values from gapThreshold.
*/
private static final int gapThreshold=0x68;
private static final int gapOffset = 0xAC00 ;
/* values between reservedStart and fixedThreshold are reserved */
private static final int reservedStart=0xA8;
/* use table of predefined fixed offsets for values from fixedThreshold */
private static final int fixedThreshold=0xF9;
//};
protected byte[] fromUSubstitution = new byte[]{(byte)0x0E,(byte)0xFF, (byte)0xFD};
/* constant offsets for the 8 static windows */
private static final int staticOffsets[]={
0x0000, /* ASCII for quoted tags */
0x0080, /* Latin - 1 Supplement (for access to punctuation) */
0x0100, /* Latin Extended-A */
0x0300, /* Combining Diacritical Marks */
0x2000, /* General Punctuation */
0x2080, /* Currency Symbols */
0x2100, /* Letterlike Symbols and Number Forms */
0x3000 /* CJK Symbols and punctuation */
};
/* initial offsets for the 8 dynamic (sliding) windows */
private static final int initialDynamicOffsets[]={
0x0080, /* Latin-1 */
0x00C0, /* Latin Extended A */
0x0400, /* Cyrillic */
0x0600, /* Arabic */
0x0900, /* Devanagari */
0x3040, /* Hiragana */
0x30A0, /* Katakana */
0xFF00 /* Fullwidth ASCII */
};
/* Table of fixed predefined Offsets */
private static final int fixedOffsets[]={
/* 0xF9 */ 0x00C0, /* Latin-1 Letters + half of Latin Extended A */
/* 0xFA */ 0x0250, /* IPA extensions */
/* 0xFB */ 0x0370, /* Greek */
/* 0xFC */ 0x0530, /* Armenian */
/* 0xFD */ 0x3040, /* Hiragana */
/* 0xFE */ 0x30A0, /* Katakana */
/* 0xFF */ 0xFF60 /* Halfwidth Katakana */
};
/* state values */
//enum {
private static final int readCommand=0;
private static final int quotePairOne=1;
private static final int quotePairTwo=2;
private static final int quoteOne=3;
private static final int definePairOne=4;
private static final int definePairTwo=5;
private static final int defineOne=6;
// };
@SuppressWarnings("unused")
private final class SCSUData{
/* dynamic window offsets, intitialize to default values from initialDynamicOffsets */
int toUDynamicOffsets[] = new int[8] ;
int fromUDynamicOffsets[] = new int[8] ;
/* state machine state - toUnicode */
boolean toUIsSingleByteMode;
short toUState;
byte toUQuoteWindow, toUDynamicWindow;
short toUByteOne;
short toUPadding[];
/* state machine state - fromUnicode */
boolean fromUIsSingleByteMode;
byte fromUDynamicWindow;
/*
* windowUse[] keeps track of the use of the dynamic windows:
* At nextWindowUseIndex there is the least recently used window,
* and the following windows (in a wrapping manner) are more and more
* recently used.
* At nextWindowUseIndex-1 there is the most recently used window.
*/
byte locale;
byte nextWindowUseIndex;
byte windowUse[] = new byte[8];
SCSUData(){
initialize();
}
void initialize(){
for(int i=0;i<8;i++){
this.toUDynamicOffsets[i] = initialDynamicOffsets[i];
}
this.toUIsSingleByteMode = true;
this.toUState = readCommand;
this.toUQuoteWindow = 0;
this.toUDynamicWindow = 0;
this.toUByteOne = 0;
this.fromUIsSingleByteMode = true;
this.fromUDynamicWindow = 0;
for(int i=0;i<8;i++){
this.fromUDynamicOffsets[i] = initialDynamicOffsets[i];
}
this.nextWindowUseIndex = 0;
switch(this.locale){
/* Note being used right now because "SCSU,locale=ja" does not work in ICU4J. */
/* case l_ja:
for(int i=0;i<8;i++){
this.windowUse[i] = initialWindowUse_ja[i];
}
break; */
default:
for(int i=0;i<8;i++){
this.windowUse[i] = initialWindowUse[i];
}
}
}
}
static final byte initialWindowUse[]={ 7, 0, 3, 2, 4, 5, 6, 1 };
/* Note being used right now because "SCSU,locale=ja" does not work in ICU4J. */
// static final byte initialWindowUse_ja[]={ 3, 2, 4, 1, 0, 7, 5, 6 };
//enum {
//private static final int lGeneric = 0;
/* Note being used right now because "SCSU,locale=ja" does not work in ICU4J. */
// private static final int l_ja = 1;
//};
private SCSUData extraInfo = null;
public CharsetSCSU(String icuCanonicalName, String javaCanonicalName, String[] aliases){
super(icuCanonicalName, javaCanonicalName, aliases);
maxBytesPerChar = 3;
minBytesPerChar = 1;
maxCharsPerByte = 1;
extraInfo = new SCSUData();
}
class CharsetDecoderSCSU extends CharsetDecoderICU {
/* label values for supporting behavior similar to goto in C */
private static final int FastSingle=0;
private static final int SingleByteMode=1;
private static final int EndLoop=2;
/* Mode Type */
private static final int ByteMode = 0;
private static final int UnicodeMode =1;
public CharsetDecoderSCSU(CharsetICU cs) {
super(cs);
implReset();
}
//private SCSUData data ;
protected void implReset(){
super.implReset();
toULength = 0;
extraInfo.initialize();
}
short b;
//Get the state machine state
private boolean isSingleByteMode ;
private short state ;
private byte quoteWindow ;
private byte dynamicWindow ;
private short byteOne;
//sourceIndex=-1 if the current character began in the previous buffer
private int sourceIndex ;
private int nextSourceIndex ;
CoderResult cr;
SCSUData data ;
private boolean LabelLoop;// used to break the while loop
protected CoderResult decodeLoop(ByteBuffer source, CharBuffer target, IntBuffer offsets,
boolean flush){
data = extraInfo;
//Get the state machine state
isSingleByteMode = data.toUIsSingleByteMode;
state = data.toUState;
quoteWindow = data.toUQuoteWindow;
dynamicWindow = data.toUDynamicWindow;
byteOne = data.toUByteOne;
LabelLoop = true;
//sourceIndex=-1 if the current character began in the previous buffer
sourceIndex = data.toUState == readCommand ? 0: -1 ;
nextSourceIndex = 0;
cr = CoderResult.UNDERFLOW;
int labelType = 0;
while(LabelLoop){
if(isSingleByteMode){
switch(labelType){
case FastSingle:
/*fast path for single-byte mode*/
labelType = fastSingle(source, target, offsets, ByteMode);
break;
case SingleByteMode:
/* normal state machine for single-byte mode, minus handling for what fastSingleCovers */
labelType = singleByteMode(source, target, offsets, ByteMode);
break;
case EndLoop:
endLoop(source, target, offsets);
break;
}
}else{
switch(labelType){
case FastSingle:
/*fast path for single-byte mode*/
labelType = fastSingle(source, target, offsets, UnicodeMode);
break;
case SingleByteMode:
/* normal state machine for single-byte mode, minus handling for what fastSingleCovers */
labelType = singleByteMode(source, target, offsets, UnicodeMode);
break;
case EndLoop:
endLoop(source, target, offsets);
break;
}
//LabelLoop = false;
}
}
return cr;
}
private int fastSingle(ByteBuffer source, CharBuffer target, IntBuffer offsets, int modeType){
int label = 0;
if(modeType==ByteMode){
if(state==readCommand){
while(source.hasRemaining() && target.hasRemaining() && (b=(short)(source.get(source.position()) & UConverterConstants.UNSIGNED_BYTE_MASK)) >= 0x20){
source.position(source.position()+1);
++nextSourceIndex;
if(b <= 0x7f){
/*Write US graphic character or DEL*/
target.put((char)b);
if(offsets != null){
offsets.put(sourceIndex);
}
}else{
/*Write from dynamic window*/
int c = data.toUDynamicOffsets[dynamicWindow] + (b&0x7f);
if(c <= 0xffff){
target.put((char)c);
if(offsets != null){
offsets.put(sourceIndex);
}
}else{
/*Output surrogate pair */
target.put((char)(0xd7c0 + (c>>10)));
if(target.hasRemaining()){
target.put((char)(0xdc00 | (c&0x3ff)));
if(offsets != null){
offsets.put(sourceIndex);
offsets.put(sourceIndex);
}
}else{
/* target overflow */
if(offsets != null){
offsets.put(sourceIndex);
}
charErrorBufferArray[0] = (char)(0xdc00 | (c&0x3ff));
charErrorBufferLength = 1;
label = EndLoop;
cr = CoderResult.OVERFLOW;
return label;
}
}
}
sourceIndex = nextSourceIndex;
}
// label = SingleByteMode;
}
}else if(modeType==UnicodeMode){
/* fast path for unicode mode */
if(state == readCommand){
while((source.position()+1)<source.limit() && target.hasRemaining() && (((b=source.get(source.position()))-UC0)&UConverterConstants.UNSIGNED_BYTE_MASK)>(Urs-UC0)){
target.put((char)((b<<8)|(source.get(source.position()+1)&UConverterConstants.UNSIGNED_BYTE_MASK)));
if(offsets != null){
offsets.put(sourceIndex);
}
sourceIndex = nextSourceIndex;
nextSourceIndex+=2;
source.position(source.position()+2);
}
}
}
label = SingleByteMode;
return label;
}
private int singleByteMode(ByteBuffer source, CharBuffer target, IntBuffer offsets, int modeType){
int label = SingleByteMode;
if(modeType == ByteMode){
while(source.hasRemaining()){
if(!target.hasRemaining()){
cr = CoderResult.OVERFLOW;
label = EndLoop;
return label;
}
b = (short)(source.get() & UConverterConstants.UNSIGNED_BYTE_MASK);
++nextSourceIndex;
switch(state){
case readCommand:
/*redundant conditions are commented out */
if(((1L<<b)&0x2601)!=0){
target.put((char)b);
if(offsets != null){
offsets.put(sourceIndex);
}
sourceIndex = nextSourceIndex;
label = FastSingle;
return label;
}else if(SC0 <= b){
if(b<=SC7){
dynamicWindow = (byte)(b-SC0);
sourceIndex = nextSourceIndex;
label = FastSingle;
return label;
}else /* if(SD0<=b && b<=SQ7)*/{
dynamicWindow = (byte)(b - SD0);
state = defineOne;
}
}else if(/* SQ0<=b &&*/b <= SQ7){
quoteWindow = (byte)(b - SQ0);
state = quoteOne;
}else if(b==SDX){
state = definePairOne;
}else if(b==SQU){
state = quotePairOne;
}else if(b==SCU){
sourceIndex = nextSourceIndex;
isSingleByteMode = false;
label = FastSingle;
return label;
}else{
/*callback (illegal)*/
cr = CoderResult.malformedForLength(1);
toUBytesArray[0] = (byte)b;
toULength =1;
label = EndLoop;
return label;
}
/* Store the first byte of a multibyte sequence in toUByte[] */
toUBytesArray[0] = (byte)b;
toULength = 1;
break;
case quotePairOne:
byteOne = b;
toUBytesArray[1] = (byte)b;
toULength = 2;
state = quotePairTwo;
break;
case quotePairTwo:
target.put((char)((byteOne<< 8) | b));
if(offsets != null){
offsets.put(sourceIndex);
}
sourceIndex = nextSourceIndex;
state = readCommand;
label = FastSingle;
return label;
case quoteOne:
if(b<0x80){
/* all static offsets are in the BMP */
target.put((char)(staticOffsets[quoteWindow] + b));
if(offsets != null){
offsets.put(sourceIndex);
}
}else {
/*write from dynamic window */
int c = data.toUDynamicOffsets[quoteWindow] + (b&0x7f);
if(c<=0xffff){
target.put((char)c);
if(offsets != null){
offsets.put(sourceIndex);
}
}else {
/* output surrogate pair */
target.put((char)(0xd7c0+(c>>10)));
if(target.hasRemaining()){
target.put((char)(0xdc00 | (c&0x3ff)));
if(offsets != null){
offsets.put(sourceIndex);
offsets.put(sourceIndex);
}
}else {
/* target overflow */
if(offsets != null){
offsets.put(sourceIndex);
}
charErrorBufferArray[0] = (char)(0xdc00 | (c&0x3ff));
charErrorBufferLength = 1;
label = EndLoop;
cr = CoderResult.OVERFLOW;
LabelLoop = false;
return label;
}
}
}
sourceIndex = nextSourceIndex;
state = readCommand;
label = FastSingle;
return label;
case definePairOne:
dynamicWindow = (byte)((b>>5)&7);
byteOne = (byte)(b&0x1f);
toUBytesArray[1] = (byte)b;
toULength = 2;
state = definePairTwo;
break;
case definePairTwo:
data.toUDynamicOffsets[dynamicWindow] = 0x10000 + (byteOne<<15L | b<<7L);
sourceIndex = nextSourceIndex;
state = readCommand;
label = FastSingle;
return label;
case defineOne:
if(b==0){
/*callback (illegal)*/
toUBytesArray[1] = (byte)b;
toULength =2;
label = EndLoop;
return label;
}else if(b<gapThreshold){
data.toUDynamicOffsets[dynamicWindow] = b<<7L;
}else if(((b - gapThreshold)&UConverterConstants.UNSIGNED_BYTE_MASK)<(reservedStart - gapThreshold)){
data.toUDynamicOffsets[dynamicWindow] = (b<<7L) + gapOffset;
}else if(b>=fixedThreshold){
data.toUDynamicOffsets[dynamicWindow] = fixedOffsets[b-fixedThreshold];
}else{
/*callback (illegal)*/
toUBytesArray[1] = (byte)b;
toULength =2;
label = EndLoop;
return label;
}
sourceIndex = nextSourceIndex;
state = readCommand;
label = FastSingle;
return label;
}
}
}else if(modeType==UnicodeMode){
while(source.hasRemaining()){
if(!target.hasRemaining()){
cr = CoderResult.OVERFLOW;
label = EndLoop;
return label;
}
b = (short)(source.get() & UConverterConstants.UNSIGNED_BYTE_MASK);
++nextSourceIndex;
switch(state){
case readCommand:
if((short)((b -UC0)&UConverterConstants.UNSIGNED_BYTE_MASK)>(Urs - UC0)){
byteOne = b;
toUBytesArray[0] = (byte)b;
toULength = 1;
state = quotePairTwo;
}else if((b&UConverterConstants.UNSIGNED_BYTE_MASK) <= UC7){
dynamicWindow = (byte)(b - UC0);
sourceIndex = nextSourceIndex;
isSingleByteMode = true;
label = FastSingle;
return label;
}else if((b&UConverterConstants.UNSIGNED_BYTE_MASK) <= UD7){
dynamicWindow = (byte)(b - UD0);
isSingleByteMode = true;
toUBytesArray[0] = (byte)b;
toULength = 1;
state = defineOne;
label = SingleByteMode;
return label;
}else if((b&UConverterConstants.UNSIGNED_BYTE_MASK) == UDX){
isSingleByteMode = true;
toUBytesArray[0] = (byte)b;
toULength = 1;
state = definePairOne;
label = SingleByteMode;
return label;
}else if((b&UConverterConstants.UNSIGNED_BYTE_MASK) == UQU){
toUBytesArray[0] = (byte)b;
toULength = 1;
state = quotePairOne;
}else {
/* callback (illegal)*/
cr = CoderResult.malformedForLength(1);
toUBytesArray[0] = (byte)b;
toULength = 1;
label = EndLoop;
return label;
}
break;
case quotePairOne:
byteOne = b;
toUBytesArray[1] = (byte)b;
toULength = 2;
state = quotePairTwo;
break;
case quotePairTwo:
target.put((char)((byteOne<<8) | b));
if(offsets != null){
offsets.put(sourceIndex);
}
sourceIndex = nextSourceIndex;
state = readCommand;
label = FastSingle;
return label;
}
}
}
label = EndLoop;
return label;
}
private void endLoop(ByteBuffer source, CharBuffer target, IntBuffer offsets){
if(cr==CoderResult.OVERFLOW){
state = readCommand;
}else if(state == readCommand){
toULength = 0;
}
data.toUIsSingleByteMode = isSingleByteMode;
data.toUState = state;
data.toUQuoteWindow = quoteWindow;
data.toUDynamicWindow = dynamicWindow;
data.toUByteOne = byteOne;
LabelLoop = false;
}
}
class CharsetEncoderSCSU extends CharsetEncoderICU{
public CharsetEncoderSCSU(CharsetICU cs) {
super(cs, fromUSubstitution);
implReset();
}
//private SCSUData data;
protected void implReset() {
super.implReset();
extraInfo.initialize();
}
/* label values for supporting behavior similar to goto in C */
private static final int Loop=0;
private static final int GetTrailUnicode=1;
private static final int OutputBytes=2;
private static final int EndLoop =3;
private int delta;
private int length;
///variables of compression heuristics
private int offset;
private char lead, trail;
private int code;
private byte window;
//Get the state machine state
private boolean isSingleByteMode;
private byte dynamicWindow ;
private int currentOffset;
int c;
SCSUData data ;
//sourceIndex=-1 if the current character began in the previous buffer
private int sourceIndex ;
private int nextSourceIndex;
private int targetCapacity;
private boolean LabelLoop;//used to break the while loop
private boolean AfterGetTrail;// its value is set to true in order to ignore the code before getTrailSingle:
private boolean AfterGetTrailUnicode;// is value is set to true in order to ignore the code before getTrailUnicode:
CoderResult cr;
protected CoderResult encodeLoop(CharBuffer source, ByteBuffer target, IntBuffer offsets, boolean flush) {
data = extraInfo;
cr = CoderResult.UNDERFLOW;
//Get the state machine state
isSingleByteMode = data.fromUIsSingleByteMode;
dynamicWindow = data.fromUDynamicWindow;
currentOffset = data.fromUDynamicOffsets[dynamicWindow];
c = fromUChar32;
sourceIndex = c== 0 ? 0: -1 ;
nextSourceIndex = 0;
targetCapacity = target.limit()-target.position();
//sourceIndex=-1 if the current character began in the previous buffer
sourceIndex = c== 0 ? 0: -1 ;
nextSourceIndex = 0;
int labelType = Loop; // set to Loop so that the code starts from loop:
LabelLoop = true;
AfterGetTrail = false;
AfterGetTrailUnicode = false;
while(LabelLoop){
switch(labelType){
case Loop:
labelType = loop(source, target, offsets);
break;
case GetTrailUnicode:
labelType = getTrailUnicode(source, target, offsets);
break;
case OutputBytes:
labelType = outputBytes(source, target, offsets);
break;
case EndLoop:
endLoop(source, target, offsets);
break;
}
}
return cr;
}
private byte getWindow(int[] offsets){
int i;
for (i=0;i<8;i++){
if(((c-offsets[i]) & UConverterConstants.UNSIGNED_INT_MASK) <= 0x7f){
return (byte)i;
}
}
return -1;
}
private boolean isInOffsetWindowOrDirect(int offsetValue, int a){
return (a & UConverterConstants.UNSIGNED_INT_MASK)<=(offsetValue & UConverterConstants.UNSIGNED_INT_MASK)+0x7f &
((a & UConverterConstants.UNSIGNED_INT_MASK)>=(offsetValue & UConverterConstants.UNSIGNED_INT_MASK) ||
((a & UConverterConstants.UNSIGNED_INT_MASK)<=0x7f && ((a & UConverterConstants.UNSIGNED_INT_MASK)>=0x20
|| ((1L<<(a & UConverterConstants.UNSIGNED_INT_MASK))&0x2601)!=0)));
}
private byte getNextDynamicWindow(){
byte windowValue = data.windowUse[data.nextWindowUseIndex];
if(++data.nextWindowUseIndex==8){
data.nextWindowUseIndex=0;
}
return windowValue;
}
private void useDynamicWindow(byte windowValue){
/*first find the index of the window*/
int i,j;
i = data.nextWindowUseIndex;
do{
if(--i<0){
i=7;
}
}while(data.windowUse[i]!=windowValue);
/*now copy each window[i+1] to [i]*/
j= i+1;
if(j==8){
j=0;
}
while(j!=data.nextWindowUseIndex){
data.windowUse[i] = data.windowUse[j];
i=j;
if(++j==8){
j=0;
}
}
/*finally, set the window into the most recently used index*/
data.windowUse[i]= windowValue;
}
private int getDynamicOffset(){
int i;
for(i=0;i<7;++i){
if(((c-fixedOffsets[i])&UConverterConstants.UNSIGNED_INT_MASK)<=0x7f){
offset = fixedOffsets[i];
return 0xf9+i;
}
}
if((c&UConverterConstants.UNSIGNED_INT_MASK)<0x80){
/*No dynamic window for US-ASCII*/
return -1;
}else if((c&UConverterConstants.UNSIGNED_INT_MASK)<0x3400 || ((c-0x10000)&UConverterConstants.UNSIGNED_INT_MASK)<(0x14000-0x10000) ||
((c-0x1d000)&UConverterConstants.UNSIGNED_INT_MASK)<=(0x1ffff-0x1d000)){
/*This character is in the code range for a "small", i.e, reasonably windowable, script*/
offset = c&0x7fffff80;
return (c>>7);
}else if(0xe000<=(c&UConverterConstants.UNSIGNED_INT_MASK) && (c&UConverterConstants.UNSIGNED_INT_MASK)!=0xfeff && (c&UConverterConstants.UNSIGNED_INT_MASK) < 0xfff0){
/*for these characters we need to take the gapOffset into account*/
offset=(c)&0x7fffff80;
return ((c-gapOffset)>>7);
}else{
return -1;
}
}
private int loop(CharBuffer source, ByteBuffer target, IntBuffer offsets){
int label = 0;
if(isSingleByteMode){
if(c!=0 && targetCapacity>0 && !AfterGetTrail){
label = getTrail(source, target, offsets);
return label;
}
/*state machine for single byte mode*/
while(AfterGetTrail || source.hasRemaining()){
if(targetCapacity<=0 && !AfterGetTrail){
/*target is full*/
cr = CoderResult.OVERFLOW;
label = EndLoop;
return label;
}
if(!AfterGetTrail){
c = source.get();
++nextSourceIndex;
}
if(((c -0x20)&UConverterConstants.UNSIGNED_INT_MASK)<=0x5f && !AfterGetTrail){
/*pass US-ASCII graphic character through*/
target.put((byte)c);
if(offsets!=null){
offsets.put(sourceIndex);
}
--targetCapacity;
}else if((c & UConverterConstants.UNSIGNED_INT_MASK)<0x20 && !AfterGetTrail){
if(((1L<<(c & UConverterConstants.UNSIGNED_INT_MASK))&0x2601)!=0){
/*CR/LF/TAB/NUL*/
target.put((byte)c);
if(offsets!=null){
offsets.put(sourceIndex);
}
--targetCapacity;
} else {
/*quote c0 control character*/
c|=SQ0<<8;
length = 2;
label = OutputBytes;
return label;
}
} else if(((delta=(c-currentOffset))&UConverterConstants.UNSIGNED_INT_MASK)<=0x7f && !AfterGetTrail){
/*use the current dynamic window*/
target.put((byte)(delta|0x80));
if(offsets!=null){
offsets.put(sourceIndex);
}
--targetCapacity;
} else if(AfterGetTrail || UTF16.isSurrogate((char)c)){
if(!AfterGetTrail){
if(UTF16.isLeadSurrogate((char)c)){
label = getTrail(source, target, offsets);
if(label==EndLoop){
return label;
}
} else {
/*this is unmatched lead code unit (2nd Surrogate)*/
/*callback(illegal)*/
cr = CoderResult.malformedForLength(1);
label = EndLoop;
return label;
}
}
if(AfterGetTrail){
AfterGetTrail = false;
}
/*Compress supplementary character U+10000...U+10ffff */
if(((delta=(c-currentOffset))&UConverterConstants.UNSIGNED_INT_MASK)<=0x7f){
/*use the current dynamic window*/
target.put((byte)(delta|0x80));
if(offsets!=null){
offsets.put(sourceIndex);
}
--targetCapacity;
} else if((window=getWindow(data.fromUDynamicOffsets))>=0){
/*there is a dynamic window that contains this character, change to it*/
dynamicWindow = window;
currentOffset = data.fromUDynamicOffsets[dynamicWindow];
useDynamicWindow(dynamicWindow);
c = ((SC0+dynamicWindow)<<8 | (c-currentOffset)|0x80);
length = 2;
label = OutputBytes;
return label;
} else if((code=getDynamicOffset())>=0){
/*might check if there are come character in this window to come */
/*define an extended window with this character*/
code-=0x200;
dynamicWindow=getNextDynamicWindow();
currentOffset = data.fromUDynamicOffsets[dynamicWindow]=offset;
useDynamicWindow(dynamicWindow);
c = ((SDX<<24) | (dynamicWindow<<21)|
(code<<8)| (c- currentOffset) |0x80);
// c = (((SDX)<<25) | (dynamicWindow<<21)|
// (code<<8)| (c- currentOffset) |0x80 );
length = 4;
label = OutputBytes;
return label;
} else {
/*change to unicode mode and output this (lead, trail) pair*/
isSingleByteMode = false;
target.put((byte)SCU);
if(offsets!=null){
offsets.put(sourceIndex);
}
--targetCapacity;
c = (lead<<16)|trail;
length = 4;
label = OutputBytes;
return label;
}
} else if((c&UConverterConstants.UNSIGNED_INT_MASK)<0xa0){
/*quote C1 control character*/
c = (c&0x7f) | (SQ0+1)<<8; /*SQ0+1 == SQ1*/
length = 2;
label = OutputBytes;
return label;
} else if((c&UConverterConstants.UNSIGNED_INT_MASK)==0xfeff || (c&UConverterConstants.UNSIGNED_INT_MASK)>= 0xfff0){
/*quote signature character = byte order mark and specials*/
c |= SQU<<16;
length = 3;
label = OutputBytes;
return label;
} else {
/*compress all other BMP characters*/
if((window=getWindow(data.fromUDynamicOffsets))>=0){
/*there is a window defined that contains this character - switch to it or quote from it*/
if(source.position()>=source.limit() || isInOffsetWindowOrDirect(data.fromUDynamicOffsets[window], source.get(source.position()))){
/*change to dynamic window*/
dynamicWindow = window;
currentOffset = data.fromUDynamicOffsets[dynamicWindow];
useDynamicWindow(dynamicWindow);
c = ((SC0+window)<<8) | (c- currentOffset) | 0x80;
length = 2;
label = OutputBytes;
return label;
} else {
/*quote from dynamic window*/
c = ((SQ0+window)<<8) | (c - data.fromUDynamicOffsets[window]) |
0x80;
length = 2;
label = OutputBytes;
return label;
}
} else if((window = getWindow(staticOffsets))>=0){
/*quote from static window*/
c = ((SQ0+window)<<8) | (c - staticOffsets[window]);
length = 2;
label = OutputBytes;
return label;
}else if((code=getDynamicOffset())>=0){
/*define a dynamic window with this character*/
dynamicWindow = getNextDynamicWindow();
currentOffset = data.fromUDynamicOffsets[dynamicWindow]=offset;
useDynamicWindow(dynamicWindow);
c = ((SD0+dynamicWindow)<<16) | (code<<8)|
(c - currentOffset) | 0x80;
length = 3;
label = OutputBytes;
return label;
} else if(((int)((c-0x3400)&UConverterConstants.UNSIGNED_INT_MASK))<(0xd800-0x3400) && (source.position()>=source.limit() ||
((int)((source.get(source.position())-0x3400)&UConverterConstants.UNSIGNED_INT_MASK))< (0xd800 - 0x3400))){
/*
* this character is not compressible (a BMP ideograph of similar)
* switch to Unicode mode if this is the last character in the block
* or there is at least one more ideograph following immediately
*/
isSingleByteMode = false;
c|=SCU<<16;
length =3;
label = OutputBytes;
return label;
} else {
/*quote Unicode*/
c|=SQU<<16;
length = 3;
label = OutputBytes;
return label;
}
}
/*normal end of conversion : prepare for new character */
c = 0;
sourceIndex = nextSourceIndex;
}
} else {
if(c!=0 && targetCapacity>0 && !AfterGetTrailUnicode){
label = GetTrailUnicode;
return label;
}
/*state machine for Unicode*/
/*unicodeByteMode*/
while(AfterGetTrailUnicode || source.hasRemaining()){
if(targetCapacity<=0 && !AfterGetTrailUnicode){
/*target is full*/
cr = CoderResult.OVERFLOW;
LabelLoop = false;
break;
}
if(!AfterGetTrailUnicode){
c = source.get();
++nextSourceIndex;
}
if((((c-0x3400)& UConverterConstants.UNSIGNED_INT_MASK))<(0xd800-0x3400) && !AfterGetTrailUnicode){
/*not compressible, write character directly */
if(targetCapacity>=2){
target.put((byte)(c>>8));
target.put((byte)c);
if(offsets!=null){
offsets.put(sourceIndex);
offsets.put(sourceIndex);
}
targetCapacity-=2;
} else {
length =2;
label = OutputBytes;
return label;
}
} else if((((c-0x3400)& UConverterConstants.UNSIGNED_INT_MASK))>=(0xf300-0x3400) /* c<0x3400 || c>=0xf300*/&& !AfterGetTrailUnicode){
/*compress BMP character if the following one is not an uncompressible ideograph*/
if(!(source.hasRemaining() && (((source.get(source.position())-0x3400)& UConverterConstants.UNSIGNED_INT_MASK))<(0xd800-0x3400))){
if(((((c-0x30)&UConverterConstants.UNSIGNED_INT_MASK))<10 || (((c-0x61)&UConverterConstants.UNSIGNED_INT_MASK))<26
|| (((c-0x41)&UConverterConstants.UNSIGNED_INT_MASK))<26)){
/*ASCII digit or letter*/
isSingleByteMode = true;
c |=((UC0+dynamicWindow)<<8)|c;
length = 2;
label = OutputBytes;
return label;
} else if((window=getWindow(data.fromUDynamicOffsets))>=0){
/*there is a dynamic window that contains this character, change to it*/
isSingleByteMode = true;
dynamicWindow = window;
currentOffset = data.fromUDynamicOffsets[dynamicWindow];
useDynamicWindow(dynamicWindow);
c = ((UC0+dynamicWindow)<<8) | (c- currentOffset) | 0x80;
length = 2;
label = OutputBytes;
return label;
} else if((code=getDynamicOffset())>=0){
/*define a dynamic window with this character*/
isSingleByteMode = true;
dynamicWindow = getNextDynamicWindow();
currentOffset = data.fromUDynamicOffsets[dynamicWindow]=offset;
useDynamicWindow(dynamicWindow);
c = ((UD0+dynamicWindow)<<16) | (code<<8)
|(c - currentOffset) | 0x80;
length = 3;
label = OutputBytes;
return label;
}
}
/*don't know how to compress these character, just write it directly*/
length = 2;
label = OutputBytes;
return label;
} else if(c<0xe000 && !AfterGetTrailUnicode){
label = GetTrailUnicode;
return label;
} else if (!AfterGetTrailUnicode){
/*quote to avoid SCSU tags*/
c|=UQU<<16;
length = 3;
label = OutputBytes;
return label;
}
if(AfterGetTrailUnicode){
AfterGetTrailUnicode = false;
}
/*normal end of conversion, prepare for a new character*/
c = 0;
sourceIndex = nextSourceIndex;
}
}
label = EndLoop;
return label;
}
private int getTrail(CharBuffer source, ByteBuffer target, IntBuffer offsets){
lead = (char)c;
int label = Loop;
if(source.hasRemaining()){
/*test the following code unit*/
trail = source.get(source.position());
if(UTF16.isTrailSurrogate(trail)){
source.position(source.position()+1);
++nextSourceIndex;
c = UCharacter.getCodePoint((char)c, trail);
label = Loop;
} else {
/*this is unmatched lead code unit (1st Surrogate)*/
/*callback(illegal)*/
cr = CoderResult.malformedForLength(1);
label = EndLoop;
}
}else {
/*no more input*/
label = EndLoop;
}
AfterGetTrail = true;
return label;
}
private int getTrailUnicode(CharBuffer source, ByteBuffer target, IntBuffer offsets){
int label = EndLoop;
AfterGetTrailUnicode = true;
/*c is surrogate*/
if(UTF16.isLeadSurrogate((char)c)){
// getTrailUnicode:
lead = (char)c;
if(source.hasRemaining()){
/*test the following code unit*/
trail = source.get(source.position());
if(UTF16.isTrailSurrogate(trail)){
source.get();
++nextSourceIndex;
c = UCharacter.getCodePoint((char)c, trail);
/*convert this surrogate code point*/
/*exit this condition tree*/
} else {
/*this is unmatched lead code unit(1st surrogate)*/
/*callback(illegal)*/
cr = CoderResult.malformedForLength(1);
label = EndLoop;
return label;
}
} else {
/*no more input*/
label = EndLoop;
return label;
}
} else {
/*this is an unmatched trail code point (2nd surrogate)*/
/*callback (illegal)*/
cr = CoderResult.malformedForLength(1);
label = EndLoop;
return label;
}
/*compress supplementary character*/
if((window=getWindow(data.fromUDynamicOffsets))>=0 &&
!(source.hasRemaining() && ((source.get(source.position())-0x3400)&UConverterConstants.UNSIGNED_INT_MASK) <
(0xd800 - 0x3400))){
/*
* this is the dynamic window that contains this character and the following
* character is not uncompressible,
* change to the window
*/
isSingleByteMode = true;
dynamicWindow = window;
currentOffset = data.fromUDynamicOffsets[dynamicWindow];
useDynamicWindow(dynamicWindow);
c = ((UC0+dynamicWindow)<<8 | (c-currentOffset) | 0x80);
length = 2;
label = OutputBytes;
return label;
} else if(source.hasRemaining() && lead == source.get(source.position()) && (code=getDynamicOffset())>=0){
/*two supplementary characters in (probably) the same window - define an extended one*/
isSingleByteMode = true;
dynamicWindow = getNextDynamicWindow();
currentOffset = data.fromUDynamicOffsets[dynamicWindow] = offset;
useDynamicWindow(dynamicWindow);
c = (UDX<<24) | (dynamicWindow<<21) |(code<<8) |(c - currentOffset) | 0x80;
length = 4;
label = OutputBytes;
return label;
} else {
/*don't know how to compress this character, just write it directly*/
c = (lead<<16)|trail;
length = 4;
label = OutputBytes;
return label;
}
}
private void endLoop(CharBuffer source, ByteBuffer target, IntBuffer offsets){
/*set the converter state back to UConverter*/
data.fromUIsSingleByteMode = isSingleByteMode;
data.fromUDynamicWindow = dynamicWindow;
fromUChar32 = c;
LabelLoop = false;
}
@SuppressWarnings("fallthrough")
private int outputBytes(CharBuffer source, ByteBuffer target, IntBuffer offsets){
int label;
//int targetCapacity = target.limit()-target.position();
/*write the output character byte from c and length*/
/*from the first if in the loop we know that targetCapacity>0*/
if(length<=targetCapacity){
switch(length){
/*each branch falls through the next one*/
case 4:
target.put((byte)(c>>24));
if(offsets!=null){
offsets.put(sourceIndex);
}
case 3:
target.put((byte)(c>>16));
if(offsets!=null){
offsets.put(sourceIndex);
}
case 2:
target.put((byte)(c>>8));
if(offsets!=null){
offsets.put(sourceIndex);
}
case 1:
target.put((byte)c);
if(offsets!=null){
offsets.put(sourceIndex);
}
default:
/*will never occur*/
break;
}
targetCapacity-=length;
/*normal end of conversion: prepare for a new character*/
c = 0;
sourceIndex = nextSourceIndex;
label = Loop;
return label;
} else {
ByteBuffer p = ByteBuffer.wrap(errorBuffer);
/*
* We actually do this backwards here:
* In order to save an intermediate variable, we output
* first to the overflow buffer what does not fit into the
* regular target
*/
/* we know that 0<=targetCapacity<length<=4 */
/* targetCapacity==0 when SCU+supplementary where SCU used up targetCapacity==1 */
length -= targetCapacity;
switch(length){
/*each branch falls through the next one*/
case 4:
p.put((byte)(c>>24));
case 3:
p.put((byte)(c>>16));
case 2:
p.put((byte)(c>>8));
case 1:
p.put((byte)c);
default:
/*will never occur*/
break;
}
errorBufferLength = length;
/*now output what fits into the regular target*/
c>>=8*length; //length was reduced by targetCapacity
switch(targetCapacity){
/*each branch falls through the next one*/
case 3:
target.put((byte)(c>>16));
if(offsets!=null){
offsets.put(sourceIndex);
}
case 2:
target.put((byte)(c>>8));
if(offsets!=null){
offsets.put(sourceIndex);
}
case 1:
target.put((byte)c);
if(offsets!=null){
offsets.put(sourceIndex);
}
default:
break;
}
/*target overflow*/
targetCapacity = 0;
cr = CoderResult.OVERFLOW;
c = 0;
label = EndLoop;
return label;
}
}
}
public CharsetDecoder newDecoder() {
return new CharsetDecoderSCSU(this);
}
public CharsetEncoder newEncoder() {
return new CharsetEncoderSCSU(this);
}
void getUnicodeSetImpl( UnicodeSet setFillIn, int which){
CharsetICU.getCompleteUnicodeSet(setFillIn);
}
}