300 lines · 10.3 KB · Java
RawDownload
/* * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* */ package sun.io; import sun.nio.cs.ext.GB18030; public class ByteToCharGB18030 extends ByteToCharGB18030DB {     private static final int GB18030_SINGLE_BYTE = 1;    private static final int GB18030_DOUBLE_BYTE = 2;    private static final int GB18030_FOUR_BYTE = 3;    private static short[] decoderIndex1;    private static String[] decoderIndex2;     private int currentState;    private int savedSize;    private byte[] savedBytes;     public ByteToCharGB18030() {        super();        GB18030 nioCoder = new GB18030();        savedBytes = new byte[3];        currentState = GB18030_DOUBLE_BYTE;        decoderIndex1 = nioCoder.getDecoderIndex1();        decoderIndex2 = nioCoder.getDecoderIndex2();        savedSize = 0;    }     public short[] getOuter() {        return(index1);    }     public String[] getInner() {        return(index2);    }     public short[] getDBIndex1() {        return(super.index1);    }     public String[] getDBIndex2() {        return(super.index2);    }     public int flush(char [] output, int outStart, int outEnd)        throws MalformedInputException    {        if (savedSize != 0) {            savedSize = 0;            currentState = GB18030_DOUBLE_BYTE;            badInputLength = 0;            throw new MalformedInputException();        }        byteOff = charOff = 0;        return 0;    }      /**     * Character conversion     */    public int convert(byte[] input, int inOff, int inEnd,                       char[] output, int outOff, int outEnd)        throws UnknownCharacterException, MalformedInputException,               ConversionBufferFullException    {        int inputSize = 0;        char outputChar = '\uFFFD';        // readOff keeps the actual buffer's pointer.        // byteOff keeps original buffer's pointer.        int readOff = byteOff = inOff;         if (savedSize != 0) {            // Filter illegal bytes when they are detected in saved            // partial input from a previous conversion attempt.            if (((savedBytes[0] & 0xFF) < 0x81 || savedBytes[0] > 0xFE) ||                 (savedSize > 1 &&                 (savedBytes[1] & 0xFF) < 0x30 ) ||                 (savedSize > 2 &&                 ((savedBytes[2] & 0xFF) < 0x81 ||                 (savedBytes[2] & 0xFF) > 0xFE ))) {                    badInputLength = 0;                    throw new MalformedInputException();            }             byte[] newBuf = new byte[inEnd - inOff + savedSize];            for (int i = 0; i < savedSize; i++) {                newBuf[i] = savedBytes[i];            }            System.arraycopy(input, inOff, newBuf, savedSize, inEnd - inOff);            byteOff -= savedSize;            input = newBuf;            inOff = 0;            inEnd = newBuf.length;            savedSize = 0;        }         charOff = outOff;        readOff = inOff;         while(readOff < inEnd) {            int byte1 = 0 , byte2 = 0, byte3 = 0, byte4 = 0;             // Is there room in the output buffer for the result?            if (charOff >= outEnd) {                throw new ConversionBufferFullException();            }             // Get the input byte            byte1 = input[readOff++] & 0xFF;            inputSize = 1;             if ((byte1 & (byte)0x80) == 0){ // US-ASCII range                outputChar = (char)byte1;                currentState = GB18030_SINGLE_BYTE;            }             else if (byte1 < 0x81 || byte1 > 0xfe) {                if (subMode)                    outputChar = subChars[0];                else {                    badInputLength = 1;                    throw new UnknownCharacterException();                }            }            else {                // Either 2 or 4 byte sequence follows                // If an underrun is detected save for later                // replay.                 if (readOff + inputSize > inEnd) {                    savedBytes[0]=(byte)byte1;                    savedSize = 1;                    break;                }                 byte2 = input[readOff++] & 0xFF;                inputSize = 2;                 if (byte2 < 0x30) {                    badInputLength = 1;                    throw new MalformedInputException();                }                else if (byte2 >= 0x30 && byte2 <= 0x39) {                    currentState = GB18030_FOUR_BYTE;                    inputSize = 4;                     if (readOff + 2 > inEnd) {                        if (readOff + 1 > inEnd) {                            savedBytes[0] = (byte)byte1;                            savedBytes[1] = (byte)byte2;                            savedSize = 2;                        }                        else {                            savedBytes[0] = (byte)byte1;                            savedBytes[1] = (byte)byte2;                            savedBytes[2] = input[readOff++];                            savedSize = 3;                        }                        break;                    }                    byte3 = input[readOff++] & 0xFF;                    if (byte3 < 0x81 || byte3 > 0xfe) {                        badInputLength = 3;                        throw new MalformedInputException();                    }                     byte4 = input[readOff++] & 0xFF;                     if (byte4 < 0x30 || byte4 > 0x39) {                        badInputLength = 4;                        throw new MalformedInputException();                    }                }                else if (byte2 == 0x7f || byte2 == 0xff ||                        (byte2 < 0x40 )) {                   badInputLength = 2;                   throw new MalformedInputException();                }                else                    currentState = GB18030_DOUBLE_BYTE;            }             switch (currentState){                case GB18030_SINGLE_BYTE:                    output[charOff++] = (char)(byte1);                    break;                case GB18030_DOUBLE_BYTE:                    output[charOff++] = super.getUnicode(byte1, byte2);                    break;                case GB18030_FOUR_BYTE:                    int offset = (((byte1 - 0x81) * 10 +                                   (byte2 - 0x30)) * 126 +                                    byte3 - 0x81) * 10 + byte4 - 0x30;                    int hiByte = (offset >>8) & 0xFF;                    int lowByte = (offset & 0xFF);                 // Mixture of table lookups and algorithmic calculation                // of character values.                 // BMP Ranges                 if (offset <= 0x4A62)                    output[charOff++] = getChar(offset);                else if (offset > 0x4A62 && offset <= 0x82BC)                    output[charOff++] = (char) (offset + 0x5543);                else if (offset >= 0x82BD && offset <= 0x830D)                    output[charOff++] = getChar(offset);                else if (offset >= 0x830D && offset <= 0x93A8)                    output[charOff++] = (char) (offset + 0x6557);                else if (offset >= 0x93A9 && offset <= 0x99FB)                    output[charOff++] = getChar(offset);                // Supplemental UCS planes handled via surrogates                else if (offset >= 0x2E248 && offset < 0x12E248) {                    if (offset >= 0x12E248) {                        if (subMode)                           return subChars[0];                        else {                           badInputLength = 4;                           throw new UnknownCharacterException();                        }                    }                     if (charOff +2 > outEnd) {                        throw new ConversionBufferFullException();                    }                    offset -= 0x1e248;                    char highSurr = (char) ((offset - 0x10000) / 0x400 + 0xD800);                    char lowSurr = (char) ((offset - 0x10000) % 0x400 + 0xDC00);                    output[charOff++] = highSurr;                    output[charOff++] = lowSurr;                }                else {                    badInputLength = 4;                    throw new MalformedInputException();                    }                break;              }        byteOff += inputSize;        }         byteOff += savedSize;        return charOff - outOff;    }     public void reset() {        byteOff = charOff = 0;        currentState = GB18030_DOUBLE_BYTE;        savedSize = 0;    }     public String getCharacterEncoding() {        return "GB18030";    }     private char getChar(int offset) throws UnknownCharacterException {        int byte1 = (offset >>8) & 0xFF;        int byte2 = (offset & 0xFF);        int start = 0, end = 0xFF;         if (((byte1 < 0) || (byte1 > getOuter().length))             || ((byte2 < start) || (byte2 > end))) {                if (subMode)                   return subChars[0];                else {                   badInputLength = 1;                   throw new UnknownCharacterException();                }        }         int n = (decoderIndex1[byte1] & 0xf) * (end - start + 1) + (byte2 - start);        return decoderIndex2[decoderIndex1[byte1] >> 4].charAt(n);    }}