]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/tools/misc/src/com/ibm/icu/dev/tool/charsetdet/mbcs/EUCTool.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / tools / misc / src / com / ibm / icu / dev / tool / charsetdet / mbcs / EUCTool.java
1 /*\r
2  ***********************************************************************\r
3  *\r
4  * Copyright (C) 2005-2010, International Business Machines Corporation and\r
5  * others. All Rights Reserved.\r
6  *\r
7  ***********************************************************************\r
8  *\r
9  * euc_tool\r
10  *\r
11  *    This tool produces the character usage frequency statistics for the EUC family\r
12  *    of charsets, for use by the ICU charset detectors.\r
13  *\r
14  *    usage:  java euc_tool [-d] [directory path]\r
15  *\r
16  *        -d:   Produce the data in a form to be exported to the ICU implementation\r
17  *              Default is to produce an informative dump.\r
18  *\r
19  *        directory path\r
20  *              Source directory for the files to be analyzed.\r
21  *              Default is the current directory.\r
22  *              There should be three subdirectories under the specified directory, one\r
23  *              each for EUC_JP, EUC_CN and EUC_KR.  Within each of these subdirectories\r
24  *              should be text files in the specified encoding.\r
25  *\r
26  */\r
27 \r
28 package com.ibm.icu.dev.tool.charsetdet.mbcs;\r
29 \r
30 import java.io.File;\r
31 import java.io.FileInputStream;\r
32 import java.util.ArrayList;\r
33 import java.util.Arrays;\r
34 import java.util.HashMap;\r
35 import java.util.List;\r
36 \r
37 public class EUCTool {\r
38 \r
39     // The file buffer and file data length need to be out in class member variables\r
40     //  so that the code lifted from charSet detection for scanning the multi-byte chars\r
41     //  can see them conveniently.\r
42     byte []    buf = new byte[1000000];\r
43     int        fileSize;\r
44 \r
45     boolean    option_d = false;    // data option.  Produce exportable data\r
46     boolean    option_v = true;     // verbose informaional output.\r
47 \r
48 \r
49 \r
50     public static void main(String[] args) {\r
51         EUCTool  This = new EUCTool();\r
52         This.Main(args);\r
53     }\r
54 \r
55 \r
56 \r
57     void Main(String[] args) {\r
58         int i;\r
59 \r
60         //\r
61         //   Command Line Option Handling\r
62         //\r
63         String     dirName  = ".";\r
64         for (i=0; i<args.length; i++) {\r
65             if (args[i].equals("-d")) {\r
66                 option_d = true;\r
67                 option_v = false;\r
68                 continue;\r
69             }\r
70             if (args[i].startsWith("-")) {\r
71                 System.err.println("Unrecongized option: " + args[i]);\r
72                 System.exit(-1);\r
73             }\r
74             dirName = args[i];\r
75         }\r
76 \r
77         //\r
78         //  Verify that the specified directory exists.\r
79         //\r
80         File dir = new File(dirName);\r
81         if (dir.isDirectory() == false) {\r
82             System.err.println("\"" + dirName + "\" is not a directory");\r
83             System.exit(-1);\r
84         }\r
85 \r
86         //\r
87         //  Do each subdirectory of the specified directory.  There should be\r
88         //    one per each encoding - euc-kr, euc-cn, euc-jp\r
89         //\r
90         File[] dirs  = dir.listFiles();\r
91         for (i=0; i<dirs.length; i++) {\r
92             if (dirs[i].isDirectory()) {\r
93                 String nam = dirs[i].getName();\r
94                 if (nam.equalsIgnoreCase("CVS")) {\r
95                     continue;\r
96                 }\r
97                 processDir(dirs[i]);\r
98             }\r
99         }\r
100     }\r
101 \r
102     //\r
103     // Collect statistics from all ordinary files in a specified directory.\r
104     //\r
105     void processDir(File dir) {\r
106         int      totalMbcsChars  = 0;\r
107         HashMap  m = new HashMap(10000);\r
108         int      i;\r
109 \r
110         System.out.println(dir.getName());\r
111         File[] files = dir.listFiles();\r
112         for (i=0; i<files.length; i++) {\r
113             try {\r
114                 if (files[i].isFile()) {\r
115                     FileInputStream is = new FileInputStream(files[i]);\r
116                     fileSize = is.read(buf);\r
117                     if (option_v) {\r
118                         System.out.println(files[i].getPath());\r
119                         System.out.println("  " + fileSize + " bytes.");\r
120                     }\r
121                     iteratedChar ichar = new iteratedChar();\r
122                     int fileChars     = 0;\r
123                     int fileMbcsChars = 0;\r
124                     int errs          = 0;\r
125 \r
126                     while (nextChar(ichar)) {\r
127                         if (ichar.error == true) {\r
128                             errs++;\r
129                             continue;\r
130                         }\r
131                         fileChars++;\r
132                         if (ichar.charValue > 255) {\r
133                             fileMbcsChars++;\r
134                             totalMbcsChars++;\r
135                         }\r
136                         if (ichar.charValue <= 255) {\r
137                             // Don't keep occurence statistics for the single byte range\r
138                             continue;\r
139                         }\r
140 \r
141                         //\r
142                         //  Frequency of occurence statistics are accumulated in a map.\r
143                         //\r
144                         ChEl  keyEl = new ChEl(ichar.charValue, 0);\r
145                         ChEl  valEl = (ChEl)m.get(keyEl);\r
146                         if (valEl == null) {\r
147                             m.put(keyEl, keyEl);\r
148                             valEl = keyEl;\r
149                         }\r
150                         valEl.occurences++;\r
151                     }\r
152                     if (option_v) {\r
153                         System.out.println("  " + fileChars     + " Chars");\r
154                         System.out.println("  " + fileMbcsChars + " mbcs Chars");\r
155                         System.out.println("  " + errs          + " errors");\r
156                         System.out.println("\n");\r
157                     }\r
158                 }\r
159             }\r
160             catch (Exception e) {\r
161                 System.err.println("Exception:" + e);\r
162 \r
163             }\r
164         }\r
165 \r
166         //\r
167         //  We've processed through all of the files.\r
168         //     sort and dump out the frequency statistics.\r
169         //\r
170         Object [] encounteredChars = m.values().toArray();\r
171         Arrays.sort(encounteredChars);\r
172         int cumulativeChars = 0;\r
173         int cumulativePercent = 0;\r
174         if (option_v) {\r
175             System.out.println("# <char code> <occurences>  <Cumulative %>");\r
176             for (i=0; i<encounteredChars.length; i++) {\r
177                 ChEl c = (ChEl)encounteredChars[i];\r
178                 cumulativeChars += c.occurences;\r
179                 cumulativePercent = cumulativeChars*100/totalMbcsChars;\r
180                 System.out.println(i + "   " + Integer.toHexString(c.charCode) + "        " \r
181                         + c.occurences + "         " + cumulativePercent);\r
182             }\r
183         }\r
184         if (option_d) {\r
185             //\r
186             //   Output the list of characters formatted for pasting into a\r
187             //     Java source code array initializer.\r
188             //     Resort into order based on the character code value, not\r
189             //      on frequency of occurence.\r
190             //\r
191             List  charList = new ArrayList();\r
192             \r
193             for (i=0; i<100 && cumulativePercent<50; i++) {\r
194                 ChEl c = (ChEl)encounteredChars[i];\r
195                 cumulativeChars += c.occurences;\r
196                 cumulativePercent = cumulativeChars*100/totalMbcsChars;\r
197                 charList.add(new Integer(c.charCode));\r
198             }\r
199             Object [] sortedChars = charList.toArray();\r
200             Arrays.sort(sortedChars);\r
201             \r
202             System.out.print("          {");\r
203             for (i=0; i<sortedChars.length; i++) {\r
204                 if (i != 0) {\r
205                     System.out.print(", ");\r
206                     if ((i)%10 == 0) {\r
207                         System.out.print("\n           ");\r
208                     }\r
209                 }\r
210                 int cp = ((Integer)sortedChars[i]).intValue();\r
211                 System.out.print("0x" + Integer.toHexString(cp));\r
212             }\r
213             System.out.println("};");\r
214         }\r
215     }\r
216     \r
217     //\r
218     //  This is a little class containing a\r
219     //    multi-byte character value and an occurence count for that char.\r
220     //  Instances of this class are kept in the collection that accumulates statistics\r
221     //\r
222     //  WARNING:  this class's natural ordering (from Comparable) and equals()\r
223     //            are inconsistent.\r
224 \r
225     static class ChEl implements Comparable {\r
226         int charCode;\r
227         int occurences;\r
228 \r
229         ChEl(int c, int o) {\r
230             charCode = c;\r
231             occurences = o;\r
232         }\r
233 \r
234         // Equals needs to work with a map, with the charCode as the key.\r
235         //   For insertion/lookup, we care about the char code only, not the occurence count.\r
236         public boolean equals(Object other) {\r
237             ChEl o = (ChEl)other;\r
238             return o.charCode == this.charCode;\r
239         }\r
240 \r
241         // Hashcode needs to be compatible with equals\r
242         //   We're using this in a hashMap!\r
243         public int hashCode() {\r
244             return charCode;\r
245         }\r
246 \r
247         // We want to be able to sort the results by frequency of occurence\r
248         //   Compare backwards.  We want most frequent chars first.\r
249         public int compareTo(Object other) {\r
250             ChEl o = (ChEl)other;\r
251             return (this.occurences> o.occurences? -1 :\r
252                    (this.occurences==o.occurences?  0 : 1));\r
253         }\r
254 \r
255     }\r
256 \r
257     //\r
258     // iteratedChar is copied and slightly hacked from the similar calss in CharsetRecog_mbcs\r
259     //              Pulls out one logical char according to the rules of EUC encoding.\r
260     //\r
261     class iteratedChar {\r
262         int             charValue = 0;             // The char value is a value from the encoding.\r
263                                                    //   It's meaning is not well defined, other than\r
264                                                    //   different encodings\r
265         int             index     = 0;\r
266         int             nextIndex = 0;\r
267         boolean         error     = false;\r
268         boolean         done      = false;\r
269 \r
270         void reset() {\r
271             charValue = 0;\r
272             index     = -1;\r
273             nextIndex = 0;\r
274             error     = false;\r
275             done      = false;\r
276         }\r
277 \r
278         int nextByte() {\r
279             if (nextIndex >= fileSize) {\r
280                 done = true;\r
281                 return -1;\r
282             }\r
283             int byteValue = (int)buf[nextIndex++] & 0x00ff;\r
284             return byteValue;\r
285         }\r
286     }\r
287 \r
288 \r
289     boolean nextChar(iteratedChar it) {\r
290         it.index = it.nextIndex;\r
291         it.error = false;\r
292         int firstByte  = 0;\r
293         int secondByte = 0;\r
294         int thirdByte  = 0;\r
295         int fourthByte = 0;\r
296 \r
297         buildChar: {\r
298             firstByte = it.charValue = it.nextByte();\r
299             if (firstByte < 0) {\r
300                 // Ran off the end of the input data\r
301                 it.done = true;\r
302                 break buildChar;\r
303             }\r
304             if (firstByte <= 0x8d) {\r
305                 // single byte char\r
306                 break buildChar;\r
307             }\r
308 \r
309             secondByte = it.nextByte();\r
310             it.charValue = (it.charValue << 8) | secondByte;\r
311 \r
312             if (firstByte >= 0xA1 && firstByte <= 0xfe) {\r
313                 // Two byte Char\r
314                 if (secondByte < 0xa1) {\r
315                     it.error = true;\r
316                 }\r
317                 break buildChar;\r
318             }\r
319             if (firstByte == 0x8e) {\r
320                 // Code Set 2.\r
321                 //   In EUC-JP, total char size is 2 bytes, only one byte of actual char value.\r
322                 //   In EUC-TW, total char size is 4 bytes, three bytes contribute to char value.\r
323                 // We don't know which we've got.\r
324                 // Treat it like EUC-JP.  If the data really was EUC-TW, the following two\r
325                 //   bytes will look like a well formed 2 byte char.\r
326                 if (secondByte < 0xa1) {\r
327                     it.error = true;\r
328                 }\r
329                 break buildChar;\r
330             }\r
331 \r
332             if (firstByte == 0x8f) {\r
333                 // Code set 3.\r
334                 // Three byte total char size, two bytes of actual char value.\r
335                 thirdByte    = it.nextByte();\r
336                 it.charValue = (it.charValue << 8) | thirdByte;\r
337                 if (thirdByte < 0xa1) {\r
338                     it.error = true;\r
339                 }\r
340             }\r
341             \r
342         }\r
343         if (it.error) {\r
344             System.out.println("Error " + Integer.toHexString(firstByte) + " " + Integer.toHexString(secondByte)\r
345                     + " " +  Integer.toHexString(thirdByte) + " " + Integer.toHexString(fourthByte));\r
346         }\r
347         return (it.done == false);\r
348     }\r
349 }\r
350 \r
351 \r
352 \r
353 \r