353 lines · 11.5 KB · Java
RawDownload
/* * Copyright (c) 2008, 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; import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.BufferedReader;import java.io.IOException;import java.util.regex.Matcher;import java.util.regex.Pattern;import java.util.*;import java.security.*; public class CharsetMapping {    public final static char UNMAPPABLE_DECODING = '\uFFFD';    public final static int  UNMAPPABLE_ENCODING = 0xFFFD;     char[] b2cSB;                //singlebyte b->c    char[] b2cDB1;               //dobulebyte b->c /db1    char[] b2cDB2;               //dobulebyte b->c /db2     int    b2Min, b2Max;         //min/max(start/end) value of 2nd byte    int    b1MinDB1, b1MaxDB1;   //min/Max(start/end) value of 1st byte/db1    int    b1MinDB2, b1MaxDB2;   //min/Max(start/end) value of 1st byte/db2    int    dbSegSize;     char[] c2b;    char[] c2bIndex;     // Supplementary    char[] b2cSupp;    char[] c2bSupp;     // Composite    Entry[] b2cComp;    Entry[] c2bComp;     public char decodeSingle(int b) {        return b2cSB[b];    }     public char decodeDouble(int b1, int b2) {        if (b2 >= b2Min && b2 < b2Max) {            b2 -= b2Min;            if (b1 >= b1MinDB1 && b1 <= b1MaxDB1) {                b1 -= b1MinDB1;                return b2cDB1[b1 * dbSegSize + b2];            }            if (b1 >= b1MinDB2 && b1 <= b1MaxDB2) {                b1 -= b1MinDB2;                return b2cDB2[b1 * dbSegSize + b2];            }        }        return UNMAPPABLE_DECODING;    }     // for jis0213 all supplementary characters are in 0x2xxxx range,    // so only the xxxx part is now stored, should actually store the    // codepoint value instead.    public char[] decodeSurrogate(int db, char[] cc) {        int end = b2cSupp.length / 2;        int i = Arrays.binarySearch(b2cSupp, 0, end, (char)db);        if (i >= 0) {            Character.toChars(b2cSupp[end + i] + 0x20000, cc, 0);            return cc;        }        return null;    }     public char[] decodeComposite(Entry comp, char[] cc) {        int i = findBytes(b2cComp, comp);        if (i >= 0) {            cc[0] = (char)b2cComp[i].cp;            cc[1] = (char)b2cComp[i].cp2;            return cc;        }        return null;    }     public int encodeChar(char ch) {        int index = c2bIndex[ch >> 8];        if (index == 0xffff)            return UNMAPPABLE_ENCODING;        return c2b[index + (ch & 0xff)];    }     public int encodeSurrogate(char hi, char lo) {        int cp = Character.toCodePoint(hi, lo);        if (cp < 0x20000 || cp >= 0x30000)            return UNMAPPABLE_ENCODING;        int end = c2bSupp.length / 2;        int i = Arrays.binarySearch(c2bSupp, 0, end, (char)cp);        if (i >= 0)            return c2bSupp[end + i];        return UNMAPPABLE_ENCODING;    }     public boolean isCompositeBase(Entry comp) {        if (comp.cp <= 0x31f7 && comp.cp >= 0xe6) {            return (findCP(c2bComp, comp) >= 0);        }        return false;    }     public int encodeComposite(Entry comp) {        int i = findComp(c2bComp, comp);        if (i >= 0)            return c2bComp[i].bs;        return UNMAPPABLE_ENCODING;    }     // init the CharsetMapping object from the .dat binary file    public static CharsetMapping get(final InputStream is) {        return AccessController.doPrivileged(new PrivilegedAction<CharsetMapping>() {            public CharsetMapping run() {                return new CharsetMapping().load(is);            }        });    }     public static class Entry {        public int bs;   //byte sequence reps        public int cp;   //Unicode codepoint        public int cp2;  //CC of composite    }     static Comparator<Entry> comparatorBytes =        new Comparator<Entry>() {            public int compare(Entry m1, Entry m2) {                return m1.bs - m2.bs;            }            public boolean equals(Object obj) {                return this == obj;            }    };     static Comparator<Entry> comparatorCP =        new Comparator<Entry>() {            public int compare(Entry m1, Entry m2) {                return m1.cp - m2.cp;            }            public boolean equals(Object obj) {                return this == obj;            }    };     static Comparator<Entry> comparatorComp =        new Comparator<Entry>() {            public int compare(Entry m1, Entry m2) {                 int v = m1.cp - m2.cp;                 if (v == 0)                   v = m1.cp2 - m2.cp2;                 return v;            }            public boolean equals(Object obj) {                return this == obj;            }    };     static int findBytes(Entry[] a, Entry k) {        return Arrays.binarySearch(a, 0, a.length, k, comparatorBytes);    }     static int findCP(Entry[] a, Entry k) {        return Arrays.binarySearch(a, 0, a.length, k, comparatorCP);    }     static int findComp(Entry[] a, Entry k) {        return Arrays.binarySearch(a, 0, a.length, k, comparatorComp);    }     /*****************************************************************************/    // tags of different charset mapping tables    private final static int MAP_SINGLEBYTE      = 0x1; // 0..256  : c    private final static int MAP_DOUBLEBYTE1     = 0x2; // min..max: c    private final static int MAP_DOUBLEBYTE2     = 0x3; // min..max: c [DB2]    private final static int MAP_SUPPLEMENT      = 0x5; //           db,c    private final static int MAP_SUPPLEMENT_C2B  = 0x6; //           c,db    private final static int MAP_COMPOSITE       = 0x7; //           db,base,cc    private final static int MAP_INDEXC2B        = 0x8; // index table of c->bb     private static final boolean readNBytes(InputStream in, byte[] bb, int N)        throws IOException    {        int off = 0;        while (N > 0) {            int n = in.read(bb, off, N);            if (n == -1)                return false;            N = N - n;            off += n;        }        return true;    }     int off = 0;    byte[] bb;    private char[] readCharArray() {        // first 2 bytes are the number of "chars" stored in this table        int size  = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);        char [] cc = new char[size];        for (int i = 0; i < size; i++) {            cc[i] = (char)(((bb[off++]&0xff)<<8) | (bb[off++]&0xff));        }        return cc;    }     void readSINGLEBYTE() {        char[] map = readCharArray();        for (int i = 0; i < map.length; i++) {            char c = map[i];            if (c != UNMAPPABLE_DECODING) {                c2b[c2bIndex[c >> 8] + (c&0xff)] = (char)i;            }        }        b2cSB = map;    }     void readINDEXC2B() {        char[] map = readCharArray();        for (int i = map.length - 1; i >= 0; i--) {            if (c2b == null && map[i] != -1) {                c2b = new char[map[i] + 256];                Arrays.fill(c2b, (char)UNMAPPABLE_ENCODING);                break;            }        }        c2bIndex = map;    }     char[] readDB(int b1Min, int b2Min, int segSize) {        char[] map = readCharArray();        for (int i = 0; i < map.length; i++) {            char c = map[i];            if (c != UNMAPPABLE_DECODING) {                int b1 = i / segSize;                int b2 = i % segSize;                int b = (b1 + b1Min)* 256 + (b2 + b2Min);                //System.out.printf("    DB %x\t%x%n", b, c & 0xffff);                c2b[c2bIndex[c >> 8] + (c&0xff)] = (char)(b);            }        }        return map;    }     void readDOUBLEBYTE1() {        b1MinDB1 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);        b1MaxDB1 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);        b2Min =    ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);        b2Max =    ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);        dbSegSize = b2Max - b2Min + 1;        b2cDB1 = readDB(b1MinDB1, b2Min, dbSegSize);    }     void readDOUBLEBYTE2() {        b1MinDB2 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);        b1MaxDB2 = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);        b2Min =    ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);        b2Max =    ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);        dbSegSize = b2Max - b2Min + 1;        b2cDB2 = readDB(b1MinDB2, b2Min, dbSegSize);    }     void readCOMPOSITE() {        char[] map = readCharArray();        int mLen = map.length/3;        b2cComp = new Entry[mLen];        c2bComp = new Entry[mLen];        for (int i = 0, j= 0; i < mLen; i++) {            Entry m = new Entry();            m.bs = map[j++];            m.cp = map[j++];            m.cp2 = map[j++];            b2cComp[i] = m;            c2bComp[i] = m;        }        Arrays.sort(c2bComp, 0, c2bComp.length, comparatorComp);    }     CharsetMapping load(InputStream in) {        try {            // The first 4 bytes are the size of the total data followed in            // this .dat file.            int len = ((in.read()&0xff) << 24) | ((in.read()&0xff) << 16) |                      ((in.read()&0xff) << 8) | (in.read()&0xff);            bb = new byte[len];            off = 0;            //System.out.printf("In : Total=%d%n", len);            // Read in all bytes            if (!readNBytes(in, bb, len))                throw new RuntimeException("Corrupted data file");            in.close();             while (off < len) {                int type = ((bb[off++]&0xff)<<8) | (bb[off++]&0xff);                switch(type) {                case MAP_INDEXC2B:                    readINDEXC2B();                    break;                case MAP_SINGLEBYTE:                    readSINGLEBYTE();                    break;                case MAP_DOUBLEBYTE1:                    readDOUBLEBYTE1();                    break;                case MAP_DOUBLEBYTE2:                    readDOUBLEBYTE2();                    break;                case MAP_SUPPLEMENT:                    b2cSupp = readCharArray();                    break;                case MAP_SUPPLEMENT_C2B:                    c2bSupp = readCharArray();                    break;                case MAP_COMPOSITE:                    readCOMPOSITE();                    break;                default:                    throw new RuntimeException("Corrupted data file");                }            }            bb = null;            return this;        } catch (IOException x) {            x.printStackTrace();            return null;        }    }}