diff options
Diffstat (limited to 'libjava/classpath/java/util')
16 files changed, 606 insertions, 276 deletions
diff --git a/libjava/classpath/java/util/AbstractCollection.java b/libjava/classpath/java/util/AbstractCollection.java index 00ee23e..3ae98e0 100644 --- a/libjava/classpath/java/util/AbstractCollection.java +++ b/libjava/classpath/java/util/AbstractCollection.java @@ -423,7 +423,9 @@ public abstract class AbstractCollection implements Collection * of the form "[a, b, ...]" where a and b etc are the results of calling * toString on the elements of the collection. This implementation obtains an * Iterator over the Collection and adds each element to a StringBuffer as it - * is returned by the iterator. + * is returned by the iterator. "<this>" is inserted when the collection + * contains itself (only works for direct containment, not for collections + * inside collections). * * @return a String representation of the Collection */ @@ -431,10 +433,16 @@ public abstract class AbstractCollection implements Collection { Iterator itr = iterator(); StringBuffer r = new StringBuffer("["); - for (int pos = size(); pos > 0; pos--) + boolean hasNext = itr.hasNext(); + while (hasNext) { - r.append(itr.next()); - if (pos > 1) + Object o = itr.next(); + if (o == this) + r.append("<this>"); + else + r.append(o); + hasNext = itr.hasNext(); + if (hasNext) r.append(", "); } r.append("]"); diff --git a/libjava/classpath/java/util/ResourceBundle.java b/libjava/classpath/java/util/ResourceBundle.java index 6aea673..4dcb9ad 100644 --- a/libjava/classpath/java/util/ResourceBundle.java +++ b/libjava/classpath/java/util/ResourceBundle.java @@ -1,5 +1,5 @@ /* ResourceBundle -- aids in loading resource bundles - Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2005 + Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -476,9 +476,7 @@ public abstract class ResourceBundle if (ResourceBundle.class.isAssignableFrom(rbClass)) bundle = (ResourceBundle) rbClass.newInstance(); } - catch (IllegalAccessException ex) {} - catch (InstantiationException ex) {} - catch (ClassNotFoundException ex) {} + catch (Exception ex) {} if (bundle == null) { diff --git a/libjava/classpath/java/util/jar/Attributes.java b/libjava/classpath/java/util/jar/Attributes.java index 4db2c72..c8babdd 100644 --- a/libjava/classpath/java/util/jar/Attributes.java +++ b/libjava/classpath/java/util/jar/Attributes.java @@ -427,16 +427,13 @@ public class Attributes implements Cloneable, Map * Attributes map. * When the name already exists the value is replaced and the old value * is returned. - * <p> - * I don't know why there is no public method with this signature. I think - * there should be one. * * @param name the attribite name to add/replace * @param value the (new) value of the attribute name * @returns the old value of the attribute name or null if it didn't exist * yet */ - String putValue(Name name, String value) + public String putValue(Name name, String value) { return (String) put(name, value); } diff --git a/libjava/classpath/java/util/logging/FileHandler.java b/libjava/classpath/java/util/logging/FileHandler.java index b03df97..cde8619 100644 --- a/libjava/classpath/java/util/logging/FileHandler.java +++ b/libjava/classpath/java/util/logging/FileHandler.java @@ -115,7 +115,7 @@ import java.util.ListIterator; * * <li><code>%h</code> - replaced by the location of the home * directory of the current user. This value is taken from the - * system property <code>file.separator</code>.</li> + * system property <code>user.home</code>.</li> * * <li><code>%g</code> - replaced by a generation number for * distinguisthing the individual items in the rotating set diff --git a/libjava/classpath/java/util/logging/LogManager.java b/libjava/classpath/java/util/logging/LogManager.java index b62292f..73eb9bc 100644 --- a/libjava/classpath/java/util/logging/LogManager.java +++ b/libjava/classpath/java/util/logging/LogManager.java @@ -41,6 +41,7 @@ package java.util.logging; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; @@ -295,6 +296,28 @@ public class LogManager if (parent != logger.getParent()) logger.setParent(parent); + // The level of the newly added logger must be specified. + // The easiest case is if there is a level for exactly this logger + // in the properties. If no such level exists the level needs to be + // searched along the hirachy. So if there is a new logger 'foo.blah.blub' + // and an existing parent logger 'foo' the properties 'foo.blah.blub.level' + // and 'foo.blah.level' need to be checked. If both do not exist in the + // properties the level of the new logger is set to 'null' (i.e. it uses the + // level of its parent 'foo'). + Level logLevel = logger.getLevel(); + String searchName = name; + String parentName = parent != null ? parent.getName() : ""; + while (logLevel == null && ! searchName.equals(parentName)) + { + logLevel = getLevelProperty(searchName + ".level", logLevel); + int index = searchName.lastIndexOf('.'); + if(index > -1) + searchName = searchName.substring(0,index); + else + searchName = ""; + } + logger.setLevel(logLevel); + /* It can happen that existing loggers should be children of * the newly added logger. For example, assume that there * already exist loggers under the names "", "foo", and "foo.bar.baz". @@ -488,23 +511,37 @@ public class LogManager path = System.getProperty("java.util.logging.config.file"); if ((path == null) || (path.length() == 0)) { - String url = (System.getProperty("gnu.classpath.home.url") - + "/logging.properties"); - inputStream = new URL(url).openStream(); + String url = (System.getProperty("gnu.classpath.home.url") + + "/logging.properties"); + try + { + inputStream = new URL(url).openStream(); + } + catch (Exception e) + { + inputStream=null; + } + + // If no config file could be found use a default configuration. + if(inputStream == null) + { + String defaultConfig = "handlers = java.util.logging.ConsoleHandler \n" + + ".level=INFO \n"; + inputStream = new ByteArrayInputStream(defaultConfig.getBytes()); + } } else inputStream = new java.io.FileInputStream(path); try { - readConfiguration(inputStream); + readConfiguration(inputStream); } finally { - /* Close the stream in order to save - * resources such as file descriptors. - */ - inputStream.close(); + // Close the stream in order to save + // resources such as file descriptors. + inputStream.close(); } } diff --git a/libjava/classpath/java/util/logging/SimpleFormatter.java b/libjava/classpath/java/util/logging/SimpleFormatter.java index ff53db8..2ebb1a1 100644 --- a/libjava/classpath/java/util/logging/SimpleFormatter.java +++ b/libjava/classpath/java/util/logging/SimpleFormatter.java @@ -39,6 +39,8 @@ exception statement from your version. */ package java.util.logging; +import java.io.PrintWriter; +import java.io.StringWriter; import java.text.DateFormat; import java.util.Date; @@ -114,6 +116,14 @@ public class SimpleFormatter buf.append(lineSep); + Throwable throwable = record.getThrown(); + if (throwable != null) + { + StringWriter sink = new StringWriter(); + throwable.printStackTrace(new PrintWriter(sink, true)); + buf.append(sink.toString()); + } + return buf.toString(); } } diff --git a/libjava/classpath/java/util/prefs/AbstractPreferences.java b/libjava/classpath/java/util/prefs/AbstractPreferences.java index 3f70400..e676dc3 100644 --- a/libjava/classpath/java/util/prefs/AbstractPreferences.java +++ b/libjava/classpath/java/util/prefs/AbstractPreferences.java @@ -1,5 +1,5 @@ /* AbstractPreferences -- Partial implementation of a Preference node - Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2001, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,11 +38,13 @@ exception statement from your version. */ package java.util.prefs; +import gnu.java.util.prefs.EventDispatcher; import gnu.java.util.prefs.NodeWriter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.TreeSet; @@ -68,7 +70,7 @@ public abstract class AbstractPreferences extends Preferences { /** * Set to true in the contructor if the node did not exist in the backing * store when this preference node object was created. Should be set in - * the contructor of a subclass. Defaults to false. Used to fire node + * the constructor of a subclass. Defaults to false. Used to fire node * changed events. */ protected boolean newNode = false; @@ -97,6 +99,16 @@ public abstract class AbstractPreferences extends Preferences { */ private HashMap childCache = new HashMap(); + /** + * A list of all the registered NodeChangeListener objects. + */ + private ArrayList nodeListeners; + + /** + * A list of all the registered PreferenceChangeListener objects. + */ + private ArrayList preferenceListeners; + // constructor /** @@ -256,7 +268,7 @@ public abstract class AbstractPreferences extends Preferences { * @exception IllegalArgumentException if the path contains two or more * consecutive '/' characters, ends with a '/' charactor and is not the * string "/" (indicating the root node) or any name on the path is more - * then 80 characters long + * than 80 characters long */ public Preferences node(String path) { synchronized(lock) { @@ -325,8 +337,9 @@ public abstract class AbstractPreferences extends Preferences { // Not in childCache yet so create a new sub node child = childSpi(childName); - // XXX - check if node is new childCache.put(childName, child); + if (child.newNode && nodeListeners != null) + fire(new NodeChangeEvent(this, child), true); } // Lock the child and go down @@ -477,9 +490,7 @@ public abstract class AbstractPreferences extends Preferences { // export methods - /** - * XXX - */ + // Inherit javadoc. public void exportNode(OutputStream os) throws BackingStoreException, IOException @@ -488,9 +499,7 @@ public abstract class AbstractPreferences extends Preferences { nodeWriter.writePrefs(); } - /** - * XXX - */ + // Inherit javadoc. public void exportSubtree(OutputStream os) throws BackingStoreException, IOException @@ -765,8 +774,8 @@ public abstract class AbstractPreferences extends Preferences { * Key and value cannot be null, the key cannot exceed 80 characters * and the value cannot exceed 8192 characters. * <p> - * The result will be immediatly visible in this VM, but may not be - * immediatly written to the backing store. + * The result will be immediately visible in this VM, but may not be + * immediately written to the backing store. * <p> * Checks that key and value are valid, locks this node, and checks that * the node has not been removed. Then it calls <code>putSpi()</code>. @@ -789,7 +798,8 @@ public abstract class AbstractPreferences extends Preferences { putSpi(key, value); - // XXX - fire events + if (preferenceListeners != null) + fire(new PreferenceChangeEvent(this, key, value)); } } @@ -804,9 +814,7 @@ public abstract class AbstractPreferences extends Preferences { * @exception IllegalStateException when this node has been removed */ public void putBoolean(String key, boolean value) { - put(key, String.valueOf(value)); - // XXX - Use when using 1.4 compatible Boolean - // put(key, Boolean.toString(value)); + put(key, Boolean.toString(value)); } /** @@ -935,8 +943,8 @@ public abstract class AbstractPreferences extends Preferences { /** * Removes the preferences entry from this preferences node. * <p> - * The result will be immediatly visible in this VM, but may not be - * immediatly written to the backing store. + * The result will be immediately visible in this VM, but may not be + * immediately written to the backing store. * <p> * This implementation checks that the key is not larger then 80 * characters, gets the lock of this node, checks that the node has @@ -955,6 +963,9 @@ public abstract class AbstractPreferences extends Preferences { throw new IllegalStateException("Node removed"); removeSpi(key); + + if (preferenceListeners != null) + fire(new PreferenceChangeEvent(this, key, null)); } } @@ -962,7 +973,7 @@ public abstract class AbstractPreferences extends Preferences { * Removes all entries from this preferences node. May need access to the * backing store to get and clear all entries. * <p> - * The result will be immediatly visible in this VM, but may not be + * The result will be immediately visible in this VM, but may not be * immediatly written to the backing store. * <p> * This implementation locks this node, checks that the node has not been @@ -1049,7 +1060,7 @@ public abstract class AbstractPreferences extends Preferences { for (int i = 0; i < keys.length; i++) { // Have to lock this node again to access the childCache AbstractPreferences subNode; - synchronized(this) { + synchronized(lock) { subNode = (AbstractPreferences) childCache.get(keys[i]); } @@ -1087,8 +1098,8 @@ public abstract class AbstractPreferences extends Preferences { if (parent == null) throw new UnsupportedOperationException("Cannot remove root node"); - synchronized(parent) { - synchronized(this) { + synchronized (parent.lock) { + synchronized(this.lock) { if (isRemoved()) throw new IllegalStateException("Node Removed"); @@ -1122,7 +1133,7 @@ public abstract class AbstractPreferences extends Preferences { Iterator i = childCache.values().iterator(); while (i.hasNext()) { AbstractPreferences node = (AbstractPreferences) i.next(); - synchronized(node) { + synchronized(node.lock) { node.purge(); } } @@ -1134,30 +1145,131 @@ public abstract class AbstractPreferences extends Preferences { removeNodeSpi(); removed = true; - // XXX - check for listeners + if (nodeListeners != null) + fire(new NodeChangeEvent(parent, this), false); } // listener methods /** - * XXX + * Add a listener which is notified when a sub-node of this node + * is added or removed. + * @param listener the listener to add */ - public void addNodeChangeListener(NodeChangeListener listener) { - // XXX + public void addNodeChangeListener(NodeChangeListener listener) + { + synchronized (lock) + { + if (isRemoved()) + throw new IllegalStateException("node has been removed"); + if (listener == null) + throw new NullPointerException("listener is null"); + if (nodeListeners == null) + nodeListeners = new ArrayList(); + nodeListeners.add(listener); + } } - public void addPreferenceChangeListener(PreferenceChangeListener listener) { - // XXX + /** + * Add a listener which is notified when a value in this node + * is added, changed, or removed. + * @param listener the listener to add + */ + public void addPreferenceChangeListener(PreferenceChangeListener listener) + { + synchronized (lock) + { + if (isRemoved()) + throw new IllegalStateException("node has been removed"); + if (listener == null) + throw new NullPointerException("listener is null"); + if (preferenceListeners == null) + preferenceListeners = new ArrayList(); + preferenceListeners.add(listener); + } } - public void removeNodeChangeListener(NodeChangeListener listener) { - // XXX + /** + * Remove the indicated node change listener from the list of + * listeners to notify. + * @param listener the listener to remove + */ + public void removeNodeChangeListener(NodeChangeListener listener) + { + synchronized (lock) + { + if (isRemoved()) + throw new IllegalStateException("node has been removed"); + if (listener == null) + throw new NullPointerException("listener is null"); + if (nodeListeners != null) + nodeListeners.remove(listener); + } } - public void removePreferenceChangeListener - (PreferenceChangeListener listener) + /** + * Remove the indicated preference change listener from the list of + * listeners to notify. + * @param listener the listener to remove + */ + public void removePreferenceChangeListener (PreferenceChangeListener listener) { - // XXX + synchronized (lock) + { + if (isRemoved()) + throw new IllegalStateException("node has been removed"); + if (listener == null) + throw new NullPointerException("listener is null"); + if (preferenceListeners != null) + preferenceListeners.remove(listener); + } + } + + /** + * Send a preference change event to all listeners. Note that + * the caller is responsible for holding the node's lock, and + * for checking that the list of listeners is not null. + * @param event the event to send + */ + private void fire(final PreferenceChangeEvent event) + { + Iterator it = preferenceListeners.iterator(); + while (it.hasNext()) + { + final PreferenceChangeListener l = (PreferenceChangeListener) it.next(); + EventDispatcher.dispatch(new Runnable() + { + public void run() + { + l.preferenceChange(event); + } + }); + } + } + + /** + * Send a node change event to all listeners. Note that + * the caller is responsible for holding the node's lock, and + * for checking that the list of listeners is not null. + * @param event the event to send + */ + private void fire(final NodeChangeEvent event, final boolean added) + { + Iterator it = nodeListeners.iterator(); + while (it.hasNext()) + { + final NodeChangeListener l = (NodeChangeListener) it.next(); + EventDispatcher.dispatch(new Runnable() + { + public void run() + { + if (added) + l.childAdded(event); + else + l.childRemoved(event); + } + }); + } } // abstract spi methods @@ -1214,7 +1326,7 @@ public abstract class AbstractPreferences extends Preferences { /** * Sets the value of the given preferences entry for this node. * The implementation is not required to propagate the change to the - * backing store immediatly. It may not throw an exception when it tries + * backing store immediately. It may not throw an exception when it tries * to write to the backing store and that operation fails, the failure * should be registered so a later invocation of <code>flush()</code> * or <code>sync()</code> can signal the failure. @@ -1227,7 +1339,7 @@ public abstract class AbstractPreferences extends Preferences { /** * Removes the given key entry from this preferences node. * The implementation is not required to propagate the change to the - * backing store immediatly. It may not throw an exception when it tries + * backing store immediately. It may not throw an exception when it tries * to write to the backing store and that operation fails, the failure * should be registered so a later invocation of <code>flush()</code> * or <code>sync()</code> can signal the failure. diff --git a/libjava/classpath/java/util/prefs/NodeChangeEvent.java b/libjava/classpath/java/util/prefs/NodeChangeEvent.java index 89986db..8c48fb2 100644 --- a/libjava/classpath/java/util/prefs/NodeChangeEvent.java +++ b/libjava/classpath/java/util/prefs/NodeChangeEvent.java @@ -1,5 +1,5 @@ /* NodeChangeEvent - ObjectEvent fired when a Preference node is added/removed - Copyright (C) 2001 Free Software Foundation, Inc. + Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,6 +37,10 @@ exception statement from your version. */ package java.util.prefs; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.EventObject; /** @@ -44,12 +48,16 @@ import java.util.EventObject; * This event is only generated when a new subnode is added or a subnode is * removed from a preference node. Changes in the entries of a preference node * are indicated with a <code>PreferenceChangeEvent</code>. + * <p> + * Note that although this class is marked as serializable, attempts to + * serialize it will fail with NotSerializableException. * * @since 1.4 * @author Mark Wielaard (mark@klomp.org) */ public class NodeChangeEvent extends EventObject { + // We have this to placate the compiler. private static final long serialVersionUID =8068949086596572957L; /** @@ -88,4 +96,16 @@ public class NodeChangeEvent extends EventObject { public Preferences getChild() { return child; } + + private void readObject(ObjectInputStream ois) + throws IOException + { + throw new NotSerializableException("LineEvent is not serializable"); + } + + private void writeObject(ObjectOutputStream oos) + throws IOException + { + throw new NotSerializableException("LineEvent is not serializable"); + } } diff --git a/libjava/classpath/java/util/prefs/PreferenceChangeEvent.java b/libjava/classpath/java/util/prefs/PreferenceChangeEvent.java index fe371f1..41c3a47 100644 --- a/libjava/classpath/java/util/prefs/PreferenceChangeEvent.java +++ b/libjava/classpath/java/util/prefs/PreferenceChangeEvent.java @@ -1,5 +1,5 @@ /* PreferenceChangeEvent - ObjectEvent fired when a Preferences entry changes - Copyright (C) 2001 Free Software Foundation, Inc. + Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,6 +37,10 @@ exception statement from your version. */ package java.util.prefs; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.EventObject; /** @@ -47,12 +51,16 @@ import java.util.EventObject; * Preference change events are only generated for entries in one particular * preference node. Notification of subnode addition/removal is given by a * <code>NodeChangeEvent</code>. + * <p> + * Note that although this class is marked as serializable, attempts to + * serialize it will fail with NotSerializableException. * * @since 1.4 * @author Mark Wielaard (mark@klomp.org) */ public class PreferenceChangeEvent extends EventObject { + // We have this to placate the compiler. private static final long serialVersionUID = 793724513368024975L; /** @@ -102,4 +110,16 @@ public class PreferenceChangeEvent extends EventObject { public String getNewValue() { return newValue; } + + private void readObject(ObjectInputStream ois) + throws IOException + { + throw new NotSerializableException("LineEvent is not serializable"); + } + + private void writeObject(ObjectOutputStream oos) + throws IOException + { + throw new NotSerializableException("LineEvent is not serializable"); + } } diff --git a/libjava/classpath/java/util/prefs/Preferences.java b/libjava/classpath/java/util/prefs/Preferences.java index 3fee1c5..a78381b 100644 --- a/libjava/classpath/java/util/prefs/Preferences.java +++ b/libjava/classpath/java/util/prefs/Preferences.java @@ -1,5 +1,5 @@ /* Preferences -- Preference node containing key value entries and subnodes - Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -90,12 +90,9 @@ public abstract class Preferences { /** * Default PreferencesFactory class used when the system property * "java.util.prefs.PreferencesFactory" is not set. - * <p> - * XXX - Currently set to MemoryBasedFactory, should be changed - * when FileBasedPreferences backend works. */ private static final String defaultFactoryClass - = "gnu.java.util.prefs.MemoryBasedFactory"; + = "gnu.java.util.prefs.FileBasedFactory"; /** Permission needed to access system or user root. */ private static final Permission prefsPermission @@ -219,8 +216,7 @@ public abstract class Preferences { catch (Exception e) { throw new RuntimeException ("Couldn't load default factory" - + " '"+ defaultFactoryClass +"'"); - // XXX - when using 1.4 compatible throwables add cause + + " '"+ defaultFactoryClass +"'", e); } } @@ -288,7 +284,13 @@ public abstract class Preferences { } /** - * XXX + * Import preferences from the given input stream. This expects + * preferences to be represented in XML as emitted by + * {@link #exportNode(OutputStream)} and + * {@link #exportSubtree(OutputStream)}. + * @throws IOException if there is an error while reading + * @throws InvalidPreferencesFormatException if the XML is not properly + * formatted */ public static void importPreferences(InputStream is) throws InvalidPreferencesFormatException, @@ -385,14 +387,28 @@ public abstract class Preferences { // abstract methods (export) /** - * XXX + * Export this node, but not its descendants, as XML to the + * indicated output stream. The XML will be encoded using UTF-8 + * and will use a specified document type:<br> + * <code><!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"></code><br> + * @param os the output stream to which the XML is sent + * @throws BackingStoreException if preference data cannot be read + * @throws IOException if an error occurs while writing the XML + * @throws IllegalStateException if this node or an ancestor has been removed */ public abstract void exportNode(OutputStream os) throws BackingStoreException, IOException; /** - * XXX + * Export this node and all its descendants as XML to the + * indicated output stream. The XML will be encoded using UTF-8 + * and will use a specified document type:<br> + * <code><!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"></code><br> + * @param os the output stream to which the XML is sent + * @throws BackingStoreException if preference data cannot be read + * @throws IOException if an error occurs while writing the XML + * @throws IllegalStateException if this node or an ancestor has been removed */ public abstract void exportSubtree(OutputStream os) throws BackingStoreException, diff --git a/libjava/classpath/java/util/regex/MatchResult.java b/libjava/classpath/java/util/regex/MatchResult.java new file mode 100644 index 0000000..c82d8cc --- /dev/null +++ b/libjava/classpath/java/util/regex/MatchResult.java @@ -0,0 +1,81 @@ +/* MatchResult.java -- Result of a regular expression match. + Copyright (C) 2006 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.regex; + +/** + * This interface represents the result of a regular expression match. + * It can be used to query the contents of the match, but not to modify + * them. + * @since 1.5 + */ +public interface MatchResult +{ + /** Returns the index just after the last matched character. */ + int end(); + + /** + * Returns the index just after the last matched character of the + * given sub-match group. + * @param group the sub-match group + */ + int end(int group); + + /** Returns the substring of the input which was matched. */ + String group(); + + /** + * Returns the substring of the input which was matched by the + * given sub-match group. + * @param group the sub-match group + */ + String group(int group); + + /** Returns the number of sub-match groups in the matching pattern. */ + int groupCount(); + + /** Returns the index of the first character of the match. */ + int start(); + + /** + * Returns the index of the first character of the given sub-match + * group. + * @param group the sub-match group + */ + int start(int group); +} diff --git a/libjava/classpath/java/util/regex/Matcher.java b/libjava/classpath/java/util/regex/Matcher.java index 5d04bdb..98086bf 100644 --- a/libjava/classpath/java/util/regex/Matcher.java +++ b/libjava/classpath/java/util/regex/Matcher.java @@ -1,5 +1,5 @@ /* Matcher.java -- Instance of a regular expression applied to a char sequence. - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,6 +38,7 @@ exception statement from your version. */ package java.util.regex; +import gnu.regexp.RE; import gnu.regexp.REMatch; /** @@ -45,7 +46,7 @@ import gnu.regexp.REMatch; * * @since 1.4 */ -public final class Matcher +public final class Matcher implements MatchResult { private Pattern pattern; private CharSequence input; @@ -74,7 +75,8 @@ public final class Matcher assertMatchOp(); sb.append(input.subSequence(appendPosition, match.getStartIndex()).toString()); - sb.append(match.substituteInto(replacement)); + sb.append(RE.getReplacement(replacement, match, + RE.REG_REPLACE_USE_BACKSLASHESCAPE)); appendPosition = match.getEndIndex(); return this; } @@ -189,7 +191,8 @@ public final class Matcher { reset(); // Semantics might not quite match - return pattern.getRE().substitute(input, replacement, position); + return pattern.getRE().substitute(input, replacement, position, + RE.REG_REPLACE_USE_BACKSLASHESCAPE); } /** @@ -198,7 +201,8 @@ public final class Matcher public String replaceAll (String replacement) { reset(); - return pattern.getRE().substituteAll(input, replacement, position); + return pattern.getRE().substituteAll(input, replacement, position, + RE.REG_REPLACE_USE_BACKSLASHESCAPE); } public int groupCount () @@ -233,10 +237,15 @@ public final class Matcher */ public boolean matches () { - if (lookingAt()) + match = pattern.getRE().getMatch(input, 0, RE.REG_TRY_ENTIRE_MATCH); + if (match != null) { - if (position == input.length()) - return true; + if (match.getStartIndex() == 0) + { + position = match.getEndIndex(); + if (position == input.length()) + return true; + } match = null; } return false; diff --git a/libjava/classpath/java/util/regex/PatternSyntaxException.java b/libjava/classpath/java/util/regex/PatternSyntaxException.java index 0c80e11..41e650d 100644 --- a/libjava/classpath/java/util/regex/PatternSyntaxException.java +++ b/libjava/classpath/java/util/regex/PatternSyntaxException.java @@ -41,6 +41,7 @@ package java.util.regex; * Indicates illegal pattern for regular expression. * Includes state to inspect the pattern and what and where the expression * was not valid regular expression. + * @since 1.4 */ public class PatternSyntaxException extends IllegalArgumentException { diff --git a/libjava/classpath/java/util/zip/ZipConstants.java b/libjava/classpath/java/util/zip/ZipConstants.java index 952a44d..6d66419 100644 --- a/libjava/classpath/java/util/zip/ZipConstants.java +++ b/libjava/classpath/java/util/zip/ZipConstants.java @@ -1,5 +1,5 @@ /* java.util.zip.ZipConstants - Copyright (C) 2001 Free Software Foundation, Inc. + Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,7 +41,7 @@ interface ZipConstants { /* The local file header */ int LOCHDR = 30; - int LOCSIG = 'P'|('K'<<8)|(3<<16)|(4<<24); + long LOCSIG = 'P'|('K'<<8)|(3<<16)|(4<<24); int LOCVER = 4; int LOCFLG = 6; @@ -54,7 +54,7 @@ interface ZipConstants int LOCEXT = 28; /* The Data descriptor */ - int EXTSIG = 'P'|('K'<<8)|(7<<16)|(8<<24); + long EXTSIG = 'P'|('K'<<8)|(7<<16)|(8<<24); int EXTHDR = 16; int EXTCRC = 4; @@ -62,7 +62,7 @@ interface ZipConstants int EXTLEN = 12; /* The central directory file header */ - int CENSIG = 'P'|('K'<<8)|(1<<16)|(2<<24); + long CENSIG = 'P'|('K'<<8)|(1<<16)|(2<<24); int CENHDR = 46; int CENVEM = 4; @@ -82,7 +82,7 @@ interface ZipConstants int CENOFF = 42; /* The entries in the end of central directory */ - int ENDSIG = 'P'|('K'<<8)|(5<<16)|(6<<24); + long ENDSIG = 'P'|('K'<<8)|(5<<16)|(6<<24); int ENDHDR = 22; /* The following two fields are missing in SUN JDK */ diff --git a/libjava/classpath/java/util/zip/ZipFile.java b/libjava/classpath/java/util/zip/ZipFile.java index 4be845e..7307ee9 100644 --- a/libjava/classpath/java/util/zip/ZipFile.java +++ b/libjava/classpath/java/util/zip/ZipFile.java @@ -1,5 +1,5 @@ /* ZipFile.java -- - Copyright (C) 2001, 2002, 2003, 2004, 2005 + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,8 +41,6 @@ package java.util.zip; import gnu.java.util.EmptyEnumeration; -import java.io.BufferedInputStream; -import java.io.DataInput; import java.io.EOFException; import java.io.File; import java.io.IOException; @@ -141,23 +139,33 @@ public class ZipFile implements ZipConstants checkZipFile(); } - private void checkZipFile() throws IOException, ZipException + private void checkZipFile() throws ZipException { - byte[] magicBuf = new byte[4]; - boolean validRead = true; + boolean valid = false; try { - raf.readFully(magicBuf); - } - catch (EOFException eof) + byte[] buf = new byte[4]; + raf.readFully(buf); + int sig = buf[0] & 0xFF + | ((buf[1] & 0xFF) << 8) + | ((buf[2] & 0xFF) << 16) + | ((buf[3] & 0xFF) << 24); + valid = sig == LOCSIG; + } + catch (IOException _) { - validRead = false; } - if (validRead == false || readLeInt(magicBuf, 0) != LOCSIG) + if (!valid) { - raf.close(); + try + { + raf.close(); + } + catch (IOException _) + { + } throw new ZipException("Not a valid zip file"); } } @@ -172,69 +180,6 @@ public class ZipFile implements ZipConstants } /** - * Read an unsigned short in little endian byte order from the given - * DataInput stream using the given byte buffer. - * - * @param di DataInput stream to read from. - * @param b the byte buffer to read in (must be at least 2 bytes long). - * @return The value read. - * - * @exception IOException if a i/o error occured. - * @exception EOFException if the file ends prematurely - */ - private int readLeShort(DataInput di, byte[] b) throws IOException - { - di.readFully(b, 0, 2); - return (b[0] & 0xff) | (b[1] & 0xff) << 8; - } - - /** - * Read an int in little endian byte order from the given - * DataInput stream using the given byte buffer. - * - * @param di DataInput stream to read from. - * @param b the byte buffer to read in (must be at least 4 bytes long). - * @return The value read. - * - * @exception IOException if a i/o error occured. - * @exception EOFException if the file ends prematurely - */ - private int readLeInt(DataInput di, byte[] b) throws IOException - { - di.readFully(b, 0, 4); - return ((b[0] & 0xff) | (b[1] & 0xff) << 8) - | ((b[2] & 0xff) | (b[3] & 0xff) << 8) << 16; - } - - /** - * Read an unsigned short in little endian byte order from the given - * byte buffer at the given offset. - * - * @param b the byte array to read from. - * @param off the offset to read from. - * @return The value read. - */ - private int readLeShort(byte[] b, int off) - { - return (b[off] & 0xff) | (b[off+1] & 0xff) << 8; - } - - /** - * Read an int in little endian byte order from the given - * byte buffer at the given offset. - * - * @param b the byte array to read from. - * @param off the offset to read from. - * @return The value read. - */ - private int readLeInt(byte[] b, int off) - { - return ((b[off] & 0xff) | (b[off+1] & 0xff) << 8) - | ((b[off+2] & 0xff) | (b[off+3] & 0xff) << 8) << 16; - } - - - /** * Read the central directory of a zip file and fill the entries * array. This is called exactly once when first needed. It is called * while holding the lock on <code>raf</code>. @@ -246,63 +191,48 @@ public class ZipFile implements ZipConstants { /* Search for the End Of Central Directory. When a zip comment is * present the directory may start earlier. - * FIXME: This searches the whole file in a very slow manner if the - * file isn't a zip file. + * Note that a comment has a maximum length of 64K, so that is the + * maximum we search backwards. */ + PartialInputStream inp = new PartialInputStream(raf, 4096); long pos = raf.length() - ENDHDR; - byte[] ebs = new byte[CENHDR]; - + long top = Math.max(0, pos - 65536); do { - if (pos < 0) + if (pos < top) throw new ZipException ("central directory not found, probably not a zip file: " + name); - raf.seek(pos--); + inp.seek(pos--); } - while (readLeInt(raf, ebs) != ENDSIG); + while (inp.readLeInt() != ENDSIG); - if (raf.skipBytes(ENDTOT - ENDNRD) != ENDTOT - ENDNRD) + if (inp.skip(ENDTOT - ENDNRD) != ENDTOT - ENDNRD) throw new EOFException(name); - int count = readLeShort(raf, ebs); - if (raf.skipBytes(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ) + int count = inp.readLeShort(); + if (inp.skip(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ) throw new EOFException(name); - int centralOffset = readLeInt(raf, ebs); + int centralOffset = inp.readLeInt(); entries = new HashMap(count+count/2); - raf.seek(centralOffset); + inp.seek(centralOffset); - byte[] buffer = new byte[16]; for (int i = 0; i < count; i++) { - raf.readFully(ebs); - if (readLeInt(ebs, 0) != CENSIG) + if (inp.readLeInt() != CENSIG) throw new ZipException("Wrong Central Directory signature: " + name); - int method = readLeShort(ebs, CENHOW); - int dostime = readLeInt(ebs, CENTIM); - int crc = readLeInt(ebs, CENCRC); - int csize = readLeInt(ebs, CENSIZ); - int size = readLeInt(ebs, CENLEN); - int nameLen = readLeShort(ebs, CENNAM); - int extraLen = readLeShort(ebs, CENEXT); - int commentLen = readLeShort(ebs, CENCOM); - - int offset = readLeInt(ebs, CENOFF); - - int needBuffer = Math.max(nameLen, commentLen); - if (buffer.length < needBuffer) - buffer = new byte[needBuffer]; - - raf.readFully(buffer, 0, nameLen); - String name; - try - { - name = new String(buffer, 0, nameLen, "UTF-8"); - } - catch (UnsupportedEncodingException uee) - { - throw new AssertionError(uee); - } + inp.skip(6); + int method = inp.readLeShort(); + int dostime = inp.readLeInt(); + int crc = inp.readLeInt(); + int csize = inp.readLeInt(); + int size = inp.readLeInt(); + int nameLen = inp.readLeShort(); + int extraLen = inp.readLeShort(); + int commentLen = inp.readLeShort(); + inp.skip(8); + int offset = inp.readLeInt(); + String name = inp.readString(nameLen); ZipEntry entry = new ZipEntry(name); entry.setMethod(method); @@ -313,20 +243,12 @@ public class ZipFile implements ZipConstants if (extraLen > 0) { byte[] extra = new byte[extraLen]; - raf.readFully(extra); + inp.readFully(extra); entry.setExtra(extra); } if (commentLen > 0) { - raf.readFully(buffer, 0, commentLen); - try - { - entry.setComment(new String(buffer, 0, commentLen, "UTF-8")); - } - catch (UnsupportedEncodingException uee) - { - throw new AssertionError(uee); - } + entry.setComment(inp.readString(commentLen)); } entry.offset = offset; entries.put(name, entry); @@ -429,42 +351,6 @@ public class ZipFile implements ZipConstants } } - - //access should be protected by synchronized(raf) - private byte[] locBuf = new byte[LOCHDR]; - - /** - * Checks, if the local header of the entry at index i matches the - * central directory, and returns the offset to the data. - * - * @param entry to check. - * @return the start offset of the (compressed) data. - * - * @exception IOException if a i/o error occured. - * @exception ZipException if the local header doesn't match the - * central directory header - */ - private long checkLocalHeader(ZipEntry entry) throws IOException - { - synchronized (raf) - { - raf.seek(entry.offset); - raf.readFully(locBuf); - - if (readLeInt(locBuf, 0) != LOCSIG) - throw new ZipException("Wrong Local header signature: " + name); - - if (entry.getMethod() != readLeShort(locBuf, LOCHOW)) - throw new ZipException("Compression method mismatch: " + name); - - if (entry.getName().length() != readLeShort(locBuf, LOCNAM)) - throw new ZipException("file name length mismatch: " + name); - - int extraLen = entry.getName().length() + readLeShort(locBuf, LOCEXT); - return entry.offset + LOCHDR + extraLen; - } - } - /** * Creates an input stream reading the given zip entry as * uncompressed data. Normally zip entry should be an entry @@ -497,16 +383,32 @@ public class ZipFile implements ZipConstants if (zipEntry == null) return null; - long start = checkLocalHeader(zipEntry); + PartialInputStream inp = new PartialInputStream(raf, 1024); + inp.seek(zipEntry.offset); + + if (inp.readLeInt() != LOCSIG) + throw new ZipException("Wrong Local header signature: " + name); + + inp.skip(4); + + if (zipEntry.getMethod() != inp.readLeShort()) + throw new ZipException("Compression method mismatch: " + name); + + inp.skip(16); + + int nameLen = inp.readLeShort(); + int extraLen = inp.readLeShort(); + inp.skip(nameLen + extraLen); + + inp.setLength(zipEntry.getCompressedSize()); + int method = zipEntry.getMethod(); - InputStream is = new BufferedInputStream(new PartialInputStream - (raf, start, zipEntry.getCompressedSize())); switch (method) { case ZipOutputStream.STORED: - return is; + return inp; case ZipOutputStream.DEFLATED: - return new InflaterInputStream(is, new Inflater(true)); + return new InflaterInputStream(inp, new Inflater(true)); default: throw new ZipException("Unknown compression method " + method); } @@ -562,21 +464,41 @@ public class ZipFile implements ZipConstants } } - private static class PartialInputStream extends InputStream + private static final class PartialInputStream extends InputStream { private final RandomAccessFile raf; - long filepos, end; + private final byte[] buffer; + private long bufferOffset; + private int pos; + private long end; - public PartialInputStream(RandomAccessFile raf, long start, long len) + public PartialInputStream(RandomAccessFile raf, int bufferSize) + throws IOException { this.raf = raf; - filepos = start; - end = start + len; + buffer = new byte[bufferSize]; + bufferOffset = -buffer.length; + pos = buffer.length; + end = raf.length(); + } + + void setLength(long length) + { + end = bufferOffset + pos + length; + } + + private void fillBuffer() throws IOException + { + synchronized (raf) + { + raf.seek(bufferOffset); + raf.readFully(buffer, 0, (int) Math.min(buffer.length, end - bufferOffset)); + } } public int available() { - long amount = end - filepos; + long amount = end - (bufferOffset + pos); if (amount > Integer.MAX_VALUE) return Integer.MAX_VALUE; return (int) amount; @@ -584,41 +506,130 @@ public class ZipFile implements ZipConstants public int read() throws IOException { - if (filepos == end) + if (bufferOffset + pos >= end) return -1; - synchronized (raf) - { - raf.seek(filepos++); - return raf.read(); - } + if (pos == buffer.length) + { + bufferOffset += buffer.length; + pos = 0; + fillBuffer(); + } + return buffer[pos++] & 0xFF; } public int read(byte[] b, int off, int len) throws IOException { - if (len > end - filepos) + if (len > end - (bufferOffset + pos)) { - len = (int) (end - filepos); + len = (int) (end - (bufferOffset + pos)); if (len == 0) return -1; } - synchronized (raf) - { - raf.seek(filepos); - int count = raf.read(b, off, len); - if (count > 0) - filepos += len; - return count; - } + + int totalBytesRead = Math.min(buffer.length - pos, len); + System.arraycopy(buffer, pos, b, off, totalBytesRead); + pos += totalBytesRead; + off += totalBytesRead; + len -= totalBytesRead; + + while (len > 0) + { + bufferOffset += buffer.length; + pos = 0; + fillBuffer(); + int remain = Math.min(buffer.length, len); + System.arraycopy(buffer, pos, b, off, remain); + pos += remain; + off += remain; + len -= remain; + totalBytesRead += remain; + } + + return totalBytesRead; } - public long skip(long amount) + public long skip(long amount) throws IOException { if (amount < 0) - throw new IllegalArgumentException(); - if (amount > end - filepos) - amount = end - filepos; - filepos += amount; + return 0; + if (amount > end - (bufferOffset + pos)) + amount = end - (bufferOffset + pos); + seek(bufferOffset + pos + amount); return amount; } + + void seek(long newpos) throws IOException + { + long offset = newpos - bufferOffset; + if (offset >= 0 && offset <= buffer.length) + { + pos = (int) offset; + } + else + { + bufferOffset = newpos; + pos = 0; + fillBuffer(); + } + } + + void readFully(byte[] buf) throws IOException + { + if (read(buf, 0, buf.length) != buf.length) + throw new EOFException(); + } + + void readFully(byte[] buf, int off, int len) throws IOException + { + if (read(buf, off, len) != len) + throw new EOFException(); + } + + int readLeShort() throws IOException + { + int b0 = read(); + int b1 = read(); + if (b1 == -1) + throw new EOFException(); + return (b0 & 0xff) | (b1 & 0xff) << 8; + } + + int readLeInt() throws IOException + { + int b0 = read(); + int b1 = read(); + int b2 = read(); + int b3 = read(); + if (b3 == -1) + throw new EOFException(); + return ((b0 & 0xff) | (b1 & 0xff) << 8) + | ((b2 & 0xff) | (b3 & 0xff) << 8) << 16; + } + + String readString(int length) throws IOException + { + if (length > end - (bufferOffset + pos)) + throw new EOFException(); + + try + { + if (buffer.length - pos >= length) + { + String s = new String(buffer, pos, length, "UTF-8"); + pos += length; + return s; + } + else + { + byte[] b = new byte[length]; + readFully(b); + return new String(b, 0, length, "UTF-8"); + } + } + catch (UnsupportedEncodingException uee) + { + throw new AssertionError(uee); + } + } } } diff --git a/libjava/classpath/java/util/zip/ZipOutputStream.java b/libjava/classpath/java/util/zip/ZipOutputStream.java index 5c593b2..d292f7d 100644 --- a/libjava/classpath/java/util/zip/ZipOutputStream.java +++ b/libjava/classpath/java/util/zip/ZipOutputStream.java @@ -1,5 +1,5 @@ /* ZipOutputStream.java -- - Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -161,6 +161,16 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant } /** + * Write a long value as an int. Some of the zip constants + * are declared as longs even though they fit perfectly well + * into integers. + */ + private void writeLeInt(long value) throws IOException + { + writeLeInt((int) value); + } + + /** * Starts a new Zip entry. It automatically closes the previous * entry if present. If the compression method is stored, the entry * must have a valid size and crc, otherwise all elements (except |