]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/dev/tool/localeconverter/XLIFF2ICUConverter.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / dev / tool / localeconverter / XLIFF2ICUConverter.java
1 /*\r
2  ******************************************************************************\r
3  * Copyright (C) 2003-2009, International Business Machines Corporation and   *\r
4  * others. All Rights Reserved.                                               *\r
5  ******************************************************************************\r
6  */\r
7 \r
8 package com.ibm.icu.dev.tool.localeconverter;\r
9 \r
10 import com.ibm.icu.dev.tool.UOption;\r
11 \r
12 import org.w3c.dom.Document;\r
13 import org.w3c.dom.Node;\r
14 import org.w3c.dom.NamedNodeMap;\r
15 import org.w3c.dom.NodeList;\r
16 import org.xml.sax.ErrorHandler;\r
17 import org.xml.sax.InputSource;\r
18 import org.xml.sax.SAXException;\r
19 import org.xml.sax.SAXParseException;\r
20 import javax.xml.parsers.DocumentBuilder;\r
21 import javax.xml.parsers.DocumentBuilderFactory;\r
22 import javax.xml.validation.Schema;\r
23 import javax.xml.validation.SchemaFactory;\r
24 import javax.xml.XMLConstants;\r
25 \r
26 import java.io.*;\r
27 import java.util.*;\r
28 import java.text.*;\r
29 \r
30 public final class XLIFF2ICUConverter {\r
31     \r
32     /**\r
33      * These must be kept in sync with getOptions().\r
34      */\r
35     private static final int HELP1 = 0;\r
36     private static final int HELP2 = 1;\r
37     private static final int SOURCEDIR = 2;\r
38     private static final int DESTDIR = 3;\r
39     private static final int TARGETONLY = 4;\r
40     private static final int SOURCEONLY = 5;\r
41     private static final int MAKE_SOURCE_ROOT = 6;\r
42     private static final int XLIFF_1_0 = 7;\r
43        \r
44     private static final UOption[] options = new UOption[] {\r
45         UOption.HELP_H(),\r
46         UOption.HELP_QUESTION_MARK(),\r
47         UOption.SOURCEDIR(),\r
48         UOption.DESTDIR(),\r
49         UOption.create("target-only", 't', UOption.OPTIONAL_ARG),\r
50         UOption.create("source-only", 'c', UOption.OPTIONAL_ARG),\r
51         UOption.create("make-source-root", 'r', UOption.NO_ARG),\r
52         UOption.create("xliff-1.0", 'x', UOption.NO_ARG)\r
53     };\r
54     \r
55     private static final int ARRAY_RESOURCE     = 0;\r
56     private static final int ALIAS_RESOURCE     = 1;\r
57     private static final int BINARY_RESOURCE    = 2;\r
58     private static final int INTEGER_RESOURCE   = 3;\r
59     private static final int INTVECTOR_RESOURCE = 4;\r
60     private static final int TABLE_RESOURCE     = 5;\r
61     \r
62     private static final String NEW_RESOURCES[] = {\r
63         "x-icu-array",\r
64         "x-icu-alias",\r
65         "x-icu-binary",\r
66         "x-icu-integer",\r
67         "x-icu-intvector",\r
68         "x-icu-table"\r
69     };\r
70     \r
71     private static final String OLD_RESOURCES[] = {\r
72         "array",\r
73         "alias",\r
74         "bin",\r
75         "int",\r
76         "intvector",\r
77         "table"\r
78     };\r
79     \r
80     private String resources[];\r
81     \r
82     private static final String ROOT            = "root";\r
83     private static final String RESTYPE         = "restype";\r
84     private static final String RESNAME         = "resname";\r
85     //private static final String YES             = "yes";\r
86     //private static final String NO              = "no";\r
87     private static final String TRANSLATE       = "translate";\r
88     //private static final String BODY            = "body";\r
89     private static final String GROUPS          = "group";\r
90     private static final String FILES           = "file";\r
91     private static final String TRANSUNIT       = "trans-unit";\r
92     private static final String BINUNIT         = "bin-unit";\r
93     private static final String BINSOURCE       = "bin-source";\r
94     //private static final String TS              = "ts";\r
95     //private static final String ORIGINAL        = "original";\r
96     private static final String SOURCELANGUAGE  = "source-language";\r
97     private static final String TARGETLANGUAGE  = "target-language";\r
98     private static final String TARGET          = "target";\r
99     private static final String SOURCE          = "source";\r
100     private static final String NOTE            = "note";\r
101     private static final String XMLLANG         = "xml:lang";\r
102     private static final String FILE            = "file";\r
103     private static final String INTVECTOR       = "intvector";\r
104     private static final String ARRAYS          = "array";\r
105     private static final String STRINGS         = "string";\r
106     private static final String BIN             = "bin";\r
107     private static final String INTS            = "int";\r
108     private static final String TABLE           = "table";\r
109     private static final String IMPORT          = "import";\r
110     private static final String HREF            = "href";\r
111     private static final String EXTERNALFILE    = "external-file";\r
112     private static final String INTERNALFILE    = "internal-file";\r
113     private static final String ALTTRANS        = "alt-trans";\r
114     private static final String CRC             = "crc";\r
115     private static final String ALIAS           = "alias";\r
116     private static final String LINESEP         = System.getProperty("line.separator");\r
117     private static final String BOM             = "\uFEFF";\r
118     private static final String CHARSET         = "UTF-8";\r
119     private static final String OPENBRACE       = "{";\r
120     private static final String CLOSEBRACE      = "}";\r
121     private static final String COLON           = ":";\r
122     private static final String COMMA           = ",";\r
123     private static final String QUOTE           = "\"";\r
124     private static final String COMMENTSTART    = "/**";\r
125     private static final String COMMENTEND      = " */";\r
126     private static final String TAG             = " * @";\r
127     private static final String COMMENTMIDDLE   = " * ";\r
128     private static final String SPACE           = " ";\r
129     private static final String INDENT          = "    ";\r
130     private static final String EMPTY           = "";\r
131     private static final String ID              = "id";\r
132     \r
133     public static void main(String[] args) {\r
134         XLIFF2ICUConverter cnv = new XLIFF2ICUConverter();\r
135         cnv.processArgs(args);\r
136     }\r
137     private String    sourceDir      = null;\r
138     //private String    fileName       = null;\r
139     private String    destDir        = null;\r
140     private boolean   targetOnly     = false;\r
141     private String    targetFileName = null; \r
142     private boolean   makeSourceRoot = false;\r
143     private String    sourceFileName = null;\r
144     private boolean   sourceOnly     = false;\r
145     private boolean   xliff10        = false;\r
146     \r
147     private void processArgs(String[] args) {\r
148         int remainingArgc = 0;\r
149         try{\r
150             remainingArgc = UOption.parseArgs(args, options);\r
151         }catch (Exception e){\r
152             System.err.println("ERROR: "+ e.toString());\r
153             usage();\r
154         }\r
155         if(args.length==0 || options[HELP1].doesOccur || options[HELP2].doesOccur) {\r
156             usage();\r
157         }\r
158         if(remainingArgc==0){\r
159             System.err.println("ERROR: Either the file name to be processed is not "+\r
160                                "specified or the it is specified after the -t/-c \n"+\r
161                                "option which has an optional argument. Try rearranging "+\r
162                                "the options.");\r
163             usage();\r
164         }\r
165         if(options[SOURCEDIR].doesOccur) {\r
166             sourceDir = options[SOURCEDIR].value;\r
167         }\r
168         \r
169         if(options[DESTDIR].doesOccur) {\r
170             destDir = options[DESTDIR].value;\r
171         }\r
172         \r
173         if(options[TARGETONLY].doesOccur){\r
174             targetOnly = true;\r
175             targetFileName = options[TARGETONLY].value;\r
176         }\r
177         \r
178         if(options[SOURCEONLY].doesOccur){\r
179             sourceOnly = true;\r
180             sourceFileName = options[SOURCEONLY].value;\r
181         }\r
182         \r
183         if(options[MAKE_SOURCE_ROOT].doesOccur){\r
184             makeSourceRoot = true;\r
185         }\r
186         \r
187         if(options[XLIFF_1_0].doesOccur) {\r
188             xliff10 = true;\r
189         }\r
190         \r
191         if(destDir==null){\r
192             destDir = ".";\r
193         }\r
194         \r
195         if(sourceOnly == true && targetOnly == true){\r
196             System.err.println("--source-only and --target-only are specified. Please check the arguments and try again.");\r
197             usage();\r
198         }\r
199         \r
200         for (int i = 0; i < remainingArgc; i++) {\r
201             //int lastIndex = args[i].lastIndexOf(File.separator, args[i].length()) + 1; /* add 1 to skip past the separator */\r
202             //fileName = args[i].substring(lastIndex, args[i].length());\r
203             String xmlfileName = getFullPath(false,args[i]);\r
204             System.out.println("Processing file: "+xmlfileName);\r
205             createRB(xmlfileName);\r
206         }\r
207     }\r
208     \r
209     private void usage() {\r
210         System.out.println("\nUsage: XLIFF2ICUConverter [OPTIONS] [FILES]\n\n"+\r
211             "This program is used to convert XLIFF files to ICU ResourceBundle TXT files.\n"+\r
212             "Please refer to the following options. Options are not case sensitive.\n"+\r
213             "Options:\n"+\r
214             "-s or --sourcedir          source directory for files followed by path, default is current directory.\n" +\r
215             "-d or --destdir            destination directory, followed by the path, default is current directory.\n" +\r
216             "-h or -? or --help         this usage text.\n"+\r
217             "-t or --target-only        only generate the target language txt file, followed by optional output file name.\n" +\r
218             "                           Cannot be used in conjunction with --source-only.\n"+\r
219             "-c or --source-only        only generate the source language bundle followed by optional output file name.\n"+\r
220             "                           Cannot be used in conjunction with --target-only.\n"+\r
221             "-r or --make-source-root   produce root bundle from source elements.\n" +\r
222             "-x or --xliff-1.0          source file is XLIFF 1.0" +\r
223             "example: com.ibm.icu.dev.tool.localeconverter.XLIFF2ICUConverter -t <optional argument> -s xxx -d yyy myResources.xlf");\r
224         System.exit(-1);\r
225     }\r
226     \r
227     private String getFullPath(boolean fileType, String fName){\r
228         String str;\r
229         int lastIndex1 = fName.lastIndexOf(File.separator, fName.length()) + 1; /*add 1 to skip past the separator*/\r
230         int lastIndex2 = fName.lastIndexOf('.', fName.length());\r
231         if (fileType == true) {\r
232             if(lastIndex2 == -1){\r
233                 fName = fName.trim() + ".txt";\r
234             }else{\r
235                 if(!fName.substring(lastIndex2).equalsIgnoreCase(".txt")){\r
236                     fName =  fName.substring(lastIndex1,lastIndex2) + ".txt";\r
237                 }\r
238             }\r
239             if (destDir != null && fName != null) {\r
240                 str = destDir + File.separator + fName.trim();                   \r
241             } else {\r
242                 str = System.getProperty("user.dir") + File.separator + fName.trim();\r
243             }\r
244         } else {\r
245             if(lastIndex2 == -1){\r
246                 fName = fName.trim() + ".xlf";\r
247             }else{\r
248                 if(!fName.substring(lastIndex2).equalsIgnoreCase(".xml") && fName.substring(lastIndex2).equalsIgnoreCase(".xlf")){\r
249                     fName = fName.substring(lastIndex1,lastIndex2) + ".xlf";\r
250                 }\r
251             }\r
252             if(sourceDir != null && fName != null) {\r
253                 str = sourceDir + File.separator + fName;\r
254             } else if (lastIndex1 > 0) {\r
255                 str = fName;\r
256             } else {\r
257                 str = System.getProperty("user.dir") + File.separator + fName;\r
258             }\r
259         }\r
260         return str;\r
261     }   \r
262 \r
263     /*\r
264      * Utility method to translate a String filename to URL.  \r
265      *\r
266      * Note: This method is not necessarily proven to get the \r
267      * correct URL for every possible kind of filename; it should \r
268      * be improved.  It handles the most common cases that we've \r
269      * encountered when running Conformance tests on Xalan.\r
270      * Also note, this method does not handle other non-file:\r
271      * flavors of URLs at all.\r
272      *\r
273      * If the name is null, return null.\r
274      * If the name starts with a common URI scheme (namely the ones \r
275      * found in the examples of RFC2396), then simply return the \r
276      * name as-is (the assumption is that it's already a URL)\r
277      * Otherwise we attempt (cheaply) to convert to a file:/// URL.\r
278      */\r
279     private static String filenameToURL(String filename){\r
280         // null begets null - something like the commutative property\r
281         if (null == filename){\r
282             return null;\r
283         }\r
284 \r
285         // Don't translate a string that already looks like a URL\r
286         if (filename.startsWith("file:")\r
287             || filename.startsWith("http:")\r
288             || filename.startsWith("ftp:")\r
289             || filename.startsWith("gopher:")\r
290             || filename.startsWith("mailto:")\r
291             || filename.startsWith("news:")\r
292             || filename.startsWith("telnet:")\r
293            ){\r
294                return filename;\r
295            }\r
296         \r
297 \r
298         File f = new File(filename);\r
299         String tmp = null;\r
300         try{\r
301             // This normally gives a better path\r
302             tmp = f.getCanonicalPath();\r
303         }catch (IOException ioe){\r
304             // But this can be used as a backup, for cases \r
305             //  where the file does not exist, etc.\r
306             tmp = f.getAbsolutePath();\r
307         }\r
308 \r
309         // URLs must explicitly use only forward slashes\r
310         if (File.separatorChar == '\\') {\r
311             tmp = tmp.replace('\\', '/');\r
312         }\r
313         // Note the presumption that it's a file reference\r
314         // Ensure we have the correct number of slashes at the \r
315         //  start: we always want 3 /// if it's absolute\r
316         //  (which we should have forced above)\r
317         if (tmp.startsWith("/")){\r
318             return "file://" + tmp;\r
319         }\r
320         else{\r
321             return "file:///" + tmp;\r
322         }\r
323     }\r
324     private boolean isXmlLang (String lang){\r
325 \r
326         int suffix;\r
327         char c;\r
328         \r
329         if (lang.length () < 2){\r
330             return false;\r
331         }\r
332 \r
333         c = lang.charAt(1);\r
334         if (c == '-') {        \r
335             c = lang.charAt(0);\r
336             if (!(c == 'i' || c == 'I' || c == 'x' || c == 'X')){\r
337                 return false;\r
338             }\r
339             suffix = 1;\r
340         } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {\r
341             c = lang.charAt(0);\r
342             if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))){\r
343                 return false;\r
344             }\r
345             suffix = 2;\r
346         } else{\r
347             return false;\r
348         }\r
349         while (suffix < lang.length ()) {\r
350             c = lang.charAt(suffix);\r
351             if (c != '-'){\r
352                 break;\r
353             }\r
354             while (++suffix < lang.length ()) {\r
355                 c = lang.charAt(suffix);\r
356                 if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))){\r
357                     break;\r
358                 }\r
359             }\r
360         }\r
361         return  ((lang.length() == suffix) && (c != '-'));\r
362     }\r
363     \r
364     private void createRB(String xmlfileName) {\r
365        \r
366         String urls = filenameToURL(xmlfileName);\r
367         DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();\r
368         dfactory.setNamespaceAware(true);\r
369         Document doc = null;\r
370         \r
371         if (xliff10) {\r
372             dfactory.setValidating(true);\r
373             resources = OLD_RESOURCES;\r
374         } else {\r
375             try {\r
376                 SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);\r
377                 Schema schema = schemaFactory.newSchema();\r
378                 \r
379                 dfactory.setSchema(schema);\r
380             } catch (SAXException e) {\r
381                 System.err.println("Can't create the schema...");\r
382                 System.exit(-1);\r
383             } catch (UnsupportedOperationException e) {\r
384                 System.err.println("ERROR:\tOne of the schema operations is not supported with this JVM.");\r
385                 System.err.println("\tIf you are using GNU Java, you should try using the latest Sun JVM.");\r
386                 System.err.println("\n*Here is the stack trace:");\r
387                 e.printStackTrace();\r
388                 System.exit(-1);\r
389             }\r
390             \r
391             resources = NEW_RESOURCES;\r
392         }\r
393         \r
394         ErrorHandler nullHandler = new ErrorHandler() {\r
395             public void warning(SAXParseException e) throws SAXException {\r
396                             \r
397             }\r
398             public void error(SAXParseException e) throws SAXException {\r
399                 System.err.println("The XLIFF document is invalid, please check it first: ");\r
400                 System.err.println("Line "+e.getLineNumber()+", Column "+e.getColumnNumber());\r
401                 System.err.println("Error: " + e.getMessage());\r
402                 System.exit(-1);\r
403             }\r
404             public void fatalError(SAXParseException e) throws SAXException {\r
405                 throw e;\r
406             }\r
407         };\r
408         \r
409         try {\r
410             DocumentBuilder docBuilder = dfactory.newDocumentBuilder();\r
411             docBuilder.setErrorHandler(nullHandler);\r
412             doc = docBuilder.parse(new InputSource(urls));\r
413             \r
414             NodeList nlist = doc.getElementsByTagName(FILES);\r
415             if(nlist.getLength()>1){\r
416                 throw new RuntimeException("Multiple <file> elements in the XLIFF file not supported.");\r
417             }\r
418                         \r
419             // get the value of source-language attribute\r
420             String sourceLang = getLanguageName(doc, SOURCELANGUAGE);\r
421             // get the value of target-language attribute\r
422             String targetLang = getLanguageName(doc, TARGETLANGUAGE);\r
423             \r
424             // get the list of <source> elements\r
425             NodeList sourceList = doc.getElementsByTagName(SOURCE);\r
426             // get the list of target elements\r
427             NodeList targetList = doc.getElementsByTagName(TARGET);\r
428             \r
429             // check if the xliff file has source elements in multiple languages\r
430             // the source-language value should be the same as xml:lang values\r
431             // of all the source elements.\r
432             String xmlSrcLang = checkLangAttribute(sourceList, sourceLang);\r
433             \r
434             // check if the xliff file has target elements in multiple languages\r
435             // the target-language value should be the same as xml:lang values\r
436             // of all the target elements.\r
437             String xmlTargetLang = checkLangAttribute(targetList, targetLang);\r
438             \r
439             // Create the Resource linked list which will hold the\r
440             // source and target bundles after parsing\r
441             Resource[] set = new Resource[2];\r
442             set[0] = new ResourceTable();\r
443             set[1] = new ResourceTable();\r
444             \r
445             // lenient extraction of source language\r
446             if(makeSourceRoot == true){ \r
447                 set[0].name = ROOT;\r
448             }else if(sourceLang!=null){\r
449                 set[0].name = sourceLang.replace('-','_');\r
450             }else{\r
451                 if(xmlSrcLang != null){\r
452                     set[0].name = xmlSrcLang.replace('-','_');\r
453                 }else{\r
454                     System.err.println("ERROR: Could not figure out the source language of the file. Please check the XLIFF file.");\r
455                     System.exit(-1);\r
456                 }\r
457             }\r
458             \r
459             // lenient extraction of the target language\r
460             if(targetLang!=null){\r
461                 set[1].name = targetLang.replace('-','_');\r
462             }else{\r
463                 if(xmlTargetLang!=null){\r
464                     set[1].name = xmlTargetLang.replace('-','_');\r
465                 }else{\r
466                     System.err.println("WARNING: Could not figure out the target language of the file. Producing source bundle only.");\r
467                 }\r
468             }\r
469    \r
470             \r
471             // check if any <alt-trans> elements are present\r
472             NodeList altTrans = doc.getElementsByTagName(ALTTRANS);\r
473             if(altTrans.getLength()>0){\r
474                 System.err.println("WARNING: <alt-trans> elements in found. Ignoring all <alt-trans> elements.");\r
475             }\r
476             \r
477             // get all the group elements\r
478             NodeList list = doc.getElementsByTagName(GROUPS);\r
479             \r
480             // process the first group element. The first group element is \r
481             // the base table that must be parsed recursively\r
482             parseTable(list.item(0), set);\r
483             \r
484             // write out the bundle\r
485             writeResource(set, xmlfileName);\r
486          }\r
487         catch (Throwable se) {\r
488             System.err.println("ERROR: " + se.toString());\r
489             System.exit(1);\r
490         }        \r
491     }\r
492     \r
493     private void writeResource(Resource[] set, String xmlfileName){\r
494         if(targetOnly==false){\r
495             writeResource(set[0], xmlfileName, sourceFileName);\r
496         }\r
497         if(sourceOnly == false){\r
498             if(targetOnly==true && set[1].name == null){\r
499                 throw new RuntimeException("The "+ xmlfileName +" does not contain translation\n");\r
500             }\r
501             if(set[1].name != null){\r
502                 writeResource(set[1], xmlfileName, targetFileName);\r
503             }\r
504         }\r
505     }\r
506     \r
507     private void writeResource(Resource set, String sourceFilename, String targetFilename){\r
508         try {\r
509             String outputFileName = null;\r
510             if(targetFilename != null){\r
511                 outputFileName = destDir+File.separator+targetFilename+".txt";\r
512             }else{\r
513                 outputFileName = destDir+File.separator+set.name+".txt";\r
514             }\r
515             FileOutputStream file = new FileOutputStream(outputFileName);\r
516             BufferedOutputStream writer = new BufferedOutputStream(file);\r
517 \r
518             writeHeader(writer,sourceFilename);\r
519             \r
520             //Now start writing the resource;\r
521             Resource current = set;\r
522             while(current!=null){\r
523                 current.write(writer, 0, false);\r
524                 current = current.next;\r
525             }\r
526             writer.flush();\r
527             writer.close();\r
528         } catch (Exception ie) {\r
529             System.err.println("ERROR :" + ie.toString());\r
530             return;\r
531         }\r
532     }\r
533     \r
534     private String getLanguageName(Document doc, String lang){\r
535         if(doc!=null){\r
536             NodeList list = doc.getElementsByTagName(FILE);\r
537             Node node = list.item(0);\r
538             NamedNodeMap attr = node.getAttributes();\r
539             Node orig = attr.getNamedItem(lang);\r
540             \r
541             if(orig != null){\r
542                 String name = orig.getNodeValue();\r
543                 NodeList groupList = doc.getElementsByTagName(GROUPS);\r
544                 Node group = groupList.item(0);\r
545                 NamedNodeMap groupAtt = group.getAttributes();\r
546                 Node id = groupAtt.getNamedItem(ID);\r
547                 if(id!=null){\r
548                     String idVal = id.getNodeValue();\r
549                     \r
550                     if(!name.equals(idVal)){\r
551                         System.out.println("WARNING: The id value != language name. " +\r
552                                            "Please compare the output with the orignal " +\r
553                                            "ICU ResourceBundle before proceeding.");\r
554                     }\r
555                 }\r
556                 if(!isXmlLang(name)){\r
557                     System.err.println("The attribute "+ lang + "=\""+ name +\r
558                                        "\" of <file> element does not satisfy RFC 1766 conditions.");\r
559                     System.exit(-1);\r
560                 }\r
561                 return name;\r
562             }\r
563         }\r
564         return null;\r
565     }\r
566     \r
567     // check if the xliff file is translated into multiple languages\r
568     // The XLIFF specification allows for single <target> element\r
569     // as the child of <trans-unit> but the attributes of the \r
570     // <target> element may different across <trans-unit> elements\r
571     // check for it. Similar is the case with <source> elements\r
572     private String checkLangAttribute(NodeList list, String origName){\r
573         String oldLangName=origName;\r
574         for(int i = 0 ;i<list.getLength(); i++){\r
575             Node node = list.item(i);\r
576             NamedNodeMap attr = node.getAttributes();\r
577             Node lang = attr.getNamedItem(XMLLANG);\r
578             String langName = null;\r
579             // the target element should always contain xml:lang attribute\r
580             if(lang==null ){\r
581                 if(origName==null){\r
582                     System.err.println("Encountered <target> element without xml:lang attribute. Please fix the below element in the XLIFF file.\n"+ node.toString());\r
583                     System.exit(-1);\r
584                 }else{\r
585                     langName = origName;\r
586                 }\r
587             }else{\r
588                 langName = lang.getNodeValue();\r
589             }\r
590 \r
591             if(oldLangName!=null && langName!=null && !langName.equals(oldLangName)){\r
592                 throw new RuntimeException("The <trans-unit> elements must be bilingual, multilingual tranlations not supported. xml:lang = " + oldLangName + \r
593                                            " and xml:lang = " + langName);\r
594             }\r
595             oldLangName = langName;\r
596         }\r
597         return oldLangName;\r
598     }\r
599     \r
600     private class Resource{\r
601         String[] note = new String[20];\r
602         int noteLen = 0;\r
603         String translate;\r
604         String comment;\r
605         String name;\r
606         Resource next;\r
607         public String escapeSyntaxChars(String val){\r
608             // escape the embedded quotes\r
609             char[] str = val.toCharArray();\r
610             StringBuffer result = new StringBuffer();\r
611             for(int i=0; i<str.length; i++){\r
612                 switch (str[i]){\r
613                     case '\u0022':\r
614                         result.append('\\'); //append backslash\r
615                     default:\r
616                         result.append(str[i]);\r
617                 }      \r
618             }\r
619             return result.toString();\r
620         }\r
621         public void write(OutputStream writer, int numIndent, boolean bare){\r
622             while(next!=null){\r
623                 next.write(writer, numIndent+1, false);\r
624             }\r
625         }\r
626         public void writeIndent(OutputStream writer, int numIndent){\r
627             for(int i=0; i< numIndent; i++){\r
628                 write(writer,INDENT);\r
629             }\r
630         }\r
631         public void write(OutputStream writer, String value){\r
632             try {\r
633                 byte[] bytes = value.getBytes(CHARSET);\r
634                 writer.write(bytes, 0, bytes.length);\r
635             } catch(Exception e) {\r
636                 System.err.println(e);\r
637                 System.exit(1);\r
638             }\r
639         }\r
640         public void writeComments(OutputStream writer, int numIndent){\r
641             boolean translateIsDefault = translate == null || translate.equals("yes");\r
642             \r
643             if(comment!=null || ! translateIsDefault || noteLen > 0){\r
644                 // print the start of the comment\r
645                 writeIndent(writer, numIndent);\r
646                 write(writer, COMMENTSTART+LINESEP);\r
647                 \r
648                 // print comment if any\r
649                 if(comment!=null){\r
650                     writeIndent(writer, numIndent);\r
651                     write(writer, COMMENTMIDDLE);\r
652                     write(writer, comment);\r
653                     write(writer, LINESEP);\r
654                 }\r
655                 \r
656                 // print the translate attribute if any\r
657                 if(! translateIsDefault){\r
658                     writeIndent(writer, numIndent);\r
659                     write(writer, TAG+TRANSLATE+SPACE);\r
660                     write(writer, translate);\r
661                     write(writer, LINESEP);\r
662                 }\r
663                 \r
664                 // print note elements if any\r
665                 for(int i=0; i<noteLen; i++){\r
666                     if(note[i]!=null){\r
667                         writeIndent(writer, numIndent);\r
668                         write(writer, TAG+NOTE+SPACE+note[i]);\r
669                         write(writer, LINESEP);\r
670                     }\r
671                 }\r
672                 \r
673                 // terminate the comment\r
674                 writeIndent(writer, numIndent);\r
675                 write(writer, COMMENTEND+LINESEP);\r
676             }          \r
677         }\r
678     }\r
679 \r
680     private class ResourceString extends Resource{\r
681         String val;\r
682         public void write(OutputStream writer, int numIndent, boolean bare){\r
683             writeComments(writer, numIndent);\r
684             writeIndent(writer, numIndent);\r
685             if(bare==true){\r
686                 if(name!=null){\r
687                     throw new RuntimeException("Bare option is set to true but the resource has a name!");\r
688                 }\r
689                 \r
690                 write(writer,QUOTE+escapeSyntaxChars(val)+QUOTE); \r
691             }else{\r
692                 write(writer, name+COLON+STRINGS+ OPENBRACE + QUOTE + escapeSyntaxChars(val) + QUOTE+ CLOSEBRACE + LINESEP);\r
693             }\r
694         }\r
695     }\r
696     private class ResourceAlias extends Resource{\r
697         String val;\r
698         public void write(OutputStream writer, int numIndent, boolean bare){\r
699             writeComments(writer, numIndent);\r
700             writeIndent(writer, numIndent);\r
701             String line =  ((name==null)? EMPTY: name)+COLON+ALIAS+ OPENBRACE+QUOTE+escapeSyntaxChars(val)+QUOTE+CLOSEBRACE;\r
702             if(bare==true){\r
703                 if(name!=null){\r
704                     throw new RuntimeException("Bare option is set to true but the resource has a name!");\r
705                 }\r
706                 write(writer,line); \r
707             }else{\r
708                 write(writer, line+LINESEP);\r
709             }\r
710         }\r
711     }\r
712     private class ResourceInt extends Resource{\r
713         String val;\r
714         public void write(OutputStream writer, int numIndent, boolean bare){\r
715             writeComments(writer, numIndent);\r
716             writeIndent(writer, numIndent);\r
717             String line =  ((name==null)? EMPTY: name)+COLON+INTS+ OPENBRACE + val +CLOSEBRACE;\r
718             if(bare==true){\r
719                 if(name!=null){\r
720                     throw new RuntimeException("Bare option is set to true but the resource has a name!");\r
721                 }\r
722                 write(writer,line); \r
723             }else{\r
724                 write(writer, line+LINESEP);\r
725             }\r
726         }\r
727     }\r
728     private class ResourceBinary extends Resource{\r
729         String internal;\r
730         String external;\r
731         public void write(OutputStream writer, int numIndent, boolean bare){\r
732             writeComments(writer, numIndent);\r
733             writeIndent(writer, numIndent);\r
734             if(internal==null){\r
735                 String line = ((name==null) ? EMPTY : name)+COLON+IMPORT+ OPENBRACE+QUOTE+external+QUOTE+CLOSEBRACE + ((bare==true) ?  EMPTY : LINESEP);\r
736                 write(writer, line);\r
737             }else{\r
738                 String line = ((name==null) ? EMPTY : name)+COLON+BIN+ OPENBRACE+internal+CLOSEBRACE+ ((bare==true) ?  EMPTY : LINESEP);\r
739                 write(writer,line);\r
740             }\r
741             \r
742         }\r
743     }\r
744     private class ResourceIntVector extends Resource{\r
745         ResourceInt first;\r
746         public void write(OutputStream writer, int numIndent, boolean bare){\r
747             writeComments(writer, numIndent);\r
748             writeIndent(writer, numIndent);\r
749             write(writer, name+COLON+INTVECTOR+OPENBRACE+LINESEP);\r
750             numIndent++;\r
751             ResourceInt current = (ResourceInt) first;\r
752             while(current != null){\r
753                 //current.write(writer, numIndent, true);\r
754                 writeIndent(writer, numIndent);\r
755                 write(writer, current.val);\r
756                 write(writer, COMMA+LINESEP);\r
757                 current = (ResourceInt) current.next;\r
758             }\r
759             numIndent--;\r
760             writeIndent(writer, numIndent);\r
761             write(writer, CLOSEBRACE+LINESEP);\r
762         }\r
763     }\r
764     private class ResourceTable extends Resource{\r
765         Resource first;\r
766         public void write(OutputStream writer, int numIndent, boolean bare){\r
767             writeComments(writer, numIndent);\r
768             writeIndent(writer, numIndent);\r
769             write(writer, name+COLON+TABLE+OPENBRACE+LINESEP);\r
770             numIndent++;\r
771             Resource current = first;\r
772             while(current != null){\r
773                 current.write(writer, numIndent, false);\r
774                 current = current.next;\r
775             }\r
776             numIndent--;\r
777             writeIndent(writer, numIndent);\r
778             write(writer, CLOSEBRACE+LINESEP);\r
779         }\r
780     }\r
781     private class ResourceArray extends Resource{\r
782         Resource first;\r
783         public void write(OutputStream writer, int numIndent, boolean bare){\r
784             writeComments(writer, numIndent);\r
785             writeIndent(writer, numIndent);\r
786             write(writer, name+COLON+ARRAYS+OPENBRACE+LINESEP);\r
787             numIndent++;\r
788             Resource current = first;\r
789             while(current != null){\r
790                 current.write(writer, numIndent, true);\r
791                 write(writer, COMMA+LINESEP);\r
792                 current = current.next;\r
793             }\r
794             numIndent--;\r
795             writeIndent(writer, numIndent);\r
796             write(writer, CLOSEBRACE+LINESEP);\r
797         }\r
798     }\r
799     \r
800     private String getAttributeValue(Node sNode, String attribName){\r
801         String value=null;\r
802         Node node = sNode;\r
803 \r
804         NamedNodeMap attributes = node.getAttributes();\r
805         Node attr = attributes.getNamedItem(attribName);\r
806         if(attr!=null){\r
807             value = attr.getNodeValue();\r
808         }\r
809 \r
810         return value;\r
811     }\r
812     \r
813     private void parseResourceString(Node node, ResourceString[] set){\r
814         ResourceString currentSource;\r
815         ResourceString currentTarget;\r
816         currentSource =  set[0];\r
817         currentTarget =  set[1];\r
818         String resName   = getAttributeValue(node, RESNAME);\r
819         String translate = getAttributeValue(node, TRANSLATE);\r
820         \r
821         // loop to pickup <source>, <note> and <target> elements\r
822         for(Node transUnit = node.getFirstChild(); transUnit!=null; transUnit = transUnit.getNextSibling()){\r
823             short type = transUnit.getNodeType();\r
824             String name = transUnit.getNodeName();\r
825             if(type == Node.COMMENT_NODE){\r
826                 // get the comment\r
827                currentSource.comment =  currentTarget.comment = transUnit.getNodeValue();\r
828             }else if( type == Node.ELEMENT_NODE){\r
829                 if(name.equals(SOURCE)){\r
830                     // save the source and target values\r
831                     currentSource.name = currentTarget.name = resName;\r
832                     currentSource.val = currentTarget.val = transUnit.getFirstChild().getNodeValue();\r
833                     currentSource.translate = currentTarget.translate = translate;\r
834                 }else if(name.equals(NOTE)){\r
835                     // save the note values\r
836                     currentSource.note[currentSource.noteLen++] = \r
837                         currentTarget.note[currentTarget.noteLen++] =\r
838                         transUnit.getFirstChild().getNodeValue();\r
839                 }else if(name.equals(TARGET)){\r
840                     // if there is a target element replace it\r
841                     currentTarget.val = transUnit.getFirstChild().getNodeValue();\r
842                 }\r
843             }\r
844             \r
845         }\r
846     }\r
847 \r
848     private void parseResourceInt(Node node, ResourceInt[] set){\r
849         ResourceInt currentSource;\r
850         ResourceInt currentTarget;\r
851         currentSource =  set[0];\r
852         currentTarget =  set[1];\r
853         String resName   = getAttributeValue(node, RESNAME);\r
854         String translate = getAttributeValue(node, TRANSLATE);\r
855         // loop to pickup <source>, <note> and <target> elements\r
856         for(Node transUnit = node.getFirstChild(); transUnit!=null; transUnit = transUnit.getNextSibling()){\r
857             short type = transUnit.getNodeType();\r
858             String name = transUnit.getNodeName();\r
859             if(type == Node.COMMENT_NODE){\r
860                 // get the comment\r
861                currentSource.comment =  currentTarget.comment = transUnit.getNodeValue();\r
862             }else if( type == Node.ELEMENT_NODE){\r
863                 if(name.equals(SOURCE)){\r
864                     // save the source and target values\r
865                     currentSource.name = currentTarget.name = resName;\r
866                     currentSource.translate = currentTarget.translate = translate;\r
867                     currentSource.val = currentTarget.val = transUnit.getFirstChild().getNodeValue();\r
868                 }else if(name.equals(NOTE)){\r
869                     // save the note values\r
870                     currentSource.note[currentSource.noteLen++] = \r
871                         currentTarget.note[currentTarget.noteLen++] =\r
872                         transUnit.getFirstChild().getNodeValue();\r
873                 }else if(name.equals(TARGET)){\r
874                     // if there is a target element replace it\r
875                     currentTarget.val = transUnit.getFirstChild().getNodeValue();\r
876                 }\r
877             }\r
878             \r
879         }\r
880     }\r
881     \r
882     private void parseResourceAlias(Node node, ResourceAlias[] set){\r
883         ResourceAlias currentSource;\r
884         ResourceAlias currentTarget;\r
885         currentSource =  set[0];\r
886         currentTarget =  set[1];\r
887         String resName   = getAttributeValue(node, RESNAME);\r
888         String translate = getAttributeValue(node, TRANSLATE);\r
889         // loop to pickup <source>, <note> and <target> elements\r
890         for(Node transUnit = node.getFirstChild(); transUnit!=null; transUnit = transUnit.getNextSibling()){\r
891             short type = transUnit.getNodeType();\r
892             String name = transUnit.getNodeName();\r
893             if(type == Node.COMMENT_NODE){\r
894                 // get the comment\r
895                currentSource.comment =  currentTarget.comment = transUnit.getNodeValue();\r
896             }else if( type == Node.ELEMENT_NODE){\r
897                 if(name.equals(SOURCE)){\r
898                     // save the source and target values\r
899                     currentSource.name = currentTarget.name = resName;\r
900                     currentSource.translate = currentTarget.translate = translate;\r
901                     currentSource.val = currentTarget.val = transUnit.getFirstChild().getNodeValue();\r
902                 }else if(name.equals(NOTE)){\r
903                     // save the note values\r
904                     currentSource.note[currentSource.noteLen++] = \r
905                         currentTarget.note[currentTarget.noteLen++] =\r
906                         transUnit.getFirstChild().getNodeValue();\r
907                 }else if(name.equals(TARGET)){\r
908                     // if there is a target element replace it\r
909                     currentTarget.val = transUnit.getFirstChild().getNodeValue();\r
910                 }\r
911             }\r
912             \r
913         }\r
914     }\r
915     private void parseResourceBinary(Node node, ResourceBinary[] set){\r
916         ResourceBinary currentSource;\r
917         ResourceBinary currentTarget;\r
918         currentSource =  set[0];\r
919         currentTarget =  set[1];\r
920 \r
921         // loop to pickup <source>, <note> and <target> elements\r
922         for(Node transUnit = node.getFirstChild(); transUnit!=null; transUnit = transUnit.getNextSibling()){\r
923             short type = transUnit.getNodeType();\r
924             String name = transUnit.getNodeName();\r
925             if(type == Node.COMMENT_NODE){\r
926                 // get the comment\r
927                currentSource.comment =  currentTarget.comment = transUnit.getNodeValue();\r
928             }else if( type == Node.ELEMENT_NODE){\r
929                 if(name.equals(BINSOURCE)){\r
930                     // loop to pickup internal-file/extenal-file element\r
931                     continue;\r
932                 }else if(name.equals(NOTE)){\r
933                     // save the note values\r
934                     currentSource.note[currentSource.noteLen++] = \r
935                         currentTarget.note[currentTarget.noteLen++] =\r
936                         transUnit.getFirstChild().getNodeValue();\r
937                 }else if(name.equals(INTERNALFILE)){\r
938                     // if there is a target element replace it\r
939                     String crc = getAttributeValue(transUnit, CRC);\r
940                     String value = transUnit.getFirstChild().getNodeValue();\r
941                     \r
942                     //verify that the binary value conforms to the CRC\r
943                     if(Integer.parseInt(crc, 10) != CalculateCRC32.computeCRC32(value)) {\r
944                         System.err.println("ERROR: CRC value incorrect! Please check.");\r
945                         System.exit(1);\r
946                     }\r
947                     \r
948                     currentTarget.internal = currentSource.internal= value;\r
949                     \r
950                 }else if(name.equals(EXTERNALFILE)){\r
951                     currentSource.external = getAttributeValue(transUnit, HREF);\r
952                     currentTarget.external = currentSource.external;\r
953                 }\r
954             }\r
955             \r
956         }\r
957     }\r
958     private void parseTransUnit(Node node, Resource[] set){\r
959 \r
960         String attrType = getAttributeValue(node, RESTYPE);\r
961         String translate = getAttributeValue(node, TRANSLATE);\r
962         if(attrType==null || attrType.equals(STRINGS)){\r
963             ResourceString[] strings = new ResourceString[2];\r
964             strings[0] = new ResourceString();\r
965             strings[1] = new ResourceString();\r
966             parseResourceString(node, strings);\r
967             strings[0].translate = strings[1].translate = translate;\r
968             set[0] = strings[0];\r
969             set[1] = strings[1];\r
970         }else if(attrType.equals(resources[INTEGER_RESOURCE])){\r
971             ResourceInt[] ints = new ResourceInt[2];\r
972             ints[0] = new ResourceInt();\r
973             ints[1] = new ResourceInt();\r
974             parseResourceInt(node, ints);\r
975             ints[0].translate = ints[1].translate = translate;\r
976             set[0] = ints[0];\r
977             set[1] = ints[1];\r
978         }else if(attrType.equals(resources[ALIAS_RESOURCE])){\r
979             ResourceAlias[] ints = new ResourceAlias[2];\r
980             ints[0] = new ResourceAlias();\r
981             ints[1] = new ResourceAlias();\r
982             parseResourceAlias(node, ints);\r
983             ints[0].translate = ints[1].translate = translate;\r
984             set[0] = ints[0];\r
985             set[1] = ints[1];\r
986         }\r
987     }\r
988 \r
989     private void parseBinUnit(Node node, Resource[] set){\r
990         if (getAttributeValue(node, RESTYPE).equals(resources[BINARY_RESOURCE])) {\r
991             ResourceBinary[] bins = new ResourceBinary[2];\r
992             \r
993             bins[0] = new ResourceBinary();\r
994             bins[1] = new ResourceBinary();\r
995             \r
996             Resource currentSource = bins[0];\r
997             Resource currentTarget = bins[1];\r
998             String resName   = getAttributeValue(node, RESNAME);\r
999             String translate = getAttributeValue(node, TRANSLATE);\r
1000             \r
1001             currentTarget.name = currentSource.name = resName;\r
1002             currentSource.translate = currentTarget.translate = translate;\r
1003             \r
1004             for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()){\r
1005                 short type = child.getNodeType();\r
1006                 String name = child.getNodeName();\r
1007                 \r
1008                 if(type == Node.COMMENT_NODE){\r
1009                     currentSource.comment = currentTarget.comment = child.getNodeValue();\r
1010                 }else if(type == Node.ELEMENT_NODE){\r
1011                     if(name.equals(BINSOURCE)){\r
1012                         parseResourceBinary(child, bins);\r
1013                     }else if(name.equals(NOTE)){\r
1014                         String note =  child.getFirstChild().getNodeValue();\r
1015                         \r
1016                         currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = note;\r
1017                     }\r
1018                 }\r
1019             }\r
1020             \r
1021             set[0] = bins[0];\r
1022             set[1] = bins[1];\r
1023         }\r
1024     }\r
1025     \r
1026     private void parseArray(Node node, Resource[] set){\r
1027         if(set[0]==null){\r
1028             set[0] = new ResourceArray();\r
1029             set[1] = new ResourceArray();\r
1030         }\r
1031         Resource currentSource = set[0];\r
1032         Resource currentTarget = set[1];\r
1033         String resName = getAttributeValue(node, RESNAME);\r
1034         currentSource.name = currentTarget.name = resName;\r
1035         boolean isFirst = true;\r
1036         \r
1037         for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()){\r
1038             short type = child.getNodeType();\r
1039             String name = child.getNodeName();\r
1040             if(type == Node.COMMENT_NODE){\r
1041                 currentSource.comment = currentTarget.comment = child.getNodeValue();\r
1042             }else if(type == Node.ELEMENT_NODE){\r
1043                 if(name.equals(TRANSUNIT)){\r
1044                     Resource[] next = new Resource[2];\r
1045                     parseTransUnit(child, next);\r
1046                     if(isFirst==true){\r
1047                        ((ResourceArray) currentSource).first = next[0];\r
1048                        ((ResourceArray) currentTarget).first = next[1];\r
1049                        currentSource = ((ResourceArray) currentSource).first;\r
1050                        currentTarget = ((ResourceArray) currentTarget).first;\r
1051                        isFirst = false;\r
1052                     }else{\r
1053                         currentSource.next = next[0];\r
1054                         currentTarget.next = next[1];\r
1055                         // set the next pointers\r
1056                         currentSource = currentSource.next;\r
1057                         currentTarget = currentTarget.next;\r
1058                     }\r
1059                 }else if(name.equals(NOTE)){\r
1060                     String note =  child.getFirstChild().getNodeValue();\r
1061                     currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = note;\r
1062                 }else if(name.equals(BINUNIT)){\r
1063                     Resource[] next = new Resource[2];\r
1064                     parseBinUnit(child, next);\r
1065                     if(isFirst==true){\r
1066                        ((ResourceArray) currentSource).first = next[0];\r
1067                        ((ResourceArray) currentTarget).first = next[1];\r
1068                        currentSource = ((ResourceArray) currentSource).first.next;\r
1069                        currentTarget = ((ResourceArray) currentTarget).first.next;\r
1070                        isFirst = false;\r
1071                     }else{\r
1072                         currentSource.next = next[0];\r
1073                         currentTarget.next = next[1];\r
1074                         // set the next pointers\r
1075                         currentSource = currentSource.next;\r
1076                         currentTarget = currentTarget.next;\r
1077                     }\r
1078                 }\r
1079             }\r
1080         }\r
1081     }\r
1082     private void parseIntVector(Node node, Resource[] set){\r
1083         if(set[0]==null){\r
1084             set[0] = new ResourceIntVector();\r
1085             set[1] = new ResourceIntVector();\r
1086         }\r
1087         Resource currentSource = set[0];\r
1088         Resource currentTarget = set[1];\r
1089         String resName = getAttributeValue(node, RESNAME);\r
1090         String translate = getAttributeValue(node,TRANSLATE);\r
1091         currentSource.name = currentTarget.name = resName;\r
1092         currentSource.translate = translate;\r
1093         boolean isFirst = true;\r
1094         for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()){\r
1095             short type = child.getNodeType();\r
1096             String name = child.getNodeName();\r
1097             if(type == Node.COMMENT_NODE){\r
1098                 currentSource.comment = currentTarget.comment = child.getNodeValue();\r
1099             }else if(type == Node.ELEMENT_NODE){\r
1100                 if(name.equals(TRANSUNIT)){\r
1101                     Resource[] next = new Resource[2];\r
1102                     parseTransUnit(child, next);\r
1103                     if(isFirst==true){\r
1104                         // the down cast should be safe .. if not something is terribly wrong!!\r
1105                        ((ResourceIntVector) currentSource).first = (ResourceInt)next[0];\r
1106                        ((ResourceIntVector) currentTarget).first = (ResourceInt) next[1];\r
1107                        currentSource = ((ResourceIntVector) currentSource).first;\r
1108                        currentTarget = ((ResourceIntVector) currentTarget).first;\r
1109                        isFirst = false;\r
1110                     }else{\r
1111                         currentSource.next = next[0];\r
1112                         currentTarget.next = next[1];\r
1113                         // set the next pointers\r
1114                         currentSource = currentSource.next;\r
1115                         currentTarget = currentTarget.next;\r
1116                     }\r
1117                 }else if(name.equals(NOTE)){\r
1118                     String note =  child.getFirstChild().getNodeValue();\r
1119                     currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = note;\r
1120                 }\r
1121             }\r
1122         }\r
1123     }\r
1124     private void parseTable(Node node, Resource[] set){\r
1125         if(set[0]==null){\r
1126             set[0] = new ResourceTable();\r
1127             set[1] = new ResourceTable();\r
1128         }\r
1129         Resource currentSource = set[0];\r
1130         Resource currentTarget = set[1];\r
1131         \r
1132         String resName = getAttributeValue(node, RESNAME);\r
1133         String translate = getAttributeValue(node,TRANSLATE);\r
1134         if(resName!=null && currentSource.name==null && currentTarget.name==null){\r
1135             currentSource.name = currentTarget.name = resName;\r
1136         }\r
1137         currentTarget.translate = currentSource.translate = translate;\r
1138         \r
1139         boolean isFirst = true;\r
1140         for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()){\r
1141             short type = child.getNodeType();\r
1142             String name = child.getNodeName();\r
1143             if(type == Node.COMMENT_NODE){\r
1144                 currentSource.comment = currentTarget.comment = child.getNodeValue();\r
1145             }else if(type == Node.ELEMENT_NODE){\r
1146                 if(name.equals(GROUPS)){\r
1147                     Resource[] next = new Resource[2];\r
1148                     parseGroup(child, next);\r
1149                     if(isFirst==true){\r
1150                         // the down cast should be safe .. if not something is terribly wrong!!\r
1151                        ((ResourceTable) currentSource).first = next[0];\r
1152                        ((ResourceTable) currentTarget).first = next[1];\r
1153                        currentSource = ((ResourceTable) currentSource).first;\r
1154                        currentTarget = ((ResourceTable) currentTarget).first;\r
1155                        isFirst = false;\r
1156                     }else{\r
1157                         currentSource.next = next[0];\r
1158                         currentTarget.next = next[1];\r
1159                         // set the next pointers\r
1160                         currentSource = currentSource.next;\r
1161                         currentTarget = currentTarget.next;\r
1162                     }\r
1163                 }else if(name.equals(TRANSUNIT)){\r
1164                     Resource[] next = new Resource[2];\r
1165                     parseTransUnit(child, next);\r
1166                     if(isFirst==true){\r
1167                         // the down cast should be safe .. if not something is terribly wrong!!\r
1168                        ((ResourceTable) currentSource).first = next[0];\r
1169                        ((ResourceTable) currentTarget).first = next[1];\r
1170                        currentSource = ((ResourceTable) currentSource).first;\r
1171                        currentTarget = ((ResourceTable) currentTarget).first;\r
1172                        isFirst = false;\r
1173                     }else{\r
1174                         currentSource.next = next[0];\r
1175                         currentTarget.next = next[1];\r
1176                         // set the next pointers\r
1177                         currentSource = currentSource.next;\r
1178                         currentTarget = currentTarget.next;\r
1179                     }\r
1180                 }else if(name.equals(NOTE)){\r
1181                     String note =  child.getFirstChild().getNodeValue();\r
1182                     currentSource.note[currentSource.noteLen++] = currentTarget.note[currentTarget.noteLen++] = note;\r
1183                 }else if(name.equals(BINUNIT)){\r
1184                     Resource[] next = new Resource[2];\r
1185                     parseBinUnit(child, next);\r
1186                     if(isFirst==true){\r
1187                         // the down cast should be safe .. if not something is terribly wrong!!\r
1188                        ((ResourceTable) currentSource).first = next[0];\r
1189                        ((ResourceTable) currentTarget).first = next[1];\r
1190                        currentSource = ((ResourceTable) currentSource).first;\r
1191                        currentTarget = ((ResourceTable) currentTarget).first;\r
1192                        isFirst = false;\r
1193                     }else{\r
1194                         currentSource.next = next[0];\r
1195                         currentTarget.next = next[1];\r
1196                         // set the next pointers\r
1197                         currentSource = currentSource.next;\r
1198                         currentTarget = currentTarget.next;\r
1199                     }\r
1200                 }\r
1201             }\r
1202         }\r
1203     }\r
1204     \r
1205     private void parseGroup(Node node, Resource[] set){\r
1206 \r
1207         // figure out what kind of group this is\r
1208         String resType = getAttributeValue(node, RESTYPE);\r
1209         if(resType.equals(resources[ARRAY_RESOURCE])){\r
1210             parseArray(node, set);\r
1211         }else if( resType.equals(resources[TABLE_RESOURCE])){\r
1212             parseTable(node, set);\r
1213         }else if( resType.equals(resources[INTVECTOR_RESOURCE])){\r
1214             parseIntVector(node, set);\r
1215         }\r
1216     }\r
1217     \r
1218 \r
1219     private void writeLine(OutputStream writer, String line) {\r
1220         try {\r
1221             byte[] bytes = line.getBytes(CHARSET);\r
1222             writer.write(bytes, 0, bytes.length);\r
1223         } catch (Exception e) {\r
1224             System.err.println(e);\r
1225             System.exit(1);\r
1226         }\r
1227     }\r
1228     \r
1229     private void writeHeader(OutputStream writer, String fileName){\r
1230         final String header = \r
1231             "// ***************************************************************************" + LINESEP +\r
1232             "// *" + LINESEP +\r
1233             "// * Tool: com.ibm.icu.dev.tool.localeconverter.XLIFF2ICUConverter.java" + LINESEP +\r
1234             "// * Date & Time: {0,date,MM/dd/yyyy hh:mm:ss a z}"+ LINESEP +\r
1235             "// * Source File: {1}" + LINESEP +\r
1236             "// *" + LINESEP +                    \r
1237             "// ***************************************************************************" + LINESEP;\r
1238             \r
1239         writeBOM(writer);\r
1240         MessageFormat format = new MessageFormat(header);\r
1241         Object args[] = {new Date(System.currentTimeMillis()), fileName};\r
1242 \r
1243         writeLine(writer, format.format(args));\r
1244     }\r
1245     \r
1246     private  void writeBOM(OutputStream buffer) {\r
1247         try {\r
1248             byte[] bytes = BOM.getBytes(CHARSET);\r
1249             buffer.write(bytes, 0, bytes.length);\r
1250         } catch(Exception e) {\r
1251             System.err.println(e);\r
1252             System.exit(1);\r
1253         }\r
1254     }\r
1255 }\r