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