mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			802 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			802 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Java
		
	
	
	
/* 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 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 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
 | 
						|
{
 | 
						|
  // 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 an input 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 inStream the input stream
 | 
						|
   * @throws IOException if an error occurred when reading the input
 | 
						|
   * @throws NullPointerException if in is null
 | 
						|
   */
 | 
						|
  public void load(InputStream inStream) throws IOException
 | 
						|
  {
 | 
						|
    // The spec says that the file must be encoded using ISO-8859-1.
 | 
						|
    BufferedReader reader =
 | 
						|
      new BufferedReader(new InputStreamReader(inStream, "ISO-8859-1"));
 | 
						|
    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;
 | 
						|
        StringBuilder key = needsEscape ? new StringBuilder() : 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());
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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
 | 
						|
   */
 | 
						|
  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 ();
 | 
						|
    StringBuilder s = new StringBuilder (); // 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, StringBuilder 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;
 | 
						|
        StringBuffer 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 StringBuffer();
 | 
						|
                  }
 | 
						|
                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
 |