summaryrefslogtreecommitdiff
path: root/libjava/classpath/java/util/Properties.java
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/java/util/Properties.java
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libjava/classpath/java/util/Properties.java')
-rw-r--r--libjava/classpath/java/util/Properties.java822
1 files changed, 822 insertions, 0 deletions
diff --git a/libjava/classpath/java/util/Properties.java b/libjava/classpath/java/util/Properties.java
new file mode 100644
index 000000000..b0f436f42
--- /dev/null
+++ b/libjava/classpath/java/util/Properties.java
@@ -0,0 +1,822 @@
+/* Properties.java -- a set of persistent properties
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.util;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Element;
+import org.w3c.dom.bootstrap.DOMImplementationRegistry;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSOutput;
+import org.w3c.dom.ls.LSSerializer;
+
+/**
+ * A set of persistent properties, which can be saved or loaded from a stream.
+ * A property list may also contain defaults, searched if the main list
+ * does not contain a property for a given key.
+ *
+ * An example of a properties file for the german language is given
+ * here. This extends the example given in ListResourceBundle.
+ * Create a file MyResource_de.properties with the following contents
+ * and put it in the CLASSPATH. (The character
+ * <code>\</code><code>u00e4</code> is the german umlaut)
+ *
+ *
+<pre>s1=3
+s2=MeineDisk
+s3=3. M\<code></code>u00e4rz 96
+s4=Die Diskette ''{1}'' enth\<code></code>u00e4lt {0} in {2}.
+s5=0
+s6=keine Dateien
+s7=1
+s8=eine Datei
+s9=2
+s10={0,number} Dateien
+s11=Das Formatieren schlug fehl mit folgender Exception: {0}
+s12=FEHLER
+s13=Ergebnis
+s14=Dialog
+s15=Auswahlkriterium
+s16=1,3</pre>
+ *
+ * <p>Although this is a sub class of a hash table, you should never
+ * insert anything other than strings to this property, or several
+ * methods, that need string keys and values, will fail. To ensure
+ * this, you should use the <code>get/setProperty</code> method instead
+ * of <code>get/put</code>.
+ *
+ * Properties are saved in ISO 8859-1 encoding, using Unicode escapes with
+ * a single <code>u</code> for any character which cannot be represented.
+ *
+ * @author Jochen Hoenicke
+ * @author Eric Blake (ebb9@email.byu.edu)
+ * @see PropertyResourceBundle
+ * @status updated to 1.4
+ */
+public class Properties extends Hashtable<Object, Object>
+{
+ // WARNING: Properties is a CORE class in the bootstrap cycle. See the
+ // comments in vm/reference/java/lang/Runtime for implications of this fact.
+
+ /**
+ * The property list that contains default values for any keys not
+ * in this property list.
+ *
+ * @serial the default properties
+ */
+ protected Properties defaults;
+
+ /**
+ * Compatible with JDK 1.0+.
+ */
+ private static final long serialVersionUID = 4112578634029874840L;
+
+ /**
+ * Creates a new empty property list with no default values.
+ */
+ public Properties()
+ {
+ }
+
+ /**
+ * Create a new empty property list with the specified default values.
+ *
+ * @param defaults a Properties object containing the default values
+ */
+ public Properties(Properties defaults)
+ {
+ this.defaults = defaults;
+ }
+
+ /**
+ * Adds the given key/value pair to this properties. This calls
+ * the hashtable method put.
+ *
+ * @param key the key for this property
+ * @param value the value for this property
+ * @return The old value for the given key
+ * @see #getProperty(String)
+ * @since 1.2
+ */
+ public Object setProperty(String key, String value)
+ {
+ return put(key, value);
+ }
+
+ /**
+ * Reads a property list from a character stream. The stream should
+ * have the following format: <br>
+ *
+ * An empty line or a line starting with <code>#</code> or
+ * <code>!</code> is ignored. An backslash (<code>\</code>) at the
+ * end of the line makes the line continueing on the next line
+ * (but make sure there is no whitespace after the backslash).
+ * Otherwise, each line describes a key/value pair. <br>
+ *
+ * The chars up to the first whitespace, = or : are the key. You
+ * can include this caracters in the key, if you precede them with
+ * a backslash (<code>\</code>). The key is followed by optional
+ * whitespaces, optionally one <code>=</code> or <code>:</code>,
+ * and optionally some more whitespaces. The rest of the line is
+ * the resource belonging to the key. <br>
+ *
+ * Escape sequences <code>\t, \n, \r, \\, \", \', \!, \#, \ </code>(a
+ * space), and unicode characters with the
+ * <code>\\u</code><em>xxxx</em> notation are detected, and
+ * converted to the corresponding single character. <br>
+ *
+ *
+<pre># This is a comment
+key = value
+k\:5 \ a string starting with space and ending with newline\n
+# This is a multiline specification; note that the value contains
+# no white space.
+weekdays: Sunday,Monday,Tuesday,Wednesday,\\
+ Thursday,Friday,Saturday
+# The safest way to include a space at the end of a value:
+label = Name:\\u0020</pre>
+ *
+ * @param inReader the input {@link java.io.Reader}.
+ * @throws IOException if an error occurred when reading the input
+ * @throws NullPointerException if in is null
+ * @since 1.6
+ */
+ public void load(Reader inReader) throws IOException
+ {
+ BufferedReader reader = new BufferedReader(inReader);
+ String line;
+
+ while ((line = reader.readLine()) != null)
+ {
+ char c = 0;
+ int pos = 0;
+ // Leading whitespaces must be deleted first.
+ while (pos < line.length()
+ && Character.isWhitespace(c = line.charAt(pos)))
+ pos++;
+
+ // If empty line or begins with a comment character, skip this line.
+ if ((line.length() - pos) == 0
+ || line.charAt(pos) == '#' || line.charAt(pos) == '!')
+ continue;
+
+ // The characters up to the next Whitespace, ':', or '='
+ // describe the key. But look for escape sequences.
+ // Try to short-circuit when there is no escape char.
+ int start = pos;
+ boolean needsEscape = line.indexOf('\\', pos) != -1;
+ CPStringBuilder key = needsEscape ? new CPStringBuilder() : null;
+ while (pos < line.length()
+ && ! Character.isWhitespace(c = line.charAt(pos++))
+ && c != '=' && c != ':')
+ {
+ if (needsEscape && c == '\\')
+ {
+ if (pos == line.length())
+ {
+ // The line continues on the next line. If there
+ // is no next line, just treat it as a key with an
+ // empty value.
+ line = reader.readLine();
+ if (line == null)
+ line = "";
+ pos = 0;
+ while (pos < line.length()
+ && Character.isWhitespace(c = line.charAt(pos)))
+ pos++;
+ }
+ else
+ {
+ c = line.charAt(pos++);
+ switch (c)
+ {
+ case 'n':
+ key.append('\n');
+ break;
+ case 't':
+ key.append('\t');
+ break;
+ case 'r':
+ key.append('\r');
+ break;
+ case 'u':
+ if (pos + 4 <= line.length())
+ {
+ char uni = (char) Integer.parseInt
+ (line.substring(pos, pos + 4), 16);
+ key.append(uni);
+ pos += 4;
+ } // else throw exception?
+ break;
+ default:
+ key.append(c);
+ break;
+ }
+ }
+ }
+ else if (needsEscape)
+ key.append(c);
+ }
+
+ boolean isDelim = (c == ':' || c == '=');
+
+ String keyString;
+ if (needsEscape)
+ keyString = key.toString();
+ else if (isDelim || Character.isWhitespace(c))
+ keyString = line.substring(start, pos - 1);
+ else
+ keyString = line.substring(start, pos);
+
+ while (pos < line.length()
+ && Character.isWhitespace(c = line.charAt(pos)))
+ pos++;
+
+ if (! isDelim && (c == ':' || c == '='))
+ {
+ pos++;
+ while (pos < line.length()
+ && Character.isWhitespace(c = line.charAt(pos)))
+ pos++;
+ }
+
+ // Short-circuit if no escape chars found.
+ if (!needsEscape)
+ {
+ put(keyString, line.substring(pos));
+ continue;
+ }
+
+ // Escape char found so iterate through the rest of the line.
+ StringBuilder element = new StringBuilder(line.length() - pos);
+ while (pos < line.length())
+ {
+ c = line.charAt(pos++);
+ if (c == '\\')
+ {
+ if (pos == line.length())
+ {
+ // The line continues on the next line.
+ line = reader.readLine();
+
+ // We might have seen a backslash at the end of
+ // the file. The JDK ignores the backslash in
+ // this case, so we follow for compatibility.
+ if (line == null)
+ break;
+
+ pos = 0;
+ while (pos < line.length()
+ && Character.isWhitespace(c = line.charAt(pos)))
+ pos++;
+ element.ensureCapacity(line.length() - pos +
+ element.length());
+ }
+ else
+ {
+ c = line.charAt(pos++);
+ switch (c)
+ {
+ case 'n':
+ element.append('\n');
+ break;
+ case 't':
+ element.append('\t');
+ break;
+ case 'r':
+ element.append('\r');
+ break;
+ case 'u':
+ if (pos + 4 <= line.length())
+ {
+ char uni = (char) Integer.parseInt
+ (line.substring(pos, pos + 4), 16);
+ element.append(uni);
+ pos += 4;
+ } // else throw exception?
+ break;
+ default:
+ element.append(c);
+ break;
+ }
+ }
+ }
+ else
+ element.append(c);
+ }
+ put(keyString, element.toString());
+ }
+ }
+
+ /**
+ * Reads a property list from the supplied input stream.
+ * This method has the same functionality as {@link #load(Reader)}
+ * but the character encoding is assumed to be ISO-8859-1.
+ * Unicode characters not within the Latin1 set supplied by
+ * ISO-8859-1 should be escaped using '\\uXXXX' where XXXX
+ * is the UTF-16 code unit in hexadecimal.
+ *
+ * @param inStream the byte stream to read the property list from.
+ * @throws IOException if an I/O error occurs.
+ * @see #load(Reader)
+ * @since 1.2
+ */
+ public void load(InputStream inStream) throws IOException
+ {
+ load(new InputStreamReader(inStream, "ISO-8859-1"));
+ }
+
+ /**
+ * Calls <code>store(OutputStream out, String header)</code> and
+ * ignores the IOException that may be thrown.
+ *
+ * @param out the stream to write to
+ * @param header a description of the property list
+ * @throws ClassCastException if this property contains any key or
+ * value that are not strings
+ * @deprecated use {@link #store(OutputStream, String)} instead
+ */
+ @Deprecated
+ public void save(OutputStream out, String header)
+ {
+ try
+ {
+ store(out, header);
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+
+ /**
+ * Writes the key/value pairs to the given output stream, in a format
+ * suitable for <code>load</code>.<br>
+ *
+ * If header is not null, this method writes a comment containing
+ * the header as first line to the stream. The next line (or first
+ * line if header is null) contains a comment with the current date.
+ * Afterwards the key/value pairs are written to the stream in the
+ * following format.<br>
+ *
+ * Each line has the form <code>key = value</code>. Newlines,
+ * Returns and tabs are written as <code>\n,\t,\r</code> resp.
+ * The characters <code>\, !, #, =</code> and <code>:</code> are
+ * preceeded by a backslash. Spaces are preceded with a backslash,
+ * if and only if they are at the beginning of the key. Characters
+ * that are not in the ascii range 33 to 127 are written in the
+ * <code>\</code><code>u</code>xxxx Form.<br>
+ *
+ * Following the listing, the output stream is flushed but left open.
+ *
+ * @param out the output stream
+ * @param header the header written in the first line, may be null
+ * @throws ClassCastException if this property contains any key or
+ * value that isn't a string
+ * @throws IOException if writing to the stream fails
+ * @throws NullPointerException if out is null
+ * @since 1.2
+ */
+ public void store(OutputStream out, String header) throws IOException
+ {
+ // The spec says that the file must be encoded using ISO-8859-1.
+ PrintWriter writer
+ = new PrintWriter(new OutputStreamWriter(out, "ISO-8859-1"));
+ if (header != null)
+ writer.println("#" + header);
+ writer.println ("#" + Calendar.getInstance ().getTime ());
+
+ Iterator iter = entrySet ().iterator ();
+ int i = size ();
+ CPStringBuilder s = new CPStringBuilder (); // Reuse the same buffer.
+ while (--i >= 0)
+ {
+ Map.Entry entry = (Map.Entry) iter.next ();
+ formatForOutput ((String) entry.getKey (), s, true);
+ s.append ('=');
+ formatForOutput ((String) entry.getValue (), s, false);
+ writer.println (s);
+ }
+
+ writer.flush ();
+ }
+
+ /**
+ * Gets the property with the specified key in this property list.
+ * If the key is not found, the default property list is searched.
+ * If the property is not found in the default, null is returned.
+ *
+ * @param key The key for this property
+ * @return the value for the given key, or null if not found
+ * @throws ClassCastException if this property contains any key or
+ * value that isn't a string
+ * @see #defaults
+ * @see #setProperty(String, String)
+ * @see #getProperty(String, String)
+ */
+ public String getProperty(String key)
+ {
+ Properties prop = this;
+ // Eliminate tail recursion.
+ do
+ {
+ String value = (String) prop.get(key);
+ if (value != null)
+ return value;
+ prop = prop.defaults;
+ }
+ while (prop != null);
+ return null;
+ }
+
+ /**
+ * Gets the property with the specified key in this property list. If
+ * the key is not found, the default property list is searched. If the
+ * property is not found in the default, the specified defaultValue is
+ * returned.
+ *
+ * @param key The key for this property
+ * @param defaultValue A default value
+ * @return The value for the given key
+ * @throws ClassCastException if this property contains any key or
+ * value that isn't a string
+ * @see #defaults
+ * @see #setProperty(String, String)
+ */
+ public String getProperty(String key, String defaultValue)
+ {
+ String prop = getProperty(key);
+ if (prop == null)
+ prop = defaultValue;
+ return prop;
+ }
+
+ /**
+ * Returns an enumeration of all keys in this property list, including
+ * the keys in the default property list.
+ *
+ * @return an Enumeration of all defined keys
+ */
+ public Enumeration<?> propertyNames()
+ {
+ // We make a new Set that holds all the keys, then return an enumeration
+ // for that. This prevents modifications from ruining the enumeration,
+ // as well as ignoring duplicates.
+ Properties prop = this;
+ Set s = new HashSet();
+ // Eliminate tail recursion.
+ do
+ {
+ s.addAll(prop.keySet());
+ prop = prop.defaults;
+ }
+ while (prop != null);
+ return Collections.enumeration(s);
+ }
+
+ /**
+ * Prints the key/value pairs to the given print stream. This is
+ * mainly useful for debugging purposes.
+ *
+ * @param out the print stream, where the key/value pairs are written to
+ * @throws ClassCastException if this property contains a key or a
+ * value that isn't a string
+ * @see #list(PrintWriter)
+ */
+ public void list(PrintStream out)
+ {
+ PrintWriter writer = new PrintWriter (out);
+ list (writer);
+ }
+
+ /**
+ * Prints the key/value pairs to the given print writer. This is
+ * mainly useful for debugging purposes.
+ *
+ * @param out the print writer where the key/value pairs are written to
+ * @throws ClassCastException if this property contains a key or a
+ * value that isn't a string
+ * @see #list(PrintStream)
+ * @since 1.1
+ */
+ public void list(PrintWriter out)
+ {
+ out.println ("-- listing properties --");
+
+ Iterator iter = entrySet ().iterator ();
+ int i = size ();
+ while (--i >= 0)
+ {
+ Map.Entry entry = (Map.Entry) iter.next ();
+ out.print ((String) entry.getKey () + "=");
+
+ // JDK 1.3/1.4 restrict the printed value, but not the key,
+ // to 40 characters, including the truncating ellipsis.
+ String s = (String ) entry.getValue ();
+ if (s != null && s.length () > 40)
+ out.println (s.substring (0, 37) + "...");
+ else
+ out.println (s);
+ }
+ out.flush ();
+ }
+
+ /**
+ * Formats a key or value for output in a properties file.
+ * See store for a description of the format.
+ *
+ * @param str the string to format
+ * @param buffer the buffer to add it to
+ * @param key true if all ' ' must be escaped for the key, false if only
+ * leading spaces must be escaped for the value
+ * @see #store(OutputStream, String)
+ */
+ private void formatForOutput(String str, CPStringBuilder buffer, boolean key)
+ {
+ if (key)
+ {
+ buffer.setLength(0);
+ buffer.ensureCapacity(str.length());
+ }
+ else
+ buffer.ensureCapacity(buffer.length() + str.length());
+ boolean head = true;
+ int size = str.length();
+ for (int i = 0; i < size; i++)
+ {
+ char c = str.charAt(i);
+ switch (c)
+ {
+ case '\n':
+ buffer.append("\\n");
+ break;
+ case '\r':
+ buffer.append("\\r");
+ break;
+ case '\t':
+ buffer.append("\\t");
+ break;
+ case ' ':
+ buffer.append(head ? "\\ " : " ");
+ break;
+ case '\\':
+ case '!':
+ case '#':
+ case '=':
+ case ':':
+ buffer.append('\\').append(c);
+ break;
+ default:
+ if (c < ' ' || c > '~')
+ {
+ String hex = Integer.toHexString(c);
+ buffer.append("\\u0000".substring(0, 6 - hex.length()));
+ buffer.append(hex);
+ }
+ else
+ buffer.append(c);
+ }
+ if (c != ' ')
+ head = key;
+ }
+ }
+
+ /**
+ * <p>
+ * Encodes the properties as an XML file using the UTF-8 encoding.
+ * The format of the XML file matches the DTD
+ * <a href="http://java.sun.com/dtd/properties.dtd">
+ * http://java.sun.com/dtd/properties.dtd</a>.
+ * </p>
+ * <p>
+ * Invoking this method provides the same behaviour as invoking
+ * <code>storeToXML(os, comment, "UTF-8")</code>.
+ * </p>
+ *
+ * @param os the stream to output to.
+ * @param comment a comment to include at the top of the XML file, or
+ * <code>null</code> if one is not required.
+ * @throws IOException if the serialization fails.
+ * @throws NullPointerException if <code>os</code> is null.
+ * @since 1.5
+ */
+ public void storeToXML(OutputStream os, String comment)
+ throws IOException
+ {
+ storeToXML(os, comment, "UTF-8");
+ }
+
+ /**
+ * <p>
+ * Encodes the properties as an XML file using the supplied encoding.
+ * The format of the XML file matches the DTD
+ * <a href="http://java.sun.com/dtd/properties.dtd">
+ * http://java.sun.com/dtd/properties.dtd</a>.
+ * </p>
+ *
+ * @param os the stream to output to.
+ * @param comment a comment to include at the top of the XML file, or
+ * <code>null</code> if one is not required.
+ * @param encoding the encoding to use for the XML output.
+ * @throws IOException if the serialization fails.
+ * @throws NullPointerException if <code>os</code> or <code>encoding</code>
+ * is null.
+ * @since 1.5
+ */
+ public void storeToXML(OutputStream os, String comment, String encoding)
+ throws IOException
+ {
+ if (os == null)
+ throw new NullPointerException("Null output stream supplied.");
+ if (encoding == null)
+ throw new NullPointerException("Null encoding supplied.");
+ try
+ {
+ DOMImplementationRegistry registry =
+ DOMImplementationRegistry.newInstance();
+ DOMImplementation domImpl = registry.getDOMImplementation("LS 3.0");
+ DocumentType doctype =
+ domImpl.createDocumentType("properties", null,
+ "http://java.sun.com/dtd/properties.dtd");
+ Document doc = domImpl.createDocument(null, "properties", doctype);
+ Element root = doc.getDocumentElement();
+ if (comment != null)
+ {
+ Element commentElement = doc.createElement("comment");
+ commentElement.appendChild(doc.createTextNode(comment));
+ root.appendChild(commentElement);
+ }
+ Iterator iterator = entrySet().iterator();
+ while (iterator.hasNext())
+ {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ Element entryElement = doc.createElement("entry");
+ entryElement.setAttribute("key", (String) entry.getKey());
+ entryElement.appendChild(doc.createTextNode((String)
+ entry.getValue()));
+ root.appendChild(entryElement);
+ }
+ DOMImplementationLS loadAndSave = (DOMImplementationLS) domImpl;
+ LSSerializer serializer = loadAndSave.createLSSerializer();
+ LSOutput output = loadAndSave.createLSOutput();
+ output.setByteStream(os);
+ output.setEncoding(encoding);
+ serializer.write(doc, output);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw (IOException)
+ new IOException("The XML classes could not be found.").initCause(e);
+ }
+ catch (InstantiationException e)
+ {
+ throw (IOException)
+ new IOException("The XML classes could not be instantiated.")
+ .initCause(e);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw (IOException)
+ new IOException("The XML classes could not be accessed.")
+ .initCause(e);
+ }
+ }
+
+ /**
+ * <p>
+ * Decodes the contents of the supplied <code>InputStream</code> as
+ * an XML file, which represents a set of properties. The format of
+ * the XML file must match the DTD
+ * <a href="http://java.sun.com/dtd/properties.dtd">
+ * http://java.sun.com/dtd/properties.dtd</a>.
+ * </p>
+ *
+ * @param in the input stream from which to receive the XML data.
+ * @throws IOException if an I/O error occurs in reading the input data.
+ * @throws InvalidPropertiesFormatException if the input data does not
+ * constitute an XML properties
+ * file.
+ * @throws NullPointerException if <code>in</code> is null.
+ * @since 1.5
+ */
+ public void loadFromXML(InputStream in)
+ throws IOException, InvalidPropertiesFormatException
+ {
+ if (in == null)
+ throw new NullPointerException("Null input stream supplied.");
+ try
+ {
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ // Don't resolve external entity references
+ factory.setProperty("javax.xml.stream.isSupportingExternalEntities",
+ Boolean.FALSE);
+ XMLStreamReader reader = factory.createXMLStreamReader(in);
+ String name, key = null;
+ CPStringBuilder buf = null;
+ while (reader.hasNext())
+ {
+ switch (reader.next())
+ {
+ case XMLStreamConstants.START_ELEMENT:
+ name = reader.getLocalName();
+ if (buf == null && "entry".equals(name))
+ {
+ key = reader.getAttributeValue(null, "key");
+ if (key == null)
+ {
+ String msg = "missing 'key' attribute";
+ throw new InvalidPropertiesFormatException(msg);
+ }
+ buf = new CPStringBuilder();
+ }
+ else if (!"properties".equals(name) && !"comment".equals(name))
+ {
+ String msg = "unexpected element name '" + name + "'";
+ throw new InvalidPropertiesFormatException(msg);
+ }
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ name = reader.getLocalName();
+ if (buf != null && "entry".equals(name))
+ {
+ put(key, buf.toString());
+ buf = null;
+ }
+ else if (!"properties".equals(name) && !"comment".equals(name))
+ {
+ String msg = "unexpected element name '" + name + "'";
+ throw new InvalidPropertiesFormatException(msg);
+ }
+ break;
+ case XMLStreamConstants.CHARACTERS:
+ case XMLStreamConstants.SPACE:
+ case XMLStreamConstants.CDATA:
+ if (buf != null)
+ buf.append(reader.getText());
+ break;
+ }
+ }
+ reader.close();
+ }
+ catch (XMLStreamException e)
+ {
+ throw (InvalidPropertiesFormatException)
+ new InvalidPropertiesFormatException("Error in parsing XML.").
+ initCause(e);
+ }
+ }
+
+} // class Properties