12be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka/* 22be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * Copyright (C) 2012 The Android Open Source Project 32be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * 42be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 52be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * you may not use this file except in compliance with the License. 62be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * You may obtain a copy of the License at 72be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * 82be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 92be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * 102be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 112be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 122be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * See the License for the specific language governing permissions and 142be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka * limitations under the License. 152be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka */ 162be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 176bfd5f631908c4afd893c9b25b353e5e16c5fc0cTadashi G. Takaokapackage com.android.inputmethod.latin.maketext; 182be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 192be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport org.xml.sax.Attributes; 202be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport org.xml.sax.SAXException; 212be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport org.xml.sax.ext.DefaultHandler2; 222be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 232be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.io.IOException; 242be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.io.InputStream; 252be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.util.ArrayList; 262be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.util.Collections; 272be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.util.HashMap; 282be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.util.List; 292be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport java.util.Map; 302be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 312be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport javax.xml.parsers.ParserConfigurationException; 322be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport javax.xml.parsers.SAXParser; 332be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokaimport javax.xml.parsers.SAXParserFactory; 342be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 352be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaokapublic class StringResourceMap { 362be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka // String resource list. 372be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka private final List<StringResource> mResources; 382be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka // Name to string resource map. 392be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka private final Map<String, StringResource> mResourcesMap; 402be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 412be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka public StringResourceMap(final InputStream is) { 422be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka final StringResourceHandler handler = new StringResourceHandler(); 432be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka final SAXParserFactory factory = SAXParserFactory.newInstance(); 442be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka factory.setNamespaceAware(true); 452be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka try { 462be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka final SAXParser parser = factory.newSAXParser(); 472be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka // In order to get comment tag. 482be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler); 492be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka parser.parse(is, handler); 502be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } catch (ParserConfigurationException e) { 512be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } catch (SAXException e) { 522be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka throw new RuntimeException(e.getMessage()); 532be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } catch (IOException e) { 542be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 552be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 562be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka mResources = Collections.unmodifiableList(handler.mResources); 572be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka final HashMap<String,StringResource> map = new HashMap<String,StringResource>(); 582be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka for (final StringResource res : mResources) { 592be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka map.put(res.mName, res); 602be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 612be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka mResourcesMap = map; 622be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 632be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 642be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka public List<StringResource> getResources() { 652be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka return mResources; 662be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 672be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 682be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka public boolean contains(final String name) { 692be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka return mResourcesMap.containsKey(name); 702be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 712be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 722be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka public StringResource get(final String name) { 732be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka return mResourcesMap.get(name); 742be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 752be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 762be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka static class StringResourceHandler extends DefaultHandler2 { 772be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka private static final String TAG_RESOURCES = "resources"; 782be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka private static final String TAG_STRING = "string"; 792be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka private static final String ATTR_NAME = "name"; 802be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 812be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka final ArrayList<StringResource> mResources = new ArrayList<StringResource>(); 822be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 832be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka private String mName; 842be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka private final StringBuilder mValue = new StringBuilder(); 852be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka private final StringBuilder mComment = new StringBuilder(); 862be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 872be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka private void init() { 882be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka mName = null; 892be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka mComment.setLength(0); 902be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 912be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 922be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka @Override 932be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka public void comment(char[] ch, int start, int length) { 942be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka mComment.append(ch, start, length); 955e90f2873c92e14349bd781d69beff4f7b33e760Tadashi G. Takaoka if (ch[start + length - 1] != '\n') { 965e90f2873c92e14349bd781d69beff4f7b33e760Tadashi G. Takaoka mComment.append('\n'); 975e90f2873c92e14349bd781d69beff4f7b33e760Tadashi G. Takaoka } 982be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 992be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 1002be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka @Override 1012be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka public void startElement(String uri, String localName, String qName, Attributes attr) { 1022be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka if (TAG_RESOURCES.equals(localName)) { 1032be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka init(); 1042be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } else if (TAG_STRING.equals(localName)) { 1052be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka mName = attr.getValue(ATTR_NAME); 1062be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka mValue.setLength(0); 1072be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 1082be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 1092be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 1102be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka @Override 1112be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka public void characters(char[] ch, int start, int length) { 1122be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka mValue.append(ch, start, length); 1132be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 1142be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka 1152be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka @Override 1162be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka public void endElement(String uri, String localName, String qName) throws SAXException { 1172be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka if (TAG_STRING.equals(localName)) { 1182be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka if (mName == null) 1192be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka throw new SAXException(TAG_STRING + " doesn't have name"); 1202be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka final String comment = mComment.length() > 0 ? mComment.toString() : null; 1212be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka String value = mValue.toString(); 1222be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka if (value.startsWith("\"") && value.endsWith("\"")) { 1232be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka // Trim surroundings double quote. 1242be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka value = value.substring(1, value.length() - 1); 1252be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 1262be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka mResources.add(new StringResource(mName, value, comment)); 1272be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka init(); 1282be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 1292be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 1302be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka } 1312be51f4fd0c5cd70c7a2757558ffe45e703700cfTadashi G. Takaoka} 132