/* * * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */ /** * This tool upgrades a LocalizedStrings<locale>.java file to the new XML file * format. An example file is * src/configuration/configurator/share/l10n/en-US.xml. <p> * * Usage: * javac UpgradeL10N.java * java -cp . UpgradeL10N [inencoding] [infile] \ * [outencoding] [outfile] [outclass] * * You must specify an [inencoding] that's the same as the character * encoding used by [infile]. * * E.g., * * java -cp . UpgradeL10N ISO-8859-1 LocalizedStrings.java \ * ISO-8859-1 en-US.xml LocalizedStringsBase */ import java.util.*; import java.io.*; public class UpgradeL10N { static BufferedReader reader; static PrintWriter writer; /** * Short-hand for printint a line into the output file */ static void pl(String s) { writer.println(s); } /** * Run the tool */ public static void main(String args[]) throws Throwable { String inEncoding = args[0]; String inFile = args[1]; String outEncoding = args[2]; String outFile = args[3]; String outClass = args[4]; FileInputStream fin = new FileInputStream(inFile); InputStreamReader r = new InputStreamReader(fin, inEncoding); reader = new BufferedReader(r); FileOutputStream fout = new FileOutputStream(outFile); OutputStreamWriter w = new OutputStreamWriter(fout, outEncoding); writer = new PrintWriter(w); // Write the XML file prolog. pl("<?xml version=\"1.0\" encoding=\"" + outEncoding + "\"?>"); pl("<!DOCTYPE configuration SYSTEM \"../configuration.dtd\">"); pl("<!--"); pl(" "); pl(""); pl(" Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved."); pl(" DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER"); pl(" "); pl(" This program is free software; you can redistribute it and/or"); pl(" modify it under the terms of the GNU General Public License version"); pl(" 2 only, as published by the Free Software Foundation."); pl(" "); pl(" This program is distributed in the hope that it will be useful, but"); pl(" WITHOUT ANY WARRANTY; without even the implied warranty of"); pl(" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU"); pl(" General Public License version 2 for more details (a copy is"); pl(" included at /legal/license.txt)."); pl(" "); pl(" You should have received a copy of the GNU General Public License"); pl(" version 2 along with this work; if not, write to the Free Software"); pl(" Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA"); pl(" 02110-1301 USA"); pl(" "); pl(" Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa"); pl(" Clara, CA 95054 or visit www.sun.com if you need additional"); pl(" information or have any questions."); pl("-->"); pl("<configuration>"); pl("<localized_strings Package=\"com.sun.midp.l10n\" Name=\"" + outClass + "\">"); StringBuffer sbuf = new StringBuffer(); String line; while ((line = reader.readLine()) != null) { sbuf.append(line); sbuf.append("\n"); } // Find all occurrences of // new Integer(ResourceConstants.DONE), "\u5B8C\u6210" // ^^^^ ^^^^^^^^^^^^ // key value Parser p = new Parser(sbuf.toString()); while (p.advance("Integer")) { p.mark(); try { p.skipSpaces(); p.skip('('); p.skipSpaces(); p.skip("ResourceConstants"); p.skipSpaces(); p.skip("."); p.skipSpaces(); String key = p.readSymbol(); p.skipSpaces(); p.skip(')'); p.skipSpaces(); p.skip(','); p.skipSpaces(); String value = p.readStringLiteral(); while (true) { p.mark(); try { // Handle any "xxx" + "yyy" cases p.skipSpaces(); p.skip('+'); p.skipSpaces(); String more = p.readStringLiteral(); value += more; p.pop(); } catch (Error t) { p.reset(); break; } } pl("<localized_string Key=\"" + key + "\""); pl(" Value=\"" + quote(value) + "\"/>"); } catch (UnsupportedOperationException t) { System.out.println("Error: " + t.getMessage()); System.out.println("at line " + p.countLine()); System.out.println("at character " + p.countPos()); System.exit(1); } catch (Error t) { // This loop will eventually terminate, since we at least // consume ".*Integer" from each iteration. p.reset(); } } pl("</localized_strings>"); pl("</configuration>"); writer.close(); } /** Quote characters that must be escaped for valid XML documents */ static String quote(String s) { if (s.indexOf('&') != -1 || s.indexOf('<') != -1 || s.indexOf('>') != -1 || s.indexOf('\n') != -1 || s.indexOf('"') != -1) { StringBuffer sbuf = new StringBuffer(); for (int i=0; i<s.length(); i++) { char c = s.charAt(i); if (c == '"') { sbuf.append("""); } else if (c == '&') { sbuf.append("&"); } else if (c == '>') { sbuf.append(">"); } else if (c == '<') { sbuf.append("<"); } else if (c == '\n') { sbuf.append(" "); } else { sbuf.append(c); } } return sbuf.toString(); } return s; } } /** * A simple parser to parsing Java source code like this: * new Integer(ResourceConstants.DONE), "\u5B8C\u6210" * ^^^^ ^^^^^^^^^^^^ * key value */ class Parser { int index; String s; Stack markStack = new Stack(); /** * Encounter an error when the parser tries to prefetch data. This is * normal condition. The caller should call Parser.reset() and continue. * * In a source code error is found, a UnsupportedOperationException * is thrown instead. */ void abortPrefetch() { throw new Error(); } Parser(String s) { this.s = s; index = 0; } void mark() { markStack.push(new Integer(index)); } void reset() throws Throwable { Integer i = (Integer)markStack.pop(); index = i.intValue(); } void pop() throws Throwable { markStack.pop(); } boolean advance(String token) { int n = s.indexOf(token, index); if (n < 0) { return false; } else { index = n + token.length(); return true; } } void skipSpaces() { while (index < s.length()) { char c = s.charAt(index); if (!Character.isSpaceChar(c) && c != '\n' && c != '\r' && c != '\t') { return; } else { index ++; } } } void skip(char c) { if (s.charAt(index) == c) { index ++; return; } else { abortPrefetch(); } } void skip(String token) { for (int i=0; i<token.length(); i++) { skip(token.charAt(i)); } } String readSymbol() { StringBuffer sbuf = new StringBuffer(); while (index < s.length()) { char c = s.charAt(index); if (sbuf.length() == 0) { if (!Character.isJavaIdentifierStart(c)) { abortPrefetch(); } } else { if (!Character.isJavaIdentifierPart(c)) { return sbuf.toString(); } } index ++; sbuf.append(c); } if (sbuf.length() == 0) { abortPrefetch(); } return sbuf.toString(); } String readStringLiteral() { skip('"'); StringBuffer sbuf = new StringBuffer(); while (index < s.length()) { char c = next(); switch (c) { case '\\': switch (next()) { case '\\': sbuf.append("\\"); break; case '\'': sbuf.append("\'"); break; case '\"': sbuf.append("\""); break; case 'n': sbuf.append("\n"); break; case 'r': sbuf.append("\r"); break; case 't': sbuf.append("\t"); break; case 'x': sbuf.append((char) ((nextHex() << 4) | nextHex())); break; case 'u': sbuf.append((char) ((nextHex() << 12) | (nextHex() << 8) | (nextHex() << 4) | (nextHex() << 0))); break; default: throw new UnsupportedOperationException( "Invalid escape sequence"); } break; case '"': return sbuf.toString(); default: sbuf.append(c); } } throw new UnsupportedOperationException("unterminated string"); } int nextHex() { char c = next(); if ('0' <= c && c <= '9') { return (int)(c - '0'); } if ('A' <= c && c <= 'F') { return (int)(c - 'A'); } if ('a' <= c && c <= 'f') { return (int)(c - 'a'); } throw new UnsupportedOperationException("Expected hex number but got " + c); } char next() { // will throw if we get to EOF return s.charAt(index++); } int countLine() { int line = 1; for (int i=0; i<index && i < s.length(); i++) { if (s.charAt(i) == '\n') { ++ line; } } return line; } int countPos() { int pos = 1; for (int i=0; i<index && i < s.length(); i++) { if (s.charAt(i) == '\n') { pos = 0; } else { pos ++; } } return pos; } }