1/*
2 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package build.tools.charsetmapping;
27
28import java.io.*;
29import java.util.regex.*;
30import java.util.*;
31import static build.tools.charsetmapping.Utils.*;
32
33public class JIS0213 {
34
35    // regex pattern to parse the "jis0213.map" file
36    static Pattern sjis0213 = Pattern.compile("0x(\\p{XDigit}++)\\s++U\\+(\\p{XDigit}++)(?:\\+(\\p{XDigit}++))?\\s++#.*");
37
38    static void genClass(String argv[]) throws IOException
39    {
40        InputStream in = new FileInputStream(argv[0]) ;
41        OutputStream out = new FileOutputStream(argv[1]);
42
43        int[] sb = new int[0x100];                         // singlebyte
44        int[] db = new int[0x10000];                       // doublebyte
45        int[] indexC2B = new int[256];
46        Entry[] supp = new Entry[0x10000];
47        Entry[] comp = new Entry[0x100];
48        int suppTotal = 0;
49        int compTotal = 0;
50
51        int b1Min1 = 0x81;
52        int b1Max1 = 0x9f;
53        int b1Min2 = 0xe0;
54        int b1Max2 = 0xfc;
55        int b2Min = 0x40;
56        int b2Max = 0xfe;
57
58        //init
59        for (int i = 0; i < 0x80; i++) sb[i] = i;
60        for (int i = 0x80; i < 0x100; i++) sb[i] = UNMAPPABLE_DECODING;
61        for (int i = 0; i < 0x10000; i++) db[i] = UNMAPPABLE_DECODING;
62        try {
63            Parser p = new Parser(in, sjis0213);
64            Entry  e = null;
65            while ((e = p.next()) != null) {
66                if (e.cp2 != 0) {
67                    comp[compTotal++] = e;
68                } else {
69                    if (e.cp <= 0xffff) {
70                        if (e.bs <= 0xff)
71                            sb[e.bs] = e.cp;
72                        else
73                            db[e.bs] = e.cp;
74                        indexC2B[e.cp>>8] = 1;
75                    } else {
76                        supp[suppTotal++] = e;
77                    }
78                }
79            }
80            ByteArrayOutputStream baos = new ByteArrayOutputStream();
81            // c2b Index Table, always the first one
82            writeINDEXC2B(baos, indexC2B);
83            writeSINGLEBYTE(baos, sb);
84            writeDOUBLEBYTE1(baos, db, b1Min1, b1Max1, b2Min, b2Max);
85            writeDOUBLEBYTE2(baos, db, b1Min2, b1Max2, b2Min, b2Max);
86            writeSUPPLEMENT(baos, supp, suppTotal);
87            writeCOMPOSITE(baos, comp, compTotal);
88            writeSIZE(out, baos.size());
89            baos.writeTo(out);
90            out.close();
91        } catch (Exception x) {
92            x.printStackTrace();
93        }
94    }
95
96    static Comparator<Entry> comparatorCP =
97        new Comparator<Entry>() {
98            public int compare(Entry m1, Entry m2) {
99                return m1.cp - m2.cp;
100            }
101            public boolean equals(Object obj) {
102                return this == obj;
103            }
104    };
105
106    // tags of different charset mapping tables
107    private final static int MAP_SINGLEBYTE      = 0x1; // 0..256  : c
108    private final static int MAP_DOUBLEBYTE1     = 0x2; // min..max: c
109    private final static int MAP_DOUBLEBYTE2     = 0x3; // min..max: c [DB2]
110    private final static int MAP_SUPPLEMENT      = 0x5; //           db,c
111    private final static int MAP_SUPPLEMENT_C2B  = 0x6; //           c,db
112    private final static int MAP_COMPOSITE       = 0x7; //           db,base,cc
113    private final static int MAP_INDEXC2B        = 0x8; // index table of c->bb
114
115    private static final void writeShort(OutputStream out, int data)
116        throws IOException
117    {
118        out.write((data >>> 8) & 0xFF);
119        out.write((data      ) & 0xFF);
120    }
121
122    private static final void writeShortArray(OutputStream out,
123                                              int type,
124                                              int[] array,
125                                              int off,
126                                              int size)   // exclusive
127        throws IOException
128    {
129        writeShort(out, type);
130        writeShort(out, size);
131        for (int i = off; i < size; i++) {
132            writeShort(out, array[off+i]);
133        }
134    }
135
136    private static final void writeSIZE(OutputStream out, int data)
137        throws IOException
138    {
139        out.write((data >>> 24) & 0xFF);
140        out.write((data >>> 16) & 0xFF);
141        out.write((data >>>  8) & 0xFF);
142        out.write((data       ) & 0xFF);
143    }
144
145    private static void writeINDEXC2B(OutputStream out, int[] indexC2B)
146        throws IOException
147    {
148        writeShort(out, MAP_INDEXC2B);
149        writeShort(out, indexC2B.length);
150        int off = 0;
151        for (int i = 0; i < indexC2B.length; i++) {
152            if (indexC2B[i] != 0) {
153                writeShort(out, off);
154                off += 256;
155            } else {
156                writeShort(out, -1);
157            }
158        }
159    }
160
161    private static void writeSINGLEBYTE(OutputStream out, int[] sb)
162        throws IOException
163    {
164        writeShortArray(out, MAP_SINGLEBYTE, sb, 0, 256);
165    }
166
167    private static void writeDOUBLEBYTE(OutputStream out,
168                                        int type,
169                                        int[] db,
170                                        int b1Min, int b1Max,
171                                        int b2Min, int b2Max)
172        throws IOException
173    {
174        writeShort(out, type);
175        writeShort(out, b1Min);
176        writeShort(out, b1Max);
177        writeShort(out, b2Min);
178        writeShort(out, b2Max);
179        writeShort(out, (b1Max - b1Min + 1) * (b2Max - b2Min + 1));
180
181        for (int b1 = b1Min; b1 <= b1Max; b1++) {
182            for (int b2 = b2Min; b2 <= b2Max; b2++) {
183                writeShort(out, db[b1 * 256 + b2]);
184            }
185        }
186    }
187
188    private static void writeDOUBLEBYTE1(OutputStream out,
189                                        int[] db,
190                                        int b1Min, int b1Max,
191                                        int b2Min, int b2Max)
192        throws IOException
193    {
194        writeDOUBLEBYTE(out, MAP_DOUBLEBYTE1, db, b1Min, b1Max, b2Min, b2Max);
195    }
196
197    private static void writeDOUBLEBYTE2(OutputStream out,
198                                        int[] db,
199                                        int b1Min, int b1Max,
200                                        int b2Min, int b2Max)
201        throws IOException
202    {
203        writeDOUBLEBYTE(out, MAP_DOUBLEBYTE2, db, b1Min, b1Max, b2Min, b2Max);
204    }
205
206    // the c2b table is output as well
207    private static void writeSUPPLEMENT(OutputStream out, Entry[] supp, int size)
208        throws IOException
209    {
210        writeShort(out, MAP_SUPPLEMENT);
211        writeShort(out, size * 2);
212        // db at first half, cc at the low half
213        for (int i = 0; i < size; i++) {
214            writeShort(out, supp[i].bs);
215        }
216        for (int i = 0; i < size; i++) {
217            writeShort(out, supp[i].cp);
218        }
219
220        //c2b
221        writeShort(out, MAP_SUPPLEMENT_C2B);
222        writeShort(out, size*2);
223        Arrays.sort(supp, 0, size, comparatorCP);
224        for (int i = 0; i < size; i++) {
225            writeShort(out, supp[i].cp);
226        }
227        for (int i = 0; i < size; i++) {
228            writeShort(out, supp[i].bs);
229        }
230    }
231
232    private static void writeCOMPOSITE(OutputStream out, Entry[] comp, int size)
233        throws IOException
234    {
235        writeShort(out, MAP_COMPOSITE);
236        writeShort(out, size*3);
237        // comp is sorted already
238        for (int i = 0; i < size; i++) {
239            writeShort(out, (char)comp[i].bs);
240            writeShort(out, (char)comp[i].cp);
241            writeShort(out, (char)comp[i].cp2);
242        }
243    }
244}
245