aboutsummaryrefslogtreecommitdiffstats
path: root/tools/make-keyboard-text/src
diff options
context:
space:
mode:
authorTadashi G. Takaoka <takaoka@google.com>2013-08-13 12:34:01 +0900
committerTadashi G. Takaoka <takaoka@google.com>2013-08-13 15:33:14 +0900
commitca6acfdd6b3400ad6e29d45c29b0ec40ea92a968 (patch)
tree4f412f403c7566a0f7b650299a92e4b4f64ea81b /tools/make-keyboard-text/src
parent0adc8a2ad3630aa01984b4b6ccb2b7ca94cf8948 (diff)
downloadlatinime-ca6acfdd6b3400ad6e29d45c29b0ec40ea92a968.tar.gz
latinime-ca6acfdd6b3400ad6e29d45c29b0ec40ea92a968.tar.xz
latinime-ca6acfdd6b3400ad6e29d45c29b0ec40ea92a968.zip
Rename maketext tool to make-keyboard-text
Change-Id: Icceda22aec75f9e3602da8775c0e94b110283575
Diffstat (limited to 'tools/make-keyboard-text/src')
-rw-r--r--tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java89
-rw-r--r--tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java85
-rw-r--r--tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MakeKeyboardText.java65
-rw-r--r--tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java264
-rw-r--r--tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResource.java29
-rw-r--r--tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java135
6 files changed, 667 insertions, 0 deletions
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java
new file mode 100644
index 000000000..331003e67
--- /dev/null
+++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.tools;
+
+import java.io.PrintStream;
+
+public class ArrayInitializerFormatter {
+ private final PrintStream mOut;
+ private final int mMaxWidth;
+ private final String mIndent;
+
+ private int mCurrentIndex = 0;
+ private String mFixedElement;
+ private final StringBuilder mBuffer = new StringBuilder();
+ private int mBufferedLen;
+ private int mBufferedIndex = Integer.MIN_VALUE;
+
+ public ArrayInitializerFormatter(PrintStream out, int width, String indent) {
+ mOut = out;
+ mMaxWidth = width - indent.length();
+ mIndent = indent;
+ }
+
+ public void flush() {
+ if (mBuffer.length() == 0) {
+ return;
+ }
+ final int lastIndex = mCurrentIndex - 1;
+ if (mBufferedIndex == lastIndex) {
+ mOut.format("%s/* %d */ %s\n", mIndent, mBufferedIndex, mBuffer);
+ } else if (mBufferedIndex == lastIndex - 1) {
+ final String[] elements = mBuffer.toString().split(" ");
+ mOut.format("%s/* %d */ %s\n"
+ + "%s/* %d */ %s\n",
+ mIndent, mBufferedIndex, elements[0],
+ mIndent, lastIndex, elements[1]);
+ } else {
+ mOut.format("%s/* %d~ */\n"
+ + "%s%s\n"
+ + "%s/* ~%d */\n", mIndent, mBufferedIndex,
+ mIndent, mBuffer,
+ mIndent, lastIndex);
+ }
+ mBuffer.setLength(0);
+ mBufferedLen = 0;
+ }
+
+ public void outCommentLines(String lines) {
+ flush();
+ mOut.print(lines);
+ mFixedElement = null;
+ }
+
+ public void outElement(String element) {
+ if (!element.equals(mFixedElement)) {
+ flush();
+ mBufferedIndex = mCurrentIndex;
+ }
+ final int nextLen = mBufferedLen + " ".length() + element.length();
+ if (mBufferedLen != 0 && nextLen < mMaxWidth) {
+ mBuffer.append(' ');
+ mBuffer.append(element);
+ mBufferedLen = nextLen;
+ } else {
+ if (mBufferedLen != 0) {
+ mBuffer.append('\n');
+ mBuffer.append(mIndent);
+ }
+ mBuffer.append(element);
+ mBufferedLen = element.length();
+ }
+ mCurrentIndex++;
+ mFixedElement = element;
+ }
+}
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java
new file mode 100644
index 000000000..a74096e79
--- /dev/null
+++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.tools;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+public final class JarUtils {
+ private JarUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public static JarFile getJarFile(final Class<?> mainClass) {
+ final String mainClassPath = "/" + mainClass.getName().replace('.', '/') + ".class";
+ final URL resUrl = mainClass.getResource(mainClassPath);
+ if (!resUrl.getProtocol().equals("jar")) {
+ throw new RuntimeException("Should run as jar");
+ }
+ final String path = resUrl.getPath();
+ if (!path.startsWith("file:")) {
+ throw new RuntimeException("Unknown jar path: " + path);
+ }
+ final String jarPath = path.substring("file:".length(), path.indexOf('!'));
+ try {
+ return new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ } catch (IOException e) {
+ }
+ return null;
+ }
+
+ public static InputStream openResource(final String name) {
+ return JarUtils.class.getResourceAsStream("/" + name);
+ }
+
+ public interface JarFilter {
+ public boolean accept(String dirName, String name);
+ }
+
+ public static ArrayList<String> getNameListing(final JarFile jar, final JarFilter filter) {
+ final ArrayList<String> result = new ArrayList<String>();
+ final Enumeration<JarEntry> entries = jar.entries();
+ while (entries.hasMoreElements()) {
+ final JarEntry entry = entries.nextElement();
+ final String path = entry.getName();
+ final int pos = path.lastIndexOf('/');
+ final String dirName = (pos >= 0) ? path.substring(0, pos) : "";
+ final String name = (pos >= 0) ? path.substring(pos + 1) : path;
+ if (filter.accept(dirName, name)) {
+ result.add(path);
+ }
+ }
+ return result;
+ }
+
+ public static ArrayList<String> getNameListing(final JarFile jar, final String filterName) {
+ return getNameListing(jar, new JarFilter() {
+ @Override
+ public boolean accept(final String dirName, final String name) {
+ return name.equals(filterName);
+ }
+ });
+ }
+}
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MakeKeyboardText.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MakeKeyboardText.java
new file mode 100644
index 000000000..36a03f8dc
--- /dev/null
+++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MakeKeyboardText.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.keyboard.tools;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+import java.util.jar.JarFile;
+
+public class MakeKeyboardText {
+ static class Options {
+ private static final String OPTION_JAVA = "-java";
+
+ public final String mJava;
+
+ public static void usage(String message) {
+ if (message != null) {
+ System.err.println(message);
+ }
+ System.err.println("usage: make-keyboard-text " + OPTION_JAVA + " <java_output_dir>");
+ System.exit(1);
+ }
+
+ public Options(final String[] argsArray) {
+ final LinkedList<String> args = new LinkedList<String>(Arrays.asList(argsArray));
+ String arg = null;
+ String java = null;
+ try {
+ while (!args.isEmpty()) {
+ arg = args.removeFirst();
+ if (arg.equals(OPTION_JAVA)) {
+ java = args.removeFirst();
+ } else {
+ usage("Unknown option: " + arg);
+ }
+ }
+ } catch (NoSuchElementException e) {
+ usage("Option " + arg + " needs argument");
+ }
+
+ mJava = java;
+ }
+ }
+
+ public static void main(final String[] args) {
+ final Options options = new Options(args);
+ final JarFile jar = JarUtils.getJarFile(MakeKeyboardText.class);
+ final MoreKeysResources resources = new MoreKeysResources(jar);
+ resources.writeToJava(options.mJava);
+ }
+}
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java
new file mode 100644
index 000000000..2643e01ec
--- /dev/null
+++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.tools;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.jar.JarFile;
+
+public class MoreKeysResources {
+ private static final String TEXT_RESOURCE_NAME = "donottranslate-more-keys.xml";
+
+ private static final String JAVA_TEMPLATE = "KeyboardTextsSet.tmpl";
+ private static final String MARK_NAMES = "@NAMES@";
+ private static final String MARK_DEFAULT_TEXTS = "@DEFAULT_TEXTS@";
+ private static final String MARK_TEXTS = "@TEXTS@";
+ private static final String MARK_LANGUAGES_AND_TEXTS = "@LANGUAGES_AND_TEXTS@";
+ private static final String DEFAUT_LANGUAGE_NAME = "DEFAULT";
+ private static final String ARRAY_NAME_FOR_LANGUAGE = "LANGUAGE_%s";
+ private static final String EMPTY_STRING_VAR = "EMPTY";
+
+ private static final String NO_LANGUAGE_CODE = "zz";
+ private static final String NO_LANGUAGE_DISPLAY_NAME = "Alphabet";
+
+ private final JarFile mJar;
+ // Language to string resources map.
+ private final HashMap<String, StringResourceMap> mResourcesMap =
+ new HashMap<String, StringResourceMap>();
+ // Name to id map.
+ private final HashMap<String, Integer> mNameToIdMap = new HashMap<String,Integer>();
+
+ public MoreKeysResources(final JarFile jar) {
+ mJar = jar;
+ final ArrayList<String> resources = JarUtils.getNameListing(jar, TEXT_RESOURCE_NAME);
+ for (final String name : resources) {
+ final String dirName = name.substring(0, name.lastIndexOf('/'));
+ final int pos = dirName.lastIndexOf('/');
+ final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName;
+ final String language = getLanguageFromResDir(parentName);
+ final InputStream stream = JarUtils.openResource(name);
+ try {
+ mResourcesMap.put(language, new StringResourceMap(stream));
+ } finally {
+ close(stream);
+ }
+ }
+ }
+
+ private static String getLanguageFromResDir(final String dirName) {
+ final int languagePos = dirName.indexOf('-');
+ if (languagePos < 0) {
+ // Default resource.
+ return DEFAUT_LANGUAGE_NAME;
+ }
+ final String language = dirName.substring(languagePos + 1);
+ final int countryPos = language.indexOf("-r");
+ if (countryPos < 0) {
+ return language;
+ }
+ return language.replace("-r", "_");
+ }
+
+ public void writeToJava(final String outDir) {
+ final ArrayList<String> list = JarUtils.getNameListing(mJar, JAVA_TEMPLATE);
+ if (list.isEmpty())
+ throw new RuntimeException("Can't find java template " + JAVA_TEMPLATE);
+ if (list.size() > 1)
+ throw new RuntimeException("Found multiple java template " + JAVA_TEMPLATE);
+ final String template = list.get(0);
+ final String javaPackage = template.substring(0, template.lastIndexOf('/'));
+ PrintStream ps = null;
+ LineNumberReader lnr = null;
+ try {
+ if (outDir == null) {
+ ps = System.out;
+ } else {
+ final File outPackage = new File(outDir, javaPackage);
+ final File outputFile = new File(outPackage,
+ JAVA_TEMPLATE.replace(".tmpl", ".java"));
+ outPackage.mkdirs();
+ ps = new PrintStream(outputFile, "UTF-8");
+ }
+ lnr = new LineNumberReader(new InputStreamReader(JarUtils.openResource(template)));
+ inflateTemplate(lnr, ps);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ close(lnr);
+ close(ps);
+ }
+ }
+
+ private void inflateTemplate(final LineNumberReader in, final PrintStream out)
+ throws IOException {
+ String line;
+ while ((line = in.readLine()) != null) {
+ if (line.contains(MARK_NAMES)) {
+ dumpNames(out);
+ } else if (line.contains(MARK_DEFAULT_TEXTS)) {
+ dumpDefaultTexts(out);
+ } else if (line.contains(MARK_TEXTS)) {
+ dumpTexts(out);
+ } else if (line.contains(MARK_LANGUAGES_AND_TEXTS)) {
+ dumpLanguageMap(out);
+ } else {
+ out.println(line);
+ }
+ }
+ }
+
+ private void dumpNames(final PrintStream out) {
+ final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME);
+ int id = 0;
+ for (final StringResource res : defaultResMap.getResources()) {
+ out.format(" /* %2d */ \"%s\",\n", id, res.mName);
+ mNameToIdMap.put(res.mName, id);
+ id++;
+ }
+ }
+
+ private void dumpDefaultTexts(final PrintStream out) {
+ final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME);
+ dumpTextsInternal(out, defaultResMap, defaultResMap);
+ }
+
+ private void dumpTexts(final PrintStream out) {
+ final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME);
+ final ArrayList<String> allLanguages = new ArrayList<String>();
+ allLanguages.addAll(mResourcesMap.keySet());
+ Collections.sort(allLanguages);
+ for (final String language : allLanguages) {
+ if (language.equals(DEFAUT_LANGUAGE_NAME)) {
+ continue;
+ }
+ out.format(" /* Language %s: %s */\n", language, getLanguageDisplayName(language));
+ out.format(" private static final String[] " + ARRAY_NAME_FOR_LANGUAGE + " = {\n",
+ language);
+ final StringResourceMap resMap = mResourcesMap.get(language);
+ for (final StringResource res : resMap.getResources()) {
+ if (!defaultResMap.contains(res.mName)) {
+ throw new RuntimeException(res.mName + " in " + language
+ + " doesn't have default resource");
+ }
+ }
+ dumpTextsInternal(out, resMap, defaultResMap);
+ out.format(" };\n\n");
+ }
+ }
+
+ private void dumpLanguageMap(final PrintStream out) {
+ final ArrayList<String> allLanguages = new ArrayList<String>();
+ allLanguages.addAll(mResourcesMap.keySet());
+ Collections.sort(allLanguages);
+ for (final String language : allLanguages) {
+ out.format(" \"%s\", " + ARRAY_NAME_FOR_LANGUAGE + ", /* %s */\n",
+ language, language, getLanguageDisplayName(language));
+ }
+ }
+
+ private static String getLanguageDisplayName(final String language) {
+ if (language.equals(NO_LANGUAGE_CODE)) {
+ return NO_LANGUAGE_DISPLAY_NAME;
+ } else {
+ return new Locale(language).getDisplayLanguage();
+ }
+ }
+
+ private static void dumpTextsInternal(final PrintStream out, final StringResourceMap resMap,
+ final StringResourceMap defaultResMap) {
+ final ArrayInitializerFormatter formatter =
+ new ArrayInitializerFormatter(out, 100, " ");
+ boolean successiveNull = false;
+ for (final StringResource defaultRes : defaultResMap.getResources()) {
+ if (resMap.contains(defaultRes.mName)) {
+ final StringResource res = resMap.get(defaultRes.mName);
+ if (res.mComment != null) {
+ formatter.outCommentLines(addPrefix(" // ", res. mComment));
+ }
+ final String escaped = escapeNonAscii(res.mValue);
+ if (escaped.length() == 0) {
+ formatter.outElement(EMPTY_STRING_VAR + ",");
+ } else {
+ formatter.outElement(String.format("\"%s\",", escaped));
+ }
+ successiveNull = false;
+ } else {
+ formatter.outElement("null,");
+ successiveNull = true;
+ }
+ }
+ if (!successiveNull) {
+ formatter.flush();
+ }
+ }
+
+ private static String addPrefix(final String prefix, final String lines) {
+ final StringBuilder sb = new StringBuilder();
+ for (final String line : lines.split("\n")) {
+ sb.append(prefix + line.trim() + "\n");
+ }
+ return sb.toString();
+ }
+
+ private static String escapeNonAscii(final String text) {
+ final StringBuilder sb = new StringBuilder();
+ final int length = text.length();
+ for (int i = 0; i < length; i++) {
+ final char c = text.charAt(i);
+ if (c >= ' ' && c < 0x7f) {
+ sb.append(c);
+ } else {
+ sb.append(String.format("\\u%04X", (int)c));
+ }
+ }
+ return replaceIncompatibleEscape(sb.toString());
+ }
+
+ private static String replaceIncompatibleEscape(final String text) {
+ String t = text;
+ t = replaceAll(t, "\\?", "?");
+ t = replaceAll(t, "\\@", "@");
+ t = replaceAll(t, "@string/", "!text/");
+ return t;
+ }
+
+ private static String replaceAll(final String text, final String target, final String replace) {
+ String t = text;
+ while (t.indexOf(target) >= 0) {
+ t = t.replace(target, replace);
+ }
+ return t;
+ }
+
+ private static void close(Closeable stream) {
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException e) {
+ }
+ }
+}
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResource.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResource.java
new file mode 100644
index 000000000..a49b8fe70
--- /dev/null
+++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResource.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.tools;
+
+public class StringResource {
+ public final String mName;
+ public final String mValue;
+ public final String mComment;
+
+ public StringResource(final String name, final String value, final String comment) {
+ mName = name;
+ mValue = value;
+ mComment = comment;
+ }
+}
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java
new file mode 100644
index 000000000..cc7ff6a9c
--- /dev/null
+++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.tools;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.ext.DefaultHandler2;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+public class StringResourceMap {
+ // String resource list.
+ private final List<StringResource> mResources;
+ // Name to string resource map.
+ private final Map<String, StringResource> mResourcesMap;
+
+ public StringResourceMap(final InputStream is) {
+ final StringResourceHandler handler = new StringResourceHandler();
+ final SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+ try {
+ final SAXParser parser = factory.newSAXParser();
+ // In order to get comment tag.
+ parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
+ parser.parse(is, handler);
+ } catch (ParserConfigurationException e) {
+ } catch (SAXParseException e) {
+ throw new RuntimeException(e.getMessage() + " at line " + e.getLineNumber()
+ + ", column " + e.getColumnNumber());
+ } catch (SAXException e) {
+ throw new RuntimeException(e.getMessage());
+ } catch (IOException e) {
+ }
+
+ mResources = Collections.unmodifiableList(handler.mResources);
+ final HashMap<String,StringResource> map = new HashMap<String,StringResource>();
+ for (final StringResource res : mResources) {
+ map.put(res.mName, res);
+ }
+ mResourcesMap = map;
+ }
+
+ public List<StringResource> getResources() {
+ return mResources;
+ }
+
+ public boolean contains(final String name) {
+ return mResourcesMap.containsKey(name);
+ }
+
+ public StringResource get(final String name) {
+ return mResourcesMap.get(name);
+ }
+
+ static class StringResourceHandler extends DefaultHandler2 {
+ private static final String TAG_RESOURCES = "resources";
+ private static final String TAG_STRING = "string";
+ private static final String ATTR_NAME = "name";
+
+ final ArrayList<StringResource> mResources = new ArrayList<StringResource>();
+
+ private String mName;
+ private final StringBuilder mValue = new StringBuilder();
+ private final StringBuilder mComment = new StringBuilder();
+
+ private void init() {
+ mName = null;
+ mComment.setLength(0);
+ }
+
+ @Override
+ public void comment(char[] ch, int start, int length) {
+ mComment.append(ch, start, length);
+ if (ch[start + length - 1] != '\n') {
+ mComment.append('\n');
+ }
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attr) {
+ if (TAG_RESOURCES.equals(localName)) {
+ init();
+ } else if (TAG_STRING.equals(localName)) {
+ mName = attr.getValue(ATTR_NAME);
+ mValue.setLength(0);
+ }
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) {
+ mValue.append(ch, start, length);
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ if (TAG_STRING.equals(localName)) {
+ if (mName == null)
+ throw new SAXException(TAG_STRING + " doesn't have name");
+ final String comment = mComment.length() > 0 ? mComment.toString() : null;
+ String value = mValue.toString();
+ if (value.startsWith("\"") && value.endsWith("\"")) {
+ // Trim surroundings double quote.
+ value = value.substring(1, value.length() - 1);
+ }
+ mResources.add(new StringResource(mName, value, comment));
+ init();
+ }
+ }
+ }
+}