Properties.java revision f5597e626ecf7949d249dea08c1a2964d890ec11
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.util;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
22f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.io.BufferedInputStream;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.OutputStream;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.OutputStreamWriter;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.PrintStream;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.PrintWriter;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.StringReader;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.Charset;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.IllegalCharsetNameException;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.UnsupportedCharsetException;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AccessController;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.xml.parsers.DocumentBuilder;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.xml.parsers.DocumentBuilderFactory;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport javax.xml.parsers.ParserConfigurationException;
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.EntityResolver;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.ErrorHandler;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.InputSource;
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.SAXException;
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.xml.sax.SAXParseException;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Document;
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Element;
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.NodeList;
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project// BEGIN android-added
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Node;
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Text;
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project// END android-added
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.luni.internal.nls.Messages;
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.luni.util.PriviAction;
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
55f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * A {@code Properties} object is a {@code Hashtable} where the keys and values
56f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * must be {@code String}s. Each property can have a default
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code Properties} list which specifies the default
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * values to be used when a given key is not found in this {@code Properties}
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * instance.
60f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see Hashtable
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.lang.System#getProperties
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
64f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonpublic class Properties extends Hashtable<Object, Object> {
65f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final long serialVersionUID = 4112578634029874840L;
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private transient DocumentBuilder builder = null;
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
70f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    private static final String PROP_DTD_NAME = "http://java.sun.com/dtd/properties.dtd";
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
72f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    private static final String PROP_DTD = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            + "    <!ELEMENT properties (comment?, entry*) >"
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            + "    <!ATTLIST properties version CDATA #FIXED \"1.0\" >"
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            + "    <!ELEMENT comment (#PCDATA) >"
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            + "    <!ELEMENT entry (#PCDATA) >"
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            + "    <!ATTLIST entry key CDATA #REQUIRED >";
78f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The default values for keys not found in this {@code Properties}
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * instance.
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected Properties defaults;
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final int NONE = 0, SLASH = 1, UNICODE = 2, CONTINUE = 3,
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            KEY_DONE = 4, IGNORE = 5;
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new {@code Properties} object.
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Properties() {
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super();
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new {@code Properties} object using the specified default
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code Properties}.
98f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param properties
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the default {@code Properties}.
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Properties(Properties properties) {
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        defaults = properties;
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void dumpString(StringBuilder buffer, String string, boolean key) {
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int i = 0;
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!key && i < string.length() && string.charAt(i) == ' ') {
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.append("\\ "); //$NON-NLS-1$
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            i++;
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (; i < string.length(); i++) {
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            char ch = string.charAt(i);
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            switch (ch) {
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case '\t':
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer.append("\\t"); //$NON-NLS-1$
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case '\n':
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer.append("\\n"); //$NON-NLS-1$
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case '\f':
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer.append("\\f"); //$NON-NLS-1$
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case '\r':
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer.append("\\r"); //$NON-NLS-1$
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            default:
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if ("\\#!=:".indexOf(ch) >= 0 || (key && ch == ' ')) {
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    buffer.append('\\');
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (ch >= ' ' && ch <= '~') {
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    buffer.append(ch);
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    String hex = Integer.toHexString(ch);
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    buffer.append("\\u"); //$NON-NLS-1$
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    for (int j = 0; j < 4 - hex.length(); j++) {
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        buffer.append("0"); //$NON-NLS-1$
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    buffer.append(hex);
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Searches for the property with the specified name. If the property is not
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * found, the default {@code Properties} are checked. If the property is not
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * found in the default {@code Properties}, {@code null} is returned.
150f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the property to find.
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the named property value, or {@code null} if it can't be found.
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getProperty(String name) {
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Object result = super.get(name);
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String property = result instanceof String ? (String) result : null;
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (property == null && defaults != null) {
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            property = defaults.getProperty(name);
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return property;
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Searches for the property with the specified name. If the property is not
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * found, it looks in the default {@code Properties}. If the property is not
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * found in the default {@code Properties}, it returns the specified
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * default.
169f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the property to find.
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param defaultValue
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the default value.
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the named property value.
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getProperty(String name, String defaultValue) {
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Object result = super.get(name);
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String property = result instanceof String ? (String) result : null;
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (property == null && defaults != null) {
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            property = defaults.getProperty(name);
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (property == null) {
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return defaultValue;
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return property;
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Lists the mappings in this {@code Properties} to the specified
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code PrintStream} in a
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * human readable form.
192f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code PrintStream} to write the content to in human readable
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            form.
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void list(PrintStream out) {
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (out == null) {
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        StringBuffer buffer = new StringBuffer(80);
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Enumeration<?> keys = propertyNames();
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (keys.hasMoreElements()) {
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String key = (String) keys.nextElement();
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.append(key);
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.append('=');
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String property = (String) super.get(key);
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Properties def = defaults;
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (property == null) {
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                property = (String) def.get(key);
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                def = def.defaults;
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (property.length() > 40) {
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer.append(property.substring(0, 37));
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer.append("..."); //$NON-NLS-1$
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer.append(property);
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            out.println(buffer.toString());
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.setLength(0);
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Lists the mappings in this {@code Properties} to the specified
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code PrintWriter} in a
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * human readable form.
228f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param writer
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code PrintWriter} to write the content to in human
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            readable form.
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void list(PrintWriter writer) {
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (writer == null) {
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        StringBuffer buffer = new StringBuffer(80);
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Enumeration<?> keys = propertyNames();
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (keys.hasMoreElements()) {
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String key = (String) keys.nextElement();
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.append(key);
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.append('=');
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String property = (String) super.get(key);
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Properties def = defaults;
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (property == null) {
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                property = (String) def.get(key);
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                def = def.defaults;
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (property.length() > 40) {
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer.append(property.substring(0, 37));
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer.append("..."); //$NON-NLS-1$
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buffer.append(property);
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            writer.println(buffer.toString());
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.setLength(0);
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Loads properties from the specified {@code InputStream}. The encoding is
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * ISO8859-1. The {@code Properties} file is interpreted according to the
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * following rules:
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <ul>
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>Empty lines are ignored.</li>
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>Lines starting with either a "#" or a "!" are comment lines and are
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * ignored.</li>
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>A backslash at the end of the line escapes the following newline
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * character ("\r", "\n", "\r\n"). If there's a whitespace after the
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * backslash it will just escape that whitespace instead of concatenating
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the lines. This does not apply to comment lines.</li>
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>A property line consists of the key, the space between the key and
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the value, and the value. The key goes up to the first whitespace, "=" or
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * ":" that is not escaped. The space between the key and the value contains
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * either one whitespace, one "=" or one ":" and any number of additional
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * whitespaces before and after that character. The value starts with the
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * first character after the space between the key and the value.</li>
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <li>Following escape sequences are recognized: "\ ", "\\", "\r", "\n",
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * "\!", "\#", "\t", "\b", "\f", and "&#92;uXXXX" (unicode character).</li>
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </ul>
281f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the {@code InputStream}.
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if error occurs during reading from the {@code InputStream}.
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
287f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    @SuppressWarnings("fallthrough")
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized void load(InputStream in) throws IOException {
289f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (in == null) {
290f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            throw new NullPointerException();
291f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int mode = NONE, unicode = 0, count = 0;
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        char nextChar, buf[] = new char[40];
294f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        int offset = 0, keyLength = -1, intVal;
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        boolean firstChar = true;
296f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        BufferedInputStream bis = new BufferedInputStream(in);
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (true) {
299f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            intVal = bis.read();
300f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (intVal == -1) {
301f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // if mode is UNICODE but has less than 4 hex digits, should
302f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // throw an IllegalArgumentException
303f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // luni.08=Invalid Unicode sequence: expected format \\uxxxx
304f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (mode == UNICODE && count < 4) {
305f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    throw new IllegalArgumentException(Messages.getString("luni.08")); //$NON-NLS-1$
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
307f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // if mode is SLASH and no data is read, should append '\u0000'
308f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                // to buf
309f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                if (mode == SLASH) {
310f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    buf[offset++] = '\u0000';
311f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                }
312f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                break;
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
314f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            nextChar = (char) (intVal & 0xff);
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (offset == buf.length) {
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                char[] newBuf = new char[buf.length * 2];
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                System.arraycopy(buf, 0, newBuf, 0, offset);
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buf = newBuf;
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (mode == UNICODE) {
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                int digit = Character.digit(nextChar, 16);
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (digit >= 0) {
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    unicode = (unicode << 4) + digit;
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (++count < 4) {
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        continue;
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else if (count <= 4) {
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // luni.09=Invalid Unicode sequence: illegal character
330f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    throw new IllegalArgumentException(Messages.getString("luni.09")); //$NON-NLS-1$
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                mode = NONE;
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                buf[offset++] = (char) unicode;
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (nextChar != '\n') {
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    continue;
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (mode == SLASH) {
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                mode = NONE;
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                switch (nextChar) {
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case '\r':
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    mode = CONTINUE; // Look for a following \n
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    continue;
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case '\n':
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    mode = IGNORE; // Ignore whitespace on the next line
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    continue;
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case 'b':
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    nextChar = '\b';
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case 'f':
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    nextChar = '\f';
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case 'n':
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    nextChar = '\n';
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case 'r':
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    nextChar = '\r';
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case 't':
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    nextChar = '\t';
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case 'u':
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    mode = UNICODE;
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    unicode = count = 0;
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    continue;
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                switch (nextChar) {
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case '#':
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case '!':
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (firstChar) {
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        while (true) {
373f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            intVal = bis.read();
374f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            if (intVal == -1) {
375f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                                break;
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            }
377f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            // & 0xff not required
378f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            nextChar = (char) intVal;
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            if (nextChar == '\r' || nextChar == '\n') {
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                break;
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            }
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        continue;
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case '\n':
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (mode == CONTINUE) { // Part of a \r\n sequence
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        mode = IGNORE; // Ignore whitespace on the next line
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        continue;
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
391f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    // fall into the next case
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case '\r':
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    mode = NONE;
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    firstChar = true;
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (offset > 0) {
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (keyLength == -1) {
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            keyLength = offset;
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        String temp = new String(buf, 0, offset);
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        put(temp.substring(0, keyLength), temp
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                .substring(keyLength));
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    keyLength = -1;
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    offset = 0;
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    continue;
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case '\\':
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (mode == KEY_DONE) {
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        keyLength = offset;
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    mode = SLASH;
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    continue;
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case ':':
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                case '=':
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (keyLength == -1) { // if parsing the key
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        mode = NONE;
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        keyLength = offset;
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        continue;
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    break;
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (Character.isWhitespace(nextChar)) {
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (mode == CONTINUE) {
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        mode = IGNORE;
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // if key length == 0 or value length == 0
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (offset == 0 || offset == keyLength || mode == IGNORE) {
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        continue;
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (keyLength == -1) { // if parsing the key
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        mode = KEY_DONE;
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        continue;
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (mode == IGNORE || mode == CONTINUE) {
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    mode = NONE;
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            firstChar = false;
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (mode == KEY_DONE) {
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                keyLength = offset;
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                mode = NONE;
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buf[offset++] = nextChar;
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
445f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (keyLength == -1 && offset > 0) {
446f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            keyLength = offset;
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (keyLength >= 0) {
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String temp = new String(buf, 0, offset);
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            put(temp.substring(0, keyLength), temp.substring(keyLength));
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns all of the property names that this {@code Properties} object
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * contains.
457f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return an {@code Enumeration} containing the names of all properties
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         that this {@code Properties} object contains.
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Enumeration<?> propertyNames() {
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (defaults == null) {
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return keys();
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
466f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        Hashtable<Object, Object> set = new Hashtable<Object, Object>(defaults
467f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                .size()
468f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                + size());
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Enumeration<?> keys = defaults.propertyNames();
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (keys.hasMoreElements()) {
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            set.put(keys.nextElement(), set);
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        keys = keys();
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (keys.hasMoreElements()) {
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            set.put(keys.nextElement(), set);
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return set.keys();
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Saves the mappings in this {@code Properties} to the specified {@code
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * OutputStream}, putting the specified comment at the beginning. The output
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * from this method is suitable for being read by the
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #load(InputStream)} method.
485f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out the {@code OutputStream} to write to.
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param comment the comment to add at the beginning.
488f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws ClassCastException if the key or value of a mapping is not a
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                String.
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @deprecated This method ignores any {@code IOException} thrown while
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             writing -- use {@link #store} instead for better exception
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             handling.
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Deprecated
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void save(OutputStream out, String comment) {
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            store(out, comment);
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IOException e) {
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Maps the specified key to the specified value. If the key already exists,
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the old value is replaced. The key and value cannot be {@code null}.
505f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the key.
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param value
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the value.
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the old value mapped to the key, or {@code null}.
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public Object setProperty(String name, String value) {
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return put(name, value);
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static String lineSeparator;
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Stores the mappings in this {@code Properties} to the specified {@code
520adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * OutputStream}, putting the specified comment at the beginning. The output
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * from this method is suitable for being read by the
522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@link #load(InputStream)} method.
523f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param out the {@code OutputStream} to write to.
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param comment the comment to put at the beginning.
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException if an error occurs during the write to the {@code
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             OutputStream}.
528f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @throws ClassCastException if the key or value of a mapping is not a
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *                {@code String}.
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized void store(OutputStream out, String comment)
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IOException {
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (lineSeparator == null) {
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            lineSeparator = AccessController
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .doPrivileged(new PriviAction<String>("line.separator")); //$NON-NLS-1$
536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        StringBuilder buffer = new StringBuilder(200);
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        OutputStreamWriter writer = new OutputStreamWriter(out, "ISO8859_1"); //$NON-NLS-1$
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (comment != null) {
541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            writer.write("#"); //$NON-NLS-1$
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            writer.write(comment);
543f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            writer.write(lineSeparator);
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        writer.write("#"); //$NON-NLS-1$
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        writer.write(new Date().toString());
547f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        writer.write(lineSeparator);
548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (Map.Entry<Object, Object> entry : entrySet()) {
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String key = (String) entry.getKey();
551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            dumpString(buffer, key, true);
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.append('=');
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            dumpString(buffer, (String) entry.getValue(), false);
554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.append(lineSeparator);
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            writer.write(buffer.toString());
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            buffer.setLength(0);
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        writer.flush();
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Loads the properties from an {@code InputStream} containing the
563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * properties in XML form. The XML document must begin with (and conform to)
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * following DOCTYPE:
565f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <pre>
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * &lt;!DOCTYPE properties SYSTEM &quot;http://java.sun.com/dtd/properties.dtd">;
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </pre>
569f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Also the content of the XML data must satisfy the DTD but the xml is not
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * validated against it. The DTD is not loaded from the SYSTEM ID. After
572adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * this method returns the InputStream is not closed.
573f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
574adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param in the InputStream containing the XML document.
575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException in case an error occurs during a read operation.
576adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws InvalidPropertiesFormatException if the XML data is not a valid
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             properties file.
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
579f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public synchronized void loadFromXML(InputStream in) throws IOException,
580f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            InvalidPropertiesFormatException {
581adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (in == null) {
582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
584f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (builder == null) {
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // BEGIN android-removed
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // factory.setValidating(true);
589adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // END android-removed
590f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                builder = factory.newDocumentBuilder();
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (ParserConfigurationException e) {
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new Error(e);
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
596f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            builder.setErrorHandler(new ErrorHandler() {
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                public void warning(SAXParseException e) throws SAXException {
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    throw e;
600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                public void error(SAXParseException e) throws SAXException {
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    throw e;
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                public void fatalError(SAXParseException e) throws SAXException {
607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    throw e;
608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
609adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            });
610f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            builder.setEntityResolver(new EntityResolver() {
612f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                public InputSource resolveEntity(String publicId,
613f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                        String systemId) throws SAXException, IOException {
614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (systemId.equals(PROP_DTD_NAME)) {
615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        InputSource result = new InputSource(new StringReader(
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                PROP_DTD));
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        result.setSystemId(PROP_DTD_NAME);
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        return result;
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
620f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                    throw new SAXException("Invalid DOCTYPE declaration: "
621f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                            + systemId);
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            });
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
625f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Document doc = builder.parse(in);
628f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            NodeList entries = doc.getElementsByTagName("entry");
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (entries == null) {
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int entriesListLength = entries.getLength();
633f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (int i = 0; i < entriesListLength; i++) {
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                Element entry = (Element) entries.item(i);
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String key = entry.getAttribute("key");
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // BEGIN android-removed
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // String value = entry.getTextContent();
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // END android-removed
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // BEGIN android-added
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                String value = getTextContent(entry);
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // END android-added
643f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                /*
645f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                 * key != null & value != null but key or(and) value can be
646f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                 * empty String
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                 */
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                put(key, value);
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IOException e) {
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw e;
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (SAXException e) {
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new InvalidPropertiesFormatException(e);
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Writes all properties stored in this instance into the {@code
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * OutputStream} in XML representation. The DOCTYPE is
660f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <pre>
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * &lt;!DOCTYPE properties SYSTEM &quot;http://java.sun.com/dtd/properties.dtd">;
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </pre>
664f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * If the comment is null, no comment is added to the output. UTF-8 is used
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * as the encoding. The {@code OutputStream} is not closed at the end. A
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * call to this method is the same as a call to {@code storeToXML(os,
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * comment, "UTF-8")}.
669f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param os the {@code OutputStream} to write to.
671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param comment the comment to add. If null, no comment is added.
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException if an error occurs during writing to the output.
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
674f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    public void storeToXML(OutputStream os, String comment) throws IOException {
675f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        storeToXML(os, comment, "UTF-8"); //$NON-NLS-1$
676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Writes all properties stored in this instance into the {@code
680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * OutputStream} in XML representation. The DOCTYPE is
681f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <pre>
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * &lt;!DOCTYPE properties SYSTEM &quot;http://java.sun.com/dtd/properties.dtd">;
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * </pre>
685f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * If the comment is null, no comment is added to the output. The parameter
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code encoding} defines which encoding should be used. The {@code
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * OutputStream} is not closed at the end.
689f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param os the {@code OutputStream} to write to.
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param comment the comment to add. If null, no comment is added.
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param encoding the code identifying the encoding that should be used to
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            write into the {@code OutputStream}.
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException if an error occurs during writing to the output.
695adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized void storeToXML(OutputStream os, String comment,
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String encoding) throws IOException {
698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (os == null || encoding == null) {
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
702f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * We can write to XML file using encoding parameter but note that some
705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * aliases for encodings are not supported by the XML parser. Thus we
706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * have to know canonical name for encoding used to store data in XML
707adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * since the XML parser must recognize encoding name used to store data.
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
709f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String encodingCanonicalName;
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            encodingCanonicalName = Charset.forName(encoding).name();
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IllegalCharsetNameException e) {
714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            System.out.println("Warning: encoding name " + encoding
715adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    + " is illegal, using UTF-8 as default encoding");
716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            encodingCanonicalName = "UTF-8";
717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (UnsupportedCharsetException e) {
718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            System.out.println("Warning: encoding " + encoding
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    + " is not supported, using UTF-8 as default encoding");
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            encodingCanonicalName = "UTF-8";
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
723f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        PrintStream printStream = new PrintStream(os, false,
724f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                encodingCanonicalName);
725f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        printStream.print("<?xml version=\"1.0\" encoding=\"");
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        printStream.print(encodingCanonicalName);
728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        printStream.println("\"?>");
729f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
730adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        printStream.print("<!DOCTYPE properties SYSTEM \"");
731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        printStream.print(PROP_DTD_NAME);
732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        printStream.println("\">");
733f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        printStream.println("<properties>");
735f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (comment != null) {
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            printStream.print("<comment>");
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            printStream.print(substitutePredefinedEntries(comment));
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            printStream.println("</comment>");
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (Map.Entry<Object, Object> entry : entrySet()) {
743adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String keyValue = (String) entry.getKey();
744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String entryValue = (String) entry.getValue();
745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            printStream.print("<entry key=\"");
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            printStream.print(substitutePredefinedEntries(keyValue));
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            printStream.print("\">");
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            printStream.print(substitutePredefinedEntries(entryValue));
749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            printStream.println("</entry>");
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        printStream.println("</properties>");
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        printStream.flush();
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
754f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private String substitutePredefinedEntries(String s) {
756f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /*
758f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson         * substitution for predefined character entities to use them safely in
759f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson         * XML
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
761f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        return s.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(
762f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                ">", "&gt;").replaceAll("\u0027", "&apos;").replaceAll("\"",
763f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                "&quot;");
764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
766adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // BEGIN android-added
767adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private String getTextContent(Node node) {
768adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String result = (node instanceof Text ? ((Text) node).getData() : "");
769adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
770adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Node child = node.getFirstChild();
771adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (child != null) {
772adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            result = result + getTextContent(child);
773adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            child = child.getNextSibling();
774adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
775adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
777adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
778adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // END android-added
779adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
781