365 lines · 13.9 KB · Java
RawDownload
/* * Copyright (c) 2010, 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.nio.cs.ext; import java.nio.ByteBuffer;import java.nio.CharBuffer;import java.nio.charset.Charset;import java.nio.charset.CharsetDecoder;import java.nio.charset.CharsetEncoder;import java.nio.charset.CoderResult;import java.util.Arrays;import sun.nio.cs.Surrogate;import static sun.nio.cs.CharsetMapping.*; public class HKSCS {     public static class Decoder extends DoubleByte.Decoder {        static int b2Min = 0x40;        static int b2Max = 0xfe;         private char[][] b2cBmp;        private char[][] b2cSupp;        private DoubleByte.Decoder big5Dec;         protected Decoder(Charset cs,                          DoubleByte.Decoder big5Dec,                          char[][] b2cBmp, char[][] b2cSupp)        {            // super(cs, 0.5f, 1.0f);            // need to extends DoubleByte.Decoder so the            // sun.io can use it. this implementation            super(cs, 0.5f, 1.0f, null, null, 0, 0);            this.big5Dec = big5Dec;            this.b2cBmp = b2cBmp;            this.b2cSupp = b2cSupp;        }         public char decodeSingle(int b) {            return big5Dec.decodeSingle(b);        }         public char decodeBig5(int b1, int b2) {            return big5Dec.decodeDouble(b1, b2);        }         public char decodeDouble(int b1, int b2) {            return b2cBmp[b1][b2 - b2Min];        }         public char decodeDoubleEx(int b1, int b2) {            /* if the b2cSupp is null, the subclass need               to override the methold            if (b2cSupp == null)                return UNMAPPABLE_DECODING;             */            return b2cSupp[b1][b2 - b2Min];        }         protected CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {            byte[] sa = src.array();            int sp = src.arrayOffset() + src.position();            int sl = src.arrayOffset() + src.limit();             char[] da = dst.array();            int dp = dst.arrayOffset() + dst.position();            int dl = dst.arrayOffset() + dst.limit();             try {                while (sp < sl) {                    int b1 = sa[sp] & 0xff;                    char c = decodeSingle(b1);                    int inSize = 1, outSize = 1;                    char[] cc = null;                    if (c == UNMAPPABLE_DECODING) {                        if (sl - sp < 2)                            return CoderResult.UNDERFLOW;                        int b2 = sa[sp + 1] & 0xff;                        inSize++;                        if (b2 < b2Min || b2 > b2Max)                            return CoderResult.unmappableForLength(2);                        c = decodeDouble(b1, b2);           //bmp                        if (c == UNMAPPABLE_DECODING) {                            c = decodeDoubleEx(b1, b2);     //supp                            if (c == UNMAPPABLE_DECODING) {                                c = decodeBig5(b1, b2);     //big5                                if (c == UNMAPPABLE_DECODING)                                    return CoderResult.unmappableForLength(2);                            } else {                                // supplementary character in u+2xxxx area                                outSize = 2;                            }                        }                    }                    if (dl - dp < outSize)                        return CoderResult.OVERFLOW;                    if (outSize == 2) {                        // supplementary characters                        da[dp++] = Surrogate.high(0x20000 + c);                        da[dp++] = Surrogate.low(0x20000 + c);                    } else {                        da[dp++] = c;                    }                    sp += inSize;                }                return CoderResult.UNDERFLOW;            } finally {                src.position(sp - src.arrayOffset());                dst.position(dp - dst.arrayOffset());            }        }         protected CoderResult decodeBufferLoop(ByteBuffer src, CharBuffer dst) {            int mark = src.position();            try {                while (src.hasRemaining()) {                    char[] cc = null;                    int b1 = src.get() & 0xff;                    int inSize = 1, outSize = 1;                    char c = decodeSingle(b1);                    if (c == UNMAPPABLE_DECODING) {                        if (src.remaining() < 1)                            return CoderResult.UNDERFLOW;                        int b2 = src.get() & 0xff;                        inSize++;                        if (b2 < b2Min || b2 > b2Max)                            return CoderResult.unmappableForLength(2);                        c = decodeDouble(b1, b2);           //bmp                        if (c == UNMAPPABLE_DECODING) {                            c = decodeDoubleEx(b1, b2);     //supp                            if (c == UNMAPPABLE_DECODING) {                                c = decodeBig5(b1, b2);     //big5                                if (c == UNMAPPABLE_DECODING)                                    return CoderResult.unmappableForLength(2);                            } else {                                outSize = 2;                            }                        }                    }                    if (dst.remaining() < outSize)                        return CoderResult.OVERFLOW;                    if (outSize == 2) {                        dst.put(Surrogate.high(0x20000 + c));                        dst.put(Surrogate.low(0x20000 + c));                    } else {                        dst.put(c);                    }                    mark += inSize;                }                return CoderResult.UNDERFLOW;            } finally {                src.position(mark);            }        }         public CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {            if (src.hasArray() && dst.hasArray())                return decodeArrayLoop(src, dst);            else                return decodeBufferLoop(src, dst);        }         static void initb2c(char[][]b2c, String[] b2cStr)        {            for (int i = 0; i < b2cStr.length; i++) {                if (b2cStr[i] == null)                    b2c[i] = DoubleByte.B2C_UNMAPPABLE;                else                    b2c[i] = b2cStr[i].toCharArray();            }        }     }     public static class Encoder extends DoubleByte.Encoder {        private DoubleByte.Encoder big5Enc;        private char[][] c2bBmp;        private char[][] c2bSupp;         protected Encoder(Charset cs,                          DoubleByte.Encoder big5Enc,                          char[][] c2bBmp,                          char[][] c2bSupp)        {            super(cs, null, null);            this.big5Enc = big5Enc;            this.c2bBmp = c2bBmp;            this.c2bSupp = c2bSupp;        }         public int encodeBig5(char ch) {            return big5Enc.encodeChar(ch);        }         public int encodeChar(char ch) {            int bb = c2bBmp[ch >> 8][ch & 0xff];            if (bb == UNMAPPABLE_ENCODING)                return encodeBig5(ch);            return bb;        }         public int encodeSupp(int cp) {            if ((cp & 0xf0000) != 0x20000)                return UNMAPPABLE_ENCODING;            return c2bSupp[(cp >> 8) & 0xff][cp & 0xff];        }         public boolean canEncode(char c) {            return encodeChar(c) != UNMAPPABLE_ENCODING;        }         protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) {            char[] sa = src.array();            int sp = src.arrayOffset() + src.position();            int sl = src.arrayOffset() + src.limit();             byte[] da = dst.array();            int dp = dst.arrayOffset() + dst.position();            int dl = dst.arrayOffset() + dst.limit();             try {                while (sp < sl) {                    char c = sa[sp];                    int inSize = 1;                    int bb = encodeChar(c);                    if (bb == UNMAPPABLE_ENCODING) {                        if (Character.isSurrogate(c)) {                            int cp;                            if ((cp = sgp().parse(c, sa, sp, sl)) < 0)                                return sgp.error();                            bb = encodeSupp(cp);                            if (bb == UNMAPPABLE_ENCODING)                                return CoderResult.unmappableForLength(2);                            inSize = 2;                        } else {                            return CoderResult.unmappableForLength(1);                        }                    }                    if (bb > MAX_SINGLEBYTE) {    // DoubleByte                        if (dl - dp < 2)                            return CoderResult.OVERFLOW;                        da[dp++] = (byte)(bb >> 8);                        da[dp++] = (byte)bb;                    } else {                      // SingleByte                        if (dl - dp < 1)                            return CoderResult.OVERFLOW;                        da[dp++] = (byte)bb;                    }                    sp += inSize;                }                return CoderResult.UNDERFLOW;            } finally {                src.position(sp - src.arrayOffset());                dst.position(dp - dst.arrayOffset());            }        }         protected CoderResult encodeBufferLoop(CharBuffer src, ByteBuffer dst) {            int mark = src.position();            try {                while (src.hasRemaining()) {                    int inSize = 1;                    char c = src.get();                    int bb = encodeChar(c);                    if (bb == UNMAPPABLE_ENCODING) {                        if (Character.isSurrogate(c)) {                            int cp;                            if ((cp = sgp().parse(c, src)) < 0)                                return sgp.error();                            bb = encodeSupp(cp);                            if (bb == UNMAPPABLE_ENCODING)                                return CoderResult.unmappableForLength(2);                            inSize = 2;                        } else {                            return CoderResult.unmappableForLength(1);                        }                    }                    if (bb > MAX_SINGLEBYTE) {  // DoubleByte                        if (dst.remaining() < 2)                            return CoderResult.OVERFLOW;                        dst.put((byte)(bb >> 8));                        dst.put((byte)(bb));                    } else {                        if (dst.remaining() < 1)                        return CoderResult.OVERFLOW;                        dst.put((byte)bb);                    }                    mark += inSize;                }                return CoderResult.UNDERFLOW;            } finally {                src.position(mark);            }        }         protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {            if (src.hasArray() && dst.hasArray())                return encodeArrayLoop(src, dst);            else                return encodeBufferLoop(src, dst);        }         static char[] C2B_UNMAPPABLE = new char[0x100];        static {            Arrays.fill(C2B_UNMAPPABLE, (char)UNMAPPABLE_ENCODING);        }        static void initc2b(char[][] c2b, String[] b2cStr, String pua) {            // init c2b/c2bSupp from b2cStr and supp            int b2Min = 0x40;            Arrays.fill(c2b, C2B_UNMAPPABLE);            for (int b1 = 0; b1 < 0x100; b1++) {                String s = b2cStr[b1];                if (s == null)                    continue;                for (int i = 0; i < s.length(); i++) {                    char c = s.charAt(i);                    int hi = c >> 8;                    if (c2b[hi] == C2B_UNMAPPABLE) {                        c2b[hi] = new char[0x100];                        Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);                    }                    c2b[hi][c & 0xff] = (char)((b1 << 8) | (i + b2Min));                }            }            if (pua != null) {        // add the compatibility pua entries                char c = '\ue000';    //first pua character                for (int i = 0; i < pua.length(); i++) {                    char bb = pua.charAt(i);                    if (bb != UNMAPPABLE_DECODING) {                        int hi = c >> 8;                        if (c2b[hi] == C2B_UNMAPPABLE) {                            c2b[hi] = new char[0x100];                            Arrays.fill(c2b[hi], (char)UNMAPPABLE_ENCODING);                        }                        c2b[hi][c & 0xff] = bb;                    }                    c++;                }            }        }    }}