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.File;
29import java.io.InputStream;
30import java.io.InputStreamReader;
31import java.io.OutputStream;
32import java.io.BufferedReader;
33import java.io.IOException;
34import java.util.regex.Matcher;
35import java.util.regex.Pattern;
36import java.util.Scanner;
37import java.util.Formatter;
38
39public class Utils {
40
41    public final static char UNMAPPABLE_DECODING = '\uFFFD';
42    public final static int  UNMAPPABLE_ENCODING = 0xFFFD;
43
44    public static class Entry {
45        public int bs;   //byte sequence reps
46        public int cp;   //Unicode codepoint
47        public int cp2;  //CC of composite
48
49        public Entry () {}
50        public Entry (int bytes, int cp, int cp2) {
51            this.bs = bytes;
52            this.cp = cp;
53            this.cp2 = cp2;
54        }
55    }
56
57    public static class Parser {
58        static final Pattern basic = Pattern.compile("(?:0x)?(\\p{XDigit}++)\\s++(?:0x)?(\\p{XDigit}++)?\\s*+.*");
59        static final int gBS = 1;
60        static final int gCP = 2;
61        static final int gCP2 = 3;
62
63        BufferedReader reader;
64        boolean closed;
65        Matcher matcher;
66        int gbs, gcp, gcp2;
67
68        public Parser (InputStream in, Pattern p, int gbs, int gcp, int gcp2)
69            throws IOException
70        {
71            this.reader = new BufferedReader(new InputStreamReader(in));
72            this.closed = false;
73            this.matcher = p.matcher("");
74            this.gbs = gbs;
75            this.gcp = gcp;
76            this.gcp2 = gcp2;
77        }
78
79        public Parser (InputStream in, Pattern p) throws IOException {
80            this(in, p, gBS, gCP, gCP2);
81        }
82
83        public Parser (InputStream in) throws IOException {
84            this(in, basic, gBS, gCP, gCP2);
85        }
86
87        protected boolean isDirective(String line) {
88            return line.startsWith("#");
89        }
90
91        protected Entry parse(Matcher matcher, Entry mapping) {
92            mapping.bs = Integer.parseInt(matcher.group(gbs), 16);
93            mapping.cp = Integer.parseInt(matcher.group(gcp), 16);
94            if (gcp2 <= matcher.groupCount() &&
95                matcher.group(gcp2) != null)
96                mapping.cp2 = Integer.parseInt(matcher.group(gcp2), 16);
97            else
98                mapping.cp2 = 0;
99            return mapping;
100        }
101
102        public Entry next() throws Exception {
103            return next(new Entry());
104        }
105
106        // returns null and closes the input stream if the eof has beenreached.
107        public Entry next(Entry mapping) throws Exception {
108            if (closed)
109                return null;
110            String line;
111            while ((line = reader.readLine()) != null) {
112                if (isDirective(line))
113                    continue;
114                matcher.reset(line);
115                if (!matcher.lookingAt()) {
116                    //System.out.println("Missed: " + line);
117                    continue;
118                }
119                return parse(matcher, mapping);
120            }
121            reader.close();
122            closed = true;
123            return null;
124        }
125    }
126
127    public static class Output {
128        private Formatter out;
129
130        public Output(Formatter out) {
131            this.out = out;
132        }
133
134        public void close() {
135            out.close();
136        }
137
138        private void toChar(String fmt, char c) {
139            switch (c) {
140            case '\b':
141                out.format("\\b"); break;
142            case '\t':
143                out.format("\\t"); break;
144            case '\n':
145                out.format("\\n"); break;
146            case '\f':
147                out.format("\\f"); break;
148            case '\r':
149                out.format("\\r"); break;
150            case '\"':
151                out.format("\\\""); break;
152            case '\'':
153                out.format("\\'"); break;
154            case '\\':
155                out.format("\\\\"); break;
156            default:
157                out.format(fmt, c & 0xffff);
158            }
159        }
160
161        public void format(String fmt, Object ... args) {
162            out.format(fmt, args);
163        }
164
165        public void format(char[] cc, int off, int end, String closure) {
166            while (off < end) {
167                out.format("        \"");
168                for (int j = 0; j < 8; j++) {
169                    if (off == end)
170                        break;
171                    toChar("\\u%04X", cc[off++]);
172                }
173                if (off == end)
174                    out.format("\" %s%n", closure);
175                else
176                    out.format("\" + %n");
177            }
178        }
179
180        public void format(char[] cc, String closure) {
181            format(cc, 0, cc.length, closure);
182        }
183
184        public void format(char[] db, int b1, int b2Min, int b2Max,
185                           String closure)
186        {
187            char[] cc = new char[b2Max - b2Min + 1];
188            int off = 0;
189            for (int b2 = b2Min; b2 <= b2Max; b2++) {
190                cc[off++] = db[(b1 << 8) | b2];
191            }
192            format(cc, 0, cc.length, closure);
193        }
194
195        public void format(char[] date) {
196            int off = 0;
197            int end = date.length;
198            while (off < end) {
199                out.format("        ");
200                for (int j = 0; j < 8 && off < end; j++) {
201                    toChar("'\\u%04X',", date[off++]);
202                }
203                out.format("%n");
204            }
205        }
206    }
207
208    public static String getCopyright(File f) throws IOException {
209        Scanner s = new Scanner(f, "ISO-8859-1");
210        StringBuilder sb = new StringBuilder();
211        while (s.hasNextLine()) {
212            String ln = s.nextLine();
213            sb.append(ln + "\n");
214            // assume we have the copyright as the first comment
215            if (ln.matches("^\\s\\*\\/$"))
216                break;
217        }
218        s.close();
219        return sb.toString();
220    }
221}
222