From f911ba985aa7fe0096c386c5be385ac5825ea527 Mon Sep 17 00:00:00 2001
From: Tom Tromey
+ * This method can read a
+ * This method can read a
+ * As an example, if
+ *
+ * This method can read a
+ * This method can read a
+ * This method can read a
+ * As an example, if
+ *
+ * The value returned is in the range of -2147483648 to 2147483647.
+ *
+ * This method can read an
+ * The reading of bytes ends when either the end of file or a line
+ * terminator is encountered. The bytes read are then returned as a
+ *
+ * This method can read data that was written by an object implementing the
+ *
+ * As an example, if
+ *
+ * The value returned is in the range of -9223372036854775808 to
+ * 9223372036854775807.
+ *
+ * This method can read an
+ * As an example, if
+ *
+ * The value returned is in the range of -32768 to 32767.
+ *
+ * This method can read a
+ * This method can read an unsigned byte written by an object
+ * implementing the
+ * As an example, if
+ *
+ * The value returned is in the range of 0 to 65535.
+ *
+ * This method can read an unsigned short written by an object
+ * implementing the
+ * This method can read a
+ * This method can read a
+ * As an example, if
+ *
+ * This method can read a
+ * This method can read a
+ * This method can read a
+ * As an example, if
+ *
+ * The value returned is in the range of -2147483648 to 2147483647.
+ *
+ * This method can read an
+ * As an example, if
+ *
+ * The value returned is in the range of -9223372036854775808 to
+ * 9223372036854775807.
+ *
+ * This method can read an
+ * As an example, if
+ *
+ * The value returned is in the range of -32768 to 32767.
+ *
+ * This method can read a
+ * This method can read an unsigned byte written by an object
+ * implementing the
+ * As an example, if
+ *
+ * The value returned is in the range of 0 to 65535.
+ *
+ * This method can read an unsigned short written by an object
+ * implementing the The plug-ins are concrete implementations of the service
+ * provider interface, which is defined as an interface or an abstract
+ * class. The implementation classes must be public and have a public
+ * constructor that takes no arguments.
+ *
+ * Plug-ins are usually deployed in JAR files. A JAR that provides
+ * an implementation of a service must declare this in a resource file
+ * whose name is the fully qualified service name and whose location
+ * is the directory Example
+ *
+ * For example, a JAR might provide two implementations of the
+ * service provider interface The code for Acme’s Thread Safety
+ *
+ * It is safe to use Note for User Applications
+ *
+ * User applications that want to load plug-ins should not directly
+ * use Because {@link java.util.logging.Logger#getLogger(String)}
+ * is thread-safe, we do not need to worry about synchronization
+ * here.
+ */
+ private static final Logger LOGGER = Logger.getLogger("gnu.classpath");
+
+
+ /**
+ * Declared private in order to prevent constructing instances of
+ * this utility class.
+ */
+ private ServiceFactory()
+ {
+ }
+
+
+ /**
+ * Finds service providers that are implementing the specified
+ * Service Provider Interface.
+ *
+ * On-demand loading: Loading and initializing service
+ * providers is delayed as much as possible. The rationale is that
+ * typical clients will iterate through the set of installed service
+ * providers until one is found that matches some criteria (like
+ * supported formats, or quality of service). In such scenarios, it
+ * might make sense to install only the frequently needed service
+ * providers on the local machine. More exotic providers can be put
+ * onto a server; the server will only be contacted when no suitable
+ * service could be found locally.
+ *
+ * Security considerations: Any loaded service providers
+ * are loaded through the specified ClassLoader, or the system
+ * ClassLoader if Class loading and instantiation is encapsulated in a
+ * This class is also a thread that is responsible for pulling
+ * packets off the wire and sticking them in a queue for packet
+ * processing threads.
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class JdwpConnection
+ extends Thread
+{
+ // The JDWP handshake
+ private static final byte[] _HANDSHAKE = {'J', 'D', 'W', 'P', '-', 'H', 'a',
+ 'n', 'd', 's', 'h', 'a', 'k', 'e'};
+
+ // Transport method
+ private ITransport _transport;
+
+ // Command queue
+ private ArrayList _commandQueue;
+
+ // Shutdown flag
+ private boolean _shutdown;
+
+ // Input stream from transport
+ private DataInputStream _inStream;
+
+ // Output stream from transprot
+ private DataOutputStream _outStream;
+
+ // A buffer used to construct the packet data
+ private ByteArrayOutputStream _bytes;
+
+ // A DataOutputStream for the byte buffer
+ private DataOutputStream _doStream;
+
+ /**
+ * Creates a new The above screen shot shows the result of applying six different
+ * BitwiseXORComposites. They were constructed with the colors colors
+ * white, blue, black, orange, green, and brown, respectively. Each
+ * composite was used to paint a fully white rectangle on top of the
+ * blue bar in the background.
+ *
+ * The purpose of this composite is to support the {@link
+ * Graphics#setXORMode(Color)} method in composite-aware graphics
+ * implementations. Applications typically would use
+ * A concrete Applying this CompositeContext on a 1024x1024 BufferedImage of
+ * Applying this CompositeContext on a 1024x1024 BufferedImage of
+ * There exist some parts of AWT and Java2D that are specific to
+ * the underlying platform, but for which the {@link Toolkit} class
+ * does not provide suitable abstractions. Examples include some
+ * methods of {@link Font} or {@link GraphicsEnvironment}. Those
+ * methods use ClasspathToolkit as a central place for obtaining
+ * platform-specific functionality.
+ *
+ * In addition, ClasspathToolkit implements some abstract methods
+ * of {@link java.awt.Toolkit} that are not really platform-specific,
+ * such as the maintenance of a cache of loaded images.
+ *
+ * Thread Safety: The methods of this class may safely be
+ * called without external synchronization. This also hold for any
+ * inherited {@link Toolkit} methods. Subclasses are responsible for
+ * the necessary synchronization.
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public abstract class ClasspathToolkit
+ extends Toolkit
+{
+ /**
+ * A map from URLs to previously loaded images, used by {@link
+ * #getImage(java.net.URL)}. For images that were loaded via a path
+ * to an image file, the map contains a key with a file URL.
+ */
+ private HashMap imageCache;
+
+
+ /**
+ * Returns a shared instance of the local, platform-specific
+ * graphics environment.
+ *
+ * This method is specific to GNU Classpath. It gets called by
+ * the Classpath implementation of {@link
+ * GraphicsEnvironment.getLocalGraphcisEnvironment()}.
+ */
+ public abstract GraphicsEnvironment getLocalGraphicsEnvironment();
+
+
+ /**
+ * Determines the current size of the default, primary screen.
+ *
+ * @throws HeadlessException if the local graphics environment is
+ * headless, which means that no screen is attached and no user
+ * interaction is allowed.
+ */
+ public Dimension getScreenSize()
+ {
+ DisplayMode mode;
+
+ // getDefaultScreenDevice throws HeadlessException if the
+ // local graphics environment is headless.
+ mode = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getDefaultScreenDevice().getDisplayMode();
+
+ return new Dimension(mode.getWidth(), mode.getHeight());
+ }
+
+
+ /**
+ * Determines the current color model of the default, primary
+ * screen.
+ *
+ * @see GraphicsEnvironment#getDefaultScreenDevice()
+ * @see java.awt.GraphicsDevice#getDefaultConfiguration()
+ * @see java.awt.GraphicsConfiguration#getColorModel()
+ *
+ * @throws HeadlessException if the local graphics environment is
+ * headless, which means that no screen is attached and no user
+ * interaction is allowed.
+ */
+ public ColorModel getColorModel()
+ {
+ // getDefaultScreenDevice throws HeadlessException if the
+ // local graphics environment is headless.
+ return GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getDefaultScreenDevice().getDefaultConfiguration()
+ .getColorModel();
+ }
+
+ /**
+ * Retrieves the metrics for rendering a font on the screen.
+ *
+ * @param font the font whose metrics are requested.
+ */
+ public FontMetrics getFontMetrics(Font font)
+ {
+ return ((ClasspathFontPeer) font.getPeer ()).getFontMetrics (font);
+ }
+
+
+ /**
+ * Acquires an appropriate {@link ClasspathFontPeer}, for use in
+ * classpath's implementation of {@link java.awt.Font}.
+ *
+ * @param name The logical name of the font. This may be either a face
+ * name or a logical font name, or may even be null. A default
+ * implementation of name decoding is provided in
+ * {@link ClasspathFontPeer}, but may be overridden in other toolkits.
+ *
+ * @param attrs Any extra {@link java.awt.font.TextAttribute} attributes
+ * this font peer should have, such as size, weight, family name, or
+ * transformation.
+ */
+ public abstract ClasspathFontPeer getClasspathFontPeer (String name, Map attrs);
+
+ public abstract ClasspathTextLayoutPeer
+ getClasspathTextLayoutPeer (AttributedString str, FontRenderContext frc);
+
+
+ /**
+ * Creates a {@link Font}, in a platform-specific manner.
+ *
+ * The default implementation simply constructs a {@link Font}, but some
+ * toolkits may wish to override this, to return {@link Font} subclasses which
+ * implement {@link java.awt.font.OpenType} or
+ * {@link java.awt.font.MultipleMaster}.
+ */
+ public Font getFont (String name, Map attrs)
+ {
+ return new Font (name, attrs);
+ }
+
+
+ /**
+ * Creates a font, reading the glyph definitions from a stream.
+ *
+ * This method provides the platform-specific implementation for
+ * the static factory method {@link Font#createFont(int,
+ * java.io.InputStream)}.
+ *
+ * @param format the format of the font data, such as {@link
+ * Font#TRUETYPE_FONT}. An implementation may ignore this argument
+ * if it is able to automatically recognize the font format from the
+ * provided data.
+ *
+ * @param stream an input stream from where the font data is read
+ * in. The stream will be advanced to the position after the font
+ * data, but not closed.
+ *
+ * @throws IllegalArgumentException if This method maintains a cache for images. If an image has been
+ * loaded from the same path before, the cached copy will be
+ * returned. The implementation may hold cached copies for an
+ * indefinite time, which can consume substantial resources with
+ * large images. Users are therefore advised to use {@link
+ * #createImage(java.lang.String)} instead.
+ *
+ * The default implementation creates a file URL for the
+ * specified path and invokes {@link #getImage(URL)}.
+ *
+ * @param path A path to the image file.
+ *
+ * @return IllegalArgumentException if This method maintains a cache for images. If an image has been
+ * loaded from the same URL before, the cached copy will be
+ * returned. The implementation may hold cached copies for an
+ * indefinite time, which can consume substantial resources with
+ * large images. Users are therefore advised to use {@link
+ * #createImage(java.net.URL)} instead.
+ *
+ * @param url the URL from where the image is read.
+ */
+ public Image getImage(URL url)
+ {
+ Image result;
+
+ synchronized (this)
+ {
+ // Many applications never call getImage. Therefore, we lazily
+ // create the image cache when it is actually needed.
+ if (imageCache == null)
+ imageCache = new HashMap();
+ else
+ {
+ result = (Image) imageCache.get(url);
+ if (result != null)
+ return result;
+ }
+
+ // The createImage(URL) method, which is specified by
+ // java.awt.Toolkit, is not implemented by this abstract class
+ // because it is platform-dependent. Once Classpath has support
+ // for the javax.imageio package, it might be worth considering
+ // that toolkits provide native stream readers. Then, the class
+ // ClasspathToolkit could provide a general implementation that
+ // delegates the image format parsing to javax.imageio.
+ result = createImage(url);
+
+ // It is not clear whether it would be a good idea to use weak
+ // references here. The advantage would be reduced memory
+ // consumption, since loaded images would not be kept
+ // forever. But on VMs that frequently perform garbage
+ // collection (which includes VMs with a parallel or incremental
+ // collector), the image might frequently need to be re-loaded,
+ // possibly over a slow network connection.
+ imageCache.put(url, result);
+
+ return result;
+ }
+ }
+
+
+ /**
+ * Returns an image from the specified file, which must be in a
+ * recognized format. The set of recognized image formats may vary
+ * from toolkit to toolkit.
+ *
+ * A new image is created every time this method gets called,
+ * even if the same path has been passed before.
+ *
+ * The default implementation creates a file URL for the
+ * specified path and invokes {@link #createImage(URL)}.
+ *
+ * @param path A path to the file to be read in.
+ */
+ public Image createImage(String path)
+ {
+ try
+ {
+ // The abstract method createImage(URL) is defined by
+ // java.awt.Toolkit, but intentionally not implemented by
+ // ClasspathToolkit because it is platform specific.
+ return createImage(new File(path).toURL());
+ }
+ catch (MalformedURLException muex)
+ {
+ throw (IllegalArgumentException) new IllegalArgumentException(path)
+ .initCause(muex);
+ }
+ }
+
+ /**
+ * Creates an ImageProducer from the specified URL. The image is assumed
+ * to be in a recognised format. If the toolkit does not implement the
+ * image format or the image format is not recognised, null is returned.
+ * This default implementation is overriden by the Toolkit implementations.
+ *
+ * @param url URL to read image data from.
+ */
+ public ImageProducer createImageProducer(URL url)
+ {
+ return null;
+ }
+
+ public abstract RobotPeer createRobot (GraphicsDevice screen)
+ throws AWTException;
+
+ /**
+ * Creates an embedded window peer, and associates it with an
+ * EmbeddedWindow object.
+ *
+ * @param w The embedded window with which to associate a peer.
+ */
+ public abstract EmbeddedWindowPeer createEmbeddedWindow (EmbeddedWindow w);
+
+ /**
+ * Used to register ImageIO SPIs provided by the toolkit.
+ */
+
+ public void registerImageIOSpis(IIORegistry reg)
+ {
+ }
+
+ public abstract boolean nativeQueueEmpty();
+ public abstract void wakeNativeQueue();
+ public abstract void iterateNativeQueue(EventQueue locked, boolean block);
+}
diff --git a/libjava/classpath/gnu/java/awt/ComponentDataBlitOp.java b/libjava/classpath/gnu/java/awt/ComponentDataBlitOp.java
new file mode 100644
index 0000000..545427e
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/ComponentDataBlitOp.java
@@ -0,0 +1,156 @@
+/* Copyright (C) 2000, 2002, 2004 Free Software Foundation
+
+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 gnu.java.awt;
+
+import java.awt.RenderingHints;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.RasterOp;
+import java.awt.image.WritableRaster;
+
+/**
+ * This raster copy operation assumes that both source and destination
+ * sample models are tightly pixel packed and contain the same number
+ * of bands.
+ *
+ * @throws java.lang.ClassCastException if the sample models of the
+ * rasters are not of type ComponentSampleModel.
+ *
+ * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
+ */
+public class ComponentDataBlitOp implements RasterOp
+{
+ public static final ComponentDataBlitOp INSTANCE = new ComponentDataBlitOp();
+
+ public WritableRaster filter(Raster src, WritableRaster dest)
+ {
+ if (dest == null)
+ dest = createCompatibleDestRaster(src);
+
+ DataBuffer srcDB = src.getDataBuffer();
+ DataBuffer destDB = dest.getDataBuffer();
+
+ ComponentSampleModel srcSM = (ComponentSampleModel) src.getSampleModel();
+ ComponentSampleModel destSM = (ComponentSampleModel) dest.getSampleModel();
+
+
+ // Calculate offset to data in the underlying arrays:
+
+ int srcScanlineStride = srcSM.getScanlineStride();
+ int destScanlineStride = destSM.getScanlineStride();
+ int srcX = src.getMinX() - src.getSampleModelTranslateX();
+ int srcY = src.getMinY() - src.getSampleModelTranslateY();
+ int destX = dest.getMinX() - dest.getSampleModelTranslateX();
+ int destY = dest.getMinY() - dest.getSampleModelTranslateY();
+
+ int numBands = srcSM.getNumBands();
+
+ /* We can't use getOffset(x, y) from the sample model since we
+ don't want the band offset added in. */
+
+ int srcOffset =
+ numBands*srcX + srcScanlineStride*srcY + // from sample model
+ srcDB.getOffset(); // from data buffer
+
+ int destOffset =
+ numBands*destX + destScanlineStride*destY + // from sample model
+ destDB.getOffset(); // from data buffer
+
+ // Determine how much, and how many times to blit.
+
+ int rowSize = src.getWidth()*numBands;
+ int h = src.getHeight();
+
+ if ((rowSize == srcScanlineStride) &&
+ (rowSize == destScanlineStride))
+ {
+ // collapse scan line blits to one large blit.
+ rowSize *= h;
+ h = 1;
+ }
+
+
+ // Do blitting
+
+ Object srcArray = Buffers.getData(srcDB);
+ Object destArray = Buffers.getData(destDB);
+
+ for (int yd = 0; yd State kept by the peer: a peer is generated for each Font
+ * object in the default implementation. If you wish to share peers between
+ * fonts, you will need to subclass both ClasspathFontPeer and
+ * {@link ClasspathToolKit}. Thread Safety: Methods of this interface may be called
+ * from arbitrary threads at any time. Implementations of the
+ * This method is currently not used by {@link Font}. However,
+ * this name would be needed by any serious desktop publishing
+ * application.
+ *
+ * @param font the font whose sub-family name is requested.
+ *
+ * @param locale the locale for which to localize the name. If
+ * This method is currently not used by GNU Classpath. However,
+ * it would be very useful for someone wishing to write a good
+ * PostScript or PDF stream provider for the
+ * Names are not unique: Under some rare circumstances,
+ * the same name can be returned for different glyphs. It is
+ * therefore recommended that printer drivers check whether the same
+ * name has already been returned for antoher glyph, and make the
+ * name unique by adding the string ".alt" followed by the glyph
+ * index. This situation would occur for an OpenType or TrueType font
+ * that has a This package implements the GTK peer for java.awt.
+ **
+ ** This class is not well-synchronized. (It can be, it
+ ** just isn't yet.)
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 30 Jul 1998
+ ** @see java.beans.BeanInfo
+ **/
+
+public class BeanInfoEmbryo {
+
+ // by using a TreeMap the properties will be sorted alphabetically by name
+ // which matches the (undocumented) behavior of jdk
+ TreeMap properties = new TreeMap();
+ Hashtable events = new Hashtable();
+ Vector methods = new Vector();
+
+ BeanDescriptor beanDescriptor;
+ BeanInfo[] additionalBeanInfo;
+ java.awt.Image[] im;
+ String defaultPropertyName;
+ String defaultEventName;
+
+ public BeanInfoEmbryo() {
+ }
+
+ public BeanInfo getBeanInfo() {
+ int defaultProperty = -1;
+ int defaultEvent = -1;
+
+ PropertyDescriptor[] Aproperties = new PropertyDescriptor[properties.size()];
+ int i = 0;
+ Iterator it = properties.entrySet().iterator();
+ while (it.hasNext()) {
+ Aproperties[i] = (PropertyDescriptor) (((Map.Entry)it.next()).getValue());
+ if(defaultPropertyName != null && Aproperties[i].getName().equals(defaultPropertyName)) {
+ defaultProperty = i;
+ }
+ i++;
+ }
+
+ EventSetDescriptor[] Aevents = new EventSetDescriptor[events.size()];
+ i = 0;
+ Enumeration e = events.elements();
+ while (e.hasMoreElements()) {
+ Aevents[i] = (EventSetDescriptor) e.nextElement();
+ if(defaultEventName != null && Aevents[i].getName().equals(defaultEventName)) {
+ defaultEvent = i;
+ }
+ i++;
+ }
+
+ MethodDescriptor[] Amethods = new MethodDescriptor[methods.size()];
+ methods.copyInto(Amethods);
+
+ return new ExplicitBeanInfo(beanDescriptor,additionalBeanInfo,Aproperties,defaultProperty,Aevents,defaultEvent,Amethods,im);
+ }
+
+ public void setBeanDescriptor(BeanDescriptor b) {
+ beanDescriptor = b;
+ }
+
+ public void setAdditionalBeanInfo(BeanInfo[] b) {
+ additionalBeanInfo = b;
+ }
+
+ public boolean hasProperty(PropertyDescriptor p) {
+ return properties.get(p.getName()) != null;
+ }
+ public void addProperty(PropertyDescriptor p) {
+ properties.put(p.getName(),p);
+ }
+ public void addIndexedProperty(IndexedPropertyDescriptor p) {
+ properties.put(p.getName(),p);
+ }
+
+ public boolean hasEvent(EventSetDescriptor e) {
+ return events.get(e.getName()) != null;
+ }
+ public void addEvent(EventSetDescriptor e) {
+ events.put(e.getName(),e);
+ }
+
+ public boolean hasMethod(MethodDescriptor m) {
+ for(int i=0;i This is the default implementation for GNU Classpath and is used for It has no functionality in order to allow it to be used without any dependencies
+ * (e.g. sound, network access, ...). This class is used for This class provides the implementation for an indexed get and set method.
+ * But this does not mean that the result object supports these operation. Note: Often multiple steps are needed to construct a fully usuable object instance.
+ * Such a construction can be called assembly and thats why this exception was
+ * named AssemblyException. The constructor is invoked when a sub-context is a statement or the Context ends. Depending on the result of isStatement() a Context can be statement or an
+ * expression. An expression returns a value to the Context of its parent handler,
+ * a statement does not. Whenever a Context is a statement the parent handler's
+ * Context is informed about that through the {@link notifyStatement}-method. The implementation just writes the exception's message to When the implementation is correct none of this class' methods
+ * (except An IndexContent is a get operation when no argument is provided and a set operation if one
+ * argument is provided. When the result object is available methods can be called on it using sub-Contexts. The ObjectContext does not accept any parameter object and ignores notifications
+ * about sub-contexts being statements. When the method call has to be made and there is no argument we 'get' the property.
+ * With one argument it is 'set'. All of these tags have in common that they do not accept attributes. A warning is
+ * send to the parser's ExceptionListener when one or more attributes exist.
+ **
+ ** To Do: add support for a checkbox
+ ** as the custom editor.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 29 Jul 1998
+ **/
+
+public class NativeBooleanEditor extends PropertyEditorSupport {
+ String[] tags = {"true","false"};
+
+ /**
+ * setAsText for boolean checks for true or false or t or f.
+ * "" also means false.
+ **/
+ public void setAsText(String val) throws IllegalArgumentException {
+ if(val.equalsIgnoreCase("true") || val.equalsIgnoreCase("t")) {
+ setValue(Boolean.TRUE);
+ } else if(val.equalsIgnoreCase("false") || val.equalsIgnoreCase("f") || val.equals("")) {
+ setValue(Boolean.FALSE);
+ } else {
+ throw new IllegalArgumentException("Value must be true, false, t, f or empty.");
+ }
+ }
+
+
+ /** getAsText for boolean calls Boolean.toString(). **/
+ public String getAsText() {
+ return getValue().toString();
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java
new file mode 100644
index 0000000..f3ec5fa
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java
@@ -0,0 +1,61 @@
+/* gnu.java.beans.editors.NativeByteEditor
+ Copyright (C) 1998 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 gnu.java.beans.editors;
+
+import java.beans.PropertyEditorSupport;
+
+/**
+ ** NativeByteEditor is a property editor for the
+ ** byte type.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 29 Jul 1998
+ **/
+
+public class NativeByteEditor extends PropertyEditorSupport {
+ /** setAsText for byte calls Byte.valueOf(). **/
+ public void setAsText(String val) throws IllegalArgumentException {
+ setValue(Byte.valueOf(val));
+ }
+
+ /** getAsText for byte calls Byte.toString(). **/
+ public String getAsText() {
+ return getValue().toString();
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java
new file mode 100644
index 0000000..8d8aae1
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java
@@ -0,0 +1,61 @@
+/* gnu.java.beans.editors.NativeDoubleEditor
+ Copyright (C) 1998 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 gnu.java.beans.editors;
+
+import java.beans.PropertyEditorSupport;
+
+/**
+ ** NativeDoubleEditor is a property editor for the
+ ** double type.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 29 Jul 1998
+ **/
+
+public class NativeDoubleEditor extends PropertyEditorSupport {
+ /** setAsText for double calls Double.valueOf(). **/
+ public void setAsText(String val) throws IllegalArgumentException {
+ setValue(Double.valueOf(val));
+ }
+
+ /** getAsText for double calls Double.toString(). **/
+ public String getAsText() {
+ return getValue().toString();
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java
new file mode 100644
index 0000000..801377e
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java
@@ -0,0 +1,61 @@
+/* gnu.java.beans.editors.NativeFloatEditor
+ Copyright (C) 1998 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 gnu.java.beans.editors;
+
+import java.beans.PropertyEditorSupport;
+
+/**
+ ** NativeFloatEditor is a property editor for the
+ ** float type.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 29 Jul 1998
+ **/
+
+public class NativeFloatEditor extends PropertyEditorSupport {
+ /** setAsText for float calls Float.valueOf(). **/
+ public void setAsText(String val) throws IllegalArgumentException {
+ setValue(Float.valueOf(val));
+ }
+
+ /** getAsText for float calls Float.toString(). **/
+ public String getAsText() {
+ return getValue().toString();
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java
new file mode 100644
index 0000000..a614884
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java
@@ -0,0 +1,61 @@
+/* gnu.java.beans.editors.NativeIntEditor
+ Copyright (C) 1998 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 gnu.java.beans.editors;
+
+import java.beans.PropertyEditorSupport;
+
+/**
+ ** NativeIntEditor is a property editor for the
+ ** int type.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 29 Jul 1998
+ **/
+
+public class NativeIntEditor extends PropertyEditorSupport {
+ /** setAsText for int calls Integer.valueOf(). **/
+ public void setAsText(String val) throws IllegalArgumentException {
+ setValue(Integer.valueOf(val));
+ }
+
+ /** getAsText for int calls Integer.toString(). **/
+ public String getAsText() {
+ return getValue().toString();
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java
new file mode 100644
index 0000000..95e9dc8
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java
@@ -0,0 +1,61 @@
+/* gnu.java.beans.editors.NativeLongEditor
+ Copyright (C) 1998 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 gnu.java.beans.editors;
+
+import java.beans.PropertyEditorSupport;
+
+/**
+ ** NativeLongEditor is a property editor for the
+ ** long type.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 29 Jul 1998
+ **/
+
+public class NativeLongEditor extends PropertyEditorSupport {
+ /** setAsText for long calls Long.valueOf(). **/
+ public void setAsText(String val) throws IllegalArgumentException {
+ setValue(Long.valueOf(val));
+ }
+
+ /** getAsText for long calls Long.toString(). **/
+ public String getAsText() {
+ return getValue().toString();
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java
new file mode 100644
index 0000000..ffaa266
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java
@@ -0,0 +1,61 @@
+/* gnu.java.beans.editors.NativeShortEditor
+ Copyright (C) 1998 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 gnu.java.beans.editors;
+
+import java.beans.PropertyEditorSupport;
+
+/**
+ ** NativeShortEditor is a property editor for the
+ ** short type.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 29 Jul 1998
+ **/
+
+public class NativeShortEditor extends PropertyEditorSupport {
+ /** setAsText for short calls Short.valueOf(). **/
+ public void setAsText(String val) throws IllegalArgumentException {
+ setValue(Short.valueOf(val));
+ }
+
+ /** getAsText for short calls Short.toString(). **/
+ public String getAsText() {
+ return getValue().toString();
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/editors/StringEditor.java b/libjava/classpath/gnu/java/beans/editors/StringEditor.java
new file mode 100644
index 0000000..8242d54
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/editors/StringEditor.java
@@ -0,0 +1,61 @@
+/* gnu.java.beans.editors.StringEditor
+ Copyright (C) 1998 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 gnu.java.beans.editors;
+
+import java.beans.PropertyEditorSupport;
+
+/**
+ ** NativeByteEditor is a property editor for the
+ ** byte type.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 29 Jul 1998
+ **/
+
+public class StringEditor extends PropertyEditorSupport {
+ /** setAsText just sets the value. **/
+ public void setAsText(String val) throws IllegalArgumentException {
+ setValue(val);
+ }
+
+ /** getAsText just returns the value. **/
+ public String getAsText() {
+ return (String)getValue();
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/editors/TODO b/libjava/classpath/gnu/java/beans/editors/TODO
new file mode 100644
index 0000000..6877f4c
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/editors/TODO
@@ -0,0 +1,4 @@
+- write tests for all editors
+- add some sort of ColorChooser as a custom editor for ColorEditor
+- add a FileNameEditor
+- add a FontChooser as a custom editor for FontEditor
diff --git a/libjava/classpath/gnu/java/beans/editors/package.html b/libjava/classpath/gnu/java/beans/editors/package.html
new file mode 100644
index 0000000..465f68d
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/editors/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+ * If the supplied key is merely the empty string, then the empty string is
+ * returned.
+ *
+ * Note that if the SO_LINGER option is set on this socket, then the
+ * operation could block.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native void close() throws IOException;
+
+ public void sendUrgentData(int data)
+ {
+ throw new InternalError ("PlainSocketImpl::sendUrgentData not implemented");
+ }
+
+ /**
+ * Internal method used by SocketInputStream for reading data from
+ * the connection. Reads up to len bytes of data into the buffer
+ * buf starting at offset bytes into the buffer.
+ *
+ * @return The actual number of bytes read or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native int read(byte[] buf, int offset, int len)
+ throws IOException;
+
+ /**
+ * Internal method used by SocketOuputStream for writing data to
+ * the connection. Writes up to len bytes of data from the buffer
+ * buf starting at offset bytes into the buffer.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native void write(byte[] buf, int offset, int len)
+ throws IOException;
+
+ /**
+ * Returns an InputStream object for reading from this socket. This will
+ * be an instance of SocketInputStream.
+ *
+ * @return An input stream attached to the socket.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized InputStream getInputStream() throws IOException
+ {
+ if (in == null)
+ in = new SocketInputStream();
+
+ return in;
+ }
+
+ /**
+ * Returns an OutputStream object for writing to this socket. This will
+ * be an instance of SocketOutputStream.
+ *
+ * @return An output stream attached to the socket.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized OutputStream getOutputStream() throws IOException
+ {
+ if (out == null)
+ out = new SocketOutputStream();
+
+ return out;
+ }
+
+ /**
+ * This class contains an implementation of
+This package contains an FTP client. It can handle both active and passive
+mode connections and the various transfer modes and representation types.
+
+Interaction with the server is via a simple stream interface. Only one
+concurrent stream (input or output) is supported.
+
+The control connection to the server can be protected using TLS
+(the starttls method).
+
+This package contains an HTTP/1.1 client, as described in RFC 2616.
+It supports the following features:
+fixed
.
+ * The format, described in CORBA specification, requires to store
+ * data in hexadecimal format, two digits per byte (oceted), most
+ * significant digit first. The last half-byte in the representation
+ * stores the sign, being 0xD for negative numbers and 0xC for
+ * zero and positive numbers. To have the even number of half bytes,
+ * 0x0 is appended to the beginning, if required. The position of the
+ * decimal point is not stored.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class BigDecimalHelper
+{
+ {
+ }
+
+ /**
+ * @todo remove from the release version.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ ByteArrayOutputStream b = new ByteArrayOutputStream();
+ BigDecimal d = new BigDecimal("12234.54689");
+
+ write(b, d);
+
+ byte[] a = b.toByteArray();
+
+ for (int i = 0; i < a.length; i++)
+ {
+ int k = a [ i ] & 0xFF;
+ System.out.print(Integer.toHexString(k) + " ");
+ }
+
+ System.out.println("Now reading");
+
+ ByteArrayInputStream bin = new ByteArrayInputStream(a);
+
+ BigDecimal r = read(bin, d.scale());
+
+ System.out.println(r);
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ /**
+ * Read the CORBA fixed, autodetecting the number of bytes
+ * and assuming the given scale.
+ */
+ public static BigDecimal read(java.io.InputStream in, int scale)
+ throws IOException
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+
+ int f;
+
+ do
+ {
+ f = in.read();
+ if (f >= 0)
+ bout.write(f);
+ }
+ // The last byte has 0xC or 0xD in the last halfbyte.
+ while ((f & 0xF) <= 0x9);
+
+ return createFixed(scale, bout.toByteArray());
+ }
+
+ /**
+ * Write the big decimal as CORBA fixed<.code>.
+ * The scale will not be stored.
+ *
+ * @param out a stream to write into.
+ * @param x a big decimal to write.
+ * @param digits a number of the decimal digits in the record
+ * being written. For the smaller
+ * numbers, zeroes are added to the left.
+ *
+ * @throws IOException if the stream write method throws one.
+ * @throws BadKind if this BigDecimal has more digits than
+ * specified.
+ */
+ public static void write(java.io.OutputStream out, BigDecimal x)
+ throws IOException, BadKind
+ {
+ StringBuffer v = new StringBuffer(x.unscaledValue().toString());
+
+ boolean negative = v.charAt(0) == '-';
+
+ if (negative)
+ v = v.deleteCharAt(0);
+
+ if ( (v.length() & 1) == 0)
+ v.insert(0, '0');
+
+ int c;
+
+ for (int i = 0; i < v.length() - 1; i = i + 2)
+ {
+ c = ((v.charAt(i) - '0') << 4) | (v.charAt(i + 1) - '0');
+ out.write(c);
+ }
+
+ c = ((v.charAt(v.length() - 1) - '0') << 4) | (negative ? 0xD : 0xC);
+
+ out.write(c);
+ }
+
+ /**
+ * Convert the loaded byte array, representing
+ * CORBA
implementation that does nothing.
+ *
+ * fixed
, into an instance of
+ * the {@link BigDecimal}
+ */
+ private static BigDecimal createFixed(int scale, byte[] d)
+ {
+ StringBuffer s = new StringBuffer(2 * d.length);
+
+ int last = d.length - 1;
+
+ if ((d [ last ] & 0xF) == 0xD)
+ s.append('-');
+
+ if (last > 0)
+ for (int i = 0; i < last; i++)
+ {
+ s.append((char) (((d [ i ] >> 4) & 0xF) + '0'));
+ s.append((char) (((d [ i ]) & 0xF) + '0'));
+ }
+
+ s.append((char) (((d [ last ] >> 4) & 0xF) + '0'));
+
+ BigInteger b = new BigInteger(s.toString());
+ BigDecimal dec = new BigDecimal(b, scale);
+
+ return dec;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/ByteArrayComparator.java b/libjava/classpath/gnu/CORBA/ByteArrayComparator.java
new file mode 100644
index 0000000..8491154
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/ByteArrayComparator.java
@@ -0,0 +1,91 @@
+/* ByteArrayComparator.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * A byte array comparator for mapping with CORBA object keys.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class ByteArrayComparator
+ implements Comparator
+{
+ /**
+ * Compare arrays first by absolute equality, then by length
+ * and then (byte to byte) by content.
+ *
+ * @return 0 if arrays are equal, some comparison value otherwise.
+ */
+ public int compare(Object an_a, Object a_b)
+ {
+ if (an_a == a_b)
+ return 0;
+
+ byte[] a = null;
+ byte[] b = null;
+ try
+ {
+ a = (byte[]) an_a;
+ b = (byte[]) a_b;
+ }
+ catch (Exception ex)
+ {
+ throw new InternalError(an_a.getClass().getName() + "," +
+ a_b.getClass().getName()
+ );
+ }
+
+ if (a.length != b.length)
+ return a.length - b.length;
+ else
+ {
+ // The array sizes must be equal.
+ for (int i = 0; i < b.length; i++)
+ {
+ if (a [ i ] != b [ i ])
+ return a [ i ] - b [ i ];
+ }
+ }
+
+ return 0;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/CDR/BigEndianInputStream.java b/libjava/classpath/gnu/CORBA/CDR/BigEndianInputStream.java
new file mode 100644
index 0000000..bc01939
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/BigEndianInputStream.java
@@ -0,0 +1,61 @@
+/* BigEndianInputStream.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+import java.io.DataInputStream;
+import java.io.InputStream;
+
+/**
+ * As java uses Big Endian by default, this class is directly derived
+ * form DataInputStream.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class BigEndianInputStream
+ extends DataInputStream
+ implements abstractDataInputStream
+{
+ /**
+ * Delegates to the parent constructor.
+ */
+ public BigEndianInputStream(InputStream in)
+ {
+ super(in);
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/CDR/BigEndianOutputStream.java b/libjava/classpath/gnu/CORBA/CDR/BigEndianOutputStream.java
new file mode 100644
index 0000000..e0aa7da
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/BigEndianOutputStream.java
@@ -0,0 +1,62 @@
+/* BigEndianOutputStream.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+import java.io.DataOutputStream;
+import java.io.OutputStream;
+
+/**
+ * A stream to read the data in Big Endian format. This class is
+ * directly derived from DataOutputStream that uses the Big
+ * Endian.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class BigEndianOutputStream
+ extends DataOutputStream
+ implements abstractDataOutputStream
+{
+ /**
+ * Delegate functionality to the parent constructor.
+ */
+ public BigEndianOutputStream(OutputStream out)
+ {
+ super(out);
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/CDR/LittleEndianInputStream.java b/libjava/classpath/gnu/CORBA/CDR/LittleEndianInputStream.java
new file mode 100644
index 0000000..b71a9a4
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/LittleEndianInputStream.java
@@ -0,0 +1,633 @@
+/* LittleEndianInputStream.java --
+ Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation
+
+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 gnu.CORBA.CDR;
+
+import java.io.DataInput;
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+
+/**
+ * This class reads data in the Little Endian format. It reuses
+ * code from GNU Classpath DataInputStream.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class LittleEndianInputStream
+ extends FilterInputStream
+ implements abstractDataInputStream
+{
+ // Byte buffer, used to make primitive read calls more efficient.
+ byte[] buf = new byte[ 8 ];
+
+ /**
+ * This constructor initializes a new DataInputStream
+ * to read from the specified subordinate stream.
+ *
+ * @param in The subordinate InputStream
to read from
+ */
+ public LittleEndianInputStream(InputStream in)
+ {
+ super(in);
+ }
+
+ /**
+ * This method reads bytes from the underlying stream into the specified
+ * byte array buffer. It will attempt to fill the buffer completely, but
+ * may return a short count if there is insufficient data remaining to be
+ * read to fill the buffer.
+ *
+ * @param b The buffer into which bytes will be read.
+ *
+ * @return The actual number of bytes read, or -1 if end of stream reached
+ * before reading any bytes.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read(byte[] b)
+ throws IOException
+ {
+ return in.read(b, 0, b.length);
+ }
+
+ /**
+ * This method reads bytes from the underlying stream into the specified
+ * byte array buffer. It will attempt to read len
bytes and
+ * will start storing them at position off
into the buffer.
+ * This method can return a short count if there is insufficient data
+ * remaining to be read to complete the desired read length.
+ *
+ * @param b The buffer into which bytes will be read.
+ * @param off The offset into the buffer to start storing bytes.
+ * @param len The requested number of bytes to read.
+ *
+ * @return The actual number of bytes read, or -1 if end of stream reached
+ * before reading any bytes.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read(byte[] b, int off, int len)
+ throws IOException
+ {
+ return in.read(b, off, len);
+ }
+
+ /**
+ * This method reads a Java boolean value from an input stream. It does
+ * so by reading a single byte of data. If that byte is zero, then the
+ * value returned is false
. If the byte is non-zero, then
+ * the value returned is true
.
+ * boolean
written by an object
+ * implementing the writeBoolean()
method in the
+ * DataOutput
interface.
+ *
+ * @return The boolean
value read
+ *
+ * @exception EOFException If end of file is reached before reading
+ * the boolean
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeBoolean
+ */
+ public boolean readBoolean()
+ throws IOException
+ {
+ return convertToBoolean(in.read());
+ }
+
+ /**
+ * This method reads a Java byte value from an input stream. The value
+ * is in the range of -128 to 127.
+ * byte
written by an object
+ * implementing the writeByte()
method in the
+ * DataOutput
interface.
+ *
+ * @return The byte
value read
+ *
+ * @exception EOFException If end of file is reached before reading the byte
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeByte
+ */
+ public byte readByte()
+ throws IOException
+ {
+ return convertToByte(in.read());
+ }
+
+ /**
+ * This method reads a Java char
value from an input stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single 16-bit Java char
. The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * byte1
and byte2
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to a char
in
+ * the following manner:
+ * (char)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF)
+ * char
written by an object
+ * implementing the writeChar()
method in the
+ * DataOutput
interface.
+ *
+ * @return The char
value read
+ *
+ * @exception EOFException If end of file is reached before reading the char
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeChar
+ */
+ public char readChar()
+ throws IOException
+ {
+ readFully(buf, 0, 2);
+ return convertToChar(buf);
+ }
+
+ /**
+ * This method reads a Java double value from an input stream. It operates
+ * by first reading a long
value from the stream by calling the
+ * readLong()
method in this interface, then converts
+ * that long
to a double
using the
+ * longBitsToDouble
method in the class
+ * java.lang.Double
+ * double
written by an object
+ * implementing the writeDouble()
method in the
+ * DataOutput
interface.
+ *
+ * @return The double
value read
+ *
+ * @exception EOFException If end of file is reached before reading
+ * the double
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeDouble
+ * @see java.lang.Double#longBitsToDouble
+ */
+ public double readDouble()
+ throws IOException
+ {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ /**
+ * This method reads a Java float value from an input stream. It
+ * operates by first reading an int
value from the
+ * stream by calling the readInt()
method in this
+ * interface, then converts that int
to a
+ * float
using the intBitsToFloat
method
+ * in the class java.lang.Float
+ * float
written by an object
+ * implementing the writeFloat()
method in the
+ * DataOutput
interface.
+ *
+ * @return The float
value read
+ *
+ * @exception EOFException If end of file is reached before reading the float
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeFloat
+ * @see java.lang.Float#intBitsToFloat
+ */
+ public float readFloat()
+ throws IOException
+ {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ /**
+ * This method reads raw bytes into the passed array until the array is
+ * full. Note that this method blocks until the data is available and
+ * throws an exception if there is not enough data left in the stream to
+ * fill the buffer. Note also that zero length buffers are permitted.
+ * In this case, the method will return immediately without reading any
+ * bytes from the stream.
+ *
+ * @param b The buffer into which to read the data
+ *
+ * @exception EOFException If end of file is reached before filling the
+ * buffer
+ * @exception IOException If any other error occurs
+ */
+ public void readFully(byte[] b)
+ throws IOException
+ {
+ readFully(b, 0, b.length);
+ }
+
+ /**
+ * This method reads raw bytes into the passed array buf
+ * starting
+ * offset
bytes into the buffer. The number of bytes read
+ * will be
+ * exactly len
. Note that this method blocks until the data is
+ * available and throws an exception if there is not enough data left in
+ * the stream to read len
bytes. Note also that zero length
+ * buffers are permitted. In this case, the method will return immediately
+ * without reading any bytes from the stream.
+ *
+ * @param buf The buffer into which to read the data
+ * @param offset The offset into the buffer to start storing data
+ * @param len The number of bytes to read into the buffer
+ *
+ * @exception EOFException If end of file is reached before filling the
+ * buffer
+ * @exception IOException If any other error occurs
+ */
+ public void readFully(byte[] buf, int offset, int len)
+ throws IOException
+ {
+ if (len < 0)
+ throw new IndexOutOfBoundsException("Negative length: " + len);
+
+ while (len > 0)
+ {
+ // in.read will block until some data is available.
+ int numread = in.read(buf, offset, len);
+ if (numread < 0)
+ throw new EOFException();
+ len -= numread;
+ offset += numread;
+ }
+ }
+
+ /**
+ * This method reads a Java int
value from an input stream
+ * It operates by reading four bytes from the stream and converting them to
+ * a single Java int
. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * byte1
through byte4
represent
+ * the first four bytes read from the stream, they will be
+ * transformed to an int
in the following manner:
+ * (int)(((byte1 & 0xFF) << 24) + ((byte2 & 0xFF) << 16) +
+ * ((byte3 & 0xFF)<< 8) + (byte4 & 0xFF)))
+ * int
written by an object
+ * implementing the writeInt()
method in the
+ * DataOutput
interface.
+ *
+ * @return The int
value read
+ *
+ * @exception EOFException If end of file is reached before reading the int
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeInt
+ */
+ public int readInt()
+ throws IOException
+ {
+ readFully(buf, 0, 4);
+ return convertToInt(buf);
+ }
+
+ /**
+ * This method reads the next line of text data from an input
+ * stream. It operates by reading bytes and converting those bytes
+ * to char
values by treating the byte read as the low
+ * eight bits of the char
and using 0 as the high eight
+ * bits. Because of this, it does not support the full 16-bit
+ * Unicode character set.
+ * String
A line terminator is a byte sequence
+ * consisting of either \r
, \n
or
+ * \r\n
. These termination charaters are discarded and
+ * are not returned as part of the string.
+ * writeLine()
method in DataOutput
.
+ *
+ * @return The line read as a String
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataOutput
+ *
+ * @deprecated
+ */
+ public String readLine()
+ throws IOException
+ {
+ StringBuffer strb = new StringBuffer();
+
+ while (true)
+ {
+ int c = in.read();
+ if (c == -1) // got an EOF
+ return strb.length() > 0 ? strb.toString() : null;
+ if (c == '\r')
+ {
+ int next_c = in.read();
+ if (next_c != '\n' && next_c != -1)
+ {
+ if (!(in instanceof PushbackInputStream))
+ in = new PushbackInputStream(in);
+ ((PushbackInputStream) in).unread(next_c);
+ }
+ break;
+ }
+ if (c == '\n')
+ break;
+ strb.append((char) c);
+ }
+
+ return strb.length() > 0 ? strb.toString() : "";
+ }
+
+ /**
+ * This method reads a Java long
value from an input stream
+ * It operates by reading eight bytes from the stream and converting them to
+ * a single Java long
. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * byte1
through byte8
represent
+ * the first eight bytes read from the stream, they will be
+ * transformed to an long
in the following manner:
+ * (long)(((byte1 & 0xFF) << 56) + ((byte2 & 0xFF) << 48) +
+ * ((byte3 & 0xFF) << 40) + ((byte4 & 0xFF) << 32) +
+ * ((byte5 & 0xFF) << 24) + ((byte6 & 0xFF) << 16) +
+ * ((byte7 & 0xFF) << 8) + (byte8 & 0xFF)))
+ *
+ * long
written by an object
+ * implementing the writeLong()
method in the
+ * DataOutput
interface.
+ *
+ * @return The long
value read
+ *
+ * @exception EOFException If end of file is reached before reading the long
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeLong
+ */
+ public long readLong()
+ throws IOException
+ {
+ readFully(buf, 0, 8);
+ return convertToLong(buf);
+ }
+
+ /**
+ * This method reads a signed 16-bit value into a Java in from the
+ * stream. It operates by reading two bytes from the stream and
+ * converting them to a single 16-bit Java short
. The
+ * two bytes are stored most significant byte first (i.e., "big
+ * endian") regardless of the native host byte ordering.
+ * byte1
and byte2
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to a short
. in
+ * the following manner:
+ * (short)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF))
+ * short
written by an object
+ * implementing the writeShort()
method in the
+ * DataOutput
interface.
+ *
+ * @return The short
value read
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeShort
+ */
+ public short readShort()
+ throws IOException
+ {
+ readFully(buf, 0, 2);
+ return convertToShort(buf);
+ }
+
+ /**
+ * This method reads 8 unsigned bits into a Java int
+ * value from the stream. The value returned is in the range of 0 to
+ * 255.
+ * writeUnsignedByte()
method in the
+ * DataOutput
interface.
+ *
+ * @return The unsigned bytes value read as a Java int
.
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeByte
+ */
+ public int readUnsignedByte()
+ throws IOException
+ {
+ return convertToUnsignedByte(in.read());
+ }
+
+ /**
+ * This method reads 16 unsigned bits into a Java int value from the stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single Java int
The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * byte1
and byte2
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to an int
in
+ * the following manner:
+ * (int)(((byte1 & 0xFF) << 8) + (byte2 & 0xFF))
+ * writeUnsignedShort()
method in the
+ * DataOutput
interface.
+ *
+ * @return The unsigned short value read as a Java int
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeShort
+ */
+ public int readUnsignedShort()
+ throws IOException
+ {
+ readFully(buf, 0, 2);
+ return convertToUnsignedShort(buf);
+ }
+
+ /**
+ * This method attempts to skip and discard the specified number of bytes
+ * in the input stream. It may actually skip fewer bytes than requested.
+ * This method will not skip any bytes if passed a negative number of bytes
+ * to skip.
+ *
+ * @param n The requested number of bytes to skip.
+ *
+ * @return The requested number of bytes to skip.
+ *
+ * @exception IOException If an error occurs.
+ * @specnote The JDK docs claim that this returns the number of bytes
+ * actually skipped. The JCL claims that this method can throw an
+ * EOFException. Neither of these appear to be true in the JDK 1.3's
+ * implementation. This tries to implement the actual JDK behaviour.
+ */
+ public int skipBytes(int n)
+ throws IOException
+ {
+ if (n <= 0)
+ return 0;
+ try
+ {
+ return (int) in.skip(n);
+ }
+ catch (EOFException x)
+ {
+ // do nothing.
+ }
+ return n;
+ }
+
+ protected boolean convertToBoolean(int b)
+ throws EOFException
+ {
+ if (b < 0)
+ throw new EOFException();
+
+ return (b != 0);
+ }
+
+ protected byte convertToByte(int i)
+ throws EOFException
+ {
+ if (i < 0)
+ throw new EOFException();
+
+ return (byte) i;
+ }
+
+ protected int convertToUnsignedByte(int i)
+ throws EOFException
+ {
+ if (i < 0)
+ throw new EOFException();
+
+ return (i & 0xFF);
+ }
+
+ /**
+ * Less significant byte first.
+ */
+ protected char convertToChar(byte[] buf)
+ {
+ return (char) ((buf [ 1 ] << 8) | (buf [ 0 ] & 0xff));
+ }
+
+ /**
+ * Less significant byte first.
+ */
+ protected short convertToShort(byte[] buf)
+ {
+ return (short) ((buf [ 1 ] << 8) | (buf [ 0 ] & 0xff));
+ }
+
+ /**
+ * Less significant byte first.
+ */
+ protected int convertToUnsignedShort(byte[] buf)
+ {
+ return (((buf [ 1 ] & 0xff) << 8) | (buf [ 0 ] & 0xff));
+ }
+
+ /**
+ * Less significant byte first.
+ */
+ protected int convertToInt(byte[] buf)
+ {
+ return (((buf [ 3 ] & 0xff) << 24) | ((buf [ 2 ] & 0xff) << 16) |
+ ((buf [ 1 ] & 0xff) << 8) | (buf [ 0 ] & 0xff));
+ }
+
+ /**
+ * Less significant byte first.
+ */
+ protected long convertToLong(byte[] buf)
+ {
+ return (((long) (buf [ 7 ] & 0xff) << 56) |
+ ((long) (buf [ 6 ] & 0xff) << 48) |
+ ((long) (buf [ 5 ] & 0xff) << 40) |
+ ((long) (buf [ 4 ] & 0xff) << 32) |
+ ((long) (buf [ 3 ] & 0xff) << 24) |
+ ((long) (buf [ 2 ] & 0xff) << 16) |
+ ((long) (buf [ 1 ] & 0xff) << 8) | ((long) (buf [ 0 ] & 0xff)));
+ }
+
+ /**
+ * This should never be called.
+ *
+ * @throws InternalError, always.
+ */
+ public String readUTF()
+ {
+ throw new InternalError();
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/CDR/LittleEndianOutputStream.java b/libjava/classpath/gnu/CORBA/CDR/LittleEndianOutputStream.java
new file mode 100644
index 0000000..a6d56cf
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/LittleEndianOutputStream.java
@@ -0,0 +1,253 @@
+/* LittleEndianOutputStream.java --
+ Copyright (C) 1998, 2001, 2003, 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 gnu.CORBA.CDR;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * This stream writes data in the Little Endian format
+ * (less significant byte first). This is opposite to the
+ * usual data presentation in java platform.
+ *
+ * This class reuses code from DataOutputStream.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ */
+public class LittleEndianOutputStream
+ extends FilterOutputStream
+ implements abstractDataOutputStream
+{
+ /**
+ * This method initializes an instance of DataOutputStream
to
+ * write its data to the specified underlying OutputStream
+ *
+ * @param out The subordinate OutputStream
to which this
+ * object will write
+ */
+ public LittleEndianOutputStream(OutputStream out)
+ {
+ super(out);
+ }
+
+ /**
+ * This method flushes any unwritten bytes to the underlying stream.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public void flush()
+ throws IOException
+ {
+ out.flush();
+ }
+
+ /**
+ * This method writes the specified byte (passed as an int
)
+ * to the underlying output stream.
+ *
+ * @param value The byte
to write, passed as an int
.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public synchronized void write(int value)
+ throws IOException
+ {
+ out.write(value);
+ }
+
+ /**
+ * This method writes len
bytes from the specified byte array
+ * buf
starting at position offset
into the
+ * buffer to the underlying output stream.
+ *
+ * @param buf The byte array to write from.
+ * @param offset The index into the byte array to start writing from.
+ * @param len The number of bytes to write.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public synchronized void write(byte[] buf, int offset, int len)
+ throws IOException
+ {
+ out.write(buf, offset, len);
+ }
+
+ /**
+ * This method writes a Java boolean value to an output stream. If
+ * value
is true
, a byte with the value of
+ * 1 will be written, otherwise a byte with the value of 0 will be
+ * written.
+ *
+ * The value written can be read using the readBoolean
+ * method in DataInput
.
+ *
+ * @param value The boolean
value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readBoolean
+ */
+ public void writeBoolean(boolean value)
+ throws IOException
+ {
+ write(value ? 1 : 0);
+ }
+
+ /**
+ * This method writes a Java byte value to an output stream. The
+ * byte to be written will be in the lowest 8 bits of the
+ * int
value passed.
+ *
+ * The value written can be read using the readByte
or
+ * readUnsignedByte
methods in DataInput
.
+ *
+ * @param value The byte
to write to the stream, passed as
+ * the low eight bits of an int
.
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readByte
+ * @see DataInput#readUnsignedByte
+ */
+ public void writeByte(int value)
+ throws IOException
+ {
+ write(value & 0xff);
+ }
+
+ /**
+ * This method writes a Java short value to an output stream.
+ *
+ * @param value The short
value to write to the stream,
+ * passed as an int
.
+ *
+ * @exception IOException If an error occurs
+ */
+ public synchronized void writeShort(int value)
+ throws IOException
+ {
+ write((byte) (0xff & value));
+ write((byte) (0xff & (value >> 8)));
+ }
+
+ /**
+ * Writes char in Little Endian.
+ */
+ public synchronized void writeChar(int value)
+ throws IOException
+ {
+ write((byte) (0xff & value));
+ write((byte) (0xff & (value >> 8)));
+ }
+
+ /**
+ * Writes int in Little Endian.
+ */
+ public synchronized void writeInt(int value)
+ throws IOException
+ {
+ write((byte) (0xff & value));
+ write((byte) (0xff & (value >> 8)));
+ write((byte) (0xff & (value >> 16)));
+ write((byte) (0xff & (value >> 24)));
+ }
+
+ /**
+ * Writes long in Little Endian.
+ */
+ public synchronized void writeLong(long value)
+ throws IOException
+ {
+ write((byte) (0xff & value));
+ write((byte) (0xff & (value >> 8)));
+ write((byte) (0xff & (value >> 16)));
+ write((byte) (0xff & (value >> 24)));
+ write((byte) (0xff & (value >> 32)));
+ write((byte) (0xff & (value >> 40)));
+ write((byte) (0xff & (value >> 48)));
+ write((byte) (0xff & (value >> 56)));
+ }
+
+ /**
+ * This method writes a Java float
value to the stream. This
+ * value is written by first calling the method
+ * Float.floatToIntBits
+ * to retrieve an int
representing the floating point number,
+ * then writing this int
value to the stream exactly the same
+ * as the writeInt()
method does.
+ *
+ * @param value The float
value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see writeInt
+ * @see DataInput#readFloat
+ * @see Float#floatToIntBits
+ */
+ public void writeFloat(float value)
+ throws IOException
+ {
+ writeInt(Float.floatToIntBits(value));
+ }
+
+ /**
+ * This method writes a Java double
value to the stream. This
+ * value is written by first calling the method
+ * Double.doubleToLongBits
+ * to retrieve an long
representing the floating point number,
+ * then writing this long
value to the stream exactly the same
+ * as the writeLong()
method does.
+ *
+ * @param value The double
value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see writeLong
+ * @see DataInput#readDouble
+ * @see Double#doubleToLongBits
+ */
+ public void writeDouble(double value)
+ throws IOException
+ {
+ writeLong(Double.doubleToLongBits(value));
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/CDR/Vio.java b/libjava/classpath/gnu/CORBA/CDR/Vio.java
new file mode 100644
index 0000000..8f17bd2
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/Vio.java
@@ -0,0 +1,638 @@
+/* gnuValueBaseHelper.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+import gnu.CORBA.ObjectCreator;
+
+import org.omg.CORBA.CustomMarshal;
+import org.omg.CORBA.DataInputStream;
+import org.omg.CORBA.DataOutputStream;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.NO_IMPLEMENT;
+import org.omg.CORBA.StringSeqHelper;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.Streamable;
+import org.omg.CORBA.portable.ValueFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * A specialised class for reading and writing the value types.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public abstract class Vio
+{
+ /**
+ * If true, wrap value type data into chunks. This decrease the
+ * performance, but is required for the interoperability with
+ * Sun's CORBA implementation. Chunking may increase the security,
+ * as there is more control on the number of bytes being transferred.
+ *
+ * The current implementation would accept both single chunk or multiple
+ * chunks, but will always send a single chunk.
+ */
+ public static boolean USE_CHUNKING = true;
+
+ /**
+ * The first field in the value record. The last octet may contain
+ * additional flags (vf_CODEBASE, vf_ID and vf_MULTIPLE_IDS). The tag
+ * value is different for the indirections (vt_INDIRECTION) and
+ * nulls (vt_NULL).
+ */
+ public static final int vt_VALUE_TAG = 0x7fffff00;
+
+ /**
+ * The value tag flag, indicating that the codebase URL is present
+ * in the value tag record.
+ */
+ public static final int vf_CODEBASE = 0x1;
+
+ /**
+ * The value tag flag, indicating that a single repository id is present
+ * in the value tag record.
+ */
+ public static final int vf_ID = 0x2;
+
+ /**
+ * The value tag flag, indicating, that there are multiple repository
+ * ids present in the record. If this flag is set, the flag vf_ID must
+ * also be set, resulting the value of the least significant byte 0x6.
+ */
+ public static final int vf_MULTIPLE_IDS = 0x4;
+
+ /**
+ * The value tag flag, indicating the presence of chunking. Each chunk is
+ * preceeded by a positive int, indicating the number of bytes in the chunk.
+ * A sequence of chunks is terminated by a non positive int.
+ */
+ public static final int vf_CHUNKING = 0x8;
+
+ /**
+ * The indirection tag value. Such tag must be followed by the CORBA long,
+ * indicating the offset in the CORBA message, where the indirected
+ * information is present. This offset is assumed zero at the position
+ * where the mentioned CORBA long starts and can refer both forward
+ * (positive values) and backward (negative values).
+ */
+ public static final int vt_INDIRECTION = 0xffffffff;
+
+ /**
+ * This tag value means that the value object being transferred is equal
+ * to null.
+ */
+ public static final int vt_NULL = 0x0;
+
+ /**
+ * Read the value base from the given input stream. Determines the
+ * required class from the repository id. This includes operations
+ * that are not required when an unitialised instance or at least
+ * class of the value type is known. Hence it may be faster to use
+ * the alternative methods, read(InputStream, Class) or
+ * read(InputStream, Serializable).
+ *
+ * @param input a stream to read from.
+ *
+ * @return the loaded value.
+ *
+ * @throws MARSHAL if the reading has failed due any reason.
+ */
+ public static Serializable read(InputStream input)
+ {
+ // Explicitly prevent the stream from closing as we may need
+ // to read the subsequent bytes as well. Stream may be auto-closed
+ // in its finalizer.
+ try
+ {
+ // We may need to jump back if the value is read via value factory.
+ input.mark(512);
+
+ int value_tag = input.read_long();
+ checkTag(value_tag);
+
+ String codebase = null;
+ String[] ids = null;
+ String id = null;
+
+ // The existing implementing object.
+ java.lang.Object ox = null;
+
+ // Check for the agreed null value.
+ if (value_tag == vt_NULL)
+ return null;
+ else if (value_tag == vt_INDIRECTION)
+
+ // TODO FIXME Implement support for indirections.
+ throw new NO_IMPLEMENT("Indirections unsupported");
+ else
+ {
+ // Read the value.
+ if ((value_tag & vf_CODEBASE) != 0)
+ {
+ // The codebase is present. The codebase is a space
+ // separated list of URLs from where the implementing
+ // code can be downloaded.
+ codebase = input.read_string();
+ }
+
+ if ((value_tag & vf_MULTIPLE_IDS) != 0)
+ {
+ // Multiple supported repository ids are present.
+ ids = StringSeqHelper.read(input);
+ for (int i = 0; (i < ids.length) && (ox == null); i++)
+ {
+ ox = ObjectCreator.Idl2Object(ids [ i ]);
+
+ if (ox == null)
+ {
+ // Try to find the value factory.
+ ValueFactory f =
+ ((org.omg.CORBA_2_3.ORB) input.orb()).lookup_value_factory(ids [ i ]);
+
+ if (f != null)
+ {
+ // Reset, as the value factory reads from beginning.
+ input.reset();
+ return f.read_value((org.omg.CORBA_2_3.portable.InputStream) input);
+ }
+ }
+ }
+ }
+ else if ((value_tag & vf_ID) != 0)
+ {
+ // Single supported repository id is present.
+ id = input.read_string();
+ ox = ObjectCreator.Idl2Object(id);
+
+ if (ox == null)
+ {
+ // Try to find the value factory.
+ ValueFactory f =
+ ((org.omg.CORBA_2_3.ORB) input.orb()).lookup_value_factory(id);
+
+ if (f != null)
+ {
+ input.reset();
+ return f.read_value((org.omg.CORBA_2_3.portable.InputStream) input);
+ }
+ }
+ }
+ }
+
+ if (ox == null)
+ throw new MARSHAL("Unable to instantiate the value type");
+ else
+ {
+ read_instance(input, ox, value_tag);
+ return (Serializable) ox;
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new MARSHAL(ex + ":" + ex.getMessage());
+ }
+ }
+
+ /**
+ * Read the value base from the given input stream when
+ * the value base class is available. Hence there is no need
+ * to guess it from the repository id.
+ *
+ * @param input a stream to read from.
+ * @param value_class the class of the value being read.
+ *
+ * @return the loaded value.
+ *
+ * @throws MARSHAL if the reading has failed due any reason.
+ */
+ public static Serializable read(InputStream input, Class value_class)
+ {
+ // Explicitly prevent the stream from closing as we may need
+ // to read the subsequent bytes as well. Stream may be auto-closed
+ // in its finalizer.
+ try
+ {
+ int value_tag = input.read_long();
+ checkTag(value_tag);
+
+ // The existing implementing object.
+ java.lang.Object ox = value_class.newInstance();
+
+ // Check for the agreed null value.
+ if (value_tag == vt_NULL)
+ return null;
+ else if (value_tag == vt_INDIRECTION)
+
+ // TODO FIXME Implement support for indirections.
+ throw new NO_IMPLEMENT("Indirections unsupported");
+ else
+ {
+ // Read the value.
+ if ((value_tag & vf_CODEBASE) != 0)
+ {
+ // The codebase is present, but skip it.
+ input.read_string();
+ }
+
+ if ((value_tag & vf_MULTIPLE_IDS) != 0)
+ {
+ // Multiple supported repository ids are present, but skip them.
+ StringSeqHelper.read(input);
+ }
+ else if ((value_tag & vf_ID) != 0)
+ {
+ // Single supported repository id is present, but skip it.
+ input.read_string();
+ }
+ }
+
+ read_instance(input, ox, value_tag);
+ return (Serializable) ox;
+ }
+ catch (Exception ex)
+ {
+ throw new MARSHAL(ex + ":" + ex.getMessage());
+ }
+ }
+
+ /**
+ * Read the value base from the given input stream when
+ * the unitialised instance is available. Hence there is no need
+ * to guess the class from the repository id and then to instantiate
+ * an instance.
+ *
+ * @param input a stream to read from.
+ * @param value_instance an instance of the value.
+ *
+ * @return the loaded value.
+ *
+ * @throws MARSHAL if the reading has failed due any reason.
+ */
+ public static Serializable read(InputStream input, Serializable value_instance)
+ {
+ // Explicitly prevent the stream from closing as we may need
+ // to read the subsequent bytes as well. Stream may be auto-closed
+ // in its finalizer.
+ try
+ {
+ int value_tag = input.read_long();
+ checkTag(value_tag);
+
+ // Check for the agreed null value.
+ if (value_tag == vt_NULL)
+ return null;
+ else if (value_tag == vt_INDIRECTION)
+
+ // TODO FIXME Implement support for indirections.
+ throw new NO_IMPLEMENT("Indirections unsupported");
+ else
+ {
+ // Read the value.
+ if ((value_tag & vf_CODEBASE) != 0)
+ {
+ // The codebase is present, but skip it.
+ input.read_string();
+ }
+
+ if ((value_tag & vf_MULTIPLE_IDS) != 0)
+ {
+ // Multiple supported repository ids are present, but skip them.
+ StringSeqHelper.read(input);
+ }
+ else if ((value_tag & vf_ID) != 0)
+ {
+ // Single supported repository id is present, but skip it.
+ input.read_string();
+ }
+ }
+
+ read_instance(input, value_instance, value_tag);
+ return (Serializable) value_instance;
+ }
+ catch (Exception ex)
+ {
+ throw new MARSHAL(ex + ":" + ex.getMessage());
+ }
+ }
+
+ /**
+ * Fill in the instance fields by the data from the input stream.
+ * The method assumes that the value header, if any, is already
+ * behind. The information from the stream is stored into the
+ * passed ox parameter.
+ *
+ * @param input an input stream to read from.
+ * @param value a value type object, must be either Streamable or
+ * CustomMarshal.
+ */
+ public static void read_instance(InputStream input, Object value,
+ int value_tag
+ )
+ {
+ try
+ {
+ if ((value_tag & vf_CHUNKING) != 0)
+ {
+ ByteArrayOutputStream bout = null;
+ int n = -1;
+
+ // Read all chunks.
+ int chunk_size = input.read_long();
+ if (chunk_size <= 0)
+ throw new MARSHAL("Invalid first chunk size " + chunk_size);
+
+ byte[] r = new byte[ chunk_size ];
+
+ while (chunk_size > 0)
+ {
+ if (r.length < chunk_size)
+ r = new byte[ chunk_size + 256 ];
+
+ n = 0;
+ reading:
+ while (n < chunk_size)
+ n += input.read(r, n, r.length - n);
+
+ // Read the size of the next chunk.
+ chunk_size = input.read_long();
+
+ // If the value is non negative, there is more than one chunk.
+ // Accumulate chunks in the buffer.
+ // The last chunk (or the only chunk, if only one chunk is
+ // present) is not written in the buffer. It is stored in the
+ // array r, avoiding unnecessary buffer operations.
+ if (chunk_size > 0)
+ {
+ bout = new ByteArrayOutputStream(2 * chunk_size);
+ bout.write(r, 0, chunk_size);
+ }
+ }
+
+ if (bout != null)
+ {
+ // More than one chunk was present.
+ // Add the last chunk.
+ bout.write(r, 0, n);
+ input = new cdrBufInput(bout.toByteArray());
+ }
+ else
+ {
+ // Only one chunk was present.
+ input = new cdrBufInput(r);
+ }
+ }
+ }
+ catch (IOException ex)
+ {
+ MARSHAL m = new MARSHAL("Unable to read chunks");
+ m.initCause(ex);
+ throw m;
+ }
+
+ // The user-defines io operations are implemented.
+ if (value instanceof CustomMarshal)
+ {
+ CustomMarshal marsh = (CustomMarshal) value;
+ try
+ {
+ marsh.unmarshal((DataInputStream) input);
+ }
+ catch (ClassCastException ex)
+ {
+ incorrect_plug_in(ex);
+ }
+ }
+ else
+ // The IDL-generated io operations are implemented.
+ if (value instanceof Streamable)
+ {
+ ((Streamable) value)._read(input);
+ }
+ else
+
+ // Stating the interfaces that the USER should use.
+ throw new MARSHAL("The " + value.getClass().getName() +
+ " must implement either StreamableValue or CustomValue."
+ );
+
+ // The negative end of state marker is expected from OMG standard.
+ // If the chunking is used, this marker is already extracted.
+ if ((value_tag & vf_CHUNKING) == 0)
+ {
+ int eor = input.read_long();
+ if (eor >= 0)
+ throw new MARSHAL("End of state marker has an invalid value " + eor);
+ }
+ }
+
+ /**
+ * Write the value base into the given stream.
+ *
+ * @param output a stream to write to.
+ *
+ * @param value a value type object, must be either Streamable or
+ * CustomMarshal.
+ *
+ * @throws MARSHAL if the writing failed due any reason.
+ */
+ public static void write(OutputStream output, Serializable value)
+ {
+ // Write null if this is a null value.
+ if (value == null)
+ output.write_long(vt_NULL);
+ else
+ write(output, value, ObjectCreator.toIDL(value.getClass().getName()));
+ }
+
+ /**
+ * Write the value base into the given stream, stating that it is an
+ * instance of the given class. The written record has no repository
+ * id and requires to supply a class or initialised instance for reading
+ * rather than an actual class it is.
+ *
+ * This results writing a different repository id.
+ *
+ * If the passed value implements the {@link CustomMarshal},
+ * the helper uses {@link CustomMarshal#marshal}
+ * to write the content in a user defined way. Otherwise,
+ * this implementation initialises the {@link ObjectOutputStream}
+ * and writes through it.
+ *
+ * @param output a stream to write to.
+ *
+ * @param value a value to write.
+ *
+ * @throws MARSHAL if the writing failed due any reason.
+ */
+ public static void write(OutputStream output, Serializable value,
+ Class substitute
+ )
+ {
+ // Write null if this is a null value.
+ if (value == null)
+ output.write_long(vt_NULL);
+
+ else
+ write(output, value, ObjectCreator.toIDL(substitute.getName()));
+ }
+
+ /**
+ * Write value when its repository Id is explicitly given.
+ *
+ * @param output an output stream to write into.
+ * @param value a value to write.
+ * @param id a value repository id.
+ */
+ public static void write(OutputStream output, Serializable value, String id)
+ {
+ if (value == null)
+ output.write_long(vt_NULL);
+ else
+ write_instance(output, value, id);
+ }
+
+ /**
+ * Write value when its repository Id is explicitly given.
+ * Does not handle null.
+ *
+ * @param output an output stream to write into.
+ * @param value a value to write.
+ * @param id a value repository id.
+ */
+ private static void write_instance(OutputStream output, Serializable value,
+ String id
+ )
+ {
+ // This implementation always writes a single repository id.
+ // It never writes multiple repository ids and currently does not use
+ // a codebase.
+ int value_tag = vt_VALUE_TAG | vf_ID;
+
+ OutputStream outObj;
+ cdrBufOutput out = null;
+
+ if (USE_CHUNKING)
+ {
+ out = new cdrBufOutput();
+ out.setOrb(output.orb());
+ outObj = out;
+ value_tag |= vf_CHUNKING;
+ }
+ else
+ outObj = output;
+
+ output.write_long(value_tag);
+ output.write_string(id);
+
+ // User defince write method is present.
+ if (value instanceof CustomMarshal)
+ {
+ try
+ {
+ ((CustomMarshal) value).marshal((DataOutputStream) outObj);
+ }
+ catch (ClassCastException ex)
+ {
+ incorrect_plug_in(ex);
+ }
+ }
+ else if (value instanceof Streamable)
+ {
+ ((Streamable) value)._write(outObj);
+ }
+ else
+
+ // Stating the interfaces that the USER should use.
+ throw new MARSHAL("The " + value.getClass().getName() +
+ " must implement either StreamableValue or CustomValue."
+ );
+
+ if (USE_CHUNKING)
+ {
+ output.write_long(out.buffer.size());
+ try
+ {
+ out.buffer.writeTo(output);
+ }
+ catch (IOException ex)
+ {
+ MARSHAL m = new MARSHAL();
+ m.initCause(ex);
+ throw m;
+ }
+ }
+
+ // The end of record marker, required by OMG standard.
+ output.write_long(-1);
+ }
+
+ /**
+ * This can be called if the alternative CORBA implementation
+ * is incorrectly plugged in.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ private static void incorrect_plug_in(Throwable ex)
+ throws NO_IMPLEMENT
+ {
+ NO_IMPLEMENT no = new NO_IMPLEMENT("Incorrect CORBA plug-in");
+ no.initCause(ex);
+ throw no;
+ }
+
+ /**
+ * Check the passed value tag for correctness.
+ *
+ * @param value_tag a tag to check, must be between 0x7fffff00 and 0x7fffffff
+ *
+ * @throws MARSHAL if the tag is outside this interval.
+ */
+ private static final void checkTag(int value_tag)
+ {
+ if ((value_tag < 0x7fffff00 || value_tag > 0x7fffffff) &&
+ value_tag != vt_NULL && value_tag != vt_INDIRECTION
+ )
+ throw new MARSHAL("Invalid value record, unsupported header tag: " +
+ value_tag
+ );
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/CDR/abstractDataInputStream.java b/libjava/classpath/gnu/CORBA/CDR/abstractDataInputStream.java
new file mode 100644
index 0000000..be92625
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/abstractDataInputStream.java
@@ -0,0 +1,392 @@
+/* abstractDataInputStream.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+import java.io.IOException;
+
+/**
+ * Some data input stream that can be either Big or
+ * Little Endian.
+ *
+ * This class reuses code from GNU Classpath DataInputStream.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public interface abstractDataInputStream
+{
+ /**
+ * This method reads bytes from the underlying stream into the specified
+ * byte array buffer. It will attempt to fill the buffer completely, but
+ * may return a short count if there is insufficient data remaining to be
+ * read to fill the buffer.
+ *
+ * @param b The buffer into which bytes will be read.
+ *
+ * @return The actual number of bytes read, or -1 if end of stream reached
+ * before reading any bytes.
+ *
+ * @exception IOException If an error occurs.
+ */
+ int read(byte[] b)
+ throws IOException;
+
+ /**
+ * This method reads bytes from the underlying stream into the specified
+ * byte array buffer. It will attempt to read len
bytes and
+ * will start storing them at position off
into the buffer.
+ * This method can return a short count if there is insufficient data
+ * remaining to be read to complete the desired read length.
+ *
+ * @param b The buffer into which bytes will be read.
+ * @param off The offset into the buffer to start storing bytes.
+ * @param len The requested number of bytes to read.
+ *
+ * @return The actual number of bytes read, or -1 if end of stream reached
+ * before reading any bytes.
+ *
+ * @exception IOException If an error occurs.
+ */
+ int read(byte[] b, int off, int len)
+ throws IOException;
+
+ /**
+ * This method reads a Java boolean value from an input stream. It does
+ * so by reading a single byte of data. If that byte is zero, then the
+ * value returned is false
. If the byte is non-zero, then
+ * the value returned is true
.
+ * boolean
written by an object
+ * implementing the writeBoolean()
method in the
+ * DataOutput
interface.
+ *
+ * @return The boolean
value read
+ *
+ * @exception EOFException If end of file is reached before reading
+ * the boolean
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeBoolean
+ */
+ boolean readBoolean()
+ throws IOException;
+
+ /**
+ * This method reads a Java byte value from an input stream. The value
+ * is in the range of -128 to 127.
+ * byte
written by an object
+ * implementing the writeByte()
method in the
+ * DataOutput
interface.
+ *
+ * @return The byte
value read
+ *
+ * @exception EOFException If end of file is reached before reading the byte
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeByte
+ */
+ byte readByte()
+ throws IOException;
+
+ /**
+ * This method reads a Java char
value from an input stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single 16-bit Java char
. The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * byte1
and byte2
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to a char
in
+ * the following manner:
+ * (char)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF)
+ * char
written by an object
+ * implementing the writeChar()
method in the
+ * DataOutput
interface.
+ *
+ * @return The char
value read
+ *
+ * @exception EOFException If end of file is reached before reading the char
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeChar
+ */
+ char readChar()
+ throws IOException;
+
+ /**
+ * This method reads a Java double value from an input stream. It operates
+ * by first reading a long
value from the stream by calling the
+ * readLong()
method in this interface, then converts
+ * that long
to a double
using the
+ * longBitsToDouble
method in the class
+ * java.lang.Double
+ * double
written by an object
+ * implementing the writeDouble()
method in the
+ * DataOutput
interface.
+ *
+ * @return The double
value read
+ *
+ * @exception EOFException If end of file is reached before reading
+ * the double
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeDouble
+ * @see java.lang.Double#longBitsToDouble
+ */
+ double readDouble()
+ throws IOException;
+
+ /**
+ * This method reads a Java float value from an input stream. It
+ * operates by first reading an int
value from the
+ * stream by calling the readInt()
method in this
+ * interface, then converts that int
to a
+ * float
using the intBitsToFloat
method
+ * in the class java.lang.Float
+ * float
written by an object
+ * implementing the writeFloat()
method in the
+ * DataOutput
interface.
+ *
+ * @return The float
value read
+ *
+ * @exception EOFException If end of file is reached before reading the float
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeFloat
+ * @see java.lang.Float#intBitsToFloat
+ */
+ float readFloat()
+ throws IOException;
+
+ /**
+ * This method reads raw bytes into the passed array until the array is
+ * full. Note that this method blocks until the data is available and
+ * throws an exception if there is not enough data left in the stream to
+ * fill the buffer. Note also that zero length buffers are permitted.
+ * In this case, the method will return immediately without reading any
+ * bytes from the stream.
+ *
+ * @param b The buffer into which to read the data
+ *
+ * @exception EOFException If end of file is reached before filling the
+ * buffer
+ * @exception IOException If any other error occurs
+ */
+ void readFully(byte[] b)
+ throws IOException;
+
+ /**
+ * This method reads a Java int
value from an input stream
+ * It operates by reading four bytes from the stream and converting them to
+ * a single Java int
. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * byte1
through byte4
represent
+ * the first four bytes read from the stream, they will be
+ * transformed to an int
in the following manner:
+ * (int)(((byte1 & 0xFF) << 24) + ((byte2 & 0xFF) << 16) +
+ * ((byte3 & 0xFF)<< 8) + (byte4 & 0xFF)))
+ * int
written by an object
+ * implementing the writeInt()
method in the
+ * DataOutput
interface.
+ *
+ * @return The int
value read
+ *
+ * @exception EOFException If end of file is reached before reading the int
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeInt
+ */
+ int readInt()
+ throws IOException;
+
+ /**
+ * This method reads a Java long
value from an input stream
+ * It operates by reading eight bytes from the stream and converting them to
+ * a single Java long
. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * byte1
through byte8
represent
+ * the first eight bytes read from the stream, they will be
+ * transformed to an long
in the following manner:
+ * (long)(((byte1 & 0xFF) << 56) + ((byte2 & 0xFF) << 48) +
+ * ((byte3 & 0xFF) << 40) + ((byte4 & 0xFF) << 32) +
+ * ((byte5 & 0xFF) << 24) + ((byte6 & 0xFF) << 16) +
+ * ((byte7 & 0xFF) << 8) + (byte8 & 0xFF)))
+ *
+ * long
written by an object
+ * implementing the writeLong()
method in the
+ * DataOutput
interface.
+ *
+ * @return The long
value read
+ *
+ * @exception EOFException If end of file is reached before reading the long
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeLong
+ */
+ long readLong()
+ throws IOException;
+
+ /**
+ * This method reads a signed 16-bit value into a Java in from the
+ * stream. It operates by reading two bytes from the stream and
+ * converting them to a single 16-bit Java short
. The
+ * two bytes are stored most significant byte first (i.e., "big
+ * endian") regardless of the native host byte ordering.
+ * byte1
and byte2
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to a short
. in
+ * the following manner:
+ * (short)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF))
+ * short
written by an object
+ * implementing the writeShort()
method in the
+ * DataOutput
interface.
+ *
+ * @return The short
value read
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeShort
+ */
+ short readShort()
+ throws IOException;
+
+ /**
+ * This method reads 8 unsigned bits into a Java int
+ * value from the stream. The value returned is in the range of 0 to
+ * 255.
+ * writeUnsignedByte()
method in the
+ * DataOutput
interface.
+ *
+ * @return The unsigned bytes value read as a Java int
.
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeByte
+ */
+ int readUnsignedByte()
+ throws IOException;
+
+ /**
+ * This method reads 16 unsigned bits into a Java int value from the stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single Java int
The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * byte1
and byte2
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to an int
in
+ * the following manner:
+ * (int)(((byte1 & 0xFF) << 8) + (byte2 & 0xFF))
+ * writeUnsignedShort()
method in the
+ * DataOutput
interface.
+ *
+ * @return The unsigned short value read as a Java int
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeShort
+ */
+ int readUnsignedShort()
+ throws IOException;
+
+ /**
+ * Read a single byte.
+ *
+ * @return a byte, extracted from the stream or -1 if
+ * EOF has been reached.
+ * @throws IOException
+ */
+ public int read()
+ throws IOException;
+
+ /**
+ * This method attempts to skip and discard the specified number of bytes
+ * in the input stream. It may actually skip fewer bytes than requested.
+ * This method will not skip any bytes if passed a negative number of bytes
+ * to skip.
+ *
+ * @param n The requested number of bytes to skip.
+ *
+ * @return The requested number of bytes to skip.
+ *
+ * @exception IOException If an error occurs.
+ * @specnote The JDK docs claim that this returns the number of bytes
+ * actually skipped. The JCL claims that this method can throw an
+ * EOFException. Neither of these appear to be true in the JDK 1.3's
+ * implementation. This tries to implement the actual JDK behaviour.
+ */
+ int skipBytes(int n)
+ throws IOException;
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/CDR/abstractDataOutputStream.java b/libjava/classpath/gnu/CORBA/CDR/abstractDataOutputStream.java
new file mode 100644
index 0000000..2f9b8c4
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/abstractDataOutputStream.java
@@ -0,0 +1,185 @@
+/* abstractDataOutputStream.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+import java.io.IOException;
+
+/**
+ * An abstract data output stream that could write data in either
+ * Big Endian or Little Endian format.
+ *
+ * This class reuses code from GNU Classpath DataOutputStream.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public interface abstractDataOutputStream
+{
+ /**
+ * This method flushes any unwritten bytes to the underlying stream.
+ *
+ * @exception IOException If an error occurs.
+ */
+ void flush()
+ throws IOException;
+
+ /**
+ * This method writes the specified byte (passed as an int
)
+ * to the underlying output stream.
+ *
+ * @param value The byte
to write, passed as an int
.
+ *
+ * @exception IOException If an error occurs.
+ */
+ void write(int value)
+ throws IOException;
+
+ /**
+ * This method writes len
bytes from the specified byte array
+ * buf
starting at position offset
into the
+ * buffer to the underlying output stream.
+ *
+ * @param buf The byte array to write from.
+ * @param offset The index into the byte array to start writing from.
+ * @param len The number of bytes to write.
+ *
+ * @exception IOException If an error occurs.
+ */
+ void write(byte[] buf, int offset, int len)
+ throws IOException;
+
+ /**
+ * Write the complete byte array.
+ * @throws IOException
+ */
+ void write(byte[] buf)
+ throws IOException;
+
+ /**
+ * This method writes a Java boolean value to an output stream. If
+ * value
is true
, a byte with the value of
+ * 1 will be written, otherwise a byte with the value of 0 will be
+ * written.
+ *
+ * The value written can be read using the readBoolean
+ * method in DataInput
.
+ *
+ * @param value The boolean
value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeBoolean(boolean value)
+ throws IOException;
+
+ /**
+ * This method writes a Java byte value to an output stream. The
+ * byte to be written will be in the lowest 8 bits of the
+ * int
value passed.
+ *
+ * The value written can be read using the readByte
or
+ * readUnsignedByte
methods in DataInput
.
+ *
+ * @param value The byte
to write to the stream, passed as
+ * the low eight bits of an int
.
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeByte(int value)
+ throws IOException;
+
+ /**
+ * This method writes a Java short value to an output stream. The
+ * char to be written will be in the lowest 16 bits of the int
+ * value passed.
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeShort(int value)
+ throws IOException;
+
+ /**
+ * This method writes a Java char value to an output stream. The
+ * char to be written will be in the lowest 16 bits of the int
+ * value passed.
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeChar(int value)
+ throws IOException;
+
+ /**
+ * This method writes a Java int value to an output stream.
+ *
+ * @param value The int
value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeInt(int value)
+ throws IOException;
+
+ /**
+ * This method writes a Java long value to an output stream.
+ *
+ * @param value The long
value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeLong(long value)
+ throws IOException;
+
+ /**
+ * This method writes a Java float
value to the stream.
+ * @param value The float
value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeFloat(float value)
+ throws IOException;
+
+ /**
+ * This method writes a Java double
value to the stream.
+ *
+ * @param value The double
value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeDouble(double value)
+ throws IOException;
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/CDR/aligningInputStream.java b/libjava/classpath/gnu/CORBA/CDR/aligningInputStream.java
new file mode 100644
index 0000000..a719b32
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/aligningInputStream.java
@@ -0,0 +1,122 @@
+/* aligningInputStream.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+import java.io.ByteArrayInputStream;
+
+import org.omg.CORBA.BAD_PARAM;
+
+/**
+ * The input stream with the possibility to align on the
+ * word (arbitrary size) boundary.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class aligningInputStream
+ extends ByteArrayInputStream
+{
+ /**
+ * The alignment offset.
+ */
+ private int offset = 0;
+
+ /**
+ * Create a stream, reading form the given buffer.
+ *
+ * @param a_buffer a buffer to read from.
+ */
+ public aligningInputStream(byte[] a_buffer)
+ {
+ super(a_buffer);
+ }
+
+ /**
+ * Create a stream, reading from the given buffer region.
+ *
+ * @param a_buffer a buffer to read from.
+ * @param offset the offset of the region.
+ * @param length thr length of the region.
+ */
+ public aligningInputStream(byte[] a_buffer, int offset, int length)
+ {
+ super(a_buffer, offset, length);
+ }
+
+ /**
+ * Set the alignment offset, if the index of the first byte in the
+ * stream is different from 0.
+ */
+ public void setOffset(int an_offset)
+ {
+ offset = an_offset;
+ }
+
+ /**
+ * Skip several bytes, aligning the internal pointer on the
+ * selected boundary.
+ *
+ * @throws BAD_PARAM, minor code 0, the alignment is not possible,
+ * usually due the wrong parameter value.
+ */
+ public void align(int alignment)
+ {
+ try
+ {
+ int d = (pos + offset) % alignment;
+ if (d > 0)
+ {
+ skip(alignment - d);
+ }
+ }
+ catch (Exception ex)
+ {
+ BAD_PARAM p = new BAD_PARAM("Unable to align at " + alignment);
+ p.initCause(ex);
+ throw p;
+ }
+ }
+
+ /**
+ * Get the byte buffer, from where the data are read.
+ */
+ public byte[] getBuffer()
+ {
+ return buf;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/CDR/aligningOutputStream.java b/libjava/classpath/gnu/CORBA/CDR/aligningOutputStream.java
new file mode 100644
index 0000000..8a682c1
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/aligningOutputStream.java
@@ -0,0 +1,121 @@
+/* aligningOutputStream.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import org.omg.CORBA.BAD_PARAM;
+
+/**
+ * The input stream with the possibility to align on the
+ * word (arbitrary size) boundary.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class aligningOutputStream
+ extends ByteArrayOutputStream
+{
+ /**
+ * The alignment offset.
+ */
+ private int offset = 0;
+
+ /**
+ * Create a stream with the default intial buffer size.
+ */
+ public aligningOutputStream()
+ {
+ }
+
+ /**
+ * Create a stream with the given intial buffer size.
+ */
+ public aligningOutputStream(int initial_size)
+ {
+ super(initial_size);
+ }
+
+ /**
+ * Set the alignment offset, if the index of the first byte in the
+ * stream is different from 0.
+ */
+ public void setOffset(int an_offset)
+ {
+ offset = an_offset;
+ }
+
+ /**
+ * Skip several bytes, aligning the internal pointer on the
+ * selected boundary.
+ *
+ * @throws BAD_PARAM, minor code 0, the alignment is not possible,
+ * usually due the wrong parameter value.
+ */
+ public void align(int alignment)
+ {
+ try
+ {
+ int d = (count + offset) % alignment;
+ if (d > 0)
+ {
+ skip(alignment - d);
+ }
+ }
+ catch (Exception ex)
+ {
+ BAD_PARAM p = new BAD_PARAM("Unable to align at " + alignment);
+ p.initCause(ex);
+ throw p;
+ }
+ }
+
+ /**
+ * Write the specified number of zero bytes.
+ *
+ * @param bytes the number of zero bytes to write.
+ */
+ public void skip(int bytes)
+ {
+ for (int i = 0; i < bytes; i++)
+ {
+ write(0);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/CDR/cdrBufInput.java b/libjava/classpath/gnu/CORBA/CDR/cdrBufInput.java
new file mode 100644
index 0000000..3cab721
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/cdrBufInput.java
@@ -0,0 +1,115 @@
+/* cdrBufInput.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+
+/**
+ * The CDR input stream that reads data from the byte buffer.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ *
+ * TODO character encoding. Now the encoding can be set, but it is ignored.
+ * If you take this task, scan 'TODO character encoding' for
+ * relevant places.
+ */
+public class cdrBufInput
+ extends cdrInput
+{
+ /**
+ * The byte array input stream to read data from.
+ */
+ public final aligningInputStream buffer;
+
+ /**
+ * Creates the CDR input stream that reads from the given buffer
+ * array.
+ *
+ * @param a_buffer an array to read from.
+ */
+ public cdrBufInput(byte[] a_buffer)
+ {
+ buffer = new aligningInputStream(a_buffer);
+ setInputStream(buffer);
+ }
+
+ /**
+ * Set the alignment offset, if the index of the first byte in the
+ * stream is different from 0.
+ */
+ public void setOffset(int offset)
+ {
+ buffer.setOffset(offset);
+ }
+
+ /**
+ * Skip several bytes, aligning the internal pointer on the
+ * selected boundary.
+ */
+ public void align(int alignment)
+ {
+ buffer.align(alignment);
+ }
+
+ /**
+ * Mark the current position.
+ * @param ahead
+ */
+ public synchronized void mark(int ahead)
+ {
+ buffer.mark(ahead);
+ }
+
+ /**
+ * Checks if marking is supported.
+ * @return
+ */
+ public boolean markSupported()
+ {
+ return buffer.markSupported();
+ }
+
+ /**
+ * Resets the stream to the previously marked position.
+ */
+ public void reset()
+ {
+ buffer.reset();
+ setInputStream(buffer);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/CDR/cdrBufOutput.java b/libjava/classpath/gnu/CORBA/CDR/cdrBufOutput.java
new file mode 100644
index 0000000..47f5f17
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/cdrBufOutput.java
@@ -0,0 +1,115 @@
+/* cdrBufOutput.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * A CORBA output stream, writing data into the internal
+ * buffer ({@link ByteArrayOutputStream}).
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class cdrBufOutput
+ extends cdrOutput
+{
+ /**
+ * The byte buffer.
+ */
+ public final aligningOutputStream buffer;
+
+ /**
+ * Creates the instance with the given initial buffer size.
+ * @param bufSize the buffer size.
+ */
+ public cdrBufOutput(int bufSize)
+ {
+ buffer = new aligningOutputStream(bufSize);
+ setOutputStream(buffer);
+ }
+
+ /**
+ * Creates the instance with the default buffer size.
+ */
+ public cdrBufOutput()
+ {
+ buffer = new aligningOutputStream();
+ setOutputStream(buffer);
+ }
+
+ /**
+ * Set the alignment offset, if the index of the first byte in the
+ * stream is different from 0.
+ */
+ public void setOffset(int an_offset)
+ {
+ buffer.setOffset(an_offset);
+ }
+
+ /**
+ * Align the curretn position at the given natural boundary.
+ */
+ public void align(int boundary)
+ {
+ buffer.align(boundary);
+ }
+
+ /**
+ * Return the input stream that reads the previously written values.
+ */
+ public org.omg.CORBA.portable.InputStream create_input_stream()
+ {
+ cdrBufInput in = new cdrBufInput(buffer.toByteArray());
+ in.setOrb(orb);
+
+ in.setVersion(giop);
+ in.setCodeSet(getCodeSet());
+
+ return in;
+ }
+
+ /**
+ * Resets (clears) the buffer.
+ */
+ public void reset()
+ {
+ buffer.reset();
+ setOutputStream(buffer);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/CDR/cdrInput.java b/libjava/classpath/gnu/CORBA/CDR/cdrInput.java
new file mode 100644
index 0000000..859f93a
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/cdrInput.java
@@ -0,0 +1,1671 @@
+/* cdrInput.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+import gnu.CORBA.BigDecimalHelper;
+import gnu.CORBA.Functional_ORB;
+import gnu.CORBA.GIOP.CharSets_OSF;
+import gnu.CORBA.GIOP.cxCodeSet;
+import gnu.CORBA.IOR;
+import gnu.CORBA.IOR_Delegate;
+import gnu.CORBA.TypeCodeHelper;
+import gnu.CORBA.Unexpected;
+import gnu.CORBA.Version;
+import gnu.CORBA.gnuAny;
+import gnu.CORBA.stubFinder;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.AnySeqHolder;
+import org.omg.CORBA.BAD_OPERATION;
+import org.omg.CORBA.BooleanSeqHolder;
+import org.omg.CORBA.CharSeqHolder;
+import org.omg.CORBA.DoubleSeqHolder;
+import org.omg.CORBA.FloatSeqHolder;
+import org.omg.CORBA.LongLongSeqHolder;
+import org.omg.CORBA.LongSeqHolder;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.OctetSeqHolder;
+import org.omg.CORBA.ShortSeqHolder;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+import org.omg.CORBA.TypeCodePackage.Bounds;
+import org.omg.CORBA.ULongLongSeqHolder;
+import org.omg.CORBA.ULongSeqHolder;
+import org.omg.CORBA.UShortSeqHolder;
+import org.omg.CORBA.WCharSeqHolder;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.ObjectImpl;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+
+import java.math.BigDecimal;
+
+/**
+ * A simple CORBA CDR (common data representation)
+ * input stream, reading data from the
+ * given {@link java.io.InputStream}. The primitive types
+ * are aligned on they natural boundaries by implementing the
+ * abstract method {@link #align(int boundary)}.
+ *
+ * The same class also implements {@link org.omg.CORBA.DataInputStream} to
+ * read the object content in a user defined way.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public abstract class cdrInput
+ extends org.omg.CORBA_2_3.portable.InputStream
+ implements org.omg.CORBA.DataInputStream
+{
+ /**
+ * The message, explaining that the exception has been thrown due
+ * unexpected end of the input stream. This usually happens the
+ * server and client disagree on communication or data representation
+ * rules.
+ */
+ protected static final String UNEXP_EOF = "Unexpected end of stream";
+
+ /**
+ * This instance is used to convert primitive data types into the
+ * byte sequences.
+ */
+ protected abstractDataInputStream b;
+
+ /**
+ * The input stream, from where the data are actually
+ * being read.
+ */
+ protected java.io.InputStream actual_stream;
+
+ /**
+ * The associated orb, if any.
+ */
+ protected ORB orb;
+
+ /**
+ * The GIOP version.
+ */
+ protected Version giop = new Version(1, 2);
+
+ /**
+ * The code set information.
+ */
+ protected cxCodeSet codeset = cxCodeSet.STANDARD;
+
+ /**
+ * The name of the currently used narrow charset, null if
+ * the native narrow charset is used.
+ */
+ private String narrow_charset = null;
+
+ /**
+ * The name of the currently used wide charset, null if
+ * the native wide charset is used.
+ */
+ private String wide_charset = null;
+
+ /**
+ * True if the native code set is used for narrow characters.
+ * If the set is native, no the intermediate Reader object
+ * is instantiated when writing characters.
+ */
+ private boolean narrow_native;
+
+ /**
+ * True if the native code set is used for wide characters.
+ * If the set is native, no the intermediate Reader object
+ * is instantiated when writing characters.
+ */
+ private boolean wide_native;
+
+ /**
+ * If true, the stream expect
+ * the multi-byte data in the form "less significant byte
+ * first" (Little Endian). This is the opposite to the
+ * java standard (Big Endian).
+ */
+ private boolean little_endian;
+
+ /**
+ * Creates the stream. The stream reads Big Endian by
+ * default.
+ *
+ * @param readFrom a stream to read CORBA input from.
+ */
+ public cdrInput(java.io.InputStream readFrom)
+ {
+ setInputStream(readFrom);
+ setCodeSet(cxCodeSet.STANDARD);
+ }
+
+ /**
+ * Creates the stream, requiring the subsequent call
+ * of {@link #setInputStream(java.io.InputStream)}.
+ */
+ public cdrInput()
+ {
+ setCodeSet(cxCodeSet.STANDARD);
+ }
+
+ /**
+ * Set the Big Endian or Little Endian encoding.
+ * The stream reads Big Endian by default.
+ *
+ * @param use_little_endian if true, the stream expect
+ * the multi-byte data in the form "less significant byte
+ * first" (Little Endian). This is the opposite to the
+ * java standard (Big Endian).
+ */
+ public void setBigEndian(boolean use_big_endian)
+ {
+ little_endian = !use_big_endian;
+ setInputStream(actual_stream);
+ }
+
+ /**
+ * Set the input stream that receives the CORBA input.
+ *
+ * @param readFrom the stream.
+ */
+ public void setInputStream(java.io.InputStream readFrom)
+ {
+ if (little_endian)
+ b = new LittleEndianInputStream(readFrom);
+ else
+ b = new BigEndianInputStream(readFrom);
+
+ actual_stream = readFrom;
+ }
+
+ /**
+ * Set the alignment offset, if the index of the first byte in the
+ * stream is different from 0.
+ */
+ public abstract void setOffset(int offset);
+
+ /**
+ * Set the orb, associated with this stream.
+ * @param an_orb
+ */
+ public void setOrb(ORB an_orb)
+ {
+ orb = an_orb;
+ }
+
+ /**
+ * Set the GIOP version. Some data types are written differently
+ * for the different versions. The default version is 1.0 .
+ */
+ public void setVersion(Version giop_version)
+ {
+ giop = giop_version;
+ }
+
+ /**
+ * Align the curretn position at the given natural boundary.
+ */
+ public abstract void align(int boundary);
+
+ /**
+ * Reads the CORBA unsigned long (java int), returning the
+ * value in the sufficiently large java long.
+ */
+ public long gnu_read_ulong()
+ {
+ try
+ {
+ long l = b.readInt();
+ l &= 0xFFFFFFF;
+ return l;
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the unsigned short integer value and return it as java
+ * int, sufficiently large to hold all values.
+ */
+ public int gnu_read_ushort()
+ {
+ try
+ {
+ align(2);
+ return b.readUnsignedShort();
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Return the associated {@link ORB}.
+ * @return the associated {@link ORB} or null is no such is set.
+ */
+ public ORB orb()
+ {
+ return orb;
+ }
+
+ /**
+ * Read a single byte directly from the buffer.
+ */
+ public int read()
+ throws java.io.IOException
+ {
+ try
+ {
+ return b.read();
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+ }
+
+ /**
+ * Read bytes directly from the buffer.
+ */
+ public int read(byte[] x, int ofs, int len)
+ throws java.io.IOException
+ {
+ try
+ {
+ return b.read(x, ofs, len);
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+ }
+
+ /**
+ * Read bytes directly from the buffer.
+ */
+ public int read(byte[] x)
+ throws java.io.IOException
+ {
+ try
+ {
+ return b.read(x);
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+ }
+
+ /**
+ * Read the CORBA object. The object to read is represented in the
+ * form of the plain (not a string-encoded) IOR profile without the
+ * heading endian indicator. The responsible method for reading such
+ * data is {@link IOR.read_no_endian}.
+ *
+ * The returned object is usually casted into the given type using
+ * the .narrow method of its helper, despite in some cases the direct
+ * cast would also work.
+ *
+ * The null objects are recognised from the empty profile set.
+ * For such objects, null is returned.
+ *
+ * @return the loaded and constructed object.
+ */
+ public org.omg.CORBA.Object read_Object()
+ {
+ try
+ {
+ IOR ior = new IOR();
+ ior._read_no_endian(this);
+
+ if (ior.Id == null)
+ return null;
+
+ // Check maybe this is a remote reference to the local object.
+ // This is only possible if we access the repository of the
+ // connected object.
+ if (orb instanceof Functional_ORB)
+ {
+ Functional_ORB forb = (Functional_ORB) orb;
+ org.omg.CORBA.Object local = forb.find_local_object(ior);
+ if (local != null)
+ return local;
+ }
+
+ // Search for the available stubs.
+ ObjectImpl impl = stubFinder.search(orb, ior);
+ try
+ {
+ if (impl._get_delegate() == null)
+ impl._set_delegate(new IOR_Delegate(orb, ior));
+ }
+ catch (BAD_OPERATION ex)
+ {
+ // Some colaborants may throw this exception
+ // in response to the attempt to get the unset delegate.
+ impl._set_delegate(new IOR_Delegate(orb, ior));
+ }
+
+ return impl;
+ }
+ catch (IOException ex)
+ {
+ BAD_OPERATION bad = new BAD_OPERATION();
+ bad.initCause(ex);
+ throw bad;
+ }
+ }
+
+ /**
+ * Read the type code. The type code format is defined in the
+ * CORBA documenation.
+ */
+ public TypeCode read_TypeCode()
+ {
+ try
+ {
+ return TypeCodeHelper.read(this);
+ }
+
+ catch (Bounds ex)
+ {
+ throw new Unexpected();
+ }
+ catch (BadKind ex)
+ {
+ throw new Unexpected();
+ }
+ }
+
+ /**
+ * Read the CORBA {@link Any}. This method first reads the
+ * type code, then delegates the functionality
+ * to {@link Any#read_value}.
+ */
+ public Any read_any()
+ {
+ TypeCode ty = read_TypeCode();
+ gnuAny any = new gnuAny();
+ any.read_value(this, ty);
+ return any;
+ }
+
+ /**
+ * Read the boolean, treating any non zero byte as true,
+ * zero byte as false.
+ */
+ public boolean read_boolean()
+ {
+ try
+ {
+ return b.read() == 0 ? false : true;
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the array of boolean.
+ */
+ public void read_boolean_array(boolean[] x, int offs, int len)
+ {
+ try
+ {
+ for (int i = offs; i < offs + len; i++)
+ {
+ x [ i ] = b.read() == 0 ? false : true;
+ }
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read a character using narrow charset encoding. Depending form
+ * which encoding is set, this still can be Unicode or ever wider.
+ */
+ public char read_char()
+ {
+ try
+ {
+ if (narrow_native)
+ return (char) b.read();
+ else
+ return (char) new InputStreamReader((InputStream) b, narrow_charset).read();
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read a character array, using narrow charset encoding.
+ */
+ public void read_char_array(char[] x, int offset, int length)
+ {
+ try
+ {
+ if (narrow_native)
+ {
+ for (int i = offset; i < offset + length; i++)
+ x [ i ] = (char) b.read();
+ }
+ else
+ {
+ InputStreamReader reader =
+ new InputStreamReader((InputStream) b, narrow_charset);
+ reader.read(x, offset, length);
+ }
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the double value, IEEE 754 format.
+ */
+ public double read_double()
+ {
+ try
+ {
+ align(8);
+ return b.readDouble();
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected();
+ }
+ }
+
+ /**
+ * Read the array of double values, IEEE 754 format.
+ */
+ public void read_double_array(double[] x, int offs, int len)
+ {
+ try
+ {
+ align(8);
+ for (int i = offs; i < offs + len; i++)
+ {
+ x [ i ] = b.readDouble();
+ }
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the encapsulated stream.
+ * If the encapsulated sequence appears to be in the
+ * Little endian format, the flag of the returned stream
+ * is set to read Little endian.
+ */
+ public cdrBufInput read_encapsulation()
+ {
+ try
+ {
+ int l = read_long();
+
+ byte[] r = new byte[ l ];
+ int n = 0;
+ reading:
+ while (n < r.length)
+ {
+ n += read(r, n, r.length - n);
+ }
+
+ cdrBufInput capsule = new cdrBufInput(r);
+ capsule.setOrb(orb);
+
+ int endian = capsule.read_octet();
+
+ if (endian != 0)
+ {
+ capsule.setBigEndian(false);
+ }
+
+ return capsule;
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the CORBA fixed (the end of the fixed
+ * can be determined by its last byte). The scale is always
+ * assumed to be zero.
+ */
+ public BigDecimal read_fixed()
+ {
+ try
+ {
+ return BigDecimalHelper.read(this, 0);
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the float value, IEEE 754 format.
+ */
+ public float read_float()
+ {
+ try
+ {
+ align(4);
+ return b.readFloat();
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read an array of float values, IEEE 754 format.
+ */
+ public void read_float_array(float[] x, int offs, int len)
+ {
+ try
+ {
+ align(4);
+ for (int i = offs; i < offs + len; i++)
+ {
+ x [ i ] = b.readFloat();
+ }
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the CORBA long (java int), high byte first.
+ */
+ public int read_long()
+ {
+ try
+ {
+ align(4);
+ return b.readInt();
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read an array of CORBA longs (java ints).
+ */
+ public void read_long_array(int[] x, int offs, int len)
+ {
+ try
+ {
+ align(4);
+ for (int i = offs; i < offs + len; i++)
+ {
+ x [ i ] = b.readInt();
+ }
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the CORBA long long (java long).
+ */
+ public long read_longlong()
+ {
+ try
+ {
+ align(8);
+ return b.readLong();
+ }
+ catch (EOFException ex)
+ {
+ throw new MARSHAL(UNEXP_EOF);
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read an array of CORBA long longs (java longs).
+ */
+ public void read_longlong_array(long[] x, int offs, int len)
+ {
+ try
+ {
+ align(8);
+ for (int i = offs; i < offs + len; i++)
+ {
+ x [ i ] = b.readLong();
+ }
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read a single byte.
+ */
+ public byte read_octet()
+ {
+ try
+ {
+ return b.readByte();
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the byte array.
+ */
+ public void read_octet_array(byte[] x, int offs, int len)
+ {
+ try
+ {
+ b.read(x, offs, len);
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the length of the byte array as CORBA long and then
+ * the array itseld.
+ */
+ public byte[] read_sequence()
+ {
+ try
+ {
+ int l = read_long();
+ byte[] b = new byte[ l ];
+ if (l > 0)
+ {
+ read(b);
+ }
+ return b;
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the CORBA short integer.
+ */
+ public short read_short()
+ {
+ try
+ {
+ align(2);
+ return b.readShort();
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read the array of CORBA short integer values.
+ */
+ public void read_short_array(short[] x, int offs, int len)
+ {
+ try
+ {
+ align(2);
+ for (int i = offs; i < offs + len; i++)
+ {
+ x [ i ] = b.readShort();
+ }
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Read a singe byte string. The method firs reads the
+ * byte array and then calls a constructor to create a
+ * string from this array. The character encoding, if
+ * previously set, is taken into consideration.
+ *
+ * @return a loaded string.
+ */
+ public String read_string()
+ {
+ try
+ {
+ align(4);
+
+ int n = b.readInt();
+ byte[] s = new byte[ n ];
+ b.read(s);
+
+ // Discard the null terminator.
+ if (narrow_charset == null)
+ return new String(s, 0, n - 1);
+ else
+ return new String(s, 0, n - 1, narrow_charset);
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected();
+ }
+ }
+
+ /**
+ * Reads the CORBA unsigned long (java int), delegating
+ * functionality to {@link #read_long}.
+ */
+ public int read_ulong()
+ {
+ return read_long();
+ }
+
+ /**
+ * Reads the array of CORBA unsigned long (java integer) values,
+ * delegating functionality to
+ * {@link #real_long_array}.
+ */
+ public void read_ulong_array(int[] x, int offs, int len)
+ {
+ read_long_array(x, offs, len);
+ }
+
+ /**
+ * Read the CORBA unsigned long long value,
+ * delegating functionality to {@link #read_longlong}.
+ * There is no way to return values over the limit of
+ * the java signed long in other way than returning
+ * the negative value.
+ */
+ public long read_ulonglong()
+ {
+ return read_longlong();
+ }
+
+ /**
+ * Reads the array of CORBA long long (java long) values,
+ * delegating functionality to
+ * {@link #real_longlong_array}.
+ */
+ public void read_ulonglong_array(long[] x, int offs, int len)
+ {
+ read_longlong_array(x, offs, len);
+ }
+
+ /**
+ * Read the unsigned short integer value. Due strange specification,
+ * the returned value must be the short type as well, so the
+ * the best solution seems just to delegete functionality to
+ * read_short.
+ */
+ public short read_ushort()
+ {
+ return read_short();
+ }
+
+ /**
+ * Read an array of unsigned short values, delegating the
+ * functionality to {@link read_short_array}.
+ */
+ public void read_ushort_array(short[] x, int offs, int len)
+ {
+ read_short_array(x, offs, len);
+ }
+
+ /**
+ * Reads the wide character using the encoding, specified in the
+ * wide_charset.
+ */
+ public char read_wchar()
+ {
+ try
+ {
+ if (giop.until_inclusive(1, 1))
+ align(2);
+
+ if (wide_native)
+ return (char) b.readShort();
+ else
+ return (char) new InputStreamReader((InputStream) b, wide_charset).read();
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+ catch (IOException ex)
+ {
+ throw new Unexpected();
+ }
+ }
+
+ /**
+ * Read an array of "wide chars", each representing a two byte
+ * Unicode character, high byte first.
+ */
+ public void read_wchar_array(char[] x, int offset, int length)
+ {
+ try
+ {
+ if (giop.until_inclusive(1, 1))
+ align(2);
+
+ if (wide_native)
+ {
+ for (int i = offset; i < offset + length; i++)
+ x [ i ] = (char) b.readShort();
+ }
+ else
+ {
+ InputStreamReader reader =
+ new InputStreamReader((InputStream) b, wide_charset);
+ reader.read(x, offset, length);
+ }
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Reads the string in wide character format
+ * (ussually UTF-16, Unicode). Takes the currently set charset
+ * into consideration.
+ *
+ * If the native (UTF-16) encoding is used
+ * of the GIOP protocol is before 1.2, delegates functionality
+ * to "plain" {@link #read_wstring_UTF_16}.
+ */
+ public String read_wstring()
+ {
+ // Native encoding or word oriented data.
+ if (wide_native || giop.until_inclusive(1, 1))
+ return read_wstring_UTF_16();
+ try
+ {
+ align(4);
+
+ int n = b.readInt();
+ byte[] s = new byte[ n ];
+ b.read(s);
+
+ return new String(s, 0, n, wide_charset);
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Reads first length of the string and the all characters as an
+ * Unicode (UTF-16) characters. Mind that GIOP 1.1 has the extra
+ * null character at the end that must be discarded.
+ */
+ public String read_wstring_UTF_16()
+ {
+ try
+ {
+ int p = 0;
+ int n = read_long();
+
+ // The null terminator that is no longer present since 1.2 .
+ int nt = giop.since_inclusive(1, 2) ? 0 : 1;
+
+ // Convert bytes to shorts.
+ n = n / 2;
+
+ char[] s = new char[ n ];
+
+ for (int i = 0; i < s.length; i++)
+ s [ i ] = (char) b.readShort();
+
+ // Check for the byte order marker here.
+ if (s [ 0 ] == 0xFEFF)
+ {
+ // Big endian encoding - do nothing, but move the pointer
+ // one position forward.
+ p = 1;
+ }
+ else if (s [ 0 ] == 0xFFFE)
+ {
+ // Little endian encoding, swap the bytes and move one
+ // position forward.
+ p = 1;
+
+ for (int i = p; i < s.length; i++)
+ s [ i ] = swap(s [ i ]);
+ }
+
+ // Discard the null terminator and, if needed, the endian marker.
+ return new String(s, p, n - nt - p);
+ }
+ catch (EOFException ex)
+ {
+ MARSHAL t = new MARSHAL(UNEXP_EOF);
+ t.initCause(ex);
+ throw t;
+ }
+
+ catch (IOException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /**
+ * Swap bytes in the character.
+ */
+ public static char swap(char x)
+ {
+ int hi;
+ int lo;
+
+ lo = x & 0xFF;
+ hi = (x >> 8) & 0xFF;
+
+ return (char) ((lo << 8) | hi);
+ }
+
+ /**
+ * Set the current code set context.
+ */
+ public void setCodeSet(cxCodeSet a_codeset)
+ {
+ this.codeset = a_codeset;
+ narrow_charset = CharSets_OSF.getName(codeset.char_data);
+ wide_charset = CharSets_OSF.getName(codeset.wide_char_data);
+
+ narrow_native = CharSets_OSF.NATIVE_CHARACTER == codeset.char_data;
+ wide_native = CharSets_OSF.NATIVE_WIDE_CHARACTER == codeset.wide_char_data;
+ }
+
+ /**
+ * Get the current code set context.
+ */
+ public cxCodeSet getCodeSet()
+ {
+ return codeset;
+ }
+
+ /**
+ * Read the object that is an instance of the given class. The current
+ * implementation delegates functionality to the parameterless
+ * {@link readObject()}.
+ *
+ * @param klass a class of that this object the instance is.
+ *
+ * @return the returned object.
+ */
+ public org.omg.CORBA.Object read_Object(Class klass)
+ {
+ return read_Object();
+ }
+
+ /**
+ * Read a value type structure from the stream.
+ *
+ * OMG specification states the writing format is outside the scope
+ * of GIOP definition. This implementation uses java serialization
+ * mechanism, calling {@link ObjectInputStream#readObject}
+ *
+ * @return an value type structure, unmarshaled from the stream
+ */
+ public Serializable read_Value()
+ {
+ return read_value();
+ }
+
+ /**
+ * Read the abstract interface. An abstract interface can be either
+ * CORBA value type or CORBA object and is returned as an abstract
+ * java.lang.Object.
+ *
+ * As specified in OMG specification, this reads a single
+ * boolean and then delegates either to {@link #read_Object()} (for false)
+ * or to {@link #read_Value()} (for true).
+ *
+ * @return an abstract interface, unmarshaled from the stream
+ */
+ public java.lang.Object read_Abstract()
+ {
+ return read_abstract_interface();
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_char_array(CharSeqHolder holder, int offset, int length)
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_char_array(holder.value, offset, length);
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_wchar_array(WCharSeqHolder holder, int offset, int length)
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_wchar_array(holder.value, offset, length);
+ }
+
+ /**
+ * If required, allocate or resize the char array to fit the newly
+ * read values.
+ *
+ * @param holder_value the existing char array, may be null.
+ * @param offset the required offset to read.
+ * @param length the length of the new sequence.
+ *
+ * @return the allocated or resized array, same array if no such operations
+ * are required.
+ */
+ private char[] ensureArray(char[] holder_value, int offset, int length)
+ {
+ if (holder_value == null)
+ return new char[ offset + length ];
+ else if (holder_value.length < offset + length)
+ {
+ char[] value = new char[ offset + length ];
+ System.arraycopy(holder_value, 0, value, 0, holder_value.length);
+ return value;
+ }
+ else
+ return holder_value;
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_ulong_array(ULongSeqHolder holder, int offset, int length)
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_ulong_array(holder.value, offset, length);
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_long_array(LongSeqHolder holder, int offset, int length)
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_ulong_array(holder.value, offset, length);
+ }
+
+ /**
+ * If required, allocate or resize the int array to fit the newly
+ * read values.
+ *
+ * @param holder_value the existing int array, may be null.
+ * @param offset the required offset to read.
+ * @param length the length of the new sequence.
+ *
+ * @return the allocated or resized array, same array if no such operations
+ * are required.
+ */
+ private int[] ensureArray(int[] holder_value, int offset, int length)
+ {
+ if (holder_value == null)
+ return new int[ offset + length ];
+ else if (holder_value.length < offset + length)
+ {
+ int[] value = new int[ offset + length ];
+ System.arraycopy(holder_value, 0, value, 0, holder_value.length);
+ return value;
+ }
+ else
+ return holder_value;
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_float_array(FloatSeqHolder holder, int offset, int length)
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_float_array(holder.value, offset, length);
+ }
+
+ /**
+ * If required, allocate or resize the float array to fit the newly
+ * read values.
+ *
+ * @param holder_value the existing float array, may be null.
+ * @param offset the required offset to read.
+ * @param length the length of the new sequence.
+ *
+ * @return the allocated or resized array, same array if no such operations
+ * are required.
+ */
+ private float[] ensureArray(float[] holder_value, int offset, int length)
+ {
+ if (holder_value == null)
+ return new float[ offset + length ];
+ else if (holder_value.length < offset + length)
+ {
+ float[] value = new float[ offset + length ];
+ System.arraycopy(holder_value, 0, value, 0, holder_value.length);
+ return value;
+ }
+ else
+ return holder_value;
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_double_array(DoubleSeqHolder holder, int offset, int length)
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_double_array(holder.value, offset, length);
+ }
+
+ /**
+ * If required, allocate or resize the double array to fit the newly
+ * read values.
+ *
+ * @param holder_value the existing double array, may be null.
+ * @param offset the required offset to read.
+ * @param length the length of the new sequence.
+ *
+ * @return the allocated or resized array, same array if no such operations
+ * are required.
+ */
+ private double[] ensureArray(double[] holder_value, int offset, int length)
+ {
+ if (holder_value == null)
+ return new double[ offset + length ];
+ else if (holder_value.length < offset + length)
+ {
+ double[] value = new double[ offset + length ];
+ System.arraycopy(holder_value, 0, value, 0, holder_value.length);
+ return value;
+ }
+ else
+ return holder_value;
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_short_array(ShortSeqHolder holder, int offset, int length)
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_short_array(holder.value, offset, length);
+ }
+
+ /** {@inheritDoc} */
+ public void read_ushort_array(UShortSeqHolder holder, int offset, int length)
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_ushort_array(holder.value, offset, length);
+ }
+
+ /**
+ * If required, allocate or resize the short array to fit the newly
+ * read values.
+ *
+ * @param holder_value the existing short array, may be null.
+ * @param offset the required offset to read.
+ * @param length the length of the new sequence.
+ *
+ * @return the allocated or resized array, same array if no such operations
+ * are required.
+ */
+ private short[] ensureArray(short[] holder_value, int offset, int length)
+ {
+ if (holder_value == null)
+ return new short[ offset + length ];
+ else if (holder_value.length < offset + length)
+ {
+ short[] value = new short[ offset + length ];
+ System.arraycopy(holder_value, 0, value, 0, holder_value.length);
+ return value;
+ }
+ else
+ return holder_value;
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_octet_array(OctetSeqHolder holder, int offset, int length)
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_octet_array(holder.value, offset, length);
+ }
+
+ /**
+ * If required, allocate or resize the byte array to fit the newly
+ * read values.
+ *
+ * @param holder_value the existing byte array, may be null.
+ * @param offset the required offset to read.
+ * @param length the length of the new sequence.
+ *
+ * @return the allocated or resized array, same array if no such operations
+ * are required.
+ */
+ private byte[] ensureArray(byte[] holder_value, int offset, int length)
+ {
+ if (holder_value == null)
+ return new byte[ offset + length ];
+ else if (holder_value.length < offset + length)
+ {
+ byte[] value = new byte[ offset + length ];
+ System.arraycopy(holder_value, 0, value, 0, holder_value.length);
+ return value;
+ }
+ else
+ return holder_value;
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_longlong_array(LongLongSeqHolder holder, int offset,
+ int length
+ )
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_longlong_array(holder.value, offset, length);
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_ulonglong_array(ULongLongSeqHolder holder, int offset,
+ int length
+ )
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_ulonglong_array(holder.value, offset, length);
+ }
+
+ /**
+ * If required, allocate or resize the array of longs to fit the newly
+ * read values.
+ *
+ * @param holder_value the existing array, may be null.
+ * @param offset the required offset to read.
+ * @param length the length of the new sequence.
+ *
+ * @return the allocated or resized array, same array if no such operations
+ * are required.
+ */
+ private long[] ensureArray(long[] holder_value, int offset, int length)
+ {
+ if (holder_value == null)
+ return new long[ offset + length ];
+ else if (holder_value.length < offset + length)
+ {
+ long[] value = new long[ offset + length ];
+ System.arraycopy(holder_value, 0, value, 0, holder_value.length);
+ return value;
+ }
+ else
+ return holder_value;
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_boolean_array(BooleanSeqHolder holder, int offset, int length)
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ read_boolean_array(holder.value, offset, length);
+ }
+
+ /**
+ * If required, allocate or resize the array of booleans to fit the newly
+ * read values.
+ *
+ * @param holder_value the existing array of booleans, may be null.
+ * @param offset the required offset to read.
+ * @param length the length of the new sequence.
+ *
+ * @return the allocated or resized array, same array if no such operations
+ * are required.
+ */
+ private boolean[] ensureArray(boolean[] holder_value, int offset, int length)
+ {
+ if (holder_value == null)
+ return new boolean[ offset + length ];
+ else if (holder_value.length < offset + length)
+ {
+ boolean[] value = new boolean[ offset + length ];
+ System.arraycopy(holder_value, 0, value, 0, holder_value.length);
+ return value;
+ }
+ else
+ return holder_value;
+ }
+
+ /**
+ * Read an array. In OMG specification is written that if the data does
+ * not fit into the holder value field, that array must be resized.
+ * The implementation follows this rule. If the holder value field
+ * contains null, it is newly instantiated.
+ */
+ public void read_any_array(AnySeqHolder holder, int offset, int length)
+ {
+ holder.value = ensureArray(holder.value, offset, length);
+ for (int i = offset; i < offset + length; i++)
+ {
+ holder.value [ i ] = read_any();
+ }
+ }
+
+ /**
+ * If required, allocate or resize the array of Anys to fit the newly
+ * read values.
+ *
+ * @param holder_value the existing array of Anys, may be null.
+ * @param offset the required offset to read.
+ * @param length the length of the new sequence.
+ *
+ * @return the allocated or resized array, same array if no such operations
+ * are required.
+ */
+ private Any[] ensureArray(Any[] holder_value, int offset, int length)
+ {
+ if (holder_value == null)
+ return new Any[ offset + length ];
+ else if (holder_value.length < offset + length)
+ {
+ Any[] value = new Any[ offset + length ];
+ System.arraycopy(holder_value, 0, value, 0, holder_value.length);
+ return value;
+ }
+ else
+ return holder_value;
+ }
+
+ /**
+ * This method is required to represent the DataInputStream as a value
+ * type object.
+ *
+ * @return a single entity "IDL:omg.org/CORBA/DataInputStream:1.0",
+ * always.
+ */
+ public String[] _truncatable_ids()
+ {
+ return new String[] { "IDL:omg.org/CORBA/DataInputStream:1.0" };
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/CDR/cdrOutput.java b/libjava/classpath/gnu/CORBA/CDR/cdrOutput.java
new file mode 100644
index 0000000..86ca3b1
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/cdrOutput.java
@@ -0,0 +1,999 @@
+/* cdrOutput.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+import gnu.CORBA.BigDecimalHelper;
+import gnu.CORBA.GIOP.CharSets_OSF;
+import gnu.CORBA.GIOP.cxCodeSet;
+import gnu.CORBA.IOR;
+import gnu.CORBA.Simple_delegate;
+import gnu.CORBA.TypeCodeHelper;
+import gnu.CORBA.Unexpected;
+import gnu.CORBA.Version;
+import gnu.CORBA.primitiveTypeCode;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.BAD_OPERATION;
+import org.omg.CORBA.Context;
+import org.omg.CORBA.ContextList;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.NO_IMPLEMENT;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+import org.omg.CORBA.UserException;
+import org.omg.CORBA.portable.Delegate;
+import org.omg.CORBA.portable.ObjectImpl;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.Streamable;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Serializable;
+
+import java.math.BigDecimal;
+
+/**
+ * A simple CORBA CDR (common data representation)
+ * output stream, writing data into the
+ * given {@link java.io.OutputStream}.
+ *
+ * The same class also implements the {@link DataInputStream},
+ * providing support for writing the value type objects
+ * in a user defined way.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public abstract class cdrOutput
+ extends org.omg.CORBA_2_3.portable.OutputStream
+ implements org.omg.CORBA.DataOutputStream
+{
+ /**
+ * This instance is used to convert primitive data types into the
+ * byte sequences.
+ */
+ protected abstractDataOutputStream b;
+
+ /**
+ * The associated orb, if any.
+ */
+ protected ORB orb;
+
+ /**
+ * The GIOP version.
+ */
+ protected Version giop = new Version(1, 0);
+
+ /**
+ * The code set information.
+ */
+ protected cxCodeSet codeset;
+
+ /**
+ * The name of the currently used narrow charset.
+ */
+ private String narrow_charset;
+
+ /**
+ * The name of the currently used wide charset, null if
+ * the native wide charset is used.
+ */
+ private String wide_charset;
+
+ /**
+ * True if the native code set is used for narrow characters.
+ * If the set is native, no the intermediate Reader object
+ * is instantiated when writing characters.
+ */
+ private boolean narrow_native;
+
+ /**
+ * True if the native code set is used for wide characters.
+ * If the set is native, no the intermediate Reader object
+ * is instantiated when writing characters.
+ */
+ private boolean wide_native;
+
+ /**
+ * If true, the Little Endian encoding is used to write the
+ * data. Otherwise, the Big Endian encoding is used.
+ */
+ private boolean little_endian;
+
+ /**
+ * The stream whre the data are actually written.
+ */
+ private java.io.OutputStream actual_stream;
+
+ /**
+ * Creates the stream.
+ *
+ * @param writeTo a stream to write CORBA output to.
+ */
+ public cdrOutput(java.io.OutputStream writeTo)
+ {
+ setOutputStream(writeTo);
+ setCodeSet(cxCodeSet.STANDARD);
+ }
+
+ /**
+ * Creates the stream, requiring the subsequent call
+ * of {@link #setOutputStream(java.io.OutputStream)}.
+ */
+ public cdrOutput()
+ {
+ setCodeSet(cxCodeSet.STANDARD);
+ }
+
+ /**
+ * Set the alignment offset, if the index of the first byte in the
+ * stream is different from 0.
+ */
+ public abstract void setOffset(int an_offset);
+
+ /**
+ * Set the current code set context.
+ */
+ public void setCodeSet(cxCodeSet a_codeset)
+ {
+ this.codeset = a_codeset;
+ narrow_charset = CharSets_OSF.getName(codeset.char_data);
+ wide_charset = CharSets_OSF.getName(codeset.wide_char_data);
+
+ narrow_native = CharSets_OSF.NATIVE_CHARACTER == codeset.char_data;
+ wide_native = CharSets_OSF.NATIVE_WIDE_CHARACTER == codeset.wide_char_data;
+ }
+
+ /**
+ * Get the current code set context.
+ */
+ public cxCodeSet getCodeSet()
+ {
+ return codeset;
+ }
+
+ /**
+ * Set the orb, associated with this stream.
+ * @param an_orb
+ */
+ public void setOrb(ORB an_orb)
+ {
+ orb = an_orb;
+ }
+
+ /**
+ * Set the output stream that receives the CORBA output.
+ *
+ * @param writeTo the stream.
+ */
+ public void setOutputStream(java.io.OutputStream writeTo)
+ {
+ if (little_endian)
+ b = new LittleEndianOutputStream(writeTo);
+ else
+ b = new BigEndianOutputStream(writeTo);
+
+ actual_stream = writeTo;
+ }
+
+ /**
+ * Set the GIOP version. Some data types are written differently
+ * for the different versions. The default version is 1.0 .
+ */
+ public void setVersion(Version giop_version)
+ {
+ giop = giop_version;
+ }
+
+ /**
+ * Specify if the stream should use the Big Endian (usual for java)
+ * or Little Encoding. The default is Big Endian.
+ *
+ * @param use_big_endian if true, use Big Endian, if false,
+ * use Little Endian.
+ */
+ public void setBigEndian(boolean use_big_endian)
+ {
+ little_endian = !use_big_endian;
+ setOutputStream(actual_stream);
+ }
+
+ /**
+ * Align the curretn position at the given natural boundary.
+ */
+ public abstract void align(int boundary);
+
+ /**
+ * Create the encapsulation stream, associated with the current
+ * stream. The encapsulated stream must be closed. When being
+ * closed, the encapsulation stream writes its buffer into
+ * this stream using the CORBA CDR encapsulation rules.
+ *
+ * It is not allowed to write to the current stream directly
+ * before the encapsulation stream is closed.
+ *
+ * The encoding (Big/Little Endian) inside the encapsulated
+ * sequence is the same as used into the parent stream.
+ *
+ * @return the encapsulated stream.
+ */
+ public cdrOutput createEncapsulation()
+ {
+ return new encapsulatedOutput(this, !little_endian);
+ }
+
+ /**
+ * Return the associated {@link ORB}.
+ * @return the associated {@link ORB} or null is no such is set.
+ */
+ public ORB orb()
+ {
+ return orb;
+ }
+
+ /**
+ * Write a single byte.
+ * @param a byte to write (low 8 bits are written).
+ */
+ public void write(int n)
+ {
+ try
+ {
+ b.write(n);
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Write bytes directly into the underlying stream.
+ */
+ public void write(byte[] x)
+ throws java.io.IOException
+ {
+ b.write(x);
+ }
+
+ /**
+ * Write bytes directly into the underlying stream.
+ */
+ public void write(byte[] x, int ofs, int len)
+ throws java.io.IOException
+ {
+ b.write(x, ofs, len);
+ }
+
+ /**
+ * Following the specification, this is not implemented.
+ * Override to get the functionality.
+ */
+ public void write_Context(Context context, ContextList contexts)
+ {
+ throw new NO_IMPLEMENT();
+ }
+
+ /**
+ * Read the CORBA object. The object is written
+ * form of the plain (not a string-encoded) IOR profile without the
+ * heading endian indicator. The responsible method for reading such
+ * data is {@link IOR.write_no_endian}.
+ *
+ * The null value is written as defined in OMG specification
+ * (zero length string, followed by an empty set of profiles).
+ */
+ public void write_Object(org.omg.CORBA.Object x)
+ {
+ if (x == null)
+ {
+ IOR.write_null(this);
+ return;
+ }
+ else if (x instanceof ObjectImpl)
+ {
+ Delegate d = ((ObjectImpl) x)._get_delegate();
+
+ if (d instanceof Simple_delegate)
+ {
+ Simple_delegate ido = (Simple_delegate) d;
+ ido.getIor()._write_no_endian(this);
+ return;
+ }
+ }
+
+ // Either this is not an ObjectImpl or it has the
+ // unexpected delegate. Try to convert via ORBs
+ // object_to_string().
+ if (orb != null)
+ {
+ IOR ior = IOR.parse(orb.object_to_string(x));
+ ior._write_no_endian(this);
+ return;
+ }
+ else
+ throw new BAD_OPERATION("Please set the ORB for this stream.");
+ }
+
+ /**
+ * Write the TypeCode. This implementation delegates functionality
+ * to {@link cdrTypeCode}.
+ *
+ * @param x a TypeCode to write.
+ */
+ public void write_TypeCode(TypeCode x)
+ {
+ try
+ {
+ TypeCodeHelper.write(this, x);
+ }
+ catch (UserException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes an instance of the CORBA {@link Any}.
+ * This method writes the typecode, followed
+ * by value itself. In Any contains null
+ * (value not set), the {@link TCKind#tk_null}
+ * is written.
+ *
+ * @param x the {@link Any} to write.
+ */
+ public void write_any(Any x)
+ {
+ Streamable value = x.extract_Streamable();
+ if (value != null)
+ {
+ write_TypeCode(x.type());
+ value._write(this);
+ }
+ else
+ {
+ primitiveTypeCode p = new primitiveTypeCode(TCKind.tk_null);
+ write_TypeCode(p);
+ }
+ }
+
+ /**
+ * Writes a single byte, 0 for false
,
+ * 1 for true
.
+ *
+ * @param x the value to write
+ */
+ public void write_boolean(boolean x)
+ {
+ try
+ {
+ b.write(x ? 1 : 0);
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the boolean array.
+ *
+ * @param x array
+ * @param ofs offset
+ * @param len length.
+ */
+ public void write_boolean_array(boolean[] x, int ofs, int len)
+ {
+ try
+ {
+ for (int i = ofs; i < ofs + len; i++)
+ {
+ b.write(x [ i ] ? 1 : 0);
+ }
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the lower byte of the passed parameter.
+ * @param x the char to write
+ *
+ * It is effective to write more characters at once.
+ */
+ public void write_char(char x)
+ {
+ try
+ {
+ if (narrow_native)
+ b.write(x);
+ else
+ {
+ OutputStreamWriter ow =
+ new OutputStreamWriter((OutputStream) b, narrow_charset);
+ ow.write(x);
+ ow.flush();
+ }
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the lower bytes of the passed array members.
+ *
+ * @param chars an array
+ * @param offsets offset
+ * @param length length
+ */
+ public void write_char_array(char[] chars, int offset, int length)
+ {
+ try
+ {
+ if (narrow_native)
+ {
+ for (int i = offset; i < offset + length; i++)
+ {
+ b.write(chars [ i ]);
+ }
+ }
+ else
+ {
+ OutputStreamWriter ow =
+ new OutputStreamWriter((OutputStream) b, narrow_charset);
+ ow.write(chars, offset, length);
+ ow.flush();
+ }
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the double value (IEEE 754 format).
+ */
+ public void write_double(double x)
+ {
+ try
+ {
+ align(8);
+ b.writeDouble(x);
+ }
+ catch (Exception ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the array of double values.
+ */
+ public void write_double_array(double[] x, int ofs, int len)
+ {
+ try
+ {
+ align(8);
+ for (int i = ofs; i < ofs + len; i++)
+ {
+ b.writeDouble(x [ i ]);
+ }
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes CORBA fixed, storing all digits but not the scale.
+ * The end of the record on fixed
can
+ * be determined from its last byte.
+ */
+ public void write_fixed(BigDecimal fixed)
+ {
+ try
+ {
+ BigDecimalHelper.write(this, fixed);
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ catch (BadKind ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Write the float value (IEEE 754 format).
+ */
+ public void write_float(float x)
+ {
+ try
+ {
+ align(4);
+ b.writeFloat(x);
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes an array of the float values.
+ */
+ public void write_float_array(float[] x, int ofs, int len)
+ {
+ try
+ {
+ align(4);
+ for (int i = ofs; i < ofs + len; i++)
+ {
+ b.writeFloat(x [ i ]);
+ }
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the integer value (CORBA long, four bytes, high byte first).
+ * @param x the value to write.
+ */
+ public void write_long(int x)
+ {
+ try
+ {
+ align(4);
+ b.writeInt(x);
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the array of integer (CORBA long) values.
+ *
+ * @param x value
+ * @param ofs offset
+ * @param len length
+ */
+ public void write_long_array(int[] x, int ofs, int len)
+ {
+ try
+ {
+ align(4);
+ for (int i = ofs; i < ofs + len; i++)
+ {
+ b.writeInt(x [ i ]);
+ }
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the long (CORBA long long) value, 8 bytes,
+ * high byte first.
+ *
+ * @param x the value to write.
+ */
+ public void write_longlong(long x)
+ {
+ try
+ {
+ align(8);
+ b.writeLong(x);
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the array of longs (CORBA long longs) values.
+ *
+ * @param x value
+ * @param ofs offset
+ * @param len length
+ */
+ public void write_longlong_array(long[] x, int ofs, int len)
+ {
+ try
+ {
+ align(8);
+ for (int i = ofs; i < ofs + len; i++)
+ {
+ b.writeLong(x [ i ]);
+ }
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes this byte.
+ * @param x
+ */
+ public void write_octet(byte x)
+ {
+ try
+ {
+ b.writeByte(x);
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the array of bytes (CORBA octets) values.
+ *
+ * @param x value
+ * @param ofs offset
+ * @param len length
+ */
+ public void write_octet_array(byte[] x, int ofs, int len)
+ {
+ try
+ {
+ b.write(x, ofs, len);
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes first the size of array, and then the byte array using
+ * the {@link java.io.OutputStream#write(byte[]) }. The sequence
+ * being written is preceeded by the int, representing the array
+ * length.
+ */
+ public void write_sequence(byte[] buf)
+ {
+ try
+ {
+ write_long(buf.length);
+ write(buf);
+ }
+ catch (IOException ex)
+ {
+ MARSHAL t = new MARSHAL();
+ t.initCause(ex);
+ throw t;
+ }
+ }
+
+ /**
+ * Writes the contents of the provided stream.
+ * The sequence being written is preceeded by the int,
+ * representing the stream buffer length (the number of
+ * bytes being subsequently written).
+ */
+ public void write_sequence(cdrBufOutput from)
+ {
+ try
+ {
+ write_long(from.buffer.size());
+ from.buffer.writeTo(this);
+ }
+ catch (IOException ex)
+ {
+ MARSHAL t = new MARSHAL();
+ t.initCause(ex);
+ throw t;
+ }
+ }
+
+ /**
+ * Writes the two byte integer (short), high byte first.
+ *
+ * @param x the integer to write.
+ */
+ public void write_short(short x)
+ {
+ try
+ {
+ align(2);
+ b.writeShort(x);
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the array of short (two byte integer) values.
+ *
+ * @param x value
+ * @param ofs offset
+ * @param len length
+ */
+ public void write_short_array(short[] x, int ofs, int len)
+ {
+ try
+ {
+ align(2);
+ for (int i = ofs; i < ofs + len; i++)
+ {
+ b.writeShort(x [ i ]);
+ }
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the string. This implementation first calls
+ * String.getBytes() and then writes the length of the returned
+ * array (as CORBA ulong) and the returned array itself.
+ *
+ * The encoding information, if previously set, is taken
+ * into consideration.
+ *
+ * @param x the string to write.
+ */
+ public void write_string(String x)
+ {
+ try
+ {
+ byte[] ab = x.getBytes(narrow_charset);
+ write_long(ab.length + 1);
+ write(ab);
+
+ // write null terminator.
+ write(0);
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the CORBA unsigned long in the same way as CORBA long.
+ */
+ public void write_ulong(int x)
+ {
+ write_long(x);
+ }
+
+ /**
+ * Writes the array of CORBA unsigned longs in the same way as
+ * array of ordinary longs.
+ */
+ public void write_ulong_array(int[] x, int ofs, int len)
+ {
+ write_long_array(x, ofs, len);
+ }
+
+ /**
+ * Write the unsigned long long in the same way as an ordinary long long.
+ *
+ * @param x a value to write.
+ */
+ public void write_ulonglong(long x)
+ {
+ write_longlong(x);
+ }
+
+ /**
+ * Write the array of unsingel long longs in the same way
+ * an an array of the ordinary long longs.
+ */
+ public void write_ulonglong_array(long[] x, int ofs, int len)
+ {
+ write_longlong_array(x, ofs, len);
+ }
+
+ /**
+ * Write the unsigned short in the same way as an ordinary short.
+ */
+ public void write_ushort(short x)
+ {
+ write_short(x);
+ }
+
+ /**
+ * Write an array of unsigned short integersin the same way
+ * as an array of ordinary short integers.
+ */
+ public void write_ushort_array(short[] x, int ofs, int len)
+ {
+ write_short_array(x, ofs, len);
+ }
+
+ /**
+ * Writes the character as two byte short integer (Unicode value),
+ * high byte first. Writes in Big Endian, but never writes the
+ * endian indicator.
+ *
+ * The character is always written using the native UTF-16BE charset
+ * because its size under arbitrary encoding is not evident.
+ */
+ public void write_wchar(char x)
+ {
+ try
+ {
+ if (giop.until_inclusive(1, 1))
+ align(2);
+
+ if (wide_native)
+ b.writeShort(x);
+ else
+ {
+ OutputStreamWriter ow =
+ new OutputStreamWriter((OutputStream) b, wide_charset);
+ ow.write(x);
+ ow.flush();
+ }
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Write the array of wide chars.
+ *
+ * @param chars the array of wide chars
+ * @param offset offset
+ * @param length length
+ *
+ * The char array is always written using the native UTF-16BE charset
+ * because the character size under arbitrary encoding is not evident.
+ */
+ public void write_wchar_array(char[] chars, int offset, int length)
+ {
+ try
+ {
+ if (giop.until_inclusive(1, 1))
+ align(2);
+
+ if (wide_native)
+ {
+ for (int i = offset; i < offset + length; i++)
+ {
+ b.writeShort(chars [ i ]);
+ }
+ }
+ else
+ {
+ OutputStreamWriter ow =
+ new OutputStreamWriter((OutputStream) b, wide_charset);
+ ow.write(chars, offset, length);
+ ow.flush();
+ }
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Writes the length of the string in bytes (not characters) and
+ * then all characters as two byte unicode chars. Adds the
+ * Big Endian indicator, 0xFFFE, at the beginning and null wide char at
+ * the end.
+ *
+ * @param x the string to write.
+ */
+ public void write_wstring(String x)
+ {
+ try
+ {
+ if (giop.since_inclusive(1, 2))
+ {
+ byte[] bytes = x.getBytes(wide_charset);
+ write_sequence(bytes);
+ }
+ else
+ {
+ // Encoding with null terminator always in UTF-16.
+ // The wide null terminator needs extra two bytes.
+ write_long(2 * x.length() + 2);
+
+ for (int i = 0; i < x.length(); i++)
+ {
+ b.writeShort(x.charAt(i));
+ }
+
+ // Write null terminator.
+ b.writeShort(0);
+ }
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void write_any_array(Any[] anys, int offset, int length)
+ {
+ for (int i = offset; i < offset + length; i++)
+ {
+ write_any(anys [ i ]);
+ }
+ }
+
+ public String[] _truncatable_ids()
+ {
+ /**@todo Implement this org.omg.CORBA.portable.ValueBase abstract method*/
+ throw new java.lang.UnsupportedOperationException("Method _truncatable_ids() not yet implemented.");
+ }
+
+ /** {@inheritDoc} */
+ public void write_Abstract(java.lang.Object value)
+ {
+ write_Abstract(value);
+ }
+
+ /** {@inheritDoc} */
+ public void write_Value(Serializable value)
+ {
+ write_Value(value);
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/CDR/encapsulatedOutput.java b/libjava/classpath/gnu/CORBA/CDR/encapsulatedOutput.java
new file mode 100644
index 0000000..3350291
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/CDR/encapsulatedOutput.java
@@ -0,0 +1,146 @@
+/* EncapsulationOutput.java --
+ Copyright (C) 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 gnu.CORBA.CDR;
+
+import java.io.IOException;
+
+/**
+ * The encapsulated data, as they are defined by CORBA specification.
+ * This includes the extra 0 byte (Big endian) in the beginning.
+ * When written to the parent steam, the encapsulated data are preceeded
+ * by the data length in bytes.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class encapsulatedOutput
+ extends cdrOutput
+{
+ /**
+ * The Big Endian (most siginificant byte first flag).
+ */
+ public static final byte BIG_ENDIAN = 0;
+
+ /**
+ * The Little Endian (least siginificant byte first flag).
+ */
+ public static final byte LITTLE_ENDIAN = 1;
+
+ /**
+ * The byte buffer.
+ */
+ public final aligningOutputStream buffer;
+
+ /**
+ * The stream, where the data are being encapsulated.
+ */
+ public final org.omg.CORBA.portable.OutputStream parent;
+
+ /**
+ * Create the EncapsulationOutput with the given parent stream
+ * and the specified encoding.
+ */
+ public encapsulatedOutput(org.omg.CORBA.portable.OutputStream _parent,
+ boolean use_big_endian)
+ {
+ super();
+ buffer = new aligningOutputStream();
+ setOutputStream(buffer);
+ parent = _parent;
+ write(use_big_endian?BIG_ENDIAN:LITTLE_ENDIAN);
+ }
+
+ /**
+ * Set the alignment offset, if the index of the first byte in the
+ * stream is different from 0.
+ */
+ public void setOffset(int an_offset)
+ {
+ buffer.setOffset(an_offset);
+ }
+
+ /**
+ * Align the curretn position at the given natural boundary.
+ */
+ public void align(int boundary)
+ {
+ buffer.align(boundary);
+ }
+
+ /**
+ * Writes the content of the encapsulated output into the parent
+ * buffer.
+ */
+ public void close()
+ {
+ try
+ {
+ parent.write_long(buffer.size());
+ buffer.writeTo(parent);
+ }
+ catch (IOException ex)
+ {
+ InternalError err = new InternalError();
+ err.initCause(ex);
+ throw err;
+ }
+ }
+
+ /**
+ * Return the input stream that reads the previously written values.
+ */
+ public org.omg.CORBA.portable.InputStream create_input_stream()
+ {
+ cdrBufInput in = new cdrBufInput(buffer.toByteArray());
+ in.setOrb(orb);
+
+ in.setVersion(giop);
+ in.setCodeSet(getCodeSet());
+
+ return in;
+ }
+
+ /**
+ * Resets (clears) the buffer.
+ */
+ public void reset()
+ {
+ buffer.reset();
+ setOutputStream(buffer);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/Connected_objects.java b/libjava/classpath/gnu/CORBA/Connected_objects.java
new file mode 100644
index 0000000..30d15e7
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/Connected_objects.java
@@ -0,0 +1,231 @@
+/* Connected_objects.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * The repository of objects, that have been connected to the
+ * {@link FunctionalORB} by the method
+ * {@link ORB.connect(org.omg.CORBA.Object)}.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class Connected_objects
+{
+ /**
+ * The reference data about the connected object.
+ */
+ public class cObject
+ {
+ /**
+ * Create an initialised instance.
+ */
+ cObject(org.omg.CORBA.Object _object, int _port, byte[] _key)
+ {
+ object = _object;
+ port = _port;
+ key = _key;
+ }
+
+ /**
+ * The object.
+ */
+ public final org.omg.CORBA.Object object;
+
+ /**
+ * The port on that the object is connected.
+ */
+ public final int port;
+
+ /**
+ * The object key.
+ */
+ public final byte[] key;
+
+ public boolean equals(java.lang.Object other)
+ {
+ if (other instanceof cObject)
+ {
+ cObject o = (cObject) other;
+ return o.object.equals(object) && o.port == port;
+ }
+ else
+ return false;
+ }
+ }
+
+ /**
+ * The free number to give for the next instance.
+ * This field is incremented each time the
+ * new collection of the connected objects is created.
+ * Each collection has its own unique instance number.
+ */
+ private static long free_object_number;
+
+ /**
+ * The map of the all connected objects, maps the object key to the
+ * object.
+ */
+ private Map objects = new TreeMap(new ByteArrayComparator());
+
+ /**
+ * Get the record of the stored object.
+ *
+ * @param object the stored object
+ *
+ * @return the record about the stored object, null if
+ * this object is not stored here.
+ */
+ public cObject getKey(org.omg.CORBA.Object stored_object)
+ {
+ Map.Entry item;
+ Iterator iter = objects.entrySet().iterator();
+ cObject ref;
+
+ while (iter.hasNext())
+ {
+ item = (Map.Entry) iter.next();
+ ref = (cObject) item.getValue();
+ if (stored_object.equals(ref.object))
+ return ref;
+ }
+ return null;
+ }
+
+ /**
+ * Add the new object to the repository. The object key is
+ * generated automatically.
+ *
+ * @param object the object to add.
+ * @param port, on that the ORB will be listening to the remote
+ * invocations.
+ *
+ * @return the newly created object record.
+ */
+ public cObject add(org.omg.CORBA.Object object, int port)
+ {
+ return add(generateObjectKey(object), object, port);
+ }
+
+ /**
+ * Add the new object to the repository.
+ *
+ * @param key the object key.
+ * @param object the object to add.
+ * @param port the port, on that the ORB will be listening on the
+ * remote invocations.
+ */
+ public cObject add(byte[] key, org.omg.CORBA.Object object, int port)
+ {
+ cObject rec = new cObject(object, port, key);
+ objects.put(key, rec);
+ return rec;
+ }
+
+ /**
+ * Get the stored object.
+ *
+ * @param key the key (in the byte array form).
+ *
+ * @return the matching object, null if none is matching.
+ */
+ public cObject get(byte[] key)
+ {
+ return (cObject) objects.get(key);
+ }
+
+ /**
+ * Get the map entry set.
+ * @return
+ */
+ public Set entrySet()
+ {
+ return objects.entrySet();
+ }
+
+ /**
+ * Remove the given object.
+ *
+ * @param object the object to remove.
+ */
+ public void remove(org.omg.CORBA.Object object)
+ {
+ cObject ref = getKey(object);
+ if (ref != null)
+ objects.remove(ref.key);
+ }
+
+ /**
+ * Remove the given object, indiciating it by the key.
+ *
+ * @param object the object to remove.
+ */
+ public void remove(byte[] key)
+ {
+ objects.remove(key);
+ }
+
+ /**
+ * Generate the object key, unique in the currently
+ * running java virtual machine.
+ *
+ * The generated key includes the object class name
+ * and the absolute instance number.
+ *
+ * @return the generated key.
+ */
+ protected byte[] generateObjectKey(org.omg.CORBA.Object object)
+ {
+ return (object.getClass().getName() + ":" + getFreeInstanceNumber()).getBytes();
+ }
+
+ /**
+ * Get next free instance number.
+ */
+ private static synchronized long getFreeInstanceNumber()
+ {
+ long instance_number = free_object_number;
+ free_object_number++;
+ return instance_number;
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/DefinitionKindHolder.java b/libjava/classpath/gnu/CORBA/DefinitionKindHolder.java
new file mode 100644
index 0000000..1ef7350
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/DefinitionKindHolder.java
@@ -0,0 +1,91 @@
+/* DefinitionKindHolder.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.DefinitionKind;
+import org.omg.CORBA.DefinitionKindHelper;
+
+
+/**
+ * The definition kind holder. This class is not included in the original
+ * API specification, so we place it outside the org.omg namespace.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class DefinitionKindHolder
+ implements org.omg.CORBA.portable.Streamable
+{
+ /**
+ * The stored value.
+ */
+ public DefinitionKind value;
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue
+ */
+ public DefinitionKindHolder(DefinitionKind initialValue)
+ {
+ value = initialValue;
+ }
+
+ /**
+ * Read from the CDR stream.
+ */
+ public void _read(org.omg.CORBA.portable.InputStream in)
+ {
+ value = DefinitionKindHelper.read(in);
+ }
+
+ /**
+ * Get the typecode.
+ */
+ public org.omg.CORBA.TypeCode _type()
+ {
+ return DefinitionKindHelper.type();
+ }
+
+ /**
+ * Write into the CDR stream.
+ */
+ public void _write(org.omg.CORBA.portable.OutputStream out)
+ {
+ DefinitionKindHelper.write(out, value);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/DuplicateNameHolder.java b/libjava/classpath/gnu/CORBA/DuplicateNameHolder.java
new file mode 100644
index 0000000..ad004bc
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/DuplicateNameHolder.java
@@ -0,0 +1,106 @@
+/* DuplicateNameHolder.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.Streamable;
+import org.omg.PortableInterceptor.ORBInitInfoPackage.DuplicateName;
+import org.omg.PortableInterceptor.ORBInitInfoPackage.DuplicateNameHelper;
+
+/**
+* A holder for the exception {@link DuplicateName}.
+
+* @author Audrius Meskauskas, Lithiania (AudriusA@Bioinformatics.org)
+*/
+public class DuplicateNameHolder
+ implements Streamable
+{
+ /**
+ * The stored DuplicateName value.
+ */
+ public DuplicateName value;
+
+ /**
+ * Create the unitialised instance, leaving the value field
+ * with default null
value.
+ */
+ public DuplicateNameHolder()
+ {
+ }
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue the value that will be assigned to
+ * the value
field.
+ */
+ public DuplicateNameHolder(DuplicateName initialValue)
+ {
+ value = initialValue;
+ }
+
+ /**
+ * Fill in the {@link value} by data from the CDR stream.
+ *
+ * @param input the org.omg.CORBA.portable stream to read.
+ */
+ public void _read(InputStream input)
+ {
+ value = DuplicateNameHelper.read(input);
+ }
+
+ /**
+ * Write the stored value into the CDR stream.
+ *
+ * @param output the org.omg.CORBA.portable stream to write.
+ */
+ public void _write(OutputStream output)
+ {
+ DuplicateNameHelper.write(output, value);
+ }
+
+ /**
+ * Get the typecode of the DuplicateName.
+ */
+ public TypeCode _type()
+ {
+ return DuplicateNameHelper.type();
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/DynAn/NameValuePairHolder.java b/libjava/classpath/gnu/CORBA/DynAn/NameValuePairHolder.java
new file mode 100644
index 0000000..7afc81c
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/DynAn/NameValuePairHolder.java
@@ -0,0 +1,95 @@
+/* NameValuePairHolder.java --
+ Copyright (C) 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 gnu.CORBA.DynAn;
+
+import org.omg.CORBA.NameValuePair;
+import org.omg.CORBA.NameValuePairHelper;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.Streamable;
+
+/**
+ * The name-value pair holder. The {@link NameValuePair} has no standard
+ * holder defined, but it is needed to store the {@link NameValuePair} into
+ * {@link Any}.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class NameValuePairHolder
+ implements Streamable
+{
+ /**
+ * The stored value of the name value pair.
+ */
+ public NameValuePair value;
+
+ public NameValuePairHolder()
+ {
+ }
+
+ public NameValuePairHolder(NameValuePair a_value)
+ {
+ value = a_value;
+ }
+
+ /**
+ * Read the name value pair.
+ */
+ public void _read(InputStream input)
+ {
+ value = NameValuePairHelper.read(input);
+ }
+
+ /**
+ * Return the typecode of the name value pair.
+ */
+ public TypeCode _type()
+ {
+ return NameValuePairHelper.type();
+ }
+
+ /**
+ * Write the name value pair.
+ */
+ public void _write(OutputStream output)
+ {
+ NameValuePairHelper.write(output, value);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/EmptyExceptionHolder.java b/libjava/classpath/gnu/CORBA/EmptyExceptionHolder.java
new file mode 100644
index 0000000..890ca5f
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/EmptyExceptionHolder.java
@@ -0,0 +1,132 @@
+/* EmptyStructHolder.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.BAD_OPERATION;
+import org.omg.CORBA.NO_IMPLEMENT;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.UNKNOWN;
+import org.omg.CORBA.UnknownUserException;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.Streamable;
+
+/**
+ * This holder can store any CORBA exception that has no user defined fields.
+ * Only the repository ID is written when the method {@link #_write} is called.
+ * The _read method is not supported for this holder.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class EmptyExceptionHolder
+ implements Streamable
+{
+ /**
+ * The wrapped exception.
+ */
+ public Throwable value;
+
+ /**
+ * The typecode of the wrapped exception.
+ */
+ public TypeCode typecode;
+
+ /**
+ * Create the exception holder, initialised to the given values.
+ *
+ * @param an_exception the wrapped exception.
+ * @param an_id the exception repository id.
+ */
+ public EmptyExceptionHolder(Throwable an_exception, TypeCode a_typecode)
+ {
+ value = an_exception;
+ typecode = a_typecode;
+ }
+
+ /**
+ * Reads the exception from the input stream.
+ *
+ * The value field obtains the value of either the read exception or
+ * the UNKNOWN if the repository ID does not match
+ * the exception from the reachable code.
+ */
+ public void _read(InputStream input)
+ {
+ String id = input.read_string();
+ Object ex = ObjectCreator.Idl2Object(id);
+ if (ex == null)
+ value = new UNKNOWN(id);
+ else
+ value = (Throwable) ex;
+ }
+
+ /**
+ * Return the typecode of the stored exception.
+ *
+ * @return the value, passed as a_typecode in constructor.
+ */
+ public TypeCode _type()
+ {
+ return typecode;
+ }
+
+ /**
+ * Write the exception into the give output stream. Writes the
+ * repository id that is taken from the typecode. This method also
+ * works when no helper class is available.
+ *
+ * @param output a stream to write into.
+ *
+ * @throws BAD_OPERATION if the value for the holder is not set or
+ * the typecode cannot provide repository id.
+ */
+ public void _write(OutputStream output)
+ {
+ try
+ {
+ output.write_string(typecode.id());
+ }
+ catch (Exception ex)
+ {
+ BAD_OPERATION bad = new BAD_OPERATION();
+ bad.initCause(ex);
+ throw bad;
+ }
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/ExceptionCreator.java b/libjava/classpath/gnu/CORBA/ExceptionCreator.java
new file mode 100644
index 0000000..536053c
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/ExceptionCreator.java
@@ -0,0 +1,248 @@
+/* ExceptionCreator.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.CompletionStatus;
+import org.omg.CORBA.CompletionStatusHelper;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.SystemException;
+import org.omg.CORBA.UNKNOWN;
+import org.omg.CORBA.UserException;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * Creates the objects from the agreed IDL names.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class ExceptionCreator
+{
+ /**
+ * The standard OMG prefix.
+ */
+ public static final String OMG_PREFIX = "omg.org/";
+
+ /**
+ * The standard java prefix.
+ */
+ public static final String JAVA_PREFIX = "org.omg.";
+
+ /**
+ * Create the system exception with the given idl name.
+ *
+ * @param idl the exception IDL name, must match the syntax
+ * "IDL:null
.
+ */
+ protected void set_parameters(Applet app, Properties props)
+ {
+ useProperties(props);
+
+ String[][] para = app.getParameterInfo();
+ if (para != null)
+ {
+ for (int i = 0; i < para.length; i++)
+ {
+ if (para [ i ] [ 0 ].equals(LISTEN_ON))
+ Port = Integer.parseInt(para [ i ] [ 1 ]);
+
+ if (para [ i ] [ 0 ].equals(REFERENCE))
+ {
+ StringTokenizer st = new StringTokenizer(para [ i ] [ 1 ], "=");
+ initial_references.put(st.nextToken(),
+ string_to_object(st.nextToken())
+ );
+ }
+
+ if (para [ i ] [ 0 ].equals(NS_HOST))
+ ns_host = para [ i ] [ 1 ];
+
+ if (para [ i ] [ 0 ].equals(START_READING_MESSAGE))
+ TOUT_START_READING_MESSAGE = Integer.parseInt(para [ i ] [ 1 ]);
+
+ if (para [ i ] [ 0 ].equals(WHILE_READING))
+ TOUT_WHILE_READING = Integer.parseInt(para [ i ] [ 1 ]);
+
+ if (para [ i ] [ 0 ].equals(AFTER_RECEIVING))
+ TOUT_AFTER_RECEIVING = Integer.parseInt(para [ i ] [ 1 ]);
+
+ try
+ {
+ if (para [ i ] [ 0 ].equals(NS_PORT))
+ ns_port = Integer.parseInt(para [ i ] [ 1 ]);
+ }
+ catch (NumberFormatException ex)
+ {
+ BAD_PARAM bad =
+ new BAD_PARAM("Invalid " + NS_PORT +
+ "property, unable to parse '" +
+ props.getProperty(NS_PORT) + "'"
+ );
+ bad.initCause(ex);
+ throw bad;
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the ORB parameters. This method is normally called from
+ * {@link #init(String[], Properties)}.
+ *
+ * @param para the parameters, that were passed as the parameters
+ * to the main(String[] args)
method of the current standalone
+ * application.
+ *
+ * @param props application specific properties that were passed
+ * as a second parameter in {@link init(String[], Properties)}).
+ * Can be null
.
+ */
+ protected void set_parameters(String[] para, Properties props)
+ {
+ if (para.length > 1)
+ for (int i = 0; i < para.length - 1; i++)
+ {
+ if (para [ i ].endsWith("ListenOn"))
+ Port = Integer.parseInt(para [ i + 1 ]);
+
+ if (para [ i ].endsWith("ORBInitRef"))
+ {
+ StringTokenizer st = new StringTokenizer(para [ i + 1 ], "=");
+ initial_references.put(st.nextToken(),
+ string_to_object(st.nextToken())
+ );
+ }
+
+ if (para [ i ].endsWith("ORBInitialHost"))
+ ns_host = para [ i + 1 ];
+
+ try
+ {
+ if (para [ i ].endsWith("ORBInitialPort"))
+ ns_port = Integer.parseInt(para [ i + 1 ]);
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new BAD_PARAM("Invalid " + para [ i ] +
+ "parameter, unable to parse '" +
+ props.getProperty(para [ i + 1 ]) + "'"
+ );
+ }
+ }
+
+ useProperties(props);
+ }
+
+ private IOR createIOR(Connected_objects.cObject ref)
+ throws BAD_OPERATION
+ {
+ IOR ior = new IOR();
+ ior.key = ref.key;
+ ior.Internet.port = ref.port;
+
+ if (ref.object instanceof ObjectImpl)
+ {
+ ObjectImpl imp = (ObjectImpl) ref.object;
+ if (imp._ids().length > 0)
+ ior.Id = imp._ids() [ 0 ];
+ }
+ if (ior.Id == null)
+ ior.Id = ref.object.getClass().getName();
+
+ try
+ {
+ ior.Internet.host = InetAddress.getLocalHost().getHostAddress();
+ ior.Internet.port = ref.port;
+ }
+ catch (UnknownHostException ex)
+ {
+ throw new BAD_OPERATION("Cannot resolve the local host address");
+ }
+ return ior;
+ }
+
+ /**
+ * Prepare object for connecting it to this ORB.
+ *
+ * @param object the object being connected.
+ *
+ * @throws BAD_PARAM if the object does not implement the
+ * {@link InvokeHandler}).
+ */
+ private void prepareObject(org.omg.CORBA.Object object, IOR ior)
+ throws BAD_PARAM
+ {
+ if (!(object instanceof InvokeHandler))
+ throw new BAD_PARAM(object.getClass().getName() +
+ " does not implement InvokeHandler. "
+ );
+
+ // If no delegate is set, set the default delegate.
+ if (object instanceof ObjectImpl)
+ {
+ ObjectImpl impl = (ObjectImpl) object;
+ try
+ {
+ if (impl._get_delegate() == null)
+ {
+ impl._set_delegate(new Simple_delegate(this, ior));
+ }
+ }
+ catch (BAD_OPERATION ex)
+ {
+ // Some colaborants may throw this exception.
+ impl._set_delegate(new Simple_delegate(this, ior));
+ }
+ }
+ }
+
+ /**
+ * Write the response message.
+ *
+ * @param net_out the stream to write response into
+ * @param msh_request the request message header
+ * @param rh_request the request header
+ * @param handler the invocation handler that has been used to
+ * invoke the operation
+ * @param sysEx the system exception, thrown during the invocation,
+ * null if none.
+ *
+ * @throws IOException
+ */
+ private void respond_to_client(OutputStream net_out,
+ MessageHeader msh_request,
+ RequestHeader rh_request,
+ bufferedResponseHandler handler,
+ SystemException sysEx
+ )
+ throws IOException
+ {
+ // Set the reply header properties.
+ ReplyHeader reply = handler.reply_header;
+
+ if (sysEx != null)
+ reply.reply_status = ReplyHeader.SYSTEM_EXCEPTION;
+ else if (handler.isExceptionReply())
+ reply.reply_status = ReplyHeader.USER_EXCEPTION;
+ else
+ reply.reply_status = ReplyHeader.NO_EXCEPTION;
+
+ reply.request_id = rh_request.request_id;
+
+ cdrBufOutput out = new cdrBufOutput(50 + handler.getBuffer().buffer.size());
+ out.setOrb(this);
+
+ out.setOffset(msh_request.getHeaderSize());
+
+ reply.write(out);
+
+ // Write the reply data from the handler.
+ handler.getBuffer().buffer.writeTo(out);
+
+ MessageHeader msh_reply = new MessageHeader();
+
+ msh_reply.version = msh_request.version;
+ msh_reply.message_type = MessageHeader.REPLY;
+ msh_reply.message_size = out.buffer.size();
+
+ // Write the reply.
+ msh_reply.write(net_out);
+ out.buffer.writeTo(net_out);
+ net_out.flush();
+ }
+
+ /**
+ * Contains a single servicing task.
+ *
+ * Normally, each task matches a single remote invocation.
+ * However under frequent tandem submissions the same
+ * task may span over several invocations.
+ *
+ * @param serverSocket the ORB server socket.
+ *
+ * @throws MARSHAL
+ * @throws IOException
+ */
+ private void serve(final portServer p, ServerSocket serverSocket)
+ throws MARSHAL, IOException
+ {
+ final Socket service;
+ service = serverSocket.accept();
+
+ // Tell the server there are no more resources.
+ if (p.running_threads >= MAX_RUNNING_THREADS)
+ {
+ serveStep(service, true);
+ return;
+ }
+
+ new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ synchronized (p)
+ {
+ p.running_threads++;
+ }
+ serveStep(service, false);
+ }
+ finally
+ {
+ synchronized (p)
+ {
+ p.running_threads--;
+ }
+ }
+ }
+ }.start();
+ }
+
+ /**
+ * A single servicing step, when the client socket is alrady open.
+ *
+ * Normally, each task matches a single remote invocation.
+ * However under frequent tandem submissions the same
+ * task may span over several invocations.
+ *
+ * @param service the opened client socket.
+ * @param no_resources if true, the "NO RESOURCES" exception
+ * is thrown to the client.
+ */
+ private void serveStep(Socket service, boolean no_resources)
+ {
+ try
+ {
+ Serving:
+ while (true)
+ {
+ InputStream in = service.getInputStream();
+ service.setSoTimeout(TOUT_START_READING_MESSAGE);
+
+ MessageHeader msh_request = new MessageHeader();
+
+ try
+ {
+ msh_request.read(in);
+ }
+ catch (MARSHAL ex)
+ {
+ // This exception may be thrown due closing the connection.
+ return;
+ }
+
+ if (max_version != null)
+ if (!msh_request.version.until_inclusive(max_version.major,
+ max_version.minor
+ )
+ )
+ {
+ OutputStream out = service.getOutputStream();
+ new ErrorMessage(max_version).write(out);
+ return;
+ }
+
+ byte[] r = new byte[ msh_request.message_size ];
+
+ int n = 0;
+
+ service.setSoTimeout(TOUT_WHILE_READING);
+
+ reading:
+ while (n < r.length)
+ {
+ n += in.read(r, n, r.length - n);
+ }
+
+ service.setSoTimeout(TOUT_AFTER_RECEIVING);
+
+ if (msh_request.message_type == MessageHeader.REQUEST)
+ {
+ RequestHeader rh_request;
+
+ cdrBufInput cin = new cdrBufInput(r);
+ cin.setOrb(this);
+ cin.setVersion(msh_request.version);
+ cin.setOffset(msh_request.getHeaderSize());
+ cin.setBigEndian(msh_request.isBigEndian());
+
+ rh_request = msh_request.create_request_header();
+
+ // Read header and auto set the charset.
+ rh_request.read(cin);
+
+ // in 1.2 and higher, align the current position at
+ // 8 octet boundary.
+ if (msh_request.version.since_inclusive(1, 2))
+ cin.align(8);
+
+ // find the target object.
+ InvokeHandler target =
+ (InvokeHandler) find_connected_object(rh_request.object_key);
+
+ // Prepare the reply header. This must be done in advance,
+ // as the size must be known for handler to set alignments
+ // correctly.
+ ReplyHeader rh_reply = msh_request.create_reply_header();
+
+ // TODO log errors about not existing objects and methods.
+ bufferedResponseHandler handler =
+ new bufferedResponseHandler(this, msh_request, rh_reply);
+
+ SystemException sysEx = null;
+
+ try
+ {
+ if (no_resources)
+ throw new NO_RESOURCES();
+ if (target == null)
+ throw new OBJECT_NOT_EXIST();
+ target._invoke(rh_request.operation, cin, handler);
+ }
+ catch (SystemException ex)
+ {
+ sysEx = ex;
+
+ org.omg.CORBA.portable.OutputStream ech =
+ handler.createExceptionReply();
+ ObjectCreator.writeSystemException(ech, ex);
+ }
+ catch (Exception except)
+ {
+ sysEx =
+ new UNKNOWN("Unknown", 2, CompletionStatus.COMPLETED_MAYBE);
+
+ org.omg.CORBA.portable.OutputStream ech =
+ handler.createExceptionReply();
+
+ ObjectCreator.writeSystemException(ech, sysEx);
+ }
+
+ // Write the response.
+ if (rh_request.isResponseExpected())
+ {
+ OutputStream sou = service.getOutputStream();
+ respond_to_client(sou, msh_request, rh_request, handler,
+ sysEx
+ );
+ }
+ }
+ else if (msh_request.message_type == MessageHeader.CLOSE_CONNECTION ||
+ msh_request.message_type == MessageHeader.MESSAGE_ERROR
+ )
+ {
+ CloseMessage.close(service.getOutputStream());
+ service.close();
+ return;
+ }
+ else
+ ;
+
+ // TODO log error: "Not a request message."
+ if (service != null && !service.isClosed())
+ {
+ // Wait for the subsequent invocations on the
+ // same socket for the TANDEM_REQUEST duration.
+ service.setSoTimeout(TANDEM_REQUESTS);
+ }
+ else
+ return;
+ }
+ }
+ catch (SocketException ex)
+ {
+ // OK.
+ return;
+ }
+ catch (IOException ioex)
+ {
+ // Network error, probably transient.
+ // TODO log it.
+ return;
+ }
+ }
+
+ private void useProperties(Properties props)
+ {
+ if (props != null)
+ {
+ if (props.containsKey(LISTEN_ON))
+ Port = Integer.parseInt(props.getProperty(LISTEN_ON));
+
+ if (props.containsKey(NS_HOST))
+ ns_host = props.getProperty(NS_HOST);
+
+ try
+ {
+ if (props.containsKey(NS_PORT))
+ ns_port = Integer.parseInt(props.getProperty(NS_PORT));
+
+ if (props.containsKey(START_READING_MESSAGE))
+ TOUT_START_READING_MESSAGE =
+ Integer.parseInt(props.getProperty(START_READING_MESSAGE));
+
+ if (props.containsKey(WHILE_READING))
+ TOUT_WHILE_READING =
+ Integer.parseInt(props.getProperty(WHILE_READING));
+
+ if (props.containsKey(AFTER_RECEIVING))
+ TOUT_AFTER_RECEIVING =
+ Integer.parseInt(props.getProperty(AFTER_RECEIVING));
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new BAD_PARAM("Invalid " + NS_PORT +
+ "property, unable to parse '" +
+ props.getProperty(NS_PORT) + "'"
+ );
+ }
+
+ Enumeration en = props.elements();
+ while (en.hasMoreElements())
+ {
+ String item = (String) en.nextElement();
+ if (item.equals(REFERENCE))
+ initial_references.put(item,
+ string_to_object(props.getProperty(item))
+ );
+ }
+ }
+ }
+
+ /**
+ * Get the next instance with a response being received. If all currently
+ * sent responses not yet processed, this method pauses till at least one of
+ * them is complete. If there are no requests currently sent, the method
+ * pauses till some request is submitted and the response is received.
+ * This strategy is identical to the one accepted by Suns 1.4 ORB
+ * implementation.
+ *
+ * The returned response is removed from the list of the currently
+ * submitted responses and is never returned again.
+ *
+ * @return the previously sent request that now contains the received
+ * response.
+ *
+ * @throws WrongTransaction If the method was called from the transaction
+ * scope different than the one, used to send the request. The exception
+ * can be raised only if the request is implicitly associated with some
+ * particular transaction.
+ */
+ public Request get_next_response()
+ throws org.omg.CORBA.WrongTransaction
+ {
+ return asynchron.get_next_response();
+ }
+
+ /**
+ * Find if any of the requests that have been previously sent with
+ * {@link #send_multiple_requests_deferred}, have a response yet.
+ *
+ * @return true if there is at least one response to the previously
+ * sent request, false otherwise.
+ */
+ public boolean poll_next_response()
+ {
+ return asynchron.poll_next_response();
+ }
+
+ /**
+ * Send multiple prepared requests expecting to get a reply. All requests
+ * are send in parallel, each in its own separate thread. When the
+ * reply arrives, it is stored in the agreed fields of the corresponing
+ * request data structure. If this method is called repeatedly,
+ * the new requests are added to the set of the currently sent requests,
+ * but the old set is not discarded.
+ *
+ * @param requests the prepared array of requests.
+ *
+ * @see #poll_next_response()
+ * @see #get_next_response()
+ * @see Request#send_deferred()
+ */
+ public void send_multiple_requests_deferred(Request[] requests)
+ {
+ asynchron.send_multiple_requests_deferred(requests);
+ }
+
+ /**
+ * Send multiple prepared requests one way, do not caring about the answer.
+ * The messages, containing requests, will be marked, indicating that
+ * the sender is not expecting to get a reply.
+ *
+ * @param requests the prepared array of requests.
+ *
+ * @see Request#send_oneway()
+ */
+ public void send_multiple_requests_oneway(Request[] requests)
+ {
+ asynchron.send_multiple_requests_oneway(requests);
+ }
+
+ /**
+ * Set the flag, forcing all server threads to terminate.
+ */
+ protected void finalize()
+ throws java.lang.Throwable
+ {
+ running = false;
+ super.finalize();
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/GIOP/CancelHeader.java b/libjava/classpath/gnu/CORBA/GIOP/CancelHeader.java
new file mode 100644
index 0000000..9f4de0d
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/CancelHeader.java
@@ -0,0 +1,70 @@
+/* CancelHeader.java --
+ Copyright (C) 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 gnu.CORBA.GIOP;
+
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+
+/**
+ * The message header for cancelling the request.
+ *
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public abstract class CancelHeader
+{
+ /**
+ * The Id of request being cancelled.
+ */
+ public int request_id;
+
+ /**
+ * Write the header.
+ *
+ * @param out a stream to write to.
+ */
+ public abstract void read(InputStream input);
+
+ /**
+ * Write the header.
+ *
+ * @param out a stream to write to.
+ */
+ public abstract void write(OutputStream output);
+}
diff --git a/libjava/classpath/gnu/CORBA/GIOP/CharSets_OSF.java b/libjava/classpath/gnu/CORBA/GIOP/CharSets_OSF.java
new file mode 100644
index 0000000..f3f35db
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/CharSets_OSF.java
@@ -0,0 +1,235 @@
+/* CharSets_OSF.java --
+ Copyright (C) 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 gnu.CORBA.GIOP;
+
+import java.nio.charset.Charset;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * This class contains the codes, used to identify character sets
+ * in CORBA. These codes are defined in Open Software Foundation (OSF)
+ * code set registry
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class CharSets_OSF
+{
+ public static final int ASCII = 0x00010020;
+ public static final int ISO8859_1 = 0x00010001;
+ public static final int ISO8859_2 = 0x00010002;
+ public static final int ISO8859_3 = 0x00010003;
+ public static final int ISO8859_4 = 0x00010004;
+ public static final int ISO8859_5 = 0x00010005;
+ public static final int ISO8859_6 = 0x00010006;
+ public static final int ISO8859_7 = 0x00010007;
+ public static final int ISO8859_8 = 0x00010008;
+ public static final int ISO8859_9 = 0x00010009;
+ public static final int ISO8859_15_FDIS = 0x0001000F;
+ public static final int UTF8 = 0x05010001;
+ public static final int UTF16 = 0x00010109;
+ public static final int UCS2 = 0x00010100;
+ public static final int Cp1047 = 0x10020417;
+ public static final int Cp1250 = 0x100204E2;
+ public static final int Cp1251 = 0x100204E3;
+ public static final int Cp1252 = 0x100204E4;
+ public static final int Cp1253 = 0x100204E5;
+ public static final int Cp1254 = 0x100204E6;
+ public static final int Cp1255 = 0x100204E7;
+ public static final int Cp1256 = 0x100204E8;
+ public static final int Cp1257 = 0x100204E9;
+ public static final int Cp1363 = 0x10020553;
+ public static final int Cp1363C = 0x10020553;
+ public static final int Cp1381 = 0x10020565;
+ public static final int Cp1383 = 0x10020567;
+ public static final int Cp1386 = 0x1002056A;
+ public static final int Cp33722 = 0x100283BA;
+ public static final int Cp33722C = 0x100283BA;
+ public static final int Cp930 = 0x100203A2;
+ public static final int Cp943 = 0x100203AF;
+ public static final int Cp943C = 0x100203AF;
+ public static final int Cp949 = 0x100203B5;
+ public static final int Cp949C = 0x100203B5;
+ public static final int Cp950 = 0x100203B6;
+ public static final int Cp964 = 0x100203C4;
+ public static final int Cp970 = 0x100203CA;
+ public static final int EUC_JP = 0x00030010;
+ public static final int EUC_KR = 0x0004000A;
+ public static final int EUC_TW = 0x00050010;
+
+ /**
+ * The native character set for the narrow character.
+ */
+ public static final int NATIVE_CHARACTER = ISO8859_1;
+
+ /**
+ * The native character set for the wide character.
+ */
+ public static final int NATIVE_WIDE_CHARACTER = UTF16;
+
+ /**
+ * Table to convert from the code to string name.
+ */
+ private static Hashtable code_to_string;
+
+ /**
+ * Table to convert from the string name to code.
+ */
+ private static Hashtable string_to_code;
+
+ /**
+ * Get the charset code from its name.
+ *
+ * @return the charset code of 0 if not defined.
+ */
+ public static int getCode(String name)
+ {
+ if (string_to_code == null)
+ makeMap();
+
+ Integer code = (Integer) string_to_code.get(name);
+ return code == null ? 0 : code.intValue();
+ }
+
+ /**
+ * Get the charset name from its code.
+ *
+ * @return the code set name or nullfor the unknown code set.
+ */
+ public static String getName(int code)
+ {
+ if (code_to_string == null)
+ makeMap();
+ return (String) code_to_string.get(new Integer(code));
+ }
+
+ /**
+ * Get the list of supported char sets for that the CORBA codes are
+ * also known.
+ */
+ public static int[] getSupportedCharSets()
+ {
+ Set supported_sets = Charset.availableCharsets().keySet();
+ int[] supported = new int[ supported_sets.size() ];
+ Iterator iter = supported_sets.iterator();
+
+ int i = 0;
+ int code;
+ while (iter.hasNext())
+ {
+ code = getCode(iter.next().toString());
+ if (code > 0)
+ supported [ i++ ] = code;
+ }
+
+ // Truncate the unused part.
+ int[] f = new int[ i ];
+ System.arraycopy(supported, 0, f, 0, f.length);
+
+ return f;
+ }
+
+ /**
+ * Create a convertion map.
+ */
+ private static void makeMap()
+ {
+ code_to_string = new Hashtable();
+ string_to_code = new Hashtable();
+
+ // Put standard char sets.
+ put(ASCII, "US-ASCII");
+ put(ISO8859_1, "ISO-8859-1");
+ put(UTF16, "UTF-16");
+
+ // Put other known char sets.
+ put(ISO8859_2, "ISO-8859-2");
+ put(ISO8859_3, "ISO-8859-3");
+ put(ISO8859_4, "ISO-8859-4");
+ put(ISO8859_5, "ISO-8859-5");
+ put(ISO8859_6, "ISO-8859-6");
+ put(ISO8859_7, "ISO-8859-7");
+ put(ISO8859_8, "ISO-8859-8");
+ put(ISO8859_9, "ISO-8859-9");
+
+ put(UTF8, "UTF-8");
+ put(UCS2, "UCS-2");
+
+ put(ISO8859_15_FDIS, "ISO8859-15-FDIS");
+
+ put(Cp1047, "Cp1047");
+ put(Cp1250, "Cp1250");
+ put(Cp1251, "Cp1251");
+ put(Cp1252, "Cp1252");
+ put(Cp1253, "Cp1253");
+ put(Cp1254, "Cp1254");
+ put(Cp1255, "Cp1255");
+ put(Cp1256, "Cp1256");
+ put(Cp1257, "Cp1257");
+ put(Cp1363, "Cp1363");
+ put(Cp1363C, "Cp1363C");
+ put(Cp1381, "Cp1381");
+ put(Cp1383, "Cp1383");
+ put(Cp1386, "Cp1386");
+ put(Cp33722, "Cp33722");
+ put(Cp33722C, "Cp33722C");
+ put(Cp930, "Cp930");
+ put(Cp943, "Cp943");
+ put(Cp943C, "Cp943C");
+ put(Cp949, "Cp949");
+ put(Cp949C, "Cp949C");
+ put(Cp950, "Cp950");
+ put(Cp964, "Cp964");
+ put(Cp970, "Cp970");
+
+ put(EUC_JP, "EUC-JP");
+ put(EUC_KR, "EUC-KR");
+ put(EUC_TW, "EUC-TW");
+ }
+
+ private static void put(int code, String name)
+ {
+ Integer ic = new Integer(code);
+
+ code_to_string.put(ic, name);
+ string_to_code.put(name, ic);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/GIOP/CloseMessage.java b/libjava/classpath/gnu/CORBA/GIOP/CloseMessage.java
new file mode 100644
index 0000000..d884329
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/CloseMessage.java
@@ -0,0 +1,102 @@
+/* CloseMessage.java --
+ Copyright (C) 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 gnu.CORBA.GIOP;
+
+import gnu.CORBA.IOR;
+
+import org.omg.CORBA.MARSHAL;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.net.Socket;
+
+/**
+ * The explicit command to close the connection.
+ *
+ *
+ * The close message consists from the message header only and
+ * is the same for GIOP 1.0, 1.1, 1.2 and 1.3. The CloseMessage
+ * uses the default value from the {@link MessageHeader}.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class CloseMessage
+ extends MessageHeader
+{
+ /**
+ * The singleton close message is typically enough, despite new
+ * instances may be instantiated if the specific version field
+ * value is mandatory.
+ */
+ private static final CloseMessage Singleton = new CloseMessage();
+
+ /**
+ * Create a new error message, setting the message field
+ * to the {@link MESSAGE_CLOSE} and the version number to
+ * the given major and minor values.
+ */
+ public CloseMessage()
+ {
+ message_type = CLOSE_CONNECTION;
+ }
+
+ /**
+ * Send the close message to the given output stream. The method,
+ * however, does not close the socket itself, this must be done
+ * explicitly in the calling code.
+ *
+ * @param socketStream a stream, where the close message is
+ * written.
+ */
+ public static void close(OutputStream socketStream)
+ {
+ try
+ {
+ Singleton.write(socketStream);
+ socketStream.flush();
+ }
+ catch (IOException ex)
+ {
+ MARSHAL m = new MARSHAL("Unable to flush the stream");
+ m.initCause(ex);
+ throw m;
+ }
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/GIOP/ErrorMessage.java b/libjava/classpath/gnu/CORBA/GIOP/ErrorMessage.java
new file mode 100644
index 0000000..8d3b353
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/ErrorMessage.java
@@ -0,0 +1,97 @@
+/* ErrorMessage.java --
+ Copyright (C) 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 gnu.CORBA.GIOP;
+
+import gnu.CORBA.IOR;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.net.Socket;
+
+import org.omg.CORBA.MARSHAL;
+
+/**
+ * The error message is sent in response to the message, encoded
+ * in the unsupported version of the format or otherwise invalid.
+ *
+ * The error message consists from the message header only and
+ * is the same for GIOP 1.0, 1.1, 1.2 and 1.3.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class ErrorMessage
+ extends MessageHeader
+{
+ /**
+ * Create a new error message, setting the message field
+ * to the {@link MESSAGE_ERROR} and the version number to
+ * the given major and minor values.
+ */
+ public ErrorMessage(gnu.CORBA.Version msg_version)
+ {
+ version = msg_version;
+ message_type = MESSAGE_ERROR;
+ }
+
+ /**
+ * Send the error message to the given IOR address.
+ *
+ * @param to the IOR address (host and port, other fields
+ * are not used).
+ */
+ public void send(IOR ior)
+ {
+ try
+ {
+ Socket socket = new Socket(ior.Internet.host, ior.Internet.port);
+
+ OutputStream socketOutput = socket.getOutputStream();
+ write(socketOutput);
+ socketOutput.close();
+ socket.close();
+ }
+ catch (IOException ex)
+ {
+ MARSHAL t = new MARSHAL();
+ t.initCause(ex);
+ throw t;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/GIOP/MessageHeader.java b/libjava/classpath/gnu/CORBA/GIOP/MessageHeader.java
new file mode 100644
index 0000000..61c46e1
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/MessageHeader.java
@@ -0,0 +1,350 @@
+/* MessageHeader.java -- GIOP 1.0 message header.
+ Copyright (C) 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 gnu.CORBA.GIOP;
+
+import gnu.CORBA.CDR.BigEndianOutputStream;
+import gnu.CORBA.CDR.LittleEndianInputStream;
+import gnu.CORBA.CDR.LittleEndianOutputStream;
+import gnu.CORBA.CDR.abstractDataOutputStream;
+import gnu.CORBA.Version;
+
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.portable.IDLEntity;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.util.Arrays;
+import gnu.CORBA.CDR.BigEndianInputStream;
+import gnu.CORBA.CDR.abstractDataInputStream;
+import java.io.InputStream;
+
+/**
+ * The GIOP message header.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class MessageHeader
+ implements IDLEntity
+{
+ /**
+ * Request message.
+ */
+ public static final byte REQUEST = 0;
+
+ /**
+ * Reply message
+ */
+ public static final byte REPLY = 1;
+
+ /**
+ * Cancel request message.
+ */
+ public static final byte CANCEL_REQUEST = 2;
+
+ /**
+ * Locate request message, used to check the server ability to
+ * process requests for the object reference.
+ * This message is also used to get the
+ * address where the object reference should be sent.
+ */
+ public static final byte LOCATE_REQUEST = 3;
+
+ /**
+ * Locate reply message, sent in response to the
+ * {@link #LocateRequest} message.
+ */
+ public static final byte LOCATE_REPLY = 4;
+
+ /**
+ * Instruction to close the connection.
+ */
+ public static final byte CLOSE_CONNECTION = 5;
+
+ /**
+ * Error report.
+ */
+ public static final byte MESSAGE_ERROR = 6;
+
+ /**
+ * The fragment messge, following the previous message that
+ * has more fragments flag set. Added in GIOP 1.1
+ */
+ public static final byte FRAGMENT = 7;
+
+ /**
+ * This must always be "GIOP".
+ */
+ public static final byte[] MAGIC = new byte[] { 'G', 'I', 'O', 'P' };
+
+ /**
+ * The message type names.
+ */
+ protected static String[] types =
+ new String[]
+ {
+ "Request", "Reply", "Cancel", "Locate request", "Locate reply",
+ "Close connection", "Error", "Fragment"
+ };
+
+ /**
+ * The GIOP version. Initialised to 1.0 .
+ */
+ public Version version;
+
+ /**
+ * The flags field, introduced since GIOP 1.1.
+ */
+ public byte flags = 0;
+
+ /**
+ * The message type.
+ */
+ public byte message_type = REQUEST;
+
+ /**
+ * The message size, excluding the message header.
+ */
+ public int message_size = 0;
+
+ /**
+ * Create an empty message header, corresponding version 1.0.
+ */
+ public MessageHeader()
+ {
+ version = new Version(1, 0);
+ }
+
+ /**
+ * Create an empty message header, corresponding the given version.
+ *
+ * @param major the major message header version.
+ * @param minor the minot message header version.
+ */
+ public MessageHeader(int major, int minor)
+ {
+ version = new Version(major, minor);
+ }
+
+ /**
+ * Checks if the message is encoded in the Big Endian, most significant
+ * byte first.
+ */
+ public boolean isBigEndian()
+ {
+ return (flags & 0x1) == 0;
+ }
+
+ /**
+ * Set the encoding to use.
+ *
+ * @param use_big_endian if true (default), the Big Endian
+ * encoding is used. If false, the Little Endian encoding is used.
+ */
+ public void setBigEndian(boolean use_big_endian)
+ {
+ if (use_big_endian)
+ flags = (byte) (flags & ~1);
+ else
+ flags = (byte) (flags | 1);
+ }
+
+ /**
+ * Get the size of the message header itself. So far, it is always 12 bytes.
+ */
+ public int getHeaderSize()
+ {
+ return 12;
+ }
+
+ /**
+ * Get the message type as string.
+ *
+ * @param type the message type as int (the field {@link message_type}).
+ *
+ * @return the message type as string.
+ */
+ public String getTypeString(int type)
+ {
+ try
+ {
+ return types [ type ];
+ }
+ catch (ArrayIndexOutOfBoundsException ex)
+ {
+ return "unknown type (" + type + ")";
+ }
+ }
+
+ /**
+ * Creates reply header, matching the message header version number.
+ *
+ * @return one of {@link gnu.CORBA.GIOP.v1_0.ReplyHeader},
+ * {@link gnu.CORBA.GIOP.v1_2.ReplyHeader}, etc - depending on
+ * the version number in this header.
+ */
+ public ReplyHeader create_reply_header()
+ {
+ if (version.since_inclusive(1, 2))
+ return new gnu.CORBA.GIOP.v1_2.ReplyHeader();
+ else
+ return new gnu.CORBA.GIOP.v1_0.ReplyHeader();
+ }
+
+ /**
+ * Creates request header, matching the message header version number.
+ *
+ * @return one of {@link gnu.CORBA.GIOP.v1_0.RequestHeader},
+ * {@link gnu.CORBA.GIOP.v1_2.RequestHeader}, etc - depending on
+ * the version number in this header.
+ */
+ public RequestHeader create_request_header()
+ {
+ if (version.since_inclusive(1, 2))
+ return new gnu.CORBA.GIOP.v1_2.RequestHeader();
+ else
+ return new gnu.CORBA.GIOP.v1_0.RequestHeader();
+ }
+
+ /**
+ * Create the cancel header, matching the message header version number.
+ */
+ public CancelHeader create_cancel_header()
+ {
+ return new gnu.CORBA.GIOP.v1_0.CancelHeader();
+ }
+
+ /**
+ * Create the error message.
+ */
+ public ErrorMessage create_error_message()
+ {
+ return new ErrorMessage(version);
+ }
+
+ /**
+ * Read the header from the stream.
+ *
+ * @param istream a stream to read from.
+ *
+ * @throws MARSHAL if this is not a GIOP 1.0 header.
+ */
+ public void read(java.io.InputStream istream)
+ throws MARSHAL
+ {
+ try
+ {
+ byte[] xMagic = new byte[ MAGIC.length ];
+ istream.read(xMagic);
+ if (!Arrays.equals(xMagic, MAGIC))
+ throw new MARSHAL("Not a GIOP message");
+
+ version = Version.read_version(istream);
+
+ abstractDataInputStream din;
+
+ flags = (byte) istream.read();
+
+ // This checks the bit in the byte we have just received.
+ if (isBigEndian())
+ din = new BigEndianInputStream(istream);
+ else
+ din = new LittleEndianInputStream(istream);
+
+ message_type = (byte) din.read();
+
+ message_size = din.readInt();
+ }
+ catch (IOException ex)
+ {
+ MARSHAL t = new MARSHAL();
+ t.initCause(ex);
+ throw t;
+ }
+ }
+
+ /**
+ * Get the short string summary of the message.
+ *
+ * @return a short message summary.
+ */
+ public String toString()
+ {
+ return "GIOP " + version + ", " + (isBigEndian() ? "Big" : "Little") +
+ " endian, " + getTypeString(message_type) + ", " + message_size +
+ " bytes. ";
+ }
+
+ /**
+ * Write the header to stream.
+ *
+ * @param out a stream to write into.
+ */
+ public void write(java.io.OutputStream out)
+ {
+ try
+ {
+ abstractDataOutputStream dout;
+
+ if (isBigEndian())
+ dout = new BigEndianOutputStream(out);
+ else
+ dout = new LittleEndianOutputStream(out);
+
+ // Write magic sequence.
+ dout.write(MAGIC);
+
+ // Write version number.
+ version.write((OutputStream) dout);
+
+ dout.write(flags);
+
+ dout.write(message_type);
+
+ dout.writeInt(message_size);
+ }
+ catch (IOException ex)
+ {
+ MARSHAL t = new MARSHAL();
+ t.initCause(ex);
+ throw t;
+ }
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/GIOP/ReplyHeader.java b/libjava/classpath/gnu/CORBA/GIOP/ReplyHeader.java
new file mode 100644
index 0000000..1e0e154
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/ReplyHeader.java
@@ -0,0 +1,156 @@
+/* ReplyHeader.java --
+ Copyright (C) 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 gnu.CORBA.GIOP;
+
+import gnu.CORBA.CDR.cdrInput;
+import gnu.CORBA.CDR.cdrOutput;
+
+
+/**
+ * The header of the standard reply.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public abstract class ReplyHeader
+{
+ /**
+ * Reply status, if no exception occured.
+ */
+ public static final int NO_EXCEPTION = 0;
+
+ /**
+ * Reply status, user exception.
+ */
+ public static final int USER_EXCEPTION = 1;
+
+ /**
+ * Reply status, system exception.
+ */
+ public static final int SYSTEM_EXCEPTION = 2;
+
+ /**
+ * Reply status, if the client ORB must re - send
+ * the request to another destination. The body
+ * contains IOR.
+ */
+ public static final int LOCATION_FORWARD = 3;
+
+ /**
+ * Reply status, indicating that the target has permanently changed the
+ * address to the supplied IOR.
+ */
+ public static final int LOCATION_FORWARD_PERM = 4;
+
+ /**
+ * Reply status, indicating, that the ORB requires to resend the object
+ * address in the required addressing mode, contained as the reply body.
+ */
+ public static final int NEEDS_ADDRESSING_MODE = 5;
+
+ /**
+ * Empty array, indicating that no service context is available.
+ */
+ protected static final ServiceContext[] NO_CONTEXT = new ServiceContext[ 0 ];
+
+ /**
+ * The ORB service data.
+ */
+ public ServiceContext[] service_context = NO_CONTEXT;
+
+ /**
+ * The status of this reply, holds one of the reply status constants.
+ */
+ public int reply_status;
+
+ /**
+ * The Id of request into response of which this reply has been sent.
+ */
+ public int request_id;
+
+ /**
+ * Return the message status as a string.
+ */
+ public String getStatusString()
+ {
+ switch (reply_status)
+ {
+ case NO_EXCEPTION :
+ return "ok";
+
+ case USER_EXCEPTION :
+ return "user exception";
+
+ case SYSTEM_EXCEPTION :
+ return "system exception";
+
+ case LOCATION_FORWARD :
+ return "moved";
+
+ default :
+ return null;
+ }
+ }
+
+ /**
+ * Reads the header from the stream.
+ *
+ * @param in a stream to read from.
+ */
+ public abstract void read(cdrInput in);
+
+ /**
+ * Returns a short string representation.
+ *
+ * @return a string representation.
+ */
+ public String toString()
+ {
+ String status = getStatusString();
+ if (status == null)
+ status = "status " + reply_status;
+ return request_id + ", " + status;
+ }
+
+ /**
+ * Writes the header to the stream.
+ *
+ * @param out a stream to write into.
+ */
+ public abstract void write(cdrOutput out);
+}
diff --git a/libjava/classpath/gnu/CORBA/GIOP/RequestHeader.java b/libjava/classpath/gnu/CORBA/GIOP/RequestHeader.java
new file mode 100644
index 0000000..f2de4e2
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/RequestHeader.java
@@ -0,0 +1,161 @@
+/* RequestHeader.java -- The GIOP 1.0 request message.
+ Copyright (C) 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 gnu.CORBA.GIOP;
+
+import gnu.CORBA.CDR.cdrInput;
+import gnu.CORBA.CDR.cdrOutput;
+
+
+import org.omg.CORBA.portable.IDLEntity;
+
+/**
+ * The GIOP request message.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public abstract class RequestHeader
+ implements IDLEntity
+{
+ /**
+ * The currently free request id. This field is incremented
+ * each time the new request header is constructed. To facilitate
+ * error detection, the first free id is equal to 0x01234567
+ * (19088743).
+ */
+ private static int freeId = 0x01234567;
+
+ /**
+ * The operation being invoked (IDL scope name).
+ */
+ public String operation;
+
+ /**
+ * Identifies the object that is the target of the invocation.
+ */
+ public byte[] object_key;
+
+ /**
+ * A value identifying the requesting principal.
+ * Initialised into a single zero byte.
+ *
+ * @deprecated by CORBA 2.2.
+ */
+ public byte[] requesting_principal;
+
+ /**
+ * Contains the ORB service data being passed. Initialised as the
+ * zero size array by default.
+ */
+ public ServiceContext[] service_context = new ServiceContext[ 0 ];
+
+ /**
+ * This is used to associate the reply message with the
+ * previous request message. Initialised each time by the
+ * different value, increasing form 1 to Integer.MAX_VALUE.
+ */
+ public int request_id = getNextId();
+
+ /**
+ * If true, the response from the server is expected.
+ */
+ protected boolean response_expected = true;
+
+ /**
+ * Get next free request id. The value of the free request
+ * id starts from 0x02345678, it is incremented each time this
+ * function is called and is reset to 1 after reaching
+ * Integer.MAX_VALUE.
+ *
+ * @return the next free request id.
+ */
+ public static synchronized int getNextId()
+ {
+ int f = freeId;
+ if (freeId == Integer.MAX_VALUE)
+ freeId = 1;
+ else
+ freeId++;
+
+ return f;
+ }
+
+ /**
+ * Set if the sender expects any response to this message.
+ */
+ public abstract void setResponseExpected(boolean expected);
+
+ /**
+ * Return true if response is expected.
+ */
+ public abstract boolean isResponseExpected();
+
+ /**
+ * Converts an byte array into hexadecimal string values.
+ * Used in various toString() methods.
+ */
+ public String bytes(byte[] array)
+ {
+ StringBuffer b = new StringBuffer();
+ for (int i = 0; i < array.length; i++)
+ {
+ b.append(Integer.toHexString(array [ i ] & 0xFF));
+ b.append(" ");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Reads the header from the stream.
+ *
+ * @param in a stream to read from.
+ */
+ public abstract void read(cdrInput in);
+
+ /**
+ * Return a string representation.
+ */
+ public abstract String toString();
+
+ /**
+ * Writes the header to the stream.
+ *
+ * @param out a stream to write into.
+ */
+ public abstract void write(cdrOutput out);
+}
diff --git a/libjava/classpath/gnu/CORBA/GIOP/ServiceContext.java b/libjava/classpath/gnu/CORBA/GIOP/ServiceContext.java
new file mode 100644
index 0000000..7e44bdce
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/ServiceContext.java
@@ -0,0 +1,131 @@
+/* ServiceContext.java --
+ Copyright (C) 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 gnu.CORBA.GIOP;
+
+import gnu.CORBA.CDR.cdrInput;
+import gnu.CORBA.CDR.cdrOutput;
+
+
+import org.omg.CORBA.portable.IDLEntity;
+
+/**
+ * Contains the ORB service data being passed.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class ServiceContext
+ implements IDLEntity
+{
+ /**
+ * The context data.
+ */
+ public byte[] context_data;
+
+ /**
+ * The context id.
+ */
+ public int context_id;
+
+ /**
+ * Read the context values from the stream.
+ *
+ * @param istream a stream to read from.
+ */
+ public static ServiceContext read(cdrInput istream)
+ {
+ int id = istream.read_ulong();
+
+ switch (id)
+ {
+ case cxCodeSet.ID :
+
+ cxCodeSet codeset = new cxCodeSet();
+ codeset.readContext(istream);
+ return codeset;
+
+ default :
+
+ ServiceContext ctx = new ServiceContext();
+ ctx.context_id = id;
+ ctx.context_data = istream.read_sequence();
+ return ctx;
+ }
+ }
+
+ /**
+ * Read a sequence of contexts from the input stream.
+ */
+ public static ServiceContext[] readSequence(cdrInput istream)
+ {
+ int size = istream.read_long();
+ ServiceContext[] value = new gnu.CORBA.GIOP.ServiceContext[ size ];
+ for (int i = 0; i < value.length; i++)
+ value [ i ] = read(istream);
+ return value;
+ }
+
+ /**
+ * Write the context values into the stream.
+ *
+ * @param ostream a stream to write the data to.
+ */
+ public void write(cdrOutput ostream)
+ {
+ ostream.write_ulong(context_id);
+ ostream.write_sequence(context_data);
+ }
+
+ /**
+ * Write the sequence of contexts into the input stream.
+ */
+ public static void writeSequence(cdrOutput ostream, ServiceContext[] value)
+ {
+ ostream.write_long(value.length);
+ for (int i = 0; i < value.length; i++)
+ value [ i ].write(ostream);
+ }
+
+ /**
+ * Return a string representation.
+ */
+ public String toString()
+ {
+ return "ctx "+context_id+", size "+context_data.length;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/GIOP/cxCodeSet.java b/libjava/classpath/gnu/CORBA/GIOP/cxCodeSet.java
new file mode 100644
index 0000000..7f42c07
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/cxCodeSet.java
@@ -0,0 +1,224 @@
+/* CodeSet_sctx.java --
+ Copyright (C) 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 gnu.CORBA.GIOP;
+
+import gnu.CORBA.CDR.cdrInput;
+import gnu.CORBA.CDR.cdrOutput;
+import gnu.CORBA.IOR;
+import gnu.CORBA.IOR.CodeSets_profile;
+
+import java.io.IOException;
+
+/**
+ * The code set service context. This context must be included in all
+ * messages that use wide characters.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class cxCodeSet
+ extends ServiceContext
+{
+ /**
+ * The context code sets id.
+ */
+ public static final int ID = 1;
+
+ /**
+ * The standard component to include in the messages.
+ */
+ public static final cxCodeSet STANDARD = new cxCodeSet();
+
+ /**
+ * The encoding, used to transfer the narrow (1 byte) character data.
+ * The default value is taken from {@link CharSets_OSF#NATIVE_CHARACTER}.
+ */
+ public int char_data = CharSets_OSF.NATIVE_CHARACTER;
+
+ /**
+ * The encoding, used to transfer the wide character data.
+ * The default value is taken from
+ * {@link CharSets_OSF#NATIVE_WIDE_CHARACTER}.
+ */
+ public int wide_char_data = CharSets_OSF.NATIVE_WIDE_CHARACTER;
+
+ /**
+ * Find and return the code set service context in the give
+ * contexts array. Returns {@link #STANDARD} if no code set
+ * context is present.
+ *
+ * @param contexts the array of contexts, can be null.
+ */
+ public static cxCodeSet find(ServiceContext[] contexts)
+ {
+ if (contexts != null)
+ for (int i = 0; i < contexts.length; i++)
+ {
+ if (contexts [ i ] instanceof cxCodeSet)
+ return (cxCodeSet) contexts [ i ];
+ }
+ return STANDARD;
+ }
+
+ /**
+ * Select the suitable encoding that is defined in the provided profile.
+ *
+ * TODO character encoding. Now the encoding can be set, but it is ignored.
+ * If you take this task, scan 'TODO character encoding' for
+ * relevant places.
+ */
+ public static cxCodeSet negotiate(IOR.CodeSets_profile profile)
+ {
+ if (profile.negotiated != null)
+ return profile.negotiated;
+
+ cxCodeSet use = new cxCodeSet();
+
+ use.char_data =
+ negotiate(profile.narrow, STANDARD.char_data, CharSets_OSF.ISO8859_1);
+
+ use.wide_char_data =
+ negotiate(profile.wide, STANDARD.wide_char_data, CharSets_OSF.UTF16);
+
+ profile.negotiated = use;
+
+ return use;
+ }
+
+ /**
+ * Read the context from the given stream. Does not read the
+ * code sets id.
+ */
+ public void readContext(cdrInput input)
+ {
+ cdrInput encap = input.read_encapsulation();
+
+ char_data = encap.read_ulong();
+ wide_char_data = encap.read_ulong();
+ }
+
+ /**
+ * Return a string representation.
+ */
+ public String toString()
+ {
+ return " Encoding: narrow " + name(char_data) + ", wide " +
+ name(wide_char_data) + ". ";
+ }
+
+ /**
+ * Write the context to the given stream, including the code
+ * sets id.
+ */
+ public void write(cdrOutput output)
+ {
+ output.write_ulong(ID);
+
+ cdrOutput enout = output.createEncapsulation();
+
+ enout.write_long(char_data);
+ enout.write_ulong(wide_char_data);
+
+ try
+ {
+ enout.close();
+ }
+ catch (IOException ex)
+ {
+ InternalError t = new InternalError();
+ t.initCause(ex);
+ throw t;
+ }
+ }
+
+ /**
+ * Negotiate about the character encoding. Prefer our native encoding,
+ * if no, prefer IORs native encoding, if no, find any encoding,
+ * supported by both sides, if no, return the specified final decission.
+ *
+ * @param profile the component profile in IOR.
+ * @param our_native our native encoding
+ * @param final_decission the encoding that must be returned if no
+ * compromise is found.
+ *
+ * @return the resulted encoding.
+ */
+ protected static int negotiate(IOR.CodeSets_profile.CodeSet_component profile,
+ int our_native, int final_decission
+ )
+ {
+ // If our and IORs native sets match, use the native set.
+ if (profile.native_set == our_native)
+ return our_native;
+
+ // If the native sets do not match, but the IOR says it
+ // supports our native set, use our native set.
+ if (profile.conversion != null)
+ for (int i = 0; i < profile.conversion.length; i++)
+ {
+ if (our_native == profile.conversion [ i ])
+ return our_native;
+ }
+
+ // At this point, we suggest to use the IORs native set.
+ int[] allSupported = CharSets_OSF.getSupportedCharSets();
+
+ for (int s = 0; s < allSupported.length; s++)
+ if (allSupported [ s ] == profile.native_set)
+ return profile.native_set;
+
+ // Any compromise left?
+ if (profile.conversion != null)
+ for (int s = 0; s < allSupported.length; s++)
+ for (int i = 0; i < profile.conversion.length; i++)
+ if (allSupported [ s ] == profile.conversion [ i ])
+ return allSupported [ s ];
+
+ // Return the CORBA default char encoding.
+ return final_decission;
+ }
+
+ /**
+ * Conveniency method, used in toString()
+ */
+ private String name(int set)
+ {
+ return "0x" + Integer.toHexString(set) + " (" + CharSets_OSF.getName(set) +
+ ") ";
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/GIOP/v1_0/CancelHeader.java b/libjava/classpath/gnu/CORBA/GIOP/v1_0/CancelHeader.java
new file mode 100644
index 0000000..6e3650c
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/v1_0/CancelHeader.java
@@ -0,0 +1,72 @@
+/* CancelHeader.java --
+ Copyright (C) 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 gnu.CORBA.GIOP.v1_0;
+
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+
+/**
+ * The message header for cancelling the request.
+ *
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class CancelHeader
+ extends gnu.CORBA.GIOP.CancelHeader
+{
+ /**
+ * Write the header.
+ *
+ * @param out a stream to write to.
+ */
+ public void read(InputStream input)
+ {
+ request_id = input.read_ulong();
+ }
+
+ /**
+ * Write the header.
+ *
+ * @param out a stream to write to.
+ */
+ public void write(OutputStream output)
+ {
+ output.write_ulong(request_id);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/GIOP/v1_0/ReplyHeader.java b/libjava/classpath/gnu/CORBA/GIOP/v1_0/ReplyHeader.java
new file mode 100644
index 0000000..27181ca
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/v1_0/ReplyHeader.java
@@ -0,0 +1,139 @@
+/* ReplyHeader.java --
+ Copyright (C) 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 gnu.CORBA.GIOP.v1_0;
+
+import gnu.CORBA.CDR.cdrInput;
+import gnu.CORBA.CDR.cdrOutput;
+import gnu.CORBA.GIOP.ServiceContext;
+import gnu.CORBA.GIOP.cxCodeSet;
+
+/**
+ * The header of the standard reply.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class ReplyHeader
+ extends gnu.CORBA.GIOP.ReplyHeader
+{
+ /**
+ * Return the message status as a string.
+ */
+ public String getStatusString()
+ {
+ switch (reply_status)
+ {
+ case NO_EXCEPTION :
+ return "ok";
+
+ case USER_EXCEPTION :
+ return "user exception";
+
+ case SYSTEM_EXCEPTION :
+ return "system exception";
+
+ case LOCATION_FORWARD :
+ return "moved";
+
+ default :
+ return null;
+ }
+ }
+
+ /**
+ * Get the string representation of all included contexts.
+ */
+ public String contexts()
+ {
+ StringBuffer b = new StringBuffer();
+ for (int i = 0; i < service_context.length; i++)
+ {
+ b.append(service_context [ i ].toString());
+ b.append(' ');
+ }
+ return b.toString();
+ }
+
+ /**
+ * Reads the header from the stream.
+ *
+ * Sets the code set of this stream to
+ * the code set, specfied in the header.
+ *
+ * @param in a stream to read from.
+ */
+
+ public void read(cdrInput in)
+ {
+ service_context = ServiceContext.readSequence(in);
+ request_id = in.read_ulong();
+ reply_status = in.read_ulong();
+
+ in.setCodeSet(cxCodeSet.find(service_context));
+ }
+
+ /**
+ * Returns a short string representation.
+ *
+ * @return a string representation.
+ */
+ public String toString()
+ {
+ String status = getStatusString();
+ if (status == null)
+ status = "status " + reply_status;
+ return request_id + ", " + status + " " + contexts();
+ }
+
+ /**
+ * Writes the header to the stream.
+ *
+ * Sets the code set of this stream to
+ * the code set, specfied in the header.
+ *
+ * @param out a stream to write into.
+ */
+ public void write(cdrOutput out)
+ {
+ ServiceContext.writeSequence(out, service_context);
+ out.write_ulong(request_id);
+ out.write_ulong(reply_status);
+
+ out.setCodeSet(cxCodeSet.find(service_context));
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/GIOP/v1_0/RequestHeader.java b/libjava/classpath/gnu/CORBA/GIOP/v1_0/RequestHeader.java
new file mode 100644
index 0000000..ffa45c3
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/v1_0/RequestHeader.java
@@ -0,0 +1,157 @@
+/* RequestHeader.java -- The GIOP 1.0 request message.
+ Copyright (C) 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 gnu.CORBA.GIOP.v1_0;
+
+import gnu.CORBA.CDR.cdrInput;
+import gnu.CORBA.CDR.cdrOutput;
+
+import org.omg.CORBA.portable.IDLEntity;
+import gnu.CORBA.GIOP.ServiceContext;
+import gnu.CORBA.GIOP.cxCodeSet;
+
+/**
+ * The GIOP 1.0 request message.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class RequestHeader
+ extends gnu.CORBA.GIOP.RequestHeader
+ implements IDLEntity
+{
+ /**
+ * Creates an empty request header, setting requesting principal
+ * to byte[] { 'P' }.
+ */
+ public RequestHeader()
+ {
+ requesting_principal = new byte[] { 'P' };
+ }
+
+ /**
+ * Set if the sender expects any response to this message.
+ */
+ public void setResponseExpected(boolean expected)
+ {
+ response_expected = expected;
+ }
+
+ /**
+ * Return true if response is expected.
+ */
+ public boolean isResponseExpected()
+ {
+ return response_expected;
+ }
+
+ public String bytes(byte[] array)
+ {
+ StringBuffer b = new StringBuffer();
+ for (int i = 0; i < array.length; i++)
+ {
+ b.append(Integer.toHexString(array [ i ] & 0xFF));
+ b.append(" ");
+ }
+ return b.toString();
+ }
+
+ /**
+ * Get the string representation of all included contexts.
+ */
+ public String contexts()
+ {
+ StringBuffer b = new StringBuffer();
+ for (int i = 0; i < service_context.length; i++)
+ {
+ b.append(service_context [ i ].toString());
+ b.append(' ');
+ }
+ return b.toString();
+ }
+
+ /**
+ * Reads the header from the stream.
+ *
+ * Sets the code set of this stream to
+ * the code set, specfied in the header.
+ *
+ * @param in a stream to read from.
+ */
+ public void read(cdrInput in)
+ {
+ service_context = ServiceContext.readSequence(in);
+ request_id = in.read_ulong();
+ response_expected = in.read_boolean();
+ object_key = in.read_sequence();
+ operation = in.read_string();
+ requesting_principal = in.read_sequence();
+
+ in.setCodeSet(cxCodeSet.find(service_context));
+ }
+
+ /**
+ * Return a string representation.
+ */
+ public String toString()
+ {
+ return "Request " + request_id + ", call '" + operation + "' on " +
+ bytes(object_key) + ", " +
+ (response_expected ? "wait response" : "one way") + ", from " +
+ bytes(requesting_principal) + contexts();
+ }
+
+ /**
+ * Writes the header to the stream.
+ *
+ * Sets the code set of this stream to
+ * the code set, specfied in the header.
+ *
+ * @param out a stream to write into.
+ */
+ public void write(cdrOutput out)
+ {
+ ServiceContext.writeSequence(out, service_context);
+ out.write_ulong(request_id);
+ out.write_boolean(response_expected);
+ out.write_sequence(object_key);
+ out.write_string(operation);
+ out.write_sequence(requesting_principal);
+
+ out.setCodeSet(cxCodeSet.find(service_context));
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/GIOP/v1_2/ReplyHeader.java b/libjava/classpath/gnu/CORBA/GIOP/v1_2/ReplyHeader.java
new file mode 100644
index 0000000..c3f51a3
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/v1_2/ReplyHeader.java
@@ -0,0 +1,118 @@
+/* ReplyHeader.java --
+ Copyright (C) 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 gnu.CORBA.GIOP.v1_2;
+
+import gnu.CORBA.CDR.cdrInput;
+import gnu.CORBA.CDR.cdrOutput;
+import gnu.CORBA.GIOP.ServiceContext;
+import gnu.CORBA.GIOP.cxCodeSet;
+
+/**
+ * GIOP 1.2 reply header.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class ReplyHeader
+ extends gnu.CORBA.GIOP.v1_0.ReplyHeader
+{
+ /**
+ * Adds the standard encoding context.
+ */
+ public ReplyHeader()
+ {
+ service_context = new ServiceContext[] { cxCodeSet.STANDARD };
+ }
+
+ /**
+ * Return the message status as a string.
+ */
+ public String getStatusString()
+ {
+ String s = super.getStatusString();
+ if (s != null)
+ return s;
+ switch (reply_status)
+ {
+ case LOCATION_FORWARD_PERM :
+ return "moved permanently";
+
+ case NEEDS_ADDRESSING_MODE :
+ return "the alternative addressing mode required";
+
+ default :
+ return null;
+ }
+ }
+
+ /**
+ * Reads the header from the stream.
+ * The fields go in different order than in the previous GIOP versions.
+ *
+ * Sets the code set of this stream to
+ * the code set, specfied in the header.
+ *
+ * @param in a stream to read from.
+ */
+ public void read(cdrInput in)
+ {
+ request_id = in.read_ulong();
+ reply_status = in.read_ulong();
+ service_context = gnu.CORBA.GIOP.ServiceContext.readSequence(in);
+
+ in.setCodeSet(cxCodeSet.find(service_context));
+ }
+
+ /**
+ * Writes the header to the stream.
+ * The fields go in different order than in the previous GIOP versions.
+ *
+ * Sets the code set of this stream to
+ * the code set, specfied in the header.
+ *
+ * @param out a stream to write into.
+ */
+ public void write(cdrOutput out)
+ {
+ out.write_ulong(request_id);
+ out.write_ulong(reply_status);
+ gnu.CORBA.GIOP.ServiceContext.writeSequence(out, service_context);
+
+ out.setCodeSet(cxCodeSet.find(service_context));
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/GIOP/v1_2/RequestHeader.java b/libjava/classpath/gnu/CORBA/GIOP/v1_2/RequestHeader.java
new file mode 100644
index 0000000..d294d00
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/GIOP/v1_2/RequestHeader.java
@@ -0,0 +1,213 @@
+/* RequestHeader.java --
+ Copyright (C) 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 gnu.CORBA.GIOP.v1_2;
+
+import gnu.CORBA.CDR.cdrInput;
+import gnu.CORBA.CDR.cdrOutput;
+import gnu.CORBA.GIOP.ServiceContext;
+import gnu.CORBA.GIOP.cxCodeSet;
+
+import java.io.IOException;
+
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.NO_IMPLEMENT;
+
+/**
+ * The GIOP 1.2 request header. The GIOP 1.1 request header
+ * is the same as GIOP 1.0 request header, if taking the
+ * alignment into consideration.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class RequestHeader
+ extends gnu.CORBA.GIOP.v1_0.RequestHeader
+{
+ /**
+ * Indicates that the object is addressed by the object key.
+ */
+ public static final short KeyAddr = 0;
+
+ /**
+ * Indicates that the object is addressed by the IOP tagged profile.
+ */
+ public static final short ProfileAddr = 1;
+
+ /**
+ * Indicates that the objec is addressed by IOR addressing info.
+ */
+ public static final short ReferenceAddr = 2;
+
+ /**
+ * The response flags of the header. By default, the flags are initialised
+ * by value 0x3 (response expected).
+ */
+ public byte response_flags = 3;
+
+ /**
+ * The used addressing method.
+ */
+ public short AddressingDisposition;
+
+ /**
+ * Adds the standard encoding context.
+ */
+ public RequestHeader()
+ {
+ service_context = new ServiceContext[] { cxCodeSet.STANDARD };
+ }
+
+ /**
+ * Set if the sender expects any response to this message.
+ * Clears or sets the 2 lower bits of flags
+ * (0 - not expected, 0x3 - expected).
+ */
+ public void setResponseExpected(boolean expected)
+ {
+ response_expected = expected;
+
+ if (expected)
+ response_flags = (byte) (response_flags | 0x3);
+ else
+ response_flags = (byte) (response_flags & (~0x3));
+ }
+
+ /**
+ * Return true if response is expected.
+ *
+ * @return true if the two lowest bits of the flags are set or
+ * the response expected is explicitly set to true.
+ */
+ public boolean isResponseExpected()
+ {
+ return response_expected || ((response_flags & 0x3) == 0x3);
+ }
+
+ /**
+ * Read the header from the given stream.
+ *
+ * @param in a stream to read from.
+ */
+ public void read(cdrInput in)
+ {
+ try
+ {
+ request_id = in.read_ulong();
+ response_flags = (byte) in.read();
+
+ // Skip 3 reserved octets:
+ in.skip(3);
+
+ // Read target address.
+ AddressingDisposition = in.read_ushort();
+
+ switch (AddressingDisposition)
+ {
+ case KeyAddr :
+ object_key = in.read_sequence();
+ break;
+
+ // TODO FIXME add other addressing methods.
+ case ProfileAddr :
+ throw new NO_IMPLEMENT("Object addressing by IOP tagged profile");
+
+ case ReferenceAddr :
+ throw new NO_IMPLEMENT("Object addressing by by IOR addressing info");
+
+ default :
+ throw new MARSHAL("Unknow addressing method in request, " +
+ AddressingDisposition
+ );
+ }
+
+ operation = in.read_string();
+ service_context = gnu.CORBA.GIOP.ServiceContext.readSequence(in);
+
+ // No requesting principal in this new format.
+ in.setCodeSet(cxCodeSet.find(service_context));
+ }
+ catch (IOException ex)
+ {
+ MARSHAL t = new MARSHAL();
+ t.initCause(ex);
+ throw t;
+ }
+ }
+
+ /**
+ * Return a string representation.
+ */
+ public String toString()
+ {
+ return "Request " + request_id + ", call '" + operation + "' on " +
+ bytes(object_key) + ", " +
+ (response_expected ? "wait response" : "one way") +
+ " addressed by " + " method " + AddressingDisposition + "." +
+ contexts();
+ }
+
+ /**
+ * Write the header to the given stream.
+ *
+ * @param out a stream to write into.
+ */
+ public void write(cdrOutput out)
+ {
+ out.write_ulong(request_id);
+
+ out.write(response_flags);
+
+ // Skip 3 reserved octets:
+ out.write(0);
+ out.write(0);
+ out.write(0);
+
+ // Write addressing disposition from IOR.
+ // TODO FIXME add other addressing methods.
+ out.write_ushort(KeyAddr);
+
+ out.write_sequence(object_key);
+
+ out.write_string(operation);
+
+ ServiceContext.writeSequence(out, service_context);
+
+ // No requesting principal in this new format.
+ out.setCodeSet(cxCodeSet.find(service_context));
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/IOR.java b/libjava/classpath/gnu/CORBA/IOR.java
new file mode 100644
index 0000000..cedbce4
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/IOR.java
@@ -0,0 +1,563 @@
+/* IOR.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufInput;
+import gnu.CORBA.CDR.cdrBufOutput;
+import gnu.CORBA.CDR.cdrInput;
+import gnu.CORBA.CDR.cdrOutput;
+import gnu.CORBA.GIOP.CharSets_OSF;
+import gnu.CORBA.GIOP.cxCodeSet;
+
+import org.omg.CORBA.BAD_PARAM;
+import org.omg.CORBA.CompletionStatus;
+import org.omg.CORBA.ULongSeqHelper;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * The implementaton of the Interoperable Object Reference (IOR).
+ * IOR can be compared with the Internet address for a web page,
+ * it provides means to locate the CORBA service on the web.
+ * IOR contains the host address, port number, the object identifier
+ * (key) inside the server, the communication protocol version,
+ * supported charsets and so on.
+ *
+ * Ths class provides method for encoding and
+ * decoding the IOR information from/to the stringified references,
+ * usually returned by {@link org.omg.CORBA.ORB#String object_to_string()}.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ *
+ * @see org.mog.CORBA.Object.object_to_string(Object forObject)
+ * @see string_to_object(String IOR)
+ */
+public class IOR
+{
+ /**
+ * The code sets profile.
+ */
+ public static class CodeSets_profile
+ {
+ /**
+ * The code set component.
+ */
+ public static class CodeSet_component
+ {
+ /**
+ * The conversion code sets.
+ */
+ public int[] conversion;
+
+ /**
+ * The native code set.
+ */
+ public int native_set;
+
+ /**
+ * Read from the CDR stream.
+ */
+ public void read(org.omg.CORBA.portable.InputStream in)
+ {
+ native_set = in.read_ulong();
+ conversion = ULongSeqHelper.read(in);
+ }
+
+ /**
+ * Get a string representation.
+ */
+ public String toString()
+ {
+ StringBuffer b = new StringBuffer();
+ b.append("native " + name(native_set));
+ if (conversion != null && conversion.length > 0)
+ {
+ b.append(" conversion ");
+ for (int i = 0; i < conversion.length; i++)
+ {
+ b.append(name(conversion [ i ]));
+ b.append(' ');
+ }
+ }
+ b.append(' ');
+ return b.toString();
+ }
+
+ /**
+ * Write into CDR stream.
+ */
+ public void write(org.omg.CORBA.portable.OutputStream out)
+ {
+ out.write_long(native_set);
+ ULongSeqHelper.write(out, conversion);
+ }
+
+ private String name(int set)
+ {
+ return "0x" + Integer.toHexString(set) + " (" +
+ CharSets_OSF.getName(set) + ") ";
+ }
+ }
+
+ /**
+ * The agreed tag for the Codesets profile.
+ */
+ public static final int TAG_CODE_SETS = 1;
+
+ /**
+ * Information about narrow character encoding (TCS-C).
+ */
+ public CodeSet_component narrow = new CodeSet_component();
+
+ /**
+ * About wide character encoding (TCS-W).
+ */
+ public CodeSet_component wide = new CodeSet_component();
+
+ /**
+ * The negotiated coding result for this IOR. Saves time, requred for
+ * negotiation computations.
+ */
+ public cxCodeSet negotiated;
+
+ /**
+ * Read the code set profile information from the given input stream.
+ *
+ * @param profile a stream to read from.
+ */
+ public void read(cdrInput profile)
+ {
+ cdrBufInput encapsulation = profile.read_encapsulation();
+ narrow.read(encapsulation);
+ wide.read(encapsulation);
+ }
+
+ /**
+ * Returns a string representation.
+ */
+ public String toString()
+ {
+ return "Narrow char: " + narrow + ", Wide char: " + wide;
+ }
+
+ /**
+ * Write the code set profile information into the given input stream.
+ *
+ * @param profile a stream to write into.
+ */
+ public void write(cdrOutput profile)
+ {
+ cdrOutput encapsulation = profile.createEncapsulation();
+ narrow.write(encapsulation);
+ wide.write(encapsulation);
+ try
+ {
+ encapsulation.close();
+ }
+ catch (IOException ex)
+ {
+ throw new InternalError();
+ }
+ }
+ }
+
+ /**
+ * The internet profile.
+ */
+ public static class Internet_profile
+ {
+ /**
+ * The agreed tag for the Internet profile.
+ */
+ public static final int TAG_INTERNET_IOP = 0;
+
+ /**
+ * The host.
+ */
+ public String host;
+
+ /**
+ * The IIOP version (initialised to 1.2 by default).
+ */
+ public Version version = new Version(1, 2);
+
+ /**
+ * The port.
+ */
+ public int port;
+
+ /**
+ * Return the human readable representation.
+ */
+ public String toString()
+ {
+ StringBuffer b = new StringBuffer();
+ b.append(host);
+ b.append(":");
+ b.append(port);
+ b.append(" (v");
+ b.append(version);
+ b.append(")");
+ return b.toString();
+ }
+ }
+
+ /**
+ * The standard minor code, indicating that the string to object
+ * converstio has failed due non specific reasons.
+ */
+ public static final int FAILED = 10;
+
+ /**
+ * The code sets profile of this IOR.
+ */
+ public CodeSets_profile CodeSets = new CodeSets_profile();
+
+ /**
+ * The internet profile of this IOR.
+ */
+ public Internet_profile Internet = new Internet_profile();
+
+ /**
+ * The object repository Id.
+ */
+ public String Id;
+
+ /**
+ * The additional tagged components, encapsulated in
+ * the byte arrays. They are only supported by the
+ * later versions, than currently implemented.
+ */
+ public byte[][] extra;
+
+ /**
+ * The object key.
+ */
+ public byte[] key;
+
+ /**
+ * True if the profile was encoded using the Big Endian or
+ * the encoding is not known.
+ *
+ * false if it was encoded using the Little Endian.
+ */
+ public boolean Big_Endian = true;
+
+ /**
+ * Create an empty instance, initialising the code sets to default
+ * values.
+ */
+ public IOR()
+ {
+ int[] supported = CharSets_OSF.getSupportedCharSets();
+
+ CodeSets.narrow.native_set = CharSets_OSF.NATIVE_CHARACTER;
+ CodeSets.narrow.conversion = supported;
+
+ CodeSets.wide.native_set = CharSets_OSF.NATIVE_WIDE_CHARACTER;
+ CodeSets.wide.conversion = supported;
+ }
+
+ /**
+ * Parse the provided stringifed reference.
+ *
+ * @param stringified_reference, in the form of
+ * IOR:nnnnnn.....
+ *
+ * @return the parsed IOR
+ *
+ * @throws BAD_PARAM, minor code 10, if the IOR cannot be parsed.
+ *
+ * TODO corballoc and other alternative formats.
+ */
+ public static IOR parse(String stringified_reference)
+ throws BAD_PARAM
+ {
+ try
+ {
+ if (!stringified_reference.startsWith("IOR:"))
+ throw new BAD_PARAM("The string refernce must start with IOR:",
+ FAILED, CompletionStatus.COMPLETED_NO
+ );
+
+ IOR r = new IOR();
+
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ String x = stringified_reference;
+ x = x.substring(x.indexOf(":") + 1);
+
+ char cx;
+
+ for (int i = 0; i < x.length(); i = i + 2)
+ {
+ cx = (char) Integer.parseInt(x.substring(i, i + 2), 16);
+ buf.write(cx);
+ }
+
+ cdrBufInput cdr = new cdrBufInput(buf.toByteArray());
+
+ r._read(cdr);
+ return r;
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ throw new BAD_PARAM(ex + " while parsing " + stringified_reference,
+ FAILED, CompletionStatus.COMPLETED_NO
+ );
+ }
+ }
+
+ /**
+ * Read the IOR from the provided input stream.
+ *
+ * @param c a stream to read from.
+ * @throws IOException if the stream throws it.
+ */
+ public void _read(cdrInput c)
+ throws IOException, BAD_PARAM
+ {
+ int endian;
+
+ endian = c.read_long();
+ if (endian != 0)
+ {
+ Big_Endian = false;
+ c.setBigEndian(false);
+ }
+ _read_no_endian(c);
+ }
+
+ /**
+ * Read the IOR from the provided input stream, not reading
+ * the endian data at the beginning of the stream. The IOR is
+ * thansferred in this form in
+ * {@link write_Object(org.omg.CORBA.Object)}.
+ *
+ * If the stream contains a null value, the Id and Internet fields become
+ * equal to null. Otherwise Id contains some string (possibly
+ * empty).
+ *
+ * Id is checked for null in cdrInput that then returns
+ * null instead of object.
+ *
+ * @param c a stream to read from.
+ * @throws IOException if the stream throws it.
+ */
+ public void _read_no_endian(cdrInput c)
+ throws IOException, BAD_PARAM
+ {
+ Id = c.read_string();
+
+ int n_profiles = c.read_long();
+
+ if (n_profiles == 0)
+ {
+ Id = null;
+ Internet = null;
+ return;
+ }
+
+ for (int i = 0; i < n_profiles; i++)
+ {
+ int tag = c.read_long();
+ cdrBufInput profile = c.read_encapsulation();
+
+ if (tag == Internet_profile.TAG_INTERNET_IOP)
+ {
+ Internet = new Internet_profile();
+ Internet.version = Version.read_version(profile);
+ Internet.host = profile.read_string();
+ Internet.port = profile.gnu_read_ushort();
+
+ int lk = profile.read_long();
+ key = new byte[ lk ];
+ profile.read(key);
+
+ // Read tagged components.
+ int n_components = 0;
+
+ try
+ {
+ if (Internet.version.since_inclusive(1, 1))
+ n_components = profile.read_long();
+
+ for (int t = 0; t < n_components; t++)
+ {
+ int ctag = profile.read_long();
+
+ if (ctag == CodeSets_profile.TAG_CODE_SETS)
+ {
+ CodeSets.read(profile);
+ }
+ }
+ }
+ catch (Unexpected ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Write this IOR record to the provided CDR stream.
+ * This procedure writes the zero (Big Endian) marker first.
+ */
+ public void _write(cdrOutput out)
+ {
+ // Always use Big Endian.
+ out.write(0);
+ _write_no_endian(out);
+ }
+
+ /**
+ * Write a null value to the CDR output stream.
+ *
+ * The null value is written as defined in OMG specification
+ * (zero length string, followed by an empty set of profiles).
+ */
+ public static void write_null(cdrOutput out)
+ {
+ // Empty Id string.
+ out.write_string("");
+
+ // Empty set of profiles.
+ out.write_long(0);
+ }
+
+ /**
+ * Write this IOR record to the provided CDR stream. The procedure
+ * writed data in Big Endian, but does NOT add any endian marker
+ * to the beginning.
+ */
+ public void _write_no_endian(cdrOutput out)
+ {
+ try
+ {
+ // Write repository id.
+ out.write_string(Id);
+
+ // Always one profile.
+ out.write_long(1);
+
+ // It is the Internet profile.
+ out.write_long(Internet_profile.TAG_INTERNET_IOP);
+
+ // Need to write the Internet profile into the separate
+ // stream as we must know the size in advance.
+ cdrOutput b = out.createEncapsulation();
+
+ Internet.version.write(b);
+ b.write_string(Internet.host);
+
+ b.write_ushort((short) (Internet.port & 0xFFFF));
+
+ // Write the object key.
+ b.write_long(key.length);
+ b.write(key);
+
+ // One tagged component.
+ b.write_long(1);
+
+ b.write_long(CodeSets_profile.TAG_CODE_SETS);
+ CodeSets.write(b);
+
+ b.close();
+ }
+ catch (IOException ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ /**
+ * Returns a human readable string representation of this IOR object.
+ */
+ public String toString()
+ {
+ StringBuffer b = new StringBuffer();
+ b.append(Id);
+ b.append(" at ");
+ b.append(Internet);
+
+ if (!Big_Endian)
+ b.append(" (Little endian) ");
+
+ b.append(" Key ");
+
+ for (int i = 0; i < key.length; i++)
+ {
+ b.append(Integer.toHexString(key [ i ] & 0xFF));
+ }
+
+ b.append(" ");
+ b.append(CodeSets);
+
+ return b.toString();
+ }
+
+ /**
+ * Returs a stringified reference.
+ *
+ * @return a newly constructed stringified reference.
+ */
+ public String toStringifiedReference()
+ {
+ cdrBufOutput out = new cdrBufOutput();
+
+ _write(out);
+
+ StringBuffer b = new StringBuffer("IOR:");
+
+ byte[] binary = out.buffer.toByteArray();
+ String s;
+
+ for (int i = 0; i < binary.length; i++)
+ {
+ s = Integer.toHexString(binary [ i ] & 0xFF);
+ if (s.length() == 1)
+ b.append('0');
+ b.append(s);
+ }
+
+ return b.toString();
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/IOR_Delegate.java b/libjava/classpath/gnu/CORBA/IOR_Delegate.java
new file mode 100644
index 0000000..b06f630
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/IOR_Delegate.java
@@ -0,0 +1,311 @@
+/* gnuDelegate.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufInput;
+import gnu.CORBA.GIOP.ReplyHeader;
+
+import org.omg.CORBA.Context;
+import org.omg.CORBA.ContextList;
+import org.omg.CORBA.ExceptionList;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.NVList;
+import org.omg.CORBA.NamedValue;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.Request;
+import org.omg.CORBA.portable.ApplicationException;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.RemarshalException;
+
+import java.io.IOException;
+
+import java.net.Socket;
+
+/**
+ * The Classpath implementation of the {@link Delegate} functionality in the
+ * case, when the object was constructed from an IOR object. The IOR can be
+ * constructed from the stringified object reference.
+ *
+ * There is an different instance of this delegate for each CORBA object.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class IOR_Delegate
+ extends Simple_delegate
+{
+ /**
+ * Contructs an instance of object using the given IOR.
+ */
+ public IOR_Delegate(ORB an_orb, IOR an_ior)
+ {
+ super(an_orb, an_ior);
+ }
+
+ /**
+ * Creates the request to invoke the method on this object.
+ *
+ * @param target the object, for that the operation must be invoked.
+ * @param context context (null allowed)
+ * @param operation the method name
+ * @param parameters the method parameters
+ * @param returns the return value holder
+ * @param exceptions the exceptions that can be thrown by the method
+ * @param ctx_list the context list (null allowed)
+ *
+ * @return the created request.
+ */
+ public Request create_request(org.omg.CORBA.Object target, Context context,
+ String operation, NVList parameters,
+ NamedValue returns
+ )
+ {
+ gnuRequest request = new gnuRequest();
+
+ request.setIor(getIor());
+ request.set_target(target);
+
+ request.setOperation(operation);
+ request.set_args(parameters);
+ request.m_context = context;
+ request.set_result(returns);
+ request.setORB(orb);
+
+ return request;
+ }
+
+ /**
+ * Creates the request to invoke the method on this object.
+ *
+ * @param target the object, for that the operation must be invoked.
+ * @param context context (null allowed)
+ * @param operation the method name
+ * @param parameters the method parameters
+ * @param returns the return value holder
+ *
+ * @return the created request.
+ */
+ public Request create_request(org.omg.CORBA.Object target, Context context,
+ String operation, NVList parameters,
+ NamedValue returns, ExceptionList exceptions,
+ ContextList ctx_list
+ )
+ {
+ gnuRequest request = new gnuRequest();
+
+ request.setIor(ior);
+ request.set_target(target);
+
+ request.setOperation(operation);
+ request.set_args(parameters);
+ request.m_context = context;
+ request.set_result(returns);
+ request.set_exceptions(exceptions);
+ request.set_context_list(ctx_list);
+ request.setORB(orb);
+
+ return request;
+ }
+
+ /**
+ * Invoke operation on the given object, writing parameters to the given
+ * output stream.
+ *
+ * @param target the target object.
+ * @param output the output stream, previously returned by
+ * {@link #request(org.omg.CORBA.Object, String, boolean)}.
+ *
+ * @return the input stream, to read the response from or null for a
+ * one-way request.
+ *
+ * @throws SystemException if the SystemException has been thrown on the
+ * remote side (the exact type and the minor code matches the data of
+ * the remote exception that has been thrown).
+ *
+ * @throws org.omg.CORBA.portable.ApplicationException as specified.
+ * @throws org.omg.CORBA.portable.RemarshalException as specified.
+ */
+ public InputStream invoke(org.omg.CORBA.Object target, OutputStream output)
+ throws ApplicationException, RemarshalException
+ {
+ streamRequest request = (streamRequest) output;
+ if (request.response_expected)
+ {
+ binaryReply response = request.request.submit();
+
+ // Read reply header.
+ ReplyHeader rh = response.header.create_reply_header();
+ cdrBufInput input = response.getStream();
+ input.setOrb(orb);
+ rh.read(input);
+
+ boolean moved_permanently = false;
+
+ switch (rh.reply_status)
+ {
+ case ReplyHeader.NO_EXCEPTION :
+ if (response.header.version.since_inclusive(1, 2))
+ input.align(8);
+ return input;
+
+ case ReplyHeader.SYSTEM_EXCEPTION :
+ if (response.header.version.since_inclusive(1, 2))
+ input.align(8);
+ throw ObjectCreator.readSystemException(input);
+
+ case ReplyHeader.USER_EXCEPTION :
+ if (response.header.version.since_inclusive(1, 2))
+ input.align(8);
+ input.mark(2000);
+
+ String uxId = input.read_string();
+ input.reset();
+
+ throw new ApplicationException(uxId, input);
+
+ case ReplyHeader.LOCATION_FORWARD_PERM :
+ moved_permanently = true;
+
+ case ReplyHeader.LOCATION_FORWARD :
+ if (response.header.version.since_inclusive(1, 2))
+ input.align(8);
+
+ IOR forwarded = new IOR();
+ try
+ {
+ forwarded._read_no_endian(input);
+ }
+ catch (IOException ex)
+ {
+ MARSHAL t = new MARSHAL("Cant read forwarding info");
+ t.initCause(ex);
+ throw t;
+ }
+
+ request.request.setIor(forwarded);
+
+ // If the object has moved permanently, its IOR is replaced.
+ if (moved_permanently)
+ setIor(forwarded);
+
+ return invoke(target, request);
+
+ default :
+ throw new MARSHAL("Unknow reply status: " + rh.reply_status);
+ }
+ }
+ else
+ {
+ request.request.send_oneway();
+ return null;
+ }
+ }
+
+ /**
+ * Create a request to invoke the method of this CORBA object.
+ *
+ * @param target the CORBA object, to that this operation must be applied.
+ * @param operation the name of the method to invoke.
+ *
+ * @return the request.
+ */
+ public Request request(org.omg.CORBA.Object target, String operation)
+ {
+ gnuRequest request = new gnuRequest();
+
+ request.setIor(ior);
+ request.set_target(target);
+
+ request.setOperation(operation);
+ request.setORB(orb);
+
+ return request;
+ }
+
+ /**
+ * Create a request to invoke the method of this CORBA object.
+ *
+ * @param target the CORBA object, to that this operation must be applied.
+ * @param operation the name of the method to invoke.
+ * @param response_expected specifies if this is one way message or the
+ * response to the message is expected.
+ *
+ * @return the stream where the method arguments should be written.
+ */
+ public OutputStream request(org.omg.CORBA.Object target, String operation,
+ boolean response_expected
+ )
+ {
+ gnuRequest request = new gnuRequest();
+
+ request.setIor(ior);
+ request.set_target(target);
+ request.setOperation(operation);
+
+ request.getParameterStream().response_expected = response_expected;
+ request.setORB(orb);
+
+ return request.getParameterStream();
+ }
+
+ /**
+ * If there is an opened cache socket to access this object, close
+ * that socket.
+ *
+ * @param target The target is not used, this delegate requires a
+ * single instance per object.
+ */
+ public void release(org.omg.CORBA.Object target)
+ {
+ String key = ior.Internet.host + ":" + ior.Internet.port;
+
+ Socket socket = SocketRepository.get_socket(key);
+ try
+ {
+ if (socket != null)
+ {
+ socket.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ // do nothing, then.
+ }
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/IOR_contructed_object.java b/libjava/classpath/gnu/CORBA/IOR_contructed_object.java
new file mode 100644
index 0000000..2fab707
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/IOR_contructed_object.java
@@ -0,0 +1,109 @@
+/* IOR_contructed_object.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.portable.ObjectImpl;
+
+/**
+ * Implements an object, constructed from an IOR reference.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class IOR_contructed_object
+ extends ObjectImpl
+{
+ /**
+ * The IOR, from which the object was constructed.
+ */
+ protected final IOR ior;
+
+ /**
+ * The object id, as defined in IOR.
+ */
+ protected final String[] id;
+
+ /**
+ * Create the object from the given IOR.
+ *
+ * @param an_ior the IOR.
+ */
+ public IOR_contructed_object(ORB orb, IOR an_ior)
+ {
+ ior = an_ior;
+ _set_delegate(new IOR_Delegate(orb, ior));
+ id = new String[] { ior.Id };
+ }
+
+ /**
+ * Create the object from the given string IOR representation.
+ *
+ * @param an_ior the IOR in the string form.
+ */
+ public IOR_contructed_object(Functional_ORB orb, String an_ior)
+ {
+ ior = IOR.parse(an_ior);
+ _set_delegate(new IOR_Delegate(orb, ior));
+ id = new String[] { ior.Id };
+ }
+
+ public String[] _ids()
+ {
+ return id;
+ }
+
+ /**
+ * Get a string reference for this object.
+ *
+ * @return the class name:IOR profile
+ */
+ public String toString()
+ {
+ return getClass().getName() + ":IOR:" + ior;
+ }
+
+ /**
+ * Calls realease on the delegate.
+ */
+ protected void finalize()
+ throws java.lang.Throwable
+ {
+ _get_delegate().release(this);
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java b/libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java
new file mode 100644
index 0000000..79d7870
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java
@@ -0,0 +1,139 @@
+/* Binding_iterator.java --
+ Copyright (C) 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 gnu.CORBA.NamingService;
+
+import org.omg.CosNaming.Binding;
+import org.omg.CosNaming.BindingHolder;
+import org.omg.CosNaming.BindingListHolder;
+import org.omg.CosNaming.BindingType;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming._BindingIteratorImplBase;
+
+/**
+ * The implementation of the {@link BindingIterator}.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class Binding_iterator_impl
+ extends _BindingIteratorImplBase
+{
+ /**
+ * The value, returned by the {@link #next_one} when there
+ * are no bindings available.
+ */
+ private static final Binding no_more_bindings =
+ new Binding(new NameComponent[ 0 ], BindingType.nobject);
+
+ /**
+ * The collection of the available bindings.
+ */
+ private final Binding[] bindings;
+
+ /**
+ * The position of the internal iterator pointer.
+ */
+ private int p;
+
+ public Binding_iterator_impl(Binding[] a_bindings)
+ {
+ bindings = a_bindings;
+ }
+
+ /**
+ * Disconnect the iterator from its ORB. The iterator will
+ * no longer be accessible and will be a subject of the
+ * garbage collection.
+ */
+ public void destroy()
+ {
+ _orb().disconnect(this);
+ }
+
+ /**
+ * Return the desired amount of bindings.
+ *
+ * @param amount the maximal number of bindings to return.
+ * @param a_list a holder to store the returned bindings.
+ *
+ * @return false if there are no more bindings available,
+ * true otherwise.
+ */
+ public boolean next_n(int amount, BindingListHolder a_list)
+ {
+ if (p < bindings.length)
+ {
+ int n = bindings.length - p;
+ if (n > amount)
+ n = amount;
+
+ a_list.value = new Binding[ n ];
+ for (int i = 0; i < n; i++)
+ a_list.value [ i ] = bindings [ p++ ];
+
+ return true;
+ }
+ else
+ {
+ a_list.value = new Binding[ 0 ];
+ return false;
+ }
+ }
+
+ /**
+ * Return the next binding.
+ *
+ * @param a_binding a holder, where the next binding will be stored.
+ *
+ * @return false if there are no more bindings available, true
+ * otherwise.
+ */
+ public boolean next_one(BindingHolder a_binding)
+ {
+ if (p < bindings.length)
+ {
+ a_binding.value = (Binding) bindings [ p++ ];
+ return true;
+ }
+ else
+ {
+ a_binding.value = no_more_bindings;
+ return false;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/NamingService/Ext.java b/libjava/classpath/gnu/CORBA/NamingService/Ext.java
new file mode 100644
index 0000000..fb7406c
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/NamingService/Ext.java
@@ -0,0 +1,230 @@
+/* TransientContextExt.java --
+ Copyright (C) 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 gnu.CORBA.NamingService;
+
+import org.omg.CORBA.NO_IMPLEMENT;
+import org.omg.CORBA.Object;
+import org.omg.CORBA.portable.Delegate;
+import org.omg.CORBA.portable.ObjectImpl;
+import org.omg.CosNaming.BindingIteratorHolder;
+import org.omg.CosNaming.BindingListHolder;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContext;
+import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
+import org.omg.CosNaming.NamingContextPackage.CannotProceed;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+import org.omg.CosNaming.NamingContextPackage.NotEmpty;
+import org.omg.CosNaming.NamingContextPackage.NotFound;
+import org.omg.CosNaming._NamingContextExtImplBase;
+
+/**
+ * This naming context that adds the the string based extensions,
+ * defined by {@link NamingContextExt}. The basic functionality
+ * is handled by the enclosed instance of the {@link NamingContext}.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class Ext
+ extends _NamingContextExtImplBase
+{
+ /**
+ * The older version of the naming context, where all relevant calls
+ * are forwarded.
+ */
+ private final NamingContext classic;
+
+ /**
+ * The converter class converts between string and array form of the
+ * name.
+ */
+ private snConverter converter = new snConverter();
+
+ /**
+ * Create the extensions for the given instance of the context.
+ *
+ * @param previous_version the previous version of the naming context.
+ */
+ public Ext(NamingContext previous_version)
+ {
+ classic = previous_version;
+ }
+
+ /**
+ * Sets a delegate to this context and, if appropriated, also
+ * sets the same delegate to the enclosing 'classic' context.
+ *
+ * @param a_delegate a delegate to set.
+ */
+ public void _set_delegate(Delegate a_delegate)
+ {
+ super._set_delegate(a_delegate);
+ if (classic instanceof ObjectImpl)
+ ((ObjectImpl) classic)._set_delegate(a_delegate);
+ }
+
+ /** {@inheritDoc} */
+ public void bind(NameComponent[] a_name, Object an_object)
+ throws NotFound, CannotProceed, InvalidName, AlreadyBound
+ {
+ classic.bind(a_name, an_object);
+ }
+
+ /** {@inheritDoc} */
+ public void bind_context(NameComponent[] a_name, NamingContext context)
+ throws NotFound, CannotProceed, InvalidName, AlreadyBound
+ {
+ classic.bind_context(a_name, context);
+ }
+
+ /** {@inheritDoc} */
+ public NamingContext bind_new_context(NameComponent[] a_name)
+ throws NotFound, AlreadyBound, CannotProceed,
+ InvalidName
+ {
+ return classic.bind_new_context(a_name);
+ }
+
+ /** {@inheritDoc} */
+ public void destroy()
+ throws NotEmpty
+ {
+ classic.destroy();
+ }
+
+ /** {@inheritDoc} */
+ public void list(int amount, BindingListHolder a_list,
+ BindingIteratorHolder an_iter
+ )
+ {
+ classic.list(amount, a_list, an_iter);
+ }
+
+ /** {@inheritDoc} */
+ public NamingContext new_context()
+ {
+ return classic.new_context();
+ }
+
+ /** {@inheritDoc} */
+ public void rebind(NameComponent[] a_name, Object an_object)
+ throws NotFound, CannotProceed, InvalidName
+ {
+ classic.rebind(a_name, an_object);
+ }
+
+ /** {@inheritDoc} */
+ public void rebind_context(NameComponent[] a_name, NamingContext context)
+ throws NotFound, CannotProceed, InvalidName
+ {
+ classic.rebind_context(a_name, context);
+ }
+
+ /** {@inheritDoc} */
+ public Object resolve(NameComponent[] a_name)
+ throws NotFound, CannotProceed, InvalidName
+ {
+ return classic.resolve(a_name);
+ }
+
+ /**
+ * Resolves the name, represented in the form of the string. The name
+ * is first parsed into an array representation, then the call
+ * is forwarded to the {@link resolve(NameComponent[])}.
+ *
+ * @param a_name_string a name to resolve.
+ *
+ * @return the resolved object.
+ *
+ * @throws NotFound if the name cannot be resolved.
+ * @throws InvalidName if the name is invalid.
+ * @throws CannotProceed on unexpected circumstances.
+ */
+ public Object resolve_str(String a_name_string)
+ throws NotFound, CannotProceed, InvalidName
+ {
+ return resolve(to_name(a_name_string));
+ }
+
+ /**
+ * Convert the name string representation into array representation.
+ *
+ * @param a_name_string a string to convert.
+ * @return a converted array of the name components
+ *
+ * @throws InvalidName on parsing error.
+ */
+ public NameComponent[] to_name(String a_name_string)
+ throws InvalidName
+ {
+ return converter.toName(a_name_string);
+ }
+
+ /**
+ * Convert a name component array representation into string representation.
+ *
+ * @param a_name a name to convert.
+ *
+ * @return a string form.
+ *
+ * @throws InvalidName if the passed name is invalid.
+ */
+ public String to_string(NameComponent[] a_name)
+ throws InvalidName
+ {
+ return converter.toString(a_name);
+ }
+
+ /**
+ * This method is not yet implemented.
+ * FIXME TODO implement it.
+ */
+ public String to_url(String an_address, String a_name_string)
+ throws org.omg.CosNaming.NamingContextExtPackage.InvalidAddress,
+ InvalidName
+ {
+ throw new NO_IMPLEMENT("Method to_url() not yet implemented.");
+ }
+
+ /** {@inheritDoc} */
+ public void unbind(NameComponent[] a_name)
+ throws NotFound, CannotProceed, InvalidName
+ {
+ classic.unbind(a_name);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/NamingService/NameValidator.java b/libjava/classpath/gnu/CORBA/NamingService/NameValidator.java
new file mode 100644
index 0000000..d7d5a14
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/NamingService/NameValidator.java
@@ -0,0 +1,79 @@
+/* NameValidator.java --
+ Copyright (C) 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 gnu.CORBA.NamingService;
+
+
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+
+/**
+ * Checks the given name for validity.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class NameValidator
+{
+ /**
+ * Check the given name. This method must be package level, as it is
+ * not defined in the API.
+ *
+ * @param name the name to check.
+ *
+ * @throws InvalidName if the given name is not valid.
+ */
+ public static void check(NameComponent[] name)
+ throws InvalidName
+ {
+ if (name == null)
+ throw new InvalidName("name=null");
+
+ if (name.length == 0)
+ throw new InvalidName("name.length=0");
+
+ for (int i = 0; i < name.length; i++)
+ {
+ if (name [ i ] == null)
+ throw new InvalidName("name[" + i + "]=null");
+ if (name [ i ].id == null)
+ throw new InvalidName("name[" + i + "].id=null");
+ if (name [ i ].kind == null)
+ throw new InvalidName("name[" + i + "].kind=null");
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/NamingService/NamingMap.java b/libjava/classpath/gnu/CORBA/NamingService/NamingMap.java
new file mode 100644
index 0000000..a69b061
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/NamingService/NamingMap.java
@@ -0,0 +1,187 @@
+/* NamingMap.java --
+ Copyright (C) 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 gnu.CORBA.NamingService;
+
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * The Naming Map maps the single names components into associated objects or
+ * naming contexts.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class NamingMap
+{
+ /**
+ * The actual map.
+ */
+ private final TreeMap map;
+
+ /**
+ * Creates an instance of the naming map, intialising the comparator
+ * to the {@link cmpNameComparator}.
+ */
+ public NamingMap()
+ {
+ map = new TreeMap(cmpNameComponent.singleton);
+ }
+
+ /**
+ * Put the given CORBA object, specifying the given name as a key.
+ * If the entry with the given name already exists, or if the given
+ * object is already mapped under another name, the
+ * {@link AlreadyBound} exception will be thrown.
+ *
+ * @param name the name
+ * @param object the object
+ */
+ public void bind(NameComponent name, org.omg.CORBA.Object object)
+ throws AlreadyBound, InvalidName
+ {
+ if (containsKey(name))
+ {
+ Object x = get(name);
+
+ // Do not throw an exception if the same object is named by
+ // the same name.
+ if (x.equals(object))
+ throw new AlreadyBound("The name is in use for another object");
+ }
+ else
+ {
+ if (containsValue(object))
+ throw new AlreadyBound("Tha object has another name");
+ }
+ }
+
+ /**
+ * Checks if this map contains the definition of the given name.
+ *
+ * @param key the name to check.
+ */
+ public boolean containsKey(NameComponent key)
+ {
+ return map.containsKey(key);
+ }
+
+ /**
+ * Checks if this map contains the definition of the given object.
+ *
+ * @param object the object to check.
+ */
+ public boolean containsValue(org.omg.CORBA.Object object)
+ {
+ return map.containsValue(object);
+ }
+
+ /**
+ * Returns the map entry set.
+ *
+ * @return the map entry set, containing the instances of the
+ * Map.Entry.
+ */
+ public Set entries()
+ {
+ return map.entrySet();
+ }
+
+ /**
+ * Get the CORBA object, associated with the given name.
+ *
+ * @param name the name.
+ *
+ * @return the associated object, null if none.
+ */
+ public org.omg.CORBA.Object get(NameComponent name)
+ {
+ return (org.omg.CORBA.Object) map.get(name);
+ }
+
+ /**
+ * Put the given CORBA object, specifying the given name as a key.
+ * Remove all pre - existing mappings for the given name and object.
+ *
+ * @param name the name.
+ * @param object
+ */
+ public void rebind(NameComponent name, org.omg.CORBA.Object object)
+ throws InvalidName
+ {
+ // Remove the existing mapping for the given name, if present.
+ remove(name);
+
+ Iterator iter = entries().iterator();
+ Map.Entry item;
+
+ // Remove the existing mapping for the given object, if present.
+ while (iter.hasNext())
+ {
+ item = (Map.Entry) iter.next();
+ if (item.getValue().equals(object))
+ iter.remove();
+ }
+
+ map.put(name, object);
+ }
+
+ /**
+ * Removes the given name, if present.
+ *
+ * @param name a name to remove.
+ */
+ public void remove(NameComponent name)
+ {
+ map.remove(name);
+ }
+
+ /**
+ * Get the size of the map.
+ */
+ public int size()
+ {
+ return map.size();
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java b/libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java
new file mode 100644
index 0000000..fda46ad
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java
@@ -0,0 +1,160 @@
+/* Server.java --
+ Copyright (C) 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 gnu.CORBA.NamingService;
+
+import gnu.CORBA.Functional_ORB;
+
+import org.omg.CosNaming.NamingContextExt;
+
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * The server for the gnu classpath naming service. This is an executable
+ * class that must be started to launch the GNU Classpath CORBA
+ * transient naming service.
+ *
+ * GNU Classpath currently works with this naming service and is also
+ * interoperable with the Sun Microsystems naming services from
+ * releases 1.3 and 1.4, both transient tnameserv and persistent
+ * orbd.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class NamingServiceTransient
+{
+ /**
+ * The default port (900), on that the naming service starts if no
+ * -ORBInitialPort is specified in the command line.
+ */
+ public static final int PORT = 900;
+
+ /**
+ * Get the object key for the naming service. The default
+ * key is the string "NameService" in ASCII.
+ *
+ * @return the byte array.
+ */
+ public static byte[] getDefaultKey()
+ {
+ try
+ { // NameService
+ return "NameService".getBytes("UTF-8");
+ }
+ catch (UnsupportedEncodingException ex)
+ {
+ throw new InternalError("UTF-8 unsupported");
+ }
+ }
+
+ /**
+ * Start the naming service on the current host at the given port.
+ * The parameter -org.omg.CORBA.ORBInitialPort NNN or
+ * -ORBInitialPort NNN, if present, specifies the port, on that
+ * the service must be started. If this key is not specified,
+ * the service starts at the port 900.
+ *
+ * The parameter -ior FILE_NAME, if present, forces to store the ior string
+ * of this naming service to the specified file.
+ *
+ * @param args the parameter string.
+ */
+ public static void main(String[] args)
+ {
+ int port = PORT;
+ String iorf = null;
+ try
+ {
+ // Create and initialize the ORB
+ final Functional_ORB orb = new Functional_ORB();
+
+ if (args.length > 1)
+ for (int i = 0; i < args.length - 1; i++)
+ {
+ if (args [ i ].endsWith("ORBInitialPort"))
+ port = Integer.parseInt(args [ i + 1 ]);
+
+ if (args [ i ].equals("-ior"))
+ iorf = args [ i + 1 ];
+ }
+
+ Functional_ORB.setPort(port);
+
+ // Create the servant and register it with the ORB
+ NamingContextExt namer = new Ext(new TransientContext());
+ orb.connect(namer, getDefaultKey());
+
+ // Storing the IOR reference.
+ String ior = orb.object_to_string(namer);
+ if (iorf != null)
+ {
+ FileOutputStream f = new FileOutputStream(iorf);
+ PrintStream p = new PrintStream(f);
+ p.print(ior);
+ p.close();
+ }
+
+ System.out.println("GNU Classpath, transient naming service. " +
+ "Copyright (C) 2005 Free Software Foundation\n" +
+ "This tool comes with ABSOLUTELY NO WARRANTY. " +
+ "This is free software, and you are\nwelcome to " +
+ "redistribute it under conditions, defined in " +
+ "GNU Classpath license.\n\n" + ior
+ );
+
+ new Thread()
+ {
+ public void run()
+ {
+ // Wait for invocations from clients.
+ orb.run();
+ }
+ }.start();
+ }
+ catch (Exception e)
+ {
+ System.err.println("ERROR: " + e);
+ e.printStackTrace(System.out);
+ }
+
+ // Restore the default value for allocating ports for the subsequent objects.
+ Functional_ORB.setPort(Functional_ORB.DEFAULT_INITIAL_PORT);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/NamingService/TransientContext.java b/libjava/classpath/gnu/CORBA/NamingService/TransientContext.java
new file mode 100644
index 0000000..4b7c193
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/NamingService/TransientContext.java
@@ -0,0 +1,416 @@
+/* nContext.java -- implementation of NamingContext
+ Copyright (C) 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 gnu.CORBA.NamingService;
+
+import org.omg.CORBA.Object;
+import org.omg.CosNaming.Binding;
+import org.omg.CosNaming.BindingIteratorHolder;
+import org.omg.CosNaming.BindingListHolder;
+import org.omg.CosNaming.BindingType;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContext;
+import org.omg.CosNaming.NamingContextOperations;
+import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
+import org.omg.CosNaming.NamingContextPackage.CannotProceed;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+import org.omg.CosNaming.NamingContextPackage.NotEmpty;
+import org.omg.CosNaming.NamingContextPackage.NotFound;
+import org.omg.CosNaming.NamingContextPackage.NotFoundReason;
+import org.omg.CosNaming._NamingContextImplBase;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * This class implements the transient naming service, defined by
+ * {@link NamingContex}. The 'transient' means that the service does
+ * not store its state into the persistent memory. If the service is
+ * restarted, the named objects must be re-registered again.
+ *
+ * TODO Write the persistent naming service.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class TransientContext
+ extends _NamingContextImplBase
+ implements NamingContext, NamingContextOperations
+{
+ /**
+ * The already named contexts.
+ */
+ protected final NamingMap named_contexts = new NamingMap();
+
+ /**
+ * The already named objects.
+ */
+ protected final NamingMap named_objects = new NamingMap();
+
+ /**
+ * Gives the object a name, valid in this context.
+ *
+ * @param a_name the name, being given to the object.
+ * @param an_object the object, being named.
+ *
+ * @throws AlreadyBound if the object is already named in this context.
+ * @throws InvalidName if the name has zero length or otherwise invalid.
+ */
+ public void bind(NameComponent[] a_name, Object an_object)
+ throws NotFound, CannotProceed, InvalidName, AlreadyBound
+ {
+ if (a_name.length == 1)
+ named_objects.bind(a_name [ 0 ], an_object);
+ else
+ {
+ NamingContext context =
+ (NamingContext) named_contexts.get(a_name [ 0 ]);
+ context.bind(getSuffix(a_name), an_object);
+ }
+ }
+
+ /**
+ * Gives a child context name, valid in this context.
+ *
+ * @param a_name the name, being given to the child context.
+ * @param a_context the child context being named.
+ *
+ * @throws AlreadyBound if the child context is already named in
+ * the current context.
+ */
+ public void bind_context(NameComponent[] a_name, NamingContext a_context)
+ throws NotFound, CannotProceed, InvalidName, AlreadyBound
+ {
+ if (a_name.length == 1)
+ named_contexts.bind(a_name [ 0 ], a_context);
+ else
+ {
+ NamingContext context =
+ (NamingContext) named_contexts.get(a_name [ 0 ]);
+ context.bind_context(getSuffix(a_name), a_context);
+ }
+ }
+
+ /**
+ * Create a new context and give it a given name (bound it)
+ * in the current context.
+ *
+ * The context being created is returned by calling
+ * {@link #new_context()}.
+ *
+ * @param a_name the name being given to the new context.
+ *
+ * @return the newly created context.
+ *
+ * @throws AlreadyBound if the name is already in use.
+ * @throws InvalidName if the name has zero length or otherwise invalid.
+ */
+ public NamingContext bind_new_context(NameComponent[] a_name)
+ throws NotFound, AlreadyBound, CannotProceed,
+ InvalidName
+ {
+ if (named_contexts.containsKey(a_name [ 0 ]) ||
+ named_objects.containsKey(a_name [ 0 ])
+ )
+ throw new AlreadyBound();
+
+ NamingContext child = new_context();
+ bind_context(a_name, child);
+ return child;
+ }
+
+ /**
+ * Destroy this context (must be empty).
+ * @throws NotEmpty if the context being destroyed is not empty.
+ */
+ public void destroy()
+ throws NotEmpty
+ {
+ if (named_contexts.size() > 0 || named_objects.size() > 0)
+ throw new NotEmpty();
+ }
+
+ /**
+ * Iterate over all bindings, defined in this namind context.
+ *
+ * @param amount the maximal number of context to return in the
+ * holder a_list. The remaining bindings are accessible via iterator
+ * an_iter. If the parameter amount is zero, all bindings are accessed only
+ * via this iterator.
+ *
+ * This implementation list contexts first, then objects.
+ *
+ * @param a_list the holder, where the returned bindigs are stored.
+ * @param an_iter the iterator that can be used to access the remaining
+ * bindings.
+ */
+ public void list(int amount, BindingListHolder a_list,
+ BindingIteratorHolder an_iter
+ )
+ {
+ int nb = named_contexts.size() + named_objects.size();
+ int nl = nb;
+ if (nl > amount)
+ nl = amount;
+
+ a_list.value = new Binding[ nl ];
+
+ Iterator contexts = named_contexts.entries().iterator();
+ Iterator objects = named_objects.entries().iterator();
+
+ // Create a binding list.
+ for (int i = 0; i < nl; i++)
+ {
+ if (contexts.hasNext())
+ a_list.value [ i ] = mkBinding(contexts.next(), BindingType.ncontext);
+ else if (objects.hasNext())
+ a_list.value [ i ] = mkBinding(objects.next(), BindingType.nobject);
+ else
+ throw new InternalError();
+ }
+
+ // Create an iterator.
+ Binding[] remainder = new Binding[ nb - nl ];
+ int p = 0;
+
+ while (contexts.hasNext())
+ remainder [ p++ ] = mkBinding(contexts.next(), BindingType.ncontext);
+
+ while (objects.hasNext())
+ remainder [ p++ ] = mkBinding(objects.next(), BindingType.nobject);
+
+ Binding_iterator_impl bit = new Binding_iterator_impl(remainder);
+ _orb().connect(bit);
+ an_iter.value = bit;
+ }
+
+ /**
+ * Creates a new naming context, not bound to any name.
+ */
+ public NamingContext new_context()
+ {
+ Ext context = new Ext(new TransientContext());
+
+ // Connect the context to the current ORB:
+ _orb().connect(context);
+ return context;
+ }
+
+ /**
+ * Names or renames the object.
+ *
+ * @param a_name the new name, being given to the object
+ * in the scope of the current context. If the object is already
+ * named in this context, it is renamed.
+ *
+ * @param an_object the object, being named.
+ *
+ * @throws InvalidName if the name has zero length or otherwise invalid.
+ */
+ public void rebind(NameComponent[] a_name, Object an_object)
+ throws NotFound, CannotProceed, InvalidName
+ {
+ if (a_name.length == 1)
+ named_objects.rebind(a_name [ 0 ], an_object);
+ else
+ {
+ NamingContext context =
+ (NamingContext) named_contexts.get(a_name [ 0 ]);
+ context.rebind(getSuffix(a_name), an_object);
+ }
+ }
+
+ /**
+ * Names or renames the child context.
+ * If the child context is already named in
+ * the current context, it is renamed. The the name being given is in
+ * use, the old meaning of the name is discarded.
+ *
+ * @param a_name the name, being given to the child context in the scope
+ * of the current context.
+ *
+ * @param a_context the child context being named.
+ *
+ * @throws InvalidName if the name has zero length or otherwise invalid.
+ */
+ public void rebind_context(NameComponent[] a_name, NamingContext a_context)
+ throws NotFound, CannotProceed, InvalidName
+ {
+ if (a_name.length == 1)
+ named_contexts.rebind(a_name [ 0 ], a_context);
+ else
+ {
+ NamingContext context =
+ (NamingContext) named_contexts.get(a_name [ 0 ]);
+ context.rebind_context(getSuffix(a_name), a_context);
+ }
+ }
+
+ /**
+ * Get the object, bound to the specified name in this
+ * context. The given object must match the bound
+ * name.
+ *
+ * This implementation resolves the names as defined in specification
+ * of the CORBA naming service. This means, if the beginning of the
+ * name can be resolved to some naming context, the request is
+ * forwarded to this context, passing the unresolved name part as a
+ * parameter. In this way, it is possible to have a hierarchy of the
+ * naming services. The central services resolve the the beginning
+ * of the name. The local services resolve the remaining nodes of the
+ * name that may be relevant to some local details. It can be three or
+ * more ranks of the naming services.
+ *
+ * @param a_name the object name.
+ *
+ * @return the object, matching this name. The client
+ * usually casts or narrows (using the helper) the returned value
+ * to the more specific type.
+ *
+ * @throws NotFound if the name cannot be resolved.
+ * @throws InvalidName if the name has zero length or otherwise invalid.
+ */
+ public Object resolve(NameComponent[] a_name)
+ throws NotFound, CannotProceed, InvalidName
+ {
+ NameValidator.check(a_name);
+
+ if (a_name.length > 1)
+ return resolveSubContext(a_name);
+ else
+ {
+ // A single node name.
+ org.omg.CORBA.Object object;
+
+ object = named_objects.get(a_name [ 0 ]);
+ if (object != null)
+ return object;
+
+ object = named_contexts.get(a_name [ 0 ]);
+ if (object != null)
+ return object;
+ }
+
+ throw new NotFound(NotFoundReason.missing_node, a_name);
+ }
+
+ /**
+ * Removes the name from the binding context.
+ *
+ * @param a_name a name to remove.
+ *
+ * @throws InvalidName if the name has zero length or otherwise invalid.
+ */
+ public void unbind(NameComponent[] a_name)
+ throws NotFound, CannotProceed, InvalidName
+ {
+ NameValidator.check(a_name);
+
+ // Single node name - handle it.
+ if (a_name.length == 1)
+ {
+ if (named_objects.containsKey(a_name [ 0 ]))
+ named_objects.remove(a_name [ 0 ]);
+ else if (named_contexts.containsKey(a_name [ 0 ]))
+ named_contexts.remove(a_name [ 0 ]);
+ else
+ throw new NotFound(NotFoundReason.missing_node, a_name);
+ }
+ else
+ {
+ // Handle the first node and forward the command.
+ NamingContext subcontext =
+ (NamingContext) named_contexts.get(a_name [ 0 ]);
+
+ if (subcontext == null)
+ throw new NotFound(NotFoundReason.missing_node, a_name);
+
+ subcontext.unbind(getSuffix(a_name));
+ }
+ }
+
+ /**
+ * Get the name suffix, discarding the first member.
+ */
+ private NameComponent[] getSuffix(NameComponent[] a_name)
+ {
+ NameComponent[] suffix = new NameComponent[ a_name.length - 1 ];
+ System.arraycopy(a_name, 1, suffix, 0, suffix.length);
+ return suffix;
+ }
+
+ /**
+ * Create a binding.
+ *
+ * @param entry the entry, defining the bound object.
+ * @param type the binding type.
+ * @return the created binding.
+ */
+ private Binding mkBinding(java.lang.Object an_entry, BindingType type)
+ {
+ Map.Entry entry = (Map.Entry) an_entry;
+ Binding b = new Binding();
+
+ // The name component has always only one node (the current context)
+ b.binding_name = new NameComponent[] { (NameComponent) entry.getKey() };
+ b.binding_type = type;
+ return b;
+ }
+
+ /**
+ * Find the context, bound to the first name of the given
+ * name, and pass the remainder (without the first node)
+ * of the name for that context to resolve.
+ *
+ * @param name the name to resolve.
+ *
+ * @return the resolved context
+ */
+ private Object resolveSubContext(NameComponent[] a_name)
+ throws NotFound, CannotProceed, InvalidName
+ {
+ // A multiple node name.
+ // This context resolves the first node only.
+ NamingContext context = (NamingContext) named_contexts.get(a_name [ 0 ]);
+ if (context == null)
+ throw new NotFound(NotFoundReason.missing_node, a_name);
+
+ NameComponent[] suffix = getSuffix(a_name);
+
+ return context.resolve(suffix);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/NamingService/cmpNameComponent.java b/libjava/classpath/gnu/CORBA/NamingService/cmpNameComponent.java
new file mode 100644
index 0000000..1e06fb8
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/NamingService/cmpNameComponent.java
@@ -0,0 +1,98 @@
+/* cmpNameComponent.java --
+ Copyright (C) 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 gnu.CORBA.NamingService;
+
+import org.omg.CORBA.BAD_PARAM;
+import org.omg.CosNaming.NameComponent;
+
+import java.util.Comparator;
+
+/**
+ * This class implements the name component comparator, needed to
+ * sort and compare the name components in maps and sorted sets.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public final class cmpNameComponent
+ implements Comparator
+{
+ /**
+ * The singleton instance of the name comparator.
+ */
+ public static final cmpNameComponent singleton = new cmpNameComponent();
+
+ /**
+ * It is enough to have a singleton.
+ */
+ private cmpNameComponent()
+ {
+ }
+
+ /**
+ * Compare the two names components.
+ *
+ * @param nc_a the first name component.
+ * @param nc_b the second name component.
+ *
+ * @return 0 if the name components are equal, non zero value
+ * as result of comparison otherwise.
+ *
+ * @throws BAD_PARAM if one of the components is empty or
+ * has {@link NameComponent#id} or {@link NameComponent#kind}
+ * field intialised to null.
+ */
+ public final int compare(Object nc_a, Object nc_b)
+ {
+ NameComponent a = (NameComponent) nc_a;
+ NameComponent b = (NameComponent) nc_b;
+
+ int cn = a.id.compareTo(b.id);
+ if (cn != 0)
+ return cn;
+ return a.kind.compareTo(b.kind);
+ }
+
+ /**
+ * All instances of this class are equal.
+ */
+ public boolean equals(Object x)
+ {
+ return x instanceof cmpNameComponent;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/NamingService/snConverter.java b/libjava/classpath/gnu/CORBA/NamingService/snConverter.java
new file mode 100644
index 0000000..a9b9219
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/NamingService/snConverter.java
@@ -0,0 +1,328 @@
+/* snConverter.java --
+ Copyright (C) 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 gnu.CORBA.NamingService;
+
+import org.omg.CORBA.IntHolder;
+import org.omg.CosNaming.NameComponent;
+import org.omg.CosNaming.NamingContextPackage.InvalidName;
+
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+/**
+ * This class converts between string and array representations of the
+ * multi component object names.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class snConverter
+{
+ /**
+ * A string, indicating the escape character.
+ */
+ public static final String ESCAPE = "\\";
+
+ /**
+ * Convert the string name representation into the array name
+ * representation. See {@link #toString(NameComponent)} for the
+ * description of this format.
+ *
+ * @param name the string form of the name.
+ *
+ * @return the array form of the name.
+ *
+ * @throws InvalidName if the name cannot be parsed.
+ */
+ public NameComponent[] toName(String a_name)
+ throws InvalidName
+ {
+ ArrayList components = new ArrayList();
+ StringTokenizer st = new StringTokenizer(a_name, "./\\", true);
+
+ String id;
+ String kind;
+ String next;
+
+ // Create the buffer array, reserving the last element for null.
+ String[] n = new String[ st.countTokens() + 1 ];
+
+ int pp = 0;
+ while (st.hasMoreTokens())
+ n [ pp++ ] = st.nextToken();
+
+ IntHolder p = new IntHolder();
+
+ NameComponent node = readNode(p, n);
+
+ while (node != null)
+ {
+ components.add(node);
+ node = readNode(p, n);
+ }
+
+ NameComponent[] name = new NameComponent[ components.size() ];
+ for (int i = 0; i < name.length; i++)
+ {
+ name [ i ] = (NameComponent) components.get(i);
+ }
+
+ NameValidator.check(name);
+
+ return name;
+ }
+
+ /**
+ * Converts the name into its string representation, as defined in
+ * the specification CORBA naming service.
+ *
+ * A string representation for the name consists of the name components,
+ * separated by a slash '/' character (for example, 'a/b/c'). If the
+ * {@link NameComponent#kind} field is not empty, it is given after
+ * period ('.'), for example 'a.b/c.d/.' .
+ * The period alone represents node where part where both
+ * {@link NameComponent#kind} and {@link NameComponent#id} are empty strings.
+ *
+ * If slash or dot are part of the name, they are escaped by backslash ('\').
+ * If the backslash itself is part of the name, it is doubled.
+ *
+ * @param a_name a name to convert.
+ * @return a string representation.
+ */
+ public String toString(NameComponent[] a_name)
+ throws InvalidName
+ {
+ NameValidator.check(a_name);
+
+ StringBuffer b = new StringBuffer();
+
+ NameComponent n;
+
+ for (int ni = 0; ni < a_name.length; ni++)
+ {
+ n = a_name [ ni ];
+ appEscaping(b, n.id);
+ if (n.kind.length() > 0)
+ {
+ b.append('.');
+ appEscaping(b, n.kind);
+ }
+
+ if (ni < a_name.length - 1)
+ b.append('/');
+ }
+ return b.toString();
+ }
+
+ /**
+ * Append the contents of the string to this
+ * string buffer, inserting the escape sequences, where required.
+ *
+ * @param b a buffer to append the contents to.
+ * @param s a string to append.
+ */
+ private void appEscaping(StringBuffer b, String s)
+ {
+ char c;
+ for (int i = 0; i < s.length(); i++)
+ {
+ c = s.charAt(i);
+ switch (c)
+ {
+ case '.' :
+ case '/' :
+ case '\\' :
+ b.append('\\');
+ b.append(c);
+ break;
+
+ default :
+ b.append(c);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Assert the end of the current name component.
+ */
+ private void assertEndOfNode(IntHolder p, String[] t)
+ throws InvalidName
+ {
+ if (t [ p.value ] != null)
+ if (!t [ p.value ].equals("/"))
+ throw new InvalidName("End of node expected at token " + p.value);
+ }
+
+ /**
+ * Read the named component node. After reading the current positon
+ * advances to the beginning of the next node in an array.
+ *
+ * @param p the current position being wrapped inside the passed
+ * IntHolder.
+ *
+ * @param t the text buffer.
+ *
+ * @return the created node.
+ */
+ private NameComponent readNode(IntHolder p, String[] t)
+ throws InvalidName
+ {
+ // End of stream has been reached.
+ if (t [ p.value ] == null)
+ return null;
+
+ NameComponent n = new NameComponent();
+
+ if (t [ p.value ].equals("."))
+ {
+ // The 'id' is missing, but the 'kind' may follow.
+ n.id = "";
+ p.value++;
+ n.kind = readPart(p, t);
+ assertEndOfNode(p, t);
+ if (t [ p.value ] != null)
+ p.value++;
+ }
+ else if (t [ p.value ].equals("/"))
+ {
+ // This is not allowed here and may happen only
+ // on two subsequent slashes.
+ throw new InvalidName("Unexpected '/' token " + p.value);
+ }
+ else
+ {
+ n.id = readPart(p, t);
+
+ // If some chars follow the id.
+ if (t [ p.value ] != null)
+ {
+ // Dot means that the kind part follows
+ if (t [ p.value ].equals("."))
+ {
+ p.value++;
+ n.kind = readPart(p, t);
+ assertEndOfNode(p, t);
+ if (t [ p.value ] != null)
+ p.value++;
+ }
+
+ // The next name component follows - advance to
+ // the beginning of the next name component.
+ else if (t [ p.value ].equals("/"))
+ {
+ n.kind = "";
+ p.value++;
+ }
+ else
+ throw new InvalidName("Unexpected '" + t [ p.value ] +
+ "' at token " + p.value
+ );
+ }
+ else
+
+ // Id, and then end of sequence.
+ n.kind = "";
+ }
+
+ return n;
+ }
+
+ /**
+ * Read the name part (id or kind).
+ *
+ * @param p the current position. After reading, advances
+ * to the beginning of the next name fragment.
+ *
+ * @param t the string buffer.
+ *
+ * @return the name part with resolved escape sequences.
+ */
+ private String readPart(IntHolder p, String[] t)
+ {
+ StringBuffer part = new StringBuffer();
+
+ while (t [ p.value ] != null && !t [ p.value ].equals(".") &&
+ !t [ p.value ].equals("/")
+ )
+ {
+ if (t [ p.value ].equals(ESCAPE))
+ {
+ p.value++;
+ part.append(t [ p.value ]);
+ }
+ else
+ part.append(t [ p.value ]);
+
+ p.value++;
+ }
+
+ return part.toString();
+ }
+
+ public static void main(String[] args)
+ {
+ NameComponent a = new NameComponent("a", "ak");
+ NameComponent b = new NameComponent("b/z", "b.k");
+ NameComponent c = new NameComponent("c", "");
+
+ snConverter sn = new snConverter();
+
+ try
+ {
+ String s = sn.toString(new NameComponent[] { a, b, c });
+ System.out.println(s);
+
+ //NameComponent[] k = toName("a.k/b.k2/c/d/.");
+ //NameComponent[] k = toName("a.bc/.b/c.x");
+
+ NameComponent[] k = sn.toName(s);
+ System.out.println("ToString");
+
+ for (int i = 0; i < k.length; i++)
+ {
+ System.out.println(k [ i ].id + ":" + k [ i ].kind);
+ }
+ }
+ catch (InvalidName ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/CORBA/ObjectCreator.java b/libjava/classpath/gnu/CORBA/ObjectCreator.java
new file mode 100644
index 0000000..b99c46b
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/ObjectCreator.java
@@ -0,0 +1,348 @@
+/* ExceptionCreator.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.CompletionStatus;
+import org.omg.CORBA.CompletionStatusHelper;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.SystemException;
+import org.omg.CORBA.UNKNOWN;
+import org.omg.CORBA.UserException;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * Creates java objects from the agreed IDL names for the simple
+ * case when the CORBA object is directly mapped into the locally
+ * defined java class.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class ObjectCreator
+{
+ /**
+ * The standard OMG prefix.
+ */
+ public static final String OMG_PREFIX = "omg.org/";
+
+ /**
+ * The standard java prefix.
+ */
+ public static final String JAVA_PREFIX = "org.omg.";
+
+ /**
+ * The prefix for classes that are placed instide the
+ * gnu.CORBA namespace.
+ */
+ public static final String CLASSPATH_PREFIX = "gnu.CORBA.";
+
+ /**
+ * Try to instantiate an object with the given IDL name.
+ * The object must be mapped to the local java class.
+ * The omg.org domain must be mapped into the object in either
+ * org/omg or gnu/CORBA namespace.
+ *
+ * @param IDL name
+ * @return instantiated object instance or null if no such
+ * available.
+ */
+ public static java.lang.Object createObject(String idl, String suffix)
+ {
+ try
+ {
+ return Class.forName(toClassName(JAVA_PREFIX, idl) + suffix)
+ .newInstance();
+ }
+ catch (Exception ex)
+ {
+ try
+ {
+ return Class.forName(toClassName(CLASSPATH_PREFIX, idl) + suffix)
+ .newInstance();
+ }
+ catch (Exception exex)
+ {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Create the system exception with the given idl name.
+ *
+ * @param idl the exception IDL name, must match the syntax
+ * "IDL:octet
that is mapped into
+ * java long
.
+ *
+ * The holders have several application areas. The end user usually
+ * sees them implementing CORBA methods where the primitive type
+ * is passed by reference. While CORBA (or, for example, C) supports
+ * this, the java does not and a wrapper class is required.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public final class OctetHolder
+ implements Streamable
+{
+ /**
+ * The default type code for this holder.
+ */
+ private static final TypeCode t_octet =
+ new primitiveTypeCode(TCKind.tk_octet);
+
+ /**
+ * The long
(CORBA octet
) value,
+ * held by this OctetHolder.
+ */
+ public byte value;
+
+ /**
+ * Constructs an instance of OctetHolder,
+ * initializing {@link #value} to 0
.
+ */
+ public OctetHolder()
+ {
+ }
+
+ /**
+ * Constructs an instance of OctetHolder,
+ * initializing {@link #value} to the given octed
(byte).
+ *
+ * @param initial_value a value that will be assigned to the
+ * {@link #value} field.
+ */
+ public OctetHolder(byte initial_value)
+ {
+ value = initial_value;
+ }
+
+ /**
+ * Fill in the {@link value } field by reading the required data
+ * from the given stream. For octet
, the functionality
+ * is delegated to
+ * {@link org.omg.CORBA.portable.InputStream#read_octet}.
+ *
+ * @param input the input stream to read from.
+ */
+ public void _read(InputStream input)
+ {
+ value = input.read_octet();
+ }
+
+ /**
+ * Returns the TypeCode, corresponding the CORBA type that is stored
+ * using this holder.
+ */
+ public TypeCode _type()
+ {
+ return t_octet;
+ }
+
+ /**
+ * Write the {@link value } field to the given stream.
+ * For octet
, the functionality
+ * is delegated to
+ * {@link org.omg.CORBA.portable.OutputStream#write_octet(long) }.
+ *
+ * @param output the output stream to write into.
+ */
+ public void _write(OutputStream output)
+ {
+ output.write_octet(value);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/Poa/InvalidPolicyHolder.java b/libjava/classpath/gnu/CORBA/Poa/InvalidPolicyHolder.java
new file mode 100644
index 0000000..154762a
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/Poa/InvalidPolicyHolder.java
@@ -0,0 +1,106 @@
+/* InvalidPolicyHolder.java --
+ Copyright (C) 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 gnu.CORBA.Poa;
+
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.Streamable;
+import org.omg.PortableServer.POAPackage.InvalidPolicy;
+import org.omg.PortableServer.POAPackage.InvalidPolicyHelper;
+
+/**
+* A holder for the exception {@link InvalidPolicy}.
+
+* @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+*/
+public class InvalidPolicyHolder
+ implements Streamable
+{
+ /**
+ * The stored InvalidPolicy value.
+ */
+ public InvalidPolicy value;
+
+ /**
+ * Create the unitialised instance, leaving the value field
+ * with default null
value.
+ */
+ public InvalidPolicyHolder()
+ {
+ }
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue the value that will be assigned to
+ * the value
field.
+ */
+ public InvalidPolicyHolder(InvalidPolicy initialValue)
+ {
+ value = initialValue;
+ }
+
+ /**
+ * Fill in the {@link value} by data from the CDR stream.
+ *
+ * @param input the org.omg.CORBA.portable stream to read.
+ */
+ public void _read(InputStream input)
+ {
+ value = InvalidPolicyHelper.read(input);
+ }
+
+ /**
+ * Write the stored value into the CDR stream.
+ *
+ * @param output the org.omg.CORBA.portable stream to write.
+ */
+ public void _write(OutputStream output)
+ {
+ InvalidPolicyHelper.write(output, value);
+ }
+
+ /**
+ * Get the typecode of the InvalidPolicy.
+ */
+ public TypeCode _type()
+ {
+ return InvalidPolicyHelper.type();
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/Restricted_ORB.java b/libjava/classpath/gnu/CORBA/Restricted_ORB.java
new file mode 100644
index 0000000..801154e
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/Restricted_ORB.java
@@ -0,0 +1,463 @@
+/* RestrictedORB.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufOutput;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.BAD_PARAM;
+import org.omg.CORBA.ContextList;
+import org.omg.CORBA.Environment;
+import org.omg.CORBA.ExceptionList;
+import org.omg.CORBA.NO_IMPLEMENT;
+import org.omg.CORBA.NVList;
+import org.omg.CORBA.NamedValue;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.ORBPackage.InvalidName;
+import org.omg.CORBA.Request;
+import org.omg.CORBA.StructMember;
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+import org.omg.CORBA.UnionMember;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.ValueFactory;
+
+import java.applet.Applet;
+
+import java.util.Hashtable;
+import java.util.Properties;
+
+/**
+ * This class implements so-called Singleton ORB, a highly restricted version
+ * that cannot communicate over network. This ORB is provided
+ * for the potentially malicious applets with heavy security restrictions.
+ * It, however, supports some basic features that might be needed even
+ * when the network access is not granted.
+ *
+ * This ORB can only create typecodes,
+ * {@link Any}, {@link ContextList}, {@link NVList} and
+ * {@link org.omg.CORBA.portable.OutputStream} that writes to an
+ * internal buffer.
+ *
+ * All other methods throw the {@link NO_IMPLEMENT} exception.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class Restricted_ORB
+ extends org.omg.CORBA_2_3.ORB
+{
+ /**
+ * The singleton instance of this ORB.
+ */
+ public static final ORB Singleton = new Restricted_ORB();
+
+ /**
+ * The value factories.
+ */
+ protected Hashtable factories = new Hashtable();
+
+ /**
+ * Create a new instance of the RestrictedORB. This is used
+ * in derived classes only.
+ */
+ protected Restricted_ORB()
+ {
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode create_alias_tc(String id, String name, TypeCode typecode)
+ {
+ return new aliasTypeCode(typecode, id, name);
+ }
+
+ /** {@inheritDoc} */
+ public Any create_any()
+ {
+ gnuAny any = new gnuAny();
+ any.setOrb(this);
+ return any;
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode create_array_tc(int length, TypeCode element_type)
+ {
+ primitiveArrayTypeCode p =
+ new primitiveArrayTypeCode(TCKind.tk_array, element_type);
+ p.setLength(length);
+ return p;
+ }
+
+ /** {@inheritDoc} */
+ public ContextList create_context_list()
+ {
+ return new gnuContextList();
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode create_enum_tc(String id, String name, String[] values)
+ {
+ recordTypeCode r = new recordTypeCode(TCKind.tk_enum);
+ for (int i = 0; i < values.length; i++)
+ {
+ r.field().name = values [ i ];
+ }
+
+ r.setId(id);
+ r.setName(name);
+
+ return r;
+ }
+
+ /** {@inheritDoc} */
+ public Environment create_environment()
+ {
+ return new gnuEnvironment();
+ }
+
+ /** {@inheritDoc} */
+ public ExceptionList create_exception_list()
+ {
+ return new gnuExceptionList();
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode create_exception_tc(String id, String name,
+ StructMember[] members
+ )
+ {
+ recordTypeCode r = new recordTypeCode(TCKind.tk_except);
+ r.setId(id);
+ r.setName(name);
+
+ for (int i = 0; i < members.length; i++)
+ {
+ r.add(members [ i ]);
+ }
+
+ return r;
+ }
+
+ /**
+ * This method is not allowed for a RestrictedORB.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public TypeCode create_interface_tc(String id, String name)
+ {
+ no();
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public NVList create_list(int count)
+ {
+ return new gnuNVList(count);
+ }
+
+ /** {@inheritDoc} */
+ public NamedValue create_named_value(String s, Any any, int flags)
+ {
+ return new gnuNamedValue();
+ }
+
+ /** {@inheritDoc} */
+ public OutputStream create_output_stream()
+ {
+ cdrBufOutput stream = new cdrBufOutput();
+ stream.setOrb(this);
+ return stream;
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode create_sequence_tc(int bound, TypeCode element_type)
+ {
+ primitiveArrayTypeCode p =
+ new primitiveArrayTypeCode(TCKind.tk_sequence, element_type);
+ p.setLength(bound);
+ return p;
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode create_string_tc(int bound)
+ {
+ stringTypeCode p = new stringTypeCode(TCKind.tk_string);
+ p.setLength(bound);
+ return p;
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode create_struct_tc(String id, String name,
+ StructMember[] members
+ )
+ {
+ recordTypeCode r = new recordTypeCode(TCKind.tk_struct);
+ r.setId(id);
+ r.setName(name);
+
+ for (int i = 0; i < members.length; i++)
+ {
+ r.add(members [ i ]);
+ }
+
+ return r;
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode create_union_tc(String id, String name, TypeCode type,
+ UnionMember[] members
+ )
+ {
+ recordTypeCode r = new recordTypeCode(TCKind.tk_union);
+ r.setId(id);
+ r.setName(name);
+
+ for (int i = 0; i < members.length; i++)
+ {
+ r.add(members [ i ]);
+ }
+
+ return r;
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode create_wstring_tc(int bound)
+ {
+ stringTypeCode p = new stringTypeCode(TCKind.tk_wstring);
+ p.setLength(bound);
+ return p;
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode get_primitive_tc(TCKind tcKind)
+ {
+ try
+ {
+ return typeNamer.getPrimitveTC(tcKind);
+ }
+ catch (BadKind ex)
+ {
+ throw new BAD_PARAM("This is not a primitive type code: " +
+ tcKind.value()
+ );
+ }
+ }
+
+ /**
+ * This method is not allowed for a RestrictedORB.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public String[] list_initial_services()
+ {
+ no();
+ throw new InternalError();
+ }
+
+ /**
+ * This method is not allowed for a RestrictedORB.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public String object_to_string(org.omg.CORBA.Object forObject)
+ {
+ no();
+ throw new InternalError();
+ }
+
+ /**
+ * This method is not allowed for a RestrictedORB.
+ *
+ * @throws InvalidName never in this class, but it is thrown
+ * in the derived classes.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public org.omg.CORBA.Object resolve_initial_references(String name)
+ throws InvalidName
+ {
+ no();
+ throw new InternalError();
+ }
+
+ /**
+ * Shutdown the ORB server.
+ *
+ * For RestrictedORB, returns witout action.
+ */
+ public void run()
+ {
+ }
+
+ /**
+ * Shutdown the ORB server.
+ *
+ * For RestrictedORB, returns witout action.
+ */
+ public void shutdown(boolean wait_for_completion)
+ {
+ }
+
+ /**
+ * This method is not allowed for a RestrictedORB.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public org.omg.CORBA.Object string_to_object(String IOR)
+ {
+ no();
+ throw new InternalError();
+ }
+
+ /**
+ * This method is not allowed for a RestrictedORB.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ protected void set_parameters(Applet app, Properties props)
+ {
+ no();
+ }
+
+ /**
+ * This method is not allowed for a RestrictedORB.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ protected void set_parameters(String[] args, Properties props)
+ {
+ no();
+ }
+
+ /**
+ * Throws an exception, stating that the given method is not supported
+ * by the Restricted ORB.
+ */
+ private final void no()
+ {
+ // Apart the programming errors, this can only happen if the
+ // malicious code is trying to do that it is not allowed.
+ throw new NO_IMPLEMENT("Use init(args, props) for the functional version.");
+ }
+
+ /**
+ * This method is not allowed for a RestrictedORB.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public Request get_next_response()
+ throws org.omg.CORBA.WrongTransaction
+ {
+ no();
+ throw new InternalError();
+ }
+
+ /**
+ * This method is not allowed for a RestrictedORB.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public boolean poll_next_response()
+ {
+ no();
+ throw new InternalError();
+ }
+
+ /**
+ * This method is not allowed for a RestrictedORB.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public void send_multiple_requests_deferred(Request[] requests)
+ {
+ no();
+ }
+
+ /**
+ * This method is not allowed for a RestrictedORB.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public void send_multiple_requests_oneway(Request[] requests)
+ {
+ no();
+ }
+
+ /**
+ * Register the value factory under the given repository id.
+ */
+ public ValueFactory register_value_factory(String repository_id,
+ ValueFactory factory
+ )
+ {
+ factories.put(repository_id, factory);
+ return factory;
+ }
+
+ /**
+ * Unregister the value factroy.
+ */
+ public void unregister_value_factory(String id)
+ {
+ factories.remove(id);
+ }
+
+ /**
+ * Look for the value factory for the value, having the given repository id.
+ * The implementation checks for the registered value factories first.
+ * If none found, it tries to load and instantiate the class, mathing the
+ * given naming convention. If this faild, null is returned.
+ *
+ * @param repository_id a repository id.
+ *
+ * @return a found value factory, null if none.
+ */
+ public ValueFactory lookup_value_factory(String repository_id)
+ {
+ ValueFactory f = (ValueFactory) factories.get(repository_id);
+ if (f != null)
+ return f;
+
+ f = (ValueFactory) ObjectCreator.createObject(repository_id, "DefaultFactory");
+ if (f != null)
+ factories.put(repository_id, f);
+
+ return f;
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/ServiceDetailHolder.java b/libjava/classpath/gnu/CORBA/ServiceDetailHolder.java
new file mode 100644
index 0000000..e878637
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/ServiceDetailHolder.java
@@ -0,0 +1,91 @@
+/* ServiceDetailHolder.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.ServiceDetail;
+import org.omg.CORBA.ServiceDetailHelper;
+
+
+/**
+ * The service detail holder. This class is not included in the original
+ * API specification, so we place it outside the org.omg namespace.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class ServiceDetailHolder
+ implements org.omg.CORBA.portable.Streamable
+{
+ /**
+ * The stored value.
+ */
+ public ServiceDetail value;
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue
+ */
+ public ServiceDetailHolder(ServiceDetail initialValue)
+ {
+ value = initialValue;
+ }
+
+ /**
+ * Read from the CDR stream.
+ */
+ public void _read(org.omg.CORBA.portable.InputStream in)
+ {
+ value = ServiceDetailHelper.read(in);
+ }
+
+ /**
+ * Get the typecode.
+ */
+ public org.omg.CORBA.TypeCode _type()
+ {
+ return ServiceDetailHelper.type();
+ }
+
+ /**
+ * Write into the CDR stream.
+ */
+ public void _write(org.omg.CORBA.portable.OutputStream out)
+ {
+ ServiceDetailHelper.write(out, value);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/ServiceRequestAdapter.java b/libjava/classpath/gnu/CORBA/ServiceRequestAdapter.java
new file mode 100644
index 0000000..0b69881
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/ServiceRequestAdapter.java
@@ -0,0 +1,159 @@
+/* ServiceRequestConverter.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufOutput;
+
+import org.omg.CORBA.ARG_IN;
+import org.omg.CORBA.ARG_INOUT;
+import org.omg.CORBA.ARG_OUT;
+import org.omg.CORBA.Any;
+import org.omg.CORBA.Bounds;
+import org.omg.CORBA.ServerRequest;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.InvokeHandler;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.ResponseHandler;
+import org.omg.CORBA.portable.Streamable;
+
+/**
+ * This class exists to handle obsolete invocation style using
+ * ServerRequest.
+ *
+ * @deprecated The method {@link ObjectImpl#_invoke} is much faster.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class ServiceRequestAdapter
+ implements ResponseHandler
+{
+ /**
+ * A buffer for writing the response.
+ */
+ cdrBufOutput reply = new cdrBufOutput();
+
+ /**
+ * If set to true, an exception has been thrown during the invocation.
+ */
+ boolean isException;
+
+ public OutputStream createExceptionReply()
+ {
+ isException = true;
+ return reply;
+ }
+
+ public OutputStream createReply()
+ {
+ isException = false;
+ return reply;
+ }
+
+ /**
+ * The old style invocation using the currently deprecated server
+ * request class.
+ *
+ * @param request a server request, containg the invocation information.
+ * @param target the invocation target
+ * @param result the result holder with the set suitable streamable to read
+ * the result or null for void.
+ */
+ public static void invoke(ServerRequest request, InvokeHandler target,
+ Streamable result
+ )
+ {
+ try
+ {
+ int IN = ARG_IN.value;
+ int OUT = ARG_OUT.value;
+
+ // Write all arguments to the buffer output stream.
+ cdrBufOutput buffer = new cdrBufOutput();
+ gnuNVList args = new gnuNVList();
+ request.arguments(args);
+
+ for (int i = 0; i < args.count(); i++)
+ {
+ if ((args.item(i).flags() & IN) != 0)
+ {
+ args.item(i).value().write_value(buffer);
+ }
+ }
+
+ ServiceRequestAdapter h = new ServiceRequestAdapter();
+
+ target._invoke(request.operation(), buffer.create_input_stream(), h);
+
+ InputStream in = h.reply.create_input_stream();
+
+ if (h.isException)
+ {
+ // Write the exception information
+ gnuAny exc = new gnuAny();
+ universalHolder uku = new universalHolder(h.reply);
+ exc.insert_Streamable(uku);
+ request.set_exception(exc);
+ }
+ else
+ {
+ if (result != null)
+ {
+ result._read(in);
+ gnuAny r = new gnuAny();
+ r.insert_Streamable(result);
+ request.set_result(r);
+ };
+
+ // Unpack the arguments
+ for (int i = 0; i < args.count(); i++)
+ {
+ if ((args.item(i).flags() & OUT) != 0)
+ {
+ Any a = args.item(i).value();
+ a.read_value(in, a.type());
+ }
+ }
+ }
+ }
+ catch (Bounds ex)
+ {
+ throw new InternalError();
+ }
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/SetOverrideTypeHolder.java b/libjava/classpath/gnu/CORBA/SetOverrideTypeHolder.java
new file mode 100644
index 0000000..12b4b9f
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/SetOverrideTypeHolder.java
@@ -0,0 +1,90 @@
+/* SetOverrideTypeHolder.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.SetOverrideType;
+import org.omg.CORBA.SetOverrideTypeHelper;
+
+/**
+ * The holder for SetOverrideType.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class SetOverrideTypeHolder
+ implements org.omg.CORBA.portable.Streamable
+{
+ /**
+ * The stored SetOverrideType value.
+ */
+ public SetOverrideType value;
+
+ /**
+ * Create the initialised instance.
+ *
+ * @param initialValue the initial value.
+ */
+ public SetOverrideTypeHolder(SetOverrideType initialValue)
+ {
+ value = initialValue;
+ }
+
+ /**
+ * Fill in the {@link value} by data from the CDR stream.
+ */
+ public void _read(org.omg.CORBA.portable.InputStream in)
+ {
+ value = SetOverrideTypeHelper.read(in);
+ }
+
+ /**
+ * Get the typecode of the SetOverrideType.
+ */
+ public org.omg.CORBA.TypeCode _type()
+ {
+ return SetOverrideTypeHelper.type();
+ }
+
+ /**
+ * Write the stored value into the CDR stream.
+ */
+ public void _write(org.omg.CORBA.portable.OutputStream out)
+ {
+ SetOverrideTypeHelper.write(out, value);
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/Simple_delegate.java b/libjava/classpath/gnu/CORBA/Simple_delegate.java
new file mode 100644
index 0000000..d0b2ad2
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/Simple_delegate.java
@@ -0,0 +1,249 @@
+/* Local_delegate.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.Context;
+import org.omg.CORBA.ContextList;
+import org.omg.CORBA.ExceptionList;
+import org.omg.CORBA.NO_IMPLEMENT;
+import org.omg.CORBA.NVList;
+import org.omg.CORBA.NamedValue;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.Request;
+import org.omg.CORBA.portable.Delegate;
+import org.omg.CORBA.portable.ObjectImpl;
+
+/**
+ * The delegate, implementing the basic functionality only. This delegate
+ * is set in {@link ORG.connect(org.omg.CORBA.Object)} if ORB
+ * determines that the object is an instance of the
+ * {@link org.omg.CORBA.portable.ObjectImpl} and no other delegate is set.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class Simple_delegate
+ extends Delegate
+{
+ /**
+ * The orb.
+ */
+ protected final ORB orb;
+
+ /**
+ * The ior.
+ */
+ protected IOR ior;
+
+ public Simple_delegate(ORB an_orb, IOR an_ior)
+ {
+ orb = an_orb;
+ ior = an_ior;
+ }
+
+ /**
+ * Set the IOR of this object. The IOR must be newly set if
+ * the server reports that the object has permanently moved to a new
+ * location.
+ *
+ * @param an_ior the new IOR.
+ */
+ public void setIor(IOR an_ior)
+ {
+ this.ior = an_ior;
+ }
+
+ /**
+ * Get the IOR of this object.
+ */
+ public IOR getIor()
+ {
+ return ior;
+ }
+
+ /**
+ * Not implemented.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public Request create_request(org.omg.CORBA.Object target, Context context,
+ String operation, NVList parameters,
+ NamedValue returns
+ )
+ {
+ throw new NO_IMPLEMENT();
+ }
+
+ /**
+ * Not implemented.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public Request create_request(org.omg.CORBA.Object target, Context context,
+ String operation, NVList parameters,
+ NamedValue returns, ExceptionList exceptions,
+ ContextList ctx_list
+ )
+ {
+ throw new NO_IMPLEMENT();
+ }
+
+ /**
+ * Not implemented.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public org.omg.CORBA.Object duplicate(org.omg.CORBA.Object target)
+ {
+ throw new NO_IMPLEMENT();
+ }
+
+ /**
+ * Performs direct comparison ('==').
+ */
+ public boolean equals(org.omg.CORBA.Object self, org.omg.CORBA.Object other)
+ {
+ return self == other;
+ }
+
+ /**
+ * Not implemented.
+ *
+ * @throws NO_IMPLEMENT, always.
+ */
+ public org.omg.CORBA.Object get_interface_def(org.omg.CORBA.Object target)
+ {
+ throw new NO_IMPLEMENT();
+ }
+
+ /**
+ * Return the hashcode (0 <= hashcode < maximum).
+ */
+ public int hash(org.omg.CORBA.Object target, int maximum)
+ {
+ return target == null ? 0 : target.hashCode() % maximum;
+ }
+
+ /**
+ * Delegates functionality to java.lang.Object.hashCode();
+ */
+ public int hashCode(org.omg.CORBA.Object target)
+ {
+ return target == null ? 0 : target.hashCode();
+ }
+
+ /**
+ * Check if this object can be referenced by the given repository id.
+ *
+ * @param target the CORBA object, must be an instance of
+ * {@link org.omg.CORBA.portable.ObjectImpl}.
+ *
+ * @param repositoryIdentifer the repository id.
+ *
+ * @return true if the passed parameter is a repository id of this
+ * CORBA object.
+ */
+ public boolean is_a(org.omg.CORBA.Object target, String repositoryIdentifer)
+ {
+ if (!(target instanceof ObjectImpl))
+ throw new NO_IMPLEMENT("Supported only for org.omg.CORBA.portable.ObjectImpl");
+
+ ObjectImpl imp = (ObjectImpl) target;
+ String[] ids = imp._ids();
+
+ for (int i = 0; i < ids.length; i++)
+ {
+ if (ids [ i ].equals(repositoryIdentifer))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Only returns true if the objects are equal ('==').
+ */
+ public boolean is_equivalent(org.omg.CORBA.Object target,
+ org.omg.CORBA.Object other
+ )
+ {
+ return target == other;
+ }
+
+ /**
+ * Returns true by default.
+ */
+ public boolean is_local(org.omg.CORBA.Object self)
+ {
+ return true;
+ }
+
+ /**
+ * Returns true if the target is null.
+ */
+ public boolean non_existent(org.omg.CORBA.Object target)
+ {
+ return target == null;
+ }
+
+ /**
+ * Returns the ORB, passed in constructor,
+ * regardless of the argument. This class requires a single instance
+ * per each object.
+ */
+ public ORB orb(org.omg.CORBA.Object target)
+ {
+ return orb;
+ }
+
+ /**
+ * Returns without action.
+ */
+ public void release(org.omg.CORBA.Object target)
+ {
+ }
+
+ /**
+ * This should never be called this type delegate.
+ *
+ * @throws InternalError, always.
+ */
+ public Request request(org.omg.CORBA.Object target, String operation)
+ {
+ throw new InternalError();
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/SocketRepository.java b/libjava/classpath/gnu/CORBA/SocketRepository.java
new file mode 100644
index 0000000..70bcead
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/SocketRepository.java
@@ -0,0 +1,93 @@
+/* SocketRepository.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import java.net.Socket;
+
+import java.util.HashMap;
+
+/**
+ * This class caches the opened sockets that are reused during the
+ * frequent calls. Otherwise, some CORBA applications may spend
+ * up to 90 % of the working time just for closing and opening the sockets.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class SocketRepository
+{
+ /**
+ * The socket map.
+ */
+ private static HashMap sockets = new HashMap();
+
+ /**
+ * Put a socket.
+ *
+ * @param key as socket key.
+ *
+ * @param s a socket.
+ */
+ public static void put_socket(Object key, Socket s)
+ {
+ sockets.put(key, s);
+ }
+
+ /**
+ * Get a socket.
+ *
+ * @param key a socket key.
+ *
+ * @return an opened socket for reuse, null if no such
+ * available or it is closed.
+ */
+ public static Socket get_socket(Object key)
+ {
+ Socket s = (Socket) sockets.get(key);
+ if (s != null && s.isClosed())
+ {
+ sockets.remove(key);
+ return null;
+ }
+ else
+ {
+ sockets.remove(key);
+ return s;
+ }
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/TypeCodeHelper.java b/libjava/classpath/gnu/CORBA/TypeCodeHelper.java
new file mode 100644
index 0000000..c742275
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/TypeCodeHelper.java
@@ -0,0 +1,297 @@
+/* TypeCodeHelper.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+import org.omg.CORBA.TypeCodePackage.Bounds;
+
+/**
+ * Reads and writes the TypeCodes usind common data representation.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class TypeCodeHelper
+{
+ /**
+ * Read the CORBA {@link TypeCode}. First, the TypeCode kind
+ * is read as four byte long. Then, if needed, the additional
+ * parameters are loaded following CORBA specification.
+ *
+ * @param in a stream to read from.
+ */
+ public static TypeCode read(org.omg.CORBA.portable.InputStream in)
+ throws BadKind, Bounds
+ {
+ TCKind kind = TCKind.from_int(in.read_long());
+ TypeCode rt;
+ generalTypeCode g;
+ recordTypeCode r;
+ recordTypeCode.Field f;
+ stringTypeCode s;
+ int n;
+
+ switch (kind.value())
+ {
+ case TCKind._tk_sequence :
+ case TCKind._tk_array :
+
+ primitiveArrayTypeCode p = new primitiveArrayTypeCode(kind);
+ p.setLength(in.read_long());
+ rt = p;
+ break;
+
+ case TCKind._tk_string :
+ case TCKind._tk_wstring :
+ s = new stringTypeCode(kind);
+ s.setLength(in.read_long());
+ rt = s;
+ break;
+
+ case TCKind._tk_fixed :
+
+ fixedTypeCode fx = new fixedTypeCode();
+ fx.setDigits(in.read_short());
+ fx.setScale(in.read_short());
+ rt = fx;
+ break;
+
+ case TCKind._tk_objref :
+ case TCKind._tk_native :
+ case TCKind._tk_abstract_interface :
+ g = new generalTypeCode(kind);
+ g.setId(in.read_string());
+ g.setName(in.read_string());
+ rt = g;
+ break;
+
+ case TCKind._tk_alias :
+ case TCKind._tk_value_box :
+ g = new generalTypeCode(kind);
+ g.setId(in.read_string());
+ g.setName(in.read_string());
+ g.setContentType(in.read_TypeCode());
+ rt = g;
+ break;
+
+ case TCKind._tk_struct :
+ case TCKind._tk_except :
+ r = new recordTypeCode(kind);
+ r.setId(in.read_string());
+ r.setName(in.read_string());
+
+ n = in.read_long();
+
+ for (int i = 0; i < n; i++)
+ {
+ f = r.field();
+ f.name = in.read_string();
+ f.type = in.read_TypeCode();
+ }
+ rt = r;
+ break;
+
+ case TCKind._tk_enum :
+ r = new recordTypeCode(kind);
+ r.setId(in.read_string());
+ r.setName(in.read_string());
+
+ n = in.read_long();
+
+ for (int i = 0; i < n; i++)
+ {
+ f = r.field();
+ f.name = in.read_string();
+ }
+ rt = r;
+ break;
+
+ case TCKind._tk_union :
+ r = new recordTypeCode(kind);
+ r.setId(in.read_string());
+ r.setName(in.read_string());
+ r.setDiscriminator_type(in.read_TypeCode());
+ r.setDefaultIndex(in.read_long());
+
+ n = in.read_long();
+
+ for (int i = 0; i < n; i++)
+ {
+ f = r.field();
+ f.label = in.read_any();
+ f.name = in.read_string();
+ f.type = in.read_TypeCode();
+ }
+ rt = r;
+
+ break;
+
+ case TCKind._tk_value :
+ r = new recordTypeCode(kind);
+ r.setId(in.read_string());
+ r.setName(in.read_string());
+ r.setTypeModifier(in.read_short());
+ r.setConcreteBase_type(in.read_TypeCode());
+
+ n = in.read_long();
+
+ for (int i = 0; i < n; i++)
+ {
+ f = r.field();
+ f.name = in.read_string();
+ f.type = in.read_TypeCode();
+ f.visibility = in.read_short();
+ }
+ rt = r;
+ break;
+
+ default :
+ rt = new primitiveTypeCode(kind);
+ }
+ return rt;
+ }
+
+ /**
+ * Write the CORBA {@link TypeCode}. First, the TypeCode kind
+ * is written as four byte long. Then, if needed, the additional
+ * parameters are stored following CORBA specification.
+ *
+ * @param out a stream to write into.
+ * @param x a {@link TypeCode} to write.
+ */
+ public static void write(org.omg.CORBA.portable.OutputStream out, TypeCode x)
+ throws BadKind, Bounds
+ {
+ out.write_long(x.kind().value());
+
+ switch (x.kind().value())
+ {
+ case TCKind._tk_string :
+ case TCKind._tk_wstring :
+ out.write_long(x.length());
+ break;
+
+ case TCKind._tk_sequence :
+ case TCKind._tk_array :
+ write(out, x.content_type());
+ out.write_long(x.length());
+ break;
+
+ case TCKind._tk_fixed :
+ out.write_short(x.fixed_digits());
+ out.write_short(x.fixed_scale());
+ break;
+
+ case TCKind._tk_objref :
+ case TCKind._tk_native :
+ case TCKind._tk_abstract_interface :
+ out.write_string(x.id());
+ out.write_string(x.name());
+ break;
+
+ case TCKind._tk_alias :
+ case TCKind._tk_value_box :
+ out.write_string(x.id());
+ out.write_string(x.name());
+ write(out, x.content_type());
+ break;
+
+ case TCKind._tk_struct :
+ case TCKind._tk_except :
+ out.write_string(x.id());
+ out.write_string(x.name());
+
+ out.write_long(x.member_count());
+
+ for (int i = 0; i < x.member_count(); i++)
+ {
+ out.write_string(x.member_name(i));
+ write(out, x.member_type(i));
+ }
+ break;
+
+ case TCKind._tk_enum :
+ out.write_string(x.id());
+ out.write_string(x.name());
+
+ out.write_long(x.member_count());
+
+ for (int i = 0; i < x.member_count(); i++)
+ {
+ out.write_string(x.member_name(i));
+ }
+ break;
+
+ case TCKind._tk_union :
+ out.write_string(x.id());
+ out.write_string(x.name());
+
+ write(out, x.discriminator_type());
+ out.write_long(x.default_index());
+
+ out.write_long(x.member_count());
+
+ for (int i = 0; i < x.member_count(); i++)
+ {
+ out.write_any(x.member_label(i));
+ out.write_string(x.member_name(i));
+ write(out, x.member_type(i));
+ }
+ break;
+
+ case TCKind._tk_value :
+ out.write_string(x.id());
+ out.write_string(x.name());
+ out.write_short(x.type_modifier());
+ write(out, x.concrete_base_type());
+
+ out.write_long(x.member_count());
+
+ for (int i = 0; i < x.member_count(); i++)
+ {
+ out.write_string(x.member_name(i));
+ write(out, x.member_type(i));
+ out.write_short(x.member_visibility(i));
+ }
+ break;
+
+ default :}
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/Unexpected.java b/libjava/classpath/gnu/CORBA/Unexpected.java
new file mode 100644
index 0000000..89fb7e7
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/Unexpected.java
@@ -0,0 +1,128 @@
+/* DNW.java --
+ Copyright (C) 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 gnu.CORBA;
+
+
+/**
+ * Contains the static method to throw an error in the case
+ * when the execution should never get into the current point.
+ *
+ * The error message contains the text, suggesting to check
+ * the user code first and then report a bug.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class Unexpected
+ extends InternalError
+{
+ /**
+ * Use serialVersionUID for interoperability.
+ */
+ private static final long serialVersionUID = 1;
+
+ /**
+ * The default message for the CORBA assertion error.
+ */
+ public static final String SHARED_MESSAGE =
+ "CORBA assertion error. Please check your code. " +
+ "If you think it is Classpath problem, please report " +
+ "this bug providing as much information as possible.";
+
+ /**
+ * Create an instance with explaining message and enclosing
+ * exception.
+ */
+ public Unexpected(String msg, Exception why)
+ {
+ super(msg + ". " + SHARED_MESSAGE);
+ if (why != null)
+ initCause(why);
+ }
+
+ /**
+ * Create an instance with enclosing exception.
+ */
+ public Unexpected(Exception why)
+ {
+ super(SHARED_MESSAGE);
+ if (why != null)
+ initCause(why);
+ }
+
+ /**
+ * Create an instance.
+ */
+ public Unexpected()
+ {
+ super(SHARED_MESSAGE);
+ }
+
+ /**
+ * Throws an error with the custom explaining message and
+ * the appended share message.
+ *
+ * @param msg the error message
+ * @param why the enclosing exception.
+ */
+ public static void error(String msg, Exception why)
+ {
+ throw new Unexpected(msg, why);
+ }
+
+ /**
+ * Throws an error with the shared explaining message.
+ *
+ * @param why the enclosing exception.
+ * @throws Error, always.
+ */
+ public static void error(Exception why)
+ {
+ throw new Unexpected(why);
+ }
+
+ /**
+ * Throws an error with the shared explaining message.
+ *
+ * @throws Error, always.
+ */
+ public static void error()
+ {
+ throw new Unexpected();
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/Version.java b/libjava/classpath/gnu/CORBA/Version.java
new file mode 100644
index 0000000..84f40bf
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/Version.java
@@ -0,0 +1,206 @@
+/* Version.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import org.omg.CORBA.MARSHAL;
+
+/**
+ * A version number, represented by the major version number
+ * and the minor version number.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class Version
+ implements Serializable
+{
+ /**
+ * Use serialVersionUID for interoperability.
+ */
+ private static final long serialVersionUID = 1;
+
+ /**
+ * Major number (0..256, so the byte cannot be used).
+ */
+ public final int major;
+
+ /**
+ * Minor number.
+ */
+ public final int minor;
+
+ /**
+ * Create the version with the given version numbers.
+ *
+ * @param major major number (0..255)
+ * @param minor minor number (0..255)
+ */
+ public Version(int _major, int _minor)
+ {
+ major = (byte) _major;
+ minor = (byte) _minor;
+ }
+
+ /**
+ * Returns true if the versions are equal.
+ * @param other the other version to compare.
+ *
+ * @return true if the versions are equal
+ */
+ public boolean equals(java.lang.Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+ if (!(other instanceof Version))
+ {
+ return false;
+ }
+
+ Version that = (Version) other;
+ return same(that);
+ }
+
+ /**
+ * Read from the input stream, major number first.
+ * @param in a stream to read from.
+ */
+ public static Version read_version(java.io.InputStream in)
+ {
+ try
+ {
+ int major = in.read() & 0xFF;
+ int minor = in.read() & 0xFF;
+ return new Version(major, minor);
+ }
+ catch (IOException ex)
+ {
+ throw new MARSHAL("IOException while reading message header");
+ }
+ }
+
+ /**
+ * Returns true if the versions are the same.
+ *
+ * @param that the other version to compare.
+ *
+ * @return true if the versions are the same.
+ */
+ public boolean same(Version that)
+ {
+ return major == that.major && minor == that.minor;
+ }
+
+ /**
+ * Returns true if the given version is higher than
+ * or equals to the version, supplied as parameter
+ * in the form of two integers.
+ *
+ * @param a_major major number of the version to compare.
+ * @param a_minor minor number of the version to compare.
+ *
+ * @return true if this version is higher than or equals to
+ * the version v.
+ */
+ public boolean since_inclusive(int a_major, int a_minor)
+ {
+ if (major > a_major)
+ return true;
+ else if (major < a_major)
+ return false;
+ else
+
+ // Major numbers are equal.
+ return minor >= a_minor;
+ }
+
+ /**
+ * Return the string representation, in the form
+ * major.minor.
+ */
+ public String toString()
+ {
+ return major + "." + minor;
+ }
+
+ /**
+ * Returs true if the given version is lower or equal to the
+ * version, specified by the provided minor and major version
+ * number. This means, the version, specified by these two numbers,
+ * should be supported by teh current version.
+ *
+ * @param a_major a major version number.
+ * @param a_minor a minor version number.
+ *
+ * @return true if the current version should be supported by the
+ * version, specified by the two passed numbers.
+ */
+ public boolean until_inclusive(int a_major, int a_minor)
+ {
+ if (major < a_major)
+ return true;
+ else if (major > a_major)
+ return false;
+ else
+
+ // Major numbers are equal.
+ return minor <= a_minor;
+ }
+
+ /**
+ * Write into the output stream, major number first.
+ *
+ * @param out a stream to write into.
+ */
+ public void write(java.io.OutputStream out)
+ {
+ try
+ {
+ out.write(major & 0xFF);
+ out.write(minor & 0xFF);
+ }
+ catch (IOException ex)
+ {
+ throw new MARSHAL("IOException while writing message header");
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/WCharHolder.java b/libjava/classpath/gnu/CORBA/WCharHolder.java
new file mode 100644
index 0000000..23f0ad1
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/WCharHolder.java
@@ -0,0 +1,126 @@
+/* WCharHolder.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.Streamable;
+
+/**
+ * A holder for CORBA char
that is mapped into
+ * java char
.
+ *
+ * The holders have several application areas. The end user usually
+ * sees them implementing CORBA methods where the primitive type
+ * is passed by reference. While CORBA (or, for example, C) supports
+ * this, the java does not and a wrapper class is required.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public final class WCharHolder
+ implements Streamable
+{
+ /**
+ * The default type code for this holder.
+ */
+ private static final TypeCode t_char = new primitiveTypeCode(TCKind.tk_wchar);
+
+ /**
+ * The char
(CORBA wchar
) value,
+ * held by this WCharHolder.
+ */
+ public char value;
+
+ /**
+ * Constructs an instance of WCharHolder,
+ * initializing {@link #value} to 0
.
+ */
+ public WCharHolder()
+ {
+ }
+
+ /**
+ * Constructs an instance of WCharHolder,
+ * initializing {@link #value} to the given char
.
+ *
+ * @param initial_value a value that will be assigned to the
+ * {@link #value} field.
+ */
+ public WCharHolder(char initial_value)
+ {
+ value = initial_value;
+ }
+
+ /**
+ * Fill in the {@link value } field by reading the required data
+ * from the given stream. For char
, the functionality
+ * is delegated to
+ * {@link org.omg.CORBA.portable.InputStream#read_wchar}.
+ *
+ * @param input the input stream to read from.
+ */
+ public void _read(InputStream input)
+ {
+ value = input.read_wchar();
+ }
+
+ /**
+ * Returns the TypeCode, corresponding the CORBA type that is stored
+ * using this holder.
+ */
+ public TypeCode _type()
+ {
+ return t_char;
+ }
+
+ /**
+ * Write the {@link value } field to the given stream.
+ * For char
, the functionality
+ * is delegated to
+ * {@link org.omg.CORBA.portable.OutputStream#write_wchar(char) }.
+ *
+ * @param output the output stream to write into.
+ */
+ public void _write(OutputStream output)
+ {
+ output.write_wchar(value);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/WStringHolder.java b/libjava/classpath/gnu/CORBA/WStringHolder.java
new file mode 100644
index 0000000..c9e8e33
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/WStringHolder.java
@@ -0,0 +1,129 @@
+/* WStringHolder.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.Streamable;
+
+/**
+ * A holder for CORBA wstring
that is mapped into
+ * java String
. This holder writes and reads differently
+ * from the StringHolder.
+ *
+ * The holders have several application areas. The end user usually
+ * sees them implementing CORBA methods where the primitive type
+ * is passed by reference. While CORBA (or, for example, C) supports
+ * this, the java does not and a wrapper class is required.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class WStringHolder
+ implements Streamable
+{
+ /**
+ * The default type code for this holder.
+ */
+ private static final stringTypeCode t_string =
+ new stringTypeCode(TCKind.tk_wstring);
+
+ /**
+ * The String
(CORBA string
) value,
+ * held by this WStringHolder.
+ */
+ public String value;
+
+ /**
+ * Constructs an instance of WStringHolder,
+ * initializing {@link #value} to null
.
+ */
+ public WStringHolder()
+ {
+ }
+
+ /**
+ * Constructs an instance of WStringHolder,
+ * initializing {@link #value} to the given String
.
+ *
+ * @param initial_value a value that will be assigned to the
+ * {@link #value} field.
+ */
+ public WStringHolder(String initial_value)
+ {
+ value = initial_value;
+ }
+
+ /**
+ * Fill in the {@link #value } field by reading the required data
+ * from the given stream. For string
, the functionality
+ * is delegated to
+ * {@link org.omg.CORBA.portable.InputStream#read_wstring}.
+ *
+ * @param input the input stream to read from.
+ */
+ public void _read(InputStream input)
+ {
+ value = input.read_wstring();
+ }
+
+ /**
+ * Returns the TypeCode, corresponding the CORBA type that is stored
+ * using this holder. The {@link TypeCode#length()} method of the
+ * returned typecode always returns 0.
+ */
+ public TypeCode _type()
+ {
+ return t_string;
+ }
+
+ /**
+ * Write the {@link #value } field to the given stream.
+ * For string
, the functionality
+ * is delegated to
+ * {@link org.omg.CORBA.portable.OutputStream#write_wstring(String) }.
+ *
+ * @param output the output stream to write into.
+ */
+ public void _write(OutputStream output)
+ {
+ output.write_wstring(value);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/_PolicyImplBase.java b/libjava/classpath/gnu/CORBA/_PolicyImplBase.java
new file mode 100644
index 0000000..d9ff9d6
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/_PolicyImplBase.java
@@ -0,0 +1,231 @@
+/* _PolicyImplBase.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.BAD_OPERATION;
+import org.omg.CORBA.CompletionStatus;
+import org.omg.CORBA.Policy;
+import org.omg.CORBA.PolicyHelper;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.InvokeHandler;
+import org.omg.CORBA.portable.ObjectImpl;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.ResponseHandler;
+
+/**
+ * The server side implementation base for the {@link Policy}.
+ *
+ * @specnote The java 1.4 API does not define the server side policy
+ * implementation base, but it defines the policy client side stub.
+ * As these two classes always work together, and even no separate testing is
+ * possible, the required implementation base is provided in gnu.CORBA
+ * namespace. Sun will probably include they base in the future java APIs.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public abstract class _PolicyImplBase
+ extends ObjectImpl
+ implements Policy, InvokeHandler
+{
+ /**
+ * Use serialVersionUID for interoperability.
+ */
+ private static final long serialVersionUID = 1;
+
+ /**
+ * The policy repository ids.
+ */
+ private final String[] ids;
+
+ /**
+ * The type of this policy.
+ */
+ private final int type;
+
+ /**
+ * The value of this policy. The value object is never the same
+ * for different policies.
+ */
+ private final java.lang.Object value;
+
+ /**
+ * The policy integer code, written in request to write
+ * the policy value.
+ */
+ private final int policyCode;
+
+ /**
+ * Create the new policy of the given type, having the given value.
+ * For security reasons, the method is kept package private.
+ *
+ * @param p_type the type of this policy.
+ * @param p_value the value of this policy.
+ * @param p_code the integer code of this policy.
+ * @param p_idl the policy IDL type string. The {@link #_ids()}
+ * will return array, first line being this string and another
+ * being PolicyHelper.id().
+ */
+ public _PolicyImplBase(int p_type, java.lang.Object p_value, int p_code,
+ String p_idl
+ )
+ {
+ type = p_type;
+ value = p_value;
+ policyCode = p_code;
+ ids = new String[] { p_idl, PolicyHelper.id() };
+ }
+
+ /**
+ * Get the integer code of the type of this policy.
+ */
+ public final int policy_type()
+ {
+ return type;
+ }
+
+ /**
+ * Return the list of repository ids.
+ */
+ public final String[] _ids()
+ {
+ return ids;
+ }
+
+ /**
+ * Call the required method.
+ */
+ public final OutputStream _invoke(String method, InputStream input,
+ ResponseHandler rh
+ )
+ {
+ OutputStream output = null;
+
+ if (method.equals("destroy"))
+ {
+ // The "destroy" has been invoked.
+ destroy();
+ output = rh.createReply();
+ }
+ else if (method.equals("copy"))
+ {
+ // The "copy" has been invoked.
+ org.omg.CORBA.Object returns = copy();
+ output = rh.createReply();
+ output.write_Object(this);
+ }
+ else if (method.equals("policy_type"))
+ {
+ // The "policy_type" has been invoked.
+ int returns = policy_type();
+ output = rh.createReply();
+ output.write_long(returns);
+ }
+ else if (method.equals("value"))
+ {
+ // The "value" can be invoked on the children types
+ // and must return an integer, representing the policy value
+ // (CORBA enumeration).
+ output = rh.createReply();
+ output.write_long(policyCode);
+ }
+ else
+ throw new BAD_OPERATION(method, 0, CompletionStatus.COMPLETED_MAYBE);
+
+ return output;
+ }
+
+ /**
+ * Get the value of this policy
+ */
+ public final java.lang.Object getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Get the integer code of this policy value.
+ */
+ public final int getCode()
+ {
+ return policyCode;
+ }
+
+ /**
+ * Returns without action. It is a work of garbage collector
+ * to remove the unused objects.
+ */
+ public final void destroy()
+ {
+ }
+
+ /**
+ * Returns the string representation of the given policy.
+ */
+ public final String toString()
+ {
+ return value.toString();
+ }
+
+ /**
+ * Create a copy of this policy. The object is not mutable, so
+ * this
can be returned.
+ *
+ * @return this
+ */
+ public Policy copy()
+ {
+ return this;
+ }
+
+ /**
+ * Use the value to get a hash code.
+ */
+ public int hashCode()
+ {
+ return getValue().hashCode();
+ }
+
+ /**
+ * Check the values for equality.
+ */
+ public boolean equals(Object x)
+ {
+ return x == null ? false : getValue().equals(x);
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/aliasTypeCode.java b/libjava/classpath/gnu/CORBA/aliasTypeCode.java
new file mode 100644
index 0000000..8846631
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/aliasTypeCode.java
@@ -0,0 +1,142 @@
+/* aliasTypeCode.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+
+/**
+ * The type code that is an alias of another type code.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class aliasTypeCode
+ extends primitiveTypeCode
+{
+ /**
+ * The typecode repository id.
+ */
+ protected final String id;
+
+ /**
+ * The typecode name.
+ */
+ protected final String name;
+
+ /**
+ * The type code for that this typecode is an alias.
+ */
+ protected final TypeCode aliasFor;
+
+ /**
+ * Create the typecode, specifying for that typecode it is an
+ * alias and the id and name of the newly created typecode.
+ *
+ * @param an_aliasFor the typecode, for that this typecode is an
+ * alias.
+ *
+ * @param an_id the repository id fo the newly created typecode.
+ *
+ * @param a_name the name of the newly created typecode.
+ */
+ public aliasTypeCode(TypeCode an_aliasFor, String an_id, String a_name)
+ {
+ super(TCKind.tk_alias);
+ aliasFor = an_aliasFor;
+ id = an_id;
+ name = a_name;
+ }
+
+ /**
+ * Get the typecode, for that this typecode is an alias.
+ */
+ public TypeCode content_type()
+ {
+ return aliasFor;
+ }
+
+ /**
+ * The objects are assumed to be equal if they repository
+ * ids are both equal or both unavailable and the
+ * kind values are equal.
+ *
+ * @param other the other typecode to compare.
+ */
+ public boolean equal(TypeCode other)
+ {
+ if (super.equal(other))
+ return true;
+ try
+ {
+ return id.equals(other.id());
+ }
+ catch (BadKind ex)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Return true if the given typecode is equal for
+ * either this typecode of the alias typecode.
+ *
+ * @param other the typecode to compare.
+ */
+ public boolean equivalent(TypeCode other)
+ {
+ return other.equal(this) || other.equal(aliasFor);
+ }
+
+ /**
+ * Get the repository id of this typecode.
+ */
+ public String id()
+ {
+ return id;
+ }
+
+ /**
+ * Get the name of this typecode.
+ */
+ public String name()
+ {
+ return name;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/binaryReply.java b/libjava/classpath/gnu/CORBA/binaryReply.java
new file mode 100644
index 0000000..71afa37
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/binaryReply.java
@@ -0,0 +1,95 @@
+/* binaryReply.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufInput;
+import gnu.CORBA.GIOP.MessageHeader;
+
+import org.omg.CORBA.ORB;
+
+/**
+ * The remote object reply in the binary form, holding
+ * the message header and the following binary data.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+class binaryReply
+{
+ /**
+ * The message header.
+ */
+ final MessageHeader header;
+
+ /**
+ * The associated orb.
+ */
+ final ORB orb;
+
+ /**
+ * The message data.
+ */
+ final byte[] data;
+
+ /**
+ * Create the binary reply.
+ *
+ * @param an_header the message header
+ * @param a_data the message data.
+ */
+ binaryReply(ORB an_orb, MessageHeader an_header, byte[] a_data)
+ {
+ orb = an_orb;
+ header = an_header;
+ data = a_data;
+ }
+
+ /**
+ * Get the CDR input stream with the correctly set alignment.
+ *
+ * @return the CDR stream to read the message data.
+ */
+ cdrBufInput getStream()
+ {
+ cdrBufInput in = new cdrBufInput(data);
+ in.setOffset(header.getHeaderSize());
+ in.setVersion(header.version);
+ in.setOrb(orb);
+ in.setBigEndian(header.isBigEndian());
+ return in;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/bufferedResponseHandler.java b/libjava/classpath/gnu/CORBA/bufferedResponseHandler.java
new file mode 100644
index 0000000..e7f00ba
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/bufferedResponseHandler.java
@@ -0,0 +1,187 @@
+/* bufferedResponseHandler.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufOutput;
+import gnu.CORBA.GIOP.MessageHeader;
+import gnu.CORBA.GIOP.ReplyHeader;
+import gnu.CORBA.GIOP.cxCodeSet;
+
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.ResponseHandler;
+
+/**
+ * Provides the CDR output streams for writing the response to the given
+ * buffer.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+class bufferedResponseHandler
+ implements ResponseHandler
+{
+ /**
+ * The message header.
+ * This field is used to compute the size and alignments.
+ * It is, however, never directly written to the buffer stream.
+ */
+ final MessageHeader message_header;
+
+ /**
+ * The associated orb.
+ */
+ final ORB orb;
+
+ /**
+ * The reply header. This field is used to compute the size and alignments.
+ * It is, however, never directly written to the buffer stream.
+ */
+ final ReplyHeader reply_header;
+
+ /**
+ * True if the stream was obtained by invoking {@link #createExceptionReply()},
+ * false otherwise.
+ */
+ private boolean exceptionReply;
+
+ /**
+ * The buffer to write into.
+ */
+ private cdrBufOutput buffer;
+
+ /**
+ * Create a new buffered response handler that uses the given message
+ * headers. The headers are used to compute sizes and check the versions.
+ * They are not written into a stream inside this class.
+ *
+ * @param m_header a message header.
+ * @param r_header a reply header.
+ */
+ bufferedResponseHandler(ORB an_orb, MessageHeader m_header,
+ ReplyHeader r_header
+ )
+ {
+ message_header = m_header;
+ reply_header = r_header;
+ orb = an_orb;
+ prepareStream();
+ }
+
+ /**
+ * Get an output stream for providing details about the exception.
+ * Before returning the stream, the handler automatically writes
+ * the message header and the reply about exception header,
+ * but not the message header.
+ *
+ * @return the stream to write exception details into.
+ */
+ public OutputStream createExceptionReply()
+ {
+ exceptionReply = true;
+ prepareStream();
+ return buffer;
+ }
+
+ /**
+ * Get an output stream for writing a regular reply (not an exception).
+ *
+ * Before returning the stream, the handler automatically writes
+ * the regular reply header, but not the message header.
+ *
+ * @return the output stream for writing a regular reply.
+ */
+ public OutputStream createReply()
+ {
+ exceptionReply = false;
+ prepareStream();
+ reply_header.reply_status = ReplyHeader.NO_EXCEPTION;
+ return buffer;
+ }
+
+ /**
+ * Get the buffer, normally containing the written reply.
+ * The reply includes the reply header (or the exception header)
+ * but does not include the message header.
+ *
+ * The stream buffer can also be empty if no data have been written
+ * into streams, returned by {@link #createReply()} or
+ * {@link #createExceptionReply()}.
+ *
+ * @return the CDR output stream, containing the written output.
+ */
+ cdrBufOutput getBuffer()
+ {
+ return buffer;
+ }
+
+ /**
+ * True if the stream was obtained by invoking
+ * {@link #createExceptionReply()}, false otherwise
+ * (usually no-exception reply).
+ */
+ boolean isExceptionReply()
+ {
+ return exceptionReply;
+ }
+
+ /**
+ * Compute the header offset, set the correct version number and codeset.
+ */
+ private void prepareStream()
+ {
+ buffer = new cdrBufOutput();
+ buffer.setOrb(orb);
+ buffer.setOffset(message_header.getHeaderSize());
+
+ // Get the position after the reply header would be written.
+ reply_header.write(buffer);
+
+ int new_offset = message_header.getHeaderSize() + buffer.buffer.size();
+
+ buffer.buffer.reset();
+ buffer.setOffset(new_offset);
+
+ if (message_header.version.since_inclusive(1, 2))
+ buffer.align(8);
+
+ buffer.setVersion(message_header.version);
+
+ buffer.setCodeSet(cxCodeSet.find(reply_header.service_context));
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/cdrEncapsCodec.java b/libjava/classpath/gnu/CORBA/cdrEncapsCodec.java
new file mode 100644
index 0000000..699c6f7
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/cdrEncapsCodec.java
@@ -0,0 +1,356 @@
+/* cdrEncapsCodec.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufInput;
+import gnu.CORBA.CDR.cdrBufOutput;
+import gnu.CORBA.CDR.cdrOutput;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.LocalObject;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.UserException;
+import org.omg.IOP.Codec;
+import org.omg.IOP.CodecPackage.FormatMismatch;
+import org.omg.IOP.CodecPackage.InvalidTypeForEncoding;
+import org.omg.IOP.CodecPackage.TypeMismatch;
+
+/**
+ * The local {@link Codec} implementation for ENCODING_CDR_ENCAPS
+ * encoding. This is a local implementation; the remote side should
+ * have its own Codec of this kind.
+ *
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class cdrEncapsCodec
+ extends LocalObject
+ implements Codec
+{
+ /**
+ * The default version of encoding, used in parameterless constructor.
+ */
+ private static final Version DEFAULT_VERSION = new Version(1, 2);
+
+ /**
+ * If set to true, no wide string or wide character is allowed (GIOP 1.0).
+ */
+ private final boolean noWide;
+
+ /**
+ * The version of this encoding.
+ */
+ private final Version version;
+
+ /**
+ * The associated ORB.
+ */
+ protected final ORB orb;
+
+ /**
+ * If true, this Codec writes the record length (as int) in the beginning
+ * of the record. This indicator is part of the formal OMG standard, but it is
+ * missing in Sun's implementation. Both Suns's and this Codec detects
+ * the indicator, if present, but can also decode data where this information
+ * is missing. If the length indicator is missing, the first four bytes in
+ * Suns encoding are equal to 0 (Big Endian marker).
+ */
+ private boolean lengthIndicator = true;
+
+ /**
+ * Create an instance of this Codec, encoding following the given version.
+ */
+ public cdrEncapsCodec(ORB _orb, Version _version)
+ {
+ orb = _orb;
+ version = _version;
+ noWide = version.until_inclusive(1, 0);
+ }
+
+ /**
+ * Return the array of repository ids for this object.
+ *
+ * @return { "IDL:gnu/CORBA/cdrEnapsCodec:1.0" }, always.
+ */
+ public String[] _ids()
+ {
+ return new String[] { "IDL:gnu/CORBA/cdrEnapsCodec:1.0" };
+ }
+
+ /**
+ * Decode the contents of the byte array into Any.
+ * The byte array may have the optional four byte length indicator
+ * in the beginning. If these four bytes are zero, it is assumed,
+ * that no length indicator is present.
+ */
+ public Any decode(byte[] them)
+ throws FormatMismatch
+ {
+ cdrBufInput input = createInput(them);
+ cdrBufInput encapsulation = createEncapsulation(them, input);
+
+ TypeCode type = encapsulation.read_TypeCode();
+
+ try
+ {
+ checkTypePossibility("", type);
+ }
+ catch (InvalidTypeForEncoding ex)
+ {
+ throw new FormatMismatch(ex.getMessage());
+ }
+
+ return readAny(type, encapsulation);
+ }
+
+ private cdrBufInput createEncapsulation(byte[] them, cdrBufInput input)
+ {
+ cdrBufInput encapsulation;
+
+ if ((them [ 0 ] | them [ 1 ] | them [ 2 ] | them [ 3 ]) == 0)
+ {
+ // Skip that appears to be the always present Big Endian marker.
+ encapsulation = input;
+ input.read_short();
+ }
+ else
+ encapsulation = input.read_encapsulation();
+ return encapsulation;
+ }
+
+ /** {@inheritDoc} */
+ public byte[] encode(Any that)
+ throws InvalidTypeForEncoding
+ {
+ checkTypePossibility("", that.type());
+
+ cdrBufOutput output = createOutput(that);
+
+ // cdrBufOutput has internal support for this encoding.
+ cdrOutput encapsulation = output.createEncapsulation();
+
+ try
+ {
+ TypeCodeHelper.write(encapsulation, that.type());
+ that.write_value(encapsulation);
+
+ encapsulation.close();
+ output.close();
+ }
+ catch (Exception ex)
+ {
+ MARSHAL m = new MARSHAL();
+ m.initCause(ex);
+ throw m;
+ }
+ return output.buffer.toByteArray();
+ }
+
+ /**
+ * Decode the value, stored in the byte array, into Any, assuming,
+ * that the byte array holds the data structure, defined by the
+ * given typecode.
+ *
+ * The byte array may have the optional four byte length indicator
+ * in the beginning. If these four bytes are zero, it is assumed,
+ * that no length indicator is present.
+ */
+ public Any decode_value(byte[] them, TypeCode type)
+ throws FormatMismatch, TypeMismatch
+ {
+ try
+ {
+ checkTypePossibility("", type);
+ }
+ catch (InvalidTypeForEncoding ex)
+ {
+ throw new TypeMismatch(ex.getMessage());
+ }
+
+ cdrBufInput input = createInput(them);
+ cdrBufInput encapsulation = createEncapsulation(them, input);
+ return readAny(type, encapsulation);
+ }
+
+ /**
+ * Read an Any from the given stream.
+ *
+ * @param type a type of the Any to read.
+ * @param input the encapsulation stream.
+ */
+ private Any readAny(TypeCode type, cdrBufInput encapsulation)
+ throws MARSHAL
+ {
+ gnuAny a = new gnuAny();
+ a.setOrb(orb);
+
+ // cdrBufInput has internal support for this encoding.
+ a.read_value(encapsulation, type);
+ return a;
+ }
+
+ /** {@inheritDoc} */
+ public byte[] encode_value(Any that)
+ throws InvalidTypeForEncoding
+ {
+ checkTypePossibility("", that.type());
+
+ cdrBufOutput output = createOutput(that);
+
+ cdrOutput encapsulation = output.createEncapsulation();
+
+ try
+ {
+ that.write_value(encapsulation);
+
+ encapsulation.close();
+ output.close();
+ }
+ catch (Exception ex)
+ {
+ MARSHAL m = new MARSHAL();
+ m.initCause(ex);
+ throw m;
+ }
+ return output.buffer.toByteArray();
+ }
+
+ /**
+ * Create the CDR output stream for writing the given Any.
+ * The cdrBufOutput has internal support for encapsulation encodings.
+ *
+ * @param that the Any that will be written.
+ *
+ * @return the stream.
+ *
+ * @throws InvalidTypeForEncoding if that Any cannot be written under the
+ * given version.
+ */
+ private cdrBufOutput createOutput(Any that)
+ throws InvalidTypeForEncoding
+ {
+ cdrBufOutput output = new cdrBufOutput();
+ output.setOrb(orb);
+ output.setVersion(version);
+ return output;
+ }
+
+ /**
+ * Checks if the given type can be encoded. Currently only checks for wide
+ * strings and wide chars for GIOP 1.0.
+ *
+ * @param t a typecode to chek.
+ *
+ * @throws InvalidTypeForEncoding if the typecode is not valid for the given
+ * version.
+ */
+ private void checkTypePossibility(String name, TypeCode t)
+ throws InvalidTypeForEncoding
+ {
+ if (noWide)
+ {
+ try
+ {
+ int kind = t.kind().value();
+
+ if (kind == TCKind._tk_wchar || kind == TCKind._tk_wstring)
+ throw new InvalidTypeForEncoding(name + " wide char in " +
+ version
+ );
+ else if (kind == TCKind._tk_alias || kind == TCKind._tk_array ||
+ kind == TCKind._tk_sequence
+ )
+ checkTypePossibility("Array member", t.content_type());
+
+ else if (kind == TCKind._tk_struct || kind == TCKind._tk_union)
+ {
+ for (int i = 0; i < t.member_count(); i++)
+ {
+ checkTypePossibility(t.member_name(i), t.member_type(i));
+ }
+ }
+ }
+ catch (UserException ex)
+ {
+ InternalError ierr = new InternalError();
+ ierr.initCause(ex);
+ throw ierr;
+ }
+ }
+ }
+
+ /**
+ * Create the CDR input stream for reading the given byte array.
+ *
+ * @param them a byte array to read.
+ *
+ * @return the stream.
+ */
+ private cdrBufInput createInput(byte[] them)
+ {
+ cdrBufInput input = new cdrBufInput(them);
+ input.setOrb(orb);
+ input.setVersion(version);
+ return input;
+ }
+
+ /**
+ * Check if the Codec writes the length indicator.
+ */
+ public boolean hasLengthIndicator()
+ {
+ return lengthIndicator;
+ }
+
+ /**
+ * Sets if the Codec must write the record length in the beginning of the
+ * array. Encodings both with and without that indicator are understood
+ * both by Suns and this codec, but the OMG specification seems requiring
+ * it. The default behavior is to use the length indicator.
+ *
+ * @param use_lengthIndicator
+ */
+ public void setUseLengthIndicator(boolean use_lengthIndicator)
+ {
+ lengthIndicator = use_lengthIndicator;
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/corbaArrayList.java b/libjava/classpath/gnu/CORBA/corbaArrayList.java
new file mode 100644
index 0000000..1690f05
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/corbaArrayList.java
@@ -0,0 +1,115 @@
+/* corbaArrayList.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import java.io.Serializable;
+
+import java.util.ArrayList;
+
+import org.omg.CORBA.Bounds;
+
+/**
+ * This class is used to store array lists. Differently from
+ * the java.util lists,
+ * it throws {@link org.omg.CORBA.Bounds} rather than
+ * {@link IndexOutOfBoundsException}.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class corbaArrayList
+ extends ArrayList
+ implements Serializable
+{
+ /**
+ * Use serialVersionUID for interoperability.
+ */
+ private static final long serialVersionUID = 1;
+
+ /**
+ * Creates the list with the given initial size.
+ */
+ public corbaArrayList(int initial_size)
+ {
+ super(initial_size);
+ }
+
+ /**
+ * Creates the list with the default size.
+ */
+ public corbaArrayList()
+ {
+ }
+
+ /**
+ * Remove the item at the given index.
+ * @param at the index
+ * @throws org.omg.CORBA.Bounds if the index is out of bounds.
+ */
+ public void drop(int at)
+ throws Bounds
+ {
+ try
+ {
+ super.remove(at);
+ }
+ catch (IndexOutOfBoundsException ex)
+ {
+ throw new Bounds("[" + at + "], valid [0.." + size() + "]");
+ }
+ }
+
+ /**
+ * Get the item at the given index.
+ * @param at the index
+ * @return the item at the index
+ * @throws org.omg.CORBA.Bounds if the index is out of bounds.
+ */
+ public Object item(int at)
+ throws Bounds
+ {
+ try
+ {
+ return super.get(at);
+ }
+ catch (IndexOutOfBoundsException ex)
+ {
+ throw new Bounds("[" + at + "], valid [0.." + size() + "]");
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/fixedTypeCode.java b/libjava/classpath/gnu/CORBA/fixedTypeCode.java
new file mode 100644
index 0000000..ec88c22
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/fixedTypeCode.java
@@ -0,0 +1,149 @@
+/* fixedTypeCode.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import java.math.BigDecimal;
+
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+
+/**
+ * A typecode for CORBA fixed
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class fixedTypeCode
+ extends primitiveTypeCode
+{
+ /**
+ * The number of the used digits.
+ */
+ private short digits;
+
+ /**
+ * The number of the digits after the decimal point.
+ */
+ private short scale;
+
+ /**
+ * Creates the instance of the fixed type code.
+ */
+ public fixedTypeCode()
+ {
+ super(TCKind.tk_fixed);
+ }
+
+ /**
+ * Creates the instance of the fixed type code,
+ * setting the digits and scale by example.
+ */
+ public fixedTypeCode(BigDecimal example)
+ {
+ super(TCKind.tk_fixed);
+ if (example != null)
+ {
+ setScale(example.scale());
+ setDigits(countDigits(example));
+ }
+ }
+
+ /**
+ * Set the number of digits.
+ */
+ public void setDigits(int a_digits)
+ {
+ this.digits = (short) a_digits;
+ }
+
+ /**
+ * Set the number of digits after the decimal point.
+ */
+ public void setScale(int a_scale)
+ {
+ this.scale = (short) a_scale;
+ }
+
+ /**
+ * Get the number of digits in thid BigDecimal
+ *
+ * @param x a BigDecimal to check.
+ */
+ public static int countDigits(BigDecimal number)
+ {
+ return number.unscaledValue().abs().toString().length();
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+ if (!(other instanceof TypeCode))
+ {
+ return false;
+ }
+ try
+ {
+ TypeCode that = (TypeCode) other;
+ return kind() == that.kind() && digits == that.fixed_digits() &&
+ scale == that.fixed_scale();
+ }
+ catch (BadKind ex)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Get the number of digits.
+ */
+ public short fixed_digits()
+ {
+ return digits;
+ }
+
+ /**
+ * Get the number of digits after the decimal point.
+ */
+ public short fixed_scale()
+ {
+ return scale;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/generalTypeCode.java b/libjava/classpath/gnu/CORBA/generalTypeCode.java
new file mode 100644
index 0000000..3b79148
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/generalTypeCode.java
@@ -0,0 +1,243 @@
+/* generalTypeCode.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufOutput;
+
+import java.util.Arrays;
+import java.util.BitSet;
+
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+
+/**
+ * A typecode for types, requiring to provide various additional
+ * properties but still not requiring to store the
+ * members of the structure. The property can be retrieved
+ * by the corresponding method if it has been previously assigned.
+ * Otherwise, a {@link BadKind} is thrown.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class generalTypeCode
+ extends primitiveTypeCode
+{
+ /**
+ * Indicates that the field value has not been previously set.
+ */
+ protected static int UNSET = Integer.MIN_VALUE;
+
+ /**
+ * The kinds for that the length() must return 0 even if it
+ * has not been previously set.
+ */
+ private static final BitSet lengthAllowed = new BitSet();
+
+ static
+ {
+ lengthAllowed.set(TCKind._tk_array);
+ lengthAllowed.set(TCKind._tk_sequence);
+ lengthAllowed.set(TCKind._tk_string);
+ lengthAllowed.set(TCKind._tk_wstring);
+ }
+
+ private String id;
+ private String name;
+ private TypeCode concrete_base_type;
+ private TypeCode content_type;
+ private int len;
+ private int type_modifier = UNSET;
+
+ /**
+ * Create a new instance, setting kind to the given kind.
+ * @param kind
+ */
+ public generalTypeCode(TCKind kind)
+ {
+ super(kind);
+ if (!lengthAllowed.get(kind.value()))
+ len = UNSET;
+ }
+
+ /**
+ * Set this property.
+ */
+ public void setConcreteBase_type(TypeCode concrete_base_type)
+ {
+ this.concrete_base_type = concrete_base_type;
+ }
+
+ /**
+ * Set the component content type.
+ */
+ public void setContentType(TypeCode a_content_type)
+ {
+ this.content_type = a_content_type;
+ }
+
+ /**
+ * Set this property.
+ */
+ public void setId(String id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * Set the length property.
+ * @param l
+ */
+ public void setLength(int l)
+ {
+ len = l;
+ }
+
+ /**
+ * Set this property.
+ */
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * Set the type modifier.
+ */
+ public void setTypeModifier(int a_type_modifier)
+ {
+ this.type_modifier = a_type_modifier;
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode concrete_base_type()
+ throws BadKind
+ {
+ if (concrete_base_type != null)
+ return concrete_base_type;
+ throw new BadKind("concrete_base_type");
+ }
+
+ /**
+ * Returns the content type that must be explicitly set
+ * for this class.
+ *
+ * @throws BadKind if the content type has not been set.
+ */
+ public TypeCode content_type()
+ throws BadKind
+ {
+ if (content_type != null)
+ return content_type;
+ throw new BadKind("content_type");
+ }
+
+ /**
+ * Returns true if both typecodes, if written into CDR
+ * stream, would result the same stream content.
+ */
+ public boolean equal(TypeCode other)
+ {
+ if (this == other)
+ return true;
+ if (kind() != other.kind())
+ return false;
+
+ cdrBufOutput a = new cdrBufOutput(16);
+ cdrBufOutput b = new cdrBufOutput(16);
+
+ a.write_TypeCode(this);
+ b.write_TypeCode(other);
+
+ return Arrays.equals(a.buffer.toByteArray(), b.buffer.toByteArray());
+ }
+
+ /**
+ * Delegates functionality to {@link #equal}.
+ */
+ public boolean equivalent(TypeCode other)
+ {
+ return equal(other);
+ }
+
+ /** {@inheritDoc} */
+ public String id()
+ throws BadKind
+ {
+ if (id != null)
+ return id;
+ throw new BadKind("id");
+ }
+
+ /**
+ * Get the length. For sequences, arrays, strings and wstrings
+ * this method returns 0 rather than throwing a BadKind even
+ * if {@link setLength(int)} has not been previously called.
+ *
+ * @return the length of string, array or sequence.
+ *
+ * @throws BadKind if the method cannot be invoked for the
+ * given kind of typecode.
+ */
+ public int length()
+ throws BadKind
+ {
+ if (len != UNSET)
+ return len;
+ throw new BadKind("length");
+ }
+
+ /** {@inheritDoc} */
+ public String name()
+ throws BadKind
+ {
+ if (name != null)
+ return name;
+ throw new BadKind("name");
+ }
+
+ /** {@inheritDoc} */
+ public short type_modifier()
+ throws BadKind
+ {
+ if (type_modifier != UNSET)
+ return (short) type_modifier;
+ throw new BadKind("type_modifier");
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/gnuAny.java b/libjava/classpath/gnu/CORBA/gnuAny.java
new file mode 100644
index 0000000..a48c50d
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/gnuAny.java
@@ -0,0 +1,830 @@
+/* gnuAny.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufInput;
+import gnu.CORBA.CDR.cdrBufOutput;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.AnyHolder;
+import org.omg.CORBA.BAD_OPERATION;
+import org.omg.CORBA.BooleanHolder;
+import org.omg.CORBA.CharHolder;
+import org.omg.CORBA.DoubleHolder;
+import org.omg.CORBA.FixedHolder;
+import org.omg.CORBA.FloatHolder;
+import org.omg.CORBA.IntHolder;
+import org.omg.CORBA.LongHolder;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.ObjectHolder;
+import org.omg.CORBA.Principal;
+import org.omg.CORBA.PrincipalHolder;
+import org.omg.CORBA.ShortHolder;
+import org.omg.CORBA.StringHolder;
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodeHolder;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+import org.omg.CORBA.ValueBaseHolder;
+import org.omg.CORBA.portable.Streamable;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import java.lang.reflect.Field;
+
+import java.math.BigDecimal;
+
+import java.util.Arrays;
+
+/**
+ * The implementation of {@link Any}.
+ *
+ * For performance reasonse, the inserted values are not cloned.
+ * If the value object allows modifications (like {@link Streamable}),
+ * these subsequent alterations are reflected by the instance of
+ * this gnuAny, and the gnuAny alterations are reflected by the
+ * returned value. If it is required to have the uncoupled value,
+ * it must be requested from the copy of the current instance.
+ * The {@link gnuAny} can be simply cloned by the provided
+ * {@link Clone()} method.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class gnuAny
+ extends Any
+{
+ /**
+ * The value, returned by {@link #type()} if the value has been
+ * not intialized.
+ */
+ protected static final TypeCode nullType =
+ new primitiveTypeCode(TCKind.tk_null);
+
+ /**
+ * The Streamable, representing the value, held by this gnuAny.
+ */
+ protected Streamable has;
+
+ /**
+ * The complete typecode of the Streamable, if explicitly set.
+ */
+ protected TypeCode typecode;
+
+ /**
+ * The typecode kind of the Streamable, if explicitly set.
+ */
+ protected int xKind = -1;
+
+ /**
+ * The associated ORB.
+ */
+ private ORB orb;
+
+ /**
+ * Set the associated orb.
+ */
+ public void setOrb(ORB an_orb)
+ {
+ orb = an_orb;
+ }
+
+ /**
+ * Creates a deep copy of this gnuAny, writing to and subsequently
+ * reading from from the byte buffer.
+ *
+ * @return the uncoupled gnuAny with all fields set to identical
+ * values.
+ */
+ public gnuAny Clone()
+ {
+ cdrBufOutput out = new cdrBufOutput();
+ out.setOrb(orb);
+ out.write_any(this);
+
+ cdrBufInput in = new cdrBufInput(out.buffer.toByteArray());
+ in.setOrb(orb);
+ return (gnuAny) in.read_any();
+ }
+
+ /**
+ * Create the buffered CDR input stream, containing the
+ * value, stored inside of this {@link Any}.
+ */
+ public org.omg.CORBA.portable.InputStream create_input_stream()
+ {
+ if (has instanceof universalHolder)
+ {
+ universalHolder u = (universalHolder) has;
+ return u.getInputStream();
+ }
+ else
+ {
+ cdrBufOutput out = new cdrBufOutput();
+ out.setOrb(orb);
+ write_value(out);
+
+ cdrBufInput in = new cdrBufInput(out.buffer.toByteArray());
+ in.setOrb(orb);
+ return in;
+ }
+ }
+
+ /**
+ * Create the buffered CDR output stream (empty).
+ */
+ public org.omg.CORBA.portable.OutputStream create_output_stream()
+ {
+ cdrBufOutput stream = new cdrBufOutput();
+ stream.setOrb(orb);
+ return stream;
+ }
+
+ /**
+ * Compare two Any's for equality.
+ * @param other the other Any to compare.
+ */
+ public boolean equal(Any other)
+ {
+ if (other == this)
+ return true;
+ if (type().kind() != other.type().kind())
+ return false;
+
+ if (has != null && other instanceof gnuAny)
+ if (has.equals(((gnuAny) other).has))
+ return true;
+
+ cdrBufOutput a = new cdrBufOutput();
+ a.setOrb(orb);
+ write_value(a);
+
+ cdrBufOutput b = new cdrBufOutput();
+ b.setOrb(orb);
+ other.write_value(b);
+
+ byte[] ba = a.buffer.toByteArray();
+ byte[] bb = b.buffer.toByteArray();
+
+ return Arrays.equals(ba, bb);
+ }
+
+ /**
+ * Delegates functionality to {@link #equal(Any)}.
+ */
+ public boolean equals(java.lang.Object other)
+ {
+ if (other == this)
+ return true;
+ if (!(other instanceof Any))
+ return false;
+
+ return equal((Any) other);
+ }
+
+ /**
+ * Extract the previously stored object.
+ */
+ public org.omg.CORBA.Object extract_Object()
+ {
+ try
+ {
+ return ((ObjectHolder) has).value;
+ }
+ catch (ClassCastException ex)
+ {
+ throw new BAD_OPERATION();
+ }
+ }
+
+ /**
+ * Extract the previously inserted CORBA Principal
/
+ * @return the previously inserted value.
+ *
+ * @throws org.omg.CORBA.BAD_OPERATION if the holder contains something
+ * else than Principal.
+ *
+ * @deprecated by CORBA 2.2.
+ */
+ public Principal extract_Principal()
+ {
+ check(TCKind._tk_Principal);
+ return ((PrincipalHolder) has).value;
+ }
+
+ /**
+ * Return the value, encapsulated in a suitable holder.
+ * This implementation returns the direct reference,
+ * so the alterations on the returned streamable are
+ * directly reflected to the content of this {@link Any}.
+ */
+ public Streamable extract_Streamable()
+ {
+ return has;
+ }
+
+ public TypeCode extract_TypeCode()
+ throws BAD_OPERATION
+ {
+ check(TCKind._tk_TypeCode);
+ return ((TypeCodeHolder) has).value;
+ }
+
+ /**
+ * Extract the stored value type.
+ *
+ * @return the previously stored value type.
+ *
+ * @throws BAD_OPERATION if the Any contains something different.
+ *
+ * @see org.omg.CORBA.portable.ValueBase
+ */
+ public Serializable extract_Value()
+ throws BAD_OPERATION
+ {
+ try
+ {
+ if (has instanceof ValueBaseHolder)
+ return ((ValueBaseHolder) has).value;
+ else
+ {
+ // Normally, ValueBase holder must be an instance of the
+ // ValueBaseHolder. However some IDL compilers probably
+ // have a bug, do not deriving this way. The the only
+ // way to access the wrapped value is via reflection.
+ Field f = has.getClass().getField("value");
+ return (Serializable) f.get(has);
+ }
+ }
+ catch (Exception ex)
+ {
+ return new BAD_OPERATION("Value type expected");
+ }
+ }
+
+ /** {@inheritDoc} */
+ public Any extract_any()
+ throws BAD_OPERATION
+ {
+ check(TCKind._tk_any);
+ return ((AnyHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public boolean extract_boolean()
+ throws BAD_OPERATION
+ {
+ check(TCKind._tk_boolean);
+ return ((BooleanHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public char extract_char()
+ throws BAD_OPERATION
+ {
+ check(TCKind._tk_char);
+ return ((CharHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public double extract_double()
+ throws BAD_OPERATION
+ {
+ check(TCKind._tk_double);
+ return ((DoubleHolder) has).value;
+ }
+
+ /**
+ * Extract the previously inserted CORBA fixed
/
+ * @return the previously inserted value.
+ *
+ * @throws org.omg.CORBA.BAD_OPERATION if the holder contains something
+ * else than BigDecimal.
+ */
+ public BigDecimal extract_fixed()
+ throws org.omg.CORBA.BAD_OPERATION
+ {
+ check(TCKind._tk_fixed);
+ return ((FixedHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public float extract_float()
+ throws BAD_OPERATION
+ {
+ check(TCKind._tk_float);
+ return ((FloatHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public int extract_long()
+ throws BAD_OPERATION
+ {
+ // CORBA long = java int.
+ check(TCKind._tk_long);
+ return ((IntHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public long extract_longlong()
+ throws BAD_OPERATION
+ {
+ check(TCKind._tk_longlong);
+ return ((LongHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public byte extract_octet()
+ throws BAD_OPERATION
+ {
+ // ShortHolder holds also octets.
+ check(TCKind._tk_octet);
+ return (byte) ((OctetHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public short extract_short()
+ throws BAD_OPERATION
+ {
+ check(TCKind._tk_short);
+ return ((ShortHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public String extract_string()
+ throws BAD_OPERATION
+ {
+ check(TCKind._tk_string);
+ return ((StringHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public int extract_ulong()
+ throws BAD_OPERATION
+ {
+ // IntHolder also holds ulongs.
+ check(TCKind._tk_ulong);
+ return ((IntHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public long extract_ulonglong()
+ throws BAD_OPERATION
+ {
+ // LongHolder also holds ulonglong
+ check(TCKind._tk_ulonglong);
+ return ((LongHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public short extract_ushort()
+ throws BAD_OPERATION
+ {
+ // ShortHolder also holds ushorts.
+ check(TCKind._tk_ushort);
+ return ((ShortHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public char extract_wchar()
+ throws BAD_OPERATION
+ {
+ check(TCKind._tk_wchar);
+ return ((WCharHolder) has).value;
+ }
+
+ /** {@inheritDoc} */
+ public String extract_wstring()
+ throws BAD_OPERATION
+ {
+ // StringHolder also holds wstrings.
+ check(TCKind._tk_wstring);
+ return ((WStringHolder) has).value;
+ }
+
+ /**
+ * Inserts the CORBA object and sets the typecode to the given type.
+ */
+ public void insert_Object(org.omg.CORBA.Object x, TypeCode typecode)
+ {
+ has = new ObjectHolder(x);
+ type(typecode);
+ }
+
+ /**
+ * Inserts the CORBA object.
+ */
+ public void insert_Object(org.omg.CORBA.Object x)
+ {
+ has = new ObjectHolder(x);
+ }
+
+ /**
+ * Insert the CORBA Principal.
+ * This implementation uses direct assignment, so the later
+ * alterations of that BigDecimal are reflected on the
+ * content of this {@link Any}.
+ *
+ * @deprecated by CORBA 2.2.
+ */
+ public void insert_Principal(Principal x)
+ {
+ resetTypes();
+ if (has instanceof PrincipalHolder)
+ ((PrincipalHolder) has).value = x;
+ else
+ has = new PrincipalHolder(x);
+ }
+
+ /**
+ * Sets the value to the value, encapsulated in this holder.
+ * This implementation uses direct assignment, so the later
+ * alterations of that streamable are reflected on the
+ * content of this {@link Any}.
+ */
+ public void insert_Streamable(Streamable x)
+ {
+ resetTypes();
+ has = x;
+ }
+
+ /**
+ * Insert the typecode into this Any
+ * @param typecode the typecode to insert.
+ */
+ public void insert_TypeCode(TypeCode typecode)
+ {
+ resetTypes();
+ if (has instanceof TypeCodeHolder)
+ ((TypeCodeHolder) has).value = typecode;
+ else
+ has = new TypeCodeHolder(typecode);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_Value(Serializable x, TypeCode typecode)
+ {
+ type(typecode);
+ insert_Value(x);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_Value(Serializable x)
+ {
+ resetTypes();
+ if (has instanceof ValueBaseHolder)
+ ((ValueBaseHolder) has).value = x;
+ else
+ has = new ValueBaseHolder(x);
+ }
+
+ /**
+ * Insert another {@link Any} into this {@link Any}.
+ * This implementation uses direct assignment, so the later
+ * alterations of that {@link Any} are reflected on the
+ * content of this {@link Any}.
+ */
+ public void insert_any(Any an_any)
+ {
+ resetTypes();
+ if (has instanceof AnyHolder)
+ ((AnyHolder) has).value = an_any;
+ else
+ has = new AnyHolder(an_any);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_boolean(boolean x)
+ {
+ resetTypes();
+ if (has instanceof BooleanHolder)
+ ((BooleanHolder) has).value = x;
+ else
+ has = new BooleanHolder(x);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_char(char x)
+ {
+ resetTypes();
+ if (has instanceof CharHolder)
+ ((CharHolder) has).value = x;
+ else
+ has = new CharHolder(x);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_double(double x)
+ {
+ resetTypes();
+ if (has instanceof DoubleHolder)
+ ((DoubleHolder) has).value = x;
+ else
+ has = new DoubleHolder(x);
+ }
+
+ /**
+ * Inserts the CORBA fixed
, setting the typecode
+ * explicitly.
+ * This implementation uses direct assignment, so the later
+ * alterations of that BigDecimal are reflected on the
+ * content of this {@link Any}.
+ */
+ public void insert_fixed(BigDecimal x, TypeCode x_typecode)
+ {
+ resetTypes();
+ insert_fixed(x);
+ typecode = x_typecode;
+ }
+
+ /**
+ * Inserts the CORBA fixed
, setting the typecode
+ * by example of the currently passed value.
+ * This implementation uses direct assignment, so the later
+ * alterations of that BigDecimal are reflected on the
+ * content of this {@link Any}, including the typecode.
+ */
+ public void insert_fixed(BigDecimal x)
+ {
+ resetTypes();
+ if (has instanceof FixedHolder)
+ ((FixedHolder) has).value = x;
+ else
+ has = new FixedHolder(x);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_float(float x)
+ {
+ resetTypes();
+ if (has instanceof FloatHolder)
+ ((FloatHolder) has).value = x;
+ else
+ has = new FloatHolder(x);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_long(int x)
+ {
+ resetTypes();
+ if (has instanceof IntHolder)
+ ((IntHolder) has).value = x;
+ else
+ has = new IntHolder(x);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_longlong(long x)
+ {
+ resetTypes();
+ if (has instanceof LongHolder)
+ ((LongHolder) has).value = x;
+ else
+ has = new LongHolder(x);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_octet(byte x)
+ {
+ resetTypes();
+ if (has instanceof OctetHolder)
+ ((OctetHolder) has).value = x;
+ else
+ has = new OctetHolder(x);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_short(short x)
+ {
+ resetTypes();
+ if (has instanceof ShortHolder)
+ ((ShortHolder) has).value = x;
+ else
+ has = new ShortHolder(x);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_string(String x)
+ {
+ resetTypes();
+ if (has instanceof StringHolder)
+ ((StringHolder) has).value = x;
+ else
+ has = new StringHolder(x);
+
+ typecode = new stringTypeCode(TCKind.tk_string);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_ulong(int x)
+ {
+ resetTypes();
+ if (has instanceof IntHolder)
+ ((IntHolder) has).value = x;
+ else
+ has = new IntHolder(x);
+ xKind = TCKind._tk_ulong;
+ }
+
+ /** {@inheritDoc} */
+ public void insert_ulonglong(long x)
+ {
+ resetTypes();
+ if (has instanceof LongHolder)
+ ((LongHolder) has).value = x;
+ else
+ has = new LongHolder(x);
+ xKind = TCKind._tk_ulonglong;
+ }
+
+ /** {@inheritDoc} */
+ public void insert_ushort(short x)
+ {
+ resetTypes();
+ if (has instanceof ShortHolder)
+ ((ShortHolder) has).value = x;
+ else
+ has = new ShortHolder(x);
+ xKind = TCKind._tk_ushort;
+ }
+
+ /** {@inheritDoc} */
+ public void insert_wchar(char x)
+ {
+ resetTypes();
+ if (has instanceof WCharHolder)
+ ((WCharHolder) has).value = x;
+ else
+ has = new WCharHolder(x);
+ }
+
+ /** {@inheritDoc} */
+ public void insert_wstring(String x)
+ {
+ resetTypes();
+ if (has instanceof WStringHolder)
+ ((WStringHolder) has).value = x;
+ else
+ has = new WStringHolder(x);
+ }
+
+ /**
+ * Return the associated orb.
+ */
+ public ORB orb()
+ {
+ return orb;
+ }
+
+ /**
+ * Read the value of the given type from the given stream.
+ *
+ * @param input a stream to read from.
+ * @param a_type a typecode of the value to read.
+ */
+ public void read_value(org.omg.CORBA.portable.InputStream input,
+ TypeCode a_type
+ )
+ throws MARSHAL
+ {
+ try
+ {
+ int kind = a_type.kind().value();
+
+ // Fixed needs special handling.
+ if (kind == TCKind._tk_fixed)
+ {
+ BigDecimal dec = BigDecimalHelper.read(input, a_type.fixed_scale());
+ has = new FixedHolder(dec);
+ }
+ else
+ {
+ has = holderFactory.createHolder(a_type);
+ if (has == null)
+ {
+ // Use the Universal Holder that reads till the end of stream.
+ // This works with the extract/insert pair of the typical
+ // Helper.
+ cdrBufOutput buffer = new cdrBufOutput();
+ buffer.setOrb(orb);
+ has = new universalHolder(buffer);
+ }
+ }
+ type(a_type);
+ has._read(input);
+ }
+ catch (BadKind ex)
+ {
+ throw new MARSHAL("Bad kind: " + ex.getMessage());
+ }
+ catch (IOException ex)
+ {
+ throw new MARSHAL("IO exception: " + ex.getMessage());
+ }
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode type()
+ {
+ if (typecode != null)
+ return typecode;
+ else if (xKind >= 0)
+ {
+ typecode = new primitiveTypeCode(TCKind.from_int(xKind));
+ return typecode;
+ }
+ else
+ return has != null ? has._type() : nullType;
+ }
+
+ /**
+ * Explicitly set the typecode of the value to the given type.
+ *
+ * @param valueTypeCode the typecode of the value.
+ */
+ public void type(TypeCode valueTypeCode)
+ {
+ xKind = valueTypeCode.kind().value();
+ typecode = valueTypeCode;
+ }
+
+ /** {@inheritDoc} */
+ public void write_value(org.omg.CORBA.portable.OutputStream output)
+ {
+ if (has != null)
+ has._write(output);
+ }
+
+ /**
+ * Check if the current value if the value of the given kind.
+ * @param kind a kind to check.
+ * @throws BAD_OPERATION if the value is not set of is different kind.
+ */
+ protected void check(int kind)
+ throws BAD_OPERATION
+ {
+ if (has == null)
+ throw new BAD_OPERATION("value not set");
+
+ if (xKind >= 0)
+ {
+ if (xKind != kind)
+ throw new BAD_OPERATION("Extracting " + typeNamer.nameIt(kind) +
+ " when stored " + typeNamer.nameIt(xKind)
+ );
+ }
+ else
+ {
+ if (type().kind().value() != kind)
+ throw new BAD_OPERATION("Extracting " + typeNamer.nameIt(kind) +
+ " stored " + typeNamer.nameIt(type())
+ );
+ }
+ }
+
+ /**
+ * Clear the additional type information before reusing this instance.
+ */
+ private final void resetTypes()
+ {
+ typecode = null;
+ xKind = -1;
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/gnuCodecFactory.java b/libjava/classpath/gnu/CORBA/gnuCodecFactory.java
new file mode 100644
index 0000000..8b71baf
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/gnuCodecFactory.java
@@ -0,0 +1,95 @@
+/* gnuCodecFactory.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.*;
+import org.omg.CORBA.LocalObject;
+import org.omg.IOP.*;
+import org.omg.IOP.Codec;
+import org.omg.IOP.CodecFactory;
+import org.omg.IOP.CodecFactoryPackage.UnknownEncoding;
+import org.omg.IOP.Encoding;
+
+/**
+ * A simple implementation of the Codec factory, able to return the
+ * standard Codec's. Only ENCODING_CDR_ENCAPS encoding is supported.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class gnuCodecFactory
+ extends LocalObject
+ implements CodecFactory
+{
+ /**
+ * The associated ORB.
+ */
+ private final ORB orb;
+
+ /**
+ * Create a new instance of the this factory, associated with the given ORB.
+ */
+ public gnuCodecFactory(ORB an_orb)
+ {
+ orb = an_orb;
+ }
+
+ /**
+ * Creates the Codec for the given encoding.
+ *
+ * @param for_encoding the encoding for that the Codec must be created.
+ *
+ * @return the suitable Codec.
+ *
+ * @throws UnknownEncoding if the encoding is not a ENCODING_CDR_ENCAPS.
+ */
+ public Codec create_codec(Encoding for_encoding)
+ throws UnknownEncoding
+ {
+ if (for_encoding.format != ENCODING_CDR_ENCAPS.value)
+ throw new UnknownEncoding("Only ENCODING_CDR_ENCAPS is " +
+ "supported by this factory."
+ );
+
+ return new cdrEncapsCodec(orb,
+ new Version(for_encoding.major_version,
+ for_encoding.minor_version
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/gnuContext.java b/libjava/classpath/gnu/CORBA/gnuContext.java
new file mode 100644
index 0000000..baa9fc8
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/gnuContext.java
@@ -0,0 +1,202 @@
+/* gnuContext.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.Bounds;
+import org.omg.CORBA.CTX_RESTRICT_SCOPE;
+import org.omg.CORBA.Context;
+import org.omg.CORBA.NVList;
+
+/**
+ * The working implementation of the {@link org.omg.CORBA.Context}.
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class gnuContext
+ extends Context
+{
+ /**
+ * The parent context.
+ */
+ Context parent;
+
+ /**
+ * The collection to store the context properties.
+ */
+ Map properties = new Hashtable();
+
+ /**
+ * The name of this context.
+ */
+ String name;
+
+ /**
+ * Creates the new context with the given name and parent.
+ *
+ * @param a_name a name of the new context.
+ * @param a_parent a parent, used to resolve the missing references.
+ */
+ public gnuContext(String a_name, Context a_parent)
+ {
+ name = a_name;
+ parent = a_parent;
+ }
+
+ /** {@inheritDoc} */
+ public String context_name()
+ {
+ return name;
+ }
+
+ /** {@inheritDoc} */
+ public Context create_child(String child)
+ {
+ return new gnuContext(child, this);
+ }
+
+ /** {@inheritDoc} */
+ public void delete_values(String property)
+ {
+ boolean starts = false;
+ if (property.endsWith("*"))
+ {
+ starts = true;
+ property = property.substring(0, property.length() - 1);
+ }
+
+ Set keys = properties.keySet();
+
+ Iterator iter = keys.iterator();
+ while (iter.hasNext())
+ {
+ String key = (String) iter.next();
+ if ((starts && key.startsWith(property)) ||
+ (!starts && key.equals(property))
+ )
+ iter.remove();
+ }
+ }
+
+ /** {@inheritDoc} */
+ public NVList get_values(String start_scope, int flags, String pattern)
+ {
+ if (start_scope != null)
+ {
+ Context c = this;
+ while (c != null && !c.context_name().equals(start_scope))
+ c = c.parent();
+ if (c == null)
+ return new gnuNVList();
+ }
+
+ try
+ {
+ gnuNVList rt = new gnuNVList();
+
+ boolean starts = false;
+ if (pattern.endsWith("*"))
+ {
+ starts = true;
+ pattern = pattern.substring(0, pattern.length() - 1);
+ }
+
+ Set keys = properties.keySet();
+
+ Iterator iter = keys.iterator();
+ while (iter.hasNext())
+ {
+ String key = (String) iter.next();
+ if ((starts && key.startsWith(pattern)) ||
+ (!starts && key.equals(pattern))
+ )
+ {
+ rt.add_value(key, (Any) properties.get(key), 0);
+ }
+ }
+
+ if ((flags & CTX_RESTRICT_SCOPE.value) == 0 && parent != null)
+ {
+ NVList par = parent.get_values(start_scope, flags, pattern);
+ for (int i = 0; i < par.count(); i++)
+ {
+ rt.list.add(par.item(i));
+ }
+ }
+
+ return rt;
+ }
+ catch (Bounds ex)
+ {
+ throw new Error("Report this bug.");
+ }
+ }
+
+ /** {@inheritDoc} */
+ public Context parent()
+ {
+ return parent;
+ }
+
+ /** {@inheritDoc} */
+ public void set_one_value(String name, Any value)
+ {
+ properties.put(name, value);
+ }
+
+ /** {@inheritDoc} */
+ public void set_values(NVList values)
+ {
+ try
+ {
+ for (int i = 0; i < values.count(); i++)
+ {
+ properties.put(values.item(i).name(), values.item(i).value());
+ }
+ }
+ catch (Bounds ex)
+ {
+ throw new Error("Please report this bug.");
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/gnuContextList.java b/libjava/classpath/gnu/CORBA/gnuContextList.java
new file mode 100644
index 0000000..2a26437
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/gnuContextList.java
@@ -0,0 +1,83 @@
+/* gnuContextList.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import java.util.ArrayList;
+
+import org.omg.CORBA.Bounds;
+import org.omg.CORBA.ContextList;
+
+/**
+ * The working implementation of the {@link org.omg.CORBA.ContextList}.
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class gnuContextList
+ extends ContextList
+{
+ /**
+ * The collection, holding the actual list of strings.
+ */
+ corbaArrayList strings = new corbaArrayList();
+
+ /** {@inheritDoc} */
+ public void add(String name)
+ {
+ strings.add(name);
+ }
+
+ /** {@inheritDoc} */
+ public int count()
+ {
+ return strings.size();
+ }
+
+ /** {@inheritDoc} */
+ public String item(int at)
+ throws Bounds
+ {
+ return (String) strings.item(at);
+ }
+
+ /** {@inheritDoc} */
+ public void remove(int at)
+ throws Bounds
+ {
+ strings.drop(at);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/gnuEnvironment.java b/libjava/classpath/gnu/CORBA/gnuEnvironment.java
new file mode 100644
index 0000000..ba02e3b
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/gnuEnvironment.java
@@ -0,0 +1,72 @@
+/* gnuEnvironment.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.Environment;
+
+/**
+ * The implementation of the exception container ("Environment").
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class gnuEnvironment
+ extends Environment
+{
+ /**
+ * The stored exception.
+ */
+ protected Exception exception;
+
+ /** {@inheritDoc} */
+ public void clear()
+ {
+ exception = null;
+ }
+
+ /** {@inheritDoc} */
+ public void exception(Exception except)
+ {
+ exception = except;
+ }
+
+ /** {@inheritDoc} */
+ public Exception exception()
+ {
+ return exception;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/gnuExceptionList.java b/libjava/classpath/gnu/CORBA/gnuExceptionList.java
new file mode 100644
index 0000000..b684ec9
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/gnuExceptionList.java
@@ -0,0 +1,84 @@
+/* gnuExceptionList.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import java.util.ArrayList;
+
+import org.omg.CORBA.Bounds;
+import org.omg.CORBA.ExceptionList;
+import org.omg.CORBA.TypeCode;
+
+/**
+ * The implementation of the list of type codes for exceptions.
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org).
+ */
+public class gnuExceptionList
+ extends ExceptionList
+{
+ /**
+ * A list to store the objects.
+ */
+ protected corbaArrayList list = new corbaArrayList();
+
+ /** {@inheritDoc} */
+ public void add(TypeCode an_exception)
+ {
+ list.add(an_exception);
+ }
+
+ /** {@inheritDoc} */
+ public int count()
+ {
+ return list.size();
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode item(int at)
+ throws Bounds
+ {
+ return (TypeCode) list.item(at);
+ }
+
+ /** {@inheritDoc} */
+ public void remove(int at)
+ throws Bounds
+ {
+ list.drop(at);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/gnuNVList.java b/libjava/classpath/gnu/CORBA/gnuNVList.java
new file mode 100644
index 0000000..e436c33
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/gnuNVList.java
@@ -0,0 +1,127 @@
+/* gnuNVList.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.Bounds;
+import org.omg.CORBA.NVList;
+import org.omg.CORBA.NamedValue;
+
+/**
+ * The implementation of {@link NVList}.
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class gnuNVList
+ extends NVList
+{
+ /**
+ * The list of the named values.
+ */
+ protected corbaArrayList list;
+
+ /**
+ * Creates the list with the default initial size.
+ */
+ public gnuNVList()
+ {
+ list = new corbaArrayList();
+ }
+
+ /**
+ * Creates the list with the given initial size.
+ */
+ public gnuNVList(int initial_size)
+ {
+ list = new corbaArrayList(initial_size);
+ }
+
+ /** {@inheritDoc} */
+ public NamedValue add(int a_flags)
+ {
+ return add_value(null, new gnuAny(), a_flags);
+ }
+
+ /** {@inheritDoc} */
+ public NamedValue add_item(String a_name, int a_flags)
+ {
+ return add_value(a_name, new gnuAny(), a_flags);
+ }
+
+ /** {@inheritDoc} */
+ public NamedValue add_value(String a_name, Any a_value, int a_flags)
+ {
+ gnuNamedValue n = new gnuNamedValue();
+ n.setName(a_name);
+ n.setValue(a_value);
+ n.setFlags(a_flags);
+ list.add(n);
+ return n;
+ }
+
+ /**
+ * Add the given named value to the list directly.
+ *
+ * @param value the named vaue to add.
+ */
+ public void add(NamedValue value)
+ {
+ list.add(value);
+ }
+
+
+ /** {@inheritDoc} */
+ public int count()
+ {
+ return list.size();
+ }
+
+ /** {@inheritDoc} */
+ public NamedValue item(int at)
+ throws Bounds
+ {
+ return (NamedValue) list.item(at);
+ }
+
+ /** {@inheritDoc} */
+ public void remove(int at)
+ throws Bounds
+ {
+ list.drop(at);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/gnuNamedValue.java b/libjava/classpath/gnu/CORBA/gnuNamedValue.java
new file mode 100644
index 0000000..6e3c271
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/gnuNamedValue.java
@@ -0,0 +1,112 @@
+/* gnuNamedValue.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.NamedValue;
+
+/**
+ * The implementation of the named value.
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class gnuNamedValue
+ extends NamedValue
+{
+ /**
+ * The named value value.
+ */
+ private Any m_value = new gnuAny();
+
+ /**
+ * The named value name.
+ */
+ private String m_name;
+
+ /**
+ * The named value flags.
+ */
+ private int m_flags;
+
+ /**
+ * Set the flags, the normally expected values are
+ * {@link org.omg.CORBA.ARG_IN#value},
+ * {@link org.omg.CORBA.ARG_OUT#value} and
+ * {@link org.omg.CORBA.ARG_INOUT#value}.
+ */
+ public void setFlags(int flags)
+ {
+ m_flags = flags;
+ }
+
+ /**
+ * Set the name of the value.
+ * @param name the name of this value
+ */
+ public void setName(String name)
+ {
+ m_name = name;
+ }
+
+ /**
+ * Set the value of the value.
+ * @param value the value of this object.
+ */
+ public void setValue(Any value)
+ {
+ m_value = value;
+ }
+
+ /** {@inheritDoc} */
+ public int flags()
+ {
+ return m_flags;
+ }
+
+ /** {@inheritDoc} */
+ public String name()
+ {
+ return m_name;
+ }
+
+ /** {@inheritDoc} */
+ public Any value()
+ {
+ return m_value;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/gnuRequest.java b/libjava/classpath/gnu/CORBA/gnuRequest.java
new file mode 100644
index 0000000..a47410e
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/gnuRequest.java
@@ -0,0 +1,1008 @@
+/* gnuRequest.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufInput;
+import gnu.CORBA.CDR.cdrBufOutput;
+import gnu.CORBA.GIOP.CloseMessage;
+import gnu.CORBA.GIOP.MessageHeader;
+import gnu.CORBA.GIOP.ReplyHeader;
+import gnu.CORBA.GIOP.RequestHeader;
+import gnu.CORBA.GIOP.cxCodeSet;
+
+import org.omg.CORBA.ARG_IN;
+import org.omg.CORBA.ARG_INOUT;
+import org.omg.CORBA.ARG_OUT;
+import org.omg.CORBA.Any;
+import org.omg.CORBA.BAD_INV_ORDER;
+import org.omg.CORBA.Bounds;
+import org.omg.CORBA.Context;
+import org.omg.CORBA.ContextList;
+import org.omg.CORBA.Environment;
+import org.omg.CORBA.ExceptionList;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.NO_RESOURCES;
+import org.omg.CORBA.NVList;
+import org.omg.CORBA.NamedValue;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.Request;
+import org.omg.CORBA.SystemException;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.UnknownUserException;
+import org.omg.CORBA.UserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.net.BindException;
+import java.net.Socket;
+
+/**
+ * The implementation of the CORBA request.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class gnuRequest
+ extends Request
+ implements Cloneable
+{
+ /**
+ * The maximal supported GIOP version.
+ */
+ public static Version MAX_SUPPORTED = new Version(1, 2);
+
+ /**
+ * The initial pause that the Request makes when
+ * the required port is not available.
+ */
+ public static int PAUSE_INITIAL = 50;
+
+ /**
+ * The number of repretetive attempts to get a required
+ * port, if it is not immediately available.
+ */
+ public static int PAUSE_STEPS = 12;
+
+ /**
+ * The maximal pausing interval between two repetetive attempts.
+ * The interval doubles after each unsuccessful attempt, but
+ * will not exceed this value.
+ */
+ public static int PAUSE_MAX = 1000;
+
+ /**
+ * The empty byte array.
+ */
+ private static final binaryReply EMPTY =
+ new binaryReply(null, new MessageHeader(), new byte[ 0 ]);
+
+ /**
+ * The context holder for methods ctx(Context) and ctx().
+ */
+ protected Context m_context;
+
+ /**
+ * The context list for method contexts().
+ */
+ protected ContextList m_context_list;
+
+ /**
+ * The request environment for holding the exception
+ * the has possibly been thrown by the method being invoked.
+ */
+ protected Environment m_environment = new gnuEnvironment();
+
+ /**
+ * The list of all exceptions that can be thrown by the
+ * method being invoked.
+ */
+ protected ExceptionList m_exceptions = new gnuExceptionList();
+
+ /**
+ * The result, returned by the invoked method (function).
+ */
+ protected NamedValue m_result = new gnuNamedValue();
+
+ /**
+ * The invocation target.
+ */
+ protected org.omg.CORBA.Object m_target;
+
+ /**
+ * The name of the method being invoked.
+ */
+ protected String m_operation;
+
+ /**
+ * The flag, indicating that the request has been sent
+ * and the result is already received.
+ */
+ protected boolean complete;
+
+ /**
+ * The flag, indicating that the response to this request must be
+ * ignored (used with {@link #send_oneway()}).
+ */
+ protected boolean oneWay;
+
+ /**
+ * The flag, indicating that the request has been sent
+ * and no result is yet received.
+ */
+ protected boolean running;
+
+ /**
+ * The request arguments.
+ */
+ protected gnuNVList m_args = new gnuNVList();
+
+ /**
+ * The request arguments in the case when they are directly written into
+ * the parameter buffer.
+ */
+ protected streamRequest m_parameter_buffer;
+
+ /**
+ * The IOR of the target.
+ */
+ private IOR ior;
+
+ /**
+ * The ORB of the target.
+ */
+ private ORB orb;
+
+ /**
+ * The encoding, used to send the message.
+ *
+ * The default encoding is inherited from the set IOR
+ * (that string reference can be encoded in either Big or
+ * Little endian). If the IOR encoding is not known
+ * (for example, by obtaining the reference from the naming
+ * service), the Big Endian is used.
+ */
+ private boolean Big_endian = true;
+
+ /**
+ * Set the IOR data, sufficient to find the invocation target.
+ * This also sets default endian encoding for invocations.
+ *
+ * @see IOR.parse(String)
+ */
+ public void setIor(IOR an_ior)
+ {
+ ior = an_ior;
+ setBigEndian(ior.Big_Endian);
+ }
+
+ /**
+ * Get the IOR data, sufficient to find the invocation target.
+ *
+ * @return the IOR data.
+ */
+ public IOR getIor()
+ {
+ return ior;
+ }
+
+ /**
+ * Set the ORB, related to the invocation target.
+ */
+ public void setORB(ORB an_orb)
+ {
+ orb = an_orb;
+ }
+
+ /**
+ * Set the encoding that will be used to send the message.
+ * The default encoding is inherited from the set IOR
+ * (that string reference can be encoded in either Big or
+ * Little endian). If the IOR encoding is not known
+ * (for example, by obtaining the reference from the naming
+ * service), the Big Endian is used.
+ *
+ * @param use_big_endian true to use the Big Endian, false
+ * to use the Little Endian encoding.
+ */
+ public void setBigEndian(boolean use_big_endian)
+ {
+ Big_endian = use_big_endian;
+ }
+
+ /**
+ * The the method name to invoke.
+ *
+ * @param operation the method name.
+ */
+ public void setOperation(String operation)
+ {
+ m_operation = operation;
+ }
+
+ /**
+ * Get the parameter stream, where the invocation arguments should
+ * be written if they are written into the stream directly.
+ */
+ public streamRequest getParameterStream()
+ {
+ m_parameter_buffer = new streamRequest();
+ m_parameter_buffer.request = this;
+ m_parameter_buffer.setVersion(ior.Internet.version);
+ m_parameter_buffer.setCodeSet(cxCodeSet.negotiate(ior.CodeSets));
+ m_parameter_buffer.setOrb(orb);
+ m_parameter_buffer.setBigEndian(Big_endian);
+ return m_parameter_buffer;
+ }
+
+ /**
+ * Creates a shallow copy of this request.
+ */
+ public gnuRequest Clone()
+ {
+ try
+ {
+ return (gnuRequest) clone();
+ }
+ catch (CloneNotSupportedException ex)
+ {
+ throw new Unexpected(ex);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public Any add_in_arg()
+ {
+ gnuNamedValue v = new gnuNamedValue();
+ v.setFlags(ARG_IN.value);
+ m_args.add(v);
+ return v.value();
+ }
+
+ /** {@inheritDoc} */
+ public Any add_inout_arg()
+ {
+ gnuNamedValue v = new gnuNamedValue();
+ v.setFlags(ARG_INOUT.value);
+ m_args.add(v);
+ return v.value();
+ }
+
+ /** {@inheritDoc} */
+ public Any add_named_in_arg(String name)
+ {
+ gnuNamedValue v = new gnuNamedValue();
+ v.setFlags(ARG_IN.value);
+ v.setName(name);
+ m_args.add(v);
+ return v.value();
+ }
+
+ /** {@inheritDoc} */
+ public Any add_named_inout_arg(String name)
+ {
+ gnuNamedValue v = new gnuNamedValue();
+ v.setFlags(ARG_INOUT.value);
+ v.setName(name);
+ m_args.add(v);
+ return v.value();
+ }
+
+ /** {@inheritDoc} */
+ public Any add_named_out_arg(String name)
+ {
+ gnuNamedValue v = new gnuNamedValue();
+ v.setFlags(ARG_OUT.value);
+ v.setName(name);
+ m_args.add(v);
+ return v.value();
+ }
+
+ /** {@inheritDoc} */
+ public Any add_out_arg()
+ {
+ gnuNamedValue v = new gnuNamedValue();
+ v.setFlags(ARG_OUT.value);
+ m_args.add(v);
+ return v.value();
+ }
+
+ /** {@inheritDoc} */
+ public NVList arguments()
+ {
+ return m_args;
+ }
+
+ /** {@inheritDoc} */
+ public ContextList contexts()
+ {
+ return m_context_list;
+ }
+
+ /** {@inheritDoc} */
+ public Context ctx()
+ {
+ return m_context;
+ }
+
+ /** {@inheritDoc} */
+ public void ctx(Context a_context)
+ {
+ m_context = a_context;
+ }
+
+ /** {@inheritDoc} */
+ public Environment env()
+ {
+ return m_environment;
+ }
+
+ /** {@inheritDoc} */
+ public ExceptionList exceptions()
+ {
+ return m_exceptions;
+ }
+
+ /** {@inheritDoc} */
+ public void get_response()
+ throws org.omg.CORBA.WrongTransaction
+ {
+ /**
+ * The response is ready after it is received.
+ * FIXME implement context checks and any other functionality,
+ * if required.
+ */
+ }
+
+ /**
+ * Submit the request, suspending the current thread until the
+ * answer is received.
+ *
+ * This implementation requires to set the IOR property
+ * ({@link #setIOR(IOR)} before calling this method.
+ *
+ * @throws BAD_INV_ORDER, minor code 0, if the IOR has not been
+ * previously set.
+ *
+ * @throws SystemException if this exception has been thrown on
+ * remote side. The exact exception type and the minor code are
+ * the same as they have been for the exception, thrown on remoted
+ * side.
+ */
+ public synchronized void invoke()
+ throws BAD_INV_ORDER
+ {
+ waitWhileBusy();
+ complete = false;
+ running = true;
+
+ if (ior == null)
+ throw new BAD_INV_ORDER("Set IOR property first");
+
+ try
+ {
+ p_invoke();
+ }
+ finally
+ {
+ running = false;
+ complete = true;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public String operation()
+ {
+ return m_operation;
+ }
+
+ /**
+ * Get the orb, related to the invocation target.
+ */
+ public ORB orb()
+ {
+ return orb;
+ }
+
+ /** {@inheritDoc} */
+ public boolean poll_response()
+ {
+ return complete && !running;
+ }
+
+ /** {@inheritDoc} */
+ public NamedValue result()
+ {
+ return m_result;
+ }
+
+ /** {@inheritDoc}
+ *
+ */
+ public Any return_value()
+ {
+ return m_result.value();
+ }
+
+ /** {@inheritDoc} */
+ public synchronized void send_deferred()
+ {
+ waitWhileBusy();
+ new Thread()
+ {
+ public void run()
+ {
+ invoke();
+ }
+ }.start();
+ }
+
+ /**
+ * Send a request and forget about it, not waiting for a response.
+ * This can be done also for methods that normally are expected
+ * to return some values.
+ *
+ * TODO It is generally recommended to reuse the threads. Reuse?
+ */
+ public void send_oneway()
+ {
+ final gnuRequest cloned = Clone();
+ cloned.oneWay = true;
+
+ new Thread()
+ {
+ public void run()
+ {
+ cloned.invoke();
+ }
+ }.start();
+ }
+
+ /**
+ * Set the argument list.
+ * This field is initialised as empty non null instance by default,
+ * so the method is only used in cases when the direct replacement
+ * is desired.
+ *
+ * @param a_args the argument list.
+ */
+ public void set_args(NVList a_args)
+ {
+ if (a_args instanceof gnuNVList)
+ m_args = (gnuNVList) a_args;
+ else
+ {
+ try
+ {
+ // In case if this is another implementation of the NVList.
+ m_args.list.clear();
+ for (int i = 0; i < a_args.count(); i++)
+ {
+ m_args.add(a_args.item(i));
+ }
+ }
+ catch (Bounds ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+ }
+
+ /**
+ * Set the context list that is later returned by the
+ * method {@link #contexts()}.
+ *
+ * @param a_context_list a new context list.
+ */
+ public void set_context_list(ContextList a_context_list)
+ {
+ m_context_list = a_context_list;
+ }
+
+ /**
+ * Set the exception container.
+ * This field is initialised as empty non null instance by default,
+ * so the method is only used in cases when the direct replacement
+ * is desired.
+ *
+ * @param a_environment the new exception container.
+ */
+ public void set_environment(Environment a_environment)
+ {
+ m_environment = a_environment;
+ }
+
+ /**
+ * Set the list of exceptions.
+ * This field is initialised as empty non null instance by default,
+ * so the method is only used in cases when the direct replacement
+ * is desired.
+ *
+ * @param a_exceptions a list of exceptions.
+ */
+ public void set_exceptions(ExceptionList a_exceptions)
+ {
+ m_exceptions = a_exceptions;
+ }
+
+ /**
+ * Set the operation name.
+ *
+ * @param a_operation the operation name.
+ */
+ public void set_operation(String a_operation)
+ {
+ m_operation = a_operation;
+ }
+
+ /**
+ * Set the named value, returned as result.
+ * This field is initialised as empty non null instance by default,
+ * so the method is only used in cases when the direct replacement
+ * is desired.
+ *
+ * @param a_result the result keeper.
+ */
+ public void set_result(NamedValue a_result)
+ {
+ m_result = a_result;
+ }
+
+ /**
+ * Set the type of the named value, returned as a result.
+ * Instantiates a new instance of the result value.
+ */
+ public void set_return_type(TypeCode returns)
+ {
+ if (m_result == null || !returns.equal(m_result.value().type()))
+ {
+ m_result = new gnuNamedValue();
+ m_result.value().type(returns);
+ }
+ }
+
+ /**
+ * Set the invocation target.
+ *
+ * @param a_target the CORBA object for that the method will be invoked.
+ */
+ public void set_target(org.omg.CORBA.Object a_target)
+ {
+ m_target = a_target;
+ }
+
+ /**
+ * Do the actual invocation.
+ * This implementation requires to set the IOR property
+ * ({@link #setIOR(IOR)} before calling this method.
+ *
+ * @throws BAD_INV_ORDER, minor code 0, if the IOR has not been
+ * previously set or if the direct argument addition is mixed with
+ * the direct argument writing into the output stream.
+ *
+ * @return the server response in binary form.
+ */
+ public synchronized binaryReply submit()
+ {
+ gnu.CORBA.GIOP.MessageHeader header = new gnu.CORBA.GIOP.MessageHeader();
+
+ header.setBigEndian(Big_endian);
+
+ // The byte order will be Big Endian by default.
+ header.message_type = gnu.CORBA.GIOP.MessageHeader.REQUEST;
+ header.version = useVersion(ior.Internet.version);
+
+ RequestHeader rh = header.create_request_header();
+
+ rh.object_key = ior.key;
+ rh.operation = m_operation;
+
+ // Prepare the submission.
+ cdrBufOutput request_part = new cdrBufOutput();
+
+ request_part.setOffset(header.getHeaderSize());
+ request_part.setVersion(header.version);
+ request_part.setCodeSet(cxCodeSet.negotiate(ior.CodeSets));
+ request_part.setOrb(orb);
+ request_part.setBigEndian(header.isBigEndian());
+
+ // This also sets the stream encoding to the encoding, specified
+ // in the header.
+ rh.write(request_part);
+
+ if (m_args != null && m_args.count() > 0)
+ {
+ write_parameters(header, request_part);
+
+ if (m_parameter_buffer != null)
+ throw new BAD_INV_ORDER("Please either add parameters or " +
+ "write them into stream, but not both " +
+ "at once."
+ );
+ }
+
+ if (m_parameter_buffer != null)
+ {
+ write_parameter_buffer(header, request_part);
+ }
+
+ // Now the message size is available.
+ header.message_size = request_part.buffer.size();
+
+ Socket socket = null;
+
+ java.lang.Object key = ior.Internet.host + ":" + ior.Internet.port;
+
+ synchronized (SocketRepository.class)
+ {
+ socket = SocketRepository.get_socket(key);
+ }
+
+ try
+ {
+ long pause = PAUSE_INITIAL;
+
+ if (socket == null)
+ {
+ // The BindException may be thrown under very heavy parallel
+ // load. For some time, just wait, exceptiong the socket to free.
+ Open:
+ for (int i = 0; i < PAUSE_STEPS; i++)
+ {
+ try
+ {
+ socket = new Socket(ior.Internet.host, ior.Internet.port);
+ break Open;
+ }
+ catch (BindException ex)
+ {
+ try
+ {
+ // Expecting to free a socket via finaliser.
+ System.gc();
+ Thread.sleep(pause);
+ pause = pause * 2;
+ if (pause > PAUSE_MAX)
+ pause = PAUSE_MAX;
+ }
+ catch (InterruptedException iex)
+ {
+ }
+ }
+ }
+ }
+
+ if (socket == null)
+ throw new NO_RESOURCES(ior.Internet.host + ":" + ior.Internet.port +
+ " in use"
+ );
+ socket.setKeepAlive(true);
+
+ OutputStream socketOutput = socket.getOutputStream();
+
+ // Write the message header.
+ header.write(socketOutput);
+
+ // Write the request header and parameters (if present).
+ request_part.buffer.writeTo(socketOutput);
+
+ socketOutput.flush();
+ if (!socket.isClosed())
+ {
+ MessageHeader response_header = new MessageHeader();
+ InputStream socketInput = socket.getInputStream();
+ response_header.read(socketInput);
+
+ byte[] r = new byte[ response_header.message_size ];
+ int n = 0;
+ reading:
+ while (n < r.length)
+ {
+ n += socketInput.read(r, n, r.length - n);
+ }
+ return new binaryReply(orb, response_header, r);
+ }
+ else
+ return EMPTY;
+ }
+ catch (IOException io_ex)
+ {
+ MARSHAL m =
+ new MARSHAL("Unable to open a socket at " + ior.Internet.host + ":" +
+ ior.Internet.port
+ );
+ m.initCause(io_ex);
+ throw m;
+ }
+ finally
+ {
+ try
+ {
+ if (socket != null && !socket.isClosed())
+ {
+ socket.setSoTimeout(Functional_ORB.TANDEM_REQUESTS);
+ SocketRepository.put_socket(key, socket);
+ }
+ }
+ catch (IOException scx)
+ {
+ InternalError ierr = new InternalError();
+ ierr.initCause(scx);
+ throw ierr;
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public org.omg.CORBA.Object target()
+ {
+ return m_target;
+ }
+
+ /**
+ * Get the used version. Normally, it is better to respond using the
+ * same version as it is specified in IOR, but not above the maximal
+ * supported version.
+ */
+ public Version useVersion(Version desired)
+ {
+ if (desired.until_inclusive(MAX_SUPPORTED.major, MAX_SUPPORTED.minor))
+ return desired;
+ else
+ return MAX_SUPPORTED;
+ }
+
+ /**
+ * Wait while the response to request, submitted using
+ * {@link #send_deferred()} or {@link #invoke()} (from other thread)
+ * is returned.
+ *
+ * FIXME It is possible to rewrite this using
+ * Object.wait() and Object.notify(), but be sure to prepare the test
+ * as well.
+ */
+ public synchronized void waitWhileBusy()
+ {
+ // Waiting constants.
+ long wait = 10;
+ long increment = 2;
+ long max = 5000;
+
+ while (running)
+ {
+ try
+ {
+ Thread.sleep(wait);
+ if (wait < max)
+ wait = wait * increment;
+ }
+ catch (InterruptedException ex)
+ {
+ }
+ }
+ }
+
+ /**
+ * Do actual invocation. This method recursively calls itself if
+ * the redirection is detected.
+ */
+ private void p_invoke()
+ throws SystemException
+ {
+ binaryReply response = submit();
+
+ ReplyHeader rh = response.header.create_reply_header();
+ cdrBufInput input = response.getStream();
+ input.setOrb(orb);
+
+ rh.read(input);
+
+ // The stream must be aligned sinve v1.2, but only once.
+ boolean align = response.header.version.since_inclusive(1, 2);
+
+ boolean moved_permanently = false;
+
+ switch (rh.reply_status)
+ {
+ case ReplyHeader.NO_EXCEPTION :
+
+ NamedValue arg;
+
+ // Read return value, if set.
+ if (m_result != null)
+ {
+ if (align)
+ {
+ input.align(8);
+ align = false;
+ }
+ m_result.value().read_value(input, m_result.value().type());
+ }
+
+ // Read returned parameters, if set.
+ if (m_args != null)
+ for (int i = 0; i < m_args.count(); i++)
+ {
+ try
+ {
+ arg = m_args.item(i);
+
+ // Both ARG_INOUT and ARG_OUT have this binary flag set.
+ if ((arg.flags() & ARG_OUT.value) != 0)
+ {
+ if (align)
+ {
+ input.align(8);
+ align = false;
+ }
+
+ arg.value().read_value(input, arg.value().type());
+ }
+ }
+ catch (Bounds ex)
+ {
+ Unexpected.error(ex);
+ }
+ }
+
+ break;
+
+ case ReplyHeader.SYSTEM_EXCEPTION :
+ if (align)
+ {
+ input.align(8);
+ align = false;
+ }
+
+ SystemException exception = ObjectCreator.readSystemException(input);
+
+ m_environment.exception(exception);
+
+ throw exception;
+
+ case ReplyHeader.USER_EXCEPTION :
+ if (align)
+ {
+ input.align(8);
+ align = false;
+ }
+
+ // Prepare an Any that will hold the exception.
+ gnuAny exc = new gnuAny();
+
+ exc.insert_Streamable(new streamReadyHolder(input));
+
+ UnknownUserException unuex = new UnknownUserException(exc);
+ m_environment.exception(unuex);
+
+ break;
+
+ case ReplyHeader.LOCATION_FORWARD_PERM :
+ case ReplyHeader.LOCATION_FORWARD :
+ if (response.header.version.since_inclusive(1, 2))
+ input.align(8);
+
+ IOR forwarded = new IOR();
+ try
+ {
+ forwarded._read_no_endian(input);
+ }
+ catch (IOException ex)
+ {
+ throw new MARSHAL(ex + " while reading the forwarding info");
+ }
+
+ setIor(forwarded);
+
+ // Repeat with the forwarded information.
+ p_invoke();
+ return;
+
+ default :
+ throw new MARSHAL("Unknow reply status: " + rh.reply_status);
+ }
+ }
+
+ /**
+ * Write the operation parameters.
+ *
+ * @param header the message header
+ * @param request_part the stream to write parameters into
+ *
+ * @throws MARSHAL if the attempt to write the parameters has failde.
+ */
+ private void write_parameter_buffer(MessageHeader header,
+ cdrBufOutput request_part
+ )
+ throws MARSHAL
+ {
+ try
+ {
+ if (header.version.since_inclusive(1, 2))
+ {
+ request_part.align(8);
+ }
+ m_parameter_buffer.buffer.writeTo(request_part);
+ }
+ catch (IOException ex)
+ {
+ throw new MARSHAL("Unable to write method arguments to CDR output.");
+ }
+ }
+
+ /**
+ * Write the operation parameters.
+ *
+ * @param header the message header
+ * @param request_part the stream to write parameters into
+ *
+ * @throws MARSHAL if the attempt to write the parameters has failde.
+ */
+ private void write_parameters(MessageHeader header, cdrBufOutput request_part)
+ throws MARSHAL
+ {
+ // Align after 1.2, but only once.
+ boolean align = header.version.since_inclusive(1, 2);
+ NamedValue para;
+
+ try
+ {
+ // Write parameters now.
+ for (int i = 0; i < m_args.count(); i++)
+ {
+ para = m_args.item(i);
+
+ //This bit is set both for ARG_IN and ARG_INOUT
+ if ((para.flags() & ARG_IN.value) != 0)
+ {
+ if (align)
+ {
+ request_part.align(8);
+ align = false;
+ }
+ para.value().write_value(request_part);
+ }
+ }
+ }
+ catch (Bounds ex)
+ {
+ throw new MARSHAL("Unable to write method arguments to CDR output.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/holderFactory.java b/libjava/classpath/gnu/CORBA/holderFactory.java
new file mode 100644
index 0000000..177797a
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/holderFactory.java
@@ -0,0 +1,183 @@
+/* holderFactory.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.AnyHolder;
+import org.omg.CORBA.AnySeqHolder;
+import org.omg.CORBA.BooleanHolder;
+import org.omg.CORBA.BooleanSeqHolder;
+import org.omg.CORBA.CharHolder;
+import org.omg.CORBA.CharSeqHolder;
+import org.omg.CORBA.DoubleHolder;
+import org.omg.CORBA.DoubleSeqHolder;
+import org.omg.CORBA.FixedHolder;
+import org.omg.CORBA.FloatHolder;
+import org.omg.CORBA.FloatSeqHolder;
+import org.omg.CORBA.IntHolder;
+import org.omg.CORBA.LongHolder;
+import org.omg.CORBA.LongLongSeqHolder;
+import org.omg.CORBA.LongSeqHolder;
+import org.omg.CORBA.OctetSeqHolder;
+import org.omg.CORBA.PrincipalHolder;
+import org.omg.CORBA.ShortHolder;
+import org.omg.CORBA.ShortSeqHolder;
+import org.omg.CORBA.StringHolder;
+import org.omg.CORBA.StringSeqHolder;
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodeHolder;
+import org.omg.CORBA.ULongLongSeqHolder;
+import org.omg.CORBA.ULongSeqHolder;
+import org.omg.CORBA.UShortSeqHolder;
+import org.omg.CORBA.WCharSeqHolder;
+import org.omg.CORBA.WStringSeqHolder;
+import org.omg.CORBA.portable.Streamable;
+
+/**
+ * Creates the suitable holder for storing the value of the given
+ * type.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class holderFactory
+{
+ /**
+ * The array, sufficiently large to use any {@link TCKind}._tk* constant
+ * as an index.
+ */
+ private static final Class[] holders;
+ private static final Class[] seqHolders;
+
+ static
+ {
+ holders = new Class[ 32 ];
+ holders [ TCKind._tk_Principal ] = PrincipalHolder.class;
+ holders [ TCKind._tk_TypeCode ] = TypeCodeHolder.class;
+ holders [ TCKind._tk_any ] = AnyHolder.class;
+ holders [ TCKind._tk_boolean ] = BooleanHolder.class;
+ holders [ TCKind._tk_char ] = CharHolder.class;
+ holders [ TCKind._tk_double ] = DoubleHolder.class;
+ holders [ TCKind._tk_float ] = FloatHolder.class;
+ holders [ TCKind._tk_fixed ] = FixedHolder.class;
+ holders [ TCKind._tk_long ] = IntHolder.class;
+ holders [ TCKind._tk_longdouble ] = DoubleHolder.class;
+ holders [ TCKind._tk_longlong ] = LongHolder.class;
+ holders [ TCKind._tk_octet ] = OctetHolder.class;
+ holders [ TCKind._tk_short ] = ShortHolder.class;
+ holders [ TCKind._tk_string ] = StringHolder.class;
+ holders [ TCKind._tk_ulong ] = IntHolder.class;
+ holders [ TCKind._tk_ulonglong ] = LongHolder.class;
+ holders [ TCKind._tk_ushort ] = ShortHolder.class;
+ holders [ TCKind._tk_wchar ] = WCharHolder.class;
+ holders [ TCKind._tk_wstring ] = WStringHolder.class;
+
+ seqHolders = new Class[ 32 ];
+
+ seqHolders [ TCKind._tk_ulonglong ] = ULongLongSeqHolder.class;
+ seqHolders [ TCKind._tk_short ] = ShortSeqHolder.class;
+ seqHolders [ TCKind._tk_octet ] = OctetSeqHolder.class;
+ seqHolders [ TCKind._tk_any ] = AnySeqHolder.class;
+ seqHolders [ TCKind._tk_long ] = LongSeqHolder.class;
+ seqHolders [ TCKind._tk_longlong ] = LongLongSeqHolder.class;
+ seqHolders [ TCKind._tk_float ] = FloatSeqHolder.class;
+ seqHolders [ TCKind._tk_double ] = DoubleSeqHolder.class;
+ seqHolders [ TCKind._tk_char ] = CharSeqHolder.class;
+ seqHolders [ TCKind._tk_boolean ] = BooleanSeqHolder.class;
+ seqHolders [ TCKind._tk_wchar ] = WCharSeqHolder.class;
+ seqHolders [ TCKind._tk_ushort ] = UShortSeqHolder.class;
+ seqHolders [ TCKind._tk_ulong ] = ULongSeqHolder.class;
+ seqHolders [ TCKind._tk_string ] = StringSeqHolder.class;
+ seqHolders [ TCKind._tk_wstring ] = WStringSeqHolder.class;
+ }
+
+ /**
+ * Create a holder for storing the value of the given built-in type.
+ * This function returns the defined holders for the built-in primitive
+ * types and they sequences.
+ *
+ * @param t the typecode
+ *
+ * @return an instance of the corresponding built-in holder of null
+ * if no such is defined for this type. The holder is created with a
+ * parameterless constructor.
+ */
+ public static Streamable createHolder(TypeCode t)
+ {
+ try
+ {
+ int kind = t.kind().value();
+ int componentKind;
+
+ Streamable holder = null;
+ Streamable component;
+
+ if (kind < holders.length && holders [ kind ] != null)
+ holder = (Streamable) holders [ kind ].newInstance();
+
+ if (holder != null)
+ return holder;
+
+ switch (kind)
+ {
+ case TCKind._tk_sequence :
+ componentKind = t.content_type().kind().value();
+ if (componentKind < seqHolders.length)
+ return (Streamable) seqHolders [ componentKind ].newInstance();
+ break;
+
+ default :
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new Unexpected(ex);
+ }
+
+ try
+ {
+ Object ox = ObjectCreator.createObject(t.id(), "Holder");
+ return (Streamable) ox;
+ }
+ catch (Exception ex)
+ {
+ return null;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/primitiveArrayTypeCode.java b/libjava/classpath/gnu/CORBA/primitiveArrayTypeCode.java
new file mode 100644
index 0000000..7e2beeb
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/primitiveArrayTypeCode.java
@@ -0,0 +1,265 @@
+/* primitiveArrayTypeCode.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+
+/**
+ * A TypeCode for arrays.
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class primitiveArrayTypeCode
+ extends primitiveTypeCode
+{
+ /**
+ * The array components.
+ */
+ TypeCode of;
+
+ /**
+ * The length of the array, must be updated when setting
+ * a new value.
+ */
+ private int length;
+
+ /**
+ * Create a primitive array type code, defining the sequence
+ * {@link TCKind.tk_sequence)} with
+ * the given member type.
+ *
+ * @param array_of the sequence member type.
+ */
+ public primitiveArrayTypeCode(TCKind array_of)
+ {
+ super(TCKind.tk_sequence);
+ of = new primitiveTypeCode(array_of);
+ }
+
+ /**
+ * Create a primitive array type code, defining the array, sequence
+ * or other type with the given member type.
+ *
+ * @param this_type the type of this type (normally either
+ * sequence of array).
+ * @param array_of the sequence member type.
+ */
+ public primitiveArrayTypeCode(TCKind this_type, TypeCode array_of)
+ {
+ super(this_type);
+ of = array_of;
+ }
+
+ /**
+ * Return the array component type.
+ * @return the array component type
+ * @throws org.omg.CORBA.TypeCodePackage.BadKind
+ */
+ public TypeCode content_type()
+ throws org.omg.CORBA.TypeCodePackage.BadKind
+ {
+ return of;
+ }
+
+ /**
+ * Return true if the other TypeCode defines the array, having elements
+ * of the same type. The sizes of arrays are not taken into
+ * consideration.
+ *
+ * @param other the other TypeCode
+ * @return true if other
is an array with the same
+ * component type.
+ */
+ public boolean equal(TypeCode other)
+ {
+ try
+ {
+ return kind() == other.kind() &&
+ content_type() == other.content_type();
+ }
+ catch (BadKind ex)
+ {
+ // Should not be thrown.
+ return false;
+ }
+ }
+
+ /**
+ * Returns the agreed Id in the form of
+ * IDL:omg.org/CORBA/ {type name} Seq:1.0
.
+ *
+ * @return the Id of this TypeCode.
+ *
+ * @throws org.omg.CORBA.TypeCodePackage.BadKind if the content type
+ * is not one of the constants, defined in {@link TCKind}.
+ * This package class should not be used as TypeCode for the arrays,
+ * holding the user defined components.
+ */
+ public String id()
+ throws org.omg.CORBA.TypeCodePackage.BadKind
+ {
+ switch (content_type().kind().value())
+ {
+ case TCKind._tk_null :
+ return "IDL:omg.org/CORBA/NullSeq:1.0";
+
+ case TCKind._tk_void :
+ return "IDL:omg.org/CORBA/VoidSeq:1.0";
+
+ case TCKind._tk_short :
+ return "IDL:omg.org/CORBA/ShortSeq:1.0";
+
+ case TCKind._tk_long :
+ return "IDL:omg.org/CORBA/LongSeq:1.0";
+
+ case TCKind._tk_ushort :
+ return "IDL:omg.org/CORBA/UShortSeq:1.0";
+
+ case TCKind._tk_ulong :
+ return "IDL:omg.org/CORBA/ULongSeq:1.0";
+
+ case TCKind._tk_float :
+ return "IDL:omg.org/CORBA/FloatSeq:1.0";
+
+ case TCKind._tk_double :
+ return "IDL:omg.org/CORBA/DoubleSeq:1.0";
+
+ case TCKind._tk_boolean :
+ return "IDL:omg.org/CORBA/BooleanSeq:1.0";
+
+ case TCKind._tk_char :
+ return "IDL:omg.org/CORBA/CharSeq:1.0";
+
+ case TCKind._tk_octet :
+ return "IDL:omg.org/CORBA/OctetSeq:1.0";
+
+ case TCKind._tk_any :
+ return "IDL:omg.org/CORBA/AnySeq:1.0";
+
+ case TCKind._tk_TypeCode :
+ return "IDL:omg.org/CORBA/TypeCodeSeq:1.0";
+
+ case TCKind._tk_Principal :
+ return "IDL:omg.org/CORBA/PrincipalSeq:1.0";
+
+ case TCKind._tk_objref :
+ return "IDL:omg.org/CORBA/ObjrefSeq:1.0";
+
+ case TCKind._tk_struct :
+ return "IDL:omg.org/CORBA/StructSeq:1.0";
+
+ case TCKind._tk_union :
+ return "IDL:omg.org/CORBA/UnionSeq:1.0";
+
+ case TCKind._tk_enum :
+ return "IDL:omg.org/CORBA/EnumSeq:1.0";
+
+ case TCKind._tk_string :
+ return "IDL:omg.org/CORBA/StringSeq:1.0";
+
+ case TCKind._tk_sequence :
+ return "IDL:omg.org/CORBA/SequenceSeq:1.0";
+
+ case TCKind._tk_array :
+ return "IDL:omg.org/CORBA/ArraySeq:1.0";
+
+ case TCKind._tk_alias :
+ return "IDL:omg.org/CORBA/AliasSeq:1.0";
+
+ case TCKind._tk_except :
+ return "IDL:omg.org/CORBA/ExceptSeq:1.0";
+
+ case TCKind._tk_longlong :
+ return "IDL:omg.org/CORBA/LongLongSeq:1.0";
+
+ case TCKind._tk_ulonglong :
+ return "IDL:omg.org/CORBA/ULongLongSeq:1.0";
+
+ case TCKind._tk_longdouble :
+ return "IDL:omg.org/CORBA/LongDoubleSeq:1.0";
+
+ case TCKind._tk_wchar :
+ return "IDL:omg.org/CORBA/WCharSeq:1.0";
+
+ case TCKind._tk_wstring :
+ return "IDL:omg.org/CORBA/WStringSeq:1.0";
+
+ case TCKind._tk_fixed :
+ return "IDL:omg.org/CORBA/FixedSeq:1.0";
+
+ case TCKind._tk_value :
+ return "IDL:omg.org/CORBA/ValueSeq:1.0";
+
+ case TCKind._tk_value_box :
+ return "IDL:omg.org/CORBA/Value_boxSeq:1.0";
+
+ case TCKind._tk_native :
+ return "IDL:omg.org/CORBA/NativeSeq:1.0";
+
+ case TCKind._tk_abstract_interface :
+ return "IDL:omg.org/CORBA/Abstract_interfaceSeq:1.0";
+
+ default :
+ throw new BadKind();
+ }
+ }
+
+ /**
+ * Return the array length.
+ * @return the length of the array.
+ * @throws org.omg.CORBA.TypeCodePackage.BadKind
+ */
+ public int length()
+ throws org.omg.CORBA.TypeCodePackage.BadKind
+ {
+ return length;
+ }
+
+ /**
+ * Sets the array length to the supplied value.
+ *
+ * @param l the new length.
+ */
+ public void setLength(int l)
+ {
+ this.length = l;
+ }
+
+}
diff --git a/libjava/classpath/gnu/CORBA/primitiveTypeCode.java b/libjava/classpath/gnu/CORBA/primitiveTypeCode.java
new file mode 100644
index 0000000..1fa5cd0
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/primitiveTypeCode.java
@@ -0,0 +1,195 @@
+/* primitiveTypeCode.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import java.io.Serializable;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.IDLEntity;
+import org.omg.CORBA.NO_IMPLEMENT;
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+import org.omg.CORBA.TypeCodePackage.Bounds;
+
+/**
+ * An information about a primitive CORBA data type
+ * (boolean, char, wchar, octet and also signed or unsigned short, long,
+ * long long, float and double).
+ * This class only implements the methods {@link #kind() }
+ * and {@link equal() } that are valid for
+ * all TypeCode kinds. Other methods are implemented in derived
+ * subclasses.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class primitiveTypeCode
+ extends TypeCode
+ implements IDLEntity, Serializable
+{
+ /**
+ * The kind of this TypeCode.
+ */
+ protected final TCKind kind;
+
+ public primitiveTypeCode(TCKind a_kind)
+ {
+ kind = a_kind;
+ }
+
+ public TypeCode concrete_base_type()
+ throws BadKind
+ {
+ throw new BadKind();
+ }
+
+ public TypeCode content_type()
+ throws BadKind
+ {
+ throw new BadKind();
+ }
+
+ public int default_index()
+ throws BadKind
+ {
+ throw new BadKind();
+ }
+
+ public TypeCode discriminator_type()
+ throws BadKind
+ {
+ throw new BadKind();
+ }
+
+ /**
+ * Test two types for equality. The default implementation
+ * returs true of the types of the same kind.
+ * @param other the other type to compere with
+ * @return true if the types are interchangeable.
+ */
+ public boolean equal(TypeCode other)
+ {
+ return kind() == other.kind();
+ }
+
+ public boolean equivalent(TypeCode parm1)
+ {
+ throw new NO_IMPLEMENT();
+ }
+
+ public short fixed_digits()
+ throws BadKind
+ {
+ throw new BadKind("fixed_digits");
+ }
+
+ public short fixed_scale()
+ throws BadKind
+ {
+ throw new BadKind("fixed_scale");
+ }
+
+ public TypeCode get_compact_typecode()
+ {
+ throw new NO_IMPLEMENT();
+ }
+
+ public String id()
+ throws BadKind
+ {
+ throw new BadKind("id");
+ }
+
+ /**
+ * Return the kind of this type code object.
+ * @return one of the TCKind.t_..
fields.
+ */
+ public TCKind kind()
+ {
+ return kind;
+ }
+
+ public int length()
+ throws BadKind
+ {
+ throw new BadKind("length");
+ }
+
+ public int member_count()
+ throws BadKind
+ {
+ throw new BadKind("member_count");
+ }
+
+ public Any member_label(int index)
+ throws BadKind, Bounds
+ {
+ throw new BadKind("member_label");
+ }
+
+ public String member_name(int index)
+ throws BadKind, Bounds
+ {
+ throw new BadKind("member_name");
+ }
+
+ public TypeCode member_type(int index)
+ throws BadKind, Bounds
+ {
+ throw new BadKind("member_type");
+ }
+
+ public short member_visibility(int index)
+ throws BadKind, Bounds
+ {
+ throw new BadKind("member_visibility");
+ }
+
+ public String name()
+ throws BadKind
+ {
+ throw new BadKind("name");
+ }
+
+ public short type_modifier()
+ throws BadKind
+ {
+ throw new BadKind("type_modifier");
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/recordTypeCode.java b/libjava/classpath/gnu/CORBA/recordTypeCode.java
new file mode 100644
index 0000000..8f2ecde
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/recordTypeCode.java
@@ -0,0 +1,245 @@
+/* recordTypeCode.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.Any;
+import org.omg.CORBA.StructMember;
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+import org.omg.CORBA.TypeCodePackage.Bounds;
+import org.omg.CORBA.UnionMember;
+import org.omg.CORBA.ValueMember;
+
+/**
+ * The type code that also has the member property getters
+ * supported.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class recordTypeCode
+ extends generalTypeCode
+{
+ /**
+ * The individual field of the record.
+ */
+ public static class Field
+ {
+ /**
+ * The record label.
+ */
+ public Any label;
+
+ /**
+ * The record name.
+ */
+ public String name;
+
+ /**
+ * The record type.
+ */
+ public TypeCode type;
+
+ /**
+ * The record visibility.
+ */
+ public int visibility = UNSET;
+ }
+
+ /**
+ * The members of this data structure.
+ */
+ protected corbaArrayList members = new corbaArrayList();
+ private TypeCode discriminator_type;
+ private int default_index = UNSET;
+
+ /**
+ * Creates the type code of the given kind.
+ */
+ public recordTypeCode(TCKind kind)
+ {
+ super(kind);
+ }
+
+ /**
+ * Set the default index.
+ */
+ public void setDefaultIndex(int a_default_index)
+ {
+ this.default_index = a_default_index;
+ }
+
+ /**
+ * Set the discriminator type.
+ */
+ public void setDiscriminator_type(TypeCode a_discriminator_type)
+ {
+ this.discriminator_type = a_discriminator_type;
+ }
+
+ public Field getField(int p)
+ {
+ return (Field) members.get(p);
+ }
+
+ public void add(Field field)
+ {
+ members.add(field);
+ }
+
+ /**
+ * Adds a new field, taking values from the passed
+ * {@link StructMember}.
+ */
+ public void add(StructMember m)
+ {
+ Field f = field();
+ f.name = m.name;
+ f.type = m.type;
+ }
+
+ /**
+ * Adds a new field, taking values from the passed
+ * {@link ValueMember}.
+ */
+ public void add(ValueMember m)
+ {
+ Field f = field();
+ f.name = m.name;
+ f.type = m.type;
+ f.visibility = m.access;
+
+ }
+
+ /**
+ * Adds a new field, taking values from the passed
+ * {@link UnionMember}.
+ */
+ public void add(UnionMember m)
+ {
+ Field f = field();
+ f.name = m.name;
+ f.type = m.type;
+ f.label = m.label;
+ }
+
+ public int default_index()
+ throws BadKind
+ {
+ if (default_index != UNSET)
+ return default_index;
+ throw new BadKind();
+ }
+
+ public TypeCode discriminator_type()
+ throws BadKind
+ {
+ if (discriminator_type != null)
+ return discriminator_type;
+ throw new BadKind();
+ }
+
+ /**
+ * Creates, adds and returns new field.
+ */
+ public Field field()
+ {
+ Field f = new Field();
+ members.add(f);
+ return f;
+ }
+
+ /** {@inheritDoc} */
+ public int member_count()
+ {
+ return members.size();
+ }
+
+ /** {@inheritDoc} */
+ public Any member_label(int index)
+ throws BadKind, Bounds
+ {
+ Field f = getField(index);
+ if (f.label != null)
+ {
+ return f.label;
+ }
+ else
+ throw new BadKind();
+ }
+
+ /** {@inheritDoc} */
+ public String member_name(int index)
+ throws BadKind
+ {
+ Field f = getField(index);
+ if (f.name != null)
+ {
+ return f.name;
+ }
+ else
+ throw new BadKind();
+ }
+
+ /** {@inheritDoc} */
+ public TypeCode member_type(int index)
+ throws BadKind, Bounds
+ {
+ Field f = getField(index);
+ if (f.type != null)
+ {
+ return f.type;
+ }
+ else
+ throw new BadKind();
+ }
+
+ /** {@inheritDoc} */
+ public short member_visibility(int index)
+ throws BadKind, Bounds
+ {
+ Field f = getField(index);
+ if (f.visibility != UNSET)
+ {
+ return (short) f.visibility;
+ }
+ else
+ throw new BadKind();
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/recursiveTypeCode.java b/libjava/classpath/gnu/CORBA/recursiveTypeCode.java
new file mode 100644
index 0000000..6bc672e
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/recursiveTypeCode.java
@@ -0,0 +1,78 @@
+/* recursiveTypeCode.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.TCKind;
+
+/**
+ * The typecode, serving as a placeholder in defining
+ * typecodes, containing recursion.
+ */
+public class recursiveTypeCode
+ extends primitiveTypeCode
+{
+ /**
+ * The id of the type for that this type serves as a
+ * placeholder.
+ */
+ private final String the_id;
+
+ /**
+ * Create a typecode that serves as a placeholder for
+ * the typecode with the given id.
+ *
+ * @param id the Id of the type for that this type serves as a
+ * placeholder.
+ */
+ public recursiveTypeCode(String an_id)
+ {
+ super(TCKind.tk_null);
+ the_id = an_id;
+ }
+
+ /**
+ * Get the id of the type for that this type serves as a
+ * placeholder.
+ */
+ public String id()
+ throws org.omg.CORBA.TypeCodePackage.BadKind
+ {
+ return the_id;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/streamReadyHolder.java b/libjava/classpath/gnu/CORBA/streamReadyHolder.java
new file mode 100644
index 0000000..a777bd5
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/streamReadyHolder.java
@@ -0,0 +1,120 @@
+/* streamReadyHolder.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.NO_IMPLEMENT;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.Streamable;
+
+import java.io.IOException;
+
+/**
+ * A holder that stores the input stream, from that the holder data
+ * can be read. There is no way to write the data into this holder.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class streamReadyHolder
+ implements Streamable
+{
+ /**
+ * The stream, holding the data for this holder.
+ */
+ protected final InputStream stream;
+
+ /**
+ * Create a holder that will read from the given stream.
+ *
+ * @param a_stream a stream.
+ */
+ public streamReadyHolder(InputStream a_stream)
+ {
+ stream = a_stream;
+ }
+
+ /**
+ * This method is not in use, should never be called.
+ */
+ public TypeCode _type()
+ {
+ throw new NO_IMPLEMENT();
+ }
+
+ /**
+ * Writes the data from the stored stream into the provided
+ * output stream till the end of the input stream is reached.
+ *
+ * @throws MARSHAL if the IOException is thrown during operation.
+ */
+ public void _write(OutputStream output)
+ {
+ try
+ {
+ int d = stream.read();
+
+ while (d >= 0)
+ {
+ output.write(d);
+ d = stream.read();
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new MARSHAL(ex + ":" + ex.getMessage());
+ }
+ }
+
+ /**
+ * This method is not in use, should never be called.
+ */
+ public void _read(InputStream input)
+ {
+ throw new NO_IMPLEMENT();
+ }
+
+ /**
+ * Get the input stream that has been passed in constructor.
+ */
+ InputStream getInputStream()
+ {
+ return stream;
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/CORBA/streamRequest.java b/libjava/classpath/gnu/CORBA/streamRequest.java
new file mode 100644
index 0000000..a0f7eb0
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/streamRequest.java
@@ -0,0 +1,60 @@
+/* gnuStreamRequest.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufOutput;
+
+/**
+ * A stream, additionally holding the gnu request.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class streamRequest
+ extends cdrBufOutput
+{
+ /**
+ * The enclosed request.
+ */
+ public gnuRequest request;
+
+ /**
+ * True if the response is expected.
+ */
+ public boolean response_expected = true;
+}
diff --git a/libjava/classpath/gnu/CORBA/stringTypeCode.java b/libjava/classpath/gnu/CORBA/stringTypeCode.java
new file mode 100644
index 0000000..27aa119
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/stringTypeCode.java
@@ -0,0 +1,83 @@
+/* stringTypeCode.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.TCKind;
+
+/**
+ * The typecode for string and wide string.
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class stringTypeCode
+ extends primitiveTypeCode
+{
+ private int len = 0;
+
+ /**
+ * Create a new instance of the string type code.
+ *
+ * @param a_kind a kind of this typecode, normally
+ * either tk_string or tk_wstring.
+ */
+ public stringTypeCode(TCKind a_kind)
+ {
+ super(a_kind);
+ }
+
+ /**
+ * Set the length property.
+ *
+ * @param a_length a length.
+ */
+ public void setLength(int a_length)
+ {
+ len = a_length;
+ }
+
+ /**
+ * Get the length of the string. This method returns 0
+ * (unbounded) if the property has not been set.
+ *
+ * @return the length (bound) of the string.
+ */
+ public int length()
+ {
+ return len;
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/stubFinder.java b/libjava/classpath/gnu/CORBA/stubFinder.java
new file mode 100644
index 0000000..77efd00
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/stubFinder.java
@@ -0,0 +1,110 @@
+/* stubFinder.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.portable.ObjectImpl;
+
+/**
+ * Finds a stub class like "_HelloStub" that can be instantiated
+ * from IOR reference. The returned object can be casted to the
+ * used type like "Hello" without using the helper .narrow method,
+ * and the object is not unnsecessarily re - instantiated if
+ * the .narrow method is used anyway. If no stub, matching the naming
+ * conventions, is available, the returned stub replacement can still be used
+ * to get the valid request, add parameter and invoke the method by name.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class stubFinder
+{
+ /**
+ * Search for the possibly available default stub.
+ *
+ * @param orb the current ORB. It is not required to find the binding
+ * classes, but is needed to instantiate the default implementation
+ * if no binding classes are found.
+ *
+ * @param ior the IOR, possibly containing the information about the
+ * correct implementation class.
+ */
+ public static ObjectImpl search(ORB orb, IOR ior)
+ {
+ try
+ {
+ int a = ior.Id.indexOf(':');
+ int b = ior.Id.lastIndexOf(':');
+
+ String s = ior.Id.substring(a + 1, b).replace('/', '.');
+
+ String path;
+
+ b = s.lastIndexOf('.');
+ if (b > 0)
+ path = s.substring(0, b + 1);
+ else
+ path = "";
+
+ String stub = "_" + s.substring(b + 1) + "Stub";
+
+ Class stubClass = Class.forName(path + stub);
+
+ return (ObjectImpl) stubClass.newInstance();
+ }
+ catch (Exception failed)
+ {
+ // Various exceptions can be thrown if the Id cannot be parsed,
+ // the class is missing, cannot be instantiated or is not an
+ // instance of the ObjectImpl.
+ return createDefaultStub(orb, ior);
+ }
+ }
+
+ /**
+ * Return the default stub for the case when the client binding classes
+ * are not locally available. The returned stub can still be used
+ * to get the valid request, add parameter and invoke the method by name.
+ *
+ * @return the default implementation.
+ */
+ protected static ObjectImpl createDefaultStub(ORB orb, IOR ior)
+ {
+ return new IOR_contructed_object(orb, ior);
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/typeNamer.java b/libjava/classpath/gnu/CORBA/typeNamer.java
new file mode 100644
index 0000000..8b70101
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/typeNamer.java
@@ -0,0 +1,171 @@
+/* primitiveTypes.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.TypeCodePackage.BadKind;
+
+/**
+ * A conveniency method for naming the built-in types.
+ * This is used in error reporting that is part of the user interface.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class typeNamer
+{
+ /**
+ * Names of the primitve types.
+ */
+ protected static final String[] tk =
+ new String[]
+ {
+ "null", "void", "short", "long", "ushort", "ulong", "float", "double",
+ "boolean", "char", "octet", "any", "TypeCode", "Principal", "objref",
+ "struct", "union", "enum", "string", "sequence", "array", "alias",
+ "exception", "longlong", "ulonglong", "longdouble", "wchar", "wstring",
+ "fixed", "value", "value_box", "native", "abstract_interface"
+ };
+
+ /**
+ * Primitve TypeCodes.
+ */
+ protected static final TypeCode[] primitveCodes =
+ new TypeCode[]
+ {
+ new primitiveTypeCode(TCKind.tk_null),
+ new primitiveTypeCode(TCKind.tk_void),
+ new primitiveTypeCode(TCKind.tk_short),
+ new primitiveTypeCode(TCKind.tk_long),
+ new primitiveTypeCode(TCKind.tk_ushort),
+ new primitiveTypeCode(TCKind.tk_ulong),
+ new primitiveTypeCode(TCKind.tk_float),
+ new primitiveTypeCode(TCKind.tk_double),
+ new primitiveTypeCode(TCKind.tk_boolean),
+ new primitiveTypeCode(TCKind.tk_char),
+ new primitiveTypeCode(TCKind.tk_octet),
+ new primitiveTypeCode(TCKind.tk_any),
+ new primitiveTypeCode(TCKind.tk_TypeCode),
+ new primitiveTypeCode(TCKind.tk_Principal),
+ new primitiveTypeCode(TCKind.tk_objref),
+ new primitiveTypeCode(TCKind.tk_struct),
+ new primitiveTypeCode(TCKind.tk_union),
+ new primitiveTypeCode(TCKind.tk_enum),
+ new primitiveTypeCode(TCKind.tk_string),
+ new primitiveTypeCode(TCKind.tk_sequence),
+ new primitiveTypeCode(TCKind.tk_array),
+ new primitiveTypeCode(TCKind.tk_alias),
+ new primitiveTypeCode(TCKind.tk_except),
+ new primitiveTypeCode(TCKind.tk_longlong),
+ new primitiveTypeCode(TCKind.tk_ulonglong),
+ new primitiveTypeCode(TCKind.tk_longdouble),
+ new primitiveTypeCode(TCKind.tk_wchar),
+ new primitiveTypeCode(TCKind.tk_wstring),
+ new primitiveTypeCode(TCKind.tk_fixed),
+ new primitiveTypeCode(TCKind.tk_value),
+ new primitiveTypeCode(TCKind.tk_value_box),
+ new primitiveTypeCode(TCKind.tk_native),
+ new primitiveTypeCode(TCKind.tk_abstract_interface)
+ };
+
+ /**
+ * Get the primitive type code.
+ *
+ * @return the primitve type code, corresponding the passed value.
+ *
+ * @throws BadKind if this is not a primitive type code.
+ */
+ public static TypeCode getPrimitveTC(TCKind tc)
+ throws BadKind
+ {
+ try
+ {
+ return primitveCodes [ tc.value() ];
+ }
+ catch (ArrayIndexOutOfBoundsException ex)
+ {
+ throw new BadKind(tc.value() + " is not a primitve type.");
+ }
+ }
+
+ /**
+ * Get the string name of the passed primitive type.
+ *
+ * @param kind the kind of the primitive type the must be defined
+ * in {@link omg.org.CORBA.TCKind}.
+ *
+ * @return the short string name, used in error reporting, etc.
+ */
+ public static String nameIt(int kind)
+ {
+ try
+ {
+ return tk [ kind ];
+ }
+ catch (ArrayIndexOutOfBoundsException ex)
+ {
+ return "type of kind '" + kind + "'";
+ }
+ }
+
+ /**
+ * Get the string name of the passed primitive type.
+ *
+ * @param kind the kind of the primitive type the must be defined
+ * in {@link omg.org.CORBA.TCKind}.
+ *
+ * @return the short string name, used in error reporting, etc.
+ */
+ public static String nameIt(TypeCode type)
+ {
+ try
+ {
+ if (type.kind().value() == TCKind._tk_array)
+ return "array of " + nameIt(type.content_type());
+ else if (type.kind().value() == TCKind._tk_sequence)
+ return "sequence of " + nameIt(type.content_type());
+ else
+ return nameIt(type.kind().value());
+ }
+ catch (Exception ex)
+ {
+ return "type of kind '" + type.kind().value() + "'";
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/CORBA/universalHolder.java b/libjava/classpath/gnu/CORBA/universalHolder.java
new file mode 100644
index 0000000..6d8b774
--- /dev/null
+++ b/libjava/classpath/gnu/CORBA/universalHolder.java
@@ -0,0 +1,157 @@
+/* universalStreamable.java --
+ Copyright (C) 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 gnu.CORBA;
+
+import gnu.CORBA.CDR.cdrBufInput;
+import gnu.CORBA.CDR.cdrBufOutput;
+
+import org.omg.CORBA.BAD_OPERATION;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.TypeCode;
+import org.omg.CORBA.portable.InputStream;
+import org.omg.CORBA.portable.OutputStream;
+import org.omg.CORBA.portable.Streamable;
+
+import java.io.IOException;
+
+/**
+ * This class holds the abstract binary data array of the Streamable
+ * being stored. It is used to insert and extract into {@link Any} objects
+ * that have no holder, but have the helper classes.
+ * Encoding/decoding then must be performed by the helper. This class is
+ * defined as package private because it is not idiot proof and
+ * must be used with care.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+class universalHolder
+ implements Streamable
+{
+ /**
+ * The binary data, stored inside this holder.
+ */
+ private cdrBufOutput value = new cdrBufOutput();
+
+ /**
+ * Create the universal holder that uses the given buffer to store the data.
+ */
+ universalHolder(cdrBufOutput buffer)
+ {
+ value = buffer;
+ }
+
+ /**
+ * Reads into the internal buffer till the end of stream is
+ * reached. No alignment operations are performed. This operation
+ * normally reads from the stream, where the single value,
+ * stored using {@link #_write}, is written.
+ *
+ * @throws MARSHALL, if the IOException is thrown during the
+ * stream operation.
+ */
+ public void _read(InputStream input)
+ {
+ try
+ {
+ if (input instanceof cdrBufInput)
+ {
+ cdrBufInput b = (cdrBufInput) input;
+ value.write(b.buffer.getBuffer());
+ }
+ else
+ {
+ int c;
+
+ do
+ {
+ c = input.read();
+ if (c >= 0)
+ value.write(c);
+ }
+ while (c >= 0);
+ }
+ }
+ catch (IOException ex)
+ {
+ MARSHAL t = new MARSHAL();
+ t.initCause(ex);
+ throw t;
+ }
+ }
+
+ /**
+ * The type is not known and cannot be returned.
+ *
+ * @throws BAD_OPERATION, always.
+ */
+ public TypeCode _type()
+ {
+ throw new BAD_OPERATION();
+ }
+
+ /**
+ * Writes the binary data being stored into the given output
+ * stream. This operation supposes that the current stream
+ * position is 0 or satisfies the required alignments anyway.
+ *
+ * @throws MARSHAL if the IOExeption is thrown when writing the
+ * byte array.
+ */
+ public void _write(OutputStream output)
+ {
+ try
+ {
+ value.buffer.writeTo(output);
+ }
+ catch (IOException ex)
+ {
+ MARSHAL t = new MARSHAL();
+ t.initCause(ex);
+ throw t;
+ }
+ }
+
+ /**
+ * Get the input stream that reads the fields of the stored value.
+ */
+ InputStream getInputStream()
+ {
+ return value.create_input_stream();
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/.cvsignore b/libjava/classpath/gnu/classpath/.cvsignore
new file mode 100644
index 0000000..11f6639
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/.cvsignore
@@ -0,0 +1 @@
+Configuration.java
diff --git a/libjava/classpath/gnu/classpath/Configuration.java.in b/libjava/classpath/gnu/classpath/Configuration.java.in
new file mode 100644
index 0000000..9da4a82
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/Configuration.java.in
@@ -0,0 +1,131 @@
+/* Configuration.java --
+ Copyright (C) 1998, 2001, 2003, 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 gnu.classpath;
+
+/**
+ * This file defines compile-time constants that can be accessed by
+ * java code. It is pre-processed by configure.
+ */
+public interface Configuration
+{
+ /**
+ * The value of CLASSPATH_HOME is the location that the classpath
+ * libraries and support files where installed in. It is set according to
+ * the argument for --prefix given to configure and used to set the
+ * System property gnu.classpath.home.
+ */
+ String CLASSPATH_HOME = "@prefix@";
+
+ /**
+ * The release version number of GNU Classpath.
+ * It is set according to the value of 'version' in the configure[.in] file
+ * and used to set the System property gnu.classpath.version.
+ */
+ String CLASSPATH_VERSION = "@VERSION@";
+
+ /**
+ * The value of DEBUG is substituted according to whether the
+ * "--enable-debug" argument was passed to configure. Code
+ * which is made conditional based on the value of this flag - typically
+ * code that generates debugging output - will be removed by the optimizer
+ * in a non-debug build.
+ */
+ boolean DEBUG = @LIBDEBUG@;
+
+ /**
+ * The value of LOAD_LIBRARY is substituted according to whether the
+ * "--enable-load-library" or "--disable-load-library" argument was passed
+ * to configure. By default, configure should define this is as true.
+ * If set to false, loadLibrary() calls to load native function
+ * implementations, typically found in static initializers of classes
+ * which contain native functions, will be omitted. This is useful for
+ * runtimes which pre-link their native function implementations and do
+ * not require additional shared libraries to be loaded.
+ */
+ boolean INIT_LOAD_LIBRARY = @INIT_LOAD_LIBRARY@;
+
+ /**
+ * Set to true if the VM provides a native method to implement
+ * Proxy.getProxyClass completely, including argument verification.
+ * If this is true, HAVE_NATIVE_GET_PROXY_DATA and
+ * HAVE_NATIVE_GENERATE_PROXY_CLASS should be false.
+ * @see java.lang.reflect.Proxy
+ */
+ boolean HAVE_NATIVE_GET_PROXY_CLASS = false;
+
+ /**
+ * Set to true if the VM provides a native method to implement
+ * the first part of Proxy.getProxyClass: generation of the array
+ * of methods to convert, and verification of the arguments.
+ * If this is true, HAVE_NATIVE_GET_PROXY_CLASS should be false.
+ * @see java.lang.reflect.Proxy
+ */
+ boolean HAVE_NATIVE_GET_PROXY_DATA = false;
+
+ /**
+ * Set to true if the VM provides a native method to implement
+ * the second part of Proxy.getProxyClass: conversion of an array of
+ * methods into an actual proxy class.
+ * If this is true, HAVE_NATIVE_GET_PROXY_CLASS should be false.
+ * @see java.lang.reflect.Proxy
+ */
+ boolean HAVE_NATIVE_GENERATE_PROXY_CLASS = false;
+
+ /**
+ * Name of default AWT peer library.
+ */
+ String default_awt_peer_toolkit = "@default_toolkit@";
+
+ /**
+ * Whether to automatically run the init* methods in java.lang.System
+ * (the default) at class initialization time or whether to have the VM
+ * explicitly invoke them.
+ *
+ * The default is false, meaning the VM does not explicitly run the
+ * initializers.
+ *
+ */
+ boolean JAVA_LANG_SYSTEM_EXPLICIT_INITIALIZATION =
+ @JAVA_LANG_SYSTEM_EXPLICIT_INITIALIZATION@;
+
+ /**
+ * Set to true if Cairo was found and enabled during configure,
+ * false otherwise.
+ */
+ boolean GTK_CAIRO_ENABLED = @GTK_CAIRO_ENABLED@;
+}
diff --git a/libjava/classpath/gnu/classpath/RawData.java b/libjava/classpath/gnu/classpath/RawData.java
new file mode 100644
index 0000000..3ce9748
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/RawData.java
@@ -0,0 +1,47 @@
+/* RawData.java -- Pointer to VM specific data
+ Copyright (C) 1999, 2000, 2004 Free Software Foundation
+
+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. */
+
+/* This file is originally part of libgcj. */
+
+package gnu.classpath;
+
+/** A type used to indicate special data used by native code that should not
+ be marked by the garbage collector. */
+
+public abstract class RawData
+{
+}
diff --git a/libjava/classpath/gnu/classpath/RawData32.java b/libjava/classpath/gnu/classpath/RawData32.java
new file mode 100644
index 0000000..c771631
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/RawData32.java
@@ -0,0 +1,52 @@
+/* RawData32.java -- 32 bit Pointer
+ Copyright (C) 2004 Free Software Foundation
+
+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 gnu.classpath;
+
+/**
+ * A type used to indicate special data used by native code that should not
+ * be marked by the garbage collector.
+ */
+public final class RawData32 extends RawData
+{
+ final int data;
+
+ public RawData32(int data)
+ {
+ this.data = data;
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/RawData64.java b/libjava/classpath/gnu/classpath/RawData64.java
new file mode 100644
index 0000000..e3b6a93
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/RawData64.java
@@ -0,0 +1,52 @@
+/* RawData64.java -- 64 bit Pointer
+ Copyright (C) 2004 Free Software Foundation
+
+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 gnu.classpath;
+
+/**
+ * A type used to indicate special data used by native code that should not
+ * be marked by the garbage collector.
+ */
+public final class RawData64 extends RawData
+{
+ final long data;
+
+ public RawData64(long data)
+ {
+ this.data = data;
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/ServiceFactory.java b/libjava/classpath/gnu/classpath/ServiceFactory.java
new file mode 100644
index 0000000..711a904
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/ServiceFactory.java
@@ -0,0 +1,573 @@
+/* ServiceFactory.java -- Factory for plug-in services.
+ Copyright (C) 2004 Free Software Foundation
+
+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 gnu.classpath;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+
+/**
+ * A factory for plug-ins that conform to a service provider
+ * interface. This is a general mechanism that gets used by a number
+ * of packages in the Java API. For instance, {@link
+ * java.nio.charset.spi.CharsetProvider} allows to write custom
+ * encoders and decoders for character sets, {@link
+ * javax.imageio.spi.ImageReaderSpi} allows to support custom image
+ * formats, and {@link javax.print.PrintService} makes it possible to
+ * write custom printer drivers.
+ *
+ * META-INF/services
. This UTF-8 encoded
+ * text file lists, on separate lines, the fully qualified names of
+ * the concrete implementations. Thus, one JAR file can provide an
+ * arbitrary number of implementations for an arbitrary count of
+ * service provider interfaces.
+ *
+ * org.foo.ThinkService
,
+ * namely com.acme.QuickThinker
and
+ * com.acme.DeepThinker
. The code for QuickThinker
+ * woud look as follows:
+ *
+ *
+ * package com.acme;
+ *
+ * /**
+ * * Provices a super-quick, but not very deep implementation of ThinkService.
+ * */
+ * public class QuickThinker
+ * implements org.foo.ThinkService
+ * {
+ * /**
+ * * Constructs a new QuickThinker. The service factory (which is
+ * * part of the Java environment) calls this no-argument constructor
+ * * when it looks up the available implementations of ThinkService.
+ * *
+ * * <p>Note that an application might query all available
+ * * ThinkService providers, but use just one of them. Therefore,
+ * * constructing an instance should be very inexpensive. For example,
+ * * large data structures should only be allocated when the service
+ * * actually gets used.
+ * */
+ * public QuickThinker()
+ * {
+ * }
+ *
+ * /**
+ * * Returns the speed of this ThinkService in thoughts per second.
+ * * Applications can choose among the available service providers
+ * * based on this value.
+ * */
+ * public double getSpeed()
+ * {
+ * return 314159.2654;
+ * }
+ *
+ * /**
+ * * Produces a thought. While the returned thoughts are not very
+ * * deep, they are generated in very short time.
+ * */
+ * public Thought think()
+ * {
+ * return null;
+ * }
+ * }
+ *
+ *
+ * com.acme.DeepThinker
is left as an
+ * exercise to the reader.
+ *
+ * ThinkService
plug-in gets deployed as
+ * a JAR file. Besides the bytecode and resources for
+ * QuickThinker
and DeepThinker
, it also
+ * contains the text file
+ * META-INF/services/org.foo.ThinkService
:
+ *
+ *
+ * # Available implementations of org.foo.ThinkService
+ * com.acme.QuickThinker
+ * com.acme.DeepThinker
+ *
+ *
+ * ServiceFactory
from multiple
+ * concurrent threads without external synchronization.
+ *
+ * gnu.classpath.ServiceFactory
, because this class
+ * is only available in Java environments that are based on GNU
+ * Classpath. Instead, it is recommended that user applications call
+ * {@link
+ * javax.imageio.spi.ServiceRegistry#lookupProviders(Class)}. This API
+ * is actually independent of image I/O, and it is available on every
+ * environment.
+ *
+ * @author Sascha Brawer
+ */
+public final class ServiceFactory
+{
+ /**
+ * A logger that gets informed when a service gets loaded, or
+ * when there is a problem with loading a service.
+ *
+ * classLoader
is
+ * null
. When lookupProviders
is called,
+ * the current {@link AccessControlContext} gets recorded. This
+ * captured security context will determine the permissions when
+ * services get loaded via the next()
method of the
+ * returned Iterator
.
+ *
+ * @param spi the service provider interface which must be
+ * implemented by any loaded service providers.
+ *
+ * @param loader the class loader that will be used to load the
+ * service providers, or null
for the system class
+ * loader. For using the context class loader, see {@link
+ * #lookupProviders(Class)}.
+ *
+ * @return an iterator over instances of spi
.
+ *
+ * @throws IllegalArgumentException if spi
is
+ * null
.
+ */
+ public static Iterator lookupProviders(Class spi,
+ ClassLoader loader)
+ {
+ String resourceName;
+ Enumeration urls;
+
+ if (spi == null)
+ throw new IllegalArgumentException();
+
+ if (loader == null)
+ loader = ClassLoader.getSystemClassLoader();
+
+ resourceName = "META-INF/services/" + spi.getName();
+ try
+ {
+ urls = loader.getResources(resourceName);
+ }
+ catch (IOException ioex)
+ {
+ /* If an I/O error occurs here, we cannot provide any service
+ * providers. In this case, we simply return an iterator that
+ * does not return anything (no providers installed).
+ */
+ log(Level.WARNING, "cannot access {0}", resourceName, ioex);
+ return Collections.EMPTY_LIST.iterator();
+ }
+
+ return new ServiceIterator(spi, urls, loader,
+ AccessController.getContext());
+ }
+
+
+ /**
+ * Finds service providers that are implementing the specified
+ * Service Provider Interface, using the context class loader
+ * for loading providers.
+ *
+ * @param spi the service provider interface which must be
+ * implemented by any loaded service providers.
+ *
+ * @return an iterator over instances of spi
.
+ *
+ * @throws IllegalArgumentException if spi
is
+ * null
.
+ *
+ * @see #lookupProviders(Class, ClassLoader)
+ */
+ public static Iterator lookupProviders(Class spi)
+ {
+ ClassLoader ctxLoader;
+
+ ctxLoader = Thread.currentThread().getContextClassLoader();
+ return lookupProviders(spi, ctxLoader);
+ }
+
+
+ /**
+ * An iterator over service providers that are listed in service
+ * provider configuration files, which get passed as an Enumeration
+ * of URLs. This is a helper class for {@link
+ * ServiceFactory#lookupProviders}.
+ *
+ * @author Sascha Brawer
+ */
+ private static final class ServiceIterator
+ implements Iterator
+ {
+ /**
+ * The service provider interface (usually an interface, sometimes
+ * an abstract class) which the services must implement.
+ */
+ private final Class spi;
+
+
+ /**
+ * An EnumerationMETA-INF/services/<org.foo.SomeService>
,
+ * as returned by {@link ClassLoader#getResources(String)}.
+ */
+ private final Enumeration urls;
+
+
+ /**
+ * The class loader used for loading service providers.
+ */
+ private final ClassLoader loader;
+
+
+ /**
+ * The security context used when loading and initializing service
+ * providers. We want to load and initialize all plug-in service
+ * providers under the same security context, namely the one that
+ * was active when {@link #lookupProviders} has been called.
+ */
+ private final AccessControlContext securityContext;
+
+
+ /**
+ * A reader for the current file listing class names of service
+ * implementors, or null
when the last reader has
+ * been fetched.
+ */
+ private BufferedReader reader;
+
+
+ /**
+ * The URL currently being processed. This is only used for
+ * emitting error messages.
+ */
+ private URL currentURL;
+
+
+ /**
+ * The service provider that will be returned by the next call to
+ * {@link #next()}, or null
if the iterator has
+ * already returned all service providers.
+ */
+ private Object nextProvider;
+
+
+ /**
+ * Constructs an Iterator that loads and initializes services on
+ * demand.
+ *
+ * @param spi the service provider interface which the services
+ * must implement. Usually, this is a Java interface type, but it
+ * might also be an abstract class or even a concrete superclass.
+ *
+ * @param urls an EnumerationMETA-INF/services/<org.foo.SomeService>
, as
+ * determined by {@link ClassLoader#getResources(String)}.
+ *
+ * @param loader the ClassLoader that gets used for loading
+ * service providers.
+ *
+ * @param securityContext the security context to use when loading
+ * and initializing service providers.
+ */
+ ServiceIterator(Class spi, Enumeration urls, ClassLoader loader,
+ AccessControlContext securityContext)
+ {
+ this.spi = spi;
+ this.urls = urls;
+ this.loader = loader;
+ this.securityContext = securityContext;
+ this.nextProvider = loadNextServiceProvider();
+ }
+
+
+ /**
+ * @throws NoSuchElementException if {@link #hasNext} returns
+ * false
.
+ */
+ public Object next()
+ {
+ Object result;
+
+ if (!hasNext())
+ throw new NoSuchElementException();
+
+ result = nextProvider;
+ nextProvider = loadNextServiceProvider();
+ return result;
+ }
+
+
+ public boolean hasNext()
+ {
+ return nextProvider != null;
+ }
+
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+
+ private Object loadNextServiceProvider()
+ {
+ String line;
+
+ if (reader == null)
+ advanceReader();
+
+ for (;;)
+ {
+ /* If we have reached the last provider list, we cannot
+ * retrieve any further lines.
+ */
+ if (reader == null)
+ return null;
+
+ try
+ {
+ line = reader.readLine();
+ }
+ catch (IOException readProblem)
+ {
+ log(Level.WARNING, "IOException upon reading {0}", currentURL,
+ readProblem);
+ line = null;
+ }
+
+ /* When we are at the end of one list of services,
+ * switch over to the next one.
+ */
+ if (line == null)
+ {
+ advanceReader();
+ continue;
+ }
+
+
+ // Skip whitespace at the beginning and end of each line.
+ line = line.trim();
+
+ // Skip empty lines.
+ if (line.length() == 0)
+ continue;
+
+ // Skip comment lines.
+ if (line.charAt(0) == '#')
+ continue;
+
+ try
+ {
+ log(Level.FINE,
+ "Loading service provider \"{0}\", specified"
+ + " by \"META-INF/services/{1}\" in {2}.",
+ new Object[] { line, spi.getName(), currentURL },
+ null);
+
+ /* Load the class in the security context that was
+ * active when calling lookupProviders.
+ */
+ return AccessController.doPrivileged(
+ new ServiceProviderLoadingAction(spi, line, loader),
+ securityContext);
+ }
+ catch (Exception ex)
+ {
+ String msg = "Cannot load service provider class \"{0}\","
+ + " specified by \"META-INF/services/{1}\" in {2}";
+ if (ex instanceof PrivilegedActionException
+ && ex.getCause() instanceof ClassCastException)
+ msg = "Service provider class \"{0}\" is not an instance"
+ + " of \"{1}\". Specified"
+ + " by \"META-INF/services/{1}\" in {2}.";
+
+ log(Level.WARNING, msg,
+ new Object[] { line, spi.getName(), currentURL },
+ ex);
+ continue;
+ }
+ }
+ }
+
+
+ private void advanceReader()
+ {
+ do
+ {
+ if (reader != null)
+ {
+ try
+ {
+ reader.close();
+ log(Level.FINE, "closed {0}", currentURL, null);
+ }
+ catch (Exception ex)
+ {
+ log(Level.WARNING, "cannot close {0}", currentURL, ex);
+ }
+ reader = null;
+ currentURL = null;
+ }
+
+ if (!urls.hasMoreElements())
+ return;
+
+ currentURL = (URL) urls.nextElement();
+ try
+ {
+ reader = new BufferedReader(new InputStreamReader(
+ currentURL.openStream(), "UTF-8"));
+ log(Level.FINE, "opened {0}", currentURL, null);
+ }
+ catch (Exception ex)
+ {
+ log(Level.WARNING, "cannot open {0}", currentURL, ex);
+ }
+ }
+ while (reader == null);
+ }
+ }
+
+
+ // Package-private to avoid a trampoline.
+ /**
+ * Passes a log message to the java.util.logging
+ * framework. This call returns very quickly if no log message will
+ * be produced, so there is not much overhead in the standard case.
+ *
+ * @param the severity of the message, for instance {@link
+ * Level#WARNING}.
+ *
+ * @param msg the log message, for instance “Could not
+ * load {0}.”
+ *
+ * @param param the parameter(s) for the log message, or
+ * null
if msg
does not specify any
+ * parameters. If param
is not an array, an array with
+ * param
as its single element gets passed to the
+ * logging framework.
+ *
+ * @param t a Throwable that is associated with the log record, or
+ * null
if the log message is not associated with a
+ * Throwable.
+ */
+ static void log(Level level, String msg, Object param, Throwable t)
+ {
+ LogRecord rec;
+
+ // Return quickly if no log message will be produced.
+ if (!LOGGER.isLoggable(level))
+ return;
+
+ rec = new LogRecord(level, msg);
+ if (param != null && param.getClass().isArray())
+ rec.setParameters((Object[]) param);
+ else
+ rec.setParameters(new Object[] { param });
+
+ rec.setThrown(t);
+
+ // While java.util.logging can sometimes infer the class and
+ // method of the caller, this automatic inference is not reliable
+ // on highly optimizing VMs. Also, log messages make more sense to
+ // developers when they display a public method in a public class;
+ // otherwise, they might feel tempted to figure out the internals
+ // of ServiceFactory in order to understand the problem.
+ rec.setSourceClassName(ServiceFactory.class.getName());
+ rec.setSourceMethodName("lookupProviders");
+
+ LOGGER.log(rec);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/ServiceProviderLoadingAction.java b/libjava/classpath/gnu/classpath/ServiceProviderLoadingAction.java
new file mode 100644
index 0000000..b5e59cb
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/ServiceProviderLoadingAction.java
@@ -0,0 +1,149 @@
+/* ServiceProviderLoadingAction.java -- Action for loading plug-in services.
+ Copyright (C) 2004 Free Software Foundation
+
+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 gnu.classpath;
+
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * A privileged action for creating a new instance of a service
+ * provider.
+ *
+ * PriviledgedAction
in order to restrict the loaded
+ * service providers to the {@link java.security.AccessControlContext}
+ * that was active when {@link
+ * gnu.classpath.ServiceFactory#lookupProviders} was called, even
+ * though the actual loading is delayed to the time when the provider
+ * is actually needed.
+ *
+ * @author Sascha Brawer
+ */
+final class ServiceProviderLoadingAction
+ implements PrivilegedExceptionAction
+{
+ /**
+ * The interface to which the loaded service provider implementation
+ * must conform. Usually, this is a Java interface type, but it
+ * might also be an abstract class or even a concrete class.
+ */
+ private final Class spi;
+
+
+ /**
+ * The fully qualified name of the class that gets loaded when
+ * this action is executed.
+ */
+ private final String providerName;
+
+
+ /**
+ * The ClassLoader that gets used for loading the service provider
+ * class.
+ */
+ private final ClassLoader loader;
+
+
+ /**
+ * Constructs a privileged action for loading a service provider.
+ *
+ * @param spi the interface to which the loaded service provider
+ * implementation must conform. Usually, this is a Java interface
+ * type, but it might also be an abstract class or even a concrete
+ * superclass.
+ *
+ * @param providerName the fully qualified name of the class that
+ * gets loaded when this action is executed.
+ *
+ * @param loader the ClassLoader that gets used for loading the
+ * service provider class.
+ *
+ * @throws IllegalArgumentException if spi
,
+ * providerName
or loader
is
+ * null
.
+ */
+ ServiceProviderLoadingAction(Class spi, String providerName,
+ ClassLoader loader)
+ {
+ if (spi == null || providerName == null || loader == null)
+ throw new IllegalArgumentException();
+
+ this.spi = spi;
+ this.providerName = providerName;
+ this.loader = loader;
+ }
+
+
+ /**
+ * Loads an implementation class for a service provider, and creates
+ * a new instance of the loaded class by invoking its public
+ * no-argument constructor.
+ *
+ * @return a new instance of the class whose name was passed as
+ * providerName
to the constructor.
+ *
+ * @throws ClassCastException if the service provider does not
+ * implement the spi
interface that was passed to the
+ * constructor.
+ *
+ * @throws IllegalAccessException if the service provider class or
+ * its no-argument constructor are not public
.
+ *
+ * @throws InstantiationException if the service provider class is
+ * abstract
, an interface, a primitive type, an array
+ * class, or void; or if service provider class does not have a
+ * no-argument constructor; or if there some other problem with
+ * creating a new instance of the service provider.
+ */
+ public Object run()
+ throws Exception
+ {
+ Class loadedClass;
+ Object serviceProvider;
+
+ loadedClass = loader.loadClass(providerName);
+ serviceProvider = loadedClass.newInstance();
+
+ // Ensure that the loaded provider is actually implementing
+ // the service provider interface.
+ if (!spi.isInstance(serviceProvider))
+ throw new ClassCastException(spi.getName());
+
+ return serviceProvider;
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/SystemProperties.java b/libjava/classpath/gnu/classpath/SystemProperties.java
new file mode 100644
index 0000000..600e1a6
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/SystemProperties.java
@@ -0,0 +1,158 @@
+/* SystemProperties.java -- Manage the System properties.
+ Copyright (C) 2004, 2005 Free Software Foundation
+
+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 gnu.classpath;
+
+import java.util.Properties;
+
+/**
+ * The class manages the System properties. This class is only available to
+ * privileged code (i.e. code loaded by the bootstrap class loader) and
+ * therefore doesn't do any security checks.
+ * This class is separated out from java.lang.System to simplify bootstrap
+ * dependencies and to allow trusted code a simple and efficient mechanism
+ * to access the system properties.
+ */
+public class SystemProperties
+{
+ /**
+ * Stores the current system properties. This can be modified by
+ * {@link #setProperties(Properties)}, but will never be null, because
+ * setProperties(null) sucks in the default properties.
+ */
+ private static Properties properties;
+
+ /**
+ * The default properties. Once the default is stabilized,
+ * it should not be modified;
+ * instead it is cloned when calling setProperties(null)
.
+ */
+ private static final Properties defaultProperties = new Properties();
+
+ static
+ {
+ VMSystemProperties.preInit(defaultProperties);
+
+ defaultProperties.put("gnu.classpath.home", Configuration.CLASSPATH_HOME);
+ defaultProperties.put("gnu.classpath.version",
+ Configuration.CLASSPATH_VERSION);
+
+ // Set base URL if not already set.
+ if (defaultProperties.get("gnu.classpath.home.url") == null)
+ defaultProperties.put("gnu.classpath.home.url",
+ "file://"
+ + Configuration.CLASSPATH_HOME
+ + "/lib");
+
+ // Set short name if not already set.
+ if (defaultProperties.get("gnu.classpath.vm.shortname") == null)
+ {
+ String value = defaultProperties.getProperty("java.vm.name");
+ int index = value.lastIndexOf(' ');
+ if (index != -1)
+ value = value.substring(index + 1);
+ defaultProperties.put("gnu.classpath.vm.shortname", value);
+ }
+
+ // Network properties
+ if (defaultProperties.get("http.agent") == null)
+ {
+ String userAgent = ("gnu-classpath/"
+ + defaultProperties.getProperty("gnu.classpath.version")
+ + " ("
+ + defaultProperties.getProperty("gnu.classpath.vm.shortname")
+ + "/"
+ + defaultProperties.getProperty("java.vm.version")
+ + ")");
+ defaultProperties.put("http.agent", userAgent);
+ }
+
+ // 8859_1 is a safe default encoding to use when not explicitly set
+ if (defaultProperties.get("file.encoding") == null)
+ defaultProperties.put("file.encoding", "8859_1");
+
+ // Default to the Swing FocusManager so that the old-style Swing API
+ // for FocusManager can be supported without hardcoding it in AWT.
+ if (defaultProperties.get("gnu.java.awt.FocusManager") == null)
+ defaultProperties.put("gnu.java.awt.FocusManager",
+ "gnu.java.awt.FocusManager");
+
+ // XXX FIXME - Temp hack for old systems that set the wrong property
+ if (defaultProperties.get("java.io.tmpdir") == null)
+ defaultProperties.put("java.io.tmpdir",
+ defaultProperties.get("java.tmpdir"));
+
+ VMSystemProperties.postInit(defaultProperties);
+
+ // Note that we use clone here and not new. Some programs assume
+ // that the system properties do not have a parent.
+ properties = (Properties) defaultProperties.clone();
+ }
+
+ public static String getProperty(String name)
+ {
+ return properties.getProperty(name);
+ }
+
+ public static String getProperty(String name, String defaultValue)
+ {
+ return properties.getProperty(name, defaultValue);
+ }
+
+ public static String setProperty(String name, String value)
+ {
+ return (String) properties.setProperty(name, value);
+ }
+
+ public static Properties getProperties()
+ {
+ return properties;
+ }
+
+ public static void setProperties(Properties properties)
+ {
+ if (properties == null)
+ {
+ // Note that we use clone here and not new. Some programs
+ // assume that the system properties do not have a parent.
+ properties = (Properties)defaultProperties.clone();
+ }
+
+ SystemProperties.properties = properties;
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/debug/Component.java b/libjava/classpath/gnu/classpath/debug/Component.java
new file mode 100644
index 0000000..3dfc892
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/debug/Component.java
@@ -0,0 +1,159 @@
+/* Component.java -- a component log level.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is a 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 of the License, 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; 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 gnu.classpath.debug;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.logging.Level;
+
+public final class Component extends Level
+{
+
+ /*
+ * HOW TO ADD NEW COMPONENTS:
+ *
+ * If you want to add a new, simple component, that you will use in
+ * logging statements, simply create a new class variable that
+ * instantiates this class, and choose an appropriate string name
+ * and a integer constant not used by any other component level.
+ *
+ * For example, if my component had to do with 'frobbing', I would
+ * add this entry below:
+ *
+ * private static final Component FROBBING = new Component ("FROBBING", 7);
+ *
+ * Then, I would update the component 'EVERYTHING' to have and end
+ * index ONE GREATER THAN the index of the new component.
+ *
+ * ADDING NEW COMPONENT CLASSES:
+ *
+ * A "component class" is a run of more than one component, which can
+ * be enabled all at once. EVERYTHING and SSL are examples of component
+ * classes. To add a new class, create a new component with a start index
+ * equal to the index of the first member component, and with an end
+ * index equal to the index of the last member component plus one.
+ */
+
+ /**
+ * Signifies that everything should be logged. This should be used to
+ * enable or disable levels only; logging code should not use it.
+ */
+ public static final Component EVERYTHING = new Component ("*", 0, 7);
+
+ /**
+ * Signifies that all SSL related messages should be logged. This should
+ * be used to enable or disable levels only; logging code should not use
+ * it.
+ */
+ public static final Component SSL = new Component ("SSL", 0, 5);
+
+ /**
+ * Traces the progression of an SSL handshake.
+ */
+ public static final Component SSL_HANDSHAKE = new Component ("SSL HANDSHAKE", 0);
+
+ /**
+ * Traces the application messages during SSL communications.
+ */
+ public static final Component SSL_APPLICATION = new Component ("SSL APPLICATION", 1);
+
+ /**
+ * Trace details about the SSL key exchange.
+ */
+ public static final Component SSL_KEY_EXCHANGE = new Component ("SSL KEY EXCHANGE", 2);
+
+ /* Indices 3 and 4 reserved for future use by SSL components. */
+
+ /**
+ * Trace the operation of cryptographic primitives.
+ */
+ public static final Component CRYPTO = new Component ("CRYPTO", 5);
+
+ /**
+ * Trace the parsing of X.509 certificates and related objects.
+ */
+ public static final Component X509 = new Component ("X.509", 6);
+
+ private final int startIndex;
+ private final int endIndex;
+
+ private Component (final String name, final int bitIndex)
+ {
+ this (name, bitIndex, bitIndex + 1);
+ }
+
+ private Component (final String name, final int startIndex, final int endIndex)
+ {
+ super (name, Level.FINE.intValue ());
+ this.startIndex = startIndex;
+ this.endIndex = endIndex;
+ }
+
+ /**
+ * Return the component for the given name.
+ *
+ * @param name The name of the component to get.
+ * @return The named component, or null if there is no such component.
+ */
+ public static Component forName (final String name)
+ {
+ try
+ {
+ Field f = Component.class.getField (name.toUpperCase ());
+ if (!Modifier.isStatic (f.getModifiers ())
+ || Component.class.isAssignableFrom (f.getClass ()))
+ return null;
+ return (Component) f.get (null);
+ }
+ catch (Throwable _)
+ {
+ return null;
+ }
+ }
+
+ public int startIndex ()
+ {
+ return startIndex;
+ }
+
+ public int endIndex ()
+ {
+ return endIndex;
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/classpath/debug/PreciseFilter.java b/libjava/classpath/gnu/classpath/debug/PreciseFilter.java
new file mode 100644
index 0000000..7b88b2c
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/debug/PreciseFilter.java
@@ -0,0 +1,105 @@
+/* PreciseFilter.java -- filter log messages by precise level.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is a 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 of the License, 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; 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 gnu.classpath.debug;
+
+import java.util.BitSet;
+import java.util.logging.Filter;
+import java.util.logging.LogRecord;
+
+public final class PreciseFilter implements Filter
+{
+
+ /**
+ * The singleton filter instance.
+ */
+ public static final PreciseFilter GLOBAL = new PreciseFilter ();
+
+ private final BitSet enabled;
+
+ private PreciseFilter ()
+ {
+ enabled = new BitSet ();
+ }
+
+ /**
+ * Disable logging of a component.
+ *
+ * @param component The component to disable logging for.
+ * @throws NullPointerException If component is null.
+ */
+ public void disable (final Component component)
+ {
+ enabled.clear (component.startIndex (), component.endIndex ());
+ }
+
+ /**
+ * Enable logging of a component.
+ *
+ * @param component The component to enable logging for.
+ * @throws NullPointerException If component is null.
+ */
+ public void enable (final Component component)
+ {
+ enabled.set (component.startIndex (), component.endIndex ());
+ }
+
+ /**
+ * Tell if a component is enabled for logging.
+ *
+ * @param component The component to test.
+ * @return True iff the specified component is enabled for logging.
+ * @throws NullPointerException If component is null.
+ */
+ public boolean isEnabled (final Component component)
+ {
+ return (enabled.get (component.startIndex ()));
+ }
+
+ public boolean isLoggable (final LogRecord record)
+ {
+ try
+ {
+ return isEnabled ((Component) record.getLevel ());
+ }
+ catch (ClassCastException cce)
+ {
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/libjava/classpath/gnu/classpath/debug/SystemLogger.java b/libjava/classpath/gnu/classpath/debug/SystemLogger.java
new file mode 100644
index 0000000..94aa93f
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/debug/SystemLogger.java
@@ -0,0 +1,71 @@
+/* SystemLogger.java -- Classpath's system debugging logger.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is a 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 of the License, 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; 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 gnu.classpath.debug;
+
+import gnu.classpath.SystemProperties;
+import java.util.StringTokenizer;
+import java.util.logging.Logger;
+
+public final class SystemLogger
+{
+ public static final Logger SYSTEM = Logger.getLogger ("gnu.classpath");
+
+ static
+ {
+ SYSTEM.setFilter (PreciseFilter.GLOBAL);
+
+ String defaults = SystemProperties.getProperty ("gnu.classpath.debug.components");
+
+ if (defaults != null)
+ {
+ StringTokenizer tok = new StringTokenizer (defaults, ",");
+ while (tok.hasMoreTokens ())
+ {
+ Component c = Component.forName (tok.nextToken ());
+ if (c != null)
+ PreciseFilter.GLOBAL.enable (c);
+ SYSTEM.log (java.util.logging.Level.INFO, "enabled: {0}", c);
+ }
+ }
+
+ java.util.logging.Handler[] h = SYSTEM.getHandlers ();
+ for (int i = 0; i < h.length; i++)
+ System.out.println (h[i]);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassException.java
new file mode 100644
index 0000000..cd276be
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassException.java
@@ -0,0 +1,63 @@
+/* InvalidClassException.java -- invalid/unknown class reference id exception
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown by the JDWP back-end when an invalid reference
+ * type id is used by the debugger.
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class InvalidClassException
+ extends JdwpException
+{
+ public InvalidClassException (long id)
+ {
+ super (JdwpConstants.Error.INVALID_CLASS,
+ "invalid class id (" + id + ")");
+ }
+
+ public InvalidClassException (Throwable t)
+ {
+ super (JdwpConstants.Error.INVALID_CLASS, t);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidCountException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidCountException.java
new file mode 100644
index 0000000..d5f40c9
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidCountException.java
@@ -0,0 +1,61 @@
+/* InvalidCountException -- an invalid count exception
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown when a count filter is given an invalid count.
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class InvalidCountException
+ extends JdwpException
+{
+ public InvalidCountException (int id)
+ {
+ super (JdwpConstants.Error.INVALID_COUNT, "invalid count (" + id + ")");
+ }
+
+ public InvalidCountException (Throwable t)
+ {
+ super (JdwpConstants.Error.INVALID_COUNT, t);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidEventTypeException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidEventTypeException.java
new file mode 100644
index 0000000..e040228
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidEventTypeException.java
@@ -0,0 +1,63 @@
+/* InvalidEventTypeException.java -- an invalid event kind exception
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown when the debugger asks for an event request
+ * for a non-existant event
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class InvalidEventTypeException
+ extends JdwpException
+{
+ public InvalidEventTypeException (byte kind)
+ {
+ super (JdwpConstants.Error.INVALID_EVENT_TYPE,
+ "invalid event type (" + kind + ")");
+ }
+
+ public InvalidEventTypeException (Throwable t)
+ {
+ super (JdwpConstants.Error.INVALID_EVENT_TYPE, t);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidObjectException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidObjectException.java
new file mode 100644
index 0000000..49e8ac1
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidObjectException.java
@@ -0,0 +1,63 @@
+/* InvalidObjectException.java -- an invalid object id exception
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown when an invalid object id is used by
+ * the debugger
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class InvalidObjectException
+ extends JdwpException
+{
+ public InvalidObjectException (long id)
+ {
+ super (JdwpConstants.Error.INVALID_OBJECT,
+ "invalid object id (" + id + ")");
+ }
+
+ public InvalidObjectException (Throwable t)
+ {
+ super (JdwpConstants.Error.INVALID_OBJECT, t);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidStringException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidStringException.java
new file mode 100644
index 0000000..c84a960
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidStringException.java
@@ -0,0 +1,68 @@
+/* InvalidStringException.java -- an invalid string exception
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown when the debugger uses an invalid String.
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class InvalidStringException
+ extends JdwpException
+{
+ public InvalidStringException (String str)
+ {
+ super (JdwpConstants.Error.INVALID_STRING,
+ "invalid string (" + str + ")");
+ }
+
+ public InvalidStringException (long id)
+ {
+ super (JdwpConstants.Error.INVALID_STRING,
+ "invalid string id (" + id + ")");
+ }
+
+ public InvalidStringException (Throwable t)
+ {
+ super (JdwpConstants.Error.INVALID_STRING, t);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadException.java
new file mode 100644
index 0000000..985b1a7
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadException.java
@@ -0,0 +1,63 @@
+/* InvalidThreadException.java -- an invalid thread exception
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown when an invalid thread is used
+ * by the debugger
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class InvalidThreadException
+ extends JdwpException
+{
+ public InvalidThreadException (long id)
+ {
+ super (JdwpConstants.Error.INVALID_THREAD,
+ "invalid thread id (" + id + ")");
+ }
+
+ public InvalidThreadException (Throwable t)
+ {
+ super (JdwpConstants.Error.INVALID_THREAD, t);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadGroupException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadGroupException.java
new file mode 100644
index 0000000..0476218
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadGroupException.java
@@ -0,0 +1,63 @@
+/* InvalidThreadGroupException.java -- an invalid thread group exception
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown when an invalid thread group is used
+ * by the debugger
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class InvalidThreadGroupException
+ extends JdwpException
+{
+ public InvalidThreadGroupException (long id)
+ {
+ super (JdwpConstants.Error.INVALID_THREAD_GROUP,
+ "invalid thread id (" + id + ")");
+ }
+
+ public InvalidThreadGroupException (Throwable t)
+ {
+ super (JdwpConstants.Error.INVALID_THREAD, t);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/JdwpException.java b/libjava/classpath/gnu/classpath/jdwp/exception/JdwpException.java
new file mode 100644
index 0000000..5c96cc5
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/JdwpException.java
@@ -0,0 +1,86 @@
+/* JdwpException.java -- an exception base class for all JDWP exceptions
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.exception;
+
+/**
+ * A base class exception for all JDWP back-end exceptions
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class JdwpException
+ extends Exception
+{
+ // The integer error code defined by JDWP
+ private short _errorCode;
+
+ /**
+ * Constructs a new JdwpException
with the
+ * given error code and given cause
+ *
+ * @param code the JDWP error code
+ * @param t the cause of the exception
+ */
+ public JdwpException (short code, Throwable t)
+ {
+ super (t);
+ _errorCode = code;
+ }
+
+ /**
+ * Constructs a new JdwpException
with the
+ * given error code and string error message
+ *
+ * @param code the JDWP error code
+ * @param str an error message
+ */
+ public JdwpException (short code, String str)
+ {
+ super (str);
+ _errorCode = code;
+ }
+
+ /**
+ * Returns the JDWP error code represented by this exception
+ */
+ public short getErrorCode ()
+ {
+ return _errorCode;
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/JdwpInternalErrorException.java b/libjava/classpath/gnu/classpath/jdwp/exception/JdwpInternalErrorException.java
new file mode 100644
index 0000000..c022dc5
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/JdwpInternalErrorException.java
@@ -0,0 +1,57 @@
+/* JdwpInternalErrorException.java -- an internal error exception
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown by the JDWP back-end when an unusual runtime
+ * error occurs internally
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class JdwpInternalErrorException
+ extends JdwpException
+{
+ public JdwpInternalErrorException (Throwable cause)
+ {
+ super (JdwpConstants.Error.INTERNAL, cause);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/NotImplementedException.java b/libjava/classpath/gnu/classpath/jdwp/exception/NotImplementedException.java
new file mode 100644
index 0000000..fba627e
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/NotImplementedException.java
@@ -0,0 +1,58 @@
+/* NotImplementedException.java -- an exception for unimplemented JDWP
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown by virtual machines when functionality
+ * or features are not implemented
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class NotImplementedException
+ extends JdwpException
+{
+ public NotImplementedException (String feature)
+ {
+ super (JdwpConstants.Error.NOT_IMPLEMENTED,
+ feature + " is not yet implemented");
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/VmDeadException.java b/libjava/classpath/gnu/classpath/jdwp/exception/VmDeadException.java
new file mode 100644
index 0000000..f3c4a15
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/exception/VmDeadException.java
@@ -0,0 +1,55 @@
+/* VmDeadException.java -- dead virtual machine exception
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.exception;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * An exception thrown when the virtual machine is dead
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class VmDeadException
+ extends JdwpException
+{
+ public VmDeadException ()
+ {
+ super (JdwpConstants.Error.VM_DEAD, "Virtual machine is dead");
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ArrayId.java b/libjava/classpath/gnu/classpath/jdwp/id/ArrayId.java
new file mode 100644
index 0000000..cd428a1
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/ArrayId.java
@@ -0,0 +1,62 @@
+/* ArrayId.java -- array object IDs
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * A class which represents a JDWP array id
+ *
+ * @author Keith Seitz ArrayId
+ */
+ public ArrayId ()
+ {
+ super (JdwpConstants.Tag.ARRAY);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ArrayReferenceTypeId.java b/libjava/classpath/gnu/classpath/jdwp/id/ArrayReferenceTypeId.java
new file mode 100644
index 0000000..14a73dc
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/ArrayReferenceTypeId.java
@@ -0,0 +1,59 @@
+/* ArrayReferenceTypeId.java -- array reference type ids
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * A reference type ID representing java arrays
+ *
+ * @author Keith Seitz ArrayReferenceTypeId
+ */
+ public ArrayReferenceTypeId ()
+ {
+ super (JdwpConstants.TypeTag.ARRAY);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ClassLoaderId.java b/libjava/classpath/gnu/classpath/jdwp/id/ClassLoaderId.java
new file mode 100644
index 0000000..1338725
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/ClassLoaderId.java
@@ -0,0 +1,64 @@
+/* ClassLoaderId.java -- class loader IDs
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * A class which represents a JDWP thread id
+ *
+ * @author Keith Seitz ClassLoaderId
+ */
+ public ClassLoaderId ()
+ {
+ super (JdwpConstants.Tag.CLASS_LOADER);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ClassObjectId.java b/libjava/classpath/gnu/classpath/jdwp/id/ClassObjectId.java
new file mode 100644
index 0000000..e5559ce
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/ClassObjectId.java
@@ -0,0 +1,64 @@
+/* ClassObjectId.java -- class object IDs
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * A class which represents a JDWP class object id
+ *
+ * @author Keith Seitz ClassObjectId
+ */
+ public ClassObjectId ()
+ {
+ super (JdwpConstants.Tag.CLASS_OBJECT);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ClassReferenceTypeId.java b/libjava/classpath/gnu/classpath/jdwp/id/ClassReferenceTypeId.java
new file mode 100644
index 0000000..6b57673
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/ClassReferenceTypeId.java
@@ -0,0 +1,59 @@
+/* ClassReferenceTypeId.java -- class reference type ids
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * A reference type ID representing java classes
+ *
+ * @author Keith Seitz ClassReferenceTypeId
+ */
+ public ClassReferenceTypeId ()
+ {
+ super (JdwpConstants.TypeTag.CLASS);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/InterfaceReferenceTypeId.java b/libjava/classpath/gnu/classpath/jdwp/id/InterfaceReferenceTypeId.java
new file mode 100644
index 0000000..bdbd6b6
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/InterfaceReferenceTypeId.java
@@ -0,0 +1,59 @@
+/* InterfaceReferenceTypeId.java -- interface reference type ids
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * A reference type ID representing java interfaces
+ *
+ * @author Keith Seitz InterfaceReferenceTypeId
+ */
+ public InterfaceReferenceTypeId ()
+ {
+ super (JdwpConstants.TypeTag.INTERFACE);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/JdwpId.java b/libjava/classpath/gnu/classpath/jdwp/id/JdwpId.java
new file mode 100644
index 0000000..37f82e2
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/JdwpId.java
@@ -0,0 +1,127 @@
+/* JdwpId.java -- base class for all object ID types
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * A baseclass for all object types reported to the debugger
+ *
+ * @author Keith Seitz JdwpId
+ */
+ public JdwpId (byte tag)
+ {
+ _tag = tag;
+ }
+
+ /**
+ * Sets the id for this object reference
+ */
+ void setId (long id)
+ {
+ _id = id;
+ }
+
+ /**
+ * Returns the id for this object reference
+ */
+ public long getId ()
+ {
+ return _id;
+ }
+
+ /**
+ * Compares two object ids for equality. Two object ids
+ * are equal if they point to the same type and contain to
+ * the same id number. (NOTE: This is a much stricter check
+ * than is necessary: all JdwpId
s have unique
+ * ids.)
+ */
+ public boolean equals (JdwpId id)
+ {
+ return ((id.getClass () == getClass ()) && (id.getId () == getId ()));
+ }
+
+ /**
+ * Returns size of this type (used by IDSizes)
+ */
+ public abstract int size ();
+
+ /**
+ * Writes the contents of this type to the DataOutputStream
+ * @param outStream the DataOutputStream
to use
+ * @throws IOException when an error occurs on the OutputStream
+ */
+ public abstract void write (DataOutputStream outStream)
+ throws IOException;
+
+ /**
+ * Writes the contents of this type to the output stream, preceded
+ * by a one-byte tag for tagged object IDs or type tag for
+ * reference type IDs.
+ *
+ * @param outStream the DataOutputStream
to use
+ * @throws IOException when an error occurs on the OutputStream
+ */
+ public void writeTagged (DataOutputStream outStream)
+ throws IOException
+ {
+ outStream.writeByte (_tag);
+ write (outStream);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/JdwpIdFactory.java b/libjava/classpath/gnu/classpath/jdwp/id/JdwpIdFactory.java
new file mode 100644
index 0000000..06ec3c7
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/JdwpIdFactory.java
@@ -0,0 +1,165 @@
+/* JdwpIdFactory.java -- factory for generating type and object IDs
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import java.util.HashMap;
+
+/**
+ * This factory generates ids for objects and types that may
+ * be sent to a debugger.
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class JdwpIdFactory
+{
+ // ID of last object / referencetype
+ private static Object _idLock = new Object ();
+ private static Object _ridLock = new Object ();
+ private static long _lastId = 0;
+ private static long _lastRid = 0;
+
+ // A list of all ID types
+ private static HashMap _idList = new HashMap ();
+
+ // Initialize the id list with known types
+ static
+ {
+ // ObjectId and ArrayId are special cases. See newId.
+ _idList.put (ClassLoaderId.typeClass, ClassLoaderId.class);
+ _idList.put (ClassObjectId.typeClass, ClassObjectId.class);
+ //_idList.put (FieldId.typeClass, FieldId.class);
+ //_idList.put (FrameId.typeClass, FrameId.class);
+ //_idList.put (MethodId.typeClass, MethodId.class);
+ _idList.put (StringId.typeClass, StringId.class);
+ _idList.put (ThreadId.typeClass, ThreadId.class);
+ _idList.put (ThreadGroupId.typeClass, ThreadGroupId.class);
+ }
+
+ /**
+ * Returns a new id for the given object
+ *
+ * @param object the object for which an id is desired
+ * @returns a suitable object id
+ */
+ public static JdwpId newId (Object object)
+ {
+ JdwpId id = null;
+
+ // Special case: arrays
+ if (object.getClass ().isArray ())
+ id = new ArrayId ();
+ else
+ {
+ // Loop through all classes until we hit baseclass
+ Class myClass;
+ for (myClass = object.getClass (); myClass != null;
+ myClass = myClass.getSuperclass ())
+ {
+ Class clz = (Class) _idList.get (myClass);
+ if (clz != null)
+ {
+ try
+ {
+ id = (JdwpId) clz.newInstance ();
+ synchronized (_idLock)
+ {
+ id.setId (++_lastId);
+ }
+ return id;
+ }
+ catch (InstantiationException ie)
+ {
+ // This really should not happen
+ throw new RuntimeException ("cannot create new ID", ie);
+ }
+ catch (IllegalAccessException iae)
+ {
+ // This really should not happen
+ throw new RuntimeException ("illegal access of ID", iae);
+ }
+ }
+ }
+
+ /* getSuperclass returned null and no matching ID type found.
+ So it must derive from Object. */
+ id = new ObjectId ();
+ }
+
+ synchronized (_idLock)
+ {
+ id.setId (++_lastId);
+ }
+
+ return id;
+ }
+
+ /**
+ * Returns a new reference type id for the given class
+ *
+ * @param clazz the Class
for which an id is desired
+ * @returns a suitable reference type id or null
+ */
+ public static ReferenceTypeId newReferenceTypeId (Class clazz)
+ {
+ ReferenceTypeId id = null;
+ try
+ {
+ if (clazz.isArray ())
+ id = new ArrayReferenceTypeId ();
+ else if (clazz.isInterface ())
+ id = new InterfaceReferenceTypeId ();
+ else
+ id = new ClassReferenceTypeId ();
+ synchronized (_ridLock)
+ {
+ id.setId (++_lastRid);
+ }
+ return id;
+ }
+ catch (InstantiationException ie)
+ {
+ return null;
+ }
+ catch (IllegalAccessException iae)
+ {
+ return null;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ObjectId.java b/libjava/classpath/gnu/classpath/jdwp/id/ObjectId.java
new file mode 100644
index 0000000..e34a3b5
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/ObjectId.java
@@ -0,0 +1,99 @@
+/* ObjectId.java -- object IDs
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * A class which represents a JDWP object id for an object
+ *
+ * @author Keith Seitz ObjectId
+ */
+ public ObjectId ()
+ {
+ super (JdwpConstants.Tag.OBJECT);
+ }
+
+ /**
+ * Constructs a new ObjectId
of the
+ * given type.
+ *
+ * @param tag the tag of this type of object ID
+ */
+ public ObjectId (byte tag)
+ {
+ super (tag);
+ }
+
+ /**
+ * Returns the size of this id type
+ */
+ public int size ()
+ {
+ return 8;
+ }
+
+ /**
+ * Writes the id to the stream
+ *
+ * @param outStream the stream to which to write
+ * @throws IOException when an error occurs on the OutputStream
+ */
+ public void write (DataOutputStream outStream)
+ throws IOException
+ {
+ // All we need to do is write out our id as an 8-byte integer
+ outStream.writeLong (_id);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ReferenceTypeId.java b/libjava/classpath/gnu/classpath/jdwp/id/ReferenceTypeId.java
new file mode 100644
index 0000000..cdb7804
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/ReferenceTypeId.java
@@ -0,0 +1,81 @@
+/* ReferenceTypeId.java -- a base class for all reference type IDs
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Base class for reference type IDs. This class usurps
+ * JdwpId
's tag member for its own use (type tag).
+ *
+ * @author Keith Seitz StringId
+ */
+ public StringId ()
+ {
+ super (JdwpConstants.Tag.STRING);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ThreadGroupId.java b/libjava/classpath/gnu/classpath/jdwp/id/ThreadGroupId.java
new file mode 100644
index 0000000..aef7d5b
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/ThreadGroupId.java
@@ -0,0 +1,64 @@
+/* ThreadGroupId.java -- thread group IDs
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * A class which represents a JDWP thread group id
+ *
+ * @author Keith Seitz ThreadGroupId
+ */
+ public ThreadGroupId ()
+ {
+ super (JdwpConstants.Tag.THREAD_GROUP);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ThreadId.java b/libjava/classpath/gnu/classpath/jdwp/id/ThreadId.java
new file mode 100644
index 0000000..733bf55
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/id/ThreadId.java
@@ -0,0 +1,64 @@
+/* ThreadId.java -- thread IDs
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.id;
+
+import gnu.classpath.jdwp.JdwpConstants;
+
+/**
+ * A class which represents a JDWP thread id
+ *
+ * @author Keith Seitz ThreadId
+ */
+ public ThreadId ()
+ {
+ super (JdwpConstants.Tag.THREAD);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/CommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/CommandSet.java
new file mode 100644
index 0000000..17b956c
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/processor/CommandSet.java
@@ -0,0 +1,68 @@
+/* CommandSet.java -- An interface defining JDWP Command Sets
+ Copyright (C) 2005 Free Software Foundation
+
+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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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
+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 gnu.classpath.jdwp.processor;
+
+import gnu.classpath.jdwp.exception.JdwpException;
+
+import java.io.DataOutputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * A class representing a JDWP Command Set. This class serves as a generic
+ * interface for all Command Sets types used by JDWP.
+ *
+ * @author Aaron Luchko PacketProcessor
object
+ * Connection must be validated before getting here!
+ *
+ * @param con the connection
+ */
+ public PacketProcessor (JdwpConnection con)
+ {
+ _connection = con;
+ _shutdown = false;
+
+ // MAXIMUM is the value of the largest command set we may receive
+ _sets = new CommandSet[JdwpConstants.CommandSet.MAXIMUM + 1];
+ _outputBytes = new ByteArrayOutputStream();
+ _os = new DataOutputStream (_outputBytes);
+
+ // Create all the Command Sets and add them to our array
+ _sets[JdwpConstants.CommandSet.VirtualMachine.CS_VALUE] =
+ new VirtualMachineCommandSet();
+ _sets[JdwpConstants.CommandSet.ReferenceType.CS_VALUE] =
+ new ReferenceTypeCommandSet();
+ _sets[JdwpConstants.CommandSet.ClassType.CS_VALUE] =
+ new ClassTypeCommandSet();
+ _sets[JdwpConstants.CommandSet.ArrayType.CS_VALUE] =
+ new ArrayTypeCommandSet();
+ _sets[JdwpConstants.CommandSet.InterfaceType.CS_VALUE] =
+ new InterfaceTypeCommandSet();
+ _sets[JdwpConstants.CommandSet.Method.CS_VALUE] =
+ new MethodCommandSet();
+ _sets[JdwpConstants.CommandSet.Field.CS_VALUE] =
+ new FieldCommandSet();
+ _sets[JdwpConstants.CommandSet.ObjectReference.CS_VALUE] =
+ new ObjectReferenceCommandSet();
+ _sets[JdwpConstants.CommandSet.StringReference.CS_VALUE] =
+ new StringReferenceCommandSet();
+ _sets[JdwpConstants.CommandSet.ThreadReference.CS_VALUE] =
+ new ThreadReferenceCommandSet();
+ _sets[JdwpConstants.CommandSet.ThreadGroupReference.CS_VALUE] =
+ new ThreadGroupReferenceCommandSet();
+ _sets[JdwpConstants.CommandSet.ArrayReference.CS_VALUE] =
+ new ArrayReferenceCommandSet();
+ _sets[JdwpConstants.CommandSet.ClassLoaderReference.CS_VALUE] =
+ new ClassLoaderReferenceCommandSet();
+ _sets[JdwpConstants.CommandSet.EventRequest.CS_VALUE] =
+ new EventRequestCommandSet();
+ _sets[JdwpConstants.CommandSet.StackFrame.CS_VALUE] =
+ new StackFrameCommandSet();
+ _sets[JdwpConstants.CommandSet.ClassObjectReference.CS_VALUE] =
+ new ClassObjectReferenceCommandSet();
+ }
+
+ /**
+ * Main run routine for this thread. Will loop getting packets
+ * from the connection and processing them.
+ */
+ public void run ()
+ {
+ try
+ {
+ while (!_shutdown)
+ {
+ _processOnePacket ();
+ }
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ // Time to shutdown, tell Jdwp to shutdown
+ Jdwp.getDefault().shutdown();
+ }
+
+ /**
+ * Shutdown the packet processor
+ */
+ public void shutdown ()
+ {
+ _shutdown = true;
+ interrupt ();
+ }
+
+ // Helper function which actually does all the work of waiting
+ // for a packet and getting it processed.
+ private void _processOnePacket ()
+ throws IOException
+ {
+ JdwpPacket pkt = _connection.getPacket ();
+
+ if (!(pkt instanceof JdwpCommandPacket))
+ {
+ // We're not supposed to get these from the debugger!
+ // Drop it on the floor
+ return;
+ }
+
+ if (pkt != null)
+ {
+ JdwpCommandPacket commandPkt = (JdwpCommandPacket) pkt;
+ JdwpReplyPacket reply = new JdwpReplyPacket(commandPkt);
+
+ // Reset our output stream
+ _outputBytes.reset();
+
+ // Create a ByteBuffer around the command packet
+ ByteBuffer bb = ByteBuffer.wrap(commandPkt.getData());
+ byte command = commandPkt.getCommand();
+ byte commandSet = commandPkt.getCommandSet();
+
+ CommandSet set = null;
+ try
+ {
+ // There is no command set with value 0
+ if (commandSet > 0 && commandSet < _sets.length)
+ {
+ set = _sets[commandPkt.getCommandSet()];
+ }
+ if (set != null)
+ {
+ _shutdown = set.runCommand(bb, _os, command);
+ reply.setData(_outputBytes.toByteArray());
+ }
+ else
+ {
+ // This command set wasn't in our tree
+ reply.setErrorCode(JdwpConstants.Error.NOT_IMPLEMENTED);
+ }
+ }
+ catch (JdwpException ex)
+ {
+ reply.setErrorCode(ex.getErrorCode ());
+ }
+ _connection.sendPacket (reply);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java
new file mode 100644
index 0000000..34def9f
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java
@@ -0,0 +1,321 @@
+/* ReferenceTypeCommandSet.java -- lass to implement the ReferenceType
+ Command Set
+ Copyright (C) 2005 Free Software Foundation
+
+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 gnu.classpath.jdwp.processor;
+
+import gnu.classpath.jdwp.IVirtualMachine;
+import gnu.classpath.jdwp.Jdwp;
+import gnu.classpath.jdwp.JdwpConstants;
+import gnu.classpath.jdwp.exception.InvalidFieldException;
+import gnu.classpath.jdwp.exception.JdwpException;
+import gnu.classpath.jdwp.exception.JdwpInternalErrorException;
+import gnu.classpath.jdwp.exception.NotImplementedException;
+import gnu.classpath.jdwp.id.IdManager;
+import gnu.classpath.jdwp.id.ObjectId;
+import gnu.classpath.jdwp.id.ReferenceTypeId;
+import gnu.classpath.jdwp.util.JdwpString;
+import gnu.classpath.jdwp.util.Signature;
+import gnu.classpath.jdwp.util.Value;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+
+/**
+ * A class representing the ReferenceType Command Set.
+ *
+ * @author Aaron Luchko JdwpCommandPacket
+ */
+ public JdwpCommandPacket ()
+ {
+ // Don't assign an id. This constructor is called by
+ // JdwpPacket.fromBytes, and that will assign a packet id.
+ }
+
+ /**
+ * Constructs a new JdwpCommandPacket
+ * with the given command set and command
+ *
+ * @param set the command set
+ * @param command the command
+ */
+ public JdwpCommandPacket (byte set, byte command)
+ {
+ _id = ++_last_id;
+ _commandSet = set;
+ _command = command;
+ }
+
+ /**
+ * Retuns the length of this packet
+ */
+ public int getLength ()
+ {
+ return MINIMUM_LENGTH + super.getLength ();
+ }
+
+ /**
+ * Returns the command set
+ */
+ public byte getCommandSet ()
+ {
+ return _commandSet;
+ }
+
+ /**
+ * Sets the command set
+ */
+ public void setCommandSet (byte cs)
+ {
+ _commandSet = cs;
+ }
+
+ /**
+ * Returns the command
+ */
+ public byte getCommand ()
+ {
+ return _command;
+ }
+
+ /**
+ * Sets the command
+ */
+ public void setCommand (byte cmd)
+ {
+ _command = cmd;
+ }
+
+ // Reads command packet data from the given buffer, starting
+ // at the given offset
+ protected int myFromBytes (byte[] bytes, int index)
+ {
+ int i = 0;
+ setCommandSet (bytes[index + i++]);
+ setCommand (bytes[index + i++]);
+ return i;
+ }
+
+ // Writes the command packet data into the given buffer
+ protected void myWrite (DataOutputStream dos)
+ throws IOException
+ {
+ dos.writeByte (getCommandSet ());
+ dos.writeByte (getCommand ());
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java
new file mode 100644
index 0000000..18250d3
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java
@@ -0,0 +1,298 @@
+/* JdwpConnection.java -- A JDWP-speaking connection
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.transport;
+
+import gnu.classpath.jdwp.Jdwp;
+import gnu.classpath.jdwp.event.Event;
+import gnu.classpath.jdwp.event.EventRequest;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * A connection via some transport to some JDWP-speaking entity.
+ * This is also a thread which handles all communications to/from
+ * the debugger. While access to the transport layer may be accessed by
+ * several threads, start-up and initialization should not be allowed
+ * to occur more than once.
+ *
+ * JdwpConnection
instance
+ *
+ * @param transport the transport to use for communications
+ */
+ public JdwpConnection (ITransport transport)
+ {
+ _transport = transport;
+ _commandQueue = new ArrayList ();
+ _shutdown = false;
+ _bytes = new ByteArrayOutputStream ();
+ _doStream = new DataOutputStream (_bytes);
+ }
+
+ /**
+ * Initializes the connection, including connecting
+ * to socket or shared memory endpoint
+ *
+ * @throws TransportException if initialization fails
+ */
+ public void initialize ()
+ throws TransportException
+ {
+ // Initialize transport (connect socket, e.g.)
+ _transport.initialize ();
+
+ // Do handshake
+ try
+ {
+ _inStream = new DataInputStream (_transport.getInputStream ());
+ _outStream = new DataOutputStream (_transport.getOutputStream ());
+ _doHandshake ();
+ }
+ catch (IOException ioe)
+ {
+ throw new TransportException (ioe);
+ }
+ }
+
+ /* Does the JDWP handshake -- this should not need synchronization
+ because this is called by VM startup code, i.e., no packet
+ processing threads have started yet. */
+ private void _doHandshake ()
+ throws IOException
+ {
+ // According to the spec, the handshake is always initiated by
+ // the debugger, regardless of whether the JVM is in client mode or
+ // server mode.
+
+ // Wait for handshake from debugger
+ byte[] hshake = new byte[_HANDSHAKE.length];
+ _inStream.readFully (hshake, 0, _HANDSHAKE.length);
+
+ if (Arrays.equals (hshake, _HANDSHAKE))
+ {
+ // Send reply handshake
+ _outStream.write (_HANDSHAKE, 0, _HANDSHAKE.length);
+ return;
+ }
+ else
+ {
+ throw new IOException ("invalid JDWP handshake (\"" + hshake + "\")");
+ }
+ }
+
+ /**
+ * Main run method for the thread. This thread loops waiting for
+ * packets to be read via the connection. When a packet is complete
+ * and ready for processing, it places the packet in a queue that can
+ * be accessed via getPacket
+ */
+ public void run ()
+ {
+ while (!_shutdown)
+ {
+ try
+ {
+ _readOnePacket ();
+ }
+ catch (IOException ioe)
+ {
+ /* IOException can occur for two reasons:
+ 1. Lost connection with the other side
+ 2. Transport was shutdown
+ In either case, we make sure that all of the
+ back-end gets shutdown. */
+ Jdwp.getInstance().shutdown ();
+ }
+ catch (Throwable t)
+ {
+ System.out.println ("JdwpConnection.run: caught an exception: "
+ + t);
+ // Just keep going
+ }
+ }
+ }
+
+ // Reads a single packet from the connection, adding it to the packet
+ // queue when a complete packet is ready.
+ private void _readOnePacket ()
+ throws IOException
+ {
+ byte[] data = null;
+
+ // Read in the packet
+ int length = _inStream.readInt ();
+ if (length < 11)
+ {
+ throw new IOException ("JDWP packet length < 11 ("
+ + length + ")");
+ }
+
+ data = new byte[length];
+ data[0] = (byte) (length >>> 24);
+ data[1] = (byte) (length >>> 16);
+ data[2] = (byte) (length >>> 8);
+ data[3] = (byte) length;
+ _inStream.readFully (data, 4, length - 4);
+
+ JdwpPacket packet = JdwpPacket.fromBytes (data);
+ if (packet != null)
+ {
+ synchronized (_commandQueue)
+ {
+ _commandQueue.add (packet);
+ _commandQueue.notifyAll ();
+ }
+ }
+ }
+
+ /**
+ * Returns a packet from the queue of ready packets
+ *
+ * @returns a JdwpPacket
ready for processing
+ * null
when shutting down
+ */
+ public JdwpPacket getPacket ()
+ {
+ synchronized (_commandQueue)
+ {
+ while (_commandQueue.isEmpty ())
+ {
+ try
+ {
+ _commandQueue.wait ();
+ }
+ catch (InterruptedException ie)
+ {
+ /* PacketProcessor is interrupted
+ when shutting down */
+ return null;
+ }
+ }
+
+ return (JdwpPacket) _commandQueue.remove (0);
+ }
+ }
+
+ /**
+ * Send a packet to the debugger
+ *
+ * @param pkt a JdwpPacket
to send
+ * @throws IOException
+ */
+ public void sendPacket (JdwpPacket pkt)
+ throws IOException
+ {
+ pkt.write (_outStream);
+ }
+
+ /**
+ * Send an event notification to the debugger
+ *
+ * @param request the debugger request that wanted this event
+ * @param event the event
+ * @throws IOException
+ */
+ public void sendEvent (EventRequest request, Event event)
+ throws IOException
+ {
+ JdwpPacket pkt;
+
+ synchronized (_bytes)
+ {
+ _bytes.reset ();
+ pkt = event.toPacket (_doStream, request);
+ pkt.setData (_bytes.toByteArray ());
+ }
+
+ sendPacket (pkt);
+ }
+
+ /**
+ * Shutdown the connection
+ */
+ public void shutdown ()
+ {
+ if (!_shutdown)
+ {
+ _transport.shutdown ();
+ _shutdown = true;
+ interrupt ();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/JdwpPacket.java b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpPacket.java
new file mode 100644
index 0000000..7fa93e2
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpPacket.java
@@ -0,0 +1,278 @@
+/* JdwpPacket.java -- Base class for JDWP command and reply packets
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.transport;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * All command and reply packets in JDWP share
+ * common header type information:
+ *
+ * length (4 bytes) : size of entire packet, including length
+ * id (4 bytes) : unique packet id
+ * flags (1 byte) : flag byte
+ * [command packet stuff | reply packet stuff]
+ * data (variable) : unique command-/reply-specific data
+ *
+ * This class deal with everything except the command- and reply-specific
+ * data, which get handled in {@link
+ * gnu.classpath.jdwp.transport.JdwpCommandPacket} and {@link
+ * gnu.classpath.jdwp.transprot.JdwpReplyPacket}.
+ *
+ * @author Keith Seitz JdwpPacket
with the id
+ * from the given packet.
+ *
+ * @param pkt a packet whose id will be used in this new packet
+ */
+ public JdwpPacket (JdwpPacket pkt)
+ {
+ _id = pkt.getId ();
+ }
+
+ /**
+ * Returns the packet id
+ */
+ public int getId ()
+ {
+ return _id;
+ }
+
+ /**
+ * Sets the packet id
+ */
+ public void setId (int id)
+ {
+ _id = id;
+ }
+
+ /**
+ * Returns the packet flags
+ */
+ public byte getFlags ()
+ {
+ return _flags;
+ }
+
+ /**
+ * Sets the packet flags
+ */
+ public void setFlags (byte flags)
+ {
+ _flags = flags;
+ }
+
+ /**
+ * Gets the command/reply-specific data in this packet
+ */
+ public byte[] getData ()
+ {
+ return _data;
+ }
+
+ /**
+ * Sets the command/reply-specific data in this packet
+ */
+ public void setData (byte[] data)
+ {
+ _data = data;
+ }
+
+ /**
+ * Returns the length of this entire packet
+ */
+ public int getLength ()
+ {
+ return MINIMUM_SIZE + (_data == null ? 0 : _data.length);
+ }
+
+ /**
+ * Allow subclasses to initialize from data
+ *
+ * @param bytes packet data from the wire
+ * @param index index into bytes
to start processing
+ * @return number of bytes in bytes
processed
+ */
+ protected abstract int myFromBytes (byte[] bytes, int index);
+
+ /**
+ * Convert the given bytes into a JdwpPacket
. Uses the
+ * abstract method myFromBytes
to allow subclasses to
+ * process data.
+ *
+ * If the given data does not represent a valid JDWP packet, it returns
+ * null
.
+ *
+ * @param bytes packet data from the wire
+ * @param index index into bytes
to start processing
+ * @return number of bytes in bytes
processed
+ */
+ public static JdwpPacket fromBytes (byte[] bytes)
+ {
+ int i = 0;
+ int length = ((bytes[i++] & 0xff) << 24 | (bytes[i++] & 0xff) << 16
+ | (bytes[i++] & 0xff) << 8 | (bytes[i++] & 0xff));
+ int id = 0;
+ byte flags = 0;
+
+ if (bytes.length == length)
+ {
+ id = ((bytes[i++] & 0xff) << 24 | (bytes[i++] & 0xff) << 16
+ | (bytes[i++] & 0xff) << 8 | (bytes[i++] & 0xff));
+ flags = bytes[i++];
+
+ Class clazz = null;
+ if (flags == 0)
+ clazz = JdwpCommandPacket.class;
+ else if ((flags & JDWP_FLAG_REPLY) != 0)
+ clazz = JdwpReplyPacket.class;
+ else
+ {
+ // Malformed packet. Discard it.
+ return null;
+ }
+
+ JdwpPacket pkt = null;
+ try
+ {
+ pkt = (JdwpPacket) clazz.newInstance ();
+ }
+ catch (InstantiationException ie)
+ {
+ // Discard packet
+ return null;
+ }
+ catch (IllegalAccessException iae)
+ {
+ // Discard packet
+ return null;
+ }
+
+ pkt.setId (id);
+ pkt.setFlags (flags);
+
+ i += pkt.myFromBytes (bytes, i);
+ byte[] data = new byte[length - i];
+ System.arraycopy (bytes, i, data, 0, data.length);
+ pkt.setData (data);
+
+ return pkt;
+ }
+
+ return null;
+ }
+
+ /**
+ * Put subclass information onto the stream
+ *
+ * @param dos the output stream to which to write
+ */
+ protected abstract void myWrite (DataOutputStream dos)
+ throws IOException;
+
+ /**
+ * Writes the packet to the output stream
+ *
+ * @param dos the output stream to which to write the packet
+ */
+ public void write (DataOutputStream dos)
+ throws IOException
+ {
+ // length
+ int length = getLength ();
+ dos.writeInt (length);
+
+ // ID
+ dos.writeInt (getId ());
+
+ // flag
+ dos.writeByte (getFlags ());
+
+ // packet-specific stuff
+ myWrite (dos);
+
+ // data (if any)
+ byte[] data = getData ();
+ if (data != null && data.length > 0)
+ dos.write (data, 0, data.length);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/JdwpReplyPacket.java b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpReplyPacket.java
new file mode 100644
index 0000000..de32ecf
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpReplyPacket.java
@@ -0,0 +1,137 @@
+/* JdwpReplyPacket.java -- JDWP reply packet
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.transport;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * A class represents a JDWP reply packet.
+ * This class adds an error code to the packet header information
+ * in {@link gnu.classpath.transport.JdwpPacket} and adds additional
+ * reply packet-specific processing.
+ *
+ * @author Keith Seitz JdwpReplyPacket
.
+ */
+ public JdwpReplyPacket ()
+ {
+ // Don't assign a packet id. This is called by JdwpPacket.fromBytes
+ // which assigns a packet id. (Not that a VM would do that...)
+ }
+
+ /**
+ * Constructs a JdwpReplyPacket
with the
+ * id from the given packet and error code
+ *
+ * @param pkt the packet whose id this packet will use
+ * @param errorCode the error code
+ */
+ public JdwpReplyPacket (JdwpPacket pkt, short errorCode)
+ {
+ this(pkt);
+ _errorCode = errorCode;
+ }
+
+ /**
+ * Constructs a JdwpReplyPacket
with the
+ * id from the given packet and an empty error code
+ *
+ * @param pkt the packet whose id this packet will use
+ */
+ public JdwpReplyPacket (JdwpPacket pkt)
+ {
+ super (pkt);
+ _flags = (byte) JDWP_FLAG_REPLY;
+ }
+
+ /**
+ * Returns the length of this packet
+ */
+ public int getLength ()
+ {
+ return MINIMUM_LENGTH + super.getLength ();
+ }
+
+ /**
+ * Returns the error code
+ */
+ public short getErrorCode ()
+ {
+ return _errorCode;
+ }
+
+ /**
+ * Sets the error code
+ */
+ public void setErrorCode (short ec)
+ {
+ _errorCode = ec;
+ }
+
+ // Reads command packet data from the given buffer, starting
+ // at the given offset
+ protected int myFromBytes (byte[] bytes, int index)
+ {
+ int i = 0;
+ setErrorCode ((short) ((bytes[index + i++] & 0xff) << 8
+ | (bytes[index + i++] & 0xff)));
+ return i;
+ }
+
+ // Writes the command packet data into the given buffer
+ protected void myWrite (DataOutputStream dos)
+ throws IOException
+ {
+ dos.writeShort (getErrorCode ());
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java b/libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java
new file mode 100644
index 0000000..0ad7357
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java
@@ -0,0 +1,171 @@
+/* SocketTransport.java -- a socket transport
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.transport;
+
+import gnu.classpath.jdwp.transport.ITransport;
+import gnu.classpath.jdwp.transport.TransportException;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashMap;
+
+import javax.net.ServerSocketFactory;
+import javax.net.SocketFactory;
+
+/**
+ * A socket-based transport. This transport uses
+ * configury string that looks like "name=dt_socket,
+ * address=localhost:1234,server=y".
+ *
+ * @author Keith Seitz InputStream
for the transport
+ *
+ * @throws IOException if an I/O error occurs creating the stream
+ * or the socket is not connected
+ */
+ public InputStream getInputStream ()
+ throws IOException
+ {
+ return _socket.getInputStream ();
+ }
+
+ /**
+ * Returns an OutputStream
for the transport
+ *
+ * @throws IOException if an I/O error occurs creating the stream
+ * or the socket is not connected
+ */
+ public OutputStream getOutputStream ()
+ throws IOException
+ {
+ return _socket.getOutputStream ();
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/TransportException.java b/libjava/classpath/gnu/classpath/jdwp/transport/TransportException.java
new file mode 100644
index 0000000..057422a
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/transport/TransportException.java
@@ -0,0 +1,75 @@
+/* TransportException.java -- Exception for transport configury errors
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.transport;
+
+/**
+ * A transport configury or initialization exception thrown by
+ * JDWP transports. This class is a generic exception class
+ * that the different transport layers use to report transport-specific
+ * exceptions that may occur (which could be very different from
+ * one transport to the next.).
+ *
+ * @author Keith Seitz TransportException
with the
+ * given message
+ *
+ * @param message a message describing the exception
+ */
+ public TransportException (String message)
+ {
+ super (message);
+ }
+
+ /**
+ * Constructs a TransportException
with the
+ * given Throwable
root cause
+ *
+ * @param t the cause of the exception
+ */
+ public TransportException (Throwable t)
+ {
+ super (t);
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/TransportFactory.java b/libjava/classpath/gnu/classpath/jdwp/transport/TransportFactory.java
new file mode 100644
index 0000000..480fb36
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/transport/TransportFactory.java
@@ -0,0 +1,115 @@
+/* TransportFactory.java -- Factory for transports
+ Copyright (C) 2005 Free Software Foundation
+
+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
+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 gnu.classpath.jdwp.transport;
+
+import java.util.HashMap;
+
+/**
+ * A factory class that constructs transports for use by
+ * the JDWP back-end.
+ *
+ * @author Keith Seitz HashMap
specifying the JDWP
+ * configuration properties
+ * @returns the created and configured transport
+ * @throws TransportException for invalid configurations
+ */
+ public static ITransport newInstance (HashMap properties)
+ throws TransportException
+ {
+ String name = null;
+ if (properties != null)
+ name = (String) properties.get (_TRANSPORT_PROPERTY);
+ if (name == null)
+ throw new TransportException ("no transport specified");
+
+ for (int i = 0; i < _transportMethods.length; ++i)
+ {
+ if (_transportMethods[i].name.equals (name))
+ {
+ try
+ {
+ ITransport t;
+ t = (ITransport) _transportMethods[i].clazz.newInstance ();
+ t.configure (properties);
+ return t;
+ }
+ catch (TransportException te)
+ {
+ throw te;
+ }
+ catch (Exception e)
+ {
+ throw new TransportException (e);
+ }
+ }
+ }
+
+ throw new TransportException ("transport \"" + name + "\" not found");
+ }
+}
diff --git a/libjava/classpath/gnu/classpath/jdwp/util/JdwpString.java b/libjava/classpath/gnu/classpath/jdwp/util/JdwpString.java
new file mode 100644
index 0000000..e94700f
--- /dev/null
+++ b/libjava/classpath/gnu/classpath/jdwp/util/JdwpString.java
@@ -0,0 +1,95 @@
+/* JdwpString.java -- utility class to read and write jdwp strings
+ Copyright (C) 2005 Free Software Foundation
+
+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 gnu.classpath.jdwp.util;
+
+import gnu.classpath.jdwp.exception.JdwpInternalErrorException;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+
+/**
+ * A class to compute the JDWP representation of Strings.
+ *
+ * @author Aaron Luchko listIndex
. The array of Components is searched from
+ * the beginning to find the matching array index.
+ *
+ * @param listIndex the index from where to begin iterating
+ */
+ VisibleComponentIterator(int listIndex)
+ {
+ this.listIndex = listIndex;
+ int visibleComponentsFound = 0;
+ for (index = 0; visibleComponentsFound != listIndex; index++)
+ {
+ if (components[index].isVisible())
+ visibleComponentsFound++;
+ }
+ }
+
+ /**
+ * Returns true
if there are more visible components in the
+ * array, false
otherwise.
+ *
+ * @return true
if there are more visible components in the
+ * array, false
otherwise
+ */
+ public boolean hasNext()
+ {
+ boolean hasNext = false;
+ for (int i = index; i < components.length; i++)
+ {
+ if (components[i].isVisible())
+ {
+ hasNext = true;
+ break;
+ }
+ }
+ return hasNext;
+ }
+
+ /**
+ * Returns the next visible Component
in the List.
+ *
+ * @return the next visible Component
in the List
+ *
+ * @throws if there is no next element
+ */
+ public Object next()
+ {
+ Object o = null;
+ for (; index < components.length; index++)
+ {
+ if (components[index].isVisible())
+ {
+ o = components[index];
+ break;
+ }
+ }
+ if (o != null)
+ {
+ index++;
+ listIndex++;
+ return o;
+ }
+ else
+ throw new NoSuchElementException();
+ }
+
+ /**
+ * Returns true
if there are more visible components in the
+ * array in the reverse direction, false
otherwise.
+ *
+ * @return true
if there are more visible components in the
+ * array in the reverse direction, false
otherwise
+ */
+ public boolean hasPrevious()
+ {
+ boolean hasPrevious = false;
+ for (int i = index - 1; i >= 0; i--)
+ {
+ if (components[i].isVisible())
+ {
+ hasPrevious = true;
+ break;
+ }
+ }
+ return hasPrevious;
+ }
+
+ /**
+ * Returns the previous visible Component
in the List.
+ *
+ * @return the previous visible Component
in the List
+ *
+ * @throws NoSuchElementException if there is no previous element
+ */
+ public Object previous()
+ {
+ Object o = null;
+ for (index--; index >= 0; index--)
+ {
+ if (components[index].isVisible())
+ {
+ o = components[index];
+ break;
+ }
+ }
+ if (o != null)
+ {
+ listIndex--;
+ return o;
+ }
+ else
+ throw new NoSuchElementException();
+ }
+
+ /**
+ * Returns the index of the next element in the List.
+ *
+ * @return the index of the next element in the List
+ */
+ public int nextIndex()
+ {
+ return listIndex + 1;
+ }
+
+ /**
+ * Returns the index of the previous element in the List.
+ *
+ * @return the index of the previous element in the List
+ */
+ public int previousIndex()
+ {
+ return listIndex - 1;
+ }
+
+ /**
+ * This operation is not supported because the List is immutable.
+ *
+ * @throws UnsupportedOperationException because the List is immutable
+ */
+ public void remove()
+ {
+ throw new UnsupportedOperationException
+ ("VisibleComponentList is immutable");
+ }
+
+ /**
+ * This operation is not supported because the List is immutable.
+ *
+ * @param o not used here
+ *
+ * @throws UnsupportedOperationException because the List is immutable
+ */
+ public void set(Object o)
+ {
+ throw new UnsupportedOperationException
+ ("VisibleComponentList is immutable");
+ }
+
+ /**
+ * This operation is not supported because the List is immutable.
+ *
+ * @param o not used here
+ *
+ * @throws UnsupportedOperationException because the List is immutable
+ */
+ public void add(Object o)
+ {
+ throw new UnsupportedOperationException
+ ("VisibleComponentList is immutable");
+ }
+ }
+
+ /**
+ * The components over which we iterate. Only the visible components
+ * are returned by this List.
+ */
+ Component[] components;
+
+ /**
+ * Creates a new instance of VisibleComponentList that wraps the specified
+ * Component[]
.
+ *
+ * @param c the Component[]
to be wrapped.
+ */
+ VisibleComponentList(Component[] c)
+ {
+ components = c;
+ }
+
+ /**
+ * Returns a {@link ListIterator} for iterating over this List.
+ *
+ * @return a {@link ListIterator} for iterating over this List
+ */
+ public ListIterator listIterator(int index)
+ {
+ return new VisibleComponentIterator(index);
+ }
+
+ /**
+ * Returns the number of visible components in the wrapped Component[].
+ *
+ * @return the number of visible components
+ */
+ public int size()
+ {
+ int visibleComponents = 0;
+ for (int i = 0; i < components.length; i++)
+ if (components[i].isVisible())
+ visibleComponents++;
+ return visibleComponents;
+ }
+ }
+
+ /**
+ * The cache for our List instances. We try to hold one instance of
+ * VisibleComponentList for each Component[] that is requested. Note
+ * that we use a WeakHashMap for caching, so that the cache itself
+ * does not keep the array or the List from beeing garbage collected
+ * if no other objects hold references to it.
+ */
+ static WeakHashMap visibleChildrenCache = new WeakHashMap();
+
+ /**
+ * Returns the visible children of a {@link Container}. This method is
+ * commonly needed in LayoutManagers, because they only have to layout
+ * the visible children of a Container.
+ *
+ * @param c the Container from which to extract the visible children
+ *
+ * @return the visible children of c
+ */
+ public static List getVisibleChildren(Container c)
+ {
+ Component[] children = c.getComponents();
+ Object o = visibleChildrenCache.get(children);
+ VisibleComponentList visibleChildren = null;
+ if (o == null)
+ {
+ visibleChildren = new VisibleComponentList(children);
+ visibleChildrenCache.put(children, visibleChildren);
+ }
+ else
+ visibleChildren = (VisibleComponentList) o;
+
+ return visibleChildren;
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/BitMaskExtent.java b/libjava/classpath/gnu/java/awt/BitMaskExtent.java
new file mode 100644
index 0000000..2813499
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/BitMaskExtent.java
@@ -0,0 +1,79 @@
+/* Copyright (C) 2000, 2002 Free Software Foundation
+
+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 gnu.java.awt;
+
+/**
+ * Simple transparent utility class that can be used to perform bit
+ * mask extent calculations.
+ */
+public final class BitMaskExtent
+{
+ /** The number of the least significant bit of the bit mask extent. */
+ public byte leastSignificantBit;
+
+ /** The number of bits in the bit mask extent. */
+ public byte bitWidth;
+
+ /**
+ * Set the bit mask. This will calculate and set the leastSignificantBit
+ * and bitWidth fields.
+ *
+ * @see #leastSignificantBit
+ * @see #bitWidth
+ */
+ public void setMask(long mask)
+ {
+ leastSignificantBit = 0;
+ bitWidth = 0;
+ if (mask == 0) return;
+ long shiftMask = mask;
+ for (; (shiftMask&1) == 0; shiftMask >>>=1) leastSignificantBit++;
+ for (; (shiftMask&1) != 0; shiftMask >>>=1) bitWidth++;
+
+ if (shiftMask != 0)
+ throw new IllegalArgumentException("mask must be continuous");
+ }
+
+ /**
+ * Calculate the bit mask based on the values of the
+ * leastSignificantBit and bitWidth fields.
+ */
+ public long toMask()
+ {
+ return ((1<
+ *
+ *
setXORMode
for drawing “highlights” such
+ * as text selections or cursors by inverting colors temporarily and
+ * then inverting them back.
+ *
+ * Graphics
implementation may contain
+ * the following code:
+ *
+ * public void setXORMode(Color xorColor)
+ * {
+ * setComposite(new gnu.java.awt.BitwiseXORComposite(xorColor));
+ * }
+ *
+ * public void setPaintMode()
+ * {
+ * setComposite(java.awt.AlphaComposite.SrcOver);
+ * }
+ *
+ * @author Graydon Hoare (graydon@redhat.com)
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+public class BitwiseXORComposite
+ implements Composite
+{
+ /**
+ * The color whose RGB value is xor-ed with the values of each
+ * pixel.
+ */
+ protected Color xorColor;
+
+
+ /**
+ * Constructs a new composite for xor-ing the pixel value.
+ *
+ * @param xorColor the color whose pixel value will be bitwise
+ * xor-ed with the source and destination pixels.
+ */
+ public BitwiseXORComposite(Color xorColor)
+ {
+ this.xorColor = xorColor;
+ }
+
+
+ /**
+ * Creates a context object for performing the compositing
+ * operation. Several contexts may co-exist for one composite; each
+ * context may simultaneously be called from concurrent threads.
+ *
+ * @param srcColorModel the color model of the source.
+ * @param dstColorModel the color model of the destination.
+ * @param hints hints for choosing between rendering alternatives.
+ */
+ public CompositeContext createContext(ColorModel srcColorModel,
+ ColorModel dstColorModel,
+ RenderingHints hints)
+ {
+ if (IntContext.isSupported(srcColorModel, dstColorModel, hints))
+ return new IntContext(srcColorModel, xorColor);
+
+ return new GeneralContext(srcColorModel, dstColorModel, xorColor);
+ }
+
+
+ /**
+ * A fallback CompositeContext that performs bitwise XOR of pixel
+ * values with the pixel value of the specified xorColor
.
+ *
+ * TYPE_INT_RGB
took 611 ms on a lightly loaded 2.4 GHz
+ * Intel Pentium 4 CPU running Sun J2SE 1.4.1_01 on GNU/Linux
+ * 2.4.20. The timing is the average of ten runs on the same
+ * BufferedImage. Since the measurements were taken with {@link
+ * System#currentTimeMillis()}, they are rather inaccurate.
+ *
+ * @author Graydon Hoare (graydon@redhat.com)
+ */
+ private static class GeneralContext
+ implements CompositeContext
+ {
+ ColorModel srcColorModel;
+ ColorModel dstColorModel;
+ Color xorColor;
+
+ public GeneralContext(ColorModel srcColorModel,
+ ColorModel dstColorModel,
+ Color xorColor)
+ {
+ this.srcColorModel = srcColorModel;
+ this.dstColorModel = dstColorModel;
+ this.xorColor = xorColor;
+ }
+
+
+ public void compose(Raster src, Raster dstIn, WritableRaster dstOut)
+ {
+ Rectangle srcRect = src.getBounds();
+ Rectangle dstInRect = dstIn.getBounds();
+ Rectangle dstOutRect = dstOut.getBounds();
+
+ int xp = xorColor.getRGB();
+ int w = Math.min(Math.min(srcRect.width, dstOutRect.width),
+ dstInRect.width);
+ int h = Math.min(Math.min(srcRect.height, dstOutRect.height),
+ dstInRect.height);
+
+ Object srcPix = null, dstPix = null, rpPix = null;
+
+ // Re-using the rpPix object saved 1-2% of execution time in
+ // the 1024x1024 pixel benchmark.
+
+ for (int y = 0; y < h; y++)
+ {
+ for (int x = 0; x < w; x++)
+ {
+ srcPix = src.getDataElements(x + srcRect.x, y + srcRect.y, srcPix);
+ dstPix = dstIn.getDataElements(x + dstInRect.x, y + dstInRect.y,
+ dstPix);
+ int sp = srcColorModel.getRGB(srcPix);
+ int dp = dstColorModel.getRGB(dstPix);
+ int rp = sp ^ xp ^ dp;
+ dstOut.setDataElements(x + dstOutRect.x, y + dstOutRect.y,
+ dstColorModel.getDataElements(rp, rpPix));
+ }
+ }
+ }
+
+
+ /**
+ * Disposes any cached resources. The default implementation does
+ * nothing because no resources are cached.
+ */
+ public void dispose()
+ {
+ }
+ }
+
+
+ /**
+ * An optimized CompositeContext that performs bitwise XOR of
+ * int
pixel values with the pixel value of a specified
+ * xorColor
. This CompositeContext working only for
+ * rasters whose transfer format is {@link DataBuffer#TYPE_INT}.
+ *
+ * TYPE_INT_RGB
took 69 ms on a lightly loaded 2.4 GHz
+ * Intel Pentium 4 CPU running Sun J2SE 1.4.1_01 on GNU/Linux
+ * 2.4.20. The timing is the average of ten runs on the same
+ * BufferedImage. Since the measurements were taken with {@link
+ * System#currentTimeMillis()}, they are rather inaccurate.
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+ private static class IntContext
+ extends GeneralContext
+ {
+ public IntContext(ColorModel colorModel, Color xorColor)
+ {
+ super(colorModel, colorModel, xorColor);
+ }
+
+
+ public void compose(Raster src, Raster dstIn,
+ WritableRaster dstOut)
+ {
+ int aX, bX, dstX, aY, bY, dstY, width, height;
+ int xorPixel;
+ int[] srcLine, dstLine;
+
+ aX = src.getMinX();
+ aY = src.getMinY();
+ bX = dstIn.getMinX();
+ bY = dstIn.getMinY();
+ dstX = dstOut.getMinX();
+ dstY = dstOut.getMinY();
+ width = Math.min(Math.min(src.getWidth(), dstIn.getWidth()),
+ dstOut.getWidth());
+ height = Math.min(Math.min(src.getHeight(), dstIn.getHeight()),
+ dstOut.getHeight());
+ if ((width < 1) || (height < 1))
+ return;
+
+ srcLine = new int[width];
+ dstLine = new int[width];
+
+ /* We need an int[] array with at least one element here;
+ * srcLine is as good as any other.
+ */
+ srcColorModel.getDataElements(this.xorColor.getRGB(), srcLine);
+ xorPixel = srcLine[0];
+
+ for (int y = 0; y < height; y++)
+ {
+ src.getDataElements(aX, y + aY, width, 1, srcLine);
+ dstIn.getDataElements(bX, y + bY, width, 1, dstLine);
+
+ for (int x = 0; x < width; x++)
+ dstLine[x] ^= srcLine[x] ^ xorPixel;
+
+ dstOut.setDataElements(dstX, y + dstY, width, 1, dstLine);
+ }
+ }
+
+
+ /**
+ * Determines whether an instance of this CompositeContext would
+ * be able to process the specified color models.
+ */
+ public static boolean isSupported(ColorModel srcColorModel,
+ ColorModel dstColorModel,
+ RenderingHints hints)
+ {
+ // FIXME: It would be good if someone could review these checks.
+ // They probably need to be more restrictive.
+
+ int transferType;
+
+ transferType = srcColorModel.getTransferType();
+ if (transferType != dstColorModel.getTransferType())
+ return false;
+
+ if (transferType != DataBuffer.TYPE_INT)
+ return false;
+
+ return true;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/Buffers.java b/libjava/classpath/gnu/java/awt/Buffers.java
new file mode 100644
index 0000000..c6ccf91
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/Buffers.java
@@ -0,0 +1,243 @@
+/* Buffers.java --
+ Copyright (C) 2000, 2002, 2004 Free Software Foundation
+
+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 gnu.java.awt;
+
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferDouble;
+import java.awt.image.DataBufferFloat;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DataBufferShort;
+import java.awt.image.DataBufferUShort;
+
+/**
+ * Utility class for creating and accessing data buffers of arbitrary
+ * data types.
+ */
+public final class Buffers
+{
+ /**
+ * Create a data buffer of a particular type.
+ *
+ * @param dataType the desired data type of the buffer.
+ * @param data an array containing data, or null
+ * @param size the size of the data buffer bank
+ */
+ public static DataBuffer createBuffer(int dataType, Object data,
+ int size)
+ {
+ if (data == null) return createBuffer(dataType, size, 1);
+
+ return createBufferFromData(dataType, data, size);
+ }
+
+
+ /**
+ * Create a data buffer of a particular type.
+ *
+ * @param dataType the desired data type of the buffer.
+ * @param size the size of the data buffer bank
+ */
+ public static DataBuffer createBuffer(int dataType, int size) {
+ return createBuffer(dataType, size, 1);
+ }
+
+ /**
+ * Create a data buffer of a particular type.
+ *
+ * @param dataType the desired data type of the buffer.
+ * @param size the size of the data buffer bank
+ * @param numBanks the number of banks the buffer should have
+ */
+ public static DataBuffer createBuffer(int dataType, int size, int numBanks)
+ {
+ switch (dataType)
+ {
+ case DataBuffer.TYPE_BYTE:
+ return new DataBufferByte(size, numBanks);
+ case DataBuffer.TYPE_SHORT:
+ return new DataBufferShort(size, numBanks);
+ case DataBuffer.TYPE_USHORT:
+ return new DataBufferUShort(size, numBanks);
+ case DataBuffer.TYPE_INT:
+ return new DataBufferInt(size, numBanks);
+ case DataBuffer.TYPE_FLOAT:
+ return new DataBufferFloat(size, numBanks);
+ case DataBuffer.TYPE_DOUBLE:
+ return new DataBufferDouble(size, numBanks);
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Create a data buffer of a particular type.
+ *
+ * @param dataType the desired data type of the buffer
+ * @param data an array containing the data
+ * @param size the size of the data buffer bank
+ */
+ public static DataBuffer createBufferFromData(int dataType, Object data,
+ int size)
+ {
+ switch (dataType)
+ {
+ case DataBuffer.TYPE_BYTE:
+ return new DataBufferByte((byte[]) data, size);
+ case DataBuffer.TYPE_SHORT:
+ return new DataBufferShort((short[]) data, size);
+ case DataBuffer.TYPE_USHORT:
+ return new DataBufferUShort((short[]) data, size);
+ case DataBuffer.TYPE_INT:
+ return new DataBufferInt((int[]) data, size);
+ case DataBuffer.TYPE_FLOAT:
+ return new DataBufferFloat((float[]) data, size);
+ case DataBuffer.TYPE_DOUBLE:
+ return new DataBufferDouble((double[]) data, size);
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Return the data array of a data buffer, regardless of the data
+ * type.
+ *
+ * @return an array of primitive values. The actual array type
+ * depends on the data type of the buffer.
+ */
+ public static Object getData(DataBuffer buffer)
+ {
+ if (buffer instanceof DataBufferByte)
+ return ((DataBufferByte) buffer).getData();
+
+ if (buffer instanceof DataBufferShort)
+ return ((DataBufferShort) buffer).getData();
+
+ if (buffer instanceof DataBufferUShort)
+ return ((DataBufferUShort) buffer).getData();
+
+ if (buffer instanceof DataBufferInt)
+ return ((DataBufferInt) buffer).getData();
+
+ if (buffer instanceof DataBufferFloat)
+ return ((DataBufferFloat) buffer).getData();
+
+ if (buffer instanceof DataBufferDouble)
+ return ((DataBufferDouble) buffer).getData();
+
+ throw new ClassCastException("Unknown data buffer type");
+ }
+
+
+ /**
+ * Copy data from array contained in data buffer, much like
+ * System.arraycopy. Create a suitable destination array if the
+ * given destination array is null.
+ */
+ public static Object getData(DataBuffer src, int srcOffset,
+ Object dest, int destOffset,
+ int length)
+ {
+ Object from;
+ if (src instanceof DataBufferByte)
+ {
+ from = ((DataBufferByte) src).getData();
+ if (dest == null) dest = new byte[length+destOffset];
+ }
+ else if (src instanceof DataBufferShort)
+ {
+ from = ((DataBufferShort) src).getData();
+ if (dest == null) dest = new short[length+destOffset];
+ }
+ else if (src instanceof DataBufferUShort)
+ {
+ from = ((DataBufferUShort) src).getData();
+ if (dest == null) dest = new short[length+destOffset];
+ }
+ else if (src instanceof DataBufferInt)
+ {
+ from = ((DataBufferInt) src).getData();
+ if (dest == null) dest = new int[length+destOffset];
+ }
+ else if (src instanceof DataBufferFloat)
+ {
+ from = ((DataBufferFloat) src).getData();
+ if (dest == null) dest = new float[length+destOffset];
+ }
+ else if (src instanceof DataBufferDouble)
+ {
+ from = ((DataBufferDouble) src).getData();
+ if (dest == null) dest = new double[length+destOffset];
+ }
+ else
+ {
+ throw new ClassCastException("Unknown data buffer type");
+ }
+
+ System.arraycopy(from, srcOffset, dest, destOffset, length);
+ return dest;
+ }
+
+ /**
+ * @param bits the width of a data element measured in bits
+ *
+ * @return the smallest data type that can store data elements of
+ * the given number of bits, without any truncation.
+ */
+ public static int smallestAppropriateTransferType(int bits)
+ {
+ if (bits <= 8)
+ {
+ return DataBuffer.TYPE_BYTE;
+ }
+ else if (bits <= 16)
+ {
+ return DataBuffer.TYPE_USHORT;
+ }
+ else if (bits <= 32)
+ {
+ return DataBuffer.TYPE_INT;
+ }
+ else
+ {
+ return DataBuffer.TYPE_UNDEFINED;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/ClasspathToolkit.java b/libjava/classpath/gnu/java/awt/ClasspathToolkit.java
new file mode 100644
index 0000000..5fb444f
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/ClasspathToolkit.java
@@ -0,0 +1,379 @@
+/* ClasspathToolkit.java -- Abstract superclass for Classpath toolkits.
+ Copyright (C) 2003, 2004 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 gnu.java.awt;
+
+import gnu.java.awt.EmbeddedWindow;
+import gnu.java.awt.peer.ClasspathFontPeer;
+import gnu.java.awt.peer.EmbeddedWindowPeer;
+import gnu.java.awt.peer.ClasspathTextLayoutPeer;
+
+import java.awt.AWTException;
+import java.awt.Dimension;
+import java.awt.DisplayMode;
+import java.awt.EventQueue;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.font.FontRenderContext;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageProducer;
+import java.awt.peer.RobotPeer;
+import java.io.File;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.AttributedString;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.imageio.spi.IIORegistry;
+
+/**
+ * An abstract superclass for Classpath toolkits.
+ *
+ * format
is
+ * not supported.
+ *
+ * @throws FontFormatException if stream
does not
+ * contain data in the expected format, or if required tables are
+ * missing from a font.
+ *
+ * @throws IOException if a problem occurs while reading in the
+ * contents of stream
.
+ */
+ public abstract Font createFont(int format, InputStream stream);
+
+
+ /**
+ * Returns an image from the specified file, which must be in a
+ * recognized format. The set of recognized image formats may vary
+ * from toolkit to toolkit.
+ *
+ * path
does not
+ * designate a valid path.
+ */
+ public Image getImage(String path)
+ {
+ try
+ {
+ return getImage(new File(path).toURL());
+ }
+ catch (MalformedURLException muex)
+ {
+ throw (IllegalArgumentException) new IllegalArgumentException(path)
+ .initCause(muex);
+ }
+ }
+
+
+ /**
+ * Loads an image from the specified URL. The image data must be in
+ * a recognized format. The set of recognized image formats may vary
+ * from toolkit to toolkit.
+ *
+ * ClasspathFontPeer
interface are required to perform
+ * the necessary synchronization.locale
is null
, the returned name is
+ * localized to the user’s default locale.
+ *
+ * @return the name of the face inside its family, or
+ * null
if the font does not provide a sub-family name.
+ */
+
+ public abstract String getSubFamilyName (Font font, Locale locale);
+
+
+ /**
+ * Implementation of {@link Font#getPSName()}
+ *
+ * @param font the font this peer is being called from. This may be
+ * useful if you are sharing peers between Font objects. Otherwise it may
+ * be ignored.
+ */
+
+ public abstract String getPostScriptName (Font font);
+
+
+ /**
+ * Implementation of {@link Font#getNumGlyphs()}
+ *
+ * @param font the font this peer is being called from. This may be
+ * useful if you are sharing peers between Font objects. Otherwise it may
+ * be ignored.
+ */
+
+ public abstract int getNumGlyphs (Font font);
+
+
+ /**
+ * Implementation of {@link Font#getMissingGlyphCode()}
+ *
+ * @param font the font this peer is being called from. This may be
+ * useful if you are sharing peers between Font objects. Otherwise it may
+ * be ignored.
+ */
+
+ public abstract int getMissingGlyphCode (Font font);
+
+
+ /**
+ * Implementation of {@link Font#getBaselineFor(char)}
+ *
+ * @param font the font this peer is being called from. This may be
+ * useful if you are sharing peers between Font objects. Otherwise it may
+ * be ignored.
+ */
+
+ public abstract byte getBaselineFor (Font font, char c);
+
+
+ /**
+ * Returns a name for the specified glyph. This is useful for
+ * generating PostScript or PDF files that embed some glyphs of a
+ * font. If the implementation follows glyph naming conventions
+ * specified by Adobe, search engines can extract the original text
+ * from the generated PostScript and PDF files.
+ *
+ * javax.print
package.
+ *
+ * post
table of format 3 and provides a
+ * mapping from glyph IDs to Unicode sequences through a
+ * Zapf
table. If the same sequence of Unicode
+ * codepoints leads to different glyphs (depending on contextual
+ * position, for example, or on typographic sophistication level),
+ * the same name would get synthesized for those glyphs. To avoid
+ * this, the font peer would have to go through the names of all
+ * glyphs, which would make this operation very inefficient with
+ * large fonts.
+ *
+ * @param font the font containing the glyph whose name is
+ * requested.
+ *
+ * @param glyphIndex the glyph whose name the caller wants to
+ * retrieve.
+ *
+ * @return the glyph name, or null
if a font does not
+ * provide glyph names.
+ */
+
+ public abstract String getGlyphName (Font font, int glyphIndex);
+
+
+ /**
+ * Implementation of {@link
+ * Font#createGlyphVector(FontRenderContext, String)}, {@link
+ * Font#createGlyphVector(FontRenderContext, char[])}, and {@link
+ * Font#createGlyphVector(FontRenderContext, CharacterIterator)}.
+ *
+ * @param font the font object that the created GlyphVector will return
+ * when it gets asked for its font. This argument is needed because the
+ * public API of {@link GlyphVector} works with {@link java.awt.Font},
+ * not with font peers.
+ */
+
+ public abstract GlyphVector createGlyphVector (Font font,
+ FontRenderContext frc,
+ CharacterIterator ci);
+
+
+ /**
+ * Implementation of {@link Font#createGlyphVector(FontRenderContext,
+ * int[])}.
+ *
+ * @param font the font object that the created GlyphVector will return
+ * when it gets asked for its font. This argument is needed because the
+ * public API of {@link GlyphVector} works with {@link java.awt.Font},
+ * not with font peers.
+ */
+
+ public abstract GlyphVector createGlyphVector (Font font,
+ FontRenderContext ctx,
+ int[] glyphCodes);
+
+
+ /**
+ * Implementation of {@link Font#layoutGlyphVector(FontRenderContext,
+ * char[], int, int, int)}.
+ *
+ * @param font the font object that the created GlyphVector will return
+ * when it gets asked for its font. This argument is needed because the
+ * public API of {@link GlyphVector} works with {@link java.awt.Font},
+ * not with font peers.
+ */
+
+ public abstract GlyphVector layoutGlyphVector (Font font,
+ FontRenderContext frc,
+ char[] chars, int start,
+ int limit, int flags);
+
+
+ /**
+ * Implementation of {@link Font#getFontMetrics()}
+ *
+ * @param font the font this peer is being called from. This may be
+ * useful if you are sharing peers between Font objects. Otherwise it may
+ * be ignored.
+ */
+
+ public abstract FontMetrics getFontMetrics (Font font);
+
+
+ /**
+ * Implementation of {@link Font#hasUniformLineMetrics()}
+ *
+ * @param font the font this peer is being called from. This may be
+ * useful if you are sharing peers between Font objects. Otherwise it may
+ * be ignored.
+ */
+
+ public abstract boolean hasUniformLineMetrics (Font font);
+
+
+ /**
+ * Implementation of {@link Font#getLineMetrics(CharacterIterator, int,
+ * int, FontRenderContext)}
+ *
+ * @param font the font this peer is being called from. This may be
+ * useful if you are sharing peers between Font objects. Otherwise it may
+ * be ignored.
+ */
+
+ public abstract LineMetrics getLineMetrics (Font font,
+ CharacterIterator ci,
+ int begin, int limit,
+ FontRenderContext rc);
+
+ /**
+ * Implementation of {@link Font#getMaxCharBounds(FontRenderContext)}
+ *
+ * @param font the font this peer is being called from. This may be
+ * useful if you are sharing peers between Font objects. Otherwise it may
+ * be ignored.
+ */
+
+ public abstract Rectangle2D getMaxCharBounds (Font font,
+ FontRenderContext rc);
+
+ /**
+ * Implementation of {@link Font#getStringBounds(CharacterIterator, int,
+ * int, FontRenderContext)}
+ *
+ * @param font the font this peer is being called from. This may be
+ * useful if you are sharing peers between Font objects. Otherwise it may
+ * be ignored.
+ */
+
+ public abstract Rectangle2D getStringBounds (Font font,
+ CharacterIterator ci,
+ int begin, int limit,
+ FontRenderContext frc);
+
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/ClasspathTextLayoutPeer.java b/libjava/classpath/gnu/java/awt/peer/ClasspathTextLayoutPeer.java
new file mode 100644
index 0000000..70df2ef
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/ClasspathTextLayoutPeer.java
@@ -0,0 +1,104 @@
+/* ClasspathTextLayoutPeer.java
+ Copyright (C) 2003 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 gnu.java.awt.peer;
+
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.font.TextHitInfo;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * @author Graydon Hoare
+ */
+
+public interface ClasspathTextLayoutPeer
+{
+ TextHitInfo getStrongCaret (TextHitInfo hit1,
+ TextHitInfo hit2);
+
+ void draw (Graphics2D g2, float x, float y);
+
+ byte getBaseline ();
+
+ boolean isLeftToRight ();
+ boolean isVertical ();
+
+ float getAdvance ();
+ float getAscent ();
+ float getDescent ();
+ float getLeading ();
+
+ int getCharacterCount ();
+ byte getCharacterLevel (int index);
+
+ float[] getBaselineOffsets ();
+ Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint);
+ Rectangle2D getBounds ();
+
+ float[] getCaretInfo (TextHitInfo hit, Rectangle2D bounds);
+ Shape getCaretShape (TextHitInfo hit, Rectangle2D bounds);
+ Shape[] getCaretShapes (int offset, Rectangle2D bounds,
+ TextLayout.CaretPolicy policy);
+
+ Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint,
+ Rectangle2D bounds);
+ int[] getLogicalRangesForVisualSelection (TextHitInfo firstEndpoint,
+ TextHitInfo secondEndpoint);
+
+ TextHitInfo getNextLeftHit (int offset, TextLayout.CaretPolicy policy);
+ TextHitInfo getNextRightHit (int offset, TextLayout.CaretPolicy policy);
+ TextHitInfo hitTestChar (float x, float y, Rectangle2D bounds);
+ TextHitInfo getVisualOtherHit (TextHitInfo hit);
+
+ float getVisibleAdvance ();
+ Shape getOutline (AffineTransform tx);
+ Shape getVisualHighlightShape (TextHitInfo firstEndpoint,
+ TextHitInfo secondEndpoint,
+ Rectangle2D bounds);
+
+ TextLayout getJustifiedLayout (float justificationWidth);
+ void handleJustify (float justificationWidth);
+
+ Object clone ();
+ int hashCode ();
+ boolean equals (ClasspathTextLayoutPeer tl);
+ String toString ();
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java
new file mode 100644
index 0000000..4c64a1d
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java
@@ -0,0 +1,47 @@
+/* EmbeddedWindowPeer.java -- Interface for window peers that may be
+ embedded into other applications
+ Copyright (C) 2003 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 gnu.java.awt.peer;
+
+import java.awt.peer.FramePeer;
+
+public interface EmbeddedWindowPeer extends FramePeer
+{
+ void embed (long handle);
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java b/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java
new file mode 100644
index 0000000..3bcaebc
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java
@@ -0,0 +1,298 @@
+/* GLightweightPeer.java --
+ Copyright (C) 2003, 2004 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 gnu.java.awt.peer;
+
+import java.awt.AWTEvent;
+import java.awt.AWTException;
+import java.awt.BufferCapabilities;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.awt.event.PaintEvent;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.VolatileImage;
+import java.awt.peer.ContainerPeer;
+import java.awt.peer.LightweightPeer;
+
+/*
+ * Another possible implementation strategy for lightweight peers is
+ * to make GLightweightPeer a placeholder class that implements
+ * LightweightPeer. Then the Component and Container classes could
+ * identify a peer as lightweight and handle it specially. The
+ * current approach is probably more clear but less efficient.
+ */
+
+/**
+ * A stub class that implements the ComponentPeer and ContainerPeer
+ * interfaces using callbacks into the Component and Container
+ * classes. GLightweightPeer allows the Component and Container
+ * classes to treat lightweight and heavyweight peers in the same way.
+ *
+ * Lightweight components are painted directly onto their parent
+ * containers through an Image object provided by the toolkit.
+ */
+public class GLightweightPeer
+ implements LightweightPeer, ContainerPeer
+{
+ private Component comp;
+
+ private Insets containerInsets;
+
+ public GLightweightPeer(Component comp)
+ {
+ this.comp = comp;
+ }
+
+ // -------- java.awt.peer.ContainerPeer implementation:
+
+ public Insets insets()
+ {
+ return getInsets ();
+ }
+
+ public Insets getInsets()
+ {
+ if (containerInsets == null)
+ containerInsets = new Insets (0,0,0,0);
+ return containerInsets;
+ }
+
+ public void beginValidate()
+ {
+ }
+
+ public void endValidate()
+ {
+ }
+
+ public void beginLayout()
+ {
+ }
+
+ public void endLayout()
+ {
+ }
+
+ public boolean isPaintPending()
+ {
+ return false;
+ }
+
+ // -------- java.awt.peer.ComponentPeer implementation:
+
+ public int checkImage(Image img, int width, int height, ImageObserver o)
+ {
+ return comp.getToolkit().checkImage(img, width, height, o);
+ }
+
+ public Image createImage(ImageProducer prod)
+ {
+ return comp.getToolkit().createImage(prod);
+ }
+
+ /* This method is not called. */
+ public Image createImage(int width, int height)
+ {
+ return null;
+ }
+
+ public void disable() {}
+
+ public void dispose() {}
+
+ public void enable() {}
+
+ public GraphicsConfiguration getGraphicsConfiguration()
+ {
+ return null;
+ }
+
+ public FontMetrics getFontMetrics(Font f)
+ {
+ return comp.getToolkit().getFontMetrics(f);
+ }
+
+ /* Returning null here tells the Component object that called us to
+ * use its parent's Graphics. */
+ public Graphics getGraphics()
+ {
+ return null;
+ }
+
+ public Point getLocationOnScreen()
+ {
+ Point parentLocation = comp.getParent().getLocationOnScreen();
+ return new Point (parentLocation.x + comp.getX(),
+ parentLocation.y + comp.getY());
+ }
+
+ public Dimension getMinimumSize()
+ {
+ return new Dimension(comp.getWidth(), comp.getHeight());
+ }
+
+ /* A lightweight component's preferred size is equivalent to its
+ * Component width and height values. */
+ public Dimension getPreferredSize()
+ {
+ return new Dimension(comp.getWidth(), comp.getHeight());
+ }
+
+ /* Returning null here tells the Component object that called us to
+ * use its parent's Toolkit. */
+ public Toolkit getToolkit()
+ {
+ return null;
+ }
+
+ public void handleEvent(AWTEvent e) {}
+
+ public void hide() {}
+
+ public boolean isFocusable()
+ {
+ return false;
+ }
+
+ public boolean isFocusTraversable()
+ {
+ return false;
+ }
+
+ public Dimension minimumSize()
+ {
+ return getMinimumSize();
+ }
+
+ public Dimension preferredSize()
+ {
+ return getPreferredSize();
+ }
+
+ public void paint(Graphics graphics) {}
+
+ public boolean prepareImage(Image img, int width, int height,
+ ImageObserver o)
+ {
+ return comp.getToolkit().prepareImage(img, width, height, o);
+ }
+
+ public void print(Graphics graphics) {}
+
+ public void repaint(long tm, int x, int y, int width, int height) {}
+
+ public void requestFocus() {}
+
+ public boolean requestFocus(Component source, boolean bool1, boolean bool2, long x)
+ {
+ return false;
+ }
+
+ public void reshape(int x, int y, int width, int height) {}
+
+ public void setBackground(Color color) {}
+
+ public void setBounds(int x, int y, int width, int height) {}
+
+ public void setCursor(Cursor cursor) {}
+
+ public void setEnabled(boolean enabled) {}
+
+ public void setEventMask(long eventMask) {}
+
+ public void setFont(Font font) {}
+
+ public void setForeground(Color color) {}
+
+ public void setVisible(boolean visible) {}
+
+ public void show() {}
+
+ public ColorModel getColorModel ()
+ {
+ return comp.getColorModel ();
+ }
+
+ public boolean isObscured()
+ {
+ return false;
+ }
+
+ public boolean canDetermineObscurity()
+ {
+ return false;
+ }
+
+ public void coalescePaintEvent(PaintEvent e) { }
+
+ public void updateCursorImmediately() { }
+
+ public VolatileImage createVolatileImage(int width, int height)
+ {
+ return null;
+ }
+
+ public boolean handlesWheelScrolling()
+ {
+ return false;
+ }
+
+ public void createBuffers(int x, BufferCapabilities capabilities)
+ throws AWTException { }
+
+ public Image getBackBuffer()
+ {
+ return null;
+ }
+
+ public void flip(BufferCapabilities.FlipContents contents) { }
+
+ public void destroyBuffers() { }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GThreadMutex.java b/libjava/classpath/gnu/java/awt/peer/gtk/GThreadMutex.java
new file mode 100644
index 0000000..e73df9e
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GThreadMutex.java
@@ -0,0 +1,109 @@
+/* GThreadMutex.java -- Implements a mutex object for glib's gthread
+ abstraction, for use with GNU Classpath's --portable-native-sync option.
+ This is used in gthread-jni.c
+
+ Copyright (C) 2004 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 gnu.java.awt.peer.gtk;
+
+/** Implements a mutex object for glib's gthread
+ abstraction, for use with GNU Classpath's --portable-native-sync option.
+ This is used in gthread-jni.c.
+
+ We use this object to implement the POSIX semantics for Mutexes. They are
+ needed are needed for the function vector that is passed to glib's
+ g_thread subpackage's initialization function.
+
+ The GThreadMutex object itself serves as the Real Lock; if code has
+ entered the monitor for this GThreadMutex object (in Java language, if
+ it's synchronized on this object) then it holds the lock that this object
+ represents.
+
+ @author Steven Augart
+ May, 2004
+
+
+*/
+
+class GThreadMutex
+{
+ /** Might "lock" be locked? Is anyone waiting
+ to get that lock? How long is the queue?
+
+ If zero, nobody holds a lock on this GThreadMutex object, and nobody is
+ trying to get one. Before someone attempts to acquire a lock on this
+ object, they must increment potentialLockers. After they release their
+ lock on this object, they must decrement potentialLockers.
+
+ Access to this field is guarded by synchronizing on the object
+ lockForPotentialLockers
.
+
+ After construction, we only access this field via JNI.
+ */
+ volatile int potentialLockers;
+
+ /** An object to synchronize to if you want to examine or modify the
+ potentialLockers
field. Only hold this lock for brief
+ moments, just long enough to check or set the value of
+ lockForPotentialLockers
.
+
+ We use this representation so that g_thread_mutex_trylock() will work
+ with the POSIX semantics. This is the only case in which you ever hold a
+ lock on lockForPotentialLockers
while trying to get another
+ lock -- if you are the mutex_trylock() implementation, and you have just
+ checked that potentialLockers
has the value zero. In that
+ case, mutex_trylock() holds the lock on lockForPotentialLockers so that
+ another thread calling mutex_trylock() or mutex_lock() won't increment
+ potentialLockers after we've checked it and before we've gained the lock
+ on the POSIX mutex. Of course, in that case the operation of gaining
+ the POSIX lock itself will succeed immediately, and once it has
+ succeeded, trylock releases lockForPotentialLockers right away,
+ incremented to 1 (one).
+
+ After construction, we only access this field via JNI.
+ */
+ Object lockForPotentialLockers;
+
+ GThreadMutex()
+ {
+ potentialLockers = 0;
+ lockForPotentialLockers = new Object();
+ }
+}
+// Local Variables:
+// c-file-style: "gnu"
+// End:
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java b/libjava/classpath/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java
new file mode 100644
index 0000000..9a1b8e3
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java
@@ -0,0 +1,303 @@
+/* GThreadNativeMethodRunner.java -- Implements pthread_create(), under
+ glib's gthread abstraction, for use with GNU Classpath's
+ --portable-native-sync option.
+ This is used by gthread-jni.c
+
+ Copyright (C) 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 gnu.java.awt.peer.gtk;
+
+import java.lang.ref.WeakReference;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/** Implements pthread_create(), under glib's gthread abstraction, for use
+ with GNU Classpath's --portable-native-sync option. This is used in
+ gthread-jni.c
+
+ Also implements a registry for threads, mapping Thread objects to small
+ integers. The registry uses weak references for threads that aren't
+ joinable, so that they will be garbage collected.
+
+ There are a number of possible alternative implementations.
+
+
+ The rest of this comment consists of an answer to a question that was
+ raised on the commit-classpath mailing list:
+
+ Mark Wielaard wrote:
+
+ > Can't we assume that jobject and gpointer are both (void *) so we don't
+ > need the int <-> Thread (global jobject ref) mapping?
+ > Maybe there are platforms where jobject and gpointer aren't the same,
+ > but I guess that is pretty unlikely.
+
+
+ I agree with you on the pointer size issues. A gpointer is a void *, so
+ it's certainly guaranteed to be at least as large as any other
+ pointer. And a jobject is implicitly an opaque pointer (in Jikes RVM, we
+ use small integers, but we coerce them into the representation of a
+ pointer).
+
+ The int <==> Thread mapping addresses a different issue. I realize that I
+ did not document this properly (two and a half lines in thread_create),
+ and the point is subtle (at least to me; took me a while to figure out).
+
+ The int => Thread mapping always returns jobjects that are local
+ references, not global ones. This is because Thread objects need to be
+ able to go away and be garbage collected after the thread they refer to
+ has died.
+
+ If we keep a global object reference to a thread, then when do we delete
+ that global object reference? We have an answer in the case of GThread
+ objects that were explicitly created with the joinable attribute. It is
+ safe for us to maintain a global reference to any joinable thread, since
+ the joinable thread must linger (even if only in a zombie state)
+ until it's explicitly joined via a g_thread_join() call. The global ref
+ could be cleaned up at that point too.
+
+ However, in the case of GThreads that were created non-joinable by
+ g_thread_create(), and in the case of Java threads that were created
+ within pure Java code (not via g_thread_create()), we don't want them to
+ linger forever, and there is no way to tell when the last reference
+ to such threads needs to expire. In the case of this application -- AWT
+ with GTK peers -- it would probably be safe anyway, since there are not
+ very many threads we create, but I was going for correctness even in the
+ case of long-running programs that might set up and tear down AWT
+ interfaces many times.
+
+ So, I duplicated the POSIX thread-ID semantics. The thread ID of a
+ non-joinable thread remains valid as long as that thread is still alive.
+ Once that thread dies, the old thread ID may be reused at any moment. And
+ that's why the array indexed by thread ID numbers is an array of weak
+ references.
+
+ That's also why the int => Thread jobject mapping function always returns
+ local references, since global references would lock the Thread in memory
+ forever.
+
+ I would dearly love there to be a cleaner solution. I dislike the
+ repeated dips from C code into Java that are necessary to look up thread
+ ID numbers. If anyone can think of one, I'm all ears.
+*/
+
+class GThreadNativeMethodRunner
+ extends Thread
+{
+ /** The C function pointer that was passed to g_thread_create().
+ Specifically, this the numeric address of an object of
+ C type "void *(*funcPtr)(void *funcArg)".
+ */
+ private final long funcPtr;
+
+ /** The argument for the function "funcPtr(funcArg)". */
+ private final long funcArg;
+
+ GThreadNativeMethodRunner(long funcPtr, long funcArg, boolean joinable)
+ {
+ this.funcPtr = funcPtr;
+ this.funcArg = funcArg;
+
+ if (joinable)
+ registerSelfJoinable();
+ }
+
+ public void run()
+ {
+ nativeRun(funcPtr, funcArg);
+ }
+
+ private native void nativeRun(long funcPtr, long funcArg);
+
+ /** THREADS is an array of threads, indexed by thread ID codes. Not sure
+ whether this is the "best" approach but it does make it O(1) to look up a
+ thread by its ID.
+
+ Zero is a valid thread ID code. Any negative number is invalid.
+
+ Possible future fixes (TODO?)
+
+ - The THREADS array will only grow. probably not a problem.
+ But we could keep count when nulling entries and shrink when we have
+ lots of nulls at the end. Probably not worth it. --mjw
+
+ - Could make this a set of Object; see the comment on "joinable" below.
+
+ The initial size of 17 is just a starting point. Any number will do,
+ including zero.
+ */
+ private static WeakReference[] threads = new WeakReference[17];
+
+ /** Used by threadToThreadID, below. Returns the registration number of
+ the newly-registered thread.
+ */
+ private static synchronized int registerThread(Thread t)
+ {
+ int i;
+
+ for (i = 0; i < threads.length; ++i)
+ {
+ WeakReference ref = threads[i];
+ if (ref == null)
+ break; // found an empty spot.
+ }
+
+ if (i == threads.length)
+ {
+ /* expand the array */
+ WeakReference[] bigger = new WeakReference[threads.length * 2];
+ System.arraycopy(threads, 0, bigger, 0, threads.length);
+ threads = bigger;
+ }
+
+ threads[i] = new WeakReference(t);
+
+ return i;
+ }
+
+ /** Look up the Thread ID # for a Thread. Assign a Thread ID # if none
+ exists. This is a general routine for handling all threads, including
+ the VM's main thread, if appropriate.
+
+
+ Runs in O(n/2) time.
+
+ We can't just issue a threadID upon thread creation. If we were to do
+ that, not all threads would have a threadID, because not all threads
+ are launched by GThreadNativeMethodRunner.
+ */
+ static synchronized int threadToThreadID(Thread t)
+ {
+ for (int i = 0; i < threads.length; ++i )
+ {
+ if (threads[i] == null)
+ continue;
+ Thread referent = (Thread) threads[i].get();
+ if (referent == null)
+ {
+ threads[i] = null; // Purge the dead WeakReference.
+ continue;
+ }
+ if (referent.equals(t))
+ return i;
+ } // for()
+
+ /* No match found. */
+ return registerThread(t);
+ }
+
+ /** @param threadID Must be a non-negative integer.
+
+ Used to return null if the thread number was out of range or if
+ the thread was unregistered. Now we throw an exception.
+
+ Possible Alternative Interface: We could go back to returning null in
+ some sort of check-free mode, so code that calls this function must
+ be prepared to get null.
+ */
+ static Thread threadIDToThread(int threadID)
+ throws IllegalArgumentException
+ {
+ if (threadID < 0)
+ throw new IllegalArgumentException("Received a negative threadID, "
+ + threadID);
+ if (threadID >= threads.length)
+ throw new IllegalArgumentException("Received a threadID (" + threadID
+ + ") higher than was"
+ + " ever issued");
+
+ /* Note: if the user is using a stale reference, things will just
+ break. We might end up getting a different thread than the one
+ expected.
+
+ TODO: Add an error-checking mode where the user's problems with threads
+ are announced. For instance, if the user asks for the thread
+ associated with a threadID that was never issued, we could print a
+ warning or even abort.
+
+ TODO: Consider optionally disabling all of the error-checking we
+ already have; it probably slows down the implementation. We could
+ just return NULL. This is just the reverse of the above TODO item.
+ */
+
+ WeakReference threadRef = threads[threadID];
+
+ if (threadRef == null)
+ throw new IllegalArgumentException("Asked to look up a stale or unissued"
+ + "threadID (" + threadID + ")" );
+
+
+ Thread referent = (Thread) threadRef.get();
+ if (referent == null)
+ throw new IllegalArgumentException ("Asked to look up a stale threadID ("
+ + threadID + ")");
+ return referent;
+ }
+
+ /** Joinable threads need a hard reference, so that they won't go away when
+ they die. That is because their thread IDs need to stay valid until the
+ thread is joined via thread_join(threadID). Joinable threads have to be
+ explicitly joined before they are allowed to go away completely.
+
+ Possible Alternative Implementation: Eliminate the Joinable set. When
+ calling getThreadIDFromThread() you know whether or not the thread
+ is joinable. So just store the Thread itself in the threads array?
+ Make that array an Object array and check with instanceof. This
+ looks cleaner and more robust to me and it saves a native -> Java
+ call. But instanceof might be expensive. --mjw
+ */
+ private static final Set joinable =
+ Collections.synchronizedSet(new HashSet());
+
+ /** Only called from the constructor. */
+ private void registerSelfJoinable()
+ {
+ joinable.add(this);
+ }
+
+ /** This method is only called from JNI, and only after we have succeeded in
+ a thread_join() operation. */
+ static void deRegisterJoinable(Thread thread)
+ {
+ joinable.remove(thread);
+ }
+}
+
+// Local Variables:
+// c-file-style: "gnu"
+// End:
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontMetrics.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontMetrics.java
new file mode 100644
index 0000000..7a439e8
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontMetrics.java
@@ -0,0 +1,134 @@
+/* GdkFontMetrics.java
+ Copyright (C) 1999, 2002, 2004 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 gnu.java.awt.peer.gtk;
+
+import gnu.java.awt.ClasspathToolkit;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Toolkit;
+
+public class GdkFontMetrics extends FontMetrics
+{
+
+ private int[] font_metrics;
+ GdkFontPeer peer;
+
+ static final int FONT_METRICS_ASCENT = 0;
+ static final int FONT_METRICS_MAX_ASCENT = 1;
+ static final int FONT_METRICS_DESCENT = 2;
+ static final int FONT_METRICS_MAX_DESCENT = 3;
+ static final int FONT_METRICS_MAX_ADVANCE = 4;
+
+ static final int TEXT_METRICS_X_BEARING = 0;
+ static final int TEXT_METRICS_Y_BEARING = 1;
+ static final int TEXT_METRICS_WIDTH = 2;
+ static final int TEXT_METRICS_HEIGHT = 3;
+ static final int TEXT_METRICS_X_ADVANCE = 4;
+ static final int TEXT_METRICS_Y_ADVANCE = 5;
+
+
+ public GdkFontMetrics (Font font)
+ {
+ super (font.getPeer() instanceof GdkFontPeer
+ ? font
+ : ((ClasspathToolkit)(Toolkit.getDefaultToolkit ()))
+ .getFont (font.getName(), font.getAttributes ()));
+
+ peer = (GdkFontPeer) this.font.getPeer();
+
+ font_metrics = new int[5];
+ double [] hires = new double[5];
+ peer.getFontMetrics (hires);
+ for (int i = 0; i < 5; ++i)
+ font_metrics[i] = (int) hires[i];
+ }
+
+ public int stringWidth (String str)
+ {
+ double [] hires = new double[6];
+ peer.getTextMetrics(str, hires);
+ return (int) hires [TEXT_METRICS_WIDTH];
+ }
+
+ public int charWidth (char ch)
+ {
+ return stringWidth (new String (new char[] { ch }));
+ }
+
+ public int charsWidth (char data[], int off, int len)
+ {
+ return stringWidth (new String (data, off, len));
+ }
+
+ /*
+ Sun's Motif implementation always returns 0 or 1 here (???), but
+ going by the X11 man pages, it seems as though we should return
+ font.ascent + font.descent.
+ */
+ public int getLeading ()
+ {
+ return 1;
+ }
+
+ public int getAscent ()
+ {
+ return font_metrics[FONT_METRICS_ASCENT];
+ }
+
+ public int getMaxAscent ()
+ {
+ return font_metrics[FONT_METRICS_MAX_ASCENT];
+ }
+
+ public int getDescent ()
+ {
+ return font_metrics[FONT_METRICS_DESCENT];
+ }
+
+ public int getMaxDescent ()
+ {
+ return font_metrics[FONT_METRICS_MAX_DESCENT];
+ }
+
+ public int getMaxAdvance ()
+ {
+ return font_metrics[FONT_METRICS_MAX_ADVANCE];
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java
new file mode 100644
index 0000000..c6d42b3
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java
@@ -0,0 +1,307 @@
+/* GdkFontPeer.java -- Implements FontPeer with GTK+
+ Copyright (C) 1999, 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 gnu.java.awt.peer.gtk;
+
+import gnu.classpath.Configuration;
+import gnu.java.awt.peer.ClasspathFontPeer;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.font.LineMetrics;
+import java.awt.geom.Rectangle2D;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+public class GdkFontPeer extends ClasspathFontPeer
+{
+ static native void initStaticState();
+ private final int native_state = GtkGenericPeer.getUniqueInteger ();
+ private static ResourceBundle bundle;
+
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary("gtkpeer");
+ }
+
+ initStaticState ();
+
+ try
+ {
+ bundle = ResourceBundle.getBundle ("gnu.java.awt.peer.gtk.font");
+ }
+ catch (Throwable ignored)
+ {
+ bundle = null;
+ }
+ }
+
+ private native void initState ();
+ private native void dispose ();
+ private native void setFont (String family, int style, int size, boolean useGraphics2D);
+
+ native void getFontMetrics(double [] metrics);
+ native void getTextMetrics(String str, double [] metrics);
+
+ protected void finalize ()
+ {
+ if (GtkToolkit.useGraphics2D ())
+ GdkGraphics2D.releasePeerGraphicsResource(this);
+ dispose ();
+ }
+
+ /*
+ * Helpers for the 3-way overloading that this class seems to suffer
+ * from. Remove them if you feel like they're a performance bottleneck,
+ * for the time being I prefer my code not be written and debugged in
+ * triplicate.
+ */
+
+ private String buildString(CharacterIterator iter)
+ {
+ StringBuffer sb = new StringBuffer();
+ for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next())
+ sb.append(c);
+ return sb.toString();
+ }
+
+ private String buildString(CharacterIterator iter, int begin, int limit)
+ {
+ StringBuffer sb = new StringBuffer();
+ int i = 0;
+ for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next(), i++)
+ {
+ if (begin <= i)
+ sb.append(c);
+ if (limit <= i)
+ break;
+ }
+ return sb.toString();
+ }
+
+ private String buildString(char[] chars, int begin, int limit)
+ {
+ return new String(chars, begin, limit - begin);
+ }
+
+ /* Public API */
+
+ public GdkFontPeer (String name, int style)
+ {
+ // All fonts get a default size of 12 if size is not specified.
+ this(name, style, 12);
+ }
+
+ public GdkFontPeer (String name, int style, int size)
+ {
+ super(name, style, size);
+ initState ();
+ setFont (this.familyName, this.style, (int)this.size,
+ GtkToolkit.useGraphics2D());
+ }
+
+ public GdkFontPeer (String name, Map attributes)
+ {
+ super(name, attributes);
+ initState ();
+ setFont (this.familyName, this.style, (int)this.size,
+ GtkToolkit.useGraphics2D());
+ }
+
+ public String getSubFamilyName(Font font, Locale locale)
+ {
+ return null;
+ }
+
+ public String getPostScriptName(Font font)
+ {
+ return null;
+ }
+
+ public boolean canDisplay (Font font, char c)
+ {
+ // FIXME: inquire with pango
+ return true;
+ }
+
+ public int canDisplayUpTo (Font font, CharacterIterator i, int start, int limit)
+ {
+ // FIXME: inquire with pango
+ return -1;
+ }
+
+ private native GdkGlyphVector getGlyphVector(String txt,
+ Font f,
+ FontRenderContext ctx);
+
+ public GlyphVector createGlyphVector (Font font,
+ FontRenderContext ctx,
+ CharacterIterator i)
+ {
+ return getGlyphVector(buildString (i), font, ctx);
+ }
+
+ public GlyphVector createGlyphVector (Font font,
+ FontRenderContext ctx,
+ int[] glyphCodes)
+ {
+ return null;
+ // return new GdkGlyphVector (font, this, ctx, glyphCodes);
+ }
+
+ public byte getBaselineFor (Font font, char c)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ protected class GdkFontLineMetrics extends LineMetrics
+ {
+ FontMetrics fm;
+ int nchars;
+
+ public GdkFontLineMetrics (FontMetrics m, int n)
+ {
+ fm = m;
+ nchars = n;
+ }
+
+ public float getAscent()
+ {
+ return (float) fm.getAscent ();
+ }
+
+ public int getBaselineIndex()
+ {
+ return Font.ROMAN_BASELINE;
+ }
+
+ public float[] getBaselineOffsets()
+ {
+ return new float[3];
+ }
+
+ public float getDescent()
+ {
+ return (float) fm.getDescent ();
+ }
+
+ public float getHeight()
+ {
+ return (float) fm.getHeight ();
+ }
+
+ public float getLeading() { return 0.f; }
+ public int getNumChars() { return nchars; }
+ public float getStrikethroughOffset() { return 0.f; }
+ public float getStrikethroughThickness() { return 0.f; }
+ public float getUnderlineOffset() { return 0.f; }
+ public float getUnderlineThickness() { return 0.f; }
+
+ }
+
+ public LineMetrics getLineMetrics (Font font, CharacterIterator ci,
+ int begin, int limit, FontRenderContext rc)
+ {
+ return new GdkFontLineMetrics (getFontMetrics (font), limit - begin);
+ }
+
+ public Rectangle2D getMaxCharBounds (Font font, FontRenderContext rc)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public int getMissingGlyphCode (Font font)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public String getGlyphName (Font font, int glyphIndex)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public int getNumGlyphs (Font font)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public Rectangle2D getStringBounds (Font font, CharacterIterator ci,
+ int begin, int limit, FontRenderContext frc)
+ {
+ GdkGlyphVector gv = getGlyphVector(buildString (ci, begin, limit), font, frc);
+ return gv.getVisualBounds();
+ }
+
+ public boolean hasUniformLineMetrics (Font font)
+ {
+ return true;
+ }
+
+ public GlyphVector layoutGlyphVector (Font font, FontRenderContext frc,
+ char[] chars, int start, int limit,
+ int flags)
+ {
+ int nchars = (limit - start) + 1;
+ char[] nc = new char[nchars];
+
+ for (int i = 0; i < nchars; ++i)
+ nc[i] = chars[start + i];
+
+ return createGlyphVector (font, frc,
+ new StringCharacterIterator (new String (nc)));
+ }
+
+ public LineMetrics getLineMetrics (Font font, String str,
+ FontRenderContext frc)
+ {
+ return new GdkFontLineMetrics (getFontMetrics (font), str.length ());
+ }
+
+ public FontMetrics getFontMetrics (Font font)
+ {
+ return new GdkFontMetrics (font);
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGlyphVector.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGlyphVector.java
new file mode 100644
index 0000000..f0ddea4
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGlyphVector.java
@@ -0,0 +1,359 @@
+/* GdkGlyphVector.java -- Glyph vector object
+ Copyright (C) 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Font;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+public class GdkGlyphVector extends GlyphVector
+{
+
+ /* We use a simple representation for glyph vectors here. Glyph i
+ * consumes 8 doubles:
+ *
+ * logical x: extents[ 10*i ]
+ * logical y: extents[ 10*i + 1 ]
+ * logical width: extents[ 10*i + 2 ]
+ * logical height: extents[ 10*i + 3 ]
+ *
+ * visual x: extents[ 10*i + 4 ]
+ * visual y: extents[ 10*i + 5 ]
+ * visual width: extents[ 10*i + 6 ]
+ * visual height: extents[ 10*i + 7 ]
+ *
+ * origin pos x: extents[ 10*i + 8 ]
+ * origin pos y: extents[ 10*i + 9 ]
+ *
+ * as well as one int, code[i], representing the glyph code in the font.
+ */
+
+ double [] extents;
+ int [] codes;
+
+ Font font;
+ FontRenderContext fontRenderContext;
+
+ Rectangle2D allLogical;
+ Rectangle2D allVisual;
+
+ public GdkGlyphVector(double[] extents, int[] codes, Font font, FontRenderContext frc)
+ {
+ this.extents = extents;
+ this.codes = codes;
+ this.font = font;
+ this.fontRenderContext = frc;
+
+ allLogical = new Rectangle2D.Double();
+ allVisual = new Rectangle2D.Double();
+
+ for (int i = 0; i < codes.length; ++i)
+ {
+ allLogical.add (new Rectangle2D.Double(extents[10*i ] + extents[10*i + 8],
+ extents[10*i + 1] + extents[10*i + 9],
+ extents[10*i + 2],
+ extents[10*i + 3]));
+
+ allVisual.add (new Rectangle2D.Double(extents[10*i + 4] + extents[10*i + 8],
+ extents[10*i + 5] + extents[10*i + 9],
+ extents[10*i + 6],
+ extents[10*i + 7]));
+ }
+ }
+
+ /*
+ geometric notes:
+
+ the FRC contains a mapping from points -> pixels.
+
+ typographics points are typically 1/72 of an inch.
+
+ pixel displays are often around 72 dpi.
+
+ so the FRC can get away with using an identity transform on a screen,
+ often. behavior is documented by sun to fall back to an identity
+ transform if the internal transformation is null.
+
+ coordinates coming up from pango are expressed as floats -- in device
+ space, so basically pixels-with-fractional-bits -- derived from their
+ storage format in pango (1024ths of pixels).
+
+ it is not clear from the javadocs whether the results of methods like
+ getGlyphPositions ought to return coordinates in device space, or
+ "point" space, or what. for now I'm returning them in device space.
+
+ */
+
+ public double[] getExtents()
+ {
+ return extents;
+ }
+
+ public int[] getCodes()
+ {
+ return codes;
+ }
+
+ public Font getFont ()
+ {
+ return font;
+ }
+
+ public FontRenderContext getFontRenderContext ()
+ {
+ return fontRenderContext;
+ }
+
+ public int getGlyphCharIndex (int glyphIndex)
+ {
+ // FIXME: currently pango does not provide glyph-by-glyph
+ // reverse mapping information, so we assume a broken 1:1
+ // glyph model here. This is plainly wrong.
+ return glyphIndex;
+ }
+
+ public int[] getGlyphCharIndices (int beginGlyphIndex,
+ int numEntries,
+ int[] codeReturn)
+ {
+ int ix[] = codeReturn;
+ if (ix == null)
+ ix = new int[numEntries];
+
+ for (int i = 0; i < numEntries; i++)
+ ix[i] = getGlyphCharIndex (beginGlyphIndex + i);
+ return ix;
+ }
+
+ public int getGlyphCode (int glyphIndex)
+ {
+ return codes[glyphIndex];
+ }
+
+ public int[] getGlyphCodes (int beginGlyphIndex, int numEntries,
+ int[] codeReturn)
+ {
+ if (codeReturn == null)
+ codeReturn = new int[numEntries];
+
+ System.arraycopy(codes, beginGlyphIndex, codeReturn, 0, numEntries);
+ return codeReturn;
+ }
+
+ public Shape getGlyphLogicalBounds (int i)
+ {
+ return new Rectangle2D.Double (extents[8*i], extents[8*i + 1],
+ extents[8*i + 2], extents[8*i + 3]);
+ }
+
+ public GlyphMetrics getGlyphMetrics (int i)
+ {
+ // FIXME: pango does not yield vertical layout information at the
+ // moment.
+
+ boolean is_horizontal = true;
+ double advanceX = extents[8*i + 2]; // "logical width" == advanceX
+ double advanceY = 0;
+
+ return new GlyphMetrics (is_horizontal,
+ (float) advanceX, (float) advanceY,
+ (Rectangle2D) getGlyphVisualBounds(i),
+ GlyphMetrics.STANDARD);
+ }
+
+ public Shape getGlyphOutline (int glyphIndex)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public Shape getGlyphOutline (int glyphIndex, float x, float y)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public Rectangle getGlyphPixelBounds (int i,
+ FontRenderContext renderFRC,
+ float x, float y)
+ {
+ return new Rectangle((int) x, (int) y,
+ (int) extents[8*i + 6], (int) extents[8*i + 7]);
+ }
+
+ public Point2D getGlyphPosition (int i)
+ {
+ return new Point2D.Double (extents[10*i + 8],
+ extents[10*i + 9]);
+ }
+
+ public float[] getGlyphPositions (int beginGlyphIndex,
+ int numEntries,
+ float[] positionReturn)
+ {
+ float fx[] = positionReturn;
+ if (fx == null)
+ fx = new float[numEntries * 2];
+
+ for (int i = 0; i < numEntries; ++i)
+ {
+ fx[2*i ] = (float) extents[10*i + 8];
+ fx[2*i + 1] = (float) extents[10*i + 9];
+ }
+ return fx;
+ }
+
+ public AffineTransform getGlyphTransform (int glyphIndex)
+ {
+ // Glyphs don't have independent transforms in these simple glyph
+ // vectors; docs specify null is an ok return here.
+ return null;
+ }
+
+ public Shape getGlyphVisualBounds (int i)
+ {
+ return new Rectangle2D.Double(extents[8*i + 4], extents[8*i + 5],
+ extents[8*i + 6], extents[8*i + 7]);
+ }
+
+ public int getLayoutFlags ()
+ {
+ return 0;
+ }
+
+ public Rectangle2D getLogicalBounds ()
+ {
+ return allLogical;
+ }
+
+ public int getNumGlyphs ()
+ {
+ return codes.length;
+ }
+
+ public Shape getOutline ()
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public Rectangle getPixelBounds (FontRenderContext renderFRC,
+ float x, float y)
+ {
+ return new Rectangle((int)x,
+ (int)y,
+ (int) allVisual.getWidth(),
+ (int) allVisual.getHeight());
+ }
+
+ public Rectangle2D getVisualBounds ()
+ {
+ return allVisual;
+ }
+
+ public void performDefaultLayout ()
+ {
+ }
+
+ public void setGlyphPosition (int i, Point2D newPos)
+ {
+ extents[8*i ] = newPos.getX();
+ extents[8*i + 1] = newPos.getY();
+
+ extents[8*i + 4] = newPos.getX();
+ extents[8*i + 5] = newPos.getY();
+ }
+
+ public void setGlyphTransform (int glyphIndex,
+ AffineTransform newTX)
+ {
+ // not yet.. maybe not ever?
+ throw new UnsupportedOperationException ();
+ }
+
+ public boolean equals(GlyphVector gv)
+ {
+ if (gv == null)
+ return false;
+
+ if (! (gv instanceof GdkGlyphVector))
+ return false;
+
+ GdkGlyphVector ggv = (GdkGlyphVector) gv;
+
+ if ((ggv.codes.length != this.codes.length)
+ || (ggv.extents.length != this.extents.length))
+ return false;
+
+ if ((ggv.font == null && this.font != null)
+ || (ggv.font != null && this.font == null)
+ || (!ggv.font.equals(this.font)))
+ return false;
+
+ if ((ggv.fontRenderContext == null && this.fontRenderContext != null)
+ || (ggv.fontRenderContext != null && this.fontRenderContext == null)
+ || (!ggv.fontRenderContext.equals(this.fontRenderContext)))
+ return false;
+
+ for (int i = 0; i < ggv.codes.length; ++i)
+ if (ggv.codes[i] != this.codes[i])
+ return false;
+
+ for (int i = 0; i < ggv.extents.length; ++i)
+ if (ggv.extents[i] != this.extents[i])
+ return false;
+
+ return true;
+ }
+
+ public GlyphJustificationInfo getGlyphJustificationInfo(int idx)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public Shape getOutline(float x, float y)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics.java
new file mode 100644
index 0000000..a125be7
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics.java
@@ -0,0 +1,388 @@
+/* GdkGraphics.java
+ Copyright (C) 1998, 1999, 2002, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.SystemColor;
+import java.awt.image.ImageObserver;
+import java.text.AttributedCharacterIterator;
+
+public class GdkGraphics extends Graphics
+{
+ private final int native_state = GtkGenericPeer.getUniqueInteger();
+
+ Color color, xorColor;
+ GtkComponentPeer component;
+ Font font;
+ Rectangle clip;
+ GtkImage image;
+
+ int xOffset = 0;
+ int yOffset = 0;
+
+ static final int GDK_COPY = 0, GDK_XOR = 2;
+
+ native void initState (GtkComponentPeer component);
+ native void initState (int width, int height);
+ native void initFromImage (GtkImage image);
+ native void copyState (GdkGraphics g);
+
+ GdkGraphics (GdkGraphics g)
+ {
+ color = g.color;
+ xorColor = g.xorColor;
+ font = g.font;
+ clip = new Rectangle (g.clip);
+ component = g.component;
+
+ copyState (g);
+ }
+
+ GdkGraphics (int width, int height)
+ {
+ initState (width, height);
+ color = Color.black;
+ clip = new Rectangle (0, 0, width, height);
+ font = new Font ("Dialog", Font.PLAIN, 12);
+ }
+
+ GdkGraphics (GtkImage image)
+ {
+ this.image = image;
+ initFromImage (image);
+ color = Color.black;
+ clip = new Rectangle (0, 0,
+ image.getWidth(null), image.getHeight(null));
+ font = new Font ("Dialog", Font.PLAIN, 12);
+ }
+
+ GdkGraphics (GtkComponentPeer component)
+ {
+ this.component = component;
+ font = component.awtComponent.getFont ();
+ color = Color.black;
+
+ if (component.isRealized ())
+ initComponentGraphics ();
+ else
+ connectSignals (component);
+ }
+
+ void initComponentGraphics ()
+ {
+ initState (component);
+ color = component.awtComponent.getForeground ();
+ Dimension d = component.awtComponent.getSize ();
+ clip = new Rectangle (0, 0, d.width, d.height);
+ }
+
+ native void connectSignals (GtkComponentPeer component);
+
+ public native void clearRect(int x, int y, int width, int height);
+
+ public void clipRect (int x, int y, int width, int height)
+ {
+ if (component != null && ! component.isRealized ())
+ return;
+
+ clip = clip.intersection (new Rectangle (x, y, width, height));
+ setClipRectangle (clip.x, clip.y, clip.width, clip.height);
+ }
+
+ public native void copyArea(int x, int y, int width, int height,
+ int dx, int dy);
+
+ public Graphics create ()
+ {
+ return new GdkGraphics (this);
+ }
+
+ public native void dispose();
+
+ public boolean drawImage (Image img, int x, int y,
+ Color bgcolor, ImageObserver observer)
+ {
+ return drawImage(img, x, y, img.getWidth(null), img.getHeight(null),
+ bgcolor, observer);
+ }
+
+ public boolean drawImage (Image img, int x, int y, ImageObserver observer)
+ {
+ return drawImage (img, x, y, null, observer);
+ }
+
+ public boolean drawImage (Image img, int x, int y, int width, int height,
+ Color bgcolor, ImageObserver observer)
+ {
+ if (img instanceof GtkImage)
+ return ((GtkImage)img).drawImage (this, x, y, width, height,
+ bgcolor, observer);
+ else
+ return (new GtkImage(img.getSource())).drawImage (this, x, y,
+ width, height,
+ bgcolor, observer);
+ }
+
+ public boolean drawImage (Image img, int x, int y, int width, int height,
+ ImageObserver observer)
+ {
+ return drawImage (img, x, y, width, height, null, observer);
+ }
+
+ public boolean drawImage (Image img, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2,
+ Color bgcolor, ImageObserver observer)
+ {
+ if (img instanceof GtkImage)
+ return ((GtkImage)img).drawImage(this, dx1, dy1, dx2, dy2,
+ sx1, sy1, sx2, sy2, bgcolor, observer);
+ else
+ return (new GtkImage(img.getSource())).drawImage(this, dx1, dy1,
+ dx2, dy2,
+ sx1, sy1, sx2, sy2,
+ bgcolor, observer);
+ }
+
+ public boolean drawImage (Image img, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2,
+ ImageObserver observer)
+ {
+ return drawImage (img, dx1, dy1, dx2, dy2,
+ sx1, sy1, sx2, sy2,
+ null, observer);
+ }
+
+ public native void drawLine(int x1, int y1, int x2, int y2);
+
+ public native void drawArc(int x, int y, int width, int height,
+ int startAngle, int arcAngle);
+ public native void fillArc(int x, int y, int width, int height,
+ int startAngle, int arcAngle);
+ public native void drawOval(int x, int y, int width, int height);
+ public native void fillOval(int x, int y, int width, int height);
+
+ public native void drawPolygon(int[] xPoints, int[] yPoints, int nPoints);
+ public native void fillPolygon(int[] xPoints, int[] yPoints, int nPoints);
+
+ public native void drawPolyline(int[] xPoints, int[] yPoints, int nPoints);
+
+ public native void drawRect(int x, int y, int width, int height);
+ public native void fillRect(int x, int y, int width, int height);
+
+ GdkFontPeer getFontPeer()
+ {
+ return (GdkFontPeer) getFont().getPeer();
+ }
+
+ native void drawString (GdkFontPeer f, String str, int x, int y);
+ public void drawString (String str, int x, int y)
+ {
+ drawString(getFontPeer(), str, x, y);
+ }
+
+
+ public void drawString (AttributedCharacterIterator ci, int x, int y)
+ {
+ throw new Error ("not implemented");
+ }
+
+ public void drawRoundRect(int x, int y, int width, int height,
+ int arcWidth, int arcHeight)
+ {
+ if (arcWidth > width)
+ arcWidth = width;
+ if (arcHeight > height)
+ arcHeight = height;
+
+ int xx = x + width - arcWidth;
+ int yy = y + height - arcHeight;
+
+ drawArc (x, y, arcWidth, arcHeight, 90, 90);
+ drawArc (xx, y, arcWidth, arcHeight, 0, 90);
+ drawArc (xx, yy, arcWidth, arcHeight, 270, 90);
+ drawArc (x, yy, arcWidth, arcHeight, 180, 90);
+
+ int y1 = y + arcHeight / 2;
+ int y2 = y + height - arcHeight / 2;
+ drawLine (x, y1, x, y2);
+ drawLine (x + width, y1, x + width, y2);
+
+ int x1 = x + arcWidth / 2;
+ int x2 = x + width - arcWidth / 2;
+ drawLine (x1, y, x2, y);
+ drawLine (x1, y + height, x2, y + height);
+ }
+
+ public void fillRoundRect (int x, int y, int width, int height,
+ int arcWidth, int arcHeight)
+ {
+ if (arcWidth > width)
+ arcWidth = width;
+ if (arcHeight > height)
+ arcHeight = height;
+
+ int xx = x + width - arcWidth;
+ int yy = y + height - arcHeight;
+
+ fillArc (x, y, arcWidth, arcHeight, 90, 90);
+ fillArc (xx, y, arcWidth, arcHeight, 0, 90);
+ fillArc (xx, yy, arcWidth, arcHeight, 270, 90);
+ fillArc (x, yy, arcWidth, arcHeight, 180, 90);
+
+ fillRect (x, y + arcHeight / 2, width, height - arcHeight + 1);
+ fillRect (x + arcWidth / 2, y, width - arcWidth + 1, height);
+ }
+
+ public Shape getClip ()
+ {
+ return getClipBounds ();
+ }
+
+ public Rectangle getClipBounds ()
+ {
+ if (clip == null)
+ return null;
+ else
+ return clip.getBounds();
+ }
+
+ public Color getColor ()
+ {
+ return color;
+ }
+
+ public Font getFont ()
+ {
+ return font;
+ }
+
+ public FontMetrics getFontMetrics (Font font)
+ {
+ return new GdkFontMetrics (font);
+ }
+
+ native void setClipRectangle (int x, int y, int width, int height);
+
+ public void setClip (int x, int y, int width, int height)
+ {
+ if ((component != null && ! component.isRealized ())
+ || clip == null)
+ return;
+
+ clip.x = x;
+ clip.y = y;
+ clip.width = width;
+ clip.height = height;
+
+ setClipRectangle (x, y, width, height);
+ }
+
+ public void setClip (Rectangle clip)
+ {
+ setClip (clip.x, clip.y, clip.width, clip.height);
+ }
+
+ public void setClip (Shape clip)
+ {
+ if (clip != null)
+ setClip(clip.getBounds());
+ }
+
+ private native void setFGColor(int red, int green, int blue);
+
+ public void setColor (Color c)
+ {
+ if (c == null)
+ color = Color.BLACK;
+ else
+ color = c;
+
+ if (xorColor == null) /* paint mode */
+ setFGColor (color.getRed (), color.getGreen (), color.getBlue ());
+ else /* xor mode */
+ setFGColor (color.getRed () ^ xorColor.getRed (),
+ color.getGreen () ^ xorColor.getGreen (),
+ color.getBlue () ^ xorColor.getBlue ());
+ }
+
+ public void setFont (Font font)
+ {
+ this.font = font;
+ }
+
+ native void setFunction (int gdk_func);
+
+ public void setPaintMode ()
+ {
+ xorColor = null;
+
+ setFunction (GDK_COPY);
+ setFGColor (color.getRed (), color.getGreen (), color.getBlue ());
+ }
+
+ public void setXORMode (Color c)
+ {
+ xorColor = c;
+
+ setFunction (GDK_XOR);
+ setFGColor (color.getRed () ^ xorColor.getRed (),
+ color.getGreen () ^ xorColor.getGreen (),
+ color.getBlue () ^ xorColor.getBlue ());
+ }
+
+ public native void translateNative(int x, int y);
+
+ public void translate (int x, int y)
+ {
+ if (component != null && ! component.isRealized ())
+ return;
+
+ clip.x -= x;
+ clip.y -= y;
+
+ translateNative (x, y);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java
new file mode 100644
index 0000000..b820317
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphics2D.java
@@ -0,0 +1,1453 @@
+/* GdkGraphics2D.java --
+ Copyright (C) 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 gnu.java.awt.peer.gtk;
+
+import gnu.classpath.Configuration;
+import gnu.java.awt.ClasspathToolkit;
+
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.TexturePaint;
+import java.awt.Toolkit;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ColorModel;
+import java.awt.image.CropImageFilter;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferInt;
+import java.awt.image.DirectColorModel;
+import java.awt.image.FilteredImageSource;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImagingOpException;
+import java.awt.image.MultiPixelPackedSampleModel;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.awt.image.renderable.RenderContext;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+
+public class GdkGraphics2D extends Graphics2D
+{
+ //////////////////////////////////////
+ ////// State Management Methods //////
+ //////////////////////////////////////
+
+ static
+ {
+ if (! Configuration.GTK_CAIRO_ENABLED)
+ throw new Error("Grahics2D not implemented. "
+ + "Cairo was not found or disabled at configure time");
+
+ if (Configuration.INIT_LOAD_LIBRARY)
+ System.loadLibrary("gtkpeer");
+
+ if (GtkToolkit.useGraphics2D())
+ initStaticState();
+ }
+
+ static native void initStaticState();
+
+ private final int native_state = GtkGenericPeer.getUniqueInteger();
+
+ // These are package-private to avoid accessor methods.
+ Paint paint;
+ Stroke stroke;
+ Color fg;
+ Color bg;
+ Shape clip;
+ AffineTransform transform;
+ private GtkComponentPeer component;
+ // This is package-private to avoid an accessor method.
+ Font font;
+ private RenderingHints hints;
+ private BufferedImage bimage;
+ private boolean pixelConversionRequired;
+ private int[] pixelBuffer;
+ // This is package-private to avoid an accessor method.
+ Composite comp;
+ private Stack stateStack;
+
+ private native void initState(GtkComponentPeer component);
+ private native void initState(int width, int height);
+ private native void initState(int[] pixes, int width, int height);
+ private native void copyState(GdkGraphics2D g);
+ public native void dispose();
+ private native void cairoSurfaceSetFilter(int filter);
+ native void connectSignals(GtkComponentPeer component);
+
+ public void finalize()
+ {
+ dispose();
+ }
+
+ public Graphics create()
+ {
+ return new GdkGraphics2D(this);
+ }
+
+ public Graphics create(int x, int y, int width, int height)
+ {
+ return new GdkGraphics2D(width, height);
+ }
+
+ GdkGraphics2D(GdkGraphics2D g)
+ {
+ paint = g.paint;
+ stroke = g.stroke;
+ setRenderingHints(g.hints);
+
+ if (g.fg.getAlpha() != -1)
+ fg = new Color(g.fg.getRed(), g.fg.getGreen(), g.fg.getBlue(),
+ g.fg.getAlpha());
+ else
+ fg = new Color(g.fg.getRGB());
+
+ if (g.bg.getAlpha() != -1)
+ bg = new Color(g.bg.getRed(), g.bg.getGreen(), g.bg.getBlue(),
+ g.bg.getAlpha());
+ else
+ bg = new Color(g.bg.getRGB());
+
+ if (g.clip == null)
+ clip = null;
+ else
+ clip = new Rectangle(g.getClipBounds());
+
+ if (g.transform == null)
+ transform = new AffineTransform();
+ else
+ transform = new AffineTransform(g.transform);
+
+ font = g.font;
+ component = g.component;
+ copyState(g);
+
+ setColor(fg);
+ setBackground(bg);
+ setPaint(paint);
+ setStroke(stroke);
+ setTransform(transform);
+ setClip(clip);
+ stateStack = new Stack();
+ }
+
+ GdkGraphics2D(int width, int height)
+ {
+ initState(width, height);
+
+ setColor(Color.black);
+ setBackground(new Color(0, 0, 0, 0));
+ setPaint(getColor());
+ setFont(new Font("SansSerif", Font.PLAIN, 12));
+ setTransform(new AffineTransform());
+ setStroke(new BasicStroke());
+ setRenderingHints(getDefaultHints());
+
+ stateStack = new Stack();
+ }
+
+ GdkGraphics2D(GtkComponentPeer component)
+ {
+ this.component = component;
+
+ if (component.isRealized())
+ initComponentGraphics2D();
+ else
+ connectSignals(component);
+ }
+
+ void initComponentGraphics2D()
+ {
+ initState(component);
+
+ setColor(component.awtComponent.getForeground());
+ setBackground(component.awtComponent.getBackground());
+ setPaint(getColor());
+ setTransform(new AffineTransform());
+ setStroke(new BasicStroke());
+ setRenderingHints(getDefaultHints());
+ setFont(new Font("SansSerif", Font.PLAIN, 12));
+
+ stateStack = new Stack();
+ }
+
+ GdkGraphics2D(BufferedImage bimage)
+ {
+ this.bimage = bimage;
+ this.pixelBuffer = findSimpleIntegerArray(bimage.getColorModel(),
+ bimage.getRaster());
+ if (this.pixelBuffer == null)
+ {
+ this.pixelBuffer = new int[bimage.getRaster().getWidth() * bimage.getRaster()
+ .getHeight()];
+ this.pixelConversionRequired = true;
+ }
+ else
+ {
+ this.pixelConversionRequired = false;
+ }
+
+ initState(this.pixelBuffer, bimage.getWidth(), bimage.getHeight());
+
+ setColor(Color.black);
+ setBackground(new Color(0, 0, 0, 0));
+ setPaint(getColor());
+ setFont(new Font("SansSerif", Font.PLAIN, 12));
+ setTransform(new AffineTransform());
+ setStroke(new BasicStroke());
+ setRenderingHints(getDefaultHints());
+
+ stateStack = new Stack();
+
+ // draw current buffered image to the pixmap associated
+ // with it, if the image is not equal to our paint buffer.
+ if (pixelConversionRequired)
+ drawImage(bimage, new AffineTransform(1, 0, 0, 1, 0, 0), bg, null);
+ }
+
+ ////////////////////////////////////
+ ////// Native Drawing Methods //////
+ ////////////////////////////////////
+
+ // GDK drawing methods
+ private native void gdkDrawDrawable(GdkGraphics2D other, int x, int y);
+
+ // drawing utility methods
+ private native void drawPixels(int[] pixels, int w, int h, int stride,
+ double[] i2u);
+ private native void setTexturePixels(int[] pixels, int w, int h, int stride);
+ private native void setGradient(double x1, double y1, double x2, double y2,
+ int r1, int g1, int b1, int a1, int r2,
+ int g2, int b2, int a2, boolean cyclic);
+
+ // simple passthroughs to cairo
+ private native void cairoSave();
+ private native void cairoRestore();
+ private native void cairoSetMatrix(double[] m);
+ private native void cairoSetOperator(int cairoOperator);
+ private native void cairoSetRGBAColor(double red, double green,
+ double blue, double alpha);
+ private native void cairoSetFillRule(int cairoFillRule);
+ private native void cairoSetLineWidth(double width);
+ private native void cairoSetLineCap(int cairoLineCap);
+ private native void cairoSetLineJoin(int cairoLineJoin);
+ private native void cairoSetDash(double[] dashes, int ndash, double offset);
+
+ private native void cairoSetMiterLimit(double limit);
+ private native void cairoNewPath();
+ private native void cairoMoveTo(double x, double y);
+ private native void cairoLineTo(double x, double y);
+ private native void cairoCurveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3);
+ private native void cairoRelMoveTo(double dx, double dy);
+ private native void cairoRelLineTo(double dx, double dy);
+ private native void cairoRelCurveTo(double dx1, double dy1, double dx2,
+ double dy2, double dx3, double dy3);
+ private native void cairoRectangle(double x, double y, double width,
+ double height);
+ private native void cairoClosePath();
+ private native void cairoStroke();
+ private native void cairoFill();
+ private native void cairoClip();
+
+ /////////////////////////////////////////////
+ ////// General Drawing Support Methods //////
+ /////////////////////////////////////////////
+
+ private class DrawState
+ {
+ private Paint paint;
+ private Stroke stroke;
+ private Color fg;
+ private Color bg;
+ private Shape clip;
+ private AffineTransform transform;
+ private Font font;
+ private Composite comp;
+
+ DrawState(GdkGraphics2D g)
+ {
+ this.paint = g.paint;
+ this.stroke = g.stroke;
+ this.fg = g.fg;
+ this.bg = g.bg;
+ this.clip = g.clip;
+ if (g.transform != null)
+ this.transform = (AffineTransform) g.transform.clone();
+ this.font = g.font;
+ this.comp = g.comp;
+ }
+
+ public void restore(GdkGraphics2D g)
+ {
+ g.paint = this.paint;
+ g.stroke = this.stroke;
+ g.fg = this.fg;
+ g.bg = this.bg;
+ g.clip = this.clip;
+ g.transform = this.transform;
+ g.font = this.font;
+ g.comp = this.comp;
+ }
+ }
+
+ private void stateSave()
+ {
+ stateStack.push(new DrawState(this));
+ cairoSave();
+ }
+
+ private void stateRestore()
+ {
+ ((DrawState) (stateStack.pop())).restore(this);
+ cairoRestore();
+ }
+
+ // Some operations (drawing rather than filling) require that their
+ // coords be shifted to land on 0.5-pixel boundaries, in order to land on
+ // "middle of pixel" coordinates and light up complete pixels.
+ private boolean shiftDrawCalls = false;
+
+ private double shifted(double coord, boolean doShift)
+ {
+ if (doShift)
+ return Math.floor(coord) + 0.5;
+ else
+ return coord;
+ }
+
+ private void walkPath(PathIterator p, boolean doShift)
+ {
+ double x = 0;
+ double y = 0;
+ double[] coords = new double[6];
+
+ cairoSetFillRule(p.getWindingRule());
+ for (; ! p.isDone(); p.next())
+ {
+ int seg = p.currentSegment(coords);
+ switch (seg)
+ {
+ case PathIterator.SEG_MOVETO:
+ x = shifted(coords[0], doShift);
+ y = shifted(coords[1], doShift);
+ cairoMoveTo(x, y);
+ break;
+ case PathIterator.SEG_LINETO:
+ x = shifted(coords[0], doShift);
+ y = shifted(coords[1], doShift);
+ cairoLineTo(x, y);
+ break;
+ case PathIterator.SEG_QUADTO:
+ // splitting a quadratic bezier into a cubic:
+ // see: http://pfaedit.sourceforge.net/bezier.html
+ double x1 = x + (2.0 / 3.0) * (shifted(coords[0], doShift) - x);
+ double y1 = y + (2.0 / 3.0) * (shifted(coords[1], doShift) - y);
+
+ double x2 = x1 + (1.0 / 3.0) * (shifted(coords[2], doShift) - x);
+ double y2 = y1 + (1.0 / 3.0) * (shifted(coords[3], doShift) - y);
+
+ x = shifted(coords[2], doShift);
+ y = shifted(coords[3], doShift);
+ cairoCurveTo(x1, y1, x2, y2, x, y);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ x = shifted(coords[4], doShift);
+ y = shifted(coords[5], doShift);
+ cairoCurveTo(shifted(coords[0], doShift),
+ shifted(coords[1], doShift),
+ shifted(coords[2], doShift),
+ shifted(coords[3], doShift), x, y);
+ break;
+ case PathIterator.SEG_CLOSE:
+ cairoClosePath();
+ break;
+ }
+ }
+ }
+
+ private Map getDefaultHints()
+ {
+ HashMap defaultHints = new HashMap();
+
+ defaultHints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
+
+ defaultHints.put(RenderingHints.KEY_STROKE_CONTROL,
+ RenderingHints.VALUE_STROKE_DEFAULT);
+
+ defaultHints.put(RenderingHints.KEY_FRACTIONALMETRICS,
+ RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
+
+ defaultHints.put(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_OFF);
+
+ defaultHints.put(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_DEFAULT);
+
+ return defaultHints;
+ }
+
+ public static int[] findSimpleIntegerArray (ColorModel cm, Raster raster)
+ {
+ if (cm == null || raster == null)
+ return null;
+
+ if (! cm.getColorSpace().isCS_sRGB())
+ return null;
+
+ if (! (cm instanceof DirectColorModel))
+ return null;
+
+ DirectColorModel dcm = (DirectColorModel) cm;
+
+ if (dcm.getRedMask() != 0x00FF0000 || dcm.getGreenMask() != 0x0000FF00
+ || dcm.getBlueMask() != 0x000000FF)
+ return null;
+
+ if (! (raster instanceof WritableRaster))
+ return null;
+
+ if (raster.getSampleModel().getDataType() != DataBuffer.TYPE_INT)
+ return null;
+
+ if (! (raster.getDataBuffer() instanceof DataBufferInt))
+ return null;
+
+ DataBufferInt db = (DataBufferInt) raster.getDataBuffer();
+
+ if (db.getNumBanks() != 1)
+ return null;
+
+ // Finally, we have determined that this is a single bank, [A]RGB-int
+ // buffer in sRGB space. It's worth checking all this, because it means
+ // that cairo can paint directly into the data buffer, which is very
+ // fast compared to all the normal copying and converting.
+
+ return db.getData();
+ }
+
+ private void updateBufferedImage()
+ {
+ if (bimage != null && pixelConversionRequired)
+ {
+ int height = bimage.getHeight();
+ int width = bimage.getWidth();
+ int index = 0;
+ for (int y = 0; y < height; ++y)
+ for (int x = 0; x < width; ++x)
+ bimage.setRGB(x, y, pixelBuffer[index++]);
+ }
+ }
+
+ private boolean drawImage(Image img, AffineTransform xform,
+ Color bgcolor, ImageObserver obs)
+ {
+ if (img == null)
+ return false;
+
+ // FIXME: I'll fix this, /Sven
+// if (img instanceof GtkOffScreenImage
+// && img.getGraphics() instanceof GdkGraphics2D
+// && (xform == null || xform.getType() == AffineTransform.TYPE_IDENTITY
+// || xform.getType() == AffineTransform.TYPE_TRANSLATION))
+// {
+// // we are being asked to flush a double buffer from Gdk
+// GdkGraphics2D g2 = (GdkGraphics2D) img.getGraphics();
+// gdkDrawDrawable(g2, (int) xform.getTranslateX(),
+// (int) xform.getTranslateY());
+
+// updateBufferedImage();
+
+// return true;
+// }
+// else
+ {
+ // In this case, xform is an AffineTransform that transforms bounding
+ // box of the specified image from image space to user space. However
+ // when we pass this transform to cairo, cairo will use this transform
+ // to map "user coordinates" to "pixel" coordinates, which is the
+ // other way around. Therefore to get the "user -> pixel" transform
+ // that cairo wants from "image -> user" transform that we currently
+ // have, we will need to invert the transformation matrix.
+ AffineTransform invertedXform = new AffineTransform();
+
+ try
+ {
+ invertedXform = xform.createInverse();
+ if (img instanceof BufferedImage)
+ {
+ // draw an image which has actually been loaded
+ // into memory fully
+ BufferedImage b = (BufferedImage) img;
+ return drawRaster(b.getColorModel(), b.getTile(0, 0),
+ invertedXform, bgcolor);
+ }
+ else
+ return this.drawImage(GdkPixbufDecoder.createBufferedImage(img
+ .getSource()),
+ xform, bgcolor, obs);
+ }
+ catch (NoninvertibleTransformException e)
+ {
+ throw new ImagingOpException("Unable to invert transform "
+ + xform.toString());
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////
+ ////// Implementation of Graphics2D Methods //////
+ //////////////////////////////////////////////////
+
+ public void draw(Shape s)
+ {
+ if (stroke != null && ! (stroke instanceof BasicStroke))
+ {
+ fill(stroke.createStrokedShape(s));
+ return;
+ }
+
+ cairoNewPath();
+
+ if (s instanceof Rectangle2D)
+ {
+ Rectangle2D r = (Rectangle2D) s;
+ cairoRectangle(shifted(r.getX(), shiftDrawCalls),
+ shifted(r.getY(), shiftDrawCalls), r.getWidth(),
+ r.getHeight());
+ }
+ else
+ walkPath(s.getPathIterator(null), shiftDrawCalls);
+ cairoStroke();
+
+ updateBufferedImage();
+ }
+
+ public void fill(Shape s)
+ {
+ cairoNewPath();
+ if (s instanceof Rectangle2D)
+ {
+ Rectangle2D r = (Rectangle2D) s;
+ cairoRectangle(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+ else
+ walkPath(s.getPathIterator(null), false);
+
+ cairoFill();
+
+ updateBufferedImage();
+ }
+
+ public void clip(Shape s)
+ {
+ // update it
+ if (clip == null || s == null)
+ clip = s;
+ else if (s instanceof Rectangle2D && clip instanceof Rectangle2D)
+ {
+ Rectangle2D r = (Rectangle2D) s;
+ Rectangle2D curr = (Rectangle2D) clip;
+ clip = curr.createIntersection(r);
+ }
+ else
+ throw new UnsupportedOperationException();
+
+ // draw it
+ if (clip != null)
+ {
+ cairoNewPath();
+ if (clip instanceof Rectangle2D)
+ {
+ Rectangle2D r = (Rectangle2D) clip;
+ cairoRectangle(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+ else
+ walkPath(clip.getPathIterator(null), false);
+
+ // cairoClosePath ();
+ cairoClip();
+ }
+ }
+
+ public Paint getPaint()
+ {
+ return paint;
+ }
+
+ public AffineTransform getTransform()
+ {
+ return (AffineTransform) transform.clone();
+ }
+
+ public void setPaint(Paint p)
+ {
+ if (paint == null)
+ return;
+
+ paint = p;
+ if (paint instanceof Color)
+ {
+ setColor((Color) paint);
+ }
+ else if (paint instanceof TexturePaint)
+ {
+ TexturePaint tp = (TexturePaint) paint;
+ BufferedImage img = tp.getImage();
+
+ // map the image to the anchor rectangle
+ int width = (int) tp.getAnchorRect().getWidth();
+ int height = (int) tp.getAnchorRect().getHeight();
+
+ double scaleX = width / (double) img.getWidth();
+ double scaleY = width / (double) img.getHeight();
+
+ AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0);
+ AffineTransformOp op = new AffineTransformOp(at, getRenderingHints());
+ BufferedImage texture = op.filter(img, null);
+ int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width);
+ setTexturePixels(pixels, width, height, width);
+ }
+ else if (paint instanceof GradientPaint)
+ {
+ GradientPaint gp = (GradientPaint) paint;
+ Point2D p1 = gp.getPoint1();
+ Point2D p2 = gp.getPoint2();
+ Color c1 = gp.getColor1();
+ Color c2 = gp.getColor2();
+ setGradient(p1.getX(), p1.getY(), p2.getX(), p2.getY(), c1.getRed(),
+ c1.getGreen(), c1.getBlue(), c1.getAlpha(), c2.getRed(),
+ c2.getGreen(), c2.getBlue(), c2.getAlpha(), gp.isCyclic());
+ }
+ else
+ throw new java.lang.UnsupportedOperationException();
+ }
+
+ public void setTransform(AffineTransform tx)
+ {
+ transform = tx;
+ if (transform != null)
+ {
+ double[] m = new double[6];
+ transform.getMatrix(m);
+ cairoSetMatrix(m);
+ }
+ }
+
+ public void transform(AffineTransform tx)
+ {
+ if (transform == null)
+ transform = new AffineTransform(tx);
+ else
+ transform.concatenate(tx);
+ setTransform(transform);
+ if (clip != null)
+ {
+ // FIXME: this should actuall try to transform the shape
+ // rather than degrade to bounds.
+ Rectangle2D r = clip.getBounds2D();
+ double[] coords = new double[]
+ {
+ r.getX(), r.getY(), r.getX() + r.getWidth(),
+ r.getY() + r.getHeight()
+ };
+ try
+ {
+ tx.createInverse().transform(coords, 0, coords, 0, 2);
+ r.setRect(coords[0], coords[1], coords[2] - coords[0],
+ coords[3] - coords[1]);
+ clip = r;
+ }
+ catch (java.awt.geom.NoninvertibleTransformException e)
+ {
+ }
+ }
+ }
+
+ public void rotate(double theta)
+ {
+ transform(AffineTransform.getRotateInstance(theta));
+ }
+
+ public void rotate(double theta, double x, double y)
+ {
+ transform(AffineTransform.getRotateInstance(theta, x, y));
+ }
+
+ public void scale(double sx, double sy)
+ {
+ transform(AffineTransform.getScaleInstance(sx, sy));
+ }
+
+ public void translate(double tx, double ty)
+ {
+ transform(AffineTransform.getTranslateInstance(tx, ty));
+ }
+
+ public void translate(int x, int y)
+ {
+ translate((double) x, (double) y);
+ }
+
+ public void shear(double shearX, double shearY)
+ {
+ transform(AffineTransform.getShearInstance(shearX, shearY));
+ }
+
+ public Stroke getStroke()
+ {
+ return stroke;
+ }
+
+ public void setStroke(Stroke st)
+ {
+ stroke = st;
+ if (stroke instanceof BasicStroke)
+ {
+ BasicStroke bs = (BasicStroke) stroke;
+ cairoSetLineCap(bs.getEndCap());
+ cairoSetLineWidth(bs.getLineWidth());
+ cairoSetLineJoin(bs.getLineJoin());
+ cairoSetMiterLimit(bs.getMiterLimit());
+ float[] dashes = bs.getDashArray();
+ if (dashes != null)
+ {
+ double[] double_dashes = new double[dashes.length];
+ for (int i = 0; i < dashes.length; i++)
+ double_dashes[i] = dashes[i];
+ cairoSetDash(double_dashes, double_dashes.length,
+ (double) bs.getDashPhase());
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////
+ ////// Implementation of Graphics Methods //////
+ ////////////////////////////////////////////////
+
+ public void setPaintMode()
+ {
+ setComposite(java.awt.AlphaComposite.SrcOver);
+ }
+
+ public void setXORMode(Color c)
+ {
+ setComposite(new gnu.java.awt.BitwiseXORComposite(c));
+ }
+
+ public void setColor(Color c)
+ {
+ if (c == null)
+ c = Color.BLACK;
+
+ fg = c;
+ paint = c;
+ cairoSetRGBAColor(fg.getRed() / 255.0, fg.getGreen() / 255.0,
+ fg.getBlue() / 255.0, fg.getAlpha() / 255.0);
+ }
+
+ public Color getColor()
+ {
+ return fg;
+ }
+
+ public void clipRect(int x, int y, int width, int height)
+ {
+ clip(new Rectangle(x, y, width, height));
+ }
+
+ public Shape getClip()
+ {
+ return clip.getBounds2D(); //getClipInDevSpace();
+ }
+
+ public Rectangle getClipBounds()
+ {
+ if (clip == null)
+ return null;
+ else
+ return clip.getBounds();
+ }
+
+ protected Rectangle2D getClipInDevSpace()
+ {
+ Rectangle2D uclip = clip.getBounds2D();
+ if (transform == null)
+ return uclip;
+ else
+ {
+ Point2D pos = transform.transform(new Point2D.Double(uclip.getX(),
+ uclip.getY()),
+ (Point2D) null);
+ Point2D extent = transform.deltaTransform(new Point2D.Double(uclip
+ .getWidth(),
+ uclip
+ .getHeight()),
+ (Point2D) null);
+ return new Rectangle2D.Double(pos.getX(), pos.getY(), extent.getX(),
+ extent.getY());
+ }
+ }
+
+ public void setClip(int x, int y, int width, int height)
+ {
+ setClip(new Rectangle2D.Double((double) x, (double) y, (double) width,
+ (double) height));
+ }
+
+ public void setClip(Shape s)
+ {
+ clip = s;
+ if (s != null)
+ {
+ cairoNewPath();
+ if (s instanceof Rectangle2D)
+ {
+ Rectangle2D r = (Rectangle2D) s;
+ cairoRectangle(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+ else
+ walkPath(s.getPathIterator(null), false);
+
+ // cairoClosePath ();
+ cairoClip();
+ }
+ }
+
+ private static BasicStroke draw3DRectStroke = new BasicStroke();
+
+ public void draw3DRect(int x, int y, int width, int height, boolean raised)
+ {
+ Stroke tmp = stroke;
+ setStroke(draw3DRectStroke);
+ super.draw3DRect(x, y, width, height, raised);
+ setStroke(tmp);
+ updateBufferedImage();
+ }
+
+ public void fill3DRect(int x, int y, int width, int height, boolean raised)
+ {
+ Stroke tmp = stroke;
+ setStroke(draw3DRectStroke);
+ super.fill3DRect(x, y, width, height, raised);
+ setStroke(tmp);
+ updateBufferedImage();
+ }
+
+ public void drawRect(int x, int y, int width, int height)
+ {
+ draw(new Rectangle(x, y, width, height));
+ }
+
+ public void fillRect(int x, int y, int width, int height)
+ {
+ cairoNewPath();
+ cairoRectangle(x, y, width, height);
+ cairoFill();
+ }
+
+ public void clearRect(int x, int y, int width, int height)
+ {
+ cairoSetRGBAColor(bg.getRed() / 255.0, bg.getGreen() / 255.0,
+ bg.getBlue() / 255.0, 1.0);
+ cairoNewPath();
+ cairoRectangle(x, y, width, height);
+ cairoFill();
+ setColor(fg);
+
+ updateBufferedImage();
+ }
+
+ public void setBackground(Color c)
+ {
+ bg = c;
+ }
+
+ public Color getBackground()
+ {
+ return bg;
+ }
+
+ private void doPolygon(int[] xPoints, int[] yPoints, int nPoints,
+ boolean close, boolean fill)
+ {
+ if (nPoints < 1)
+ return;
+ GeneralPath gp = new GeneralPath(PathIterator.WIND_EVEN_ODD);
+ gp.moveTo((float) xPoints[0], (float) yPoints[0]);
+ for (int i = 1; i < nPoints; i++)
+ gp.lineTo((float) xPoints[i], (float) yPoints[i]);
+
+ if (close)
+ gp.closePath();
+
+ Shape sh = gp;
+ if (fill == false && stroke != null && ! (stroke instanceof BasicStroke))
+ {
+ sh = stroke.createStrokedShape(gp);
+ fill = true;
+ }
+
+ if (fill)
+ fill(sh);
+ else
+ draw(sh);
+ }
+
+ public void drawLine(int x1, int y1, int x2, int y2)
+ {
+ int[] xp = new int[2];
+ int[] yp = new int[2];
+
+ xp[0] = x1;
+ xp[1] = x2;
+ yp[0] = y1;
+ yp[1] = y2;
+
+ doPolygon(xp, yp, 2, false, false);
+ }
+
+ public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
+ {
+ doPolygon(xPoints, yPoints, nPoints, true, true);
+ }
+
+ public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
+ {
+ doPolygon(xPoints, yPoints, nPoints, true, false);
+ }
+
+ public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
+ {
+ doPolygon(xPoints, yPoints, nPoints, false, false);
+ }
+
+ private boolean drawRaster(ColorModel cm, Raster r,
+ AffineTransform imageToUser, Color bgcolor)
+ {
+ if (r == null)
+ return false;
+
+ SampleModel sm = r.getSampleModel();
+ DataBuffer db = r.getDataBuffer();
+
+ if (db == null || sm == null)
+ return false;
+
+ if (cm == null)
+ cm = ColorModel.getRGBdefault();
+
+ double[] i2u = new double[6];
+ if (imageToUser != null)
+ imageToUser.getMatrix(i2u);
+ else
+ {
+ i2u[0] = 1;
+ i2u[1] = 0;
+ i2u[2] = 0;
+ i2u[3] = 1;
+ i2u[4] = 0;
+ i2u[5] = 0;
+ }
+
+ int[] pixels = findSimpleIntegerArray(cm, r);
+
+ if (pixels == null)
+ {
+ // FIXME: I don't think this code will work correctly with a non-RGB
+ // MultiPixelPackedSampleModel. Although this entire method should
+ // probably be rewritten to better utilize Cairo's different supported
+ // data formats.
+ if (sm instanceof MultiPixelPackedSampleModel)
+ {
+ pixels = r.getPixels(0, 0, r.getWidth(), r.getHeight(), pixels);
+ for (int i = 0; i < pixels.length; i++)
+ pixels[i] = cm.getRGB(pixels[i]);
+ }
+ else
+ {
+ pixels = new int[r.getWidth() * r.getHeight()];
+ for (int i = 0; i < pixels.length; i++)
+ pixels[i] = cm.getRGB(db.getElem(i));
+ }
+ }
+
+ // Change all transparent pixels in the image to the specified bgcolor,
+ // or (if there's no alpha) fill in an alpha channel so that it paints
+ // correctly.
+ if (cm.hasAlpha())
+ {
+ if (bgcolor != null && cm.hasAlpha())
+ for (int i = 0; i < pixels.length; i++)
+ {
+ if (cm.getAlpha(pixels[i]) == 0)
+ pixels[i] = bgcolor.getRGB();
+ }
+ }
+ else
+ for (int i = 0; i < pixels.length; i++)
+ pixels[i] |= 0xFF000000;
+
+ drawPixels(pixels, r.getWidth(), r.getHeight(), r.getWidth(), i2u);
+
+ updateBufferedImage();
+
+ return true;
+ }
+
+ public void drawRenderedImage(RenderedImage image, AffineTransform xform)
+ {
+ drawRaster(image.getColorModel(), image.getData(), xform, bg);
+ }
+
+ public void drawRenderableImage(RenderableImage image, AffineTransform xform)
+ {
+ drawRenderedImage(image.createRendering(new RenderContext(xform)), xform);
+ }
+
+ public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs)
+ {
+ return drawImage(img, xform, bg, obs);
+ }
+
+ public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y)
+ {
+ Image filtered = op.filter(image, null);
+ drawImage(filtered, new AffineTransform(1f, 0f, 0f, 1f, x, y), bg, null);
+ }
+
+ public boolean drawImage(Image img, int x, int y, ImageObserver observer)
+ {
+ return drawImage(img, new AffineTransform(1f, 0f, 0f, 1f, x, y), bg,
+ observer);
+ }
+
+ ///////////////////////////////////////////////
+ ////// Unimplemented Stubs and Overloads //////
+ ///////////////////////////////////////////////
+
+ public boolean hit(Rectangle rect, Shape text, boolean onStroke)
+ {
+ throw new java.lang.UnsupportedOperationException();
+ }
+
+ public GraphicsConfiguration getDeviceConfiguration()
+ {
+ throw new java.lang.UnsupportedOperationException();
+ }
+
+ public void setComposite(Composite comp)
+ {
+ this.comp = comp;
+
+ if (comp instanceof AlphaComposite)
+ {
+ AlphaComposite a = (AlphaComposite) comp;
+ cairoSetOperator(a.getRule());
+ Color c = getColor();
+ setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(),
+ (int) (a.getAlpha() * ((float) c.getAlpha()))));
+ }
+ else
+ throw new java.lang.UnsupportedOperationException();
+ }
+
+ public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
+ {
+ hints.put(hintKey, hintValue);
+
+ if (hintKey.equals(RenderingHints.KEY_INTERPOLATION)
+ || hintKey.equals(RenderingHints.KEY_ALPHA_INTERPOLATION))
+ {
+ if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
+ cairoSurfaceSetFilter(0);
+
+ else if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
+ cairoSurfaceSetFilter(1);
+
+ else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
+ cairoSurfaceSetFilter(2);
+
+ else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
+ cairoSurfaceSetFilter(3);
+
+ else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
+ cairoSurfaceSetFilter(4);
+ }
+
+ shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
+ || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
+ }
+
+ public Object getRenderingHint(RenderingHints.Key hintKey)
+ {
+ return hints.get(hintKey);
+ }
+
+ public void setRenderingHints(Map hints)
+ {
+ this.hints = new RenderingHints(getDefaultHints());
+ this.hints.add(new RenderingHints(hints));
+
+ if (hints.containsKey(RenderingHints.KEY_INTERPOLATION))
+ {
+ if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
+ cairoSurfaceSetFilter(0);
+
+ else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
+ cairoSurfaceSetFilter(1);
+ }
+
+ if (hints.containsKey(RenderingHints.KEY_ALPHA_INTERPOLATION))
+ {
+ if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
+ cairoSurfaceSetFilter(2);
+
+ else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
+ cairoSurfaceSetFilter(3);
+
+ else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
+ cairoSurfaceSetFilter(4);
+ }
+
+ shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
+ || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
+ }
+
+ public void addRenderingHints(Map hints)
+ {
+ this.hints.add(new RenderingHints(hints));
+ }
+
+ public RenderingHints getRenderingHints()
+ {
+ return hints;
+ }
+
+ public Composite getComposite()
+ {
+ if (comp == null)
+ return AlphaComposite.SrcOver;
+ else
+ return comp;
+ }
+
+ public FontRenderContext getFontRenderContext()
+ {
+ return new FontRenderContext(transform, true, true);
+ }
+
+ public void copyArea(int x, int y, int width, int height, int dx, int dy)
+ {
+ throw new java.lang.UnsupportedOperationException();
+ }
+
+ public void drawArc(int x, int y, int width, int height, int startAngle,
+ int arcAngle)
+ {
+ draw(new Arc2D.Double((double) x, (double) y, (double) width,
+ (double) height, (double) startAngle,
+ (double) arcAngle, Arc2D.OPEN));
+ }
+
+ public boolean drawImage(Image img, int x, int y, Color bgcolor,
+ ImageObserver observer)
+ {
+ return drawImage(img, x, y, img.getWidth(observer),
+ img.getHeight(observer), bgcolor, observer);
+ }
+
+ public boolean drawImage(Image img, int x, int y, int width, int height,
+ Color bgcolor, ImageObserver observer)
+ {
+ double scaleX = width / (double) img.getWidth(observer);
+ double scaleY = height / (double) img.getHeight(observer);
+
+ return drawImage(img, new AffineTransform(scaleX, 0f, 0f, scaleY, x, y),
+ bgcolor, observer);
+ }
+
+ public boolean drawImage(Image img, int x, int y, int width, int height,
+ ImageObserver observer)
+ {
+ return drawImage(img, x, y, width, height, bg, observer);
+ }
+
+ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2, Color bgcolor,
+ ImageObserver observer)
+ {
+ if (img == null)
+ return false;
+
+ Image subImage;
+
+ int sourceWidth = sx2 - sx1;
+ int sourceHeight = sy2 - sy1;
+
+ int destWidth = dx2 - dx1;
+ int destHeight = dy2 - dy1;
+
+ double scaleX = destWidth / (double) sourceWidth;
+ double scaleY = destHeight / (double) sourceHeight;
+
+ // Get the subimage of the source enclosed in the
+ // rectangle specified by sx1, sy1, sx2, sy2
+
+ if (img instanceof BufferedImage)
+ {
+ BufferedImage b = (BufferedImage) img;
+ subImage = b.getSubimage(sx1, sy1, sx2, sy2);
+ }
+ else
+ {
+ // FIXME: This code currently doesn't work. Null Pointer
+ // exception is thrown in this case. This happens
+ // because img.getSource() always returns null, since source gets
+ // never initialized when it is created with the help of
+ // createImage(int width, int height).
+ CropImageFilter filter = new CropImageFilter(sx1, sx2, sx2, sy2);
+ FilteredImageSource src = new FilteredImageSource(img.getSource(),
+ filter);
+
+ subImage = Toolkit.getDefaultToolkit().createImage(src);
+ }
+
+ return drawImage(subImage,
+ new AffineTransform(scaleX, 0, 0, scaleY, dx1, dy1),
+ bgcolor, observer);
+ }
+
+ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2,
+ ImageObserver observer)
+ {
+ return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bg, observer);
+ }
+
+ public void drawOval(int x, int y, int width, int height)
+ {
+ drawArc(x, y, width, height, 0, 360);
+ }
+
+ public void drawRoundRect(int x, int y, int width, int height, int arcWidth,
+ int arcHeight)
+ {
+ if (arcWidth > width)
+ arcWidth = width;
+ if (arcHeight > height)
+ arcHeight = height;
+
+ int xx = x + width - arcWidth;
+ int yy = y + height - arcHeight;
+
+ drawArc(x, y, arcWidth, arcHeight, 90, 90);
+ drawArc(xx, y, arcWidth, arcHeight, 0, 90);
+ drawArc(xx, yy, arcWidth, arcHeight, 270, 90);
+ drawArc(x, yy, arcWidth, arcHeight, 180, 90);
+
+ int y1 = y + arcHeight / 2;
+ int y2 = y + height - arcHeight / 2;
+ drawLine(x, y1, x, y2);
+ drawLine(x + width, y1, x + width, y2);
+
+ int x1 = x + arcWidth / 2;
+ int x2 = x + width - arcWidth / 2;
+ drawLine(x1, y, x2, y);
+ drawLine(x1, y + height, x2, y + height);
+ }
+
+ // these are the most accelerated painting paths
+ native void cairoDrawGlyphVector(GdkFontPeer font,
+ float x, float y, int n,
+ int[] codes, float[] positions);
+
+ native void cairoDrawGdkTextLayout(GdkTextLayout gl,
+ float x, float y);
+
+ GdkFontPeer getFontPeer()
+ {
+ return (GdkFontPeer) getFont().getPeer();
+ }
+
+ public void drawGdkTextLayout(GdkTextLayout gl, float x, float y)
+ {
+ cairoDrawGdkTextLayout (gl, x, y);
+ updateBufferedImage ();
+ }
+
+ public void drawString(String str, float x, float y)
+ {
+ drawGlyphVector(getFont().createGlyphVector(null, str), x, y);
+ updateBufferedImage ();
+ }
+
+ public void drawString(String str, int x, int y)
+ {
+ drawString (str, (float) x, (float) y);
+ }
+
+ public void drawString(AttributedCharacterIterator ci, int x, int y)
+ {
+ drawString (ci, (float) x, (float) y);
+ }
+
+ public void drawGlyphVector(GlyphVector gv, float x, float y)
+ {
+ int n = gv.getNumGlyphs ();
+ int[] codes = gv.getGlyphCodes (0, n, null);
+ float[] positions = gv.getGlyphPositions (0, n, null);
+
+ setFont (gv.getFont ());
+ cairoDrawGlyphVector (getFontPeer(), x, y, n, codes, positions);
+ updateBufferedImage ();
+ }
+
+ public void drawString(AttributedCharacterIterator ci, float x, float y)
+ {
+ GlyphVector gv = getFont().createGlyphVector(getFontRenderContext(), ci);
+ drawGlyphVector(gv, x, y);
+ }
+
+ public void fillArc(int x, int y, int width, int height, int startAngle,
+ int arcAngle)
+ {
+ fill(new Arc2D.Double((double) x, (double) y, (double) width,
+ (double) height, (double) startAngle,
+ (double) arcAngle, Arc2D.OPEN));
+ }
+
+ public void fillOval(int x, int y, int width, int height)
+ {
+ fillArc(x, y, width, height, 0, 360);
+ }
+
+ public void fillRoundRect(int x, int y, int width, int height, int arcWidth,
+ int arcHeight)
+ {
+ if (arcWidth > width)
+ arcWidth = width;
+ if (arcHeight > height)
+ arcHeight = height;
+
+ int xx = x + width - arcWidth;
+ int yy = y + height - arcHeight;
+
+ fillArc(x, y, arcWidth, arcHeight, 90, 90);
+ fillArc(xx, y, arcWidth, arcHeight, 0, 90);
+ fillArc(xx, yy, arcWidth, arcHeight, 270, 90);
+ fillArc(x, yy, arcWidth, arcHeight, 180, 90);
+
+ fillRect(x, y + arcHeight / 2, width, height - arcHeight + 1);
+ fillRect(x + arcWidth / 2, y, width - arcWidth + 1, height);
+ }
+
+ public Font getFont()
+ {
+ if (font == null)
+ return new Font("SansSerif", Font.PLAIN, 12);
+ return font;
+ }
+
+ // Until such time as pango is happy to talk directly to cairo, we
+ // actually need to redirect some calls from the GtkFontPeer and
+ // GtkFontMetrics into the drawing kit and ask cairo ourselves.
+
+ static native void releasePeerGraphicsResource(GdkFontPeer f);
+
+ public FontMetrics getFontMetrics()
+ {
+ return getFontMetrics(getFont());
+ }
+
+ public FontMetrics getFontMetrics(Font f)
+ {
+ // the reason we go via the toolkit here is to try to get
+ // a cached object. the toolkit keeps such a cache.
+ return Toolkit.getDefaultToolkit().getFontMetrics(f);
+ }
+
+ public void setFont(Font f)
+ {
+ if (f.getPeer() instanceof GdkFontPeer)
+ font = f;
+ else
+ font =
+ ((ClasspathToolkit)(Toolkit.getDefaultToolkit()))
+ .getFont(f.getName(), f.getAttributes());
+ }
+
+ public String toString()
+ {
+ return (getClass().getName()
+ + "[font=" + getFont().toString()
+ + ",color=" + fg.toString()
+ + "]");
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java
new file mode 100644
index 0000000..bfad87a
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java
@@ -0,0 +1,138 @@
+/* GdkGraphicsConfiguration.java -- describes characteristics of graphics
+ Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation
+
+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 gnu.java.awt.peer.gtk;
+
+import java.awt.BufferCapabilities;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.ImageCapabilities;
+import java.awt.Rectangle;
+
+import java.awt.geom.AffineTransform;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.VolatileImage;
+
+public class GdkGraphicsConfiguration
+ extends GraphicsConfiguration
+{
+ GdkScreenGraphicsDevice gdkScreenGraphicsDevice;
+ ColorModel cm;
+ Rectangle bounds;
+
+ public GtkToolkit getToolkit()
+ {
+ return gdkScreenGraphicsDevice.getToolkit();
+ }
+
+ public GdkGraphicsConfiguration(GdkScreenGraphicsDevice dev)
+ {
+ this.gdkScreenGraphicsDevice = dev;
+ cm = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getColorModel();
+ bounds = getToolkit().getBounds();
+ }
+
+ public GraphicsDevice getDevice()
+ {
+ return gdkScreenGraphicsDevice;
+ }
+
+ public BufferedImage createCompatibleImage(int w, int h)
+ {
+ return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
+ }
+
+ public BufferedImage createCompatibleImage(int w, int h,
+ int transparency)
+ {
+ return createCompatibleImage(w, h);
+ }
+
+ public VolatileImage createCompatibleVolatileImage(int w, int h)
+ {
+ return new GtkVolatileImage(w, h);
+ }
+
+ public VolatileImage createCompatibleVolatileImage(int w, int h,
+ ImageCapabilities caps)
+ throws java.awt.AWTException
+ {
+ return new GtkVolatileImage(w, h, caps);
+ }
+
+ public ColorModel getColorModel()
+ {
+ return cm;
+ }
+
+ public ColorModel getColorModel(int transparency)
+ {
+ return getColorModel();
+ }
+
+ public AffineTransform getDefaultTransform()
+ {
+ // FIXME: extract the GDK DPI information here.
+ return new AffineTransform();
+ }
+
+ public AffineTransform getNormalizingTransform()
+ {
+ // FIXME: extract the GDK DPI information here.
+ return new AffineTransform();
+ }
+
+ public Rectangle getBounds()
+ {
+ return bounds;
+ }
+
+ public BufferCapabilities getBufferCapabilities()
+ {
+ return new BufferCapabilities(getImageCapabilities(),
+ getImageCapabilities(),
+ BufferCapabilities.FlipContents.UNDEFINED);
+ }
+
+ public ImageCapabilities getImageCapabilities()
+ {
+ return new ImageCapabilities(false);
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java
new file mode 100644
index 0000000..4f9d1c2
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java
@@ -0,0 +1,107 @@
+/* GdkGraphicsEnvironment.java -- information about the graphics environment
+ Copyright (C) 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.HeadlessException;
+import java.awt.image.BufferedImage;
+import java.util.Locale;
+
+public class GdkGraphicsEnvironment extends GraphicsEnvironment
+{
+ GtkToolkit gtkToolkit;
+
+ public GtkToolkit getToolkit()
+ {
+ return gtkToolkit;
+ }
+
+ public GdkGraphicsEnvironment (GtkToolkit tk)
+ {
+ super();
+ gtkToolkit = tk;
+ }
+
+ public GraphicsDevice[] getScreenDevices ()
+ {
+ // FIXME: Support multiple screens, since GDK can.
+ return new GraphicsDevice[] { new GdkScreenGraphicsDevice (this) };
+ }
+
+ public GraphicsDevice getDefaultScreenDevice ()
+ {
+ if (GraphicsEnvironment.isHeadless ())
+ throw new HeadlessException ();
+
+ return new GdkScreenGraphicsDevice (this);
+ }
+
+ public Graphics2D createGraphics (BufferedImage image)
+ {
+ return new GdkGraphics2D (image);
+ }
+
+ private native int nativeGetNumFontFamilies();
+ private native void nativeGetFontFamilies(String[] family_names);
+
+ public Font[] getAllFonts ()
+ {
+ throw new java.lang.UnsupportedOperationException ();
+ }
+
+ public String[] getAvailableFontFamilyNames ()
+ {
+ String[] family_names;
+ int array_size;
+
+ array_size = nativeGetNumFontFamilies();
+ family_names = new String[array_size];
+
+ nativeGetFontFamilies(family_names);
+ return family_names;
+ }
+
+ public String[] getAvailableFontFamilyNames (Locale l)
+ {
+ throw new java.lang.UnsupportedOperationException ();
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java
new file mode 100644
index 0000000..57d5a36
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java
@@ -0,0 +1,681 @@
+/* GdkPixbufDecoder.java -- Image data decoding object
+ Copyright (C) 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 gnu.java.awt.peer.gtk;
+
+import gnu.classpath.Configuration;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageProducer;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Vector;
+
+import javax.imageio.IIOImage;
+import javax.imageio.ImageReadParam;
+import javax.imageio.ImageReader;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.IIORegistry;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.ImageOutputStream;
+
+public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder
+{
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary("gtkpeer");
+ }
+ initStaticState ();
+ }
+
+ static native void initStaticState();
+ private final int native_state = GtkGenericPeer.getUniqueInteger ();
+
+ // initState() has been called, but pumpDone() has not yet been called.
+ private boolean needsClose = false;
+
+ // the current set of ImageConsumers for this decoder
+ Vector curr;
+
+ // interface to GdkPixbuf
+ native void initState ();
+ native void pumpBytes (byte[] bytes, int len) throws IOException;
+ native void pumpDone () throws IOException;
+ native void finish (boolean needsClose);
+ static native void streamImage(int[] bytes, String format, int width, int height, boolean hasAlpha, DataOutput sink);
+
+ // gdk-pixbuf provids data in RGBA format
+ static final ColorModel cm = new DirectColorModel (32, 0xff000000,
+ 0x00ff0000,
+ 0x0000ff00,
+ 0x000000ff);
+ public GdkPixbufDecoder (InputStream in)
+ {
+ super (in);
+ }
+
+ public GdkPixbufDecoder (String filename)
+ {
+ super (filename);
+ }
+
+ public GdkPixbufDecoder (URL url)
+ {
+ super (url);
+ }
+
+ public GdkPixbufDecoder (byte[] imagedata, int imageoffset, int imagelength)
+ {
+ super (imagedata, imageoffset, imagelength);
+ }
+
+ // called back by native side
+ void areaPrepared (int width, int height)
+ {
+
+ if (curr == null)
+ return;
+
+ for (int i = 0; i < curr.size (); i++)
+ {
+ ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
+ ic.setDimensions (width, height);
+ ic.setColorModel (cm);
+ ic.setHints (ImageConsumer.RANDOMPIXELORDER);
+ }
+ }
+
+ // called back by native side
+ void areaUpdated (int x, int y, int width, int height,
+ int pixels[], int scansize)
+ {
+ if (curr == null)
+ return;
+
+ for (int i = 0; i < curr.size (); i++)
+ {
+ ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
+ ic.setPixels (x, y, width, height, cm, pixels, 0, scansize);
+ }
+ }
+
+ // called from an async image loader of one sort or another, this method
+ // repeatedly reads bytes from the input stream and passes them through a
+ // GdkPixbufLoader using the native method pumpBytes. pumpBytes in turn
+ // decodes the image data and calls back areaPrepared and areaUpdated on
+ // this object, feeding back decoded pixel blocks, which we pass to each
+ // of the ImageConsumers in the provided Vector.
+
+ public void produce (Vector v, InputStream is) throws IOException
+ {
+ curr = v;
+
+ byte bytes[] = new byte[4096];
+ int len = 0;
+ initState();
+ needsClose = true;
+ while ((len = is.read (bytes)) != -1)
+ pumpBytes (bytes, len);
+ pumpDone();
+ needsClose = false;
+
+ for (int i = 0; i < curr.size (); i++)
+ {
+ ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
+ ic.imageComplete (ImageConsumer.STATICIMAGEDONE);
+ }
+
+ curr = null;
+ }
+
+ public void finalize()
+ {
+ finish(needsClose);
+ }
+
+
+ public static class ImageFormatSpec
+ {
+ public String name;
+ public boolean writable = false;
+ public ArrayList mimeTypes = new ArrayList();
+ public ArrayList extensions = new ArrayList();
+
+ public ImageFormatSpec(String name, boolean writable)
+ {
+ this.name = name;
+ this.writable = writable;
+ }
+
+ public synchronized void addMimeType(String m)
+ {
+ mimeTypes.add(m);
+ }
+
+ public synchronized void addExtension(String e)
+ {
+ extensions.add(e);
+ }
+ }
+
+ static ArrayList imageFormatSpecs;
+
+ public static ImageFormatSpec registerFormat(String name, boolean writable)
+ {
+ ImageFormatSpec ifs = new ImageFormatSpec(name, writable);
+ synchronized(GdkPixbufDecoder.class)
+ {
+ if (imageFormatSpecs == null)
+ imageFormatSpecs = new ArrayList();
+ imageFormatSpecs.add(ifs);
+ }
+ return ifs;
+ }
+
+ static String[] getFormatNames(boolean writable)
+ {
+ ArrayList names = new ArrayList();
+ synchronized (imageFormatSpecs)
+ {
+ Iterator i = imageFormatSpecs.iterator();
+ while (i.hasNext())
+ {
+ ImageFormatSpec ifs = (ImageFormatSpec) i.next();
+ if (writable && !ifs.writable)
+ continue;
+ names.add(ifs.name);
+
+ /*
+ * In order to make the filtering code work, we need to register
+ * this type under every "format name" likely to be used as a synonym.
+ * This generally means "all the extensions people might use".
+ */
+
+ Iterator j = ifs.extensions.iterator();
+ while (j.hasNext())
+ names.add((String) j.next());
+ }
+ }
+ Object[] objs = names.toArray();
+ String[] strings = new String[objs.length];
+ for (int i = 0; i < objs.length; ++i)
+ strings[i] = (String) objs[i];
+ return strings;
+ }
+
+ static String[] getFormatExtensions(boolean writable)
+ {
+ ArrayList extensions = new ArrayList();
+ synchronized (imageFormatSpecs)
+ {
+ Iterator i = imageFormatSpecs.iterator();
+ while (i.hasNext())
+ {
+ ImageFormatSpec ifs = (ImageFormatSpec) i.next();
+ if (writable && !ifs.writable)
+ continue;
+ Iterator j = ifs.extensions.iterator();
+ while (j.hasNext())
+ extensions.add((String) j.next());
+ }
+ }
+ Object[] objs = extensions.toArray();
+ String[] strings = new String[objs.length];
+ for (int i = 0; i < objs.length; ++i)
+ strings[i] = (String) objs[i];
+ return strings;
+ }
+
+ static String[] getFormatMimeTypes(boolean writable)
+ {
+ ArrayList mimeTypes = new ArrayList();
+ synchronized (imageFormatSpecs)
+ {
+ Iterator i = imageFormatSpecs.iterator();
+ while (i.hasNext())
+ {
+ ImageFormatSpec ifs = (ImageFormatSpec) i.next();
+ if (writable && !ifs.writable)
+ continue;
+ Iterator j = ifs.mimeTypes.iterator();
+ while (j.hasNext())
+ mimeTypes.add((String) j.next());
+ }
+ }
+ Object[] objs = mimeTypes.toArray();
+ String[] strings = new String[objs.length];
+ for (int i = 0; i < objs.length; ++i)
+ strings[i] = (String) objs[i];
+ return strings;
+ }
+
+
+ static String findFormatName(Object ext, boolean needWritable)
+ {
+ if (ext == null)
+ throw new IllegalArgumentException("extension is null");
+
+ if (!(ext instanceof String))
+ throw new IllegalArgumentException("extension is not a string");
+
+ String str = (String) ext;
+
+ Iterator i = imageFormatSpecs.iterator();
+ while (i.hasNext())
+ {
+ ImageFormatSpec ifs = (ImageFormatSpec) i.next();
+
+ if (needWritable && !ifs.writable)
+ continue;
+
+ if (ifs.name.equals(str))
+ return str;
+
+ Iterator j = ifs.extensions.iterator();
+ while (j.hasNext())
+ {
+ String extension = (String)j.next();
+ if (extension.equals(str))
+ return ifs.name;
+ }
+
+ j = ifs.mimeTypes.iterator();
+ while (j.hasNext())
+ {
+ String mimeType = (String)j.next();
+ if (mimeType.equals(str))
+ return ifs.name;
+ }
+ }
+ throw new IllegalArgumentException("unknown extension '" + str + "'");
+ }
+
+ private static GdkPixbufReaderSpi readerSpi;
+ private static GdkPixbufWriterSpi writerSpi;
+
+ public static synchronized GdkPixbufReaderSpi getReaderSpi()
+ {
+ if (readerSpi == null)
+ readerSpi = new GdkPixbufReaderSpi();
+ return readerSpi;
+ }
+
+ public static synchronized GdkPixbufWriterSpi getWriterSpi()
+ {
+ if (writerSpi == null)
+ writerSpi = new GdkPixbufWriterSpi();
+ return writerSpi;
+ }
+
+ public static void registerSpis(IIORegistry reg)
+ {
+ reg.registerServiceProvider(getReaderSpi(), ImageReaderSpi.class);
+ reg.registerServiceProvider(getWriterSpi(), ImageWriterSpi.class);
+ }
+
+ public static class GdkPixbufWriterSpi extends ImageWriterSpi
+ {
+ public GdkPixbufWriterSpi()
+ {
+ super("GdkPixbuf", "2.x",
+ GdkPixbufDecoder.getFormatNames(true),
+ GdkPixbufDecoder.getFormatExtensions(true),
+ GdkPixbufDecoder.getFormatMimeTypes(true),
+ "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriter",
+ new Class[] { ImageOutputStream.class },
+ new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReaderSpi" },
+ false, null, null, null, null,
+ false, null, null, null, null);
+ }
+
+ public boolean canEncodeImage(ImageTypeSpecifier ts)
+ {
+ return true;
+ }
+
+ public ImageWriter createWriterInstance(Object ext)
+ {
+ return new GdkPixbufWriter(this, ext);
+ }
+
+ public String getDescription(java.util.Locale loc)
+ {
+ return "GdkPixbuf Writer SPI";
+ }
+
+ }
+
+ public static class GdkPixbufReaderSpi extends ImageReaderSpi
+ {
+ public GdkPixbufReaderSpi()
+ {
+ super("GdkPixbuf", "2.x",
+ GdkPixbufDecoder.getFormatNames(false),
+ GdkPixbufDecoder.getFormatExtensions(false),
+ GdkPixbufDecoder.getFormatMimeTypes(false),
+ "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReader",
+ new Class[] { ImageInputStream.class },
+ new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriterSpi" },
+ false, null, null, null, null,
+ false, null, null, null, null);
+ }
+
+ public boolean canDecodeInput(Object obj)
+ {
+ return true;
+ }
+
+ public ImageReader createReaderInstance(Object ext)
+ {
+ return new GdkPixbufReader(this, ext);
+ }
+
+ public String getDescription(Locale loc)
+ {
+ return "GdkPixbuf Reader SPI";
+ }
+ }
+
+ private static class GdkPixbufWriter
+ extends ImageWriter
+ {
+ String ext;
+ public GdkPixbufWriter(GdkPixbufWriterSpi ownerSpi, Object ext)
+ {
+ super(ownerSpi);
+ this.ext = findFormatName(ext, true);
+ }
+
+ public IIOMetadata convertImageMetadata (IIOMetadata inData,
+ ImageTypeSpecifier imageType,
+ ImageWriteParam param)
+ {
+ return null;
+ }
+
+ public IIOMetadata convertStreamMetadata (IIOMetadata inData,
+ ImageWriteParam param)
+ {
+ return null;
+ }
+
+ public IIOMetadata getDefaultImageMetadata (ImageTypeSpecifier imageType,
+ ImageWriteParam param)
+ {
+ return null;
+ }
+
+ public IIOMetadata getDefaultStreamMetadata (ImageWriteParam param)
+ {
+ return null;
+ }
+
+ public void write (IIOMetadata streamMetadata, IIOImage i, ImageWriteParam param)
+ throws IOException
+ {
+ RenderedImage image = i.getRenderedImage();
+ Raster ras = image.getData();
+ int width = ras.getWidth();
+ int height = ras.getHeight();
+ ColorModel model = image.getColorModel();
+ int[] pixels = GdkGraphics2D.findSimpleIntegerArray (image.getColorModel(), ras);
+
+ if (pixels == null)
+ {
+ BufferedImage img = new BufferedImage(width, height,
+ (model != null && model.hasAlpha() ?
+ BufferedImage.TYPE_INT_ARGB
+ : BufferedImage.TYPE_INT_RGB));
+ int[] pix = new int[4];
+ for (int y = 0; y < height; ++y)
+ for (int x = 0; x < width; ++x)
+ img.setRGB(x, y, model.getRGB(ras.getPixel(x, y, pix)));
+ pixels = GdkGraphics2D.findSimpleIntegerArray (img.getColorModel(),
+ img.getRaster());
+ model = img.getColorModel();
+ }
+
+ processImageStarted(1);
+ streamImage(pixels, this.ext, width, height, model.hasAlpha(),
+ (DataOutput) this.getOutput());
+ processImageComplete();
+ }
+ }
+
+ private static class GdkPixbufReader
+ extends ImageReader
+ implements ImageConsumer
+ {
+ // ImageConsumer parts
+ GdkPixbufDecoder dec;
+ BufferedImage bufferedImage;
+ ColorModel defaultModel;
+ int width;
+ int height;
+ String ext;
+
+ public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext)
+ {
+ super(ownerSpi);
+ this.ext = findFormatName(ext, false);
+ }
+
+ public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext, GdkPixbufDecoder d)
+ {
+ this(ownerSpi, ext);
+ dec = d;
+ }
+
+ public void setDimensions(int w, int h)
+ {
+ processImageStarted(1);
+ width = w;
+ height = h;
+ }
+
+ public void setProperties(Hashtable props) {}
+
+ public void setColorModel(ColorModel model)
+ {
+ defaultModel = model;
+ }
+
+ public void setHints(int flags) {}
+
+ public void setPixels(int x, int y, int w, int h,
+ ColorModel model, byte[] pixels,
+ int offset, int scansize)
+ {
+ }
+
+ public void setPixels(int x, int y, int w, int h,
+ ColorModel model, int[] pixels,
+ int offset, int scansize)
+ {
+ if (model == null)
+ model = defaultModel;
+
+ if (bufferedImage == null)
+ {
+ bufferedImage = new BufferedImage (width, height, (model != null && model.hasAlpha() ?
+ BufferedImage.TYPE_INT_ARGB
+ : BufferedImage.TYPE_INT_RGB));
+ }
+
+ int pixels2[];
+ if (model != null)
+ {
+ pixels2 = new int[pixels.length];
+ for (int yy = 0; yy < h; yy++)
+ for (int xx = 0; xx < w; xx++)
+ {
+ int i = yy * scansize + xx;
+ pixels2[i] = model.getRGB (pixels[i]);
+ }
+ }
+ else
+ pixels2 = pixels;
+
+ bufferedImage.setRGB (x, y, w, h, pixels2, offset, scansize);
+ processImageProgress(y / (height == 0 ? 1 : height));
+ }
+
+ public void imageComplete(int status)
+ {
+ processImageComplete();
+ }
+
+ public BufferedImage getBufferedImage()
+ {
+ if (bufferedImage == null && dec != null)
+ dec.startProduction (this);
+ return bufferedImage;
+ }
+
+ // ImageReader parts
+
+ public int getNumImages(boolean allowSearch)
+ throws IOException
+ {
+ return 1;
+ }
+
+ public IIOMetadata getImageMetadata(int i)
+ {
+ return null;
+ }
+
+ public IIOMetadata getStreamMetadata()
+ throws IOException
+ {
+ return null;
+ }
+
+ public Iterator getImageTypes(int imageIndex)
+ throws IOException
+ {
+ BufferedImage img = getBufferedImage();
+ Vector vec = new Vector();
+ vec.add(new ImageTypeSpecifier(img));
+ return vec.iterator();
+ }
+
+ public int getHeight(int imageIndex)
+ throws IOException
+ {
+ return getBufferedImage().getHeight();
+ }
+
+ public int getWidth(int imageIndex)
+ throws IOException
+ {
+ return getBufferedImage().getWidth();
+ }
+
+ public void setInput(Object input,
+ boolean seekForwardOnly,
+ boolean ignoreMetadata)
+ {
+ super.setInput(input, seekForwardOnly, ignoreMetadata);
+ dec = new GdkPixbufDecoder((InputStream) getInput());
+ }
+
+ public BufferedImage read(int imageIndex, ImageReadParam param)
+ throws IOException
+ {
+ return getBufferedImage ();
+ }
+ }
+
+ // remaining helper class and static method is a convenience for the Gtk
+ // peers, for loading a BufferedImage in off a disk file without going
+ // through the whole imageio system.
+
+ public static BufferedImage createBufferedImage (String filename)
+ {
+ GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(),
+ "png", // reader auto-detects, doesn't matter
+ new GdkPixbufDecoder (filename));
+ return r.getBufferedImage ();
+ }
+
+ public static BufferedImage createBufferedImage (URL u)
+ {
+ GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(),
+ "png", // reader auto-detects, doesn't matter
+ new GdkPixbufDecoder (u));
+ return r.getBufferedImage ();
+ }
+
+ public static BufferedImage createBufferedImage (byte[] imagedata, int imageoffset,
+ int imagelength)
+ {
+ GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(),
+ "png", // reader auto-detects, doesn't matter
+ new GdkPixbufDecoder (imagedata,
+ imageoffset,
+ imagelength));
+ return r.getBufferedImage ();
+ }
+
+ public static BufferedImage createBufferedImage (ImageProducer producer)
+ {
+ GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(), "png" /* ignored */, null);
+ producer.startProduction(r);
+ return r.getBufferedImage ();
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java
new file mode 100644
index 0000000..6d0218d
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java
@@ -0,0 +1,94 @@
+/* GdkRobot.java -- an XTest implementation of RobotPeer
+ Copyright (C) 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 gnu.java.awt.peer.gtk;
+
+import java.awt.AWTException;
+import java.awt.GraphicsDevice;
+import java.awt.Rectangle;
+import java.awt.image.ColorModel;
+import java.awt.image.DirectColorModel;
+import java.awt.peer.RobotPeer;
+
+/**
+ * Implements the RobotPeer interface using the XTest extension.
+ *
+ * @author Thomas Fitzsimmons
+ */
+public class GdkRobotPeer implements RobotPeer
+{
+ // gdk-pixbuf provides data in RGBA format
+ static final ColorModel cm = new DirectColorModel (32, 0xff000000,
+ 0x00ff0000,
+ 0x0000ff00,
+ 0x000000ff);
+
+ public GdkRobotPeer (GraphicsDevice screen) throws AWTException
+ {
+ // FIXME: make use of screen parameter when GraphicsDevice is
+ // implemented.
+ if (!initXTest ())
+ throw new AWTException ("XTest extension not supported");
+ }
+
+ native boolean initXTest ();
+
+ // RobotPeer methods
+ public native void mouseMove (int x, int y);
+ public native void mousePress (int buttons);
+ public native void mouseRelease (int buttons);
+ public native void mouseWheel (int wheelAmt);
+ public native void keyPress (int keycode);
+ public native void keyRelease (int keycode);
+ native int[] nativeGetRGBPixels (int x, int y, int width, int height);
+
+ public int getRGBPixel (int x, int y)
+ {
+ return cm.getRGB (nativeGetRGBPixels (x, y, 1, 1)[0]);
+ }
+
+ public int[] getRGBPixels (Rectangle r)
+ {
+ int[] gdk_pixels = nativeGetRGBPixels (r.x, r.y, r.width, r.height);
+ int[] pixels = new int[r.width * r.height];
+
+ for (int i = 0; i < r.width * r.height; i++)
+ pixels[i] = cm.getRGB (gdk_pixels[i]);
+
+ return pixels;
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java
new file mode 100644
index 0000000..2bf9d23
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java
@@ -0,0 +1,115 @@
+/* GdkScreenGraphicsDevice.java -- information about a screen device
+ Copyright (C) 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Dimension;
+import java.awt.DisplayMode;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+
+public class GdkScreenGraphicsDevice extends GraphicsDevice
+{
+ GdkGraphicsEnvironment env;
+
+ public GtkToolkit getToolkit()
+ {
+ return env.getToolkit();
+ }
+
+ public GdkScreenGraphicsDevice (GdkGraphicsEnvironment e)
+ {
+ super ();
+ env = e;
+ }
+
+ public int getType ()
+ {
+ return GraphicsDevice.TYPE_RASTER_SCREEN;
+ }
+
+ public String getIDstring ()
+ {
+ // FIXME: query X for this string
+ return "default GDK device ID string";
+ }
+
+ public GraphicsConfiguration[] getConfigurations ()
+ {
+ // FIXME: query X for the list of possible configurations
+ return new GraphicsConfiguration [] { new GdkGraphicsConfiguration(this) };
+ }
+
+ public GraphicsConfiguration getDefaultConfiguration ()
+ {
+
+ // FIXME: query X for default configuration
+ return new GdkGraphicsConfiguration(this);
+ }
+
+
+ /**
+ * Returns the current display mode of this device, or null if unknown.
+ *
+ * @return the current display mode
+ * @see #setDisplayMode(DisplayMode)
+ * @see #getDisplayModes()
+ * @since 1.4
+ */
+ public DisplayMode getDisplayMode()
+ {
+ // determine display mode
+ Dimension dim = getToolkit().getScreenSize();
+ DisplayMode mode = new DisplayMode(dim.width, dim.height, 0,
+ DisplayMode.REFRESH_RATE_UNKNOWN);
+ return mode;
+ }
+
+ /**
+ * This device does not yet support fullscreen exclusive mode, so this
+ * returns false
.
+ *
+ * @return false
+ * @since 1.4
+ */
+ public boolean isFullScreenSupported()
+ {
+ return false;
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkTextLayout.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkTextLayout.java
new file mode 100644
index 0000000..ff51745
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkTextLayout.java
@@ -0,0 +1,434 @@
+/* GdkTextLayout.java
+ Copyright (C) 2003, 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 gnu.java.awt.peer.gtk;
+
+import gnu.classpath.Configuration;
+import gnu.java.awt.peer.ClasspathTextLayoutPeer;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphMetrics;
+import java.awt.font.GlyphVector;
+import java.awt.font.TextAttribute;
+import java.awt.font.TextHitInfo;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Rectangle2D;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.text.CharacterIterator;
+
+/**
+ * This is an implementation of the text layout peer interface which
+ * delegates all the hard work to pango.
+ *
+ * @author Graydon Hoare
+ */
+
+public class GdkTextLayout
+ implements ClasspathTextLayoutPeer
+{
+ // native side, plumbing, etc.
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary("gtkpeer");
+ }
+ initStaticState ();
+ }
+ private native void setText(String str);
+ private native void getExtents(double[] inkExtents,
+ double[] logExtents);
+ private native void indexToPos(int idx, double[] pos);
+ private native void initState ();
+ private native void dispose ();
+ static native void initStaticState();
+ private final int native_state = GtkGenericPeer.getUniqueInteger ();
+ protected void finalize ()
+ {
+ dispose ();
+ }
+
+ // we hold on to these to make sure we can render when presented
+ // with non-GdkGraphics2D paint targets
+ private AttributedString attributedString;
+ private FontRenderContext fontRenderContext;
+
+ public GdkTextLayout(AttributedString str, FontRenderContext frc)
+ {
+ initState();
+ attributedString = str;
+ fontRenderContext = frc;
+ }
+
+ protected class CharacterIteratorProxy
+ implements CharacterIterator
+ {
+ public CharacterIterator target;
+ public int begin;
+ public int limit;
+ public int index;
+
+ public CharacterIteratorProxy (CharacterIterator ci)
+ {
+ target = ci;
+ }
+
+ public int getBeginIndex ()
+ {
+ return begin;
+ }
+
+ public int getEndIndex ()
+ {
+ return limit;
+ }
+
+ public int getIndex ()
+ {
+ return index;
+ }
+
+ public char setIndex (int idx)
+ throws IllegalArgumentException
+ {
+ if (idx < begin || idx >= limit)
+ throw new IllegalArgumentException ();
+ char ch = target.setIndex (idx);
+ index = idx;
+ return ch;
+ }
+
+ public char first ()
+ {
+ int save = target.getIndex ();
+ char ch = target.setIndex (begin);
+ target.setIndex (save);
+ return ch;
+ }
+
+ public char last ()
+ {
+ if (begin == limit)
+ return this.first ();
+
+ int save = target.getIndex ();
+ char ch = target.setIndex (limit - 1);
+ target.setIndex (save);
+ return ch;
+ }
+
+ public char current ()
+ {
+ return target.current();
+ }
+
+ public char next ()
+ {
+ if (index >= limit - 1)
+ return CharacterIterator.DONE;
+ else
+ {
+ index++;
+ return target.next();
+ }
+ }
+
+ public char previous ()
+ {
+ if (index <= begin)
+ return CharacterIterator.DONE;
+ else
+ {
+ index--;
+ return target.previous ();
+ }
+ }
+
+ public Object clone ()
+ {
+ CharacterIteratorProxy cip = new CharacterIteratorProxy (this.target);
+ cip.begin = this.begin;
+ cip.limit = this.limit;
+ cip.index = this.index;
+ return cip;
+ }
+
+ }
+
+
+ // public side
+
+ public void draw (Graphics2D g2, float x, float y)
+ {
+ if (g2 instanceof GdkGraphics2D)
+ {
+ // we share pango structures directly with GdkGraphics2D
+ // when legal
+ GdkGraphics2D gg2 = (GdkGraphics2D) g2;
+ gg2.drawGdkTextLayout(this, x, y);
+ }
+ else
+ {
+ // falling back to a rather tedious layout algorithm when
+ // not legal
+ AttributedCharacterIterator ci = attributedString.getIterator ();
+ CharacterIteratorProxy proxy = new CharacterIteratorProxy (ci);
+ Font defFont = g2.getFont ();
+
+ /* Note: this implementation currently only interprets FONT text
+ * attributes. There is a reasonable argument to be made for some
+ * attributes being interpreted out here, where we have control of the
+ * Graphics2D and can construct or derive new fonts, and some
+ * attributes being interpreted by the GlyphVector itself. So far, for
+ * all attributes except FONT we do neither.
+ */
+
+ for (char c = ci.first ();
+ c != CharacterIterator.DONE;
+ c = ci.next ())
+ {
+ proxy.begin = ci.getIndex ();
+ proxy.limit = ci.getRunLimit(TextAttribute.FONT);
+ if (proxy.limit <= proxy.begin)
+ continue;
+
+ proxy.index = proxy.begin;
+
+ Object fnt = ci.getAttribute(TextAttribute.FONT);
+ GlyphVector gv;
+ if (fnt instanceof Font)
+ gv = ((Font)fnt).createGlyphVector (fontRenderContext, proxy);
+ else
+ gv = defFont.createGlyphVector (fontRenderContext, proxy);
+
+ g2.drawGlyphVector (gv, x, y);
+
+ int n = gv.getNumGlyphs ();
+ for (int i = 0; i < n; ++i)
+ {
+ GlyphMetrics gm = gv.getGlyphMetrics (i);
+ if (gm.getAdvanceX() == gm.getAdvance ())
+ x += gm.getAdvanceX ();
+ else
+ y += gm.getAdvanceY ();
+ }
+ }
+ }
+ }
+
+ public TextHitInfo getStrongCaret (TextHitInfo hit1,
+ TextHitInfo hit2)
+ {
+ throw new Error("not implemented");
+ }
+
+ public byte getBaseline ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public boolean isLeftToRight ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public boolean isVertical ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public float getAdvance ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public float getAscent ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public float getDescent ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public float getLeading ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public int getCharacterCount ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public byte getCharacterLevel (int index)
+ {
+ throw new Error("not implemented");
+ }
+
+ public float[] getBaselineOffsets ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint)
+ {
+ throw new Error("not implemented");
+ }
+
+ public Rectangle2D getBounds ()
+ {
+ double[] inkExtents = new double[4];
+ double[] logExtents = new double[4];
+ getExtents(inkExtents, logExtents);
+ return new Rectangle2D.Double(logExtents[0], logExtents[1],
+ logExtents[2], logExtents[3]);
+ }
+
+ public float[] getCaretInfo (TextHitInfo hit, Rectangle2D bounds)
+ {
+ throw new Error("not implemented");
+ }
+
+ public Shape getCaretShape (TextHitInfo hit, Rectangle2D bounds)
+ {
+ throw new Error("not implemented");
+ }
+
+ public Shape[] getCaretShapes (int offset, Rectangle2D bounds,
+ TextLayout.CaretPolicy policy)
+ {
+ throw new Error("not implemented");
+ }
+
+ public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint,
+ Rectangle2D bounds)
+ {
+ AffineTransform at = new AffineTransform();
+ GeneralPath gp = new GeneralPath();
+ double [] rect = new double[4];
+ Rectangle2D tmp = new Rectangle2D.Double();
+ for (int i = firstEndpoint; i <= secondEndpoint; ++i)
+ {
+ indexToPos(i, rect);
+ tmp.setRect(rect[0], rect[1], rect[2], rect[3]);
+ Rectangle2D.intersect(tmp, bounds, tmp);
+ gp.append(tmp.getPathIterator(at), false);
+ }
+ return gp;
+ }
+
+ public int[] getLogicalRangesForVisualSelection (TextHitInfo firstEndpoint,
+ TextHitInfo secondEndpoint)
+ {
+ throw new Error("not implemented");
+ }
+
+ public TextHitInfo getNextLeftHit (int offset, TextLayout.CaretPolicy policy)
+ {
+ throw new Error("not implemented");
+ }
+ public TextHitInfo getNextRightHit (int offset, TextLayout.CaretPolicy policy)
+ {
+ throw new Error("not implemented");
+ }
+ public TextHitInfo hitTestChar (float x, float y, Rectangle2D bounds)
+ {
+ throw new Error("not implemented");
+ }
+ public TextHitInfo getVisualOtherHit (TextHitInfo hit)
+ {
+ throw new Error("not implemented");
+ }
+
+ public float getVisibleAdvance ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public Shape getOutline (AffineTransform tx)
+ {
+ throw new Error("not implemented");
+ }
+
+ public Shape getVisualHighlightShape (TextHitInfo firstEndpoint,
+ TextHitInfo secondEndpoint,
+ Rectangle2D bounds)
+ {
+ throw new Error("not implemented");
+ }
+
+
+ public TextLayout getJustifiedLayout (float justificationWidth)
+ {
+ throw new Error("not implemented");
+ }
+
+ public void handleJustify (float justificationWidth)
+ {
+ throw new Error("not implemented");
+ }
+
+ public Object clone ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public int hashCode ()
+ {
+ throw new Error("not implemented");
+ }
+
+ public boolean equals (ClasspathTextLayoutPeer tl)
+ {
+ throw new Error("not implemented");
+ }
+
+ public String toString ()
+ {
+ throw new Error("not implemented");
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java
new file mode 100644
index 0000000..ab5df9f
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java
@@ -0,0 +1,107 @@
+/* GtkButtonPeer.java -- Implements ButtonPeer with GTK
+ Copyright (C) 1998, 1999, 2004 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 gnu.java.awt.peer.gtk;
+
+import java.awt.AWTEvent;
+import java.awt.Button;
+import java.awt.Component;
+import java.awt.Point;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.peer.ButtonPeer;
+
+public class GtkButtonPeer extends GtkComponentPeer
+ implements ButtonPeer
+{
+ native void create (String label);
+
+ public native void connectSignals ();
+
+ native void gtkWidgetModifyFont (String name, int style, int size);
+ native void gtkSetLabel (String label);
+ native void gtkWidgetSetForeground (int red, int green, int blue);
+ native void gtkWidgetSetBackground (int red, int green, int blue);
+ native void gtkActivate ();
+ native void gtkWidgetRequestFocus ();
+ native void setNativeBounds (int x, int y, int width, int height);
+
+ public GtkButtonPeer (Button b)
+ {
+ super (b);
+ }
+
+ void create ()
+ {
+ create (((Button) awtComponent).getLabel ());
+ }
+
+ public void setLabel (String label)
+ {
+ gtkSetLabel(label);
+ }
+
+ public void handleEvent (AWTEvent e)
+ {
+ if (e.getID () == MouseEvent.MOUSE_RELEASED && isEnabled ())
+ {
+ MouseEvent me = (MouseEvent) e;
+ Point p = me.getPoint();
+ p.translate(((Component) me.getSource()).getX(),
+ ((Component) me.getSource()).getY());
+ if (!me.isConsumed ()
+ && (me.getModifiersEx () & MouseEvent.BUTTON1_DOWN_MASK) != 0
+ && awtComponent.getBounds().contains(p))
+ postActionEvent (((Button) awtComponent).getActionCommand (),
+ me.getModifiersEx ());
+ }
+
+ if (e.getID () == KeyEvent.KEY_PRESSED)
+ {
+ KeyEvent ke = (KeyEvent) e;
+ if (!ke.isConsumed () && ke.getKeyCode () == KeyEvent.VK_SPACE)
+ {
+ postActionEvent (((Button) awtComponent).getActionCommand (),
+ ke.getModifiersEx ());
+ gtkActivate ();
+ }
+ }
+
+ super.handleEvent (e);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java
new file mode 100644
index 0000000..dc21761
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java
@@ -0,0 +1,100 @@
+/* GtkCanvasPeer.java
+ Copyright (C) 1998, 1999 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 gnu.java.awt.peer.gtk;
+
+import java.awt.AWTEvent;
+import java.awt.Canvas;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.event.PaintEvent;
+import java.awt.peer.CanvasPeer;
+
+public class GtkCanvasPeer extends GtkComponentPeer implements CanvasPeer
+{
+ native void create ();
+
+ public GtkCanvasPeer (Canvas c)
+ {
+ super (c);
+ }
+
+ public Graphics getGraphics ()
+ {
+ if (GtkToolkit.useGraphics2D ())
+ return new GdkGraphics2D (this);
+ else
+ return new GdkGraphics (this);
+ }
+
+ public void handleEvent (AWTEvent event)
+ {
+ int id = event.getID();
+
+ switch (id)
+ {
+ case PaintEvent.PAINT:
+ case PaintEvent.UPDATE:
+ {
+ try
+ {
+ Graphics g = getGraphics ();
+ g.setClip (((PaintEvent)event).getUpdateRect());
+
+ if (id == PaintEvent.PAINT)
+ awtComponent.paint (g);
+ else
+ awtComponent.update (g);
+
+ g.dispose ();
+ }
+ catch (InternalError e)
+ {
+ System.err.println (e);
+ }
+ }
+ break;
+ }
+ }
+
+ /* Preferred size for a drawing widget is always what the user requested */
+ public Dimension getPreferredSize ()
+ {
+ return awtComponent.getSize ();
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxGroupPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxGroupPeer.java
new file mode 100644
index 0000000..46b0733
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxGroupPeer.java
@@ -0,0 +1,86 @@
+/* GtkCheckboxGroupPeer.java - Wrap a CheckboxGroup
+ Copyright (C) 2002 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 gnu.java.awt.peer.gtk;
+
+import java.awt.CheckboxGroup;
+import java.util.WeakHashMap;
+
+// Note that there is no peer interface for a CheckboxGroup. We
+// introduce our own in order to make it easier to keep a piece of
+// native state for each one.
+public class GtkCheckboxGroupPeer extends GtkGenericPeer
+{
+ // This maps from a CheckboxGroup to the native peer.
+ private static WeakHashMap map = new WeakHashMap ();
+
+ // Find the native peer corresponding to a CheckboxGroup.
+ public static synchronized GtkCheckboxGroupPeer
+ getCheckboxGroupPeer (CheckboxGroup group)
+ {
+ if (group == null)
+ return null;
+ GtkCheckboxGroupPeer nat = (GtkCheckboxGroupPeer) map.get (group);
+ if (nat == null)
+ {
+ nat = new GtkCheckboxGroupPeer ();
+ map.put (group, nat);
+ }
+ return nat;
+ }
+
+ private GtkCheckboxGroupPeer ()
+ {
+ // We don't need any special state here. Note that we can't store
+ // a reference to the java-side CheckboxGroup. That would mean
+ // they could never be collected.
+ super (null);
+ }
+
+ // Dispose of our native resources.
+ public native void dispose ();
+
+ // Remove a given checkbox from this group.
+ public native void remove (GtkCheckboxPeer box);
+
+ // When collected, clean up the native state.
+ protected void finalize ()
+ {
+ dispose ();
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java
new file mode 100644
index 0000000..01a6e31
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java
@@ -0,0 +1,69 @@
+/* GtkCheckboxMenuItemPeer.java -- Implements CheckboxMenuItemPeer with GTK+
+ Copyright (C) 1999, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.CheckboxMenuItem;
+import java.awt.ItemSelectable;
+import java.awt.event.ItemEvent;
+import java.awt.peer.CheckboxMenuItemPeer;
+
+public class GtkCheckboxMenuItemPeer extends GtkMenuItemPeer
+ implements CheckboxMenuItemPeer
+{
+ native void create (String label);
+
+ public GtkCheckboxMenuItemPeer (CheckboxMenuItem menu)
+ {
+ super (menu);
+ setState (menu.getState ());
+ }
+
+ public native void setState(boolean t);
+
+ protected void postMenuActionEvent ()
+ {
+ CheckboxMenuItem item = (CheckboxMenuItem)awtWidget;
+ q().postEvent (new ItemEvent ((ItemSelectable)awtWidget,
+ ItemEvent.ITEM_STATE_CHANGED,
+ item.getActionCommand(),
+ item.getState() ? ItemEvent.DESELECTED : ItemEvent.SELECTED));
+
+ super.postMenuActionEvent();
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java
new file mode 100644
index 0000000..8517572
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java
@@ -0,0 +1,128 @@
+/* GtkCheckboxPeer.java -- Implements CheckboxPeer with GTK
+ Copyright (C) 1998, 1999, 2002, 2003 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Checkbox;
+import java.awt.CheckboxGroup;
+import java.awt.peer.CheckboxPeer;
+
+public class GtkCheckboxPeer extends GtkComponentPeer
+ implements CheckboxPeer
+{
+ // Group from last time it was set.
+ public GtkCheckboxGroupPeer old_group;
+ // The current state of the GTK checkbox.
+ private boolean currentState;
+
+ public native void create (GtkCheckboxGroupPeer group);
+ public native void nativeSetCheckboxGroup (GtkCheckboxGroupPeer group);
+ public native void connectSignals ();
+ native void gtkWidgetModifyFont (String name, int style, int size);
+ native void gtkButtonSetLabel (String label);
+ native void gtkToggleButtonSetActive (boolean is_active);
+
+ public GtkCheckboxPeer (Checkbox c)
+ {
+ super (c);
+ }
+
+ // FIXME: we must be able to switch between a checkbutton and a
+ // radiobutton dynamically.
+ public void create ()
+ {
+ Checkbox checkbox = (Checkbox) awtComponent;
+ CheckboxGroup g = checkbox.getCheckboxGroup ();
+ old_group = GtkCheckboxGroupPeer.getCheckboxGroupPeer (g);
+ create (old_group);
+ gtkToggleButtonSetActive (checkbox.getState ());
+ gtkButtonSetLabel (checkbox.getLabel ());
+ }
+
+ public void setState (boolean state)
+ {
+ if (currentState != state)
+ gtkToggleButtonSetActive (state);
+ }
+
+ public void setLabel (String label)
+ {
+ gtkButtonSetLabel (label);
+ }
+
+ public void setCheckboxGroup (CheckboxGroup group)
+ {
+ GtkCheckboxGroupPeer gp
+ = GtkCheckboxGroupPeer.getCheckboxGroupPeer (group);
+ if (gp != old_group)
+ {
+ if (old_group != null)
+ old_group.remove (this);
+ nativeSetCheckboxGroup (gp);
+ old_group = gp;
+ }
+ }
+
+ // Override the superclass postItemEvent so that the peer doesn't
+ // need information that we have.
+ public void postItemEvent (Object item, int stateChange)
+ {
+ Checkbox currentCheckBox = ((Checkbox)awtComponent);
+ // A firing of the event is only desired if the state has changed due to a
+ // button press. The currentCheckBox's state must be different from the
+ // one that the stateChange is changing to.
+ // stateChange = 1 if it goes from false -> true
+ // stateChange = 2 if it goes from true -> false
+ if (( !currentCheckBox.getState() && stateChange == 1)
+ || (currentCheckBox.getState() && stateChange == 2))
+ {
+ super.postItemEvent (awtComponent, stateChange);
+ currentState = !currentCheckBox.getState();
+ currentCheckBox.setState(currentState);
+ }
+ }
+
+ public void dispose ()
+ {
+ // Notify the group so that the native state can be cleaned up
+ // appropriately.
+ if (old_group != null)
+ old_group.remove (this);
+ super.dispose ();
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java
new file mode 100644
index 0000000..5028ea7
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java
@@ -0,0 +1,130 @@
+/* GtkChoicePeer.java -- Implements ChoicePeer with GTK
+ Copyright (C) 1998, 1999, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Choice;
+import java.awt.event.ItemEvent;
+import java.awt.peer.ChoicePeer;
+
+public class GtkChoicePeer extends GtkComponentPeer
+ implements ChoicePeer
+{
+ public GtkChoicePeer (Choice c)
+ {
+ super (c);
+
+ int count = c.getItemCount ();
+ if (count > 0)
+ {
+ String items[] = new String[count];
+ for (int i = 0; i < count; i++)
+ items[i] = c.getItem (i);
+
+ append (items);
+ }
+
+ int selected = c.getSelectedIndex();
+ if (selected >= 0)
+ select(selected);
+ }
+
+ native void create ();
+
+ native void append (String items[]);
+ native int nativeGetSelected ();
+ native void nativeAdd (String item, int index);
+ native void nativeRemove (int index);
+ native void nativeRemoveAll ();
+
+ native void connectSignals ();
+
+ public native void select (int position);
+
+ public void add (String item, int index)
+ {
+ int before = nativeGetSelected();
+
+ nativeAdd (item, index);
+
+ /* Generate an ItemEvent if we added the first one or
+ if we inserted at or before the currently selected item. */
+ if ((before < 0) || (before >= index))
+ {
+ // Must set our state before notifying listeners
+ ((Choice) awtComponent).select (((Choice) awtComponent).getItem (0));
+ postItemEvent (((Choice) awtComponent).getItem (0), ItemEvent.SELECTED);
+ }
+ }
+
+ public void remove (int index)
+ {
+ int before = nativeGetSelected();
+ int after;
+
+ nativeRemove (index);
+ after = nativeGetSelected();
+
+ /* Generate an ItemEvent if we are removing the currently selected item
+ and there are at least one item left. */
+ if ((before == index) && (after >= 0))
+ {
+ // Must set our state before notifying listeners
+ ((Choice) awtComponent).select (((Choice) awtComponent).getItem (0));
+ postItemEvent (((Choice) awtComponent).getItem (0), ItemEvent.SELECTED);
+ }
+ }
+
+ public void removeAll ()
+ {
+ nativeRemoveAll();
+ }
+
+ public void addItem (String item, int position)
+ {
+ add (item, position);
+ }
+
+ protected void postChoiceItemEvent (String label, int stateChange)
+ {
+ // Must set our state before notifying listeners
+ if (stateChange == ItemEvent.SELECTED)
+ ((Choice) awtComponent).select (label);
+ postItemEvent (label, stateChange);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java
new file mode 100644
index 0000000..c719cdd
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java
@@ -0,0 +1,170 @@
+/* GtkClipboard.java
+ Copyright (C) 1999, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class GtkClipboard extends Clipboard
+{
+ /* the number of milliseconds that we'll wait around for the
+ owner of the GDK_SELECTION_PRIMARY selection to convert
+ the requested data */
+ static final int SELECTION_RECEIVED_TIMEOUT = 5000;
+
+ /* We currently only support transferring of text between applications */
+ static String selection;
+ static Object selectionLock = new Object ();
+
+ static boolean hasSelection = false;
+
+ protected GtkClipboard()
+ {
+ super("System Clipboard");
+ initNativeState();
+ }
+
+ public Transferable getContents(Object requestor)
+ {
+ synchronized (this)
+ {
+ if (hasSelection)
+ return contents;
+ }
+
+ /* Java doesn't own the selection, so we need to ask X11 */
+ // XXX: Does this hold with Swing too ?
+ synchronized (selectionLock)
+ {
+ requestStringConversion();
+
+ try
+ {
+ selectionLock.wait(SELECTION_RECEIVED_TIMEOUT);
+ }
+ catch (InterruptedException e)
+ {
+ return null;
+ }
+
+ return selection == null ? null : new StringSelection(selection);
+ }
+ }
+
+ void stringSelectionReceived(String newSelection)
+ {
+ synchronized (selectionLock)
+ {
+ selection = newSelection;
+ selectionLock.notify();
+ }
+ }
+
+ /* convert Java clipboard data into a String suitable for sending
+ to another application */
+ synchronized String stringSelectionHandler() throws IOException
+ {
+ String selection = null;
+
+ try
+ {
+ if (contents.isDataFlavorSupported(DataFlavor.stringFlavor))
+ selection = (String)contents.getTransferData(DataFlavor.stringFlavor);
+ else if (contents.isDataFlavorSupported(DataFlavor.plainTextFlavor))
+ {
+ StringBuffer sbuf = new StringBuffer();
+ InputStreamReader reader;
+ char readBuf[] = new char[512];
+ int numChars;
+
+ reader = new InputStreamReader
+ ((InputStream)
+ contents.getTransferData(DataFlavor.plainTextFlavor), "UNICODE");
+
+ while (true)
+ {
+ numChars = reader.read(readBuf);
+ if (numChars == -1)
+ break;
+ sbuf.append(readBuf, 0, numChars);
+ }
+
+ selection = new String(sbuf);
+ }
+ }
+ catch (Exception e)
+ {
+ }
+
+ return selection;
+ }
+
+ public synchronized void setContents(Transferable contents,
+ ClipboardOwner owner)
+ {
+ selectionGet();
+
+ this.contents = contents;
+ this.owner = owner;
+
+ hasSelection = true;
+ }
+
+ synchronized void selectionClear()
+ {
+ hasSelection = false;
+
+ if (owner != null)
+ {
+ owner.lostOwnership(this, contents);
+ owner = null;
+ contents = null;
+ }
+ }
+
+ native void initNativeState();
+ static native void requestStringConversion();
+ static native void selectionGet();
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java
new file mode 100644
index 0000000..1578a9c
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java
@@ -0,0 +1,651 @@
+/* GtkComponentPeer.java -- Implements ComponentPeer with GTK
+ Copyright (C) 1998, 1999, 2002, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.AWTEvent;
+import java.awt.AWTException;
+import java.awt.BufferCapabilities;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.ItemSelectable;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.event.FocusEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.PaintEvent;
+import java.awt.event.TextEvent;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.VolatileImage;
+import java.awt.peer.ComponentPeer;
+
+public class GtkComponentPeer extends GtkGenericPeer
+ implements ComponentPeer
+{
+ VolatileImage backBuffer;
+ BufferCapabilities caps;
+
+ Component awtComponent;
+
+ Insets insets;
+
+ boolean isInRepaint;
+
+ /* this isEnabled differs from Component.isEnabled, in that it
+ knows if a parent is disabled. In that case Component.isEnabled
+ may return true, but our isEnabled will always return false */
+ native boolean isEnabled ();
+ static native boolean modalHasGrab();
+
+ native int[] gtkWidgetGetForeground ();
+ native int[] gtkWidgetGetBackground ();
+ native void gtkWidgetGetDimensions (int[] dim);
+ native void gtkWidgetGetPreferredDimensions (int[] dim);
+ native void gtkWidgetGetLocationOnScreen (int[] point);
+ native void gtkWidgetSetCursor (int type);
+ native void gtkWidgetSetBackground (int red, int green, int blue);
+ native void gtkWidgetSetForeground (int red, int green, int blue);
+ native void gtkWidgetSetSensitive (boolean sensitive);
+ native void gtkWidgetSetParent (ComponentPeer parent);
+ native void gtkWidgetRequestFocus ();
+ native void gtkWidgetDispatchKeyEvent (int id, long when, int mods,
+ int keyCode, int keyLocation);
+
+ native boolean isRealized ();
+
+ void realize ()
+ {
+ // Default implementation does nothing
+ }
+
+ native void setNativeEventMask ();
+
+ void create ()
+ {
+ throw new RuntimeException ();
+ }
+
+ native void connectSignals ();
+
+ protected GtkComponentPeer (Component awtComponent)
+ {
+ super (awtComponent);
+ this.awtComponent = awtComponent;
+ insets = new Insets (0, 0, 0, 0);
+
+ create ();
+
+ connectSignals ();
+
+ if (awtComponent.getForeground () != null)
+ setForeground (awtComponent.getForeground ());
+ if (awtComponent.getBackground () != null)
+ setBackground (awtComponent.getBackground ());
+ if (awtComponent.getFont() != null)
+ setFont(awtComponent.getFont());
+
+ Component parent = awtComponent.getParent ();
+
+ // Only set our parent on the GTK side if our parent on the AWT
+ // side is not showing. Otherwise the gtk peer will be shown
+ // before we've had a chance to position and size it properly.
+ if (awtComponent instanceof Window
+ || (parent != null && ! parent.isShowing ()))
+ setParentAndBounds ();
+
+ setNativeEventMask ();
+
+ realize ();
+ }
+
+ void setParentAndBounds ()
+ {
+ setParent ();
+
+ setComponentBounds ();
+
+ setVisibleAndEnabled ();
+ }
+
+ void setParent ()
+ {
+ ComponentPeer p;
+ Component component = awtComponent;
+ do
+ {
+ component = component.getParent ();
+ p = component.getPeer ();
+ }
+ while (p instanceof java.awt.peer.LightweightPeer);
+
+ if (p != null)
+ gtkWidgetSetParent (p);
+ }
+
+ void beginNativeRepaint ()
+ {
+ isInRepaint = true;
+ }
+
+ void endNativeRepaint ()
+ {
+ isInRepaint = false;
+ }
+
+ /*
+ * Set the bounds of this peer's AWT Component based on dimensions
+ * returned by the native windowing system. Most Components impose
+ * their dimensions on the peers which is what the default
+ * implementation does. However some peers, like GtkFileDialogPeer,
+ * need to pass their size back to the AWT Component.
+ */
+ void setComponentBounds ()
+ {
+ Rectangle bounds = awtComponent.getBounds ();
+
+ if (bounds.x == 0 && bounds.y == 0
+ && bounds.width == 0 && bounds.height == 0)
+ return;
+
+ setBounds (bounds.x, bounds.y, bounds.width, bounds.height);
+ }
+
+ void setVisibleAndEnabled ()
+ {
+ setVisible (awtComponent.isVisible ());
+ setEnabled (awtComponent.isEnabled ());
+ }
+
+ public int checkImage (Image image, int width, int height,
+ ImageObserver observer)
+ {
+ return getToolkit().checkImage(image, width, height, observer);
+ }
+
+ public Image createImage (ImageProducer producer)
+ {
+ return new GtkImage (producer);
+ }
+
+ public Image createImage (int width, int height)
+ {
+ Image image;
+ if (GtkToolkit.useGraphics2D ())
+ image = new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB);
+ else
+ image = new GtkImage (width, height);
+
+ Graphics g = image.getGraphics();
+ g.setColor(getBackground());
+ g.fillRect(0, 0, width, height);
+ return image;
+ }
+
+ public void disable ()
+ {
+ setEnabled (false);
+ }
+
+ public void enable ()
+ {
+ setEnabled (true);
+ }
+
+ public ColorModel getColorModel ()
+ {
+ return ColorModel.getRGBdefault ();
+ }
+
+ public FontMetrics getFontMetrics (Font font)
+ {
+ return getToolkit().getFontMetrics(font);
+ }
+
+ public Graphics getGraphics ()
+ {
+ if (GtkToolkit.useGraphics2D ())
+ return new GdkGraphics2D (this);
+ else
+ return new GdkGraphics (this);
+ }
+
+ public Point getLocationOnScreen ()
+ {
+ int point[] = new int[2];
+ gtkWidgetGetLocationOnScreen (point);
+ return new Point (point[0], point[1]);
+ }
+
+ public Dimension getMinimumSize ()
+ {
+ return minimumSize ();
+ }
+
+ public Dimension getPreferredSize ()
+ {
+ return preferredSize ();
+ }
+
+ public Toolkit getToolkit ()
+ {
+ return Toolkit.getDefaultToolkit();
+ }
+
+ public void handleEvent (AWTEvent event)
+ {
+ int id = event.getID();
+ KeyEvent ke = null;
+
+ switch (id)
+ {
+ case PaintEvent.PAINT:
+ case PaintEvent.UPDATE:
+ {
+ try
+ {
+ Graphics g = getGraphics ();
+
+ // Some peers like GtkFileDialogPeer are repainted by Gtk itself
+ if (g == null)
+ break;
+
+ g.setClip (((PaintEvent) event).getUpdateRect());
+
+ if (id == PaintEvent.PAINT)
+ awtComponent.paint (g);
+ else
+ awtComponent.update (g);
+
+ g.dispose ();
+ }
+ catch (InternalError e)
+ {
+ System.err.println (e);
+ }
+ }
+ break;
+ case KeyEvent.KEY_PRESSED:
+ ke = (KeyEvent) event;
+ gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (),
+ ke.getKeyCode (), ke.getKeyLocation ());
+ break;
+ case KeyEvent.KEY_RELEASED:
+ ke = (KeyEvent) event;
+ gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (),
+ ke.getKeyCode (), ke.getKeyLocation ());
+ break;
+ }
+ }
+
+ public boolean isFocusTraversable ()
+ {
+ return true;
+ }
+
+ public Dimension minimumSize ()
+ {
+ int dim[] = new int[2];
+
+ gtkWidgetGetPreferredDimensions (dim);
+
+ return new Dimension (dim[0], dim[1]);
+ }
+
+ public void paint (Graphics g)
+ {
+ }
+
+ public Dimension preferredSize ()
+ {
+ int dim[] = new int[2];
+
+ gtkWidgetGetPreferredDimensions (dim);
+
+ return new Dimension (dim[0], dim[1]);
+ }
+
+ public boolean prepareImage (Image image, int width, int height,
+ ImageObserver observer)
+ {
+ return getToolkit().prepareImage(image, width, height, observer);
+ }
+
+ public void print (Graphics g)
+ {
+ throw new RuntimeException ();
+ }
+
+ public void repaint (long tm, int x, int y, int width, int height)
+ {
+ if (x == 0 && y == 0 && width == 0 && height == 0)
+ return;
+
+ q().postEvent (new PaintEvent (awtComponent, PaintEvent.UPDATE,
+ new Rectangle (x, y, width, height)));
+ }
+
+ public void requestFocus ()
+ {
+ gtkWidgetRequestFocus();
+ postFocusEvent(FocusEvent.FOCUS_GAINED, false);
+ }
+
+ public void reshape (int x, int y, int width, int height)
+ {
+ setBounds (x, y, width, height);
+ }
+
+ public void setBackground (Color c)
+ {
+ gtkWidgetSetBackground (c.getRed(), c.getGreen(), c.getBlue());
+ }
+
+ native void setNativeBounds (int x, int y, int width, int height);
+
+ public void setBounds (int x, int y, int width, int height)
+ {
+ Component parent = awtComponent.getParent ();
+
+ // Heavyweight components that are children of one or more
+ // lightweight containers have to be handled specially. Because
+ // calls to GLightweightPeer.setBounds do nothing, GTK has no
+ // knowledge of the lightweight containers' positions. So we have
+ // to add the offsets manually when placing a heavyweight
+ // component within a lightweight container. The lightweight
+ // container may itself be in a lightweight container and so on,
+ // so we need to continue adding offsets until we reach a
+ // container whose position GTK knows -- that is, the first
+ // non-lightweight.
+ boolean lightweightChild = false;
+ Insets i;
+ while (parent.isLightweight ())
+ {
+ lightweightChild = true;
+
+ i = ((Container) parent).getInsets ();
+
+ x += parent.getX () + i.left;
+ y += parent.getY () + i.top;
+
+ parent = parent.getParent ();
+ }
+
+ // We only need to convert from Java to GTK coordinates if we're
+ // placing a heavyweight component in a Window.
+ if (parent instanceof Window && !lightweightChild)
+ {
+ Insets insets = ((Window) parent).getInsets ();
+ GtkWindowPeer peer = (GtkWindowPeer) parent.getPeer ();
+ int menuBarHeight = 0;
+ if (peer instanceof GtkFramePeer)
+ menuBarHeight = ((GtkFramePeer) peer).getMenuBarHeight ();
+
+ // Convert from Java coordinates to GTK coordinates.
+ setNativeBounds (x - insets.left, y - insets.top + menuBarHeight,
+ width, height);
+ }
+ else
+ setNativeBounds (x, y, width, height);
+ }
+
+ void setCursor ()
+ {
+ setCursor (awtComponent.getCursor ());
+ }
+
+ public void setCursor (Cursor cursor)
+ {
+ gtkWidgetSetCursor (cursor.getType ());
+ }
+
+ public void setEnabled (boolean b)
+ {
+ gtkWidgetSetSensitive (b);
+ }
+
+ public void setFont (Font f)
+ {
+ // FIXME: This should really affect the widget tree below me.
+ // Currently this is only handled if the call is made directly on
+ // a text widget, which implements setFont() itself.
+ gtkWidgetModifyFont(f.getName(), f.getStyle(), f.getSize());
+ }
+
+ public void setForeground (Color c)
+ {
+ gtkWidgetSetForeground (c.getRed(), c.getGreen(), c.getBlue());
+ }
+
+ public Color getForeground ()
+ {
+ int rgb[] = gtkWidgetGetForeground ();
+ return new Color (rgb[0], rgb[1], rgb[2]);
+ }
+
+ public Color getBackground ()
+ {
+ int rgb[] = gtkWidgetGetBackground ();
+ return new Color (rgb[0], rgb[1], rgb[2]);
+ }
+
+ public void setVisible (boolean b)
+ {
+ if (b)
+ show ();
+ else
+ hide ();
+ }
+
+ public native void hide ();
+ public native void show ();
+
+ protected void postMouseEvent(int id, long when, int mods, int x, int y,
+ int clickCount, boolean popupTrigger)
+ {
+ q().postEvent(new MouseEvent(awtComponent, id, when, mods, x, y,
+ clickCount, popupTrigger));
+ }
+
+ protected void postExposeEvent (int x, int y, int width, int height)
+ {
+ if (!isInRepaint)
+ q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
+ new Rectangle (x, y, width, height)));
+ }
+
+ protected void postKeyEvent (int id, long when, int mods,
+ int keyCode, char keyChar, int keyLocation)
+ {
+ KeyEvent keyEvent = new KeyEvent (awtComponent, id, when, mods,
+ keyCode, keyChar, keyLocation);
+
+ // Also post a KEY_TYPED event if keyEvent is a key press that
+ // doesn't represent an action or modifier key.
+ if (keyEvent.getID () == KeyEvent.KEY_PRESSED
+ && (!keyEvent.isActionKey ()
+ && keyCode != KeyEvent.VK_SHIFT
+ && keyCode != KeyEvent.VK_CONTROL
+ && keyCode != KeyEvent.VK_ALT))
+ {
+ synchronized (q)
+ {
+ q().postEvent (keyEvent);
+ q().postEvent (new KeyEvent (awtComponent, KeyEvent.KEY_TYPED, when, mods,
+ KeyEvent.VK_UNDEFINED, keyChar, keyLocation));
+ }
+ }
+ else
+ q().postEvent (keyEvent);
+ }
+
+ protected void postFocusEvent (int id, boolean temporary)
+ {
+ q().postEvent (new FocusEvent (awtComponent, id, temporary));
+ }
+
+ protected void postItemEvent (Object item, int stateChange)
+ {
+ q().postEvent (new ItemEvent ((ItemSelectable)awtComponent,
+ ItemEvent.ITEM_STATE_CHANGED,
+ item, stateChange));
+ }
+
+ protected void postTextEvent ()
+ {
+ q().postEvent (new TextEvent (awtComponent, TextEvent.TEXT_VALUE_CHANGED));
+ }
+
+ public GraphicsConfiguration getGraphicsConfiguration ()
+ {
+ // FIXME: just a stub for now.
+ return null;
+ }
+
+ public void setEventMask (long mask)
+ {
+ // FIXME: just a stub for now.
+ }
+
+ public boolean isFocusable ()
+ {
+ return false;
+ }
+
+ public boolean requestFocus (Component source, boolean b1,
+ boolean b2, long x)
+ {
+ return false;
+ }
+
+ public boolean isObscured ()
+ {
+ return false;
+ }
+
+ public boolean canDetermineObscurity ()
+ {
+ return false;
+ }
+
+ public void coalescePaintEvent (PaintEvent e)
+ {
+
+ }
+
+ public void updateCursorImmediately ()
+ {
+
+ }
+
+ public boolean handlesWheelScrolling ()
+ {
+ return false;
+ }
+
+ // Convenience method to create a new volatile image on the screen
+ // on which this component is displayed.
+ public VolatileImage createVolatileImage (int width, int height)
+ {
+ return new GtkVolatileImage (width, height);
+ }
+
+ // Creates buffers used in a buffering strategy.
+ public void createBuffers (int numBuffers, BufferCapabilities caps)
+ throws AWTException
+ {
+ // numBuffers == 2 implies double-buffering, meaning one back
+ // buffer and one front buffer.
+ if (numBuffers == 2)
+ backBuffer = new GtkVolatileImage(awtComponent.getWidth(),
+ awtComponent.getHeight(),
+ caps.getBackBufferCapabilities());
+ else
+ throw new AWTException("GtkComponentPeer.createBuffers:"
+ + " multi-buffering not supported");
+ this.caps = caps;
+ }
+
+ // Return the back buffer.
+ public Image getBackBuffer ()
+ {
+ return backBuffer;
+ }
+
+ // FIXME: flip should be implemented as a fast native operation
+ public void flip (BufferCapabilities.FlipContents contents)
+ {
+ getGraphics().drawImage(backBuffer,
+ awtComponent.getWidth(),
+ awtComponent.getHeight(),
+ null);
+
+ // create new back buffer and clear it to the background color.
+ if (contents == BufferCapabilities.FlipContents.BACKGROUND)
+ {
+ backBuffer = createVolatileImage(awtComponent.getWidth(),
+ awtComponent.getHeight());
+ backBuffer.getGraphics().clearRect(0, 0,
+ awtComponent.getWidth(),
+ awtComponent.getHeight());
+ }
+ // FIXME: support BufferCapabilities.FlipContents.PRIOR
+ }
+
+ // Release the resources allocated to back buffers.
+ public void destroyBuffers ()
+ {
+ backBuffer.flush();
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java
new file mode 100644
index 0000000..c2865f7
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java
@@ -0,0 +1,156 @@
+/* GtkContainerPeer.java -- Implements ContainerPeer with GTK
+ Copyright (C) 1998, 1999 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Insets;
+import java.awt.Window;
+import java.awt.peer.ComponentPeer;
+import java.awt.peer.ContainerPeer;
+
+public class GtkContainerPeer extends GtkComponentPeer
+ implements ContainerPeer
+{
+ Container c;
+ boolean isValidating;
+
+ public GtkContainerPeer(Container c)
+ {
+ super (c);
+ this.c = c;
+ }
+
+ public void beginValidate ()
+ {
+ isValidating = true;
+ }
+
+ public void endValidate ()
+ {
+ Component parent = awtComponent.getParent ();
+
+ // Only set our parent on the GTK side if our parent on the AWT
+ // side is not showing. Otherwise the gtk peer will be shown
+ // before we've had a chance to position and size it properly.
+ if (parent != null && parent.isShowing ())
+ {
+ Component[] components = ((Container) awtComponent).getComponents ();
+ int ncomponents = components.length;
+
+ for (int i = 0; i < ncomponents; i++)
+ {
+ ComponentPeer peer = components[i].getPeer ();
+
+ // Skip lightweight peers.
+ if (peer instanceof GtkComponentPeer)
+ ((GtkComponentPeer) peer).setParentAndBounds ();
+ }
+
+ // GTK windows don't have parents.
+ if (!(awtComponent instanceof Window))
+ setParentAndBounds ();
+ }
+
+ isValidating = false;
+ }
+
+ public Insets getInsets()
+ {
+ return insets;
+ }
+
+ public Insets insets()
+ {
+ return getInsets ();
+ }
+
+ public void setBounds (int x, int y, int width, int height)
+ {
+ super.setBounds (x, y, width, height);
+ }
+
+ public void setFont(Font f)
+ {
+ super.setFont(f);
+ Component[] components = ((Container) awtComponent).getComponents();
+ for (int i = 0; i < components.length; i++)
+ {
+ if (components[i].isLightweight ())
+ components[i].setFont (f);
+ else
+ {
+ GtkComponentPeer peer = (GtkComponentPeer) components[i].getPeer();
+ if (peer != null && ! peer.awtComponent.isFontSet())
+ peer.setFont(f);
+ }
+ }
+ }
+
+ public Graphics getGraphics ()
+ {
+ return super.getGraphics();
+ }
+
+ public void beginLayout () { }
+ public void endLayout () { }
+ public boolean isPaintPending () { return false; }
+
+ public void setBackground (Color c)
+ {
+ super.setBackground(c);
+
+ Object components[] = ((Container) awtComponent).getComponents();
+ for (int i = 0; i < components.length; i++)
+ {
+ Component comp = (Component) components[i];
+
+ // If the child's background has not been explicitly set yet,
+ // it should inherit this container's background. This makes the
+ // child component appear as if it has a transparent background.
+ // Note that we do not alter the background property of the child,
+ // but only repaint the child with the parent's background color.
+ if (!comp.isBackgroundSet() && comp.getPeer() != null)
+ comp.getPeer().setBackground(c);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java
new file mode 100644
index 0000000..c2cbc37
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java
@@ -0,0 +1,94 @@
+/* GtkDialogPeer.java -- Implements DialogPeer with GTK
+ Copyright (C) 1998, 1999, 2002 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Dialog;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.event.PaintEvent;
+import java.awt.peer.DialogPeer;
+
+public class GtkDialogPeer extends GtkWindowPeer
+ implements DialogPeer
+{
+ public GtkDialogPeer (Dialog dialog)
+ {
+ super (dialog);
+ }
+
+ public Graphics getGraphics ()
+ {
+ Graphics g;
+ if (GtkToolkit.useGraphics2D ())
+ g = new GdkGraphics2D (this);
+ else
+ g = new GdkGraphics (this);
+ g.translate (-insets.left, -insets.top);
+ return g;
+ }
+
+ protected void postMouseEvent(int id, long when, int mods, int x, int y,
+ int clickCount, boolean popupTrigger)
+ {
+ super.postMouseEvent (id, when, mods,
+ x + insets.left, y + insets.top,
+ clickCount, popupTrigger);
+ }
+
+ protected void postExposeEvent (int x, int y, int width, int height)
+ {
+ if (!isInRepaint)
+ q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
+ new Rectangle (x + insets.left,
+ y + insets.top,
+ width, height)));
+ }
+
+ void create ()
+ {
+ // Create a decorated dialog window.
+ create (GDK_WINDOW_TYPE_HINT_DIALOG, true);
+
+ Dialog dialog = (Dialog) awtComponent;
+
+ gtkWindowSetModal (dialog.isModal ());
+ setTitle (dialog.getTitle ());
+ setResizable (dialog.isResizable ());
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java
new file mode 100644
index 0000000..0533d27
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java
@@ -0,0 +1,73 @@
+/* GtkEmbeddedWindowPeer.java -- Implements EmbeddedWindowPeer using a
+ GtkPlug
+ Copyright (C) 2003 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 gnu.java.awt.peer.gtk;
+
+import gnu.java.awt.EmbeddedWindow;
+import gnu.java.awt.peer.EmbeddedWindowPeer;
+
+public class GtkEmbeddedWindowPeer extends GtkFramePeer
+ implements EmbeddedWindowPeer
+{
+ native void create (long socket_id);
+
+ void create ()
+ {
+ create (((EmbeddedWindow) awtComponent).getHandle ());
+ }
+
+ native void construct (long socket_id);
+
+ // FIXME: embed doesn't work right now, though I believe it should.
+ // This means that you can't call setVisible (true) on an
+ // EmbeddedWindow before calling setHandle with a valid handle. The
+ // problem is that somewhere after the call to
+ // GtkEmbeddedWindow.create and before the call to
+ // GtkEmbeddedWindow.construct, the GtkPlug peer is being realized.
+ // GtkSocket silently fails to embed an already-realized GtkPlug.
+ public void embed (long handle)
+ {
+ construct (handle);
+ }
+
+ public GtkEmbeddedWindowPeer (EmbeddedWindow w)
+ {
+ super (w);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java
new file mode 100644
index 0000000..bd1f077
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java
@@ -0,0 +1,219 @@
+/* GtkFileDialogPeer.java -- Implements FileDialogPeer with GTK
+ Copyright (C) 1998, 1999, 2002, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Dialog;
+import java.awt.FileDialog;
+import java.awt.Graphics;
+import java.awt.Window;
+import java.awt.peer.FileDialogPeer;
+import java.io.File;
+import java.io.FilenameFilter;
+
+public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer
+{
+ static final String FS = System.getProperty("file.separator");
+
+ private String currentFile = null;
+ private String currentDirectory = null;
+ private FilenameFilter filter;
+
+ native void create (GtkContainerPeer parent);
+ native void connectSignals ();
+ native void nativeSetFile (String file);
+ public native String nativeGetDirectory();
+ public native void nativeSetDirectory(String directory);
+ native void nativeSetFilenameFilter (FilenameFilter filter);
+
+ public void create()
+ {
+ create((GtkContainerPeer) awtComponent.getParent().getPeer());
+
+ FileDialog fd = (FileDialog) awtComponent;
+
+ setDirectory(fd.getDirectory());
+ setFile(fd.getFile());
+
+ FilenameFilter filter = fd.getFilenameFilter();
+ if (filter != null)
+ setFilenameFilter(filter);
+ }
+
+ public GtkFileDialogPeer (FileDialog fd)
+ {
+ super (fd);
+ }
+
+ void setComponentBounds ()
+ {
+ if (awtComponent.getHeight () == 0
+ && awtComponent.getWidth () == 0)
+ {
+ int[] dims = new int[2];
+ gtkWidgetGetPreferredDimensions (dims);
+ ((GtkFileDialogPeer) this).setBoundsCallback ((Window) awtComponent,
+ awtComponent.getX (),
+ awtComponent.getY (),
+ dims[0], dims[1]);
+ }
+ super.setComponentBounds ();
+ }
+
+ public void setFile (String fileName)
+ {
+ /* If nothing changed do nothing. This usually happens because
+ the only way we have to set the file name in FileDialog is by
+ calling its SetFile which will call us back. */
+ if ((fileName == null && currentFile == null)
+ || (fileName != null && fileName.equals (currentFile)))
+ return;
+
+ if (fileName == null || fileName.equals (""))
+ {
+ currentFile = "";
+ nativeSetFile ("");
+ return;
+ }
+
+ // GtkFileChooser requires absolute filenames. If the given filename
+ // is not absolute, let's construct it based on current directory.
+ currentFile = fileName;
+ if (fileName.indexOf(FS) == 0)
+ {
+ nativeSetFile (fileName);
+ }
+ else
+ {
+ nativeSetFile (nativeGetDirectory() + FS + fileName);
+ }
+ }
+
+ public void setDirectory (String directory)
+ {
+ /* If nothing changed so nothing. This usually happens because
+ the only way we have to set the directory in FileDialog is by
+ calling its setDirectory which will call us back. */
+ if ((directory == null && currentDirectory == null)
+ || (directory != null && directory.equals (currentDirectory)))
+ return;
+
+ if (directory == null || directory.equals (""))
+ {
+ currentDirectory = FS;
+ nativeSetFile (FS);
+ return;
+ }
+
+ currentDirectory = directory;
+ nativeSetDirectory (directory);
+ }
+
+ public void setFilenameFilter (FilenameFilter filter)
+ {
+ this.filter = filter;
+ nativeSetFilenameFilter(filter);
+ }
+
+ /* This method interacts with the native callback function of the
+ same name. The native function will extract the filename from the
+ GtkFileFilterInfo object and send it to this method, which will
+ in turn call the filter's accept() method and give back the return
+ value. */
+ boolean filenameFilterCallback (String fullname) {
+ String filename = fullname.substring(fullname.lastIndexOf(FS) + 1);
+ String dirname = fullname.substring(0, fullname.lastIndexOf(FS));
+ File dir = new File(dirname);
+ return filter.accept(dir, filename);
+ }
+
+ public Graphics getGraphics ()
+ {
+ // GtkFileDialog will repaint by itself
+ return null;
+ }
+
+ void gtkHideFileDialog ()
+ {
+ ((Dialog) awtComponent).hide();
+ }
+
+ void gtkDisposeFileDialog ()
+ {
+ ((Dialog) awtComponent).dispose();
+ }
+
+ /* Callback to set the file and directory values when the user is finished
+ * with the dialog.
+ */
+ void gtkSetFilename (String fileName)
+ {
+ FileDialog fd = (FileDialog) awtWidget;
+ if (fileName == null)
+ {
+ currentFile = null;
+ fd.setFile(null);
+ return;
+ }
+
+ int sepIndex = fileName.lastIndexOf (FS);
+ if (sepIndex < 0)
+ {
+ /* This should never happen on Unix (all paths start with '/') */
+ currentFile = fileName;
+ }
+ else
+ {
+ if (fileName.length() > (sepIndex + 1))
+ {
+ String fn = fileName.substring (sepIndex + 1);
+ currentFile = fn;
+ }
+ else
+ {
+ currentFile = null;
+ }
+
+ String dn = fileName.substring (0, sepIndex + 1);
+ currentDirectory = dn;
+ fd.setDirectory(dn);
+ }
+
+ fd.setFile (currentFile);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFontPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFontPeer.java
new file mode 100644
index 0000000..80ad158
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFontPeer.java
@@ -0,0 +1,225 @@
+/* GtkFontPeer.java -- Implements FontPeer with GTK+
+ Copyright (C) 1999, 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 gnu.java.awt.peer.gtk;
+
+import gnu.java.awt.peer.ClasspathFontPeer;
+
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.font.LineMetrics;
+import java.awt.geom.Rectangle2D;
+import java.text.CharacterIterator;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class GtkFontPeer extends ClasspathFontPeer
+{
+ private static ResourceBundle bundle;
+
+ static
+ {
+ try
+ {
+ bundle = ResourceBundle.getBundle ("gnu.java.awt.peer.gtk.font");
+ }
+ catch (Throwable ignored)
+ {
+ bundle = null;
+ }
+ }
+
+ private final String Xname;
+
+ public GtkFontPeer (String name, int style)
+ {
+ // All fonts get a default size of 12 if size is not specified.
+ this(name, style, 12);
+ }
+
+ public GtkFontPeer (String name, int style, int size)
+ {
+ super(name, style, size);
+
+ String Xname = null;
+ if (bundle != null)
+ {
+ try
+ {
+ Xname = bundle.getString (name.toLowerCase () + "." + style);
+ }
+ catch (MissingResourceException mre)
+ {
+ // ignored
+ }
+ }
+
+ if (Xname == null)
+ {
+ String weight;
+ String slant;
+ String spacing;
+
+ if (style == Font.ITALIC || (style == (Font.BOLD+Font.ITALIC)))
+ slant = "i";
+ else
+ slant = "r";
+ if (style == Font.BOLD || (style == (Font.BOLD+Font.ITALIC)))
+ weight = "bold";
+ else
+ weight = "medium";
+ if (name.equals("Serif") || name.equals("SansSerif")
+ || name.equals("Helvetica") || name.equals("Times"))
+ spacing = "p";
+ else
+ spacing = "c";
+
+ Xname = "-*-*-" + weight + "-" + slant + "-normal-*-*-" + size + "-*-*-" + spacing + "-*-*-*";
+ }
+
+ this.Xname = Xname;
+ }
+
+ public String getXLFD ()
+ {
+ return Xname;
+ }
+
+
+ /* remaining methods are for static compatibility with the newer
+ ClasspathFontPeer superclass; none of these methods ever existed or
+ worked on the older FontPeer interface, but we need to pretend to
+ support them anyways. */
+
+ public boolean canDisplay (Font font, char c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public int canDisplayUpTo (Font font, CharacterIterator i, int start, int limit)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getSubFamilyName (Font font, Locale locale)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getPostScriptName (Font font)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getNumGlyphs (Font font)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getMissingGlyphCode (Font font)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public byte getBaselineFor (Font font, char c)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getGlyphName (Font font, int glyphIndex)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public GlyphVector createGlyphVector (Font font,
+ FontRenderContext frc,
+ CharacterIterator ci)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public GlyphVector createGlyphVector (Font font,
+ FontRenderContext ctx,
+ int[] glyphCodes)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public GlyphVector layoutGlyphVector (Font font,
+ FontRenderContext frc,
+ char[] chars, int start,
+ int limit, int flags)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public FontMetrics getFontMetrics (Font font)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean hasUniformLineMetrics (Font font)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public LineMetrics getLineMetrics (Font font,
+ CharacterIterator ci,
+ int begin, int limit,
+ FontRenderContext rc)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public Rectangle2D getMaxCharBounds (Font font,
+ FontRenderContext rc)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public Rectangle2D getStringBounds (Font font,
+ CharacterIterator ci,
+ int begin, int limit,
+ FontRenderContext frc)
+ {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java
new file mode 100644
index 0000000..b242d66
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java
@@ -0,0 +1,256 @@
+/* GtkFramePeer.java -- Implements FramePeer with GTK
+ Copyright (C) 1999, 2002, 2004 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.MenuBar;
+import java.awt.Rectangle;
+import java.awt.Window;
+import java.awt.event.PaintEvent;
+import java.awt.image.ColorModel;
+import java.awt.peer.FramePeer;
+import java.awt.peer.MenuBarPeer;
+
+public class GtkFramePeer extends GtkWindowPeer
+ implements FramePeer
+{
+ private int menuBarHeight;
+ private MenuBarPeer menuBar;
+ native int getMenuBarHeight (MenuBarPeer bar);
+ native void setMenuBarWidth (MenuBarPeer bar, int width);
+ native void setMenuBarPeer (MenuBarPeer bar);
+ native void removeMenuBarPeer ();
+ native void gtkFixedSetVisible (boolean visible);
+
+ int getMenuBarHeight ()
+ {
+ return menuBar == null ? 0 : getMenuBarHeight (menuBar);
+ }
+
+ public void setMenuBar (MenuBar bar)
+ {
+ if (bar == null && menuBar != null)
+ {
+ // We're removing the menubar.
+ gtkFixedSetVisible (false);
+ menuBar = null;
+ removeMenuBarPeer ();
+ insets.top -= menuBarHeight;
+ menuBarHeight = 0;
+ awtComponent.validate ();
+ gtkFixedSetVisible (true);
+ }
+ else if (bar != null && menuBar == null)
+ {
+ // We're adding a menubar where there was no menubar before.
+ gtkFixedSetVisible (false);
+ menuBar = (MenuBarPeer) ((MenuBar) bar).getPeer();
+ setMenuBarPeer (menuBar);
+ int menuBarWidth =
+ awtComponent.getWidth () - insets.left - insets.right;
+ if (menuBarWidth > 0)
+ setMenuBarWidth (menuBar, menuBarWidth);
+ menuBarHeight = getMenuBarHeight ();
+ insets.top += menuBarHeight;
+ awtComponent.validate ();
+ gtkFixedSetVisible (true);
+ }
+ else if (bar != null && menuBar != null)
+ {
+ // We're swapping the menubar.
+ gtkFixedSetVisible (false);
+ removeMenuBarPeer();
+ int oldHeight = menuBarHeight;
+ int menuBarWidth =
+ awtComponent.getWidth () - insets.left - insets.right;
+ menuBar = (MenuBarPeer) ((MenuBar) bar).getPeer ();
+ setMenuBarPeer (menuBar);
+ if (menuBarWidth > 0)
+ setMenuBarWidth (menuBar, menuBarWidth);
+ menuBarHeight = getMenuBarHeight ();
+ if (oldHeight != menuBarHeight)
+ {
+ insets.top += (menuBarHeight - oldHeight);
+ awtComponent.validate ();
+ }
+ gtkFixedSetVisible (true);
+ }
+ }
+
+ public void setBounds (int x, int y, int width, int height)
+ {
+ int menuBarWidth = width - insets.left - insets.right;
+ if (menuBar != null && menuBarWidth > 0)
+ setMenuBarWidth (menuBar, menuBarWidth);
+
+ nativeSetBounds (x, y,
+ width - insets.left - insets.right,
+ height - insets.top - insets.bottom
+ + menuBarHeight);
+ }
+
+ public void setResizable (boolean resizable)
+ {
+ // Call setSize; otherwise when resizable is changed from true to
+ // false the frame will shrink to the dimensions it had before it
+ // was resizable.
+ setSize (awtComponent.getWidth() - insets.left - insets.right,
+ awtComponent.getHeight() - insets.top - insets.bottom
+ + menuBarHeight);
+ gtkWindowSetResizable (resizable);
+ }
+
+ protected void postInsetsChangedEvent (int top, int left,
+ int bottom, int right)
+ {
+ insets.top = top + menuBarHeight;
+ insets.left = left;
+ insets.bottom = bottom;
+ insets.right = right;
+ }
+
+ public GtkFramePeer (Frame frame)
+ {
+ super (frame);
+ }
+
+ void create ()
+ {
+ // Create a normal decorated window.
+ create (GDK_WINDOW_TYPE_HINT_NORMAL, true);
+
+ Frame frame = (Frame) awtComponent;
+
+ setMenuBar (frame.getMenuBar ());
+
+ setTitle (frame.getTitle ());
+ gtkWindowSetResizable (frame.isResizable ());
+ setIconImage(frame.getIconImage());
+ }
+
+ native void nativeSetIconImage (GtkImage image);
+
+ public void setIconImage (Image image)
+ {
+ if (image != null)
+ {
+ if (image instanceof GtkImage)
+ nativeSetIconImage((GtkImage) image);
+ else
+ nativeSetIconImage(new GtkImage(image.getSource()));
+ }
+ }
+
+ public Graphics getGraphics ()
+ {
+ Graphics g;
+ if (GtkToolkit.useGraphics2D ())
+ g = new GdkGraphics2D (this);
+ else
+ g = new GdkGraphics (this);
+ g.translate (-insets.left, -insets.top);
+ return g;
+ }
+
+ protected void postConfigureEvent (int x, int y, int width, int height)
+ {
+ int frame_x = x - insets.left;
+ // Since insets.top includes the MenuBar height, we need to add back
+ // the MenuBar height to the frame's y position.
+ // If no MenuBar exists in this frame, the MenuBar height will be 0.
+ int frame_y = y - insets.top + menuBarHeight;
+ int frame_width = width + insets.left + insets.right;
+ // Ditto as above. Since insets.top already includes the MenuBar's height,
+ // we need to subtract the MenuBar's height from the top inset.
+ int frame_height = height + insets.top + insets.bottom - menuBarHeight;
+ if (frame_x != awtComponent.getX()
+ || frame_y != awtComponent.getY()
+ || frame_width != awtComponent.getWidth()
+ || frame_height != awtComponent.getHeight())
+ {
+ if (frame_width != awtComponent.getWidth() && menuBar != null
+ && width > 0)
+ setMenuBarWidth (menuBar, width);
+
+ setBoundsCallback ((Window) awtComponent,
+ frame_x,
+ frame_y,
+ frame_width,
+ frame_height);
+
+ awtComponent.validate();
+ }
+ }
+
+ protected void postMouseEvent(int id, long when, int mods, int x, int y,
+ int clickCount, boolean popupTrigger)
+ {
+ super.postMouseEvent (id, when, mods,
+ x + insets.left, y + insets.top,
+ clickCount, popupTrigger);
+ }
+
+ protected void postExposeEvent (int x, int y, int width, int height)
+ {
+ if (!isInRepaint)
+ q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
+ new Rectangle (x + insets.left,
+ y + insets.top,
+ width, height)));
+ }
+
+ public int getState ()
+ {
+ return 0;
+ }
+
+ public void setState (int state)
+ {
+
+ }
+
+ public void setMaximizedBounds (Rectangle r)
+ {
+
+ }
+}
+
+
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java
new file mode 100644
index 0000000..705eed2
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java
@@ -0,0 +1,98 @@
+/* GtkGenericPeer.java - Has a hashcode. Yuck.
+ Copyright (C) 1998, 1999, 2002 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 gnu.java.awt.peer.gtk;
+
+import java.awt.EventQueue;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+
+public class GtkGenericPeer
+{
+ final int native_state = getUniqueInteger ();
+
+ // Next native state value we will assign.
+ private static int next_native_state = 0;
+
+ // The widget or other java-side object we wrap.
+ protected Object awtWidget;
+
+ // Global event queue.
+ protected static EventQueue q = null;
+
+ // Dispose of our native state.
+ public native void dispose ();
+
+ static EventQueue q ()
+ {
+ return Toolkit.getDefaultToolkit ().getSystemEventQueue ();
+ }
+
+ protected GtkGenericPeer (Object awtWidget)
+ {
+ this.awtWidget = awtWidget;
+ }
+
+ public static void enableQueue (EventQueue sq)
+ {
+ if (q == null)
+ q = sq;
+ }
+
+ protected void postActionEvent (String command, int mods)
+ {
+ q().postEvent (new ActionEvent (awtWidget, ActionEvent.ACTION_PERFORMED,
+ command, mods));
+ }
+
+ // Return a unique integer for use in the native state mapping
+ // code. We can't use a hash code since that is not guaranteed to
+ // be unique.
+ static synchronized int getUniqueInteger ()
+ {
+ // Let's assume this will never wrap.
+ return next_native_state++;
+ }
+
+ native void gtkWidgetModifyFont (String name, int style, int size);
+
+ static void printCurrentThread ()
+ {
+ System.out.println ("gtkgenericpeer, thread: " + Thread.currentThread ());
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java
new file mode 100644
index 0000000..abb4137
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java
@@ -0,0 +1,494 @@
+/* GtkImage.java
+ Copyright (C) 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Graphics;
+import java.awt.Color;
+import java.awt.Image;
+import java.awt.image.ColorModel;
+import java.awt.image.DirectColorModel;
+import java.awt.image.MemoryImageSource;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.io.File;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Vector;
+import gnu.classpath.RawData;
+
+/**
+ * GtkImage - wraps a GdkPixbuf or GdkPixmap.
+ *
+ * The constructor GtkImage(int, int) creates an 'off-screen' GdkPixmap,
+ * this can be drawn to (it's a GdkDrawable), and correspondingly, you can
+ * create a GdkGraphics object for it.
+ *
+ * This corresponds to the Image implementation returned by
+ * Component.createImage(int, int).
+ *
+ * A GdkPixbuf is 'on-screen' and the gdk cannot draw to it,
+ * this is used for the other constructors (and other createImage methods), and
+ * corresponds to the Image implementations returned by the Toolkit.createImage
+ * methods, and is basically immutable.
+ *
+ * @author Sven de Marothy
+ */
+public class GtkImage extends Image
+{
+ int width = -1, height = -1;
+
+ /**
+ * Properties.
+ */
+ Hashtable props;
+
+ /**
+ * Loaded or not flag, for asynchronous compatibility.
+ */
+ boolean isLoaded;
+
+ /**
+ * Pointer to the GdkPixbuf
+ */
+ RawData pixmap;
+
+ /**
+ * Observer queue.
+ */
+ Vector observers;
+
+ /**
+ * If offScreen is set, a GdkBitmap is wrapped and not a Pixbuf.
+ */
+ boolean offScreen;
+
+ /**
+ * Error flag for loading.
+ */
+ boolean errorLoading;
+
+ /**
+ * Original source, if created from an ImageProducer.
+ */
+ ImageProducer source;
+
+ /*
+ * The 32-bit AABBGGRR format the GDK uses.
+ */
+ static ColorModel nativeModel = new DirectColorModel(32,
+ 0x000000FF,
+ 0x0000FF00,
+ 0x00FF0000,
+ 0xFF000000);
+
+ /**
+ * Returns a copy of the pixel data as a java array.
+ */
+ private native int[] getPixels();
+
+ /**
+ * Sets the pixel data from a java array.
+ */
+ private native void setPixels(int[] pixels);
+
+ /**
+ * Loads an image using gdk-pixbuf.
+ */
+ private native boolean loadPixbuf(String name);
+
+ /**
+ * Allocates a Gtk Pixbuf or pixmap
+ */
+ private native void createPixmap();
+
+ /**
+ * Frees the above.
+ */
+ private native void freePixmap();
+
+ /**
+ * Sets the pixmap to scaled copy of src image. hints are rendering hints.
+ */
+ private native void createScaledPixmap(GtkImage src, int hints);
+
+ /**
+ * Draws the image, optionally scaled and composited.
+ */
+ private native void drawPixelsScaled (GdkGraphics gc,
+ int bg_red, int bg_green, int bg_blue,
+ int x, int y, int width, int height,
+ boolean composite);
+
+ /**
+ * Draws the image, optionally scaled flipped and composited.
+ */
+ private native void drawPixelsScaledFlipped (GdkGraphics gc,
+ int bg_red, int bg_green,
+ int bg_blue,
+ boolean flipX, boolean flipY,
+ int srcX, int srcY,
+ int srcWidth, int srcHeight,
+ int dstX, int dstY,
+ int dstWidth, int dstHeight,
+ boolean composite);
+
+ /**
+ * Constructs a GtkImage from an ImageProducer. Asynchronity is handled in
+ * the following manner:
+ * A GtkImageConsumer gets the image data, and calls setImage() when
+ * completely finished. The GtkImage is not considered loaded until the
+ * GtkImageConsumer is completely finished. We go for all "all or nothing".
+ */
+ public GtkImage (ImageProducer producer)
+ {
+ isLoaded = false;
+ observers = new Vector();
+ source = producer;
+ errorLoading = false;
+ source.startProduction(new GtkImageConsumer(this, source));
+ offScreen = false;
+ }
+
+ /**
+ * Constructs a GtkImage by loading a given file.
+ *
+ * @throws IllegalArgumentException if the image could not be loaded.
+ */
+ public GtkImage (String filename)
+ {
+ File f = new File(filename);
+ try
+ {
+ if (loadPixbuf(f.getCanonicalPath()) != true)
+ throw new IllegalArgumentException("Couldn't load image: "+filename);
+ }
+ catch(IOException e)
+ {
+ throw new IllegalArgumentException("Couldn't load image: "+filename);
+ }
+
+ isLoaded = true;
+ observers = null;
+ offScreen = false;
+ props = new Hashtable();
+ }
+
+ /**
+ * Constructs an empty GtkImage.
+ */
+ public GtkImage (int width, int height)
+ {
+ this.width = width;
+ this.height = height;
+ props = new Hashtable();
+ isLoaded = true;
+ observers = null;
+ offScreen = true;
+ createPixmap();
+ }
+
+ /**
+ * Constructs a scaled version of the src bitmap, using the GDK.
+ */
+ private GtkImage (GtkImage src, int width, int height, int hints)
+ {
+ this.width = width;
+ this.height = height;
+ props = new Hashtable();
+ isLoaded = true;
+ observers = null;
+ offScreen = false;
+
+ // Use the GDK scaling method.
+ createScaledPixmap(src, hints);
+ }
+
+ /**
+ * Callback from the image consumer.
+ */
+ public void setImage(int width, int height,
+ int[] pixels, Hashtable properties)
+ {
+ this.width = width;
+ this.height = height;
+ props = (properties != null) ? properties : new Hashtable();
+
+ if (width <= 0 || height <= 0 || pixels == null)
+ {
+ errorLoading = true;
+ return;
+ }
+
+ isLoaded = true;
+ deliver();
+ createPixmap();
+ setPixels(pixels);
+ }
+
+ // java.awt.Image methods ////////////////////////////////////////////////
+
+ public synchronized int getWidth (ImageObserver observer)
+ {
+ if (addObserver(observer))
+ return -1;
+
+ return width;
+ }
+
+ public synchronized int getHeight (ImageObserver observer)
+ {
+ if (addObserver(observer))
+ return -1;
+
+ return height;
+ }
+
+ public synchronized Object getProperty (String name, ImageObserver observer)
+ {
+ if (addObserver(observer))
+ return UndefinedProperty;
+
+ Object value = props.get (name);
+ return (value == null) ? UndefinedProperty : value;
+ }
+
+ /**
+ * Returns the source of this image.
+ */
+ public ImageProducer getSource ()
+ {
+ if (!isLoaded)
+ return null;
+ return new MemoryImageSource(width, height, nativeModel, getPixels(),
+ 0, width);
+ }
+
+ /**
+ * Creates a GdkGraphics context for this pixmap.
+ */
+ public Graphics getGraphics ()
+ {
+ if (!isLoaded)
+ return null;
+ if (offScreen)
+ return new GdkGraphics(this);
+ else
+ throw new IllegalAccessError("This method only works for off-screen"
+ +" Images.");
+ }
+
+ /**
+ * Returns a scaled instance of this pixmap.
+ */
+ public Image getScaledInstance(int width,
+ int height,
+ int hints)
+ {
+ if (width <= 0 || height <= 0)
+ throw new IllegalArgumentException("Width and height of scaled bitmap"+
+ "must be >= 0");
+
+ return new GtkImage(this, width, height, hints);
+ }
+
+ /**
+ * If the image is loaded and comes from an ImageProducer,
+ * regenerate the image from there.
+ *
+ * I have no idea if this is ever actually used. Since GtkImage can't be
+ * instantiated directly, how is the user to know if it was created from
+ * an ImageProducer or not?
+ */
+ public synchronized void flush ()
+ {
+ if (isLoaded && source != null)
+ {
+ observers = new Vector();
+ isLoaded = false;
+ freePixmap();
+ source.startProduction(new GtkImageConsumer(this, source));
+ }
+ }
+
+ public void finalize()
+ {
+ if (isLoaded)
+ freePixmap();
+ }
+
+ /**
+ * Returns the image status, used by GtkToolkit
+ */
+ public int checkImage (ImageObserver observer)
+ {
+ if (addObserver(observer))
+ {
+ if (errorLoading == true)
+ return ImageObserver.ERROR;
+ else
+ return 0;
+ }
+
+ return ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT;
+ }
+
+ // Drawing methods ////////////////////////////////////////////////
+
+ /**
+ * Draws an image with eventual scaling/transforming.
+ */
+ public boolean drawImage (GdkGraphics g, int dx1, int dy1, int dx2, int dy2,
+ int sx1, int sy1, int sx2, int sy2,
+ Color bgcolor, ImageObserver observer)
+ {
+ if (addObserver(observer))
+ return false;
+
+ boolean flipX = (dx1 > dx2)^(sx1 > sx2);
+ boolean flipY = (dy1 > dy2)^(sy1 > sy2);
+ int dstWidth = Math.abs (dx2 - dx1);
+ int dstHeight = Math.abs (dy2 - dy1);
+ int srcWidth = Math.abs (sx2 - sx1);
+ int srcHeight = Math.abs (sy2 - sy1);
+ int srcX = (sx1 < sx2) ? sx1 : sx2;
+ int srcY = (sy1 < sy2) ? sy1 : sy2;
+ int dstX = (dx1 < dx2) ? dx1 : dx2;
+ int dstY = (dy1 < dy2) ? dy1 : dy2;
+
+ // Clipping. This requires the dst to be scaled as well,
+ if (srcWidth > width)
+ {
+ dstWidth = (int)((double)dstWidth*((double)width/(double)srcWidth));
+ srcWidth = width - srcX;
+ }
+
+ if (srcHeight > height)
+ {
+ dstHeight = (int)((double)dstHeight*((double)height/(double)srcHeight));
+ srcHeight = height - srcY;
+ }
+
+ if (srcWidth + srcX > width)
+ {
+ dstWidth = (int)((double)dstWidth * (double)(width - srcX)/(double)srcWidth);
+ srcWidth = width - srcX;
+ }
+
+ if (srcHeight + srcY > height)
+ {
+ dstHeight = (int)((double)dstHeight * (double)(width - srcY)/(double)srcHeight);
+ srcHeight = height - srcY;
+ }
+
+ if ( srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0)
+ return true;
+
+ if(bgcolor != null)
+ drawPixelsScaledFlipped (g, bgcolor.getRed (), bgcolor.getGreen (),
+ bgcolor.getBlue (),
+ flipX, flipY,
+ srcX, srcY,
+ srcWidth, srcHeight,
+ dstX, dstY,
+ dstWidth, dstHeight,
+ true);
+ else
+ drawPixelsScaledFlipped (g, 0, 0, 0, flipX, flipY,
+ srcX, srcY, srcWidth, srcHeight,
+ dstX, dstY, dstWidth, dstHeight,
+ false);
+ return true;
+ }
+
+ /**
+ * Draws an image to the GdkGraphics context, at (x,y) scaled to
+ * width and height, with optional compositing with a background color.
+ */
+ public boolean drawImage (GdkGraphics g, int x, int y, int width, int height,
+ Color bgcolor, ImageObserver observer)
+ {
+ if (addObserver(observer))
+ return false;
+
+ if(bgcolor != null)
+ drawPixelsScaled(g, bgcolor.getRed (), bgcolor.getGreen (),
+ bgcolor.getBlue (), x, y, width, height, true);
+ else
+ drawPixelsScaled(g, 0, 0, 0, x, y, width, height, false);
+
+ return true;
+ }
+
+ // Private methods ////////////////////////////////////////////////
+
+ /**
+ * Delivers notifications to all queued observers.
+ */
+ private void deliver()
+ {
+ int flags = ImageObserver.HEIGHT |
+ ImageObserver.WIDTH |
+ ImageObserver.PROPERTIES |
+ ImageObserver.ALLBITS;
+
+ if (observers != null)
+ for(int i=0; i < observers.size(); i++)
+ ((ImageObserver)observers.elementAt(i)).
+ imageUpdate(this, flags, 0, 0, width, height);
+
+ observers = null;
+ }
+
+ /**
+ * Adds an observer, if we need to.
+ * @return true if an observer was added.
+ */
+ private boolean addObserver(ImageObserver observer)
+ {
+ if (!isLoaded)
+ {
+ if(observer != null)
+ if (!observers.contains (observer))
+ observers.addElement (observer);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java
new file mode 100644
index 0000000..564cc8d
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java
@@ -0,0 +1,155 @@
+/* GtkImageConsumer.java
+ Copyright (C) 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.image.ColorModel;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * Helper class to GtkImage. Sits and gathers pixels for a GtkImage and then
+ * calls GtkImage.setImage().
+ *
+ * @author Sven de Marothy
+ */
+public class GtkImageConsumer implements ImageConsumer
+{
+ private GtkImage target;
+ private int width, height;
+ private Hashtable properties;
+ private int[] pixelCache = null;
+ private ImageProducer source;
+
+ public GtkImageConsumer(GtkImage target, ImageProducer source)
+ {
+ this.target = target;
+ this.source = source;
+ }
+
+ public synchronized void imageComplete (int status)
+ {
+ source.removeConsumer(this);
+ target.setImage(width, height, pixelCache, properties);
+ }
+
+ public synchronized void setColorModel (ColorModel model)
+ {
+ // This method is to inform on what the most used color model
+ // in the image is, for optimization reasons. We ignore this
+ // information.
+ }
+
+ public synchronized void setDimensions (int width, int height)
+ {
+ pixelCache = new int[width*height];
+
+ this.width = width;
+ this.height = height;
+ }
+
+ public synchronized void setHints (int flags)
+ {
+ // This method informs us in which order the pixels are
+ // delivered, for progressive-loading support, etc.
+ // Since we wait until it's all loaded, we can ignore the hints.
+ }
+
+ public synchronized void setPixels (int x, int y, int width, int height,
+ ColorModel cm, byte[] pixels,
+ int offset, int scansize)
+ {
+ setPixels (x, y, width, height, cm, convertPixels (pixels), offset,
+ scansize);
+ }
+
+ public synchronized void setPixels (int x, int y, int width, int height,
+ ColorModel cm, int[] pixels,
+ int offset, int scansize)
+ {
+ if (pixelCache == null)
+ return; // Not sure this should ever happen.
+
+ if (cm.equals(GtkImage.nativeModel))
+ for (int i = 0; i < height; i++)
+ System.arraycopy (pixels, offset + (i * scansize),
+ pixelCache, (y + i) * this.width + x,
+ width);
+ else
+ {
+ for (int i = 0; i < height; i++)
+ for (int j = 0; j < width; j++)
+ {
+ // get in AARRGGBB and convert to AABBGGRR
+ int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]);
+ byte b = (byte)(pix & 0xFF);
+ byte r = (byte)(((pix & 0x00FF0000) >> 16) & 0xFF);
+ pix &= 0xFF00FF00;
+ pix |= ((b & 0xFF) << 16);
+ pix |= (r & 0xFF);
+ pixelCache[(y + i) * this.width + x + j] = pix;
+ }
+ }
+ }
+
+ /**
+ * This is an old method, no idea if it's correct.
+ */
+ private int[] convertPixels (byte[] pixels)
+ {
+ int ret[] = new int[pixels.length];
+
+ for (int i = 0; i < pixels.length; i++)
+ ret[i] = pixels[i] & 0xFF;
+
+ return ret;
+ }
+
+ public synchronized void setProperties (Hashtable props)
+ {
+ this.properties = props;
+ }
+}
+
+
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java
new file mode 100644
index 0000000..fdd5fd1
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java
@@ -0,0 +1,84 @@
+/* GtkLabelPeer.java -- Implements LabelPeer with GTK
+ Copyright (C) 1998, 1999, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Label;
+import java.awt.peer.LabelPeer;
+
+public class GtkLabelPeer extends GtkComponentPeer
+ implements LabelPeer
+{
+ native void create (String text, float alignment);
+ native void gtkWidgetModifyFont (String name, int style, int size);
+ native void nativeSetAlignment (float alignment);
+
+ public native void setText(String text);
+ native void setNativeBounds (int x, int y, int width, int height);
+
+ void create ()
+ {
+ Label label = (Label) awtComponent;
+ create (label.getText (), getGtkAlignment (label.getAlignment ()));
+ }
+
+ public GtkLabelPeer (Label l)
+ {
+ super (l);
+ }
+
+ public void setAlignment (int alignment)
+ {
+ nativeSetAlignment (getGtkAlignment (alignment));
+ }
+
+ float getGtkAlignment (int alignment)
+ {
+ switch (alignment)
+ {
+ case Label.LEFT:
+ return 0.0f;
+ case Label.CENTER:
+ return 0.5f;
+ case Label.RIGHT:
+ return 1.0f;
+ }
+
+ return 0.0f;
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java
new file mode 100644
index 0000000..ff12fe3
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java
@@ -0,0 +1,180 @@
+/* GtkListPeer.java -- Implements ListPeer with GTK
+ Copyright (C) 1998, 1999 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 gnu.java.awt.peer.gtk;
+
+import java.awt.AWTEvent;
+import java.awt.Dimension;
+import java.awt.List;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.peer.ListPeer;
+
+public class GtkListPeer extends GtkComponentPeer
+ implements ListPeer
+{
+ void create ()
+ {
+ List list = (List) awtComponent;
+
+ create (list.getRows ());
+
+ setMultipleMode (list.isMultipleMode ());
+ }
+
+ native void create (int rows);
+ native void connectSignals ();
+ native void gtkWidgetModifyFont (String name, int style, int size);
+ native void gtkWidgetRequestFocus ();
+
+ native void getSize (int rows, int visibleRows, int dims[]);
+
+ public GtkListPeer (List list)
+ {
+ super (list);
+
+ setMultipleMode (list.isMultipleMode ());
+
+ if (list.getItemCount () > 0)
+ append (list.getItems ());
+ }
+
+ native void append (String items[]);
+
+ public native void add (String item, int index);
+
+ public void addItem (String item, int index)
+ {
+ add (item, index);
+ }
+
+ public void clear ()
+ {
+ removeAll ();
+ }
+
+ public native void delItems (int start, int end);
+ public native void deselect (int index);
+
+ public Dimension getMinimumSize (int rows)
+ {
+ return minimumSize (rows);
+ }
+
+ public Dimension getPreferredSize (int rows)
+ {
+ return preferredSize (rows);
+ }
+
+ public native int[] getSelectedIndexes ();
+ public native void makeVisible (int index);
+
+ public Dimension minimumSize (int rows)
+ {
+ int dims[] = new int[2];
+
+ int visibleRows = ((List) awtComponent).getRows();
+ getSize (rows, visibleRows, dims);
+ return new Dimension (dims[0], dims[1]);
+ }
+
+ public Dimension preferredSize (int rows)
+ {
+ int dims[] = new int[2];
+
+ int visibleRows = ((List) awtComponent).getRows();
+ getSize (rows, visibleRows, dims);
+ return new Dimension (dims[0], dims[1]);
+ }
+
+ public void removeAll ()
+ {
+ delItems (0, -1);
+ }
+
+ public native void select (int index);
+ public native void setMultipleMode (boolean b);
+
+ public void setMultipleSelections (boolean b)
+ {
+ setMultipleMode (b);
+ }
+
+ public void handleEvent (AWTEvent e)
+ {
+ if (e.getID () == MouseEvent.MOUSE_CLICKED && isEnabled ())
+ {
+ // Only generate the ActionEvent on the second click of a
+ // multiple click.
+ MouseEvent me = (MouseEvent) e;
+ if (!me.isConsumed ()
+ && (me.getModifiersEx () & MouseEvent.BUTTON1_DOWN_MASK) != 0
+ && me.getClickCount() == 2)
+ {
+ String selectedItem = ((List) awtComponent).getSelectedItem ();
+
+ // Double-click only generates an Action event if
+ // something is selected.
+ if (selectedItem != null)
+ postActionEvent (((List) awtComponent).getSelectedItem (),
+ me.getModifiersEx ());
+ }
+ }
+
+ if (e.getID () == KeyEvent.KEY_PRESSED)
+ {
+ KeyEvent ke = (KeyEvent) e;
+ if (!ke.isConsumed () && ke.getKeyCode () == KeyEvent.VK_ENTER)
+ {
+ String selectedItem = ((List) awtComponent).getSelectedItem ();
+
+ // Enter only generates an Action event if something is
+ // selected.
+ if (selectedItem != null)
+ postActionEvent (selectedItem, ke.getModifiersEx ());
+ }
+ }
+
+ super.handleEvent (e);
+ }
+
+ protected void postItemEvent (int item, int stateChange)
+ {
+ postItemEvent (new Integer (item), stateChange);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java
new file mode 100644
index 0000000..79eeaf9
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java
@@ -0,0 +1,80 @@
+/* GtkMenuBarPeer.java -- Implements MenuBarPeer with GTK+
+ Copyright (C) 1999, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Font;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuComponent;
+import java.awt.peer.MenuBarPeer;
+import java.awt.peer.MenuPeer;
+
+public class GtkMenuBarPeer extends GtkMenuComponentPeer
+ implements MenuBarPeer
+{
+
+ native void create ();
+ native void addMenu (MenuPeer menu);
+
+ public GtkMenuBarPeer (MenuBar target)
+ {
+ super (target);
+ }
+
+ void setFont ()
+ {
+ MenuComponent mc = (MenuComponent) awtWidget;
+ Font f = mc.getFont ();
+
+ if (f == null)
+ mc.setFont (new Font ("Dialog", Font.PLAIN, 12));
+ }
+
+ // FIXME: remove this method or replace it with one that does
+ // something useful.
+ /* In Gnome, help menus are no longer right flushed. */
+ native void nativeSetHelpMenu(MenuPeer menuPeer);
+
+ public void addHelpMenu (Menu menu)
+ {
+ // nativeSetHelpMenu((MenuPeer) menu.getPeer());
+ }
+
+ public native void delMenu(int index);
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java
new file mode 100644
index 0000000..8d9d1ca
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java
@@ -0,0 +1,63 @@
+/* GtkMenuComponentPeer.java -- Implements MenuComponentPeer with GTK+
+ Copyright (C) 1999 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 gnu.java.awt.peer.gtk;
+
+import java.awt.peer.MenuComponentPeer;
+
+public class GtkMenuComponentPeer extends GtkGenericPeer
+ implements MenuComponentPeer
+{
+ void create ()
+ {
+ throw new RuntimeException ();
+ }
+
+ void setFont ()
+ {
+ }
+
+ public GtkMenuComponentPeer (Object awtWidget)
+ {
+ super (awtWidget);
+ create ();
+ setFont ();
+ }
+
+ public native void dispose();
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java
new file mode 100644
index 0000000..5728f26
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java
@@ -0,0 +1,120 @@
+/* GtkMenuItemPeer.java -- Implements MenuItemPeer with GTK+
+ Copyright (C) 1999, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Font;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuComponent;
+import java.awt.MenuItem;
+import java.awt.peer.MenuItemPeer;
+import java.awt.peer.MenuPeer;
+
+public class GtkMenuItemPeer extends GtkMenuComponentPeer
+ implements MenuItemPeer
+{
+ native void create (String label);
+ native void connectSignals ();
+ native void gtkWidgetModifyFont (String name, int style, int size);
+
+ void create ()
+ {
+ create (((MenuItem) awtWidget).getLabel());
+ }
+
+ public GtkMenuItemPeer (MenuItem item)
+ {
+ super (item);
+ setEnabled (item.isEnabled ());
+ setParent (item);
+
+ if (item.getParent() instanceof Menu && ! (item instanceof Menu))
+ connectSignals();
+ }
+
+ void setFont ()
+ {
+ MenuComponent mc = ((MenuComponent) awtWidget);
+ Font f = mc.getFont ();
+
+ if (f == null)
+ {
+ MenuComponent parent = (MenuComponent) mc.getParent ();
+ Font pf = parent.getFont ();
+ gtkWidgetModifyFont (pf.getName (), pf.getStyle (), pf.getSize ());
+ }
+ else
+ gtkWidgetModifyFont(f.getName(), f.getStyle(), f.getSize());
+ }
+
+ void setParent (MenuItem item)
+ {
+ // add ourself differently, based on what type of parent we have
+ // yes, the typecasting here is nasty.
+ Object parent = item.getParent ();
+ if (parent instanceof MenuBar)
+ {
+ ((GtkMenuBarPeer)((MenuBar)parent).getPeer ()).addMenu ((MenuPeer) this);
+ }
+ else // parent instanceof Menu
+ {
+ ((GtkMenuPeer)((Menu)parent).getPeer ()).addItem (this,
+ item.getShortcut ());
+ }
+ }
+
+ public void disable ()
+ {
+ setEnabled (false);
+ }
+
+ public void enable ()
+ {
+ setEnabled (true);
+ }
+
+ public native void setEnabled(boolean b);
+
+ public native void setLabel(String label);
+
+ protected void postMenuActionEvent ()
+ {
+ postActionEvent (((MenuItem)awtWidget).getActionCommand (), 0);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java
new file mode 100644
index 0000000..80332dd
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java
@@ -0,0 +1,103 @@
+/* GtkMenuPeer.java -- Implements MenuPeer with GTK+
+ Copyright (C) 1999, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Component;
+import java.awt.Menu;
+import java.awt.MenuContainer;
+import java.awt.MenuItem;
+import java.awt.MenuShortcut;
+import java.awt.peer.MenuItemPeer;
+import java.awt.peer.MenuPeer;
+
+public class GtkMenuPeer extends GtkMenuItemPeer
+ implements MenuPeer
+{
+ native void create (String label);
+ native void addItem (MenuItemPeer item, int key, boolean shiftModifier);
+ native void setupAccelGroup (GtkGenericPeer container);
+ native void addTearOff ();
+
+ public GtkMenuPeer (Menu menu)
+ {
+ super (menu);
+
+ if (menu.isTearOff())
+ addTearOff();
+
+ MenuContainer parent = menu.getParent ();
+ if (parent instanceof Menu)
+ setupAccelGroup ((GtkGenericPeer)((Menu)parent).getPeer ());
+ else if (parent instanceof Component)
+ setupAccelGroup ((GtkGenericPeer)((Component)parent).getPeer ());
+ else
+ setupAccelGroup (null);
+ }
+
+ public void addItem (MenuItem item)
+ {
+ int key = 0;
+ boolean shiftModifier = false;
+
+ MenuShortcut ms = item.getShortcut ();
+ if (ms != null)
+ {
+ key = ms.getKey ();
+ shiftModifier = ms.usesShiftModifier ();
+ }
+
+ addItem ((MenuItemPeer) item.getPeer (), key, shiftModifier);
+ }
+
+ public void addItem (MenuItemPeer item, MenuShortcut ms)
+ {
+ int key = 0;
+ boolean shiftModifier = false;
+
+ if (ms != null)
+ {
+ key = ms.getKey ();
+ shiftModifier = ms.usesShiftModifier ();
+ }
+
+ addItem (item, key, shiftModifier);
+ }
+
+ public native void delItem(int index);
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java
new file mode 100644
index 0000000..fb5adde
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java
@@ -0,0 +1,70 @@
+/* GtkPanelPeer.java -- Implements PanelPeer with GTK
+ Copyright (C) 1998, 1999 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 gnu.java.awt.peer.gtk;
+
+import java.awt.AWTEvent;
+import java.awt.Panel;
+import java.awt.event.MouseEvent;
+import java.awt.peer.PanelPeer;
+
+public class GtkPanelPeer extends GtkContainerPeer
+ implements PanelPeer
+{
+ native void create ();
+
+ public GtkPanelPeer (Panel p)
+ {
+ super (p);
+ }
+
+ public void handleEvent (AWTEvent event)
+ {
+ int id = event.getID();
+
+ switch (id)
+ {
+ case MouseEvent.MOUSE_PRESSED:
+ awtComponent.requestFocusInWindow ();
+ break;
+ }
+ super.handleEvent (event);
+ }
+
+ native void connectSignals ();
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java
new file mode 100644
index 0000000..d14c16d
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java
@@ -0,0 +1,74 @@
+/* GtkPopupMenuPeer.java -- Implements PopupMenuPeer with GTK+
+ Copyright (C) 1999 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Component;
+import java.awt.Event;
+import java.awt.MenuItem;
+import java.awt.Point;
+import java.awt.PopupMenu;
+import java.awt.peer.PopupMenuPeer;
+
+public class GtkPopupMenuPeer extends GtkMenuPeer
+ implements PopupMenuPeer
+{
+ public GtkPopupMenuPeer (PopupMenu menu)
+ {
+ super (menu);
+ }
+
+ native void setupAccelGroup (GtkGenericPeer container);
+
+ void setParent (MenuItem item)
+ {
+ // we don't need to "add" ourselves to our parent
+ }
+
+ native void show (int x, int y, long time);
+ public void show (Component origin, int x, int y)
+ {
+ Point abs = origin.getLocationOnScreen ();
+ show (abs.x + x, abs.y + y, 0);
+ }
+
+ public void show (Event e)
+ {
+
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java
new file mode 100644
index 0000000..69f8b49
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java
@@ -0,0 +1,113 @@
+/* GtkScrollPanePeer.java -- Implements ScrollPanePeer with GTK
+ Copyright (C) 1998, 1999, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Adjustable;
+import java.awt.Dimension;
+import java.awt.ScrollPane;
+import java.awt.peer.ScrollPanePeer;
+
+public class GtkScrollPanePeer extends GtkContainerPeer
+ implements ScrollPanePeer
+{
+ native void create (int width, int height);
+
+ void create ()
+ {
+ create (awtComponent.getWidth (), awtComponent.getHeight ());
+ }
+
+ // native void gtkScrolledWindowSetScrollPosition(int x, int y);
+ native void gtkScrolledWindowSetHScrollIncrement (int u);
+ native void gtkScrolledWindowSetVScrollIncrement (int u);
+
+ public GtkScrollPanePeer (ScrollPane sp)
+ {
+ super (sp);
+
+ setPolicy (sp.getScrollbarDisplayPolicy ());
+ }
+
+ native void setPolicy (int policy);
+ public void childResized (int width, int height)
+ {
+ int dim[] = new int[2];
+
+ gtkWidgetGetDimensions (dim);
+
+ // If the child is in this range, GTK adds both scrollbars, but
+ // the AWT doesn't. So set the peer's scroll policy to
+ // GTK_POLICY_NEVER.
+ if ((width > dim[0] - getVScrollbarWidth ()
+ && width <= dim[0])
+ && (height > dim[1] - getHScrollbarHeight ()
+ && height <= dim[1]))
+ setPolicy (ScrollPane.SCROLLBARS_NEVER);
+ else
+ setPolicy (((ScrollPane) awtComponent).getScrollbarDisplayPolicy ());
+ }
+
+ public native int getHScrollbarHeight();
+ public native int getVScrollbarWidth();
+ public native void setScrollPosition(int x, int y);
+
+ public Dimension getPreferredSize ()
+ {
+ return awtComponent.getSize();
+ }
+
+ public void setUnitIncrement (Adjustable adj, int u)
+ {
+ if (adj.getOrientation()==Adjustable.HORIZONTAL)
+ gtkScrolledWindowSetHScrollIncrement (u);
+ else
+ gtkScrolledWindowSetVScrollIncrement (u);
+ }
+
+ public void setValue (Adjustable adj, int v)
+ {
+// System.out.println("SPP: setVal: "+adj+":"+v);
+// Point p=myScrollPane.getScrollPosition ();
+// if (adj.getOrientation()==Adjustable.HORIZONTAL)
+// gtkScrolledWindowSetScrollPosition (v,p.y);
+// else
+// gtkScrolledWindowSetScrollPosition (p.x,v);
+// adj.setValue(v);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java
new file mode 100644
index 0000000..aa3a26e
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java
@@ -0,0 +1,80 @@
+/* GtkScrollbarPeer.java -- Implements ScrollbarPeer with GTK+
+ Copyright (C) 1998, 1999, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Adjustable;
+import java.awt.Scrollbar;
+import java.awt.event.AdjustmentEvent;
+import java.awt.peer.ScrollbarPeer;
+
+public class GtkScrollbarPeer extends GtkComponentPeer
+ implements ScrollbarPeer
+{
+ void create ()
+ {
+ Scrollbar sb = (Scrollbar) awtComponent;
+
+ create (sb.getOrientation (), sb.getValue (),
+ sb.getMinimum (), sb.getMaximum (),
+ sb.getUnitIncrement (), sb.getBlockIncrement (),
+ sb.getVisibleAmount ());
+ }
+
+ native void create (int orientation, int value,
+ int min, int max, int stepIncr, int pageIncr,
+ int visibleAmount);
+
+ native void connectSignals ();
+
+ public GtkScrollbarPeer (Scrollbar s)
+ {
+ super (s);
+ }
+
+ public native void setLineIncrement(int amount);
+ public native void setPageIncrement(int amount);
+ public native void setValues(int value, int visible, int min, int max);
+
+ protected void postAdjustmentEvent (int type, int value)
+ {
+ q().postEvent (new AdjustmentEvent ((Adjustable)awtComponent,
+ AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED,
+ type, value));
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java
new file mode 100644
index 0000000..a842b83
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java
@@ -0,0 +1,212 @@
+/* GtkTextAreaPeer.java -- Implements TextAreaPeer with GTK
+ Copyright (C) 1998, 1999, 2002 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Rectangle;
+import java.awt.TextArea;
+import java.awt.peer.TextAreaPeer;
+import java.awt.peer.TextComponentPeer;
+
+public class GtkTextAreaPeer extends GtkComponentPeer
+ implements TextComponentPeer, TextAreaPeer
+{
+ private static transient int DEFAULT_ROWS = 10;
+ private static transient int DEFAULT_COLS = 80;
+
+ native void create (int width, int height, int scrollbarVisibility);
+
+ native void gtkWidgetModifyFont (String name, int style, int size);
+ native void gtkWidgetRequestFocus ();
+
+ public native void connectSignals ();
+
+ public native int getCaretPosition ();
+ public native void setCaretPosition (int pos);
+ public native int getSelectionStart ();
+ public native int getSelectionEnd ();
+ public native String getText ();
+ public native void select (int start, int end);
+ public native void setEditable (boolean state);
+ public native void setText (String text);
+
+ public int getIndexAtPoint(int x, int y)
+ {
+ // FIXME
+ return 0;
+ }
+
+ public Rectangle getCharacterBounds (int pos)
+ {
+ // FIXME
+ return null;
+ }
+
+ public long filterEvents (long filter)
+ {
+ // FIXME
+ return filter;
+ }
+
+ void create ()
+ {
+ Font f = awtComponent.getFont ();
+
+ // By default, Sun sets a TextArea's font when its peer is
+ // created. If f != null then the peer's font is set by
+ // GtkComponent.create.
+ if (f == null)
+ {
+ f = new Font ("Dialog", Font.PLAIN, 12);
+ awtComponent.setFont (f);
+ }
+
+ FontMetrics fm = getFontMetrics (f);
+
+ TextArea ta = ((TextArea) awtComponent);
+ int sizeRows = ta.getRows ();
+ int sizeCols = ta.getColumns ();
+
+ sizeRows = sizeRows == 0 ? DEFAULT_ROWS : sizeRows;
+ sizeCols = sizeCols == 0 ? DEFAULT_COLS : sizeCols;
+
+ int width = sizeCols * fm.getMaxAdvance ();
+ int height = sizeRows * (fm.getMaxDescent () + fm.getMaxAscent ());
+
+ create (width, height, ta.getScrollbarVisibility ());
+ setEditable (ta.isEditable ());
+ }
+
+ public GtkTextAreaPeer (TextArea ta)
+ {
+ super (ta);
+
+ setText (ta.getText ());
+ setCaretPosition (0);
+ }
+
+ public native void insert (String str, int pos);
+ public native void replaceRange (String str, int start, int end);
+
+ public Dimension getMinimumSize (int rows, int cols)
+ {
+ return minimumSize (rows == 0 ? DEFAULT_ROWS : rows,
+ cols == 0 ? DEFAULT_COLS : cols);
+ }
+
+ public Dimension getPreferredSize (int rows, int cols)
+ {
+ return preferredSize (rows == 0 ? DEFAULT_ROWS : rows,
+ cols == 0 ? DEFAULT_COLS : cols);
+ }
+
+ native int getHScrollbarHeight ();
+ native int getVScrollbarWidth ();
+
+ // Deprecated
+ public Dimension minimumSize (int rows, int cols)
+ {
+ TextArea ta = ((TextArea) awtComponent);
+ int height = 0;
+ int width = 0;
+
+ if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH
+ || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_HORIZONTAL_ONLY)
+ height = getHScrollbarHeight ();
+
+ if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH
+ || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_VERTICAL_ONLY)
+ width = getVScrollbarWidth ();
+
+ Font f = awtComponent.getFont ();
+ if (f == null)
+ return new Dimension (width, height);
+
+ FontMetrics fm = getFontMetrics (f);
+
+ int sizeRows = rows == 0 ? DEFAULT_ROWS : rows;
+ int sizeCols = cols == 0 ? DEFAULT_COLS : cols;
+
+ width += sizeCols * fm.getMaxAdvance ();
+ height += sizeRows * (fm.getMaxDescent () + fm.getMaxAscent ());
+
+ return new Dimension (width, height);
+ }
+
+ public Dimension preferredSize (int rows, int cols)
+ {
+ TextArea ta = ((TextArea) awtComponent);
+ int height = 0;
+ int width = 0;
+
+ if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH
+ || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_HORIZONTAL_ONLY)
+ height = getHScrollbarHeight ();
+
+ if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH
+ || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_VERTICAL_ONLY)
+ width = getVScrollbarWidth ();
+
+ Font f = awtComponent.getFont ();
+ if (f == null)
+ return new Dimension (width, height);
+
+ FontMetrics fm = getFontMetrics (f);
+
+ int sizeRows = rows == 0 ? DEFAULT_ROWS : rows;
+ int sizeCols = cols == 0 ? DEFAULT_COLS : cols;
+
+ width += sizeCols * fm.getMaxAdvance ();
+ height += sizeRows * (fm.getMaxDescent () + fm.getMaxAscent ());
+
+ return new Dimension (width, height);
+ }
+
+ public void replaceText (String str, int start, int end)
+ {
+ replaceRange (str, start, end);
+ }
+
+ public void insertText (String str, int pos)
+ {
+ insert (str, pos);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java
new file mode 100644
index 0000000..73a976b
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java
@@ -0,0 +1,196 @@
+/* GtkTextFieldPeer.java -- Implements TextFieldPeer with GTK
+ Copyright (C) 1998, 1999, 2002 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 gnu.java.awt.peer.gtk;
+
+import java.awt.AWTEvent;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Rectangle;
+import java.awt.TextField;
+import java.awt.event.KeyEvent;
+import java.awt.peer.TextFieldPeer;
+import java.awt.peer.TextComponentPeer;
+
+public class GtkTextFieldPeer extends GtkComponentPeer
+ implements TextComponentPeer, TextFieldPeer
+{
+ native void create (int width);
+ native void gtkWidgetSetBackground (int red, int green, int blue);
+ native void gtkWidgetSetForeground (int red, int green, int blue);
+
+ public native void connectSignals ();
+
+ public native int getCaretPosition ();
+ public native void setCaretPosition (int pos);
+ public native int getSelectionStart ();
+ public native int getSelectionEnd ();
+ public native String getText ();
+ public native void select (int start, int end);
+ public native void setEditable (boolean state);
+ public native void setText (String text);
+
+ public int getIndexAtPoint(int x, int y)
+ {
+ // FIXME
+ return 0;
+ }
+
+ public Rectangle getCharacterBounds (int pos)
+ {
+ // FIXME
+ return null;
+ }
+
+ public long filterEvents (long filter)
+ {
+ // FIXME
+ return filter;
+ }
+
+ void create ()
+ {
+ Font f = awtComponent.getFont ();
+
+ // By default, Sun sets a TextField's font when its peer is
+ // created. If f != null then the peer's font is set by
+ // GtkComponent.create.
+ if (f == null)
+ {
+ f = new Font ("Dialog", Font.PLAIN, 12);
+ awtComponent.setFont (f);
+ }
+
+ FontMetrics fm = getFontMetrics (f);
+
+ TextField tf = ((TextField) awtComponent);
+ int cols = tf.getColumns ();
+
+ int text_width = cols * fm.getMaxAdvance ();
+
+ create (text_width);
+
+ setEditable (tf.isEditable ());
+ }
+
+ native int gtkEntryGetBorderWidth ();
+
+ native void gtkWidgetModifyFont (String name, int style, int size);
+
+ public GtkTextFieldPeer (TextField tf)
+ {
+ super (tf);
+
+ setText (tf.getText ());
+ setCaretPosition (0);
+
+ if (tf.echoCharIsSet ())
+ setEchoChar (tf.getEchoChar ());
+ }
+
+ public Dimension getMinimumSize (int cols)
+ {
+ return minimumSize (cols);
+ }
+
+ public Dimension getPreferredSize (int cols)
+ {
+ return preferredSize (cols);
+ }
+
+ public native void setEchoChar (char c);
+
+ // Deprecated
+ public Dimension minimumSize (int cols)
+ {
+ int dim[] = new int[2];
+
+ gtkWidgetGetPreferredDimensions (dim);
+
+ Font f = awtComponent.getFont ();
+ if (f == null)
+ return new Dimension (2 * gtkEntryGetBorderWidth (), dim[1]);
+
+ FontMetrics fm = getFontMetrics (f);
+
+ int text_width = cols * fm.getMaxAdvance ();
+
+ int width = text_width + 2 * gtkEntryGetBorderWidth ();
+
+ return new Dimension (width, dim[1]);
+ }
+
+ public Dimension preferredSize (int cols)
+ {
+ int dim[] = new int[2];
+
+ gtkWidgetGetPreferredDimensions (dim);
+
+ Font f = awtComponent.getFont ();
+ if (f == null)
+ return new Dimension (2 * gtkEntryGetBorderWidth (), dim[1]);
+
+ FontMetrics fm = getFontMetrics (f);
+
+ int text_width = cols * fm.getMaxAdvance ();
+
+ int width = text_width + 2 * gtkEntryGetBorderWidth ();
+
+ return new Dimension (width, dim[1]);
+ }
+
+ public void setEchoCharacter (char c)
+ {
+ setEchoChar (c);
+ }
+
+ public void handleEvent (AWTEvent e)
+ {
+ if (e.getID () == KeyEvent.KEY_PRESSED)
+ {
+ KeyEvent ke = (KeyEvent) e;
+
+ if (!ke.isConsumed ()
+ && ke.getKeyCode () == KeyEvent.VK_ENTER)
+ postActionEvent (getText (), ke.getModifiersEx ());
+ }
+
+ super.handleEvent (e);
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java
new file mode 100644
index 0000000..6990110
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java
@@ -0,0 +1,653 @@
+/* GtkToolkit.java -- Implements an AWT Toolkit using GTK for peers
+ Copyright (C) 1998, 1999, 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 gnu.java.awt.peer.gtk;
+
+import gnu.classpath.Configuration;
+import gnu.java.awt.EmbeddedWindow;
+import gnu.java.awt.peer.ClasspathFontPeer;
+import gnu.java.awt.peer.ClasspathTextLayoutPeer;
+import gnu.java.awt.peer.EmbeddedWindowPeer;
+
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.dnd.DragGestureEvent;
+import java.awt.dnd.peer.DragSourceContextPeer;
+import java.awt.font.FontRenderContext;
+import java.awt.im.InputMethodHighlight;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.peer.*;
+import java.io.InputStream;
+import java.net.URL;
+import java.text.AttributedString;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.imageio.spi.IIORegistry;
+
+/* This class uses a deprecated method java.awt.peer.ComponentPeer.getPeer().
+ This merits comment. We are basically calling Sun's bluff on this one.
+ We think Sun has deprecated it simply to discourage its use as it is
+ bad programming style. However, we need to get at a component's peer in
+ this class. If getPeer() ever goes away, we can implement a hash table
+ that will keep up with every window's peer, but for now this is faster. */
+
+/**
+ * This class accesses a system property called
+ * gnu.java.awt.peer.gtk.Graphics. If the property is defined and
+ * equal to "Graphics2D", the cairo-based GdkGraphics2D will be used in
+ * drawing contexts. Any other value will cause the older GdkGraphics
+ * object to be used.
+ */
+public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
+{
+ Hashtable containers = new Hashtable();
+ static EventQueue q;
+ static Clipboard systemClipboard;
+ static boolean useGraphics2dSet;
+ static boolean useGraphics2d;
+
+ public static boolean useGraphics2D()
+ {
+ if (useGraphics2dSet)
+ return useGraphics2d;
+ useGraphics2d = System.getProperty("gnu.java.awt.peer.gtk.Graphics",
+ "Graphics").equals("Graphics2D");
+ useGraphics2dSet = true;
+ return useGraphics2d;
+ }
+
+ static native void gtkInit(int portableNativeSync);
+
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ System.loadLibrary("gtkpeer");
+
+ int portableNativeSync;
+ String portNatSyncProp =
+ System.getProperty("gnu.classpath.awt.gtk.portable.native.sync");
+
+ if (portNatSyncProp == null)
+ portableNativeSync = -1; // unset
+ else if (Boolean.valueOf(portNatSyncProp).booleanValue())
+ portableNativeSync = 1; // true
+ else
+ portableNativeSync = 0; // false
+
+ gtkInit(portableNativeSync);
+ }
+
+ public GtkToolkit ()
+ {
+ systemClipboard = new GtkClipboard ();
+ }
+
+ public native void beep();
+ private native void getScreenSizeDimensions(int[] xy);
+
+ public int checkImage (Image image, int width, int height,
+ ImageObserver observer)
+ {
+ int status = ImageObserver.ALLBITS
+ | ImageObserver.WIDTH
+ | ImageObserver.HEIGHT;
+
+ if (image instanceof GtkImage)
+ return ((GtkImage) image).checkImage (observer);
+
+ if (observer != null)
+ observer.imageUpdate (image, status,
+ -1, -1,
+ image.getWidth (observer),
+ image.getHeight (observer));
+
+ return status;
+ }
+
+ /**
+ * A helper class to return to clients in cases where a BufferedImage is
+ * desired but its construction fails.
+ */
+ private class GtkErrorImage extends Image
+ {
+ public GtkErrorImage()
+ {
+ }
+
+ public int getWidth(ImageObserver observer)
+ {
+ return -1;
+ }
+
+ public int getHeight(ImageObserver observer)
+ {
+ return -1;
+ }
+
+ public ImageProducer getSource()
+ {
+
+ return new ImageProducer()
+ {
+ HashSet consumers = new HashSet();
+ public void addConsumer(ImageConsumer ic)
+ {
+ consumers.add(ic);
+ }
+
+ public boolean isConsumer(ImageConsumer ic)
+ {
+ return consumers.contains(ic);
+ }
+
+ public void removeConsumer(ImageConsumer ic)
+ {
+ consumers.remove(ic);
+ }
+
+ public void startProduction(ImageConsumer ic)
+ {
+ consumers.add(ic);
+ Iterator i = consumers.iterator();
+ while(i.hasNext())
+ {
+ ImageConsumer c = (ImageConsumer) i.next();
+ c.imageComplete(ImageConsumer.IMAGEERROR);
+ }
+ }
+ public void requestTopDownLeftRightResend(ImageConsumer ic)
+ {
+ startProduction(ic);
+ }
+ };
+ }
+
+ public Graphics getGraphics()
+ {
+ return null;
+ }
+
+ public Object getProperty(String name, ImageObserver observer)
+ {
+ return null;
+ }
+ public Image getScaledInstance(int width, int height, int flags)
+ {
+ return new GtkErrorImage();
+ }
+
+ public void flush()
+ {
+ }
+ }
+
+
+ /**
+ * Helper to return either a BufferedImage -- the argument -- or a
+ * GtkErrorImage if the argument is null.
+ */
+
+ private Image bufferedImageOrError(BufferedImage b)
+ {
+ if (b == null)
+ return new GtkErrorImage();
+ else
+ return b;
+ }
+
+
+ public Image createImage (String filename)
+ {
+ if (useGraphics2D())
+ return bufferedImageOrError(GdkPixbufDecoder.createBufferedImage (filename));
+ else
+ return new GtkImage (filename);
+ }
+
+ public Image createImage (URL url)
+ {
+ if (useGraphics2D())
+ return bufferedImageOrError(GdkPixbufDecoder.createBufferedImage (url));
+ else
+ {
+ GdkPixbufDecoder d = new GdkPixbufDecoder (url);
+ GtkImage image = new GtkImage (d);
+ return image;
+ }
+ }
+
+ public Image createImage (ImageProducer producer)
+ {
+ if (useGraphics2D())
+ return bufferedImageOrError(GdkPixbufDecoder.createBufferedImage (producer));
+ else
+ return new GtkImage (producer);
+ }
+
+ public Image createImage (byte[] imagedata, int imageoffset,
+ int imagelength)
+ {
+ if (useGraphics2D())
+ return bufferedImageOrError(GdkPixbufDecoder.createBufferedImage (imagedata,
+ imageoffset,
+ imagelength));
+ else
+ {
+ GdkPixbufDecoder d = new GdkPixbufDecoder (imagedata,
+ imageoffset,
+ imagelength);
+ GtkImage image = new GtkImage (d);
+ return image;
+ }
+ }
+
+ /**
+ * Creates an ImageProducer from the specified URL. The image is assumed
+ * to be in a recognised format.
+ *
+ * @param url URL to read image data from.
+ */
+ public ImageProducer createImageProducer(URL url)
+ {
+ return new GdkPixbufDecoder(url);
+ }
+
+ /**
+ * Returns the native color model (which isn't the same as the default
+ * ARGB color model, but doesn't have to be).
+ */
+ public ColorModel getColorModel ()
+ {
+ /* Return the GDK-native ABGR format */
+ return new DirectColorModel(32,
+ 0x000000FF,
+ 0x0000FF00,
+ 0x00FF0000,
+ 0xFF000000);
+ }
+
+ public String[] getFontList ()
+ {
+ return (new String[] { "Dialog",
+ "DialogInput",
+ "Monospaced",
+ "Serif",
+ "SansSerif" });
+ }
+
+ private class LRUCache extends LinkedHashMap
+ {
+ int max_entries;
+ public LRUCache(int max)
+ {
+ super(max, 0.75f, true);
+ max_entries = max;
+ }
+ protected boolean removeEldestEntry(Map.Entry eldest)
+ {
+ return size() > max_entries;
+ }
+ }
+
+ private LRUCache fontCache = new LRUCache(50);
+ private LRUCache metricsCache = new LRUCache(50);
+ private LRUCache imageCache = new LRUCache(50);
+
+ public FontMetrics getFontMetrics (Font font)
+ {
+ synchronized (metricsCache)
+ {
+ if (metricsCache.containsKey(font))
+ return (FontMetrics) metricsCache.get(font);
+ }
+
+ FontMetrics m = new GdkFontMetrics (font);
+ synchronized (metricsCache)
+ {
+ metricsCache.put(font, m);
+ }
+ return m;
+ }
+
+ public Image getImage (String filename)
+ {
+ if (imageCache.containsKey(filename))
+ return (Image) imageCache.get(filename);
+ else
+ {
+ Image im = createImage(filename);
+ imageCache.put(filename, im);
+ return im;
+ }
+ }
+
+ public Image getImage (URL url)
+ {
+ if (imageCache.containsKey(url))
+ return (Image) imageCache.get(url);
+ else
+ {
+ Image im = createImage(url);
+ imageCache.put(url, im);
+ return im;
+ }
+ }
+
+ public PrintJob getPrintJob (Frame frame, String jobtitle, Properties props)
+ {
+ return null;
+ }
+
+ public native int getScreenResolution();
+
+ public Dimension getScreenSize ()
+ {
+ int dim[] = new int[2];
+ getScreenSizeDimensions(dim);
+ return new Dimension(dim[0], dim[1]);
+ }
+
+ public Clipboard getSystemClipboard()
+ {
+ return systemClipboard;
+ }
+
+ /**
+ * Prepares a GtkImage. For every other kind of Image it just
+ * assumes the image is already prepared for rendering.
+ */
+ public boolean prepareImage (Image image, int width, int height,
+ ImageObserver observer)
+ {
+ /* GtkImages are always prepared, as long as they're loaded. */
+ if (image instanceof GtkImage)
+ return ((((GtkImage)image).checkImage (observer) &
+ ImageObserver.ALLBITS) != 0);
+
+ /* Assume anything else is too */
+ return true;
+ }
+
+ public native void sync();
+
+ protected void setComponentState (Component c, GtkComponentPeer cp)
+ {
+ /* Make the Component reflect Peer defaults */
+ if (c.getForeground () == null)
+ c.setForeground (cp.getForeground ());
+ if (c.getBackground () == null)
+ c.setBackground (cp.getBackground ());
+ // if (c.getFont () == null)
+ // c.setFont (cp.getFont ());
+
+ /* Make the Peer reflect the state of the Component */
+ if (! (c instanceof Window))
+ {
+ cp.setCursor (c.getCursor ());
+
+ Rectangle bounds = c.getBounds ();
+ cp.setBounds (bounds.x, bounds.y, bounds.width, bounds.height);
+ cp.setVisible (c.isVisible ());
+ }
+ }
+
+ protected ButtonPeer createButton (Button b)
+ {
+ return new GtkButtonPeer (b);
+ }
+
+ protected CanvasPeer createCanvas (Canvas c)
+ {
+ return new GtkCanvasPeer (c);
+ }
+
+ protected CheckboxPeer createCheckbox (Checkbox cb)
+ {
+ return new GtkCheckboxPeer (cb);
+ }
+
+ protected CheckboxMenuItemPeer createCheckboxMenuItem (CheckboxMenuItem cmi)
+ {
+ return new GtkCheckboxMenuItemPeer (cmi);
+ }
+
+ protected ChoicePeer createChoice (Choice c)
+ {
+ return new GtkChoicePeer (c);
+ }
+
+ protected DialogPeer createDialog (Dialog d)
+ {
+ return new GtkDialogPeer (d);
+ }
+
+ protected FileDialogPeer createFileDialog (FileDialog fd)
+ {
+ return new GtkFileDialogPeer (fd);
+ }
+
+ protected FramePeer createFrame (Frame f)
+ {
+ return new GtkFramePeer (f);
+ }
+
+ protected LabelPeer createLabel (Label label)
+ {
+ return new GtkLabelPeer (label);
+ }
+
+ protected ListPeer createList (List list)
+ {
+ return new GtkListPeer (list);
+ }
+
+ protected MenuPeer createMenu (Menu m)
+ {
+ return new GtkMenuPeer (m);
+ }
+
+ protected MenuBarPeer createMenuBar (MenuBar mb)
+ {
+ return new GtkMenuBarPeer (mb);
+ }
+
+ protected MenuItemPeer createMenuItem (MenuItem mi)
+ {
+ return new GtkMenuItemPeer (mi);
+ }
+
+ protected PanelPeer createPanel (Panel p)
+ {
+ return new GtkPanelPeer (p);
+ }
+
+ protected PopupMenuPeer createPopupMenu (PopupMenu target)
+ {
+ return new GtkPopupMenuPeer (target);
+ }
+
+ protected ScrollPanePeer createScrollPane (ScrollPane sp)
+ {
+ return new GtkScrollPanePeer (sp);
+ }
+
+ protected ScrollbarPeer createScrollbar (Scrollbar sb)
+ {
+ return new GtkScrollbarPeer (sb);
+ }
+
+ protected TextAreaPeer createTextArea (TextArea ta)
+ {
+ return new GtkTextAreaPeer (ta);
+ }
+
+ protected TextFieldPeer createTextField (TextField tf)
+ {
+ return new GtkTextFieldPeer (tf);
+ }
+
+ protected WindowPeer createWindow (Window w)
+ {
+ return new GtkWindowPeer (w);
+ }
+
+ public EmbeddedWindowPeer createEmbeddedWindow (EmbeddedWindow w)
+ {
+ return new GtkEmbeddedWindowPeer (w);
+ }
+
+ /**
+ * @deprecated part of the older "logical font" system in earlier AWT
+ * implementations. Our newer Font class uses getClasspathFontPeer.
+ */
+ protected FontPeer getFontPeer (String name, int style) {
+ // All fonts get a default size of 12 if size is not specified.
+ return getFontPeer(name, style, 12);
+ }
+
+ /**
+ * Private method that allows size to be set at initialization time.
+ */
+ private FontPeer getFontPeer (String name, int style, int size)
+ {
+ Map attrs = new HashMap ();
+ ClasspathFontPeer.copyStyleToAttrs (style, attrs);
+ ClasspathFontPeer.copySizeToAttrs (size, attrs);
+ return getClasspathFontPeer (name, attrs);
+ }
+
+ /**
+ * Newer method to produce a peer for a Font object, even though Sun's
+ * design claims Font should now be peerless, we do not agree with this
+ * model, hence "ClasspathFontPeer".
+ */
+
+ public ClasspathFontPeer getClasspathFontPeer (String name, Map attrs)
+ {
+ Map keyMap = new HashMap (attrs);
+ // We don't know what kind of "name" the user requested (logical, face,
+ // family), and we don't actually *need* to know here. The worst case
+ // involves failure to consolidate fonts with the same backend in our
+ // cache. This is harmless.
+ keyMap.put ("GtkToolkit.RequestedFontName", name);
+ if (fontCache.containsKey (keyMap))
+ return (ClasspathFontPeer) fontCache.get (keyMap);
+ else
+ {
+ ClasspathFontPeer newPeer = new GdkFontPeer (name, attrs);
+ fontCache.put (keyMap, newPeer);
+ return newPeer;
+ }
+ }
+
+ public ClasspathTextLayoutPeer getClasspathTextLayoutPeer (AttributedString str,
+ FontRenderContext frc)
+ {
+ return new GdkTextLayout(str, frc);
+ }
+
+ protected EventQueue getSystemEventQueueImpl()
+ {
+ synchronized (GtkToolkit.class)
+ {
+ if (q == null)
+ {
+ q = new EventQueue();
+ GtkGenericPeer.enableQueue (q);
+ }
+ }
+ return q;
+ }
+
+ protected native void loadSystemColors (int[] systemColors);
+
+ public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e)
+ {
+ throw new Error("not implemented");
+ }
+
+ public Map mapInputMethodHighlight(InputMethodHighlight highlight)
+ {
+ throw new Error("not implemented");
+ }
+
+ public Rectangle getBounds()
+ {
+ int[] dims = new int[2];
+ getScreenSizeDimensions(dims);
+ return new Rectangle(0, 0, dims[0], dims[1]);
+ }
+
+ // ClasspathToolkit methods
+
+ public GraphicsEnvironment getLocalGraphicsEnvironment()
+ {
+ return new GdkGraphicsEnvironment(this);
+ }
+
+ public Font createFont(int format, InputStream stream)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public RobotPeer createRobot (GraphicsDevice screen) throws AWTException
+ {
+ return new GdkRobotPeer (screen);
+ }
+
+ public void registerImageIOSpis(IIORegistry reg)
+ {
+ GdkPixbufDecoder.registerSpis(reg);
+ }
+
+ public native boolean nativeQueueEmpty();
+ public native void wakeNativeQueue();
+ public native void iterateNativeQueue(EventQueue locked, boolean block);
+
+} // class GtkToolkit
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java
new file mode 100644
index 0000000..496090a
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java
@@ -0,0 +1,118 @@
+/* GtkVolatileImage.java -- a hardware-accelerated image buffer
+ Copyright (C) 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 gnu.java.awt.peer.gtk;
+
+import java.awt.ImageCapabilities;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
+import java.awt.image.VolatileImage;
+
+public class GtkVolatileImage extends VolatileImage
+{
+ private int width;
+ private int height;
+ private ImageCapabilities caps;
+
+ public GtkVolatileImage(int width, int height)
+ {
+ this(width, height, null);
+ }
+
+ public GtkVolatileImage(int width, int height, ImageCapabilities caps)
+ {
+ this.width = width;
+ this.height = height;
+ this.caps = caps;
+ }
+
+ // FIXME: should return a buffered image snapshot of the accelerated
+ // visual
+ public BufferedImage getSnapshot()
+ {
+ return null;
+ }
+
+ public int getWidth()
+ {
+ return width;
+ }
+
+ public int getHeight()
+ {
+ return height;
+ }
+
+ // FIXME: should return a graphics wrapper around this image's
+ // visual
+ public Graphics2D createGraphics()
+ {
+ return null;
+ }
+
+ public int validate(GraphicsConfiguration gc)
+ {
+ return VolatileImage.IMAGE_OK;
+ }
+
+ public boolean contentsLost()
+ {
+ return false;
+ }
+
+ public ImageCapabilities getCapabilities()
+ {
+ return caps;
+ }
+
+ public synchronized Object getProperty (String name, ImageObserver observer)
+ {
+ return null;
+ }
+
+ public synchronized int getWidth (ImageObserver observer)
+ {
+ return width;
+ }
+
+ public synchronized int getHeight (ImageObserver observer)
+ {
+ return height;
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java
new file mode 100644
index 0000000..71e05a8
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java
@@ -0,0 +1,212 @@
+/* GtkWindowPeer.java -- Implements WindowPeer with GTK
+ Copyright (C) 1998, 1999, 2002, 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 gnu.java.awt.peer.gtk;
+
+import java.awt.Component;
+import java.awt.Frame;
+import java.awt.Window;
+import java.awt.event.WindowEvent;
+import java.awt.peer.WindowPeer;
+
+public class GtkWindowPeer extends GtkContainerPeer
+ implements WindowPeer
+{
+ protected static final int GDK_WINDOW_TYPE_HINT_NORMAL = 0;
+ protected static final int GDK_WINDOW_TYPE_HINT_DIALOG = 1;
+ protected static final int GDK_WINDOW_TYPE_HINT_MENU = 2;
+ protected static final int GDK_WINDOW_TYPE_HINT_TOOLBAR = 3;
+ protected static final int GDK_WINDOW_TYPE_HINT_SPLASHSCREEN = 4;
+ protected static final int GDK_WINDOW_TYPE_HINT_UTILITY = 5;
+ protected static final int GDK_WINDOW_TYPE_HINT_DOCK = 6;
+ protected static final int GDK_WINDOW_TYPE_HINT_DESKTOP = 7;
+
+ private boolean hasBeenShown = false;
+ private int oldState = Frame.NORMAL;
+
+ native void gtkWindowSetTitle (String title);
+ native void gtkWindowSetResizable (boolean resizable);
+ native void gtkWindowSetModal (boolean modal);
+
+ native void realize ();
+
+ int getWidth ()
+ {
+ return awtComponent.getWidth();
+ }
+
+ int getHeight ()
+ {
+ return awtComponent.getHeight();
+ }
+
+ native void create (int type, boolean decorated, GtkWindowPeer parent);
+
+ void create (int type, boolean decorated)
+ {
+ GtkWindowPeer parent_peer = null;
+ Component parent = awtComponent.getParent();
+
+ if (parent != null)
+ parent_peer = (GtkWindowPeer) awtComponent.getParent().getPeer();
+
+ create (type, decorated, parent_peer);
+ }
+
+ void create ()
+ {
+ // Create a normal undecorated window.
+ create (GDK_WINDOW_TYPE_HINT_NORMAL, false);
+ }
+
+ void setParent ()
+ {
+ setVisible (awtComponent.isVisible ());
+ setEnabled (awtComponent.isEnabled ());
+ }
+
+ void setVisibleAndEnabled ()
+ {
+ }
+
+ native void connectSignals ();
+
+ public GtkWindowPeer (Window window)
+ {
+ super (window);
+ }
+
+ public native void toBack();
+ public native void toFront();
+
+ native void nativeSetBounds (int x, int y, int width, int height);
+
+ public void setBounds (int x, int y, int width, int height)
+ {
+ nativeSetBounds (x, y,
+ width - insets.left - insets.right,
+ height - insets.top - insets.bottom);
+ }
+
+ public void setTitle (String title)
+ {
+ gtkWindowSetTitle (title);
+ }
+
+ native void setSize (int width, int height);
+
+ public void setResizable (boolean resizable)
+ {
+ // Call setSize; otherwise when resizable is changed from true to
+ // false the window will shrink to the dimensions it had before it
+ // was resizable.
+ setSize (awtComponent.getWidth() - insets.left - insets.right,
+ awtComponent.getHeight() - insets.top - insets.bottom);
+ gtkWindowSetResizable (resizable);
+ }
+
+ native void setBoundsCallback (Window window,
+ int x, int y,
+ int width, int height);
+
+ protected void postInsetsChangedEvent (int top, int left,
+ int bottom, int right)
+ {
+ insets.top = top;
+ insets.left = left;
+ insets.bottom = bottom;
+ insets.right = right;
+ }
+
+ protected void postConfigureEvent (int x, int y, int width, int height)
+ {
+ int frame_x = x - insets.left;
+ int frame_y = y - insets.top;
+ int frame_width = width + insets.left + insets.right;
+ int frame_height = height + insets.top + insets.bottom;
+
+ if (frame_x != awtComponent.getX()
+ || frame_y != awtComponent.getY()
+ || frame_width != awtComponent.getWidth()
+ || frame_height != awtComponent.getHeight())
+ {
+ setBoundsCallback ((Window) awtComponent,
+ frame_x, frame_y, frame_width, frame_height);
+
+ awtComponent.validate();
+ }
+ }
+
+ native void nativeSetVisible (boolean b);
+ public void setVisible (boolean b)
+ {
+ // Prevent the window manager from automatically placing this
+ // window when it is shown.
+ if (b)
+ setBounds (awtComponent.getX(),
+ awtComponent.getY(),
+ awtComponent.getWidth(),
+ awtComponent.getHeight());
+ nativeSetVisible (b);
+ }
+
+ void postWindowEvent (int id, Window opposite, int newState)
+ {
+ if (id == WindowEvent.WINDOW_OPENED)
+ {
+ // Post a WINDOW_OPENED event the first time this window is shown.
+ if (!hasBeenShown)
+ {
+ q().postEvent (new WindowEvent ((Window) awtComponent, id,
+ opposite));
+ hasBeenShown = true;
+ }
+ }
+ else if (id == WindowEvent.WINDOW_STATE_CHANGED)
+ {
+ if (oldState != newState)
+ {
+ q().postEvent (new WindowEvent ((Window) awtComponent, id, opposite,
+ oldState, newState));
+ oldState = newState;
+ }
+ }
+ else
+ q().postEvent (new WindowEvent ((Window) awtComponent, id, opposite));
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/package.html b/libjava/classpath/gnu/java/awt/peer/gtk/package.html
new file mode 100644
index 0000000..8dd4dd8
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+Applet
+ * beans being created with {@link java.beans.Beans.instantiate}.null
object on
+ * URL.openConnection()
.
+ *
+ * @see java.applet.AppletContext#getAudioClip(java.net.URL)
+ *
+ * FIXME: When Java Sound API (javax.sound) is included in Classpath or URL is able to handle
+ * sampled sound this should be adjusted.
+ */
+ public AudioClip getAudioClip(URL url)
+ {
+ try
+ {
+ return (url.openConnection() != null ? DUMMY_CLIP : null);
+ }
+ catch (IOException ioe)
+ {
+ return null;
+ }
+ }
+
+ /** Loads the Image
instance by delegating to
+ * {@link java.awt.Toolkit.createImage(URL) }.
+ *
+ * @see java.applet.AppletContext#getImage(java.net.URL)
+ * @see java.awt.Toolkit#createImage(java.net.URL)
+ */
+ public Image getImage(URL url)
+ {
+ return Toolkit.getDefaultToolkit().createImage(url);
+ }
+
+ /** Returns null
for every argument.
+ *
+ * @see java.applet.AppletContext#getApplet(java.lang.String)
+ */
+ public Applet getApplet(String name)
+ {
+ return null;
+ }
+
+ /** Returns always an empty Enumeration
.
+ *
+ * @see java.applet.AppletContext#getApplets()
+ */
+ public Enumeration getApplets()
+ {
+ return EMPTY_ENUMERATION;
+ }
+
+ /** Does nothing.
+ *
+ * @see java.applet.AppletContext#showDocument(java.net.URL)
+ */
+ public void showDocument(URL url)
+ {
+ }
+
+ /** Does nothing.
+ *
+ * @see java.applet.AppletContext#showDocument(java.net.URL, java.lang.String)
+ */
+ public void showDocument(URL url, String target)
+ {
+ }
+
+ /** Does nothing.
+ *
+ * @see java.applet.AppletContext#showStatus(java.lang.String)
+ */
+ public void showStatus(String message)
+ {
+ }
+
+ /** Does nothing.
+ *
+ * @see java.applet.AppletContext#setStream(java.lang.String, java.io.InputStream)
+ */
+ public void setStream(String key, InputStream stream)
+ throws IOException
+ {
+ throw new IOException("Dummy implementation imposes zero InputStream associations.");
+ }
+
+ /** Returns null
for every argument.
+ *
+ * @see java.applet.AppletContext#getStream(java.lang.String)
+ */
+ public InputStream getStream(String key)
+ {
+ return null;
+ }
+
+ /** Returns always an empty iterator.
+ *
+ * @see java.applet.AppletContext#getStreamKeys()
+ */
+ public Iterator getStreamKeys()
+ {
+ return Collections.EMPTY_SET.iterator();
+ }
+
+ /** Dummy AudioClip
implementation that does nothing but
+ * preventing NullPointerException
S being thrown in programs
+ * that expect a valid AudioClip
instance to be returned by
+ * their Applet.
+ *
+ * @author Robert Schuster
+ */
+ static class DummyAudioClip implements AudioClip
+ {
+ public void play()
+ {
+ }
+
+ public void stop()
+ {
+ }
+
+ public void loop()
+ {
+ }
+
+ public String toString()
+ {
+ return "DummyAudioClip never plays anything - implement javax.sound and make us happy :)";
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/DummyAppletStub.java b/libjava/classpath/gnu/java/beans/DummyAppletStub.java
new file mode 100644
index 0000000..3bcb435
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/DummyAppletStub.java
@@ -0,0 +1,115 @@
+/* gnu.java.beans.DummyAppletStub
+ Copyright (C) 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 gnu.java.beans;
+
+import java.applet.AppletContext;
+import java.applet.AppletStub;
+import java.net.URL;
+
+/** Placeholder implementation of AppletStub
providing no functionality.
+ * Applet
being created with
+ * {@link java.beans.Bean.instantiate}.true
.
+ *
+ * @see java.applet.AppletStub#isActive()
+ */
+ public boolean isActive()
+ {
+ return true;
+ }
+
+ /**
+ * @see java.applet.AppletStub#getDocumentBase()
+ */
+ public URL getDocumentBase()
+ {
+ return documentBase;
+ }
+
+ /**
+ * @see java.applet.AppletStub#getCodeBase()
+ */
+ public URL getCodeBase()
+ {
+ return codeBase;
+ }
+
+ /** Implementation returns null
for every parameter name.
+ *
+ * @see java.applet.AppletStub#getParameter(java.lang.String)
+ */
+ public String getParameter(String name)
+ {
+ return null;
+ }
+
+ /** Returns a non-functional context instance.
+ *
+ * @see java.applet.AppletStub#getAppletContext()
+ */
+ public AppletContext getAppletContext()
+ {
+ return context;
+ }
+
+ /** Does nothing.
+ *
+ * @see java.applet.AppletStub#appletResize(int, int)
+ */
+ public void appletResize(int width, int height)
+ {
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/ExplicitBeanInfo.java b/libjava/classpath/gnu/java/beans/ExplicitBeanInfo.java
new file mode 100644
index 0000000..6da5e86
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/ExplicitBeanInfo.java
@@ -0,0 +1,149 @@
+/* ExplicitBeanInfo.java --
+ Copyright (C) 1998, 2004 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 gnu.java.beans;
+
+import java.awt.Image;
+import java.beans.BeanDescriptor;
+import java.beans.BeanInfo;
+import java.beans.EventSetDescriptor;
+import java.beans.MethodDescriptor;
+import java.beans.PropertyDescriptor;
+
+/**
+ ** ExplicitBeanInfo lets you specify in the constructor
+ ** all the various parts of the BeanInfo.
+ **
+ ** @author John Keiser
+ ** @version 1.1.0, 30 Jul 1998
+ ** @see java.beans.BeanInfo
+ **/
+
+public class ExplicitBeanInfo implements BeanInfo {
+ /** The BeanDescriptor returned by getBeanDescriptor. **/
+ protected BeanDescriptor beanDescriptor;
+
+ /** The EventSetDescriptor array returned by
+ ** getEventSetDescriptors().
+ **/
+ protected EventSetDescriptor[] eventSetDescriptors = new EventSetDescriptor[0];
+
+ /** The PropertyDescriptor array returned by
+ ** getPropertyDescriptors().
+ **/
+ protected PropertyDescriptor[] propertyDescriptors = new PropertyDescriptor[0];
+
+ /** The MethodDescriptor array returned by
+ ** getMethodDescriptors().
+ **/
+ protected MethodDescriptor[] methodDescriptors;
+
+ /** The default property index. **/
+ protected int defaultPropertyIndex;
+
+ /** The default event index. **/
+ protected int defaultEventIndex;
+
+ /** The BeanInfo array returned by
+ ** getAdditionalBeanInfo().
+ **/
+ protected BeanInfo[] additionalBeanInfo;
+
+ /** The set of icons. **/
+ protected Image[] icons;
+
+ public ExplicitBeanInfo(BeanDescriptor beanDescriptor,
+ BeanInfo[] additionalBeanInfo,
+ PropertyDescriptor[] propertyDescriptors,
+ int defaultPropertyIndex,
+ EventSetDescriptor[] eventSetDescriptors,
+ int defaultEventIndex,
+ MethodDescriptor[] methodDescriptors,
+ Image[] icons) {
+ this.beanDescriptor = beanDescriptor;
+ this.additionalBeanInfo = additionalBeanInfo;
+ this.propertyDescriptors = propertyDescriptors;
+ this.defaultPropertyIndex = defaultPropertyIndex;
+ this.eventSetDescriptors = eventSetDescriptors;
+ this.defaultEventIndex = defaultEventIndex;
+ this.methodDescriptors = methodDescriptors;
+ this.icons = icons;
+ }
+
+ /** Get Bean descriptor. **/
+ public BeanDescriptor getBeanDescriptor() {
+ return beanDescriptor;
+ }
+
+ /** Get Bean events. **/
+ public EventSetDescriptor[] getEventSetDescriptors() {
+ return eventSetDescriptors;
+ }
+
+ /** Get default event set. **/
+ public int getDefaultEventIndex() {
+ return defaultEventIndex;
+ }
+
+ /** Get Bean properties. **/
+ public PropertyDescriptor[] getPropertyDescriptors() {
+ return propertyDescriptors;
+ }
+
+ /** Get "default" property. **/
+ public int getDefaultPropertyIndex() {
+ return defaultPropertyIndex;
+ }
+
+ /** Get Bean methods. **/
+ public MethodDescriptor[] getMethodDescriptors() {
+ return methodDescriptors;
+ }
+
+ /** Get additional Bean info. **/
+ public BeanInfo[] getAdditionalBeanInfo() {
+ return additionalBeanInfo;
+ }
+
+ /** Get Bean icons.
+ ** @param iconType the type of icon
+ **/
+ public Image getIcon(int iconType) {
+ return icons != null ? icons[iconType - 1] : null;
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/IntrospectionIncubator.java b/libjava/classpath/gnu/java/beans/IntrospectionIncubator.java
new file mode 100644
index 0000000..e0d9480
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/IntrospectionIncubator.java
@@ -0,0 +1,441 @@
+/* gnu.java.beans.IntrospectionIncubator
+ Copyright (C) 1998, 2004 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 gnu.java.beans;
+
+import gnu.java.lang.ArrayHelper;
+import gnu.java.lang.ClassHelper;
+
+import java.beans.BeanInfo;
+import java.beans.EventSetDescriptor;
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.MethodDescriptor;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ ** IntrospectionIncubator takes in a bunch of Methods, and
+ ** Introspects only those Methods you give it.
+ **
+ ** See {@link addMethod(Method)} for details which rules apply to
+ ** the methods.
+ **
+ ** @author John Keiser
+ ** @author Robert Schuster
+ ** @see gnu.java.beans.ExplicitBeanInfo
+ ** @see java.beans.BeanInfo
+ **/
+
+public class IntrospectionIncubator {
+ Hashtable propertyMethods = new Hashtable();
+ Hashtable listenerMethods = new Hashtable();
+ Vector otherMethods = new Vector();
+
+ Class propertyStopClass;
+ Class eventStopClass;
+ Class methodStopClass;
+
+ public IntrospectionIncubator() {
+ }
+
+ /** Examines the given method and files it in a suitable collection.
+ * It files the method as a property method if it finds:
+ *
+ *
+ * It files the method as a listener method if all of these rules apply:
+ *
+ *
+ * All public methods are filed as such.
+ *
+ * @param method The method instance to examine.
+ */
+ public void addMethod(Method method) {
+ if(Modifier.isPublic(method.getModifiers())) {
+ String name = ClassHelper.getTruncatedName(method.getName());
+ Class retType = method.getReturnType();
+ Class[] params = method.getParameterTypes();
+ boolean isVoid = retType.equals(java.lang.Void.TYPE);
+ Class methodClass = method.getDeclaringClass();
+
+ /* Accepts the method for examination if no stop class is given or the method is declared in a subclass of the stop class.
+ * The rules for this are described in {@link java.beans.Introspector.getBeanInfo(Class, Class)}.
+ * This block finds out whether the method is a suitable getter or setter method (or read/write method).
+ */
+ if(isReachable(propertyStopClass, methodClass)) {
+ /* At this point a method may regarded as a property's read or write method if its name
+ * starts with "is", "get" or "set". However, if a method is static it cannot be part
+ * of a property.
+ */
+ if(Modifier.isStatic(method.getModifiers())) {
+ // files method as other because it is static
+ otherMethods.addElement(method);
+ } else if(name.startsWith("is")
+ && retType.equals(java.lang.Boolean.TYPE)
+ && params.length == 0) {
+ // files method as boolean "is" style getter
+ addToPropertyHash(name,method,IS);
+ } else if(name.startsWith("get") && !isVoid) {
+ if(params.length == 0) {
+ // files as legal non-argument getter
+ addToPropertyHash(name,method,GET);
+ } else if(params.length == 1 && params[0].equals(java.lang.Integer.TYPE)) {
+ // files as legal indiced getter
+ addToPropertyHash(name,method,GET_I);
+ } else {
+ // files as other because the method's signature is not Bean-like
+ otherMethods.addElement(method);
+ }
+ } else if(name.startsWith("set") && isVoid) {
+ if(params.length == 1) {
+ // files as legal single-argument setter method
+ addToPropertyHash(name,method,SET);
+ } else if(params.length == 2 && params[0].equals(java.lang.Integer.TYPE)) {
+ // files as legal indiced setter method
+ addToPropertyHash(name,method,SET_I);
+ } else {
+ // files as other because the method's signature is not Bean-like
+ otherMethods.addElement(method);
+ }
+ }
+ }
+
+ if(isReachable(eventStopClass, methodClass)) {
+ if(name.startsWith("add")
+ && isVoid
+ && params.length == 1
+ && java.util.EventListener.class.isAssignableFrom(params[0])) {
+ addToListenerHash(name,method,ADD);
+ } else if(name.startsWith("remove")
+ && isVoid
+ && params.length == 1
+ && java.util.EventListener.class.isAssignableFrom(params[0])) {
+ addToListenerHash(name,method,REMOVE);
+ }
+ }
+
+ if(isReachable(methodStopClass, methodClass)) {
+ // files as reachable public method
+ otherMethods.addElement(method);
+ }
+
+ }
+ }
+
+ public void addMethods(Method[] m) {
+ for(int i=0;ijava.util.EventListener
null
+ * or declaringClass
is a true subclass of
to determine their titlecase). The listing
+ * is a sorted sequence of character pairs; converting the first character
+ * of the pair to titlecase produces the second character.
+ */
+ String TITLE
+ = "\u01c4\u01c5\u01c5\u01c5\u01c6\u01c5\u01c7\u01c8\u01c8\u01c8\u01c9"
+ + "\u01c8\u01ca\u01cb\u01cb\u01cb\u01cc\u01cb\u01f1\u01f2\u01f2\u01f2"
+ + "\u01f3\u01f2";
+
+ /**
+ * This is a listing of characters with multi-character uppercase sequences.
+ * A character appears in this list exactly when it has a non-zero entry
+ * in the low-order 2-bit field of DIRECTION. The listing is a sorted
+ * sequence of pairs (hence a binary search on the even elements is an
+ * efficient way to lookup a character). The first element of a pair is the
+ * character with the expansion, and the second is the index into
+ * UPPER_EXPAND where the expansion begins. Use the 2-bit field of
+ * DIRECTION to determine where the expansion ends.
+ */
+ String UPPER_SPECIAL
+ = "\u00df\000\u0149\002\u01f0\004\u0390\006\u03b0\011"
+ + "\u0587\014\u1e96\016\u1e97\020\u1e98\022\u1e99\024"
+ + "\u1e9a\026\u1f50\030\u1f52\032\u1f54\035\u1f56 "
+ + "\u1f80#\u1f81%\u1f82'\u1f83)\u1f84+"
+ + "\u1f85-\u1f86/\u1f871\u1f883\u1f895"
+ + "\u1f8a7\u1f8b9\u1f8c;\u1f8d=\u1f8e?"
+ + "\u1f8fA\u1f90C\u1f91E\u1f92G\u1f93I"
+ + "\u1f94K\u1f95M\u1f96O\u1f97Q\u1f98S"
+ + "\u1f99U\u1f9aW\u1f9bY\u1f9c[\u1f9d]"
+ + "\u1f9e_\u1f9fa\u1fa0c\u1fa1e\u1fa2g"
+ + "\u1fa3i\u1fa4k\u1fa5m\u1fa6o\u1fa7q"
+ + "\u1fa8s\u1fa9u\u1faaw\u1faby\u1fac{"
+ + "\u1fad}\u1fae\u007f\u1faf\u0081\u1fb2\u0083\u1fb3\u0085"
+ + "\u1fb4\u0087\u1fb6\u0089\u1fb7\u008b\u1fbc\u008e\u1fc2\u0090"
+ + "\u1fc3\u0092\u1fc4\u0094\u1fc6\u0096\u1fc7\u0098\u1fcc\u009b"
+ + "\u1fd2\u009d\u1fd3\u00a0\u1fd6\u00a3\u1fd7\u00a5\u1fe2\u00a8"
+ + "\u1fe3\u00ab\u1fe4\u00ae\u1fe6\u00b0\u1fe7\u00b2\u1ff2\u00b5"
+ + "\u1ff3\u00b7\u1ff4\u00b9\u1ff6\u00bb\u1ff7\u00bd\u1ffc\u00c0"
+ + "\ufb00\u00c2\ufb01\u00c4\ufb02\u00c6\ufb03\u00c8\ufb04\u00cb"
+ + "\ufb05\u00ce\ufb06\u00d0\ufb13\u00d2\ufb14\u00d4\ufb15\u00d6"
+ + "\ufb16\u00d8\ufb17\u00da";
+
+ /**
+ * This is the listing of special case multi-character uppercase sequences.
+ * Characters listed in UPPER_SPECIAL index into this table to find their
+ * uppercase expansion. Remember that you must also perform special-casing
+ * on two single-character sequences in the Turkish locale, which are not
+ * covered here in CharData.
+ */
+ String UPPER_EXPAND
+ = "SS\u02bcNJ\u030c\u0399\u0308\u0301\u03a5\u0308"
+ + "\u0301\u0535\u0552H\u0331T\u0308W\u030aY\u030a"
+ + "A\u02be\u03a5\u0313\u03a5\u0313\u0300\u03a5\u0313\u0301\u03a5"
+ + "\u0313\u0342\u1f08\u0399\u1f09\u0399\u1f0a\u0399\u1f0b\u0399\u1f0c"
+ + "\u0399\u1f0d\u0399\u1f0e\u0399\u1f0f\u0399\u1f08\u0399\u1f09\u0399"
+ + "\u1f0a\u0399\u1f0b\u0399\u1f0c\u0399\u1f0d\u0399\u1f0e\u0399\u1f0f"
+ + "\u0399\u1f28\u0399\u1f29\u0399\u1f2a\u0399\u1f2b\u0399\u1f2c\u0399"
+ + "\u1f2d\u0399\u1f2e\u0399\u1f2f\u0399\u1f28\u0399\u1f29\u0399\u1f2a"
+ + "\u0399\u1f2b\u0399\u1f2c\u0399\u1f2d\u0399\u1f2e\u0399\u1f2f\u0399"
+ + "\u1f68\u0399\u1f69\u0399\u1f6a\u0399\u1f6b\u0399\u1f6c\u0399\u1f6d"
+ + "\u0399\u1f6e\u0399\u1f6f\u0399\u1f68\u0399\u1f69\u0399\u1f6a\u0399"
+ + "\u1f6b\u0399\u1f6c\u0399\u1f6d\u0399\u1f6e\u0399\u1f6f\u0399\u1fba"
+ + "\u0399\u0391\u0399\u0386\u0399\u0391\u0342\u0391\u0342\u0399\u0391"
+ + "\u0399\u1fca\u0399\u0397\u0399\u0389\u0399\u0397\u0342\u0397\u0342"
+ + "\u0399\u0397\u0399\u0399\u0308\u0300\u0399\u0308\u0301\u0399\u0342"
+ + "\u0399\u0308\u0342\u03a5\u0308\u0300\u03a5\u0308\u0301\u03a1\u0313"
+ + "\u03a5\u0342\u03a5\u0308\u0342\u1ffa\u0399\u03a9\u0399\u038f\u0399"
+ + "\u03a9\u0342\u03a9\u0342\u0399\u03a9\u0399FFFI"
+ + "FLFFIFFLSTS"
+ + "T\u0544\u0546\u0544\u0535\u0544\u053b\u054e\u0546\u0544\u053d";
+}
diff --git a/libjava/classpath/gnu/java/lang/ClassHelper.java b/libjava/classpath/gnu/java/lang/ClassHelper.java
new file mode 100644
index 0000000..14c8a39
--- /dev/null
+++ b/libjava/classpath/gnu/java/lang/ClassHelper.java
@@ -0,0 +1,177 @@
+/* ClassHelper.java -- Utility methods to augment java.lang.Class
+ Copyright (C) 1998, 2002 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 gnu.java.lang;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * ClassHelper has various methods that ought to have been in Class.
+ *
+ * @author John Keiser
+ * @author Eric Blake (ebb9@email.byu.edu)
+ */
+public class ClassHelper
+{
+ /**
+ * Strip the package part from the class name.
+ *
+ * @param clazz the class to get the truncated name from
+ * @return the truncated class name
+ */
+ public static String getTruncatedClassName(Class clazz)
+ {
+ return getTruncatedName(clazz.getName());
+ }
+
+ /**
+ * Strip the package part from the class name, or the class part from
+ * the method or field name.
+ *
+ * @param name the name to truncate
+ * @return the truncated name
+ */
+ public static String getTruncatedName(String name)
+ {
+ int lastInd = name.lastIndexOf('.');
+ if (lastInd == -1)
+ return name;
+ return name.substring(lastInd + 1);
+ }
+
+ /** Cache of methods found in getAllMethods(). */
+ private static Map allMethods = new HashMap();
+
+ /**
+ * Get all the methods, public, private and otherwise, from the class,
+ * getting them from the most recent class to find them. This may not
+ * be quite the correct approach, as this includes methods that are not
+ * inherited or accessible from clazz, so beware.
+ *
+ * @param clazz the class to start at
+ * @return all methods declared or inherited in clazz
+ */
+ public static Method[] getAllMethods(Class clazz)
+ {
+ Method[] retval = (Method[]) allMethods.get(clazz);
+ if (retval == null)
+ {
+ Set methods = new HashSet();
+ Class c = clazz;
+ while (c != null)
+ {
+ Method[] currentMethods = c.getDeclaredMethods();
+ loop:
+ for (int i = 0; i < currentMethods.length; i++)
+ {
+ Method current = currentMethods[i];
+ int size = methods.size();
+ Iterator iter = methods.iterator();
+ while (--size >= 0)
+ {
+ Method override = (Method) iter.next();
+ if (current.getName().equals(override.getName())
+ && Arrays.equals(current.getParameterTypes(),
+ override.getParameterTypes())
+ && current.getReturnType() == override.getReturnType())
+ continue loop;
+ }
+ methods.add(current);
+ }
+ c = c.getSuperclass();
+ }
+ retval = new Method[methods.size()];
+ methods.toArray(retval);
+ allMethods.put(clazz, retval);
+ }
+ return retval;
+ }
+
+ /** Cache of fields found in getAllFields(). */
+ private static Map allFields = new HashMap();
+
+ /**
+ * Get all the fields, public, private and otherwise, from the class,
+ * getting them from the most recent class to find them. This may not
+ * be quite the correct approach, as this includes fields that are not
+ * inherited or accessible from clazz, so beware.
+ *
+ * @param clazz the class to start at
+ * @return all fields declared or inherited in clazz
+ */
+ public static Field[] getAllFields(Class clazz)
+ {
+ Field[] retval = (Field[]) allFields.get(clazz);
+ if (retval == null)
+ {
+ Set fields = new HashSet();
+ Class c = clazz;
+ while (c != null)
+ {
+ Field[] currentFields = c.getDeclaredFields();
+ loop:
+ for (int i = 0; i < currentFields.length; i++)
+ {
+ Field current = currentFields[i];
+ int size = fields.size();
+ Iterator iter = fields.iterator();
+ while (--size >= 0)
+ {
+ Field override = (Field) iter.next();
+ if (current.getName().equals(override.getName())
+ && current.getType() == override.getType())
+ continue loop;
+ }
+ fields.add(current);
+ }
+ c = c.getSuperclass();
+ }
+ retval = new Field[fields.size()];
+ fields.toArray(retval);
+ allFields.put(clazz, retval);
+ }
+ return retval;
+ }
+}
diff --git a/libjava/classpath/gnu/java/lang/MainThread.java b/libjava/classpath/gnu/java/lang/MainThread.java
new file mode 100644
index 0000000..ab529ef
--- /dev/null
+++ b/libjava/classpath/gnu/java/lang/MainThread.java
@@ -0,0 +1,83 @@
+/* MainThread.java --
+ 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 gnu.java.lang;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * MainThread is a Thread which uses the main() method of some class.
+ *
+ * @author John Keiser
+ * @author Tom Tromey (tromey@redhat.com)
+ */
+public class MainThread
+{
+ // Private data.
+ String[] args;
+ Method mainMethod;
+
+ public MainThread(String classname, String[] args)
+ throws ClassNotFoundException, NoSuchMethodException
+ {
+ Class found = Class.forName(classname, true,
+ ClassLoader.getSystemClassLoader());
+ Class[] argTypes = new Class[1];
+ argTypes[0] = args.getClass();
+ mainMethod = found.getMethod("main", argTypes);
+ this.args = args;
+ }
+
+ public void run()
+ {
+ try
+ {
+ mainMethod.invoke(null,args);
+ }
+ catch(IllegalAccessException e)
+ {
+ // Ignore.
+ }
+ catch(InvocationTargetException e)
+ {
+ // Ignore.
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/lang/package.html b/libjava/classpath/gnu/java/lang/package.html
new file mode 100644
index 0000000..1f16776
--- /dev/null
+++ b/libjava/classpath/gnu/java/lang/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+stopClass
.
+ * This expression is useful to detect whether a method should be introspected or not.
+ * The rules for this are described in {@link java.beans.Introspector.getBeanInfo(Class, Class)}.
+ */
+ static boolean isReachable(Class stopClass, Class declaringClass) {
+ return stopClass == null || (stopClass.isAssignableFrom(declaringClass) && !stopClass.equals(declaringClass));
+ }
+
+ /** Transforms a property name into a part of a method name.
+ * E.g. "value" becomes "Value" which can then concatenated with
+ * "set", "get" or "is" to form a valid method name.
+ *
+ * Implementation notes:
+ * If "" is the argument, it is returned without changes.
+ * If null
is the argument, null
is returned.
+ *
+ * @param name Name of a property.
+ * @return Part of a method name of a property.
+ */
+ static String capitalize(String name) {
+ try {
+ if(Character.isUpperCase(name.charAt(0))) {
+ return name;
+ } else {
+ char[] c = name.toCharArray();
+ c[0] = Character.toLowerCase(c[0]);
+ return new String(c);
+ }
+ } catch(StringIndexOutOfBoundsException E) {
+ return name;
+ } catch(NullPointerException E) {
+ return null;
+ }
+ }
+}
+
+/** This class is a hashmap key that consists of a Class
and a
+ * String
element.
+ *
+ * It is used for XXX: find out what this is used for
+ *
+ * @author John Keiser
+ * @author Robert Schuster
+ */
+class DoubleKey {
+ Class type;
+ String name;
+
+ DoubleKey(Class type, String name) {
+ this.type = type;
+ this.name = name;
+ }
+
+ Class getType() {
+ return type;
+ }
+
+ String getName() {
+ return name;
+ }
+
+ public boolean equals(Object o) {
+ if(o instanceof DoubleKey) {
+ DoubleKey d = (DoubleKey)o;
+ return d.type.equals(type) && d.name.equals(name);
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return type.hashCode() ^ name.hashCode();
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/TODO b/libjava/classpath/gnu/java/beans/TODO
new file mode 100644
index 0000000..9112806
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/TODO
@@ -0,0 +1 @@
+- overhaul efficiency
diff --git a/libjava/classpath/gnu/java/beans/decoder/AbstractContext.java b/libjava/classpath/gnu/java/beans/decoder/AbstractContext.java
new file mode 100644
index 0000000..0e95d43
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/decoder/AbstractContext.java
@@ -0,0 +1,70 @@
+/* gnu.java.beans.decoder.AbstractContext
+ Copyright (C) 2004 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 gnu.java.beans.decoder;
+
+
+/** AbstractContext implements some basic functionality of the Context
+ * interface and is therefore the base of all Context implementations.
+ *
+ * @author Robert Schuster
+ */
+abstract class AbstractContext implements Context
+{
+ private boolean isStatement;
+ private String id;
+
+ public String getId()
+ {
+ return id;
+ }
+
+ public void setId(String newId)
+ {
+ id = newId;
+ }
+
+ public boolean isStatement()
+ {
+ return isStatement;
+ }
+
+ public void setStatement(boolean b)
+ {
+ isStatement = b;
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/decoder/AbstractCreatableObjectContext.java b/libjava/classpath/gnu/java/beans/decoder/AbstractCreatableObjectContext.java
new file mode 100644
index 0000000..47f04fa
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/decoder/AbstractCreatableObjectContext.java
@@ -0,0 +1,113 @@
+/* gnu.java.beans.decoder.AbstractCreatableContext
+ Copyright (C) 2004 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 gnu.java.beans.decoder;
+
+
+/** AbstractCreatableObjectContext is the base class for all Context implementations
+ * which create a result object in their lifetime. It provides means for preventing
+ * to create the object twice.
+ *
+ * @author Robert Schuster
+ *
+ */
+abstract class AbstractCreatableObjectContext extends AbstractObjectContext
+{
+ AbstractCreatableObjectContext()
+ {
+ }
+
+ /** Adds a parameter object to this Context if the result object has not been
+ * created yet. Otherwise an AssemblyException is thrown that indicates a wrong
+ * behavior of the decoder.
+ */
+ public final void addParameterObject(Object o) throws AssemblyException
+ {
+ if (object == null)
+ addParameterObjectImpl(o);
+ else
+ throw new AssemblyException(new IllegalStateException("No more parameter objects are allowed when the object as already been created."));
+ }
+
+ /** Adds a parameter object to this Context. Implement this without caring
+ * for illegal states because this has been done already.
+ *
+ * @param obj The parameter object to be added.
+ */
+ protected abstract void addParameterObjectImpl(Object obj);
+
+ /** Creates the result object if it does not exist already.
+ */
+ public final void notifyStatement(Context outerContext)
+ throws AssemblyException
+ {
+ if (object != null)
+ return;
+
+ object = createObject(outerContext);
+ }
+
+ /** Creates the result object. This method is called only once. Implement this
+ * without checking for double invocations as this is already being prevented.
+ *
+ * @param outerContext The Context that exists around this one.
+ * @return The result object.
+ * @throws AssemblerException if the object creation fails somehow.
+ */
+ protected abstract Object createObject(Context outerContext)
+ throws AssemblyException;
+
+ /* (non-Javadoc)
+ * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context)
+ */
+ public final Object endContext(Context outerContext)
+ throws AssemblyException
+ {
+ notifyStatement(outerContext);
+ return object;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.java.beans.decoder.Context#subContextFailed()
+ */
+ public boolean subContextFailed()
+ {
+ /* Returns true when the AbstractCreatableObjectContext has not created the result object yet
+ * (A failed subcontext automatically lets this context fail too.)
+ */
+ return object == null;
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/decoder/AbstractElementHandler.java b/libjava/classpath/gnu/java/beans/decoder/AbstractElementHandler.java
new file mode 100644
index 0000000..e5578a9
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/decoder/AbstractElementHandler.java
@@ -0,0 +1,316 @@
+/* gnu.java.beans.decoder.AbstractElementHandler
+ Copyright (C) 2004 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 gnu.java.beans.decoder;
+
+import java.beans.ExceptionListener;
+
+import org.xml.sax.Attributes;
+
+/** ElementHandler manages a Context instance and interacts with
+ * its parent and child handlers.
+ *
+ * @author Robert Schuster
+ */
+abstract class AbstractElementHandler implements ElementHandler
+{
+ /** The Context instance of this handler. The instance is available after the startElement()
+ * method was called. Otherwise the handler is marked as failed.
+ */
+ private Context context;
+
+ /** The parent handler. */
+ private ElementHandler parent;
+
+ /** Stores whether this handler is marked as failed. */
+ private boolean hasFailed;
+
+ /** Stores the character data which is contained in the body of the XML tag. */
+ private StringBuffer buffer = new StringBuffer();
+
+ /** Stores whether this ElementHandler can have subelements. The information for this is taken from
+ * javabeans.dtd which can be found here:
+ * Java Persistence Article
+ */
+ private boolean allowsSubelements;
+
+ /** Creates a new ElementHandler with the given ElementHandler instance
+ * as parent.
+ *
+ * @param parentHandler The parent handler.
+ */
+ protected AbstractElementHandler(ElementHandler parentHandler,
+ boolean allowsSubs)
+ {
+ parent = parentHandler;
+ allowsSubelements = allowsSubs;
+ }
+
+ /** Evaluates the attributes and creates a Context instance.
+ * If the creation of the Context instance fails the ElementHandler
+ * is marked as failed which may affect the parent handler other.
+ *
+ * @param attributes Attributes of the XML tag.
+ */
+ public final void start(Attributes attributes,
+ ExceptionListener exceptionListener)
+ {
+ try
+ {
+ // lets the subclass create the appropriate Context instance
+ context = startElement(attributes, exceptionListener);
+ }
+ catch (AssemblyException pe)
+ {
+ Throwable t = pe.getCause();
+
+ if (t instanceof Exception)
+ exceptionListener.exceptionThrown((Exception) t);
+ else
+ throw new InternalError("Unexpected Throwable type in AssemblerException. Please file a bug report.");
+
+ notifyContextFailed();
+
+ return;
+ }
+ }
+
+ /** Analyses the content of the Attributes instance and creates a Context
+ * object accordingly.
+ * An AssemblerException is thrown when the Context instance could not
+ * be created.
+ *
+ * @param attributes Attributes of the XML tag.
+ * @return A Context instance.
+ * @throws AssemblerException when Context instance could not be created.
+ */
+ protected abstract Context startElement(Attributes attributes, ExceptionListener exceptionListener)
+ throws AssemblyException;
+
+ /** Post-processes the Context.
+ */
+ public final void end(ExceptionListener exceptionListener)
+ {
+ // skips processing if the handler is marked as failed (because the Context
+ // is then invalid or may not exist at all)
+ if (!hasFailed)
+ {
+ try
+ {
+ // note: the order of operations is very important here
+ // sends the stored character data to the Context
+ endElement(buffer.toString());
+
+ // reports to the parent handler if this handler's Context is a
+ // statement (returning no value BACK to the parent's Context)
+ if (context.isStatement())
+ {
+ // This may create a valid result in the parent's Context
+ // or let it fail
+ parent.notifyStatement(exceptionListener);
+
+ // skips any further processing if the parent handler is now marked
+ // as failed
+ if (parent.hasFailed())
+ return;
+ }
+
+ // processes the Context and stores the result
+ putObject(context.getId(), context.endContext(parent.getContext()));
+
+ // transfers the Context's results to the parent's Context
+ // if it is an expression (rather than a statement)
+ if (! context.isStatement())
+ parent.getContext().addParameterObject(context.getResult());
+ }
+ catch (AssemblyException pe)
+ {
+ // notifies that an exception was thrown in this handler's Context
+ Throwable t = pe.getCause();
+
+ if (t instanceof Exception)
+ exceptionListener.exceptionThrown((Exception) t);
+ else
+ throw (InternalError) new InternalError("Severe problem while decoding XML data.")
+ .initCause(t);
+
+ // marks the handler as failed
+ notifyContextFailed();
+ }
+ }
+ }
+
+ /** Notifies the handler's Context that its child Context will not return
+ * a value back. Some Context variants need this information to know when
+ * a method or a constructor call can be made.
+ *
+ * This method is called by a child handler.
+ */
+ public void notifyStatement(ExceptionListener exceptionListener)
+ {
+ try
+ {
+
+ // propagates to parent handler first to generate objects
+ // needed by this Context instance
+ if(context.isStatement())
+ {
+ parent.notifyStatement(exceptionListener);
+ }
+
+ // Some Context instances do stuff which can fail now. If that
+ // happens this handler is marked as failed.
+ context.notifyStatement(parent.getContext());
+ }
+ catch (AssemblyException ae)
+ {
+ // notifies that an exception was thrown in this handler's Context
+ Throwable t = ae.getCause();
+
+ if (t instanceof Exception)
+ exceptionListener.exceptionThrown((Exception) t);
+ else
+ throw (InternalError) new InternalError("Severe problem while decoding XML data.")
+ .initCause(t);
+
+ // marks the handler as failed
+ notifyContextFailed();
+ }
+ }
+
+ /** Marks this and any depending parent handlers as failed. Which means that on their end
+ * no result is calculated.
+ *
+ * When a handler has failed no more handlers are accepted within it.
+ */
+ public final void notifyContextFailed()
+ {
+ hasFailed = true;
+
+ // marks the parent handler as failed if its Context
+ // is affected by the failure of this handler's Context
+ if (parent.getContext().subContextFailed())
+ parent.notifyContextFailed();
+ }
+
+ /** Returns whether this handler has failed.
+ *
+ * This is used to skip child elements.
+ *
+ * @return Whether this handler has failed.
+ */
+ public final boolean hasFailed()
+ {
+ return hasFailed;
+ }
+
+ /** Processes the character data when the element ends.
+ *
+ * The default implementation does nothing for convenience.
+ *
+ * @param characters
+ * @throws AssemblerException
+ */
+ protected void endElement(String characters) throws AssemblyException
+ {
+ // XXX: throw an exception when unexpected character data is available?
+ }
+
+ /** Adds characters from the body of the XML tag to the buffer.
+ *
+ * @param ch
+ * @param start
+ * @param length
+ * @throws SAXException
+ */
+ public final void characters(char[] ch, int start, int length)
+ {
+ // simply appends character data
+ buffer.append(ch, start, length);
+ }
+
+ /** Stores an object globally under a unique id. If the id is
+ * null the object is not stored.
+ *
+ * @param objectId
+ * @param o
+ */
+ public void putObject(String objectId, Object o)
+ {
+ if (objectId != null)
+ parent.putObject(objectId, o);
+ }
+
+ /** Returns a previously stored object. If the id is null the
+ * result is null, too.
+ *
+ * @param objectId
+ * @return Returns a previously stored object or null.
+ */
+ public Object getObject(String objectId) throws AssemblyException
+ {
+ return objectId == null ? null : parent.getObject(objectId);
+ }
+
+ /** Returns the Class instance as if called Class.forName() but
+ * uses a ClassLoader given by the user.
+ *
+ * @param className
+ * @return
+ * @throws ClassNotFoundException
+ */
+ public Class instantiateClass(String className)
+ throws ClassNotFoundException
+ {
+ return parent.instantiateClass(className);
+ }
+
+ public final boolean isSubelementAllowed(String subElementName)
+ {
+ return allowsSubelements && ! subElementName.equals("java");
+ }
+
+ public final Context getContext()
+ {
+ return context;
+ }
+
+ public final ElementHandler getParent()
+ {
+ return parent;
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/decoder/AbstractObjectContext.java b/libjava/classpath/gnu/java/beans/decoder/AbstractObjectContext.java
new file mode 100644
index 0000000..202c33b
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/decoder/AbstractObjectContext.java
@@ -0,0 +1,127 @@
+/* gnu.java.beans.decoder.AbstractObjectContext
+ Copyright (C) 2004 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 gnu.java.beans.decoder;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/** AbstractObjectContext is the base for all Context implementations which
+ * create or provide a result object during their lifetime.
+ *
+ * System.err
.notifyStatement()
) is called.Object
that makes
+ the methods hashCode()
and equals(Object)
+ as discriminating as possible.
+*/
+public class ObjectIdentityWrapper
+{
+
+ /**
+ Constructs a ObjectIdentityWrapper
that is wrapped
+ around o.
+ */
+ public ObjectIdentityWrapper( Object o )
+ {
+ object = o;
+ }
+
+ /**
+ Uses System.identityHashCode(Object)
to compute a
+ hash code for the object wrapped by this
+ ObjectIdentityWrapper
.
+
+ @see java.lang.System#identityHashCode(java.lang.Object)
+ @see java.util.Hashtable
+ @see java.lang.Object#hashCode()
+ */
+ public int hashCode()
+ {
+ return System.identityHashCode( object );
+ }
+
+ /**
+ Uses the ==
operator to test for equality between
+ the object wrapped by this ObjectIdentityWrapper
and
+ the object wrapped by the ObjectIdentityWrapper
o.
+ Returns false if o is not a ObjectIdentityWrapper
.
+
+ @see java.util.Hashtable
+ @see java.lang.Object#equals()
+ */
+ public boolean equals( Object o )
+ {
+ if( o instanceof ObjectIdentityWrapper )
+ return object == ((ObjectIdentityWrapper)o).object;
+ else
+ return false;
+ }
+
+ public String toString()
+ {
+ return "ObjectIdentityWrapper< " + object + ", " + hashCode() + " >";
+ }
+
+ /**
+ The Object
wrapped by this
+ ObjectIdentityWrapper
.
+ */
+ public Object object;
+}
diff --git a/libjava/classpath/gnu/java/io/PlatformHelper.java b/libjava/classpath/gnu/java/io/PlatformHelper.java
new file mode 100644
index 0000000..d2c6012
--- /dev/null
+++ b/libjava/classpath/gnu/java/io/PlatformHelper.java
@@ -0,0 +1,228 @@
+/* PlatformHelper.java -- Isolate OS-specific IO helper methods and variables
+ Copyright (C) 1998, 2002 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 gnu.java.io;
+
+import java.util.StringTokenizer;
+
+/**
+ * We had many changes in File.java, URLStreamHandler.java etc. to handle
+ * path representations on different platforms (Windows/Unix-family).
+ * Finally we'd like to collect all these ad hoc codes into this utility class.
+ * --Gansha
+ */
+public class PlatformHelper
+{
+ public static final boolean isWindows = System.getProperty("os.name").indexOf("Windows") >= 0;
+ public static final String separator = System.getProperty("file.separator");
+ public static final char separatorChar = separator.charAt(0);
+ public static final String pathSeparator = System.getProperty("path.separator");
+ public static final char pathSeparatorChar = pathSeparator.charAt(0);
+
+ /**
+ * On most platforms 260 is equal or greater than a max path value,
+ * so we can set the initial buffer size of StringBuffer to half of this value
+ * to improve performance.
+ */
+ public static final int INITIAL_MAX_PATH = 260/2;
+
+ /**
+ * This routine checks the input param "path" whether it begins with root path
+ * prefix.
+ * if not, return 0;
+ * if yes, return the len of root path prefix;
+ * --for Unix-family platform, root path begins with "/" and len is 1
+ * --for Windows platform, root path begins with "drive:\\" and len is 3
+ */
+ public static final int beginWithRootPathPrefix(String path)
+ {
+ if (path.startsWith("/") || path.startsWith("\\"))
+ return 1;
+
+ if (!isWindows)
+ return 0;
+
+ if (path.length() > 2
+ && Character.isLetter(path.charAt(0))
+ && path.charAt(1) == ':'
+ && (path.charAt(2) == '/' || path.charAt(2) == '\\'))
+ return 3;
+
+ return 0;
+ }
+
+ /**
+ * This routine checks the input param "path" whether it's root directory.
+ * --for Unix-family platform, root directory is "/"
+ * --for Windows platform, root directory is "\\" or "drive:\\".
+ */
+ public static final boolean isRootDirectory(String path)
+ {
+ int len = path.length();
+ return len > 0 && beginWithRootPathPrefix(path) == len;
+ }
+
+ /**
+ * This routine canonicalizes input param "path" to formal path representation
+ * for current platform, including interpreting ".." and "." .
+ */
+ public static final String toCanonicalForm(String path)
+ {
+ /*??
+ if(path.indexOf('.') < 0 && path.indexOf("..") < 0)
+ return path;
+ */
+ String tmppath = path.replace('/', separatorChar);
+ StringBuffer canonpath;
+
+ // We found it'll be more efficient and easy to handle to
+ // return a lowercased canonical path
+ if(isWindows)
+ tmppath = tmppath.toLowerCase();
+
+ int i;
+
+ if ((i = beginWithRootPathPrefix(tmppath)) == 0 )
+ return path;
+
+ /* The original
+ "canonpath = new StringBuffer(tmppath.substring(0, i))"
+ isn't very efficient because StringBuffer's
+ ensureCapacity_unsynchronized will fail definitely each time
+ and will enlarge buffer and copy contents. .
+ */
+ canonpath = new StringBuffer(INITIAL_MAX_PATH);
+ canonpath.append(tmppath.substring(0, i));
+ tmppath = tmppath.substring(i);
+ // pathdepth==0 indicates there're only root path in the buffer
+ int pathdepth = 0;
+
+ StringTokenizer st = new StringTokenizer(tmppath, separator);
+
+ // Traverse each element of the path, handling "." and ".."
+ // Should handle "~" too?
+ if (st.hasMoreTokens())
+ do
+ {
+ String s = st.nextToken();
+
+ // Handle "." or an empty element.
+ if (s.equals(".") || s.equals(""))
+ continue;
+
+ // Handle ".." by deleting the last element from the path
+ if (s.equals(".."))
+ {
+ if (pathdepth == 0)
+ continue;
+
+ // Strip of trailing separator
+ canonpath.setLength(canonpath.length() - 1/*separator.length()*/);
+ String tmpstr = canonpath.toString();
+ int idx = tmpstr.lastIndexOf(separator);
+
+ if ((idx == -1) || ((idx + 1/*separator.length()*/) > tmpstr.length()))
+ //throw new IOException("Can't happen error");
+ return path; // Shouldn't happen
+
+ canonpath.setLength(idx + 1/*separator.length()*/);
+ pathdepth--;
+ continue;
+ }
+
+ canonpath.append(s);
+ pathdepth++; //now it's more than root path
+
+ if (st.hasMoreTokens())
+ canonpath.append(separator);
+ }
+ while (st.hasMoreTokens());
+
+ if (endWithSeparator(path))
+ canonpath.append(separator);
+
+ String tmpstr = canonpath.toString();
+ //if (pathdepth > 0 && endWithSeparator(tmpstr) )
+ // tmpstr = tmpstr.substring(0, tmpstr.length() - 1/*separator.length()*/);
+
+ return tmpstr;
+ }
+
+ /**
+ * This routine canonicalizes input param "path" to formal path representation
+ * for current platform, and normalize all separators to "sepchar".
+ */
+ public static final String toCanonicalForm(String path, char sepchar)
+ {
+ String tmpstr = toCanonicalForm(path);
+ tmpstr = tmpstr.replace(separatorChar, sepchar);
+ return tmpstr;
+ }
+
+ /**
+ * This routine checks whether input param "path" ends with separator
+ */
+ public static final boolean endWithSeparator(String path)
+ {
+ if (path.endsWith("\\") || path.endsWith("/"))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * This routine removes from input param "path" the tail separator if it exists,
+ * and return the remain part.
+ */
+ public static final String removeTailSeparator(String path)
+ {
+ if (endWithSeparator(path) && !isRootDirectory(path))
+ return path.substring(0, path.length() - 1);
+
+ return path;
+ }
+
+ /**
+ * This routine returns last index of separator in input param "path",
+ * and return it.
+ */
+ public static final int lastIndexOfSeparator(String path)
+ {
+ return Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/io/class-dependencies.conf b/libjava/classpath/gnu/java/io/class-dependencies.conf
new file mode 100644
index 0000000..2500f6b
--- /dev/null
+++ b/libjava/classpath/gnu/java/io/class-dependencies.conf
@@ -0,0 +1,75 @@
+# This property file contains dependencies of classes, methods, and
+# field on other methods or classes.
+#
+# Syntax:
+#
+# equals(searchFor)
+ */
+ public static boolean contains(Object[] array, Object searchFor)
+ {
+ return indexOf(array, searchFor) != -1;
+ }
+
+ /**
+ * Counterpart to java.util.Collection.indexOf.
+ *
+ * @param array the array to search
+ * @param searchFor the object to locate
+ * @return the index of the first equal object, or -1
+ */
+ public static int indexOf(Object[] array, Object searchFor)
+ {
+ for (int i = 0; i < array.length; i++)
+ {
+ if(array[i].equals(searchFor))
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+}
diff --git a/libjava/classpath/gnu/java/lang/CharData.java b/libjava/classpath/gnu/java/lang/CharData.java
new file mode 100644
index 0000000..b12078d
--- /dev/null
+++ b/libjava/classpath/gnu/java/lang/CharData.java
@@ -0,0 +1,1001 @@
+/* gnu/java/lang/CharData -- Database for java.lang.Character Unicode info
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ *** This file is generated by scripts/unicode-muncher.pl ***
+
+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 gnu.java.lang;
+
+/**
+ * This contains the info about the unicode characters, that
+ * java.lang.Character needs. It is generated automatically from
+ * doc/unicode/UnicodeData-3.0.0.txt
and
+ * doc/unicode/SpecialCasing-2.txt
, by some
+ * perl scripts. These Unicode definition file can be found on the
+ * http://www.unicode.org website.
+ * JDK 1.4 uses Unicode version 3.0.0.
+ *
+ * The data is stored as string constants, but Character will convert these
+ * Strings to their respective char[]
components. The field
+ * BLOCKS
stores the offset of a block of 2SHIFT
+ * characters within DATA
. The DATA field, in turn, stores
+ * information about each character in the low order bits, and an offset
+ * into the attribute tables UPPER
, LOWER
,
+ * NUM_VALUE
, and DIRECTION
. Notice that the
+ * attribute tables are much smaller than 0xffff entries; as many characters
+ * in Unicode share common attributes. The DIRECTION table also contains
+ * a field for detecting characters with multi-character uppercase expansions.
+ * Next, there is a listing for TITLE
exceptions (most characters
+ * just have the same title case as upper case). Finally, there are two
+ * tables for multi-character capitalization, UPPER_SPECIAL
+ * which lists the characters which are special cased, and
+ * UPPER_EXPAND
, which lists their expansion.
+ *
+ * @author scripts/unicode-muncher.pl (written by Jochen Hoenicke,
+ * Eric Blake)
+ * @see Character
+ * @see String
+ */
+public interface CharData
+{
+ /**
+ * The Unicode definition file that was parsed to build this database.
+ */
+ String SOURCE = "doc/unicode/UnicodeData-3.0.0.txt";
+
+ /**
+ * The character shift amount to look up the block offset. In other words,
+ * (char) (BLOCKS.value[ch >> SHIFT] + ch)
is the index where
+ * ch
is described in DATA
.
+ */
+ int SHIFT = 5;
+
+ /**
+ * The mapping of character blocks to their location in DATA
.
+ * Each entry has been adjusted so that the 16-bit sum with the desired
+ * character gives the actual index into DATA
.
+ */
+ String BLOCKS
+ = "\u01c2\u01c2\u01c1\u012c\u012b\u01a0\u01f8\u02dc\u025f\u02ee\u0215"
+ + "\u0346\u02dc\u0326\u02bc\u0216\u015f\u02d4\u0376\u0376\u0376\u0369"
+ + "\ufe8f\u0344\uff85\uff65\ufdb5\ufda1\033\u02c4\034G\ufea8"
+ + "\uff8c\u0235\ufeff\032\ufebf&\ufb20\ufe28\u0113\u0104\ufb61"
+ + "\ufb5a\u010b\u0109\u00fe\uff08\u0229\u025e\u01c7\u01fc\u01dc\ufc46"
+ + "\u0229\ufe27\ufb55\u0169\ufbc8\u00fc\u0103\ufb68\ufb48\ufb28\ufb08"
+ + "\ufae8\ufac8\ufaa8\ufa88\ufa68\ufa48eP\u00ab\u0139\ufe0e"
+ + "c\u0155\u01a8\uf669\u0129\u0128\uf91f\ufe56\u0108\u0107\ufac0"
+ + "\ufc8e\ufead\u00c6\ufca7\ufb95\uf47d\u009f\ufb17\ufe20\ufd28\ufb2f"
+ + ";\uf3b9\ufe57\ufcce\uffbb\uf339\ufa98\uff8b\uff3b\ufa54\uf7e3"
+ + "\uff2b\ufad7\ufb69\ufc3a\ufee5\uf4c8\ufcb0\ufa88\ufdbf\uf448\ufe45"
+ + "\ufcc7\ufe4f\uf7f1\uf715\uf2e8\ufd9f\uf348\uf96a\ufc02\ufd97\uf2c8"
+ + "\uf2a8\uf4b9\uf4b3\uef6b\uf86a\uf84a\ufc58\uf80a\uf7ea\ufc0f\uf7aa"
+ + "\uee9c\ufb90\uf74a\uf7fa\uf70a\uf7ca\uf792\uf471\uf4d2\uf732\uf64a"
+ + "\uf401\uf64d\uefa8\uf5ca\uf5aa\ueca1\uf569\uf54a\uf52a\uf50a\uf4ea"
+ + "\uf4ca\uf4aa\uf48a\uf46a\uf44a\uf42a\uf40a\uf3ea\uf3ca\uf3aa\uf38a"
+ + "\uf36a\uf34a\uf32a\uf289\uf777\uf2ca\uf2aa\uf737\uec28\uec08\uebe8"
+ + "\uebc8\uf1ea\uf4a2\uf545\uedc6\uf2d7\uf14a\ue8ed\ue81e\uf0ea\uf597"
+ + "\uea68\uea48\uea28\uea08\ue9e8\ue9c8\ue9a8\ue988\ue968\ue948\ue928"
+ + "\ue908\ue8e8\ue8c8\ue8a8\ue888\ue868\ue848\ue828\ue808\ue7e8\ue7c8"
+ + "\ue7a8\ue788\ue768\ue748\ue728\ue708\ue6e8\ue6c8\ue6a8\ue688\ue668"
+ + "\ue648\ue628\ue608\ue5e8\ue5c8\ue5a8\ue588\ue568\ue548\ue55f\ue53f"
+ + "\ue51f\ue4ff\uefd7\ue4bf\ue49f\ue485\uef87\uef57\uef57\uef57\uef57"
+ + "\uef47\ue1ad\uef46\uef46\uef46\ue1e0\ue3dd\uef06\ue9d9\uebeb\ue244"
+ + "\ueed4\uef65\ue1f5\uef45\ueee9\uef7c\uee74\uef70\uef7d\uef78\uee91"
+ + "\uefd3\uee7d\uee25\uee27\uef65\uefdd\uee96\uefd3\uefe1\uef69\udf88"
+ + "\udf68\udf48\ued2b\ued3d\ued19\uef1c\uef08\ued47\ued3d\ued33\uec2b"
+ + "\uec0b\uebeb\uebcb\uebce\uea7c\ueb69\ueb6c\ue9b6\ueb0b\ueaeb\ue9e9"
+ + "\udca8\udc88\udc68\udc48\ue910\uea23\ueb58\ueb4f\ueb45\ueae5\udb68"
+ + "\udb48\ue92b\ue90b\ue8eb\ue8cb\ue8ab\ue88b\ue86b\ue84b\uda28\uda08"
+ + "\ud9e8\ud9c8\ud9a8\ud988\ud968\ud948\ud928\ud908\ud8e8\ud8c8\ud8a8"
+ + "\ud888\ud868\ud848\ud828\ud808\ud7e8\ud7c8\ud7a8\ud788\ud768\ud748"
+ + "\ud728\ud708\ud6e8\ud6c8\ud6a8\ud688\ud668\ud648\ud628\ud608\ud5e8"
+ + "\ud5c8\ud5a8\ud588\ud568\ud548\ud528\ud508\ud4e8\ud4c8\ue2b1\ue28b"
+ + "\ue26b\ue270\ue22b\ue20b\ue1eb\ue1cb\ue1ab\ue18b\ue18e\udd8f\ue3a8"
+ + "\udfd3\ud929\ud90a\ue348\ud8c9\ud8aa\udcd7\udcb2\ud681\ud82a\ud80a"
+ + "\ue268\ucede\ud168\ud148\ue116\ue0e9\ue1cb\ue0b7\ue0b7\ue15e\udf17"
+ + "\ue034\ue013\udff3\udfd3\ude6c\udf93\udf73\udf55\udf34\ud56a\ud54a"
+ + "\ud52a\ud50a\ud4ea\ud4ca\ud4aa\ud48a\ud46a\ud44a\ud42a\ud40a\ud3ea"
+ + "\ud3ca\ud3aa\ud38a\ud36a\ud34a\ud32a\ud30a\ud2ea\ud2ca\ud2aa\ud28a"
+ + "\ud26a\ud24a\ud22a\ud20a\ud1ea\ud1ca\ud1aa\ud18a\ud16a\ud14a\ud12a"
+ + "\ud10a\ud0ea\ud0ca\ud0aa\ud08a\ud06a\ud04a\ud02a\ud00a\ucfea\ucfca"
+ + "\ucfaa\ucf8a\ucf6a\ucf4a\ucf2a\ucf0a\uceea\uceca\uceaa\uce8a\uce6a"
+ + "\uce4a\uce2a\uce0a\ucdea\ucdca\ucdaa\ucd8a\ucd6a\ucd4a\ucd2a\ucd0a"
+ + "\uccea\uccca\uccaa\ucc8a\ucc6a\ucc4a\ucc2a\ucc0a\ucbea\ucbca\ucbaa"
+ + "\ucb8a\ucb6a\ucb4a\ucb2a\ucb0a\ucaea\ucaca\ucaaa\uca8a\uca6a\uca4a"
+ + "\uca2a\uca0a\uc9ea\uc9ca\uc9aa\uc98a\uc96a\uc94a\uc92a\uc90a\uc8ea"
+ + "\uc8ca\uc8aa\uc88a\uc86a\uc84a\uc82a\uc80a\uc7ea\uc7ca\uc7aa\uc78a"
+ + "\uc76a\uc74a\uc72a\uc70a\uc6ea\uc6ca\uc6aa\uc68a\uc66a\uc64a\uc62a"
+ + "\uc60a\uc5ea\uc5ca\uc5aa\uc58a\uc56a\uc54a\uc52a\uc50a\uc4ea\uc4ca"
+ + "\uc4aa\uc48a\uc46a\uc44a\uc42a\uc40a\uc3ea\uc3ca\uc3aa\uc38a\uc36a"
+ + "\uc34a\uc32a\uc30a\uc2ea\uc2ca\uc2aa\uc28a\uc26a\uc24a\uc22a\uc20a"
+ + "\uc1ea\uc1ca\uc1aa\uc18a\uc16a\uc14a\uc12a\uc10a\uc0ea\uc0ca\uc0aa"
+ + "\uc08a\uc06a\uc04a\uc02a\uc00a\ubfea\ubfca\ubfaa\ubf8a\ubf6a\ubf4a"
+ + "\ubf2a\ubf0a\ubeea\ubeca\ubeaa\ube8a\ube6a\ube4a\ube2a\ube0a\ubdea"
+ + "\ubdca\ubdaa\ubd8a\ubd6a\ubd4a\ubd2a\ubd0a\ubcea\ubcca\ubcaa\ubc8a"
+ + "\ubc6a\ubc4a\ubc2a\ubc0a\ubbea\ub2e0\ub568\ub548\ubb6a\ubb4a\ubb2a"
+ + "\ubb0a\ubaea\ubaca\ubaaa\uba8a\uba6a\uba4a\uba2a\uba0a\ub9ea\ub9ca"
+ + "\ub9aa\ub98a\ub96a\ub94a\ub92a\ub90a\ub8ea\ub8ca\ub8aa\ub88a\ub86a"
+ + "\ub84a\ub82a\ub80a\ub7ea\ub7ca\ub7aa\ub78a\ub76a\ub74a\ub72a\ub70a"
+ + "\ub6ea\ub6ca\ub6aa\ub68a\ub66a\ub64a\ub62a\ub60a\ub5ea\ub5ca\ub5aa"
+ + "\ub58a\ub56a\ub54a\ub52a\ub50a\ub4ea\ub4ca\ub4aa\ub48a\ub46a\ub44a"
+ + "\ub42a\ub40a\ub3ea\ub3ca\ub3aa\ub38a\ub36a\ub34a\ub32a\ub30a\ub2ea"
+ + "\ub2ca\ub2aa\ub28a\ub26a\ub24a\ub22a\ub20a\ub1ea\ub1ca\ub1aa\ub18a"
+ + "\ub16a\ub14a\ub12a\ub10a\ub0ea\ub0ca\ub0aa\ub08a\ub06a\ub04a\ub02a"
+ + "\ub00a\uafea\uafca\uafaa\uaf8a\uaf6a\uaf4a\uaf2a\uaf0a\uaeea\uaeca"
+ + "\uaeaa\uae8a\uae6a\uae4a\uae2a\uae0a\uadea\uadca\uadaa\uad8a\uad6a"
+ + "\uad4a\uad2a\uad0a\uacea\uacca\uacaa\uac8a\uac6a\uac4a\uac2a\uac0a"
+ + "\uabea\uabca\uabaa\uab8a\uab6a\uab4a\uab2a\uab0a\uaaea\uaaca\uaaaa"
+ + "\uaa8a\uaa6a\uaa4a\uaa2a\uaa0a\ua9ea\ua9ca\ua9aa\ua98a\ua96a\ua94a"
+ + "\ua92a\ua90a\ua8ea\ua8ca\ua8aa\ua88a\ua86a\ua84a\ua82a\ua80a\ua7ea"
+ + "\ua7ca\ua7aa\ua78a\ua76a\ua74a\ua72a\ua70a\ua6ea\ua6ca\ua6aa\ua68a"
+ + "\ua66a\ua64a\ua62a\ua60a\ua5ea\ua5ca\ua5aa\ua58a\ua56a\ua54a\ua52a"
+ + "\ua50a\ua4ea\ua4ca\ua4aa\ua48a\ua46a\ua44a\ua42a\ua40a\ua3ea\ua3ca"
+ + "\ua3aa\ua38a\ua36a\ua34a\ua32a\ua30a\ua2ea\ua2ca\ua2aa\ua28a\ua26a"
+ + "\ua24a\ua22a\ua20a\ua1ea\ua1ca\ua1aa\ua18a\ua16a\ua14a\ua12a\ua10a"
+ + "\ua0ea\ua0ca\ua0aa\ua08a\ua06a\ua04a\ua02a\ua00a\u9fea\u9fca\u9faa"
+ + "\u9f8a\u9f6a\u9f4a\u9f2a\u9f0a\u9eea\u9eca\u9eaa\u9e8a\u9e6a\u9e4a"
+ + "\u9e2a\u9e0a\u9dea\u9dca\u9daa\u9d8a\u9d6a\u9d4a\u9d2a\u9d0a\u9cea"
+ + "\u9cca\u9caa\u9c8a\u9c6a\u9c4a\u9c2a\u9c0a\u9bea\u9bca\u9baa\u9b8a"
+ + "\u9b6a\u9b4a\u9b2a\u9b0a\u9aea\u9aca\u9aaa\u9a8a\u9a6a\u9a4a\u9a2a"
+ + "\u9a0a\u99ea\u99ca\u99aa\u998a\u996a\u994a\u992a\u990a\u98ea\u98ca"
+ + "\u98aa\u988a\u986a\u984a\u982a\u980a\u97ea\u97ca\u97aa\u978a\u976a"
+ + "\u974a\u972a\u970a\u96ea\u96ca\u96aa\u968a\u966a\u964a\u962a\u960a"
+ + "\u95ea\u95ca\u95aa\u958a\u956a\u954a\u952a\u950a\u94ea\u94ca\u94aa"
+ + "\u948a\u946a\u944a\u942a\u940a\u93ea\u93ca\u93aa\u938a\u936a\u934a"
+ + "\u932a\u930a\u92ea\u92ca\u92aa\u928a\u926a\u924a\u922a\u920a\u91ea"
+ + "\u91ca\u91aa\u918a\u916a\u914a\u912a\u910a\u90ea\u90ca\u90aa\u908a"
+ + "\u906a\u904a\u902a\u900a\u8fea\u8fca\u8faa\u8f8a\u8f6a\u8f4a\u8f2a"
+ + "\u8f0a\u8eea\u8eca\u8eaa\u8e8a\u8e6a\u8e4a\u8e2a\u8e0a\u8dea\u8dca"
+ + "\u8daa\u8d8a\u8d6a\u8d4a\u8d2a\u8d0a\u8cea\u8cca\u8caa\u8c8a\u8c6a"
+ + "\u8c4a\u8c2a\u8c0a\u8bea\u8bca\u8baa\u8b8a\u8b6a\u8b4a\u8b2a\u8b0a"
+ + "\u8aea\u8aca\u8aaa\u8a8a\u8a6a\u8a4a\u8a2a\u8a0a\u89ea\u89ca\u89aa"
+ + "\u898a\u896a\u894a\u892a\u890a\u88ea\u88ca\u88aa\u888a\u886a\u884a"
+ + "\u882a\u880a\u87ea\u87ca\u87aa\u878a\u876a\u874a\u872a\u870a\u86ea"
+ + "\u86ca\u86aa\u868a\u866a\u864a\u862a\u860a\u85ea\u85ca\u85aa\u858a"
+ + "\u856a\u854a\u852a\u850a\u84ea\u84ca\u84aa\u848a\u846a\u844a\u842a"
+ + "\u840a\u83ea\u83ca\u83aa\u838a\u836a\u834a\u832a\u830a\u82ea\u82ca"
+ + "\u82aa\u828a\u826a\u824a\u822a\u820a\u81ea\u81ca\u81aa\u818a\u816a"
+ + "\u814a\u812a\u810a\u80ea\u80ca\u80aa\u808a\u806a\u804a\u802a\u800a"
+ + "\u7fea\u7fca\u7faa\u7f8a\u7f6a\u7f4a\u7f2a\u7f0a\u7eea\u7eca\u7eaa"
+ + "\u7e8a\u7e6a\u7e4a\u7e2a\u7e0a\u7dea\u7dca\u7daa\u7d8a\u7d6a\u7d4a"
+ + "\u7d2a\u7d0a\u7cea\u7cca\u7caa\u7c8a\u7c6a\u7c4a\u7c2a\u7c0a\u7bea"
+ + "\u7bca\u7baa\u7b8a\u7b6a\u7b4a\u7b2a\u7b0a\u7aea\u7aca\u7aaa\u7a8a"
+ + "\u7a6a\u7a4a\u7a2a\u7a0a\u79ea\u79ca\u79aa\u798a\u796a\u794a\u792a"
+ + "\u790a\u78ea\u78ca\u78aa\u788a\u786a\u784a\u782a\u780a\u77ea\u77ca"
+ + "\u77aa\u778a\u776a\u774a\u772a\u770a\u76ea\u76ca\u76aa\u768a\u766a"
+ + "\u764a\u762a\u760a\u75ea\u75ca\u75aa\u758a\u756a\u754a\u752a\u750a"
+ + "\u74ea\u74ca\u74aa\u748a\u746a\u744a\u742a\u740a\u73ea\u73ca\u73aa"
+ + "\u738a\u736a\u734a\u732a\u730a\u72ea\u72ca\u72aa\u728a\u726a\u724a"
+ + "\u722a\u720a\u71ea\u71ca\u71aa\u718a\u716a\u714a\u712a\u710a\u70ea"
+ + "\u70ca\u70aa\u708a\u706a\u704a\u702a\u700a\u6fea\u6fca\u6faa\u6f8a"
+ + "\u6f6a\u6f4a\u6f2a\u6f0a\u6eea\u6eca\u6eaa\u6e8a\u6e6a\u6e4a\u6e2a"
+ + "\u6e0a\u6dea\u6dca\u6daa\u6d8a\u6d6a\u6d4a\u6d2a\u6d0a\u6cea\u6cca"
+ + "\u6caa\u6c8a\u6c6a\u6c4a\u6c2a\u6c0a\u6bea\u6bca\u6baa\u6b8a\u6b6a"
+ + "\u6b4a\u6b2a\u6b0a\u6aea\u6aca\u6aaa\u6a8a\u6a6a\u6a4a\u6a2a\u6a0a"
+ + "\u69ea\u60f0\u6368\u6348\u696a\u694a\u692a\u690a\u68ea\u68ca\u68aa"
+ + "\u688a\u686a\u684a\u682a\u680a\u67ea\u67ca\u67aa\u678a\u676a\u674a"
+ + "\u672a\u670a\u66ea\u66ca\u66aa\u668a\u666a\u664a\u662a\u660a\u65ea"
+ + "\u65ca\u65aa\u658a\u656a\u654a\u652a\u650a\u6b26\u6de1\u6e9c\u5e48"
+ + "\u5e28\u5e08\u5de8\u5dc8\u5da8\u5d88\u5d68\u5d48\u5d28\u5d08\u5ce8"
+ + "\u5cc8\u5ca8\u5c88\u5c68\u5c48\u5c28\u5c08\u5be8\u5bc8\u5ba8\u5b88"
+ + "\u5b68\u5b48\u5b28\u5b08\u5ae8\u5ac8\u5aa8\u5a88\u5a68\u5a48\u5a28"
+ + "\u5a08\u59e8\u59c8\u59a8\u5988\u5968\u5948\u5928\u5908\u58e8\u58c8"
+ + "\u58a8\u5888\u5868\u5848\u5828\u5808\u57e8\u57c8\u57a8\u5788\u5768"
+ + "\u5748\u5d6a\u5d4a\u5d2a\u5d0a\u5cea\u5cca\u5caa\u5c8a\u5c6a\u5c4a"
+ + "\u5c2a\u5c0a\u5bea\u5bca\u5baa\u5b8a\u5b6a\u5b4a\u5b2a\u5b0a\u5aea"
+ + "\u5aca\u5aaa\u5a8a\u5a6a\u5a4a\u5a2a\u5a0a\u59ea\u59ca\u59aa\u598a"
+ + "\u596a\u594a\u592a\u590a\u58ea\u58ca\u58aa\u588a\u586a\u584a\u582a"
+ + "\u580a\u57ea\u57ca\u57aa\u578a\u576a\u574a\u572a\u570a\u56ea\u56ca"
+ + "\u56aa\u568a\u566a\u564a\u562a\u560a\u55ea\u55ca\u55aa\u558a\u556a"
+ + "\u554a\u552a\u550a\u54ea\u54ca\u54aa\u548a\u546a\u544a\u542a\u540a"
+ + "\u53ea\u53ca\u53aa\u538a\u536a\u534a\u532a\u530a\u52ea\u52ca\u52aa"
+ + "\u528a\u526a\u524a\u522a\u520a\u51ea\u51ca\u51aa\u518a\u516a\u514a"
+ + "\u512a\u510a\u50ea\u50ca\u50aa\u508a\u506a\u504a\u502a\u500a\u4fea"
+ + "\u4fca\u4faa\u4f8a\u4f6a\u4f4a\u4f2a\u4f0a\u4eea\u4eca\u4eaa\u4e8a"
+ + "\u4e6a\u4e4a\u4e2a\u4e0a\u4dea\u4dca\u4daa\u4d8a\u4d6a\u4d4a\u4d2a"
+ + "\u4d0a\u4cea\u4cca\u4caa\u4c8a\u4c6a\u4c4a\u4c2a\u4c0a\u4bea\u4bca"
+ + "\u4baa\u4b8a\u4b6a\u4b4a\u4b2a\u4b0a\u4aea\u4aca\u4aaa\u4a8a\u4a6a"
+ + "\u4a4a\u4a2a\u4a0a\u49ea\u49ca\u49aa\u498a\u496a\u494a\u492a\u490a"
+ + "\u48ea\u48ca\u48aa\u488a\u486a\u484a\u482a\u480a\u47ea\u47ca\u47aa"
+ + "\u478a\u476a\u474a\u472a\u470a\u46ea\u46ca\u46aa\u468a\u466a\u464a"
+ + "\u462a\u460a\u45ea\u45ca\u45aa\u458a\u456a\u454a\u452a\u450a\u44ea"
+ + "\u44ca\u44aa\u448a\u446a\u444a\u442a\u440a\u43ea\u43ca\u43aa\u438a"
+ + "\u436a\u434a\u432a\u430a\u42ea\u42ca\u42aa\u428a\u426a\u424a\u422a"
+ + "\u420a\u41ea\u41ca\u41aa\u418a\u416a\u414a\u412a\u410a\u40ea\u40ca"
+ + "\u40aa\u408a\u406a\u404a\u402a\u400a\u3fea\u3fca\u3faa\u3f8a\u3f6a"
+ + "\u3f4a\u3f2a\u3f0a\u3eea\u3eca\u3eaa\u3e8a\u3e6a\u3e4a\u3e2a\u3e0a"
+ + "\u3dea\u3dca\u3daa\u3d8a\u3d6a\u3d4a\u3d2a\u3d0a\u3cea\u3cca\u3caa"
+ + "\u3c8a\u3c6a\u3c4a\u3c2a\u3c0a\u3bea\u3bca\u3baa\u3b8a\u3b6a\u3b4a"
+ + "\u3b2a\u3b0a\u3aea\u3aca\u3aaa\u3a8a\u3a6a\u3a4a\u3a2a\u3a0a\u39ea"
+ + "\u39ca\u39aa\u398a\u396a\u394a\u392a\u390a\u38ea\u38ca\u38aa\u388a"
+ + "\u386a\u384a\u382a\u380a\u37ea\u37ca\u37aa\u378a\u376a\u374a\u372a"
+ + "\u370a\u36ea\u36ca\u36aa\u368a\u366a\u364a\u362a\u360a\u35ea\u35ca"
+ + "\u35aa\u358a\u356a\u354a\u352a\u350a\u34ea\u34ca\u34aa\u348a\u346a"
+ + "\u344a\u342a\u340a\u33ea\u33ca\u33aa\u338a\u336a\u334a\u332a\u330a"
+ + "\u32ea\u32ca\u32aa\u328a\u326a\u324a\u322a\u320a\u31ea\u28f2\u2b68"
+ + "\u2b48\u3c2b\u3c0b\u3beb\u3bcb\u3bab\u3b8b\u3b6b\u3b4b\u3b2b\u3b0b"
+ + "\u3aeb\u3acb\u3aab\u3a8b\u3a6b\u3a4b\u3a2b\u3a0b\u39eb\u39cb\u39ab"
+ + "\u398b\u396b\u394b\u392b\u390b\u38eb\u38cb\u38ab\u388b\u386b\u384b"
+ + "\u382b\u380b\u37eb\u37cb\u37ab\u378b\u376b\u374b\u372b\u370b\u36eb"
+ + "\u36cb\u36ab\u368b\u366b\u364b\u362b\u360b\u35eb\u35cb\u35ab\u358b"
+ + "\u356b\u354b\u352b\u350b\u34eb\u34cb\u34ab\u348b\u346b\u344b\u344b"
+ + "\u342b\u340b\u33eb\u33cb\u33ab\u338b\u336b\u334b\u332b\u330b\u32eb"
+ + "\u32cb\u32ab\u328b\u326b\u324b\u322b\u320b\u31eb\u31cb\u31ab\u318b"
+ + "\u316b\u314b\u312b\u310b\u30eb\u30cb\u30ab\u308b\u306b\u304b\u302b"
+ + "\u300b\u2feb\u2fcb\u2fab\u2f8b\u2f6b\u2f4b\u2f2b\u2f0b\u2eeb\u2ecb"
+ + "\u2eab\u2e8b\u2e6b\u2e4b\u2e2b\u2e0b\u2deb\u2dcb\u2dab\u2d8b\u2d6b"
+ + "\u2d4b\u2d2b\u2d0b\u2ceb\u2ccb\u2cab\u2c8b\u2c6b\u2c4b\u2c2b\u2c0b"
+ + "\u2beb\u2bcb\u2bab\u2b8b\u2b6b\u2b4b\u2b2b\u2b0b\u2aeb\u2acb\u2aab"
+ + "\u2a8b\u2a6b\u2a4b\u2a2b\u2a0b\u29eb\u29cb\u29ab\u298b\u296b\u294b"
+ + "\u292b\u290b\u28eb\u28cb\u28ab\u288b\u286b\u284b\u282b\u280b\u27eb"
+ + "\u27cb\u27ab\u278b\u276b\u274b\u272b\u270b\u26eb\u26cb\u26ab\u268b"
+ + "\u266b\u264b\u262b\u260b\u25eb\u25cb\u25ab\u258b\u256b\u254b\u252b"
+ + "\u250b\u24eb\u24cb\u24ab\u248b\u246b\u244b\u242b\u240b\u23eb\u23cb"
+ + "\u23ab\u238b\u236b\u234b\u232b\u230b\u22eb\u22cb\u22ab\u228b\u226b"
+ + "\u224b\u222b\u220b\u21eb\u21cb\u21ab\u218b\u216b\u214b\u212b\u210b"
+ + "\u20eb\u20cb\u20ab\u208b\u206b\u204b\u202b\u200b\u1feb\u1fcb\u1fab"
+ + "\u1f8b\u1f6b\u1f4b\u1f2b\u1f0b\u1eeb\u1ecb\u1eab\u1e8b\u1e6b\u1e4b"
+ + "\u1e2b\u1e0b\u1deb\u1dcb\u1dab\u1d8b\u1d6b\u1d4b\u1d2b\u1d0b\u1ceb"
+ + "\u1ccb\u1cab\u1c8b\u1c6b\u1c4b\u1c2b\u1c0b\u1beb\u1bcb\u1bab\u1b8b"
+ + "\u1b6b\u106a\u104a\u102a\u100a\u0fea\u0fca\u0faa\u0f8a\u0f6a\u0668"
+ + "\u08e8\u08c8\u08a8\u0888\u0868\u0848\u07d7\u194b\u07b6\u0d1c\u0cfc"
+ + "\u0cb2\u0ca9\u0c9c\u0c7c\u0c5c\u0c3c\u0c1c\u0bfc\u0bdc\u0bbc\u0b9c"
+ + "\u0b7c\u0b5e\u0b2c\u0b1c\u0ab8\u0adc\u0a9c\u02c2\u0528\u166b\u1667"
+ + "\u03ff\u09fc\u09dc\u09bc\u0659\u0bb8\u15a7\u0fc6\u01c0\u01b1\u09cb"
+ + "\u082c\u1285";
+
+ /**
+ * Information about each character. The low order 5 bits form the
+ * character type, the next bit is a flag for non-breaking spaces, and the
+ * next bit is a flag for mirrored directionality. The high order 9 bits
+ * form the offset into the attribute tables. Note that this limits the
+ * number of unique character attributes to 512, which is not a problem
+ * as of Unicode version 3.2.0, but may soon become one.
+ */
+ String DATA
+ = "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001"
+ + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082"
+ + "\u3e80\u3e80\u3001\u3082\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85"
+ + "\u3a85\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85"
+ + "\u3e80\u3e80\u3e80\u3e80\u5b88\u5b88\u3e80\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80"
+ + "\u3e80\u3e80\u3e80\u5198\u3e80\u3e80\u3e80\u3e80\u4606\u3e80\u3e80"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u3a85"
+ + "\u3a85\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u3e80\u3e80\u3e80\u3e80\u5202\u5202\u5202\u5202"
+ + "\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202"
+ + "\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202\u5202"
+ + "\u5202\u5202\u5202\u5202\u5202\u2e82\u3e80\u5198\u2a14\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u4606\u4606\u4606\u4606\u4606\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4686\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u1a1b\u1a1b\u3e80\u3e80\u3e80\u3e80\u4584\u3e80\u3e80"
+ + "\u3e80\u0298\u3e80\u0298\u6615\u6696\u0298\u1a97\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u4584\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u4584\u4584\u1a1b\u1a1b\u1a1b\u1a1b"
+ + "\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u4584"
+ + "\u4584\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b"
+ + "\u1a1b\u1a1b\u1a1b\u1a1b\u2e82\u7282\u2e82\u3e80\u2e82\u4902\u7481"
+ + "\u7481\u7481\u7481\u7383\u1a1b\u1a1b\u1a1b\u6d82\u6d82\u4902\u4902"
+ + "\u3e80\u3e80\u2e82\u4902\u6e01\u6e01\u7501\u7501\u3e80\u1a1b\u1a1b"
+ + "\u1a1b\u1b02\u1b82\u1c02\u1c82\u1d02\u1d82\u1e02\u1e82\u1f02\u1f82"
+ + "\u2002\u2082\u2102\u2182\u2202\u2282\u2302\u2382\u2402\u2482\u2502"
+ + "\u2582\u2602\u2682\u2702\u2782\u0455\u0c99\u04d6\u0c99\017\017"
+ + "\017\017\017\u010f\017\017\017\017\017\017\017"
+ + "\017\017\017\017\017\017\017\017\017\017\017"
+ + "\017\017\017\017\017\017\017\017\u008f\u010f\u008f"
+ + "\u018f\u010f\017\017\017\017\017\017\017\017\017"
+ + "\017\017\017\017\017\u010f\u010f\u010f\u008f\u020c\u0298"
+ + "\u0298\u0318\u039a\u0318\u0298\u0298\u0455\u04d6\u0298\u0519\u0598"
+ + "\u0614\u0598\u0698\u0709\u0789\u0809\u0889\u0909\u0989\u0a09\u0a89"
+ + "\u0b09\u0b89\u0598\u0298\u0c59\u0c99\u0c59\u0298\u0d01\u0d81\u0e01"
+ + "\u0e81\u0f01\u0f81\u1001\u1081\u1101\u1181\u1201\u1281\u1301\u1381"
+ + "\u1401\u1481\u1501\u1581\u1601\u1681\u1701\u1781\u1801\u1881\u1901"
+ + "\u1981\u0455\u0298\u04d6\u1a1b\u1a97\u0298\u0298\u0298\u0c99\u0455"
+ + "\u04d6\u3e80\u0298\u0298\u0298\u0298\u0298\u0298\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u282c\u0298\u039a\u039a\u039a\u039a\u289c"
+ + "\u289c\u1a1b\u289c\u2902\u29dd\u0c99\u2a14\u289c\u1a1b\u2a9c\u0519"
+ + "\u2b0b\u2b8b\u1a1b\u2c02\u289c\u0298\u1a1b\u2c8b\u2902\u2d5e\u2d8b"
+ + "\u2d8b\u2d8b\u0298\u0298\u0519\u0614\u0c99\u0c99\u0c99\u3e80\u0298"
+ + "\u039a\u0318\u0298\u3e80\u3e80\u3e80\u3e80\u5405\u5405\u5405\u3e80"
+ + "\u5405\u3e80\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u5405\u3e80\u3e80\u3e80\u4606\u4606\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u4606\u3e80\u501c\u501c\u4f81\u4f81"
+ + "\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81\u4f81"
+ + "\u4f81\u4f81\u4f81\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01"
+ + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01"
+ + "\u2e01\u2e01\u2e01\u2e01\u0c99\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01"
+ + "\u2e01\u2e82\u2e82\u2e82\u4902\u4902\u2e82\u2e82\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u2e82\u2e82"
+ + "\u2e82\u2e82\u2e82\u3e80\u3e80\u3e80\u3e80\u3e80\u5305\u4606\u5305"
+ + "\u5305\u3e80\u5305\u5305\u3e80\u5305\u5305\u5305\u5305\u5305\u5305"
+ + "\u5305\u5305\u5305\u5305\u5405\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5398\u5405\u4606\u4606\u4606\u4606\u4606\u4606\u4606"
+ + "\u5087\u5087\u4606\u5087\u5087\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b"
+ + "\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u840b\u3082\u3001\u3082\u3001\u3082"
+ + "\u3001\u3082\u3001\u3082\u2e82\u3001\u3082\u3001\u3082\u3001\u3082"
+ + "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001"
+ + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082"
+ + "\u3001\u3082\u3001\u3082\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5c09"
+ + "\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u4606\u4606"
+ + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u1a1b\u1a1b\u4701\u0298\u4781\u4781\u4781\u3e80"
+ + "\u4801\u3e80\u4881\u4881\u4902\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01"
+ + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2f02"
+ + "\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02"
+ + "\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02"
+ + "\u0c99\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f82\u2f02\u2f02"
+ + "\u4a82\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u4b02"
+ + "\u4b82\u4b82\u3e80\u4c02\u4c82\u4d01\u4d01\u4d01\u4d82\u4e02\u2902"
+ + "\u3e80\u3e80\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001"
+ + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u2e82\u3b81\u3c03\u3c82"
+ + "\u3001\u3082\u3d81\u3e01\u3001\u3082\u3001\u3082\u3001\u3082\u3001"
+ + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3101\u3182"
+ + "\u3001\u3082\u3001\u3082\u3001\u3082\u2902\u3001\u3082\u3001\u3082"
+ + "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001"
+ + "\u3082\u4e82\u4f02\u3d02\u2902\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5b10\u5b10\u5b10\u5b10\u5b10"
+ + "\u5b10\u7f0b\u3e80\u3e80\u3e80\u7f8b\u800b\u808b\u810b\u818b\u820b"
+ + "\u0519\u0519\u0c99\u0455\u04d6\u2902\u3301\u3001\u3082\u3001\u3082"
+ + "\u3381\u3001\u3082\u3401\u3401\u3001\u3082\u2902\u3481\u3501\u3581"
+ + "\u3001\u3082\u3401\u3601\u3682\u3701\u3781\u3001\u3082\u2902\u2902"
+ + "\u3701\u3801\u2902\u3881\u3a85\u3a85\u3a85\u3a85\u3b81\u3c03\u3c82"
+ + "\u3b81\u3c03\u3c82\u3b81\u3c03\u3c82\u3001\u3082\u3001\u3082\u3001"
+ + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082"
+ + "\u3d02\u3001\u3082\u501c\u4606\u4606\u4606\u4606\u3e80\u5087\u5087"
+ + "\u3e80\u3e80\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001"
+ + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082"
+ + "\u3001\u3082\u3001\u3082\u3201\u3001\u3082\u3001\u3082\u3001\u3082"
+ + "\u3282\u3001\u3082\u3001\u3082\u3001\u3082\u3901\u3001\u3082\u3901"
+ + "\u2902\u2902\u3001\u3082\u3901\u3001\u3082\u3981\u3981\u3001\u3082"
+ + "\u3001\u3082\u3a01\u3001\u3082\u2902\u3a85\u3001\u3082\u2902\u3b02"
+ + "\u4d01\u3001\u3082\u3001\u3082\u3e80\u3e80\u3001\u3082\u3e80\u3e80"
+ + "\u3001\u3082\u3e80\u3e80\u3e80\u3001\u3082\u3001\u3082\u3001\u3082"
+ + "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001"
+ + "\u3082\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u0598\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5398\u3e80\u3e80\u3e80\u5398"
+ + "\u5398\u5398\u5398\u5398\u5398\u5398\u5398\u5398\u5398\u5398\u5398"
+ + "\u5398\u5398\u3e80\u5b10\u5405\u4606\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u3e80\u3e80\u5b10\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01"
+ + "\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01"
+ + "\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01\u4d01"
+ + "\u4d01\u4d01\u4d01\u4d01\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89"
+ + "\u5f09\u5f89\u6009\u6089\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u2902\u2902\u2902\u3f02\u3f82\u2902\u4002"
+ + "\u4002\u2902\u4082\u2902\u4102\u2902\u2902\u2902\u2902\u4002\u2902"
+ + "\u2902\u4182\u2902\u2902\u2902\u2902\u4202\u4282\u2902\u2902\u2902"
+ + "\u2902\u2902\u4282\u2902\u2902\u4302\u2902\u2902\u4382\u2902\u2902"
+ + "\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u4402\u2902\u2902"
+ + "\u4402\u2902\u2902\u2902\u2902\u4402\u2902\u4482\u4482\u2902\u2902"
+ + "\u2902\u2902\u2902\u2902\u4502\u2902\u2902\u2902\u2902\u2902\u2902"
+ + "\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u3e80\u3e80\u4584"
+ + "\u4584\u4584\u4584\u4584\u4584\u4584\u4584\u4584\u1a1b\u1a1b\u4584"
+ + "\u4584\u4584\u4584\u4584\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b"
+ + "\u1a1b\u1a1b\u4584\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5101\u5101"
+ + "\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101"
+ + "\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u5101\u3e80"
+ + "\u3e80\u4584\u5198\u5198\u5198\u5198\u5198\u5198\u2e01\u2e01\u3e80"
+ + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u4982\u4a02"
+ + "\u4a02\u4a02\u4902\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02"
+ + "\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u4f02\u4f02\u4f02"
+ + "\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02\u4f02"
+ + "\u4f02\u4f02\u4606\u4606\u4606\u4606\u4606\u5198\u4606\u4606\u3a85"
+ + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u4606\u4606\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u3e80\u4606\u4606\u4606\u4606\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u4606\u3e80\u4606\u4606\u4606\u5298"
+ + "\u4606\u4606\u5298\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u5305\u5305\u5305\u5305\u5305\u5305\u5305"
+ + "\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u5305\u5305\u5305\u5298\u5298\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5c89\u5d09\u5d89"
+ + "\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u640b\u648b\u650b\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u4606\u5b88\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80"
+ + "\u3e80\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80"
+ + "\u3e80\u3a85\u3a85\u3e80\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3e80"
+ + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606"
+ + "\u4606\u5b88\u5b88\u5b88\u5b88\u3e80\u4606\u4606\u4606\u3e80\u4606"
+ + "\u4606\u4606\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u4606"
+ + "\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u4606"
+ + "\u5b88\u5b88\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3e80\u3e80\u3a85\u3a85\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80"
+ + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3e80\u3e80\u3e80\u3e80\u5b88\u5b88\u3e80\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3a85\u3a85\u3a85"
+ + "\u3e80\u3e80\u3e80\u3e80\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09"
+ + "\u5f89\u6009\u6089\u501c\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5509\u5589\u5609"
+ + "\u5689\u5709\u5789\u5809\u5889\u5909\u5989\u0318\u5a18\u5a18\u5398"
+ + "\u3e80\u3e80\u4606\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u3e80\u3e80\u5405"
+ + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u5405\u6615\u6696\u5484\u5405\u5405\u5405\u5405"
+ + "\u5405\u5405\u5405\u5405\u5405\u5405\u4606\u4606\u4606\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u4606\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u5b88\u5b88\u5198\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u4606\u4606\u5b88"
+ + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3e80"
+ + "\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u5198\u5198\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u4606\u4606\u4606\u4606\u4606\u5484\u5484\u4606"
+ + "\u4606\u289c\u4606\u4606\u4606\u4606\u3e80\u3e80\u0709\u0789\u0809"
+ + "\u0889\u0909\u0989\u0a09\u0a89\u0b09\u0b89\u5405\u5405\u5405\u5a9c"
+ + "\u5a9c\u3e80\u3a85\u3a85\u3a85\u3e80\u3a85\u3e80\u3a85\u3e80\u3e80"
+ + "\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u4606\u3a85\u3a85\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u3e80\u4606\u4606\u3a85\u3e80\u3e80"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u4606\u4606\u5b88"
+ + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3e80\u3e80\u4606\u3a85\u5b88\u5b88\u5b88\u5b88\u5b88\u3e80\u4606"
+ + "\u5b88\u5b88\u3e80\u5b88\u5b88\u4606\u4606\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u5b88\u5b88\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3a85\u3e80\u5198\u5198\u5198\u5198\u5198\u5198\u5198\u5198"
+ + "\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u640b\u670b"
+ + "\u678b\u680b\u688b\u690b\u698b\u6a0b\u6a8b\u648b\u6b0b\u3e80\u3e80"
+ + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3e80"
+ + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u4606\u3a85\u5b88\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u5b88\u5b88\u5b88\u5b88"
+ + "\u4606\u3e80\u3e80\u3a85\u4606\u4606\u4606\u4606\u3e80\u3e80\u3e80"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3e80\u3e80\u3e80"
+ + "\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u4606\u3e80\u5b88\u5b88\u5b88"
+ + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85"
+ + "\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3e80\u3a85"
+ + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3e80\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u4606\u3a85\u3a85\u4606\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u3e80\u3e80\u3e80\u3e80\u039a\u039a\u039a"
+ + "\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a"
+ + "\u039a\u039a\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u4606\u4606"
+ + "\u5198\u5198\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009"
+ + "\u6089\u5198\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u0298\u0298\u0318\u039a\u0318"
+ + "\u0298\u0298\u6615\u6696\u0298\u0519\u0598\u0614\u0598\u0698\u0709"
+ + "\u0789\u0809\u0889\u0909\u0989\u0a09\u0a89\u0b09\u0b89\u0598\u0298"
+ + "\u0c99\u0c99\u0c99\u0298\u0298\u0298\u0298\u0298\u0298\u2a14\u0298"
+ + "\u0298\u0298\u0298\u5b10\u5b10\u5b10\u5b10\u3e80\u5c09\u5c89\u5d09"
+ + "\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u5b88"
+ + "\u4606\u4606\u4606\u4606\u3e80\u3e80\u5b88\u5b88\u3e80\u3e80\u5b88"
+ + "\u5b88\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u5b88\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u3e80\u3a85\u3e80\u3e80"
+ + "\u3a85\u3a85\u3e80\u3a85\u3e80\u3e80\u3a85\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3e80\u3a85\u3a85\u3e80\u3a85\u3a85\u3e80\u3a85\u3a85"
+ + "\u3e80\u3e80\u4606\u3e80\u5b88\u5b88\u4606\u4606\u3e80\u3e80\u3e80"
+ + "\u3e80\u4606\u4606\u3e80\u3e80\u4606\u4606\u4606\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85"
+ + "\u3a85\u3e80\u3a85\u3e80\u3a85\u3a85\u4606\u4606\u3e80\u3e80\u5c09"
+ + "\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u3a85\u3a85"
+ + "\u039a\u039a\u610b\u618b\u620b\u628b\u630b\u638b\u501c\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3a85"
+ + "\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u4606\u3a85"
+ + "\u5b88\u5b88\u4606\u4606\u4606\u4606\u4606\u3e80\u4606\u4606\u5b88"
+ + "\u3e80\u5b88\u5b88\u4606\u3e80\u3e80\u3a85\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u630b"
+ + "\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u501c\u4606"
+ + "\u501c\u4606\u501c\u4606\u6615\u6696\u6615\u6696\u5b88\u5b88\u4606"
+ + "\u4606\u4606\u3e80\u3e80\u3e80\u5b88\u5b88\u3e80\u3e80\u5b88\u5b88"
+ + "\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u4606\u5b88"
+ + "\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3e80\u3a85\u3a85\u3e80\u5b88\u4606\u4606\u4606\u4606\u5b88"
+ + "\u4606\u3e80\u3e80\u3e80\u4606\u4606\u5b88\u4606\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u5b88\u5b88\u5b88\u4606\u4606\u4606\u4606\u4606\u4606\u4606"
+ + "\u5b88\u5b88\u3e80\u3e80\u3e80\u5b88\u5b88\u5b88\u3e80\u5b88\u5b88"
+ + "\u5b88\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u5b88\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3e80\u4584\u3e80\u4606\u4606\u4606\u4606\u4606"
+ + "\u4606\u3e80\u3e80\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89"
+ + "\u6009\u6089\u3e80\u3e80\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u5c09"
+ + "\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u5087\u5087\u5087\u5b88\u4606\u4606"
+ + "\u4606\u3e80\u3e80\u5b88\u5b88\u5b88\u3e80\u5b88\u5b88\u5b88\u4606"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u5b88\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u4606\u3e80\u3e80\u3e80\u3e80"
+ + "\u5b88\u5b88\u5b88\u4606\u4606\u4606\u3e80\u4606\u3e80\u5b88\u5b88"
+ + "\u5b88\u5b88\u5b88\u5b88\u5b88\u5b88\u4606\u5b88\u5b88\u4606\u4606"
+ + "\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u4606\u5198\u5198"
+ + "\u5198\u5198\u5198\u5198\u5198\u039a\u5198\u3e80\u3e80\u3e80\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u4584\u4606\u4606\u4606\u4606\u4606"
+ + "\u4606\u4606\u4606\u5198\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09"
+ + "\u5f89\u6009\u6089\u5198\u5198\u3e80\u3e80\u3e80\u3e80\u3a85\u501c"
+ + "\u501c\u501c\u5198\u5198\u5198\u5198\u5198\u5198\u5198\u5198\u65b8"
+ + "\u5198\u5198\u5198\u5198\u5198\u5198\u501c\u501c\u501c\u501c\u501c"
+ + "\u4606\u4606\u501c\u501c\u501c\u501c\u501c\u501c\u4606\u501c\u501c"
+ + "\u501c\u501c\u501c\u501c\u3e80\u3e80\u501c\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u1a97\u4584\u4584\u4584"
+ + "\u3e80\u5c09\u5c89\u5d09\u5d89\u5e09\u5e89\u5f09\u5f89\u6009\u6089"
+ + "\u5198\u5198\u5198\u5198\u5198\u5198\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u5b88\u5b88\u4606\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u020c\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u6615\u6696\u3e80\u3e80\u3e80\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u5198"
+ + "\u5198\u5198\u6b8b\u6c0b\u6c8b\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u4606\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3001\u3082\u3001"
+ + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082"
+ + "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u2e82\u2e82\u2e82"
+ + "\u2e82\u2e82\u6d02\u3e80\u3e80\u3e80\u3e80\u6d82\u6d82\u6d82\u6d82"
+ + "\u6d82\u6d82\u6d82\u6d82\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01"
+ + "\u6e01\u6d82\u6d82\u6d82\u6d82\u6d82\u6d82\u6d82\u6d82\u6e01\u6e01"
+ + "\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u6d82\u6d82\u6d82\u6d82\u6d82"
+ + "\u6d82\u3e80\u3e80\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u3e80\u3e80"
+ + "\u2e82\u6d82\u4902\u6d82\u4902\u6d82\u4902\u6d82\u3e80\u6e01\u3e80"
+ + "\u6e01\u3e80\u6e01\u3e80\u6e01\u6d82\u6d82\u6d82\u6d82\u6d82\u6d82"
+ + "\u6d82\u6d82\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u6e01\u6e82"
+ + "\u6e82\u6f02\u6f02\u6f02\u6f02\u6f82\u6f82\u7002\u7002\u7082\u7082"
+ + "\u7102\u7102\u3e80\u3e80\u7182\u7182\u7182\u7182\u7182\u7182\u7182"
+ + "\u7182\u7203\u7203\u7203\u7203\u7203\u7203\u7203\u7203\u7182\u7182"
+ + "\u7182\u7182\u7182\u7182\u7182\u7182\u7203\u7203\u7203\u7203\u7203"
+ + "\u7203\u7203\u7203\u6d82\u6d82\u2e82\u7282\u2e82\u3e80\u2e82\u4902"
+ + "\u6e01\u6e01\u7301\u7301\u7383\u1a1b\u7402\u1a1b\u1b02\u1b82\u1c02"
+ + "\u1c82\u1d02\u1d82\u1e02\u1e82\u1f02\u1f82\u2002\u2082\u2102\u2182"
+ + "\u2202\u2282\u2302\u2382\u2402\u2482\u2502\u2582\u2602\u2682\u2702"
+ + "\u2782\u6615\u0c99\u6696\u0c99\u3e80\u6d82\u6d82\u4902\u4902\u2e82"
+ + "\u7582\u2e82\u4902\u6e01\u6e01\u7601\u7601\u7681\u1a1b\u1a1b\u1a1b"
+ + "\u3e80\u3e80\u2e82\u7282\u2e82\u3e80\u2e82\u4902\u7701\u7701\u7781"
+ + "\u7781\u7383\u1a1b\u1a1b\u3e80\u020c\u020c\u020c\u020c\u020c\u020c"
+ + "\u020c\u782c\u020c\u020c\u020c\u788c\u5b10\u5b10\u7910\u7990\u2a14"
+ + "\u7a34\u2a14\u2a14\u2a14\u2a14\u0298\u0298\u7a9d\u7b1e\u6615\u7a9d"
+ + "\u7a9d\u7b1e\u6615\u7a9d\u0298\u0298\u0298\u0298\u0298\u0298\u0298"
+ + "\u0298\u7b8d\u7c0e\u7c90\u7d10\u7d90\u7e10\u7e90\u782c\u0318\u0318"
+ + "\u0318\u0318\u0318\u0298\u0298\u0298\u0298\u29dd\u2d5e\u0298\u0298"
+ + "\u0298\u0298\u1a97\u7f0b\u2c8b\u2b0b\u2b8b\u7f8b\u800b\u808b\u810b"
+ + "\u818b\u820b\u0519\u0519\u0c99\u0455\u04d6\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u3e80\u3e80\u3e80\u3e80\u3e80\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u4d01\u289c\u289c\u289c\u289c"
+ + "\u4d01\u289c\u289c\u2902\u4d01\u4d01\u4d01\u2902\u2902\u4d01\u4d01"
+ + "\u4d01\u2902\u289c\u4d01\u289c\u289c\u289c\u4d01\u4d01\u4d01\u4d01"
+ + "\u4d01\u289c\u289c\ua20a\ua28a\ua30a\ua38a\ua40a\ua48a\ua50a\ua58a"
+ + "\ua60a\u4606\u4606\u4606\u4606\u4606\u4606\u2a14\u4584\u4584\u4584"
+ + "\u4584\u4584\u289c\u289c\ua68a\ua70a\ua78a\u3e80\u3e80\u3e80\u289c"
+ + "\u289c\u289c\u289c\u3e80\u289c\u289c\u289c\u289c\u3e80\u3e80\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u0c99\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u0c99\u0c99\u289c\u289c\u0c99\u289c\u0c99"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u0c99\u289c\u289c\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u948a"
+ + "\u950a\u958a\u960a\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u0c99\u0c99\u0c99\u0c99\u0c99\u289c\u289c"
+ + "\u289c\u289c\u289c\u0c99\u0c99\u289c\u289c\u289c\u289c\u4d01\u289c"
+ + "\u8281\u289c\u4d01\u289c\u8301\u8381\u4d01\u4d01\u2a9c\u2902\u4d01"
+ + "\u4d01\u289c\u4d01\u2902\u3a85\u3a85\u3a85\u3a85\u2902\u289c\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u848a\u850a\u858a\u860a\u868a\u870a\u878a"
+ + "\u880a\u888a\u890a\u898a\u8a0a\u8a8a\u8b0a\u8b8a\u8c0a\u8c8a\u8d0a"
+ + "\u8d8a\u8e0a\u8e8a\u8f0a\u8f8a\u900a\u908a\u910a\u918a\u920a\u928a"
+ + "\u930a\u938a\u940a\u0c99\u0c99\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59"
+ + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59"
+ + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99"
+ + "\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99"
+ + "\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59"
+ + "\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59"
+ + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59\u0c59"
+ + "\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c99\u0c99\u0c99\u0c99"
+ + "\u0c99\u0c99\u0c99\u289c\u289c\u0c99\u289c\u289c\u0c99\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u0c99\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u3e80\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u0c99\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59"
+ + "\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c59\u0519\u0519\u0c99\u0c59"
+ + "\u0c59\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c99\u0c59\u0c99"
+ + "\u0c59\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59"
+ + "\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c99\u0c59"
+ + "\u0c59\u0c59\u0c59\u0c59\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u0455\u04d6\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c"
+ + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c"
+ + "\u501c\u501c\u501c\u3e80\u3e80\u3e80\u3e80\u501c\u501c\u501c\u501c"
+ + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c"
+ + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u9c1c\u9c1c\u9c1c\u9c1c"
+ + "\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c\u9c1c"
+ + "\u9c1c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c"
+ + "\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u9c9c\u7f0b\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u0c59\u0c99\u0c59\u0c99\u0c59"
+ + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59"
+ + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59"
+ + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u039a\u039a\u0c99\u1a1b\u289c\u039a\u039a\u3e80\u289c\u0c99"
+ + "\u0c99\u0c99\u0c99\u289c\u289c\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u5b10\u5b10\u5b10\u289c\u289c\u3e80\u3e80"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u3e80\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u3e80\u289c"
+ + "\u3e80\u289c\u289c\u289c\u289c\u3e80\u3e80\u3e80\u289c\u3e80\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u840b\u9d0b"
+ + "\u9d8b\u9e0b\u9e8b\u9f0b\u9f8b\ua00b\ua08b\ua10b\u840b\u9d0b\u9d8b"
+ + "\u9e0b\u9e8b\u9f0b\u9f8b\ua00b\ua08b\ua10b\u289c\u3e80\u3e80\u3e80"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u0c59\u0c59\u0c59"
+ + "\u0c59\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c"
+ + "\u501c\u289c\u289c\u289c\u289c\u289c\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u630b\u501c"
+ + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c"
+ + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c"
+ + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u3e80\u3e80"
+ + "\u3e80\u501c\u610b\u618b\u620b\u628b\ua80b\ua88b\ua90b\ua98b\uaa0b"
+ + "\u640b\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c"
+ + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c"
+ + "\u501c\u501c\u501c\u501c\u501c\u501c\u289c\u3e80\u289c\u289c\u289c"
+ + "\u3e80\u289c\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u2c8b\u2b0b\u2b8b\u7f8b\u800b\u808b"
+ + "\u810b\u818b\u820b\u968b\u970b\u978b\u980b\u988b\u990b\u998b\u9a0b"
+ + "\u9a8b\u9b0b\u9b8b\u2c8b\u2b0b\u2b8b\u7f8b\u800b\u808b\u810b\u818b"
+ + "\u820b\u968b\u970b\u978b\u980b\u988b\u990b\u998b\u9a0b\u9a8b\u9b0b"
+ + "\u9b8b\u501c\u501c\u501c\u501c\u020c\u0298\u0298\u0298\u289c\u4584"
+ + "\u3a85\ua18a\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455"
+ + "\u04d6\u289c\u289c\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455\u04d6"
+ + "\u2a14\u6615\u6696\u6696\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3e80\u3e80\u3e80\u3e80\u4606\u4606\u1a1b\u1a1b"
+ + "\u4584\u4584\u3e80\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85"
+ + "\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3a85\u3e80\u501c\u501c\u630b"
+ + "\u630b\u630b\u630b\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c"
+ + "\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u501c\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93"
+ + "\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93"
+ + "\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93\uaa93"
+ + "\uaa93\uaa93\uaa93\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12"
+ + "\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12"
+ + "\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12\uab12"
+ + "\uab12\uab12\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305"
+ + "\u0519\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305\u5305"
+ + "\u5305\u5305\u5305\u3e80\u5305\u5305\u5305\u5305\u5305\u3e80\u5305"
+ + "\u3e80\u4606\u4606\u4606\u4606\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80"
+ + "\u3e80\u3e80\u3e80\u3e80\u3e80\u3e80\u0298\u2a14\u2a14\u1a97\u1a97"
+ + "\u6615\u6696\u6615\u6696\u6615\u6696\u6615\u6696\u6615\u6696\u6615"
+ + "\u6696\u3e80\u3e80\u3e80\u3e80\u0298\u0298\u0298\u0298\u1a97\u1a97"
+ + "\u1a97\u0598\u0298\u0598\u3e80\u0298\u0598\u0298\u0298\u2a14\u6615"
+ + "\u6696\u6615\u6696\u6615\u6696\u0318\u0298\u0d01\u0d81\u0e01\u0e81"
+ + "\u0f01\u0f81\u1001\u1081\u1101\u1181\u1201\u1281\u1301\u1381\u1401"
+ + "\u1481\u1501\u1581\u1601\u1681\u1701\u1781\u1801\u1881\u1901\u1981"
+ + "\u6615\u0298\u6696\u1a1b\u1a97";
+
+ /**
+ * This is the attribute table for computing the numeric value of a
+ * character. The value is -1 if Unicode does not define a value, -2
+ * if the value is not a positive integer, otherwise it is the value.
+ * Note that this is a signed value, but stored as an unsigned char
+ * since this is a String literal.
+ */
+ String NUM_VALUE
+ = "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff"
+ + "\uffff\uffff\uffff\000\001\002\003\004\005\006\007"
+ + "\010\011\uffff\uffff\012\013\014\015\016\017\020"
+ + "\021\022\023\024\025\026\027\030\031\032\033"
+ + "\034\035\036\037 !\"#\uffff\uffff\012"
+ + "\013\014\015\016\017\020\021\022\023\024\025"
+ + "\026\027\030\031\032\033\034\035\036\037 "
+ + "!\"#\uffff\uffff\uffff\uffff\uffff\uffff\002\003"
+ + "\uffff\001\uffff\ufffe\uffff\uffff\uffff\uffff\uffff\uffff\uffff"
+ + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff"
+ + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff"
+ + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff"
+ + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff"
+ + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff"
+ + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff"
+ + "\uffff\uffff\uffff\uffff\uffff\000\001\002\003\004\005"
+ + "\006\007\010\011\uffff\uffff\uffff\uffff\000\001\002"
+ + "\003\004\005\006\007\010\011\001\002\003\004"
+ + "\uffff\020\012d\u03e8\uffff\uffff\uffff\024\036("
+ + "2Class
s or Member
s.
+ * More specific methods are also provided for computing the
+ * type-signature of Constructor
s and
+ * Method
s. Methods are also provided to go in the
+ * reverse direction.
+ *
+ * @author Eric Blake (ebb9@email.byu.edu)
+ */
+public class TypeSignature
+{
+ /**
+ * Returns a String
representing the type-encoding of a class.
+ * The .class file format has different encodings for classes, depending
+ * on whether it must be disambiguated from primitive types or not; hence
+ * the descriptor parameter to choose between them. If you are planning
+ * on decoding primitive types along with classes, then descriptor should
+ * be true for correct results. Type-encodings are computed as follows:
+ *
+ *
+ * boolean -> "Z"
+ * byte -> "B"
+ * char -> "C"
+ * double -> "D"
+ * float -> "F"
+ * int -> "I"
+ * long -> "J"
+ * short -> "S"
+ * void -> "V"
+ * arrays -> "[" + descriptor format of component type
+ * object -> class format: fully qualified name with '.' replaced by '/'
+ * descriptor format: "L" + class format + ";"
+ *
+ *
+ * @param type the class name to encode
+ * @param descriptor true to return objects in descriptor format
+ * @return the class name, as it appears in bytecode constant pools
+ * @see #getClassForEncoding(String)
+ */
+ public static String getEncodingOfClass(String type, boolean descriptor)
+ {
+ if (! descriptor || type.charAt(0) == '[')
+ return type.replace('.', '/');
+ if (type.equals("boolean"))
+ return "Z";
+ if (type.equals("byte"))
+ return "B";
+ if (type.equals("short"))
+ return "S";
+ if (type.equals("char"))
+ return "C";
+ if (type.equals("int"))
+ return "I";
+ if (type.equals("long"))
+ return "J";
+ if (type.equals("float"))
+ return "F";
+ if (type.equals("double"))
+ return "D";
+ if (type.equals("void"))
+ return "V";
+ return 'L' + type.replace('.', '/') + ';';
+ }
+
+ /**
+ * Gets the descriptor encoding for a class.
+ *
+ * @param clazz the class to encode
+ * @param descriptor true to return objects in descriptor format
+ * @return the class name, as it appears in bytecode constant pools
+ * @see #getEncodingOfClass(String, boolean)
+ */
+ public static String getEncodingOfClass(Class clazz, boolean descriptor)
+ {
+ return getEncodingOfClass(clazz.getName(), descriptor);
+ }
+
+ /**
+ * Gets the descriptor encoding for a class.
+ *
+ * @param clazz the class to encode
+ * @return the class name, as it appears in bytecode constant pools
+ * @see #getEncodingOfClass(String, boolean)
+ */
+ public static String getEncodingOfClass(Class clazz)
+ {
+ return getEncodingOfClass(clazz.getName(), true);
+ }
+
+
+ /**
+ * This function is the inverse of getEncodingOfClass
. This
+ * accepts both object and descriptor formats, but must know which style
+ * of string is being passed in (usually, descriptor should be true). In
+ * descriptor format, "I" is treated as int.class, in object format, it
+ * is treated as a class named I in the unnamed package. This method is
+ * strictly equivalent to {@link #getClassForEncoding(java.lang.String, boolean, java.lang.ClassLoader)}
+ * with a class loader equal to null
. In that case, it
+ * uses the default class loader on the calling stack.
+ *
+ * @param type_code the class name to decode
+ * @param descriptor if the string is in descriptor format
+ * @return the corresponding Class object
+ * @throws ClassNotFoundException if the class cannot be located
+ * @see #getEncodingOfClass(Class, boolean)
+ */
+ public static Class getClassForEncoding(String type_code, boolean descriptor)
+ throws ClassNotFoundException
+ {
+ return getClassForEncoding(type_code, descriptor, null);
+ }
+
+ /**
+ * This function is the inverse of getEncodingOfClass
. This
+ * accepts both object and descriptor formats, but must know which style
+ * of string is being passed in (usually, descriptor should be true). In
+ * descriptor format, "I" is treated as int.class, in object format, it
+ * is treated as a class named I in the unnamed package.
+ *
+ * @param type_code The class name to decode.
+ * @param descriptor If the string is in descriptor format.
+ * @param loader The class loader when resolving generic object name. If
+ * loader
is null then it uses the default class loader on the
+ * calling stack.
+ * @return the corresponding Class object.
+ * @throws ClassNotFoundException if the class cannot be located.
+ * @see #getEncodingOfClass(Class, boolean)
+ * @see #getClassForEncoding(String, boolean)
+ */
+ public static Class getClassForEncoding(String type_code, boolean descriptor,
+ ClassLoader loader)
+ throws ClassNotFoundException
+ {
+ if (descriptor)
+ {
+ switch (type_code.charAt(0))
+ {
+ case 'B':
+ return byte.class;
+ case 'C':
+ return char.class;
+ case 'D':
+ return double.class;
+ case 'F':
+ return float.class;
+ case 'I':
+ return int.class;
+ case 'J':
+ return long.class;
+ case 'S':
+ return short.class;
+ case 'V':
+ return void.class;
+ case 'Z':
+ return boolean.class;
+ default:
+ throw new ClassNotFoundException("Invalid class name: "
+ + type_code);
+ case 'L':
+ type_code = type_code.substring(1, type_code.length() - 1);
+ // Fallthrough.
+ case '[':
+ }
+ }
+ return Class.forName(type_code.replace('/', '.'), true, loader);
+ }
+
+ /**
+ * Gets the Class object for a type name.
+ *
+ * @param type_code the class name to decode
+ * @return the corresponding Class object
+ * @throws ClassNotFoundException if the class cannot be located
+ * @see #getClassForEncoding(String, boolean)
+ */
+ public static Class getClassForEncoding(String type_code)
+ throws ClassNotFoundException
+ {
+ return getClassForEncoding(type_code, true);
+ }
+
+ /**
+ * Returns a String
representing the type-encoding of a
+ * method. The type-encoding of a method is:
+ *
+ * "(" + parameter type descriptors + ")" + return type descriptor
+ *
+ * XXX This could be faster if it were implemented natively.
+ *
+ * @param m the method to encode
+ * @return the encoding
+ */
+ public static String getEncodingOfMethod(Method m)
+ {
+ Class[] paramTypes = m.getParameterTypes();
+ StringBuffer buf = new StringBuffer().append('(');
+ for (int i = 0; i < paramTypes.length; i++)
+ buf.append(getEncodingOfClass(paramTypes[i].getName(), true));
+ buf.append(')').append(getEncodingOfClass(m.getReturnType().getName(),
+ true));
+ return buf.toString();
+ }
+
+ /**
+ * Returns a String
representing the type-encoding of a
+ * constructor. The type-encoding of a method is:
+ *
+ * "(" + parameter type descriptors + ")V"
+ *
+ * XXX This could be faster if it were implemented natively.
+ *
+ * @param c the constructor to encode
+ * @return the encoding
+ */
+ public static String getEncodingOfConstructor(Constructor c)
+ {
+ Class[] paramTypes = c.getParameterTypes();
+ StringBuffer buf = new StringBuffer().append('(');
+ for (int i = 0; i < paramTypes.length; i++)
+ buf.append(getEncodingOfClass(paramTypes[i].getName(), true));
+ buf.append(")V");
+ return buf.toString();
+ }
+
+ /**
+ * Returns a String
representing the type-encoding of a
+ * class member. This appropriately handles Constructors, Methods, and
+ * Fields.
+ *
+ * @param mem the member to encode
+ * @return the encoding
+ */
+ public static String getEncodingOfMember(Member mem)
+ {
+ if (mem instanceof Constructor)
+ return getEncodingOfConstructor((Constructor) mem);
+ if (mem instanceof Method)
+ return getEncodingOfMethod((Method) mem);
+ else // Field
+ return getEncodingOfClass(((Field) mem).getType().getName(), true);
+ }
+} // class TypeSignature
diff --git a/libjava/classpath/gnu/java/lang/reflect/package.html b/libjava/classpath/gnu/java/lang/reflect/package.html
new file mode 100644
index 0000000..a837d37
--- /dev/null
+++ b/libjava/classpath/gnu/java/lang/reflect/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+ *
+ * String
, hopefully containing the localized
+ * variant of the input data.
+ * @throws NullPointerException if inLocale
is null.
+ */
+ public static String getLocalizedString(Locale inLocale, String key,
+ String name, boolean checkEnglish,
+ boolean checkRoot)
+ {
+ String localizedString;
+ String property;
+
+ if (key.equals(""))
+ return "";
+ property = name + "." + key;
+ /* Localize to inLocale */
+ try
+ {
+ localizedString =
+ ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
+ inLocale).getString(property);
+ }
+ catch (MissingResourceException exception)
+ {
+ localizedString = null;
+ }
+ /* Localize to default locale */
+ if (localizedString == null)
+ {
+ try
+ {
+ ResourceBundle bundle;
+
+ bundle =
+ ResourceBundle.getBundle("gnu.java.locale.LocaleInformation");
+ localizedString = bundle.getString(property);
+ }
+ catch (MissingResourceException exception)
+ {
+ localizedString = null;
+ }
+ }
+ /* Localize to English */
+ if (localizedString == null && checkEnglish)
+ {
+ try
+ {
+ localizedString =
+ ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
+ Locale.ENGLISH).getString(property);
+ }
+ catch (MissingResourceException exception)
+ {
+ localizedString = null;
+ }
+ }
+ /* Return unlocalized version */
+ if (localizedString == null && checkRoot)
+ {
+ try
+ {
+ localizedString =
+ ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
+ new Locale("","","")
+ ).getString(property);
+ }
+ catch (MissingResourceException exception)
+ {
+ localizedString = null;
+ }
+ }
+ /* Return original input string */
+ if (localizedString == null)
+ {
+ localizedString = key;
+ }
+ return localizedString;
+ }
+}
+
diff --git a/libjava/classpath/gnu/java/locale/package.html b/libjava/classpath/gnu/java/locale/package.html
new file mode 100644
index 0000000..c4bc7c3
--- /dev/null
+++ b/libjava/classpath/gnu/java/locale/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+IllegalBlockingModeException
if the
+ * associated channel is in non-blocking mode, except
+ * if the operation is invoked by the channel itself.
+ */
+ public final boolean isInChannelOperation()
+ {
+ return inChannelOperation;
+ }
+
+ /**
+ * Sets our indicator of whether an I/O operation is being
+ * initiated by a channel.
+ */
+ public final void setInChannelOperation(boolean b)
+ {
+ inChannelOperation = b;
+ }
+
+ /**
+ * Default do nothing constructor
+ */
+ public PlainSocketImpl()
+ {
+ }
+
+ protected void finalize() throws Throwable
+ {
+ synchronized (this)
+ {
+ if (native_fd != -1)
+ try
+ {
+ close();
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ super.finalize();
+ }
+
+ public int getNativeFD()
+ {
+ return native_fd;
+ }
+
+ /**
+ * Sets the specified option on a socket to the passed in object. For
+ * options that take an integer argument, the passed in object is an
+ * Integer. The option_id parameter is one of the defined constants in
+ * this interface.
+ *
+ * @param option_id The identifier of the option
+ * @param val The value to set the option to
+ *
+ * @exception SocketException If an error occurs
+ */
+ public native void setOption(int optID, Object value) throws SocketException;
+
+ /**
+ * Returns the current setting of the specified option. The Object returned
+ * will be an Integer for options that have integer values. The option_id
+ * is one of the defined constants in this interface.
+ *
+ * @param option_id The option identifier
+ *
+ * @return The current value of the option
+ *
+ * @exception SocketException If an error occurs
+ */
+ public native Object getOption(int optID) throws SocketException;
+
+ /**
+ * Flushes the input stream and closes it. If you read from the input stream
+ * after calling this method a IOException
will be thrown.
+ *
+ * @throws IOException if an error occurs
+ */
+ public native void shutdownInput() throws IOException;
+
+ /**
+ * Flushes the output stream and closes it. If you write to the output stream
+ * after calling this method a IOException
will be thrown.
+ *
+ * @throws IOException if an error occurs
+ */
+ public native void shutdownOutput() throws IOException;
+
+ /**
+ * Creates a new socket that is not bound to any local address/port and
+ * is not connected to any remote address/port. This will be created as
+ * a stream socket if the stream parameter is true, or a datagram socket
+ * if the stream parameter is false.
+ *
+ * @param stream true for a stream socket, false for a datagram socket
+ */
+ protected synchronized native void create(boolean stream) throws IOException;
+
+ /**
+ * Connects to the remote hostname and port specified as arguments.
+ *
+ * @param hostname The remote hostname to connect to
+ * @param port The remote port to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized void connect(String host, int port) throws IOException
+ {
+ connect(InetAddress.getByName(host), port);
+ }
+
+ /**
+ * Connects to the remote address and port specified as arguments.
+ *
+ * @param addr The remote address to connect to
+ * @param port The remote port to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native void connect(InetAddress addr, int port) throws IOException;
+
+ /**
+ * Connects to the remote socket address with a specified timeout.
+ *
+ * @param timeout The timeout to use for this connect, 0 means infinite.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized void connect(SocketAddress address, int timeout) throws IOException
+ {
+ InetSocketAddress sockAddr = (InetSocketAddress) address;
+ InetAddress addr = sockAddr.getAddress();
+
+ if (addr == null)
+ throw new IllegalArgumentException("address is unresolved: " + sockAddr);
+
+ int port = sockAddr.getPort();
+
+ if (timeout < 0)
+ throw new IllegalArgumentException("negative timeout");
+
+ Object oldTimeoutObj = null;
+
+ try
+ {
+ oldTimeoutObj = this.getOption (SocketOptions.SO_TIMEOUT);
+ this.setOption (SocketOptions.SO_TIMEOUT, new Integer (timeout));
+ connect (addr, port);
+ }
+ finally
+ {
+ if (oldTimeoutObj != null)
+ this.setOption (SocketOptions.SO_TIMEOUT, oldTimeoutObj);
+ }
+ }
+
+ /**
+ * Binds to the specified port on the specified addr. Note that this addr
+ * must represent a local IP address. **** How bind to INADDR_ANY? ****
+ *
+ * @param addr The address to bind to
+ * @param port The port number to bind to
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized native void bind(InetAddress addr, int port)
+ throws IOException;
+
+ /**
+ * Starts listening for connections on a socket. The queuelen parameter
+ * is how many pending connections will queue up waiting to be serviced
+ * before being accept'ed. If the queue of pending requests exceeds this
+ * number, additional connections will be refused.
+ *
+ * @param queuelen The length of the pending connection queue
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized native void listen(int queuelen)
+ throws IOException;
+
+ /**
+ * Accepts a new connection on this socket and returns in in the
+ * passed in SocketImpl.
+ *
+ * @param impl The SocketImpl object to accept this connection.
+ */
+ protected synchronized native void accept(SocketImpl impl)
+ throws IOException;
+
+ /**
+ * Returns the number of bytes that the caller can read from this socket
+ * without blocking.
+ *
+ * @return The number of readable bytes before blocking
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native int available() throws IOException;
+
+ /**
+ * Closes the socket. This will cause any InputStream or OutputStream
+ * objects for this Socket to be closed as well.
+ * InputStream
for
+ * sockets. It in an internal only class used by PlainSocketImpl
.
+ *
+ * @author Nic Ferrier (nferrier@tapsellferrier.co.uk)
+ */
+ final class SocketInputStream
+ extends InputStream
+ {
+ /**
+ * Returns the number of bytes available to be read before blocking
+ */
+ public int available() throws IOException
+ {
+ return PlainSocketImpl.this.available();
+ }
+
+ /**
+ * This method not only closes the stream, it closes the underlying socket
+ * (and thus any connection) and invalidates any other Input/Output streams
+ * for the underlying impl object
+ */
+ public void close() throws IOException
+ {
+ PlainSocketImpl.this.close();
+ }
+
+ /**
+ * Reads the next byte of data and returns it as an int.
+ *
+ * @return The byte read (as an int) or -1 if end of stream);
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read() throws IOException
+ {
+ byte buf[] = new byte [1];
+ int bytes_read = read(buf, 0, 1);
+
+ if (bytes_read == -1)
+ return -1;
+
+ return buf[0] & 0xFF;
+ }
+
+ /**
+ * Reads up to len bytes of data into the caller supplied buffer starting
+ * at offset bytes from the start of the buffer
+ *
+ * @param buf The buffer
+ * @param offset Offset into the buffer to start reading from
+ * @param len The number of bytes to read
+ *
+ * @return The number of bytes actually read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read (byte[] buf, int offset, int len) throws IOException
+ {
+ int bytes_read = PlainSocketImpl.this.read (buf, offset, len);
+
+ if (bytes_read == 0)
+ return -1;
+
+ return bytes_read;
+ }
+ }
+
+ /**
+ * This class is used internally by PlainSocketImpl
to be the
+ * OutputStream
subclass returned by its
+ * getOutputStream method
. It expects only to be used in that
+ * context.
+ *
+ * @author Nic Ferrier (nferrier@tapsellferrier.co.uk)
+ */
+ final class SocketOutputStream
+ extends OutputStream
+ {
+ /**
+ * This method closes the stream and the underlying socket connection. This
+ * action also effectively closes any other InputStream or OutputStream
+ * object associated with the connection.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ PlainSocketImpl.this.close();
+ }
+
+ /**
+ * Writes a byte (passed in as an int) to the given output stream
+ *
+ * @param b The byte to write
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write(int b) throws IOException
+ {
+ byte buf[] = { (byte) b };
+ write(buf, 0, 1);
+ }
+
+ /**
+ * Writes len number of bytes from the array buf to the stream starting
+ * at offset bytes into the buffer.
+ *
+ * @param buf The buffer
+ * @param offset Offset into the buffer to start writing from
+ * @param len The number of bytes to write
+ *
+ * @exception IOException If an error occurs.
+ */
+ public void write (byte[] buf, int offset, int len) throws IOException
+ {
+ PlainSocketImpl.this.write (buf, offset, len);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/net/URLParseError.java b/libjava/classpath/gnu/java/net/URLParseError.java
new file mode 100644
index 0000000..9090748
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/URLParseError.java
@@ -0,0 +1,57 @@
+/* URLParseError.java -- Helps bypassing the exception limitation for
+ URLStreamHandler.parseURL().
+ Copyright (C) 2003 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 gnu.java.net;
+
+/**
+ * This class helps the people writing protocols to report URL parse
+ * errors in parseUrl as this method cannot report other exceptions
+ * than Errors.
+ *
+ * The main drawback is that it uses the Error mechanism which should not
+ * be used for that type of error reporting.
+ *
+ * @author Guilhem Lavaux (guilhem@kaffe.org)
+ */
+public class URLParseError extends Error
+{
+ public URLParseError(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libjava/classpath/gnu/java/net/package.html b/libjava/classpath/gnu/java/net/package.html
new file mode 100644
index 0000000..5641fbd
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+directoryListing
field with a byte array
+ * containing a representation of the directory listing.
+ */
+ byte[] getDirectoryListing()
+ throws IOException
+ {
+ if (directoryListing == null)
+ {
+ ByteArrayOutputStream sink = new ByteArrayOutputStream();
+ // NB uses default character encoding for this system
+ Writer writer = new OutputStreamWriter(sink);
+
+ String[] files = file.list();
+
+ for (int i = 0; i < files.length; i++)
+ {
+ writer.write(files[i]);
+ writer.write(StaticData.lineSeparator);
+ }
+
+ directoryListing = sink.toByteArray();
+ }
+ return directoryListing;
+ }
+
+ /**
+ * Opens the file for reading and returns a stream for it.
+ *
+ * @return An InputStream for this connection.
+ *
+ * @exception IOException If an error occurs
+ */
+ public InputStream getInputStream()
+ throws IOException
+ {
+ if (!doInput)
+ throw new ProtocolException("Can't open InputStream if doInput is false");
+
+ if (!connected)
+ connect();
+
+ return inputStream;
+ }
+
+ /**
+ * Opens the file for writing and returns a stream for it.
+ *
+ * @return An OutputStream for this connection.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public OutputStream getOutputStream()
+ throws IOException
+ {
+ if (!doOutput)
+ throw new
+ ProtocolException("Can't open OutputStream if doOutput is false");
+
+ if (!connected)
+ connect();
+
+ return outputStream;
+ }
+
+ /**
+ * Get the last modified time of the resource.
+ *
+ * @return the time since epoch that the resource was modified.
+ */
+ public long getLastModified()
+ {
+ try
+ {
+ if (!connected)
+ connect();
+
+ return file.lastModified();
+ }
+ catch (IOException e)
+ {
+ return -1;
+ }
+ }
+
+ /**
+ * Get an http-style header field. Just handle a few common ones.
+ */
+ public String getHeaderField(String field)
+ {
+ try
+ {
+ if (!connected)
+ connect();
+
+ if (field.equals("content-type"))
+ return guessContentTypeFromName(file.getName());
+ else if (field.equals("content-length"))
+ {
+ if (file.isDirectory())
+ {
+ return Integer.toString(getContentLength());
+ }
+ return Long.toString(file.length());
+ }
+ else if (field.equals("last-modified"))
+ {
+ synchronized (StaticData.dateFormat)
+ {
+ return StaticData.dateFormat.format(
+ new Date(file.lastModified()));
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ // Fall through.
+ }
+ return null;
+ }
+
+ /**
+ * Get the length of content.
+ *
+ * @return the length of the content.
+ */
+ public int getContentLength()
+ {
+ try
+ {
+ if (!connected)
+ connect();
+
+ if (file.isDirectory())
+ {
+ return getDirectoryListing().length;
+ }
+ return (int) file.length();
+ }
+ catch (IOException e)
+ {
+ return -1;
+ }
+ }
+
+ /**
+ * This method returns a Permission
object representing the
+ * permissions required to access this URL. This method returns a
+ * java.io.FilePermission
for the file's path with a read
+ * permission.
+ *
+ * @return A Permission object
+ */
+ public Permission getPermission() throws IOException
+ {
+ return permission;
+ }
+}
diff --git a/libjava/classpath/gnu/java/net/protocol/file/Handler.java b/libjava/classpath/gnu/java/net/protocol/file/Handler.java
new file mode 100644
index 0000000..fc56049
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/file/Handler.java
@@ -0,0 +1,91 @@
+/* Handler.java -- "file" protocol handler for java.net
+ Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004 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 gnu.java.net.protocol.file;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+/**
+ * This is the protocol handler for the "file" protocol.
+ * It implements the abstract openConnection() method from
+ * URLStreamHandler by returning a new FileURLConnection object (from
+ * this package). All other methods are inherited
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public class Handler extends URLStreamHandler
+{
+ /**
+ * A do nothing constructor
+ */
+ public Handler()
+ {
+ }
+
+ /**
+ * This method returs a new FileURLConnection for the specified URL
+ *
+ * @param url The URL to return a connection for
+ *
+ * @return The URLConnection
+ *
+ * @exception IOException If an error occurs
+ */
+ protected URLConnection openConnection(URL url) throws IOException
+ {
+ // If a hostname is set, then we need to switch protocols to ftp
+ // in order to transfer this from the remote host.
+ String host = url.getHost();
+ if ((host != null) && (! host.equals("")))
+ {
+ // Reset the protocol (and implicitly the handler) for this URL.
+ // Then have the URL attempt the connection again, as it will
+ // get the changed handler the next time around.
+ // If the ftp protocol handler is not installed, an
+ // exception will be thrown from the new openConnection() call.
+ setURL (url, "ftp", url.getHost(), url.getPort(), url.getFile(),
+ url.getRef());
+ return url.openConnection();
+ }
+
+ return new Connection(url);
+ }
+} // class Handler
diff --git a/libjava/classpath/gnu/java/net/protocol/file/package.html b/libjava/classpath/gnu/java/net/protocol/file/package.html
new file mode 100644
index 0000000..cbce741
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/file/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+ *
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class FTPConnection
+{
+
+ /**
+ * The default FTP transmission control port.
+ */
+ public static final int FTP_PORT = 21;
+
+ /**
+ * The FTP data port.
+ */
+ public static final int FTP_DATA_PORT = 20;
+
+ // -- FTP vocabulary --
+ protected static final String USER = "USER";
+ protected static final String PASS = "PASS";
+ protected static final String ACCT = "ACCT";
+ protected static final String CWD = "CWD";
+ protected static final String CDUP = "CDUP";
+ protected static final String SMNT = "SMNT";
+ protected static final String REIN = "REIN";
+ protected static final String QUIT = "QUIT";
+
+ protected static final String PORT = "PORT";
+ protected static final String PASV = "PASV";
+ protected static final String TYPE = "TYPE";
+ protected static final String STRU = "STRU";
+ protected static final String MODE = "MODE";
+
+ protected static final String RETR = "RETR";
+ protected static final String STOR = "STOR";
+ protected static final String STOU = "STOU";
+ protected static final String APPE = "APPE";
+ protected static final String ALLO = "ALLO";
+ protected static final String REST = "REST";
+ protected static final String RNFR = "RNFR";
+ protected static final String RNTO = "RNTO";
+ protected static final String ABOR = "ABOR";
+ protected static final String DELE = "DELE";
+ protected static final String RMD = "RMD";
+ protected static final String MKD = "MKD";
+ protected static final String PWD = "PWD";
+ protected static final String LIST = "LIST";
+ protected static final String NLST = "NLST";
+ protected static final String SITE = "SITE";
+ protected static final String SYST = "SYST";
+ protected static final String STAT = "STAT";
+ protected static final String HELP = "HELP";
+ protected static final String NOOP = "NOOP";
+
+ protected static final String AUTH = "AUTH";
+ protected static final String PBSZ = "PBSZ";
+ protected static final String PROT = "PROT";
+ protected static final String CCC = "CCC";
+ protected static final String TLS = "TLS";
+
+ public static final int TYPE_ASCII = 1;
+ public static final int TYPE_EBCDIC = 2;
+ public static final int TYPE_BINARY = 3;
+
+ public static final int STRUCTURE_FILE = 1;
+ public static final int STRUCTURE_RECORD = 2;
+ public static final int STRUCTURE_PAGE = 3;
+
+ public static final int MODE_STREAM = 1;
+ public static final int MODE_BLOCK = 2;
+ public static final int MODE_COMPRESSED = 3;
+
+ // -- Telnet constants --
+ private static final String US_ASCII = "US-ASCII";
+
+ /**
+ * The socket used to communicate with the server.
+ */
+ protected Socket socket;
+
+ /**
+ * The socket input stream.
+ */
+ protected LineInputStream in;
+
+ /**
+ * The socket output stream.
+ */
+ protected CRLFOutputStream out;
+
+ /**
+ * The timeout when attempting to connect a socket.
+ */
+ protected int connectionTimeout;
+
+ /**
+ * The read timeout on sockets.
+ */
+ protected int timeout;
+
+ /**
+ * If true, print debugging information.
+ */
+ protected boolean debug;
+
+ /**
+ * The current data transfer process in use by this connection.
+ */
+ protected DTP dtp;
+
+ /**
+ * The current representation type.
+ */
+ protected int representationType = TYPE_ASCII;
+
+ /**
+ * The current file structure type.
+ */
+ protected int fileStructure = STRUCTURE_FILE;
+
+ /**
+ * The current transfer mode.
+ */
+ protected int transferMode = MODE_STREAM;
+
+ /**
+ * If true, use passive mode.
+ */
+ protected boolean passive = false;
+
+ /**
+ * Creates a new connection to the server using the default port.
+ * @param hostname the hostname of the server to connect to
+ */
+ public FTPConnection(String hostname)
+ throws UnknownHostException, IOException
+ {
+ this(hostname, -1, 0, 0, false);
+ }
+
+ /**
+ * Creates a new connection to the server.
+ * @param hostname the hostname of the server to connect to
+ * @param port the port to connect to(if <=0, use default port)
+ */
+ public FTPConnection(String hostname, int port)
+ throws UnknownHostException, IOException
+ {
+ this(hostname, port, 0, 0, false);
+ }
+
+ /**
+ * Creates a new connection to the server.
+ * @param hostname the hostname of the server to connect to
+ * @param port the port to connect to(if <=0, use default port)
+ * @param connectionTimeout the connection timeout, in milliseconds
+ * @param timeout the I/O timeout, in milliseconds
+ * @param debug print debugging information
+ */
+ public FTPConnection(String hostname, int port,
+ int connectionTimeout, int timeout, boolean debug)
+ throws UnknownHostException, IOException
+ {
+ this.connectionTimeout = connectionTimeout;
+ this.timeout = timeout;
+ this.debug = debug;
+ if (port <= 0)
+ {
+ port = FTP_PORT;
+ }
+
+ // Set up socket
+ socket = new Socket();
+ InetSocketAddress address = new InetSocketAddress(hostname, port);
+ if (connectionTimeout > 0)
+ {
+ socket.connect(address, connectionTimeout);
+ }
+ else
+ {
+ socket.connect(address);
+ }
+ if (timeout > 0)
+ {
+ socket.setSoTimeout(timeout);
+ }
+
+ InputStream in = socket.getInputStream();
+ in = new BufferedInputStream(in);
+ in = new CRLFInputStream(in);
+ this.in = new LineInputStream(in);
+ OutputStream out = socket.getOutputStream();
+ out = new BufferedOutputStream(out);
+ this.out = new CRLFOutputStream(out);
+
+ // Read greeting
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 220: // hello
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Authenticate using the specified username and password.
+ * If the username suffices for the server, the password will not be used
+ * and may be null.
+ * @param username the username
+ * @param password the optional password
+ * @return true on success, false otherwise
+ */
+ public boolean authenticate(String username, String password)
+ throws IOException
+ {
+ String cmd = USER + ' ' + username;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 230: // User logged in
+ return true;
+ case 331: // User name okay, need password
+ break;
+ case 332: // Need account for login
+ case 530: // No such user
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ cmd = PASS + ' ' + password;
+ send(cmd);
+ response = getResponse();
+ switch (response.getCode())
+ {
+ case 230: // User logged in
+ case 202: // Superfluous
+ return true;
+ case 332: // Need account for login
+ case 530: // Bad password
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Negotiates TLS over the current connection.
+ * See IETF draft-murray-auth-ftp-ssl-15.txt for details.
+ * @param confidential whether to provide confidentiality for the
+ * connection
+ */
+ public boolean starttls(boolean confidential)
+ throws IOException
+ {
+ return starttls(confidential, new EmptyX509TrustManager());
+ }
+
+ /**
+ * Negotiates TLS over the current connection.
+ * See IETF draft-murray-auth-ftp-ssl-15.txt for details.
+ * @param confidential whether to provide confidentiality for the
+ * connection
+ * @param tm the trust manager used to validate the server certificate.
+ */
+ public boolean starttls(boolean confidential, TrustManager tm)
+ throws IOException
+ {
+ try
+ {
+ // Use SSLSocketFactory to negotiate a TLS session and wrap the
+ // current socket.
+ SSLContext context = SSLContext.getInstance("TLS");
+ // We don't require strong validation of the server certificate
+ TrustManager[] trust = new TrustManager[] { tm };
+ context.init(null, trust, null);
+ SSLSocketFactory factory = context.getSocketFactory();
+
+ send(AUTH + ' ' + TLS);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 500:
+ case 502:
+ case 504:
+ case 534:
+ case 431:
+ return false;
+ case 234:
+ break;
+ default:
+ throw new FTPException(response);
+ }
+
+ String hostname = socket.getInetAddress().getHostName();
+ int port = socket.getPort();
+ SSLSocket ss =
+ (SSLSocket) factory.createSocket(socket, hostname, port, true);
+ String[] protocols = { "TLSv1", "SSLv3" };
+ ss.setEnabledProtocols(protocols);
+ ss.setUseClientMode(true);
+ ss.startHandshake();
+
+ // PBSZ:PROT sequence
+ send(PBSZ + ' ' + Integer.MAX_VALUE);
+ response = getResponse();
+ switch (response.getCode())
+ {
+ case 501: // syntax error
+ case 503: // not authenticated
+ return false;
+ case 200:
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ send(PROT + ' ' +(confidential ? 'P' : 'C'));
+ response = getResponse();
+ switch (response.getCode())
+ {
+ case 503: // not authenticated
+ case 504: // invalid level
+ case 536: // level not supported
+ return false;
+ case 200:
+ break;
+ default:
+ throw new FTPException(response);
+ }
+
+ if (confidential)
+ {
+ // Set up streams
+ InputStream in = ss.getInputStream();
+ in = new BufferedInputStream(in);
+ in = new CRLFInputStream(in);
+ this.in = new LineInputStream(in);
+ OutputStream out = ss.getOutputStream();
+ out = new BufferedOutputStream(out);
+ this.out = new CRLFOutputStream(out);
+ }
+ return true;
+ }
+ catch (GeneralSecurityException e)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Changes directory to the specified path.
+ * @param path an absolute or relative pathname
+ * @return true on success, false if the specified path does not exist
+ */
+ public boolean changeWorkingDirectory(String path)
+ throws IOException
+ {
+ String cmd = CWD + ' ' + path;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 250:
+ return true;
+ case 550:
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Changes directory to the parent of the current working directory.
+ * @return true on success, false otherwise
+ */
+ public boolean changeToParentDirectory()
+ throws IOException
+ {
+ send(CDUP);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 250:
+ return true;
+ case 550:
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Terminates an authenticated login.
+ * If file transfer is in progress, it remains active for result response
+ * only.
+ */
+ public void reinitialize()
+ throws IOException
+ {
+ send(REIN);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 220:
+ if (dtp != null)
+ {
+ dtp.complete();
+ dtp = null;
+ }
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Terminates the control connection.
+ * The file transfer connection remains open for result response only.
+ * This connection is invalid and no further commands may be issued.
+ */
+ public void logout()
+ throws IOException
+ {
+ send(QUIT);
+ try
+ {
+ getResponse(); // not required
+ }
+ catch (IOException e)
+ {
+ }
+ if (dtp != null)
+ {
+ dtp.complete();
+ dtp = null;
+ }
+ try
+ {
+ socket.close();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+
+ /**
+ * Initialise the data transfer process.
+ */
+ protected void initialiseDTP()
+ throws IOException
+ {
+ if (dtp != null)
+ {
+ dtp.complete();
+ dtp = null;
+ }
+
+ InetAddress localhost = socket.getLocalAddress();
+ if (passive)
+ {
+ send(PASV);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 227:
+ String message = response.getMessage();
+ try
+ {
+ int start = message.indexOf(',');
+ char c = message.charAt(start - 1);
+ while (c >= 0x30 && c <= 0x39)
+ {
+ c = message.charAt((--start) - 1);
+ }
+ int mid1 = start;
+ for (int i = 0; i < 4; i++)
+ {
+ mid1 = message.indexOf(',', mid1 + 1);
+ }
+ int mid2 = message.indexOf(',', mid1 + 1);
+ if (mid1 == -1 || mid2 < mid1)
+ {
+ throw new ProtocolException("Malformed 227: " +
+ message);
+ }
+ int end = mid2;
+ c = message.charAt(end + 1);
+ while (c >= 0x30 && c <= 0x39)
+ {
+ c = message.charAt((++end) + 1);
+ }
+
+ String address =
+ message.substring(start, mid1).replace(',', '.');
+ int port_hi =
+ Integer.parseInt(message.substring(mid1 + 1, mid2));
+ int port_lo =
+ Integer.parseInt(message.substring(mid2 + 1, end + 1));
+ int port = (port_hi << 8) | port_lo;
+
+ /*System.out.println("Entering passive mode: " + address +
+ ":" + port);*/
+ dtp = new PassiveModeDTP(address, port, localhost,
+ connectionTimeout, timeout);
+ break;
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new ProtocolException(e.getMessage() + ": " +
+ message);
+ }
+ catch (NumberFormatException e)
+ {
+ throw new ProtocolException(e.getMessage() + ": " +
+ message);
+ }
+ default:
+ throw new FTPException(response);
+ }
+ }
+ else
+ {
+ // Get the local port
+ int port = socket.getLocalPort() + 1;
+ int tries = 0;
+ // Bind the active mode DTP
+ while (dtp == null)
+ {
+ try
+ {
+ dtp = new ActiveModeDTP(localhost, port,
+ connectionTimeout, timeout);
+ /*System.out.println("Listening on: " + port);*/
+ }
+ catch (BindException e)
+ {
+ port++;
+ tries++;
+ if (tries > 9)
+ {
+ throw e;
+ }
+ }
+ }
+
+ // Send PORT command
+ StringBuffer buf = new StringBuffer(PORT);
+ buf.append(' ');
+ // Construct the address/port string form
+ byte[] address = localhost.getAddress();
+ for (int i = 0; i < address.length; i++)
+ {
+ int a =(int) address[i];
+ if (a < 0)
+ {
+ a += 0x100;
+ }
+ buf.append(a);
+ buf.append(',');
+ }
+ int port_hi =(port & 0xff00) >> 8;
+ int port_lo =(port & 0x00ff);
+ buf.append(port_hi);
+ buf.append(',');
+ buf.append(port_lo);
+ send(buf.toString());
+ // Get response
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200: // OK
+ break;
+ default:
+ dtp.abort();
+ dtp = null;
+ throw new FTPException(response);
+ }
+ }
+ dtp.setTransferMode(transferMode);
+ }
+
+ /**
+ * Set passive mode.
+ * @param flag true if we should use passive mode, false otherwise
+ */
+ public void setPassive(boolean flag)
+ throws IOException
+ {
+ if (passive != flag)
+ {
+ passive = flag;
+ initialiseDTP();
+ }
+ }
+
+ /**
+ * Returns the current representation type of the transfer data.
+ * @return TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY
+ */
+ public int getRepresentationType()
+ {
+ return representationType;
+ }
+
+ /**
+ * Sets the desired representation type of the transfer data.
+ * @param type TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY
+ */
+ public void setRepresentationType(int type)
+ throws IOException
+ {
+ StringBuffer buf = new StringBuffer(TYPE);
+ buf.append(' ');
+ switch (type)
+ {
+ case TYPE_ASCII:
+ buf.append('A');
+ break;
+ case TYPE_EBCDIC:
+ buf.append('E');
+ break;
+ case TYPE_BINARY:
+ buf.append('I');
+ break;
+ default:
+ throw new IllegalArgumentException(Integer.toString(type));
+ }
+ //buf.append(' ');
+ //buf.append('N');
+ send(buf.toString());
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200:
+ representationType = type;
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns the current file structure type.
+ * @return STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE
+ */
+ public int getFileStructure()
+ {
+ return fileStructure;
+ }
+
+ /**
+ * Sets the desired file structure type.
+ * @param structure STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE
+ */
+ public void setFileStructure(int structure)
+ throws IOException
+ {
+ StringBuffer buf = new StringBuffer(STRU);
+ buf.append(' ');
+ switch (structure)
+ {
+ case STRUCTURE_FILE:
+ buf.append('F');
+ break;
+ case STRUCTURE_RECORD:
+ buf.append('R');
+ break;
+ case STRUCTURE_PAGE:
+ buf.append('P');
+ break;
+ default:
+ throw new IllegalArgumentException(Integer.toString(structure));
+ }
+ send(buf.toString());
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200:
+ fileStructure = structure;
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns the current transfer mode.
+ * @return MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED
+ */
+ public int getTransferMode()
+ {
+ return transferMode;
+ }
+
+ /**
+ * Sets the desired transfer mode.
+ * @param mode MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED
+ */
+ public void setTransferMode(int mode)
+ throws IOException
+ {
+ StringBuffer buf = new StringBuffer(MODE);
+ buf.append(' ');
+ switch (mode)
+ {
+ case MODE_STREAM:
+ buf.append('S');
+ break;
+ case MODE_BLOCK:
+ buf.append('B');
+ break;
+ case MODE_COMPRESSED:
+ buf.append('C');
+ break;
+ default:
+ throw new IllegalArgumentException(Integer.toString(mode));
+ }
+ send(buf.toString());
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200:
+ transferMode = mode;
+ if (dtp != null)
+ {
+ dtp.setTransferMode(mode);
+ }
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Retrieves the specified file.
+ * @param filename the filename of the file to retrieve
+ * @return an InputStream containing the file content
+ */
+ public InputStream retrieve(String filename)
+ throws IOException
+ {
+ if (dtp == null || transferMode == MODE_STREAM)
+ {
+ initialiseDTP();
+ }
+ /*
+ int size = -1;
+ String cmd = SIZE + ' ' + filename;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 213:
+ size = Integer.parseInt(response.getMessage());
+ break;
+ case 550: // File not found
+ default:
+ throw new FTPException(response);
+ }
+ */
+ String cmd = RETR + ' ' + filename;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 125: // Data connection already open; transfer starting
+ case 150: // File status okay; about to open data connection
+ return dtp.getInputStream();
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns a stream for uploading a file.
+ * If a file with the same filename already exists on the server, it will
+ * be overwritten.
+ * @param filename the name of the file to save the content as
+ * @return an OutputStream to write the file data to
+ */
+ public OutputStream store(String filename)
+ throws IOException
+ {
+ if (dtp == null || transferMode == MODE_STREAM)
+ {
+ initialiseDTP();
+ }
+ String cmd = STOR + ' ' + filename;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 125: // Data connection already open; transfer starting
+ case 150: // File status okay; about to open data connection
+ return dtp.getOutputStream();
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns a stream for uploading a file.
+ * If a file with the same filename already exists on the server, the
+ * content specified will be appended to the existing file.
+ * @param filename the name of the file to save the content as
+ * @return an OutputStream to write the file data to
+ */
+ public OutputStream append(String filename)
+ throws IOException
+ {
+ if (dtp == null || transferMode == MODE_STREAM)
+ {
+ initialiseDTP();
+ }
+ String cmd = APPE + ' ' + filename;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 125: // Data connection already open; transfer starting
+ case 150: // File status okay; about to open data connection
+ return dtp.getOutputStream();
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * This command may be required by some servers to reserve sufficient
+ * storage to accommodate the new file to be transferred.
+ * It should be immediately followed by a store
or
+ * append
.
+ * @param size the number of bytes of storage to allocate
+ */
+ public void allocate(long size)
+ throws IOException
+ {
+ String cmd = ALLO + ' ' + size;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200: // OK
+ case 202: // Superfluous
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Renames a file.
+ * @param oldName the current name of the file
+ * @param newName the new name
+ * @return true if successful, false otherwise
+ */
+ public boolean rename(String oldName, String newName)
+ throws IOException
+ {
+ String cmd = RNFR + ' ' + oldName;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 450: // File unavailable
+ case 550: // File not found
+ return false;
+ case 350: // Pending
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ cmd = RNTO + ' ' + newName;
+ send(cmd);
+ response = getResponse();
+ switch (response.getCode())
+ {
+ case 250: // OK
+ return true;
+ case 450:
+ case 550:
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Aborts the transfer in progress.
+ * @return true if a transfer was in progress, false otherwise
+ */
+ public boolean abort()
+ throws IOException
+ {
+ send(ABOR);
+ FTPResponse response = getResponse();
+ // Abort client DTP
+ if (dtp != null)
+ {
+ dtp.abort();
+ }
+ switch (response.getCode())
+ {
+ case 226: // successful abort
+ return false;
+ case 426: // interrupted
+ response = getResponse();
+ if (response.getCode() == 226)
+ {
+ return true;
+ }
+ // Otherwise fall through to throw exception
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Causes the file specified to be deleted at the server site.
+ * @param filename the file to delete
+ */
+ public boolean delete(String filename)
+ throws IOException
+ {
+ String cmd = DELE + ' ' + filename;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 250: // OK
+ return true;
+ case 450: // File unavailable
+ case 550: // File not found
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Causes the directory specified to be deleted.
+ * This may be an absolute or relative pathname.
+ * @param pathname the directory to delete
+ */
+ public boolean removeDirectory(String pathname)
+ throws IOException
+ {
+ String cmd = RMD + ' ' + pathname;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 250: // OK
+ return true;
+ case 550: // File not found
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Causes the directory specified to be created at the server site.
+ * This may be an absolute or relative pathname.
+ * @param pathname the directory to create
+ */
+ public boolean makeDirectory(String pathname)
+ throws IOException
+ {
+ String cmd = MKD + ' ' + pathname;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 257: // Directory created
+ return true;
+ case 550: // File not found
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns the current working directory.
+ */
+ public String getWorkingDirectory()
+ throws IOException
+ {
+ send(PWD);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 257:
+ String message = response.getMessage();
+ if (message.charAt(0) == '"')
+ {
+ int end = message.indexOf('"', 1);
+ if (end == -1)
+ {
+ throw new ProtocolException(message);
+ }
+ return message.substring(1, end);
+ }
+ else
+ {
+ int end = message.indexOf(' ');
+ if (end == -1)
+ {
+ return message;
+ }
+ else
+ {
+ return message.substring(0, end);
+ }
+ }
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns a listing of information about the specified pathname.
+ * If the pathname specifies a directory or other group of files, the
+ * server should transfer a list of files in the specified directory.
+ * If the pathname specifies a file then the server should send current
+ * information on the file. A null argument implies the user's
+ * current working or default directory.
+ * @param pathname the context pathname, or null
+ */
+ public InputStream list(String pathname)
+ throws IOException
+ {
+ if (dtp == null || transferMode == MODE_STREAM)
+ {
+ initialiseDTP();
+ }
+ if (pathname == null)
+ {
+ send(LIST);
+ }
+ else
+ {
+ String cmd = LIST + ' ' + pathname;
+ send(cmd);
+ }
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 125: // Data connection already open; transfer starting
+ case 150: // File status okay; about to open data connection
+ return dtp.getInputStream();
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns a directory listing. The pathname should specify a
+ * directory or other system-specific file group descriptor; a null
+ * argument implies the user's current working or default directory.
+ * @param pathname the directory pathname, or null
+ * @return a list of filenames(strings)
+ */
+ public List nameList(String pathname)
+ throws IOException
+ {
+ if (dtp == null || transferMode == MODE_STREAM)
+ {
+ initialiseDTP();
+ }
+ if (pathname == null)
+ {
+ send(NLST);
+ }
+ else
+ {
+ String cmd = NLST + ' ' + pathname;
+ send(cmd);
+ }
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 125: // Data connection already open; transfer starting
+ case 150: // File status okay; about to open data connection
+ InputStream in = dtp.getInputStream();
+ in = new BufferedInputStream(in);
+ in = new CRLFInputStream(in); // TODO ensure that TYPE is correct
+ LineInputStream li = new LineInputStream(in);
+ List ret = new ArrayList();
+ for (String line = li.readLine();
+ line != null;
+ line = li.readLine())
+ {
+ ret.add(line);
+ }
+ li.close();
+ return ret;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns the type of operating system at the server.
+ */
+ public String system()
+ throws IOException
+ {
+ send(SYST);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 215:
+ String message = response.getMessage();
+ int end = message.indexOf(' ');
+ if (end == -1)
+ {
+ return message;
+ }
+ else
+ {
+ return message.substring(0, end);
+ }
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Does nothing.
+ * This method can be used to ensure that the connection does not time
+ * out.
+ */
+ public void noop()
+ throws IOException
+ {
+ send(NOOP);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200:
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ // -- I/O --
+
+ /**
+ * Sends the specified command line to the server.
+ * The CRLF sequence is automatically appended.
+ * @param cmd the command line to send
+ */
+ protected void send(String cmd)
+ throws IOException
+ {
+ byte[] data = cmd.getBytes(US_ASCII);
+ out.write(data);
+ out.writeln();
+ out.flush();
+ }
+
+ /**
+ * Reads the next response from the server.
+ * If the server sends the "transfer complete" code, this is handled here,
+ * and the next response is passed to the caller.
+ */
+ protected FTPResponse getResponse()
+ throws IOException
+ {
+ FTPResponse response = readResponse();
+ if (response.getCode() == 226)
+ {
+ if (dtp != null)
+ {
+ dtp.transferComplete();
+ }
+ response = readResponse();
+ }
+ return response;
+ }
+
+ /**
+ * Reads and parses the next response from the server.
+ */
+ protected FTPResponse readResponse()
+ throws IOException
+ {
+ String line = in.readLine();
+ if (line == null)
+ {
+ throw new ProtocolException( "EOF");
+ }
+ if (line.length() < 4)
+ {
+ throw new ProtocolException(line);
+ }
+ int code = parseCode(line);
+ if (code == -1)
+ {
+ throw new ProtocolException(line);
+ }
+ char c = line.charAt(3);
+ if (c == ' ')
+ {
+ return new FTPResponse(code, line.substring(4));
+ }
+ else if (c == '-')
+ {
+ StringBuffer buf = new StringBuffer(line.substring(4));
+ buf.append('\n');
+ while(true)
+ {
+ line = in.readLine();
+ if (line == null)
+ {
+ throw new ProtocolException("EOF");
+ }
+ if (line.length() >= 4 &&
+ line.charAt(3) == ' ' &&
+ parseCode(line) == code)
+ {
+ return new FTPResponse(code, line.substring(4),
+ buf.toString());
+ }
+ else
+ {
+ buf.append(line);
+ buf.append('\n');
+ }
+ }
+ }
+ else
+ {
+ throw new ProtocolException(line);
+ }
+ }
+
+ /*
+ * Parses the 3-digit numeric code at the beginning of the given line.
+ * Returns -1 on failure.
+ */
+ static final int parseCode(String line)
+ {
+ char[] c = { line.charAt(0), line.charAt(1), line.charAt(2) };
+ int ret = 0;
+ for (int i = 0; i < 3; i++)
+ {
+ int digit =((int) c[i]) - 0x30;
+ if (digit < 0 || digit > 9)
+ {
+ return -1;
+ }
+ // Computing integer powers is way too expensive in Java!
+ switch (i)
+ {
+ case 0:
+ ret +=(100 * digit);
+ break;
+ case 1:
+ ret +=(10 * digit);
+ break;
+ case 2:
+ ret += digit;
+ break;
+ }
+ }
+ return ret;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java
new file mode 100644
index 0000000..14ad381
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java
@@ -0,0 +1,76 @@
+/* FTPException.java --
+ Copyright (C) 2003. 2004 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 gnu.java.net.protocol.ftp;
+
+import java.io.IOException;
+
+/**
+ * An FTP control exception.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class FTPException
+ extends IOException
+{
+
+ /**
+ * The response that provoked this exception.
+ */
+ protected final FTPResponse response;
+
+ /**
+ * Constructs a new FTP exception.
+ * @param response the response that provoked this exception
+ */
+ public FTPException(FTPResponse response)
+ {
+ super(response.getMessage());
+ this.response = response;
+ }
+
+ /**
+ * Returns the response that provoked this exception.
+ */
+ public FTPResponse getResponse()
+ {
+ return response;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java
new file mode 100644
index 0000000..ec72c73
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java
@@ -0,0 +1,112 @@
+/* FTPResponse.java --
+ Copyright (C) 2003, 2004 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 gnu.java.net.protocol.ftp;
+
+/**
+ * An FTP control response.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public final class FTPResponse
+{
+
+ /**
+ * The 3-digit status code.
+ */
+ protected final int code;
+
+ /**
+ * The human-readable message.
+ */
+ protected final String message;
+
+ /**
+ * Multiline data, if present.
+ */
+ protected final String data;
+
+ /**
+ * Constructs a new FTP response.
+ * @param code the status code
+ * @param message the message
+ */
+ public FTPResponse(int code, String message)
+ {
+ this(code, message, null);
+ }
+
+ /**
+ * Constructs a new multiline FTP response.
+ * @param code the status code
+ * @param message the message
+ * @param data multiline data
+ */
+ public FTPResponse(int code, String message, String data)
+ {
+ this.code = code;
+ this.message = message;
+ this.data = data;
+ }
+
+ /**
+ * Returns the 3-digit status code.
+ */
+ public int getCode()
+ {
+ return code;
+ }
+
+ /**
+ * Returns the human-readable message.
+ */
+ public String getMessage()
+ {
+ return message;
+ }
+
+ /**
+ * Returns the multiline data, or null if there was no such data.
+ */
+ public String getData()
+ {
+ return data;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java
new file mode 100644
index 0000000..62c40f1
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java
@@ -0,0 +1,398 @@
+/* FTPURLConnection.java --
+ Copyright (C) 2003, 2004 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 gnu.java.net.protocol.ftp;
+
+import gnu.java.net.GetLocalHostAction;
+import gnu.java.security.action.GetPropertyAction;
+
+import java.io.FileNotFoundException;
+import java.io.FilterInputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An FTP URL connection.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class FTPURLConnection
+ extends URLConnection
+{
+
+ /**
+ * The connection managing the protocol exchange.
+ */
+ protected FTPConnection connection;
+
+ protected boolean passive;
+ protected int representationType;
+ protected int fileStructure;
+ protected int transferMode;
+
+ /**
+ * Constructs an FTP connection to the specified URL.
+ * @param url the URL
+ */
+ public FTPURLConnection(URL url)
+ {
+ super(url);
+ passive = true;
+ representationType = FTPConnection.TYPE_BINARY;
+ fileStructure = -1;
+ transferMode = -1;
+ }
+
+ /**
+ * Establishes the connection.
+ */
+ public void connect()
+ throws IOException
+ {
+ if (connected)
+ {
+ return;
+ }
+ String host = url.getHost();
+ int port = url.getPort();
+ String username = url.getUserInfo();
+ String password = null;
+ if (username != null)
+ {
+ int ci = username.indexOf(':');
+ if (ci != -1)
+ {
+ password = username.substring(ci + 1);
+ username = username.substring(0, ci);
+ }
+ }
+ else
+ {
+ username = "anonymous";
+ PrivilegedAction a = new GetPropertyAction("user.name");
+ String systemUsername =(String) AccessController.doPrivileged(a);
+ a = new GetLocalHostAction();
+ InetAddress localhost =(InetAddress) AccessController.doPrivileged(a);
+ password = systemUsername + "@" +
+ ((localhost == null) ? "localhost" : localhost.getHostName());
+ }
+ connection = new FTPConnection(host, port);
+ if (!connection.authenticate(username, password))
+ {
+ throw new SecurityException("Authentication failed");
+ }
+ connection.setPassive(passive);
+ if (representationType != -1)
+ {
+ connection.setRepresentationType(representationType);
+ }
+ if (fileStructure != -1)
+ {
+ connection.setFileStructure(fileStructure);
+ }
+ if (transferMode != -1)
+ {
+ connection.setTransferMode(transferMode);
+ }
+ }
+
+ /**
+ * This connection supports doInput.
+ */
+ public void setDoInput(boolean doinput)
+ {
+ doInput = doinput;
+ }
+
+ /**
+ * This connection supports doOutput.
+ */
+ public void setDoOutput(boolean dooutput)
+ {
+ doOutput = dooutput;
+ }
+
+ /**
+ * Returns an input stream that reads from this open connection.
+ */
+ public InputStream getInputStream()
+ throws IOException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+ String path = url.getPath();
+ String filename = null;
+ int lsi = path.lastIndexOf('/');
+ if (lsi != -1)
+ {
+ filename = path.substring(lsi + 1);
+ path = path.substring(0, lsi);
+ if (!connection.changeWorkingDirectory(path))
+ {
+ throw new FileNotFoundException(path);
+ }
+ }
+ if (filename != null && filename.length() > 0)
+ {
+ return this.new ClosingInputStream(connection.retrieve(filename));
+ }
+ else
+ {
+ return this.new ClosingInputStream(connection.list(null));
+ }
+ }
+
+ /**
+ * Returns an output stream that writes to this connection.
+ */
+ public OutputStream getOutputStream()
+ throws IOException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+ String dir = url.getPath();
+ String filename = url.getFile();
+ if (!connection.changeWorkingDirectory(dir))
+ {
+ throw new FileNotFoundException(dir);
+ }
+ if (filename != null)
+ {
+ return this.new ClosingOutputStream(connection.store(filename));
+ }
+ else
+ {
+ throw new FileNotFoundException(filename);
+ }
+ }
+
+ public String getRequestProperty(String key)
+ {
+ if ("passive".equals(key))
+ {
+ return Boolean.toString(passive);
+ }
+ else if ("representationType".equals(key))
+ {
+ switch (representationType)
+ {
+ case FTPConnection.TYPE_ASCII:
+ return "ASCII";
+ case FTPConnection.TYPE_EBCDIC:
+ return "EBCDIC";
+ case FTPConnection.TYPE_BINARY:
+ return "BINARY";
+ }
+ }
+ else if ("fileStructure".equals(key))
+ {
+ switch (fileStructure)
+ {
+ case FTPConnection.STRUCTURE_FILE:
+ return "FILE";
+ case FTPConnection.STRUCTURE_RECORD:
+ return "RECORD";
+ case FTPConnection.STRUCTURE_PAGE:
+ return "PAGE";
+ }
+ }
+ else if ("transferMode".equals(key))
+ {
+ switch (transferMode)
+ {
+ case FTPConnection.MODE_STREAM:
+ return "STREAM";
+ case FTPConnection.MODE_BLOCK:
+ return "BLOCK";
+ case FTPConnection.MODE_COMPRESSED:
+ return "COMPRESSED";
+ }
+ }
+ return null;
+ }
+
+ public Map getRequestProperties()
+ {
+ Map map = new HashMap();
+ addRequestPropertyValue(map, "passive");
+ addRequestPropertyValue(map, "representationType");
+ addRequestPropertyValue(map, "fileStructure");
+ addRequestPropertyValue(map, "transferMode");
+ return map;
+ }
+
+ private void addRequestPropertyValue(Map map, String key)
+ {
+ String value = getRequestProperty(key);
+ map.put(key, value);
+ }
+
+ public void setRequestProperty(String key, String value)
+ {
+ if (connected)
+ {
+ throw new IllegalStateException();
+ }
+ if ("passive".equals(key))
+ {
+ passive = Boolean.valueOf(value).booleanValue();
+ }
+ else if ("representationType".equals(key))
+ {
+ if ("A".equalsIgnoreCase(value) ||
+ "ASCII".equalsIgnoreCase(value))
+ {
+ representationType = FTPConnection.TYPE_ASCII;
+ }
+ else if ("E".equalsIgnoreCase(value) ||
+ "EBCDIC".equalsIgnoreCase(value))
+ {
+ representationType = FTPConnection.TYPE_EBCDIC;
+ }
+ else if ("I".equalsIgnoreCase(value) ||
+ "BINARY".equalsIgnoreCase(value))
+ {
+ representationType = FTPConnection.TYPE_BINARY;
+ }
+ else
+ {
+ throw new IllegalArgumentException(value);
+ }
+ }
+ else if ("fileStructure".equals(key))
+ {
+ if ("F".equalsIgnoreCase(value) ||
+ "FILE".equalsIgnoreCase(value))
+ {
+ fileStructure = FTPConnection.STRUCTURE_FILE;
+ }
+ else if ("R".equalsIgnoreCase(value) ||
+ "RECORD".equalsIgnoreCase(value))
+ {
+ fileStructure = FTPConnection.STRUCTURE_RECORD;
+ }
+ else if ("P".equalsIgnoreCase(value) ||
+ "PAGE".equalsIgnoreCase(value))
+ {
+ fileStructure = FTPConnection.STRUCTURE_PAGE;
+ }
+ else
+ {
+ throw new IllegalArgumentException(value);
+ }
+ }
+ else if ("transferMode".equals(key))
+ {
+ if ("S".equalsIgnoreCase(value) ||
+ "STREAM".equalsIgnoreCase(value))
+ {
+ transferMode = FTPConnection.MODE_STREAM;
+ }
+ else if ("B".equalsIgnoreCase(value) ||
+ "BLOCK".equalsIgnoreCase(value))
+ {
+ transferMode = FTPConnection.MODE_BLOCK;
+ }
+ else if ("C".equalsIgnoreCase(value) ||
+ "COMPRESSED".equalsIgnoreCase(value))
+ {
+ transferMode = FTPConnection.MODE_COMPRESSED;
+ }
+ else
+ {
+ throw new IllegalArgumentException(value);
+ }
+ }
+ }
+
+ public void addRequestProperty(String key, String value)
+ {
+ setRequestProperty(key, value);
+ }
+
+ class ClosingInputStream
+ extends FilterInputStream
+ {
+
+ ClosingInputStream(InputStream in)
+ {
+ super(in);
+ }
+
+ public void close()
+ throws IOException
+ {
+ super.close();
+ connection.logout();
+ }
+
+ }
+
+ class ClosingOutputStream
+ extends FilterOutputStream
+ {
+
+ ClosingOutputStream(OutputStream out)
+ {
+ super(out);
+ }
+
+ public void close()
+ throws IOException
+ {
+ super.close();
+ connection.logout();
+ }
+
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java b/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java
new file mode 100644
index 0000000..88491b3
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java
@@ -0,0 +1,70 @@
+/* Handler.java --
+ Copyright (C) 2003, 2004 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 gnu.java.net.protocol.ftp;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+/**
+ * An FTP URL stream handler.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Handler
+ extends URLStreamHandler
+{
+
+ protected int getDefaultPort()
+ {
+ return FTPConnection.FTP_PORT;
+ }
+
+ /**
+ * Returns an FTPURLConnection for the given URL.
+ */
+ public URLConnection openConnection(URL url)
+ throws IOException
+ {
+ return new FTPURLConnection(url);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java b/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java
new file mode 100644
index 0000000..6f4fd63
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java
@@ -0,0 +1,201 @@
+/* PassiveModeDTP.java --
+ Copyright (C) 2003, 2004 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 gnu.java.net.protocol.ftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+/**
+ * A passive mode FTP data transfer process.
+ * This connects to the host specified and proxies the resulting socket's
+ * input and output streams.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+final class PassiveModeDTP
+ implements DTP
+{
+
+ final String address;
+ final int port;
+ Socket socket;
+ DTPInputStream in;
+ DTPOutputStream out;
+ boolean completed;
+ boolean inProgress;
+ int transferMode;
+
+ PassiveModeDTP(String address, int port, InetAddress localhost,
+ int connectionTimeout, int timeout)
+ throws IOException
+ {
+ this.address = address;
+ this.port = port;
+ completed = false;
+ inProgress = false;
+ socket = new Socket();
+ InetSocketAddress remote = new InetSocketAddress(address, port);
+ InetSocketAddress local = new InetSocketAddress(localhost, port + 1);
+ socket.bind(local);
+ if (connectionTimeout > 0)
+ {
+ socket.connect(remote, connectionTimeout);
+ }
+ else
+ {
+ socket.connect(remote);
+ }
+ if (timeout > 0)
+ {
+ socket.setSoTimeout(timeout);
+ }
+ }
+
+ /**
+ * Returns an input stream from which a remote file can be read.
+ */
+ public InputStream getInputStream()
+ throws IOException
+ {
+ if (inProgress)
+ {
+ throw new IOException("Transfer in progress");
+ }
+ switch (transferMode)
+ {
+ case FTPConnection.MODE_STREAM:
+ in = new StreamInputStream(this, socket.getInputStream());
+ break;
+ case FTPConnection.MODE_BLOCK:
+ in = new BlockInputStream(this, socket.getInputStream());
+ break;
+ case FTPConnection.MODE_COMPRESSED:
+ in = new CompressedInputStream(this, socket.getInputStream());
+ break;
+ default:
+ throw new IllegalStateException("Invalid transfer mode");
+ }
+ in.setTransferComplete(false);
+ return in;
+ }
+
+ /**
+ * Returns an output stream to which a local file can be written for
+ * upload.
+ */
+ public OutputStream getOutputStream()
+ throws IOException
+ {
+ if (inProgress)
+ {
+ throw new IOException("Transfer in progress");
+ }
+ switch (transferMode)
+ {
+ case FTPConnection.MODE_STREAM:
+ out = new StreamOutputStream(this, socket.getOutputStream());
+ break;
+ case FTPConnection.MODE_BLOCK:
+ out = new BlockOutputStream(this, socket.getOutputStream());
+ break;
+ case FTPConnection.MODE_COMPRESSED:
+ out = new CompressedOutputStream(this, socket.getOutputStream());
+ break;
+ default:
+ throw new IllegalStateException("Invalid transfer mode");
+ }
+ out.setTransferComplete(false);
+ return out;
+ }
+
+ public void setTransferMode(int mode)
+ {
+ transferMode = mode;
+ }
+
+ public void complete()
+ {
+ completed = true;
+ if (!inProgress)
+ {
+ transferComplete();
+ }
+ }
+
+ public boolean abort()
+ {
+ completed = true;
+ transferComplete();
+ return inProgress;
+ }
+
+ /*
+ * Called by DTPInputStream or DTPOutputStream when end of
+ * stream is reached.
+ */
+ public void transferComplete()
+ {
+ if (in != null)
+ {
+ in.setTransferComplete(true);
+ }
+ if (out != null)
+ {
+ out.setTransferComplete(true);
+ }
+ inProgress = false;
+ completed = completed ||(transferMode == FTPConnection.MODE_STREAM);
+ if (completed && socket != null)
+ {
+ try
+ {
+ socket.close();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java
new file mode 100644
index 0000000..93eee4e
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java
@@ -0,0 +1,95 @@
+/* StreamInputStream.java --
+ Copyright (C) 2003, 2004 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 gnu.java.net.protocol.ftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A DTP input stream that implements the FTP stream data transfer mode.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+class StreamInputStream
+ extends DTPInputStream
+{
+
+ StreamInputStream(DTP dtp, InputStream in)
+ {
+ super(dtp, in);
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return -1;
+ }
+ int c = in.read();
+ if (c == -1)
+ {
+ close();
+ }
+ return c;
+ }
+
+ public int read(byte[] buf)
+ throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ public int read(byte[] buf, int off, int len)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return -1;
+ }
+ int l = in.read(buf, off, len);
+ if (l == -1)
+ {
+ close();
+ }
+ return l;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java
new file mode 100644
index 0000000..a6e28ec
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java
@@ -0,0 +1,85 @@
+/* StreamOutputStream.java --
+ Copyright (C) 2003, 2004 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 gnu.java.net.protocol.ftp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A DTP output stream that implements the FTP stream transfer mode.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+class StreamOutputStream
+ extends DTPOutputStream
+{
+
+ StreamOutputStream(DTP dtp, OutputStream out)
+ {
+ super(dtp, out);
+ }
+
+ public void write(int c)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return;
+ }
+ out.write(c);
+ }
+
+ public void write(byte[] b)
+ throws IOException
+ {
+ write(b, 0, b.length);
+ }
+
+ public void write(byte[] b, int off, int len)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return;
+ }
+ out.write(b, off, len);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/package.html b/libjava/classpath/gnu/java/net/protocol/ftp/package.html
new file mode 100644
index 0000000..fa3e34d
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/package.html
@@ -0,0 +1,60 @@
+
+
+
+
+abs_path
with
+ * optional query part
+ */
+ public Request newRequest(String method, String path)
+ {
+ if (method == null || method.length() == 0)
+ {
+ throw new IllegalArgumentException("method must have non-zero length");
+ }
+ if (path == null || path.length() == 0)
+ {
+ path = "/";
+ }
+ Request ret = new Request(this, method, path);
+ if ((secure && port != HTTPS_PORT) ||
+ (!secure && port != HTTP_PORT))
+ {
+ ret.setHeader("Host", hostname + ":" + port);
+ }
+ else
+ {
+ ret.setHeader("Host", hostname);
+ }
+ ret.setHeader("User-Agent", userAgent);
+ ret.setHeader("Connection", "keep-alive");
+ ret.setHeader("Accept-Encoding",
+ "chunked;q=1.0, gzip;q=0.9, deflate;q=0.8, " +
+ "identity;q=0.6, *;q=0");
+ if (cookieManager != null)
+ {
+ Cookie[] cookies = cookieManager.getCookies(hostname, secure, path);
+ if (cookies != null && cookies.length > 0)
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append("$Version=1");
+ for (int i = 0; i < cookies.length; i++)
+ {
+ buf.append(',');
+ buf.append(' ');
+ buf.append(cookies[i].toString());
+ }
+ ret.setHeader("Cookie", buf.toString());
+ }
+ }
+ fireRequestEvent(RequestEvent.REQUEST_CREATED, ret);
+ return ret;
+ }
+
+ /**
+ * Closes this connection.
+ */
+ public void close()
+ throws IOException
+ {
+ try
+ {
+ closeConnection();
+ }
+ finally
+ {
+ fireConnectionEvent(ConnectionEvent.CONNECTION_CLOSED);
+ }
+ }
+
+ /**
+ * Retrieves the socket associated with this connection.
+ * This creates the socket if necessary.
+ */
+ protected synchronized Socket getSocket()
+ throws IOException
+ {
+ if (socket == null)
+ {
+ String connectHostname = hostname;
+ int connectPort = port;
+ if (isUsingProxy())
+ {
+ connectHostname = proxyHostname;
+ connectPort = proxyPort;
+ }
+ socket = new Socket();
+ InetSocketAddress address =
+ new InetSocketAddress(connectHostname, connectPort);
+ if (connectionTimeout > 0)
+ {
+ socket.connect(address, connectionTimeout);
+ }
+ else
+ {
+ socket.connect(address);
+ }
+ if (timeout > 0)
+ {
+ socket.setSoTimeout(timeout);
+ }
+ if (secure)
+ {
+ try
+ {
+ SSLSocketFactory factory = getSSLSocketFactory();
+ SSLSocket ss =
+ (SSLSocket) factory.createSocket(socket, connectHostname,
+ connectPort, true);
+ String[] protocols = { "TLSv1", "SSLv3" };
+ ss.setEnabledProtocols(protocols);
+ ss.setUseClientMode(true);
+ synchronized (handshakeCompletedListeners)
+ {
+ if (!handshakeCompletedListeners.isEmpty())
+ {
+ for (Iterator i =
+ handshakeCompletedListeners.iterator();
+ i.hasNext(); )
+ {
+ HandshakeCompletedListener l =
+ (HandshakeCompletedListener) i.next();
+ ss.addHandshakeCompletedListener(l);
+ }
+ }
+ }
+ ss.startHandshake();
+ socket = ss;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new IOException(e.getMessage());
+ }
+ }
+ in = socket.getInputStream();
+ in = new BufferedInputStream(in);
+ out = socket.getOutputStream();
+ out = new BufferedOutputStream(out);
+ }
+ return socket;
+ }
+
+ SSLSocketFactory getSSLSocketFactory()
+ throws GeneralSecurityException
+ {
+ if (sslSocketFactory == null)
+ {
+ TrustManager tm = new EmptyX509TrustManager();
+ SSLContext context = SSLContext.getInstance("SSL");
+ TrustManager[] trust = new TrustManager[] { tm };
+ context.init(null, trust, null);
+ sslSocketFactory = context.getSocketFactory();
+ }
+ return sslSocketFactory;
+ }
+
+ void setSSLSocketFactory(SSLSocketFactory factory)
+ {
+ sslSocketFactory = factory;
+ }
+
+ protected synchronized InputStream getInputStream()
+ throws IOException
+ {
+ if (socket == null)
+ {
+ getSocket();
+ }
+ return in;
+ }
+
+ protected synchronized OutputStream getOutputStream()
+ throws IOException
+ {
+ if (socket == null)
+ {
+ getSocket();
+ }
+ return out;
+ }
+
+ /**
+ * Closes the underlying socket, if any.
+ */
+ protected synchronized void closeConnection()
+ throws IOException
+ {
+ if (socket != null)
+ {
+ try
+ {
+ socket.close();
+ }
+ finally
+ {
+ socket = null;
+ }
+ }
+ }
+
+ /**
+ * Returns a URI representing the connection.
+ * This does not include any request path component.
+ */
+ protected String getURI()
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append(secure ? "https://" : "http://");
+ buf.append(hostname);
+ if (secure)
+ {
+ if (port != HTTPConnection.HTTPS_PORT)
+ {
+ buf.append(':');
+ buf.append(port);
+ }
+ }
+ else
+ {
+ if (port != HTTPConnection.HTTP_PORT)
+ {
+ buf.append(':');
+ buf.append(port);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Get the number of times the specified nonce has been seen by this
+ * connection.
+ */
+ int getNonceCount(String nonce)
+ {
+ if (nonceCounts == null)
+ {
+ return 0;
+ }
+ return((Integer) nonceCounts.get(nonce)).intValue();
+ }
+
+ /**
+ * Increment the number of times the specified nonce has been seen.
+ */
+ void incrementNonce(String nonce)
+ {
+ int current = getNonceCount(nonce);
+ if (nonceCounts == null)
+ {
+ nonceCounts = new HashMap();
+ }
+ nonceCounts.put(nonce, new Integer(current + 1));
+ }
+
+ // -- Events --
+
+ public void addConnectionListener(ConnectionListener l)
+ {
+ synchronized (connectionListeners)
+ {
+ connectionListeners.add(l);
+ }
+ }
+
+ public void removeConnectionListener(ConnectionListener l)
+ {
+ synchronized (connectionListeners)
+ {
+ connectionListeners.remove(l);
+ }
+ }
+
+ protected void fireConnectionEvent(int type)
+ {
+ ConnectionEvent event = new ConnectionEvent(this, type);
+ ConnectionListener[] l = null;
+ synchronized (connectionListeners)
+ {
+ l = new ConnectionListener[connectionListeners.size()];
+ connectionListeners.toArray(l);
+ }
+ for (int i = 0; i < l.length; i++)
+ {
+ switch (type)
+ {
+ case ConnectionEvent.CONNECTION_CLOSED:
+ l[i].connectionClosed(event);
+ break;
+ }
+ }
+ }
+
+ public void addRequestListener(RequestListener l)
+ {
+ synchronized (requestListeners)
+ {
+ requestListeners.add(l);
+ }
+ }
+
+ public void removeRequestListener(RequestListener l)
+ {
+ synchronized (requestListeners)
+ {
+ requestListeners.remove(l);
+ }
+ }
+
+ protected void fireRequestEvent(int type, Request request)
+ {
+ RequestEvent event = new RequestEvent(this, type, request);
+ RequestListener[] l = null;
+ synchronized (requestListeners)
+ {
+ l = new RequestListener[requestListeners.size()];
+ requestListeners.toArray(l);
+ }
+ for (int i = 0; i < l.length; i++)
+ {
+ switch (type)
+ {
+ case RequestEvent.REQUEST_CREATED:
+ l[i].requestCreated(event);
+ break;
+ case RequestEvent.REQUEST_SENDING:
+ l[i].requestSent(event);
+ break;
+ case RequestEvent.REQUEST_SENT:
+ l[i].requestSent(event);
+ break;
+ }
+ }
+ }
+
+ void addHandshakeCompletedListener(HandshakeCompletedListener l)
+ {
+ synchronized (handshakeCompletedListeners)
+ {
+ handshakeCompletedListeners.add(l);
+ }
+ }
+ void removeHandshakeCompletedListener(HandshakeCompletedListener l)
+ {
+ synchronized (handshakeCompletedListeners)
+ {
+ handshakeCompletedListeners.remove(l);
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java
new file mode 100644
index 0000000..2f59e43
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java
@@ -0,0 +1,441 @@
+/* HTTPDateFormat.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http;
+
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.FieldPosition;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+/**
+ * HTTP date formatter and parser.
+ * Formats dates according to RFC 822 (updated by RFC 1123).
+ * Parses dates according to the above, or RFC 1036, or the
+ * ANSI C asctime()
format.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class HTTPDateFormat
+ extends DateFormat
+{
+
+ static final String[] DAYS_OF_WEEK = {
+ null, "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+
+ static final String[] MONTHS = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ public HTTPDateFormat()
+ {
+ calendar = new GregorianCalendar(TimeZone.getTimeZone ("GMT"));
+ numberFormat = new DecimalFormat();
+ }
+
+ /**
+ * Appends the textual value for the specified field to the given string
+ * buffer. This method should be avoided, use format(Date)
+ * instead.
+ * @param date the Date object
+ * @param buf the buffer to append to
+ * @param field the current field position
+ * @return the modified buffer
+ */
+ public StringBuffer format(Date date, StringBuffer buf,
+ FieldPosition field)
+ {
+ calendar.clear();
+ calendar.setTime(date);
+ buf.setLength(0);
+
+ // Day of week
+ buf.append(DAYS_OF_WEEK[calendar.get(Calendar.DAY_OF_WEEK)]);
+ buf.append(',');
+ buf.append(' ');
+
+ // Day of month
+ int day = calendar.get(Calendar.DAY_OF_MONTH);
+ buf.append(Character.forDigit(day / 10, 10));
+ buf.append(Character.forDigit(day % 10, 10));
+ buf.append(' ');
+
+ // Month
+ buf.append(MONTHS[calendar.get(Calendar.MONTH)]);
+ buf.append(' ');
+
+ // Year
+ int year = calendar.get(Calendar.YEAR);
+ if (year < 1000)
+ {
+ buf.append('0');
+ if (year < 100)
+ {
+ buf.append('0');
+ if (year < 10)
+ {
+ buf.append('0');
+ }
+ }
+ }
+ buf.append(Integer.toString(year));
+ buf.append(' ');
+
+ // Hour
+ int hour = calendar.get(Calendar.HOUR_OF_DAY);
+ buf.append(Character.forDigit(hour / 10, 10));
+ buf.append(Character.forDigit(hour % 10, 10));
+ buf.append(':');
+
+ // Minute
+ int minute = calendar.get(Calendar.MINUTE);
+ buf.append(Character.forDigit(minute / 10, 10));
+ buf.append(Character.forDigit(minute % 10, 10));
+ buf.append(':');
+
+ // Second
+ int second = calendar.get(Calendar.SECOND);
+ buf.append(Character.forDigit(second / 10, 10));
+ buf.append(Character.forDigit(second % 10, 10));
+ buf.append(' ');
+
+ // Timezone
+ // Get time offset in minutes
+ int zoneOffset =(calendar.get(Calendar.ZONE_OFFSET) +
+ calendar.get(Calendar.DST_OFFSET)) / 60000;
+
+ // Apply + or - appropriately
+ if (zoneOffset < 0)
+ {
+ zoneOffset = -zoneOffset;
+ buf.append('-');
+ }
+ else
+ {
+ buf.append('+');
+ }
+
+ // Set the 2 2-char fields as specified above
+ int tzhours = zoneOffset / 60;
+ buf.append(Character.forDigit(tzhours / 10, 10));
+ buf.append(Character.forDigit(tzhours % 10, 10));
+ int tzminutes = zoneOffset % 60;
+ buf.append(Character.forDigit(tzminutes / 10, 10));
+ buf.append(Character.forDigit(tzminutes % 10, 10));
+
+ field.setBeginIndex(0);
+ field.setEndIndex(buf.length());
+ return buf;
+ }
+
+ /**
+ * Parses the given date in the current TimeZone.
+ * @param text the formatted date to be parsed
+ * @param pos the current parse position
+ */
+ public Date parse(String text, ParsePosition pos)
+ {
+ int date, month, year, hour, minute, second;
+ String monthText;
+ int start = 0, end = -1;
+ int len = text.length();
+ calendar.clear();
+ pos.setIndex(start);
+ try
+ {
+ // Advance to date
+ if (Character.isLetter(text.charAt(start)))
+ {
+ start = skipNonWhitespace(text, start);
+ }
+ // Determine mode
+ switch(start)
+ {
+ case 3:
+ // asctime
+ start = skipWhitespace(text, start);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ monthText = text.substring(start, end);
+ month = -1;
+ for (int i = 0; i < 12; i++)
+ {
+ if (MONTHS[i].equals(monthText))
+ {
+ month = i;
+ break;
+ }
+ }
+ if (month == -1)
+ {
+ pos.setErrorIndex(end);
+ return null;
+ }
+ // Advance to date
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ date = Integer.parseInt(text.substring(start, end));
+ // Advance to hour
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ hour = Integer.parseInt(text.substring(start, end));
+ // Advance to minute
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ minute = Integer.parseInt(text.substring(start, end));
+ // Advance to second
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ second = Integer.parseInt(text.substring(start, end));
+ // Advance to year
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ year = Integer.parseInt(text.substring(start, end));
+ break;
+ case 0:
+ case 4:
+ // rfc822
+ start = skipWhitespace(text, start);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ date = Integer.parseInt(text.substring(start, end));
+ // Advance to month
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ monthText = text.substring(start, end);
+ month = -1;
+ for (int i = 0; i < 12; i++)
+ {
+ if (MONTHS[i].equals(monthText))
+ {
+ month = i;
+ break;
+ }
+ }
+ if (month == -1)
+ {
+ pos.setErrorIndex(end);
+ return null;
+ }
+ // Advance to year
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ year = Integer.parseInt(text.substring(start, end));
+ // Advance to hour
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ hour = Integer.parseInt(text.substring(start, end));
+ // Advance to minute
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ minute = Integer.parseInt(text.substring(start, end));
+ // Advance to second
+ start = end + 1;
+ pos.setIndex(start);
+ end = start + 1;
+ while (end < len && !Character.isWhitespace(text.charAt(end)))
+ {
+ end++;
+ }
+ second = Integer.parseInt(text.substring(start, end));
+ break;
+ default:
+ // rfc850(obsolete)
+ start = skipWhitespace(text, start);
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, '-');
+ date = Integer.parseInt(text.substring(start, end));
+ // Advance to month
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, '-');
+ monthText = text.substring(start, end);
+ month = -1;
+ for (int i = 0; i < 12; i++)
+ {
+ if (MONTHS[i].equals(monthText))
+ {
+ month = i;
+ break;
+ }
+ }
+ if (month == -1)
+ {
+ pos.setErrorIndex(end);
+ return null;
+ }
+ // Advance to year
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ year = 1900 + Integer.parseInt(text.substring(start, end));
+ // Advance to hour
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ hour = Integer.parseInt(text.substring(start, end));
+ // Advance to minute
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ minute = Integer.parseInt(text.substring(start, end));
+ // Advance to second
+ start = end + 1;
+ pos.setIndex(start);
+ end = start + 1;
+ while (end < len && !Character.isWhitespace(text.charAt(end)))
+ {
+ end++;
+ }
+ second = Integer.parseInt(text.substring(start, end));
+ }
+
+ calendar.set(Calendar.YEAR, year);
+ calendar.set(Calendar.MONTH, month);
+ calendar.set(Calendar.DAY_OF_MONTH, date);
+ calendar.set(Calendar.HOUR, hour);
+ calendar.set(Calendar.MINUTE, minute);
+ calendar.set(Calendar.SECOND, second);
+
+ if (end != len)
+ {
+ // Timezone
+ start = skipWhitespace(text, end + 1);
+ end = start + 1;
+ while (end < len && !Character.isWhitespace(text.charAt(end)))
+ {
+ end++;
+ }
+ char pm = text.charAt(start);
+ if (Character.isLetter(pm))
+ {
+ TimeZone tz =
+ TimeZone.getTimeZone(text.substring(start, end));
+ calendar.set(Calendar.ZONE_OFFSET, tz.getRawOffset());
+ }
+ else
+ {
+ int zoneOffset = 0;
+ zoneOffset += 600 * Character.digit(text.charAt(++start), 10);
+ zoneOffset += 60 * Character.digit(text.charAt(++start), 10);
+ zoneOffset += 10 * Character.digit(text.charAt(++start), 10);
+ zoneOffset += Character.digit(text.charAt(++start), 10);
+ zoneOffset *= 60000; // minutes -> ms
+ if ('-' == pm)
+ {
+ zoneOffset = -zoneOffset;
+ }
+ calendar.set(Calendar.ZONE_OFFSET, zoneOffset);
+ }
+ }
+ pos.setIndex(end);
+
+ return calendar.getTime();
+ }
+ catch (NumberFormatException e)
+ {
+ pos.setErrorIndex(Math.max(start, end));
+ }
+ catch (StringIndexOutOfBoundsException e)
+ {
+ pos.setErrorIndex(Math.max(start, end));
+ }
+ return null;
+ }
+
+ private int skipWhitespace(String text, int pos)
+ {
+ while(Character.isWhitespace(text.charAt(pos)))
+ {
+ pos++;
+ }
+ return pos;
+ }
+
+ private int skipNonWhitespace(String text, int pos)
+ {
+ while(!Character.isWhitespace(text.charAt(pos)))
+ {
+ pos++;
+ }
+ return pos;
+ }
+
+ private int skipTo(String text, int pos, char c)
+ {
+ while(text.charAt(pos) != c)
+ {
+ pos++;
+ }
+ return pos;
+ }
+
+ /**
+ * Don't allow setting the calendar.
+ */
+ public void setCalendar(Calendar newCalendar)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Don't allow setting the NumberFormat.
+ */
+ public void setNumberFormat(NumberFormat newNumberFormat)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java
new file mode 100644
index 0000000..9f2055f
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java
@@ -0,0 +1,688 @@
+/* HTTPURLConnection.java --
+ Copyright (C) 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 gnu.java.net.protocol.http;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ProtocolException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.cert.Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.net.ssl.HandshakeCompletedEvent;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * A URLConnection that uses the HTTPConnection class.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class HTTPURLConnection
+ extends HttpsURLConnection
+ implements HandshakeCompletedListener
+{
+
+ /**
+ * Pool of reusable connections, used if keepAlive is true.
+ */
+ private static final Map connectionPool = new LinkedHashMap();
+
+ /*
+ * The underlying connection.
+ */
+ private HTTPConnection connection;
+
+ // These are package private for use in anonymous inner classes.
+ String proxyHostname;
+ int proxyPort;
+ String agent;
+ boolean keepAlive;
+ int maxConnections;
+
+ private Request request;
+ private Headers requestHeaders;
+ private ByteArrayOutputStream requestSink;
+ private boolean requestMethodSetExplicitly;
+
+ private Response response;
+ private ByteArrayInputStream responseSink;
+ private ByteArrayInputStream errorSink;
+
+ private HandshakeCompletedEvent handshakeEvent;
+
+ /**
+ * Constructor.
+ * @param url the URL
+ */
+ public HTTPURLConnection(URL url)
+ throws IOException
+ {
+ super(url);
+ requestHeaders = new Headers();
+ AccessController.doPrivileged(this.new GetHTTPPropertiesAction());
+ }
+
+ class GetHTTPPropertiesAction
+ implements PrivilegedAction
+ {
+
+ public Object run()
+ {
+ proxyHostname = System.getProperty("http.proxyHost");
+ if (proxyHostname != null && proxyHostname.length() > 0)
+ {
+ String port = System.getProperty("http.proxyPort");
+ if (port != null && port.length() > 0)
+ {
+ proxyPort = Integer.parseInt(port);
+ }
+ else
+ {
+ proxyHostname = null;
+ proxyPort = -1;
+ }
+ }
+ agent = System.getProperty("http.agent");
+ String ka = System.getProperty("http.keepAlive");
+ keepAlive = !(ka != null && "false".equals(ka));
+ String mc = System.getProperty("http.maxConnections");
+ maxConnections = (mc != null && mc.length() > 0) ?
+ Math.max(Integer.parseInt(mc), 1) : 5;
+ return null;
+ }
+
+ }
+
+ public void connect()
+ throws IOException
+ {
+ if (connected)
+ {
+ return;
+ }
+ String protocol = url.getProtocol();
+ boolean secure = "https".equals(protocol);
+ String host = url.getHost();
+ int port = url.getPort();
+ if (port < 0)
+ {
+ port = secure ? HTTPConnection.HTTPS_PORT :
+ HTTPConnection.HTTP_PORT;
+ }
+ String file = url.getFile();
+ String username = url.getUserInfo();
+ String password = null;
+ if (username != null)
+ {
+ int ci = username.indexOf(':');
+ if (ci != -1)
+ {
+ password = username.substring(ci + 1);
+ username = username.substring(0, ci);
+ }
+ }
+ final Credentials creds = (username == null) ? null :
+ new Credentials (username, password);
+
+ boolean retry;
+ do
+ {
+ retry = false;
+ if (connection == null)
+ {
+ connection = getConnection(host, port, secure);
+ if (secure)
+ {
+ SSLSocketFactory factory = getSSLSocketFactory();
+ HostnameVerifier verifier = getHostnameVerifier();
+ if (factory != null)
+ {
+ connection.setSSLSocketFactory(factory);
+ }
+ connection.addHandshakeCompletedListener(this);
+ // TODO verifier
+ }
+ }
+ if (proxyHostname != null)
+ {
+ if (proxyPort < 0)
+ {
+ proxyPort = secure ? HTTPConnection.HTTPS_PORT :
+ HTTPConnection.HTTP_PORT;
+ }
+ connection.setProxy(proxyHostname, proxyPort);
+ }
+ request = connection.newRequest(method, file);
+ if (!keepAlive)
+ {
+ request.setHeader("Connection", "close");
+ }
+ if (agent != null)
+ {
+ request.setHeader("User-Agent", agent);
+ }
+ request.getHeaders().putAll(requestHeaders);
+ if (requestSink != null)
+ {
+ byte[] content = requestSink.toByteArray();
+ RequestBodyWriter writer = new ByteArrayRequestBodyWriter(content);
+ request.setRequestBodyWriter(writer);
+ }
+ ByteArrayResponseBodyReader reader = new ByteArrayResponseBodyReader();
+ request.setResponseBodyReader(reader);
+ if (creds != null)
+ {
+ request.setAuthenticator(new Authenticator() {
+ public Credentials getCredentials(String realm, int attempts)
+ {
+ return (attempts < 2) ? creds : null;
+ }
+ });
+ }
+ response = request.dispatch();
+ if (response.getCodeClass() == 3 && getInstanceFollowRedirects())
+ {
+ // Follow redirect
+ String location = response.getHeader("Location");
+ if (location != null)
+ {
+ String connectionUri = connection.getURI();
+ int start = connectionUri.length();
+ if (location.startsWith(connectionUri) &&
+ location.charAt(start) == '/')
+ {
+ file = location.substring(start);
+ retry = true;
+ }
+ else if (location.startsWith("http:"))
+ {
+ connection.close();
+ connection = null;
+ secure = false;
+ start = 7;
+ int end = location.indexOf('/', start);
+ host = location.substring(start, end);
+ int ci = host.lastIndexOf(':');
+ if (ci != -1)
+ {
+ port = Integer.parseInt(host.substring (ci + 1));
+ host = host.substring(0, ci);
+ }
+ else
+ {
+ port = HTTPConnection.HTTP_PORT;
+ }
+ file = location.substring(end);
+ retry = true;
+ }
+ else if (location.startsWith("https:"))
+ {
+ connection.close();
+ connection = null;
+ secure = true;
+ start = 8;
+ int end = location.indexOf('/', start);
+ host = location.substring(start, end);
+ int ci = host.lastIndexOf(':');
+ if (ci != -1)
+ {
+ port = Integer.parseInt(host.substring (ci + 1));
+ host = host.substring(0, ci);
+ }
+ else
+ {
+ port = HTTPConnection.HTTPS_PORT;
+ }
+ file = location.substring(end);
+ retry = true;
+ }
+ else if (location.length() > 0)
+ {
+ // Malformed absolute URI, treat as file part of URI
+ if (location.charAt(0) == '/')
+ {
+ // Absolute path
+ file = location;
+ }
+ else
+ {
+ // Relative path
+ int lsi = file.lastIndexOf('/');
+ file = (lsi == -1) ? "/" : file.substring(0, lsi + 1);
+ file += location;
+ }
+ retry = true;
+ }
+ }
+ }
+ else
+ {
+ responseSink = new ByteArrayInputStream(reader.toByteArray ());
+ if (response.getCode() == 404)
+ {
+ errorSink = responseSink;
+ throw new FileNotFoundException(url.toString());
+ }
+ }
+ }
+ while (retry);
+ connected = true;
+ }
+
+ /**
+ * Returns a connection, from the pool if necessary.
+ */
+ HTTPConnection getConnection(String host, int port, boolean secure)
+ throws IOException
+ {
+ HTTPConnection connection;
+ if (keepAlive)
+ {
+ StringBuffer buf = new StringBuffer(secure ? "https://" : "http://");
+ buf.append(Thread.currentThread().hashCode());
+ buf.append('@');
+ buf.append(host);
+ buf.append(':');
+ buf.append(port);
+ String key = buf.toString();
+ synchronized (connectionPool)
+ {
+ connection = (HTTPConnection) connectionPool.get(key);
+ if (connection == null)
+ {
+ connection = new HTTPConnection(host, port, secure);
+ // Good housekeeping
+ if (connectionPool.size() == maxConnections)
+ {
+ // maxConnections must always be >= 1
+ Object lru = connectionPool.keySet().iterator().next();
+ connectionPool.remove(lru);
+ }
+ connectionPool.put(key, connection);
+ }
+ }
+ }
+ else
+ {
+ connection = new HTTPConnection(host, port, secure);
+ }
+ return connection;
+ }
+
+ public void disconnect()
+ {
+ if (connection != null)
+ {
+ try
+ {
+ connection.close();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ public boolean usingProxy()
+ {
+ return (proxyHostname != null);
+ }
+
+ /**
+ * Overrides the corresponding method in HttpURLConnection to permit
+ * arbitrary methods, as long as they're valid ASCII alphabetic
+ * characters. This is to permit WebDAV and other HTTP extensions to
+ * function.
+ * @param method the method
+ */
+ public void setRequestMethod(String method)
+ throws ProtocolException
+ {
+ if (connected)
+ {
+ throw new ProtocolException("Already connected");
+ }
+ // Validate
+ method = method.toUpperCase();
+ int len = method.length();
+ if (len == 0)
+ {
+ throw new ProtocolException("Empty method name");
+ }
+ for (int i = 0; i < len; i++)
+ {
+ char c = method.charAt(i);
+ if (c < 0x41 || c > 0x5a)
+ {
+ throw new ProtocolException("Illegal character '" + c +
+ "' at index " + i);
+ }
+ }
+ // OK
+ this.method = method;
+ requestMethodSetExplicitly = true;
+ }
+
+ public String getRequestProperty(String key)
+ {
+ return requestHeaders.getValue(key);
+ }
+
+ public Map getRequestProperties()
+ {
+ return requestHeaders;
+ }
+
+ public void setRequestProperty(String key, String value)
+ {
+ requestHeaders.put(key, value);
+ }
+
+ public void addRequestProperty(String key, String value)
+ {
+ String old = requestHeaders.getValue(key);
+ if (old == null)
+ {
+ requestHeaders.put(key, value);
+ }
+ else
+ {
+ requestHeaders.put(key, old + "," + value);
+ }
+ }
+
+ public OutputStream getOutputStream()
+ throws IOException
+ {
+ if (connected)
+ {
+ throw new ProtocolException("Already connected");
+ }
+ if (!doOutput)
+ {
+ throw new ProtocolException("doOutput is false");
+ }
+ else if (!requestMethodSetExplicitly)
+ {
+ /*
+ * Silently change the method to POST if no method was set
+ * explicitly. This is due to broken applications depending on this
+ * behaviour (Apache XMLRPC for one).
+ */
+ method = "POST";
+ }
+ if (requestSink == null)
+ {
+ requestSink = new ByteArrayOutputStream();
+ }
+ return requestSink;
+ }
+
+ // -- Response --
+
+ public InputStream getInputStream()
+ throws IOException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+ if (!doInput)
+ {
+ throw new ProtocolException("doInput is false");
+ }
+ return responseSink;
+ }
+
+ public InputStream getErrorStream()
+ {
+ return errorSink;
+ }
+
+ public Map getHeaderFields()
+ {
+ if (!connected)
+ {
+ try
+ {
+ connect();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ Map headers = response.getHeaders();
+ Map ret = new LinkedHashMap();
+ ret.put("", Collections.singletonList(getStatusLine(response)));
+ for (Iterator i = headers.entrySet().iterator(); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ String key = (String) entry.getKey();
+ String value = (String) entry.getValue();
+ ret.put(key, Collections.singletonList(value));
+ }
+ return ret;
+ }
+
+ String getStatusLine(Response response)
+ {
+ return "HTTP/" + response.getMajorVersion() +
+ "." + response.getMinorVersion() +
+ " " + response.getCode() +
+ " " + response.getMessage();
+ }
+
+ public String getHeaderField(int index)
+ {
+ if (!connected)
+ {
+ try
+ {
+ connect();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ if (index == 0)
+ {
+ return getStatusLine(response);
+ }
+ Iterator i = response.getHeaders().entrySet().iterator();
+ Map.Entry entry;
+ int count = 1;
+ do
+ {
+ if (!i.hasNext())
+ {
+ return null;
+ }
+ entry = (Map.Entry) i.next();
+ count++;
+ }
+ while (count <= index);
+ return (String) entry.getValue();
+ }
+
+ public String getHeaderFieldKey(int index)
+ {
+ if (!connected)
+ {
+ try
+ {
+ connect();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ if (index == 0)
+ {
+ return null;
+ }
+ Iterator i = response.getHeaders().entrySet().iterator();
+ Map.Entry entry;
+ int count = 1;
+ do
+ {
+ if (!i.hasNext())
+ {
+ return null;
+ }
+ entry = (Map.Entry) i.next();
+ count++;
+ }
+ while (count <= index);
+ return (String) entry.getKey();
+ }
+
+ public String getHeaderField(String name)
+ {
+ if (!connected)
+ {
+ try
+ {
+ connect();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ return (String) response.getHeader(name);
+ }
+
+ public long getHeaderFieldDate(String name, long def)
+ {
+ if (!connected)
+ {
+ try
+ {
+ connect();
+ }
+ catch (IOException e)
+ {
+ return def;
+ }
+ }
+ Date date = response.getDateHeader(name);
+ return (date == null) ? def : date.getTime();
+ }
+
+ public String getContentType()
+ {
+ return getHeaderField("Content-Type");
+ }
+
+ public int getResponseCode()
+ throws IOException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+ return response.getCode();
+ }
+
+ public String getResponseMessage()
+ throws IOException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+ return response.getMessage();
+ }
+
+ // -- HTTPS specific --
+
+ public String getCipherSuite()
+ {
+ if (!connected)
+ {
+ throw new IllegalStateException("not connected");
+ }
+ return handshakeEvent.getCipherSuite();
+ }
+
+ public Certificate[] getLocalCertificates()
+ {
+ if (!connected)
+ {
+ throw new IllegalStateException("not connected");
+ }
+ return handshakeEvent.getLocalCertificates();
+ }
+
+ public Certificate[] getServerCertificates()
+ throws SSLPeerUnverifiedException
+ {
+ if (!connected)
+ {
+ throw new IllegalStateException("not connected");
+ }
+ return handshakeEvent.getPeerCertificates();
+ }
+
+ // HandshakeCompletedListener
+
+ public void handshakeCompleted(HandshakeCompletedEvent event)
+ {
+ handshakeEvent = event;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/Handler.java b/libjava/classpath/gnu/java/net/protocol/http/Handler.java
new file mode 100644
index 0000000..6405425
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Handler.java
@@ -0,0 +1,73 @@
+/* Handler.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+/**
+ * An HTTP URL stream handler.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Handler
+ extends URLStreamHandler
+{
+
+ /**
+ * Returns the default HTTP port (80).
+ */
+ protected int getDefaultPort()
+ {
+ return HTTPConnection.HTTP_PORT;
+ }
+
+ /**
+ * Returns an HTTPURLConnection for the given URL.
+ */
+ public URLConnection openConnection(URL url)
+ throws IOException
+ {
+ return new HTTPURLConnection(url);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/Headers.java b/libjava/classpath/gnu/java/net/protocol/http/Headers.java
new file mode 100644
index 0000000..847ebef
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Headers.java
@@ -0,0 +1,369 @@
+/* Headers.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http;
+
+import gnu.java.net.LineInputStream;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A collection of HTTP header names and associated values.
+ * Retrieval of values is case insensitive. An iteration over the keys
+ * returns the header names in the order they were received.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Headers
+ implements Map
+{
+
+ static final DateFormat dateFormat = new HTTPDateFormat();
+
+ static class Header
+ {
+
+ final String name;
+
+ Header(String name)
+ {
+ if (name == null || name.length() == 0)
+ {
+ throw new IllegalArgumentException(name);
+ }
+ this.name = name;
+ }
+
+ public int hashCode()
+ {
+ return name.toLowerCase().hashCode();
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other instanceof Header)
+ {
+ return ((Header) other).name.equalsIgnoreCase(name);
+ }
+ return false;
+ }
+
+ public String toString()
+ {
+ return name;
+ }
+
+ }
+
+ static class HeaderEntry
+ implements Map.Entry
+ {
+
+ final Map.Entry entry;
+
+ HeaderEntry(Map.Entry entry)
+ {
+ this.entry = entry;
+ }
+
+ public Object getKey()
+ {
+ return ((Header) entry.getKey()).name;
+ }
+
+ public Object getValue()
+ {
+ return entry.getValue();
+ }
+
+ public Object setValue(Object value)
+ {
+ return entry.setValue(value);
+ }
+
+ public int hashCode()
+ {
+ return entry.hashCode();
+ }
+
+ public boolean equals(Object other)
+ {
+ return entry.equals(other);
+ }
+
+ public String toString()
+ {
+ return getKey().toString() + "=" + getValue();
+ }
+
+ }
+
+ private LinkedHashMap headers;
+
+ public Headers()
+ {
+ headers = new LinkedHashMap();
+ }
+
+ public int size()
+ {
+ return headers.size();
+ }
+
+ public boolean isEmpty()
+ {
+ return headers.isEmpty();
+ }
+
+ public boolean containsKey(Object key)
+ {
+ return headers.containsKey(new Header((String) key));
+ }
+
+ public boolean containsValue(Object value)
+ {
+ return headers.containsValue(value);
+ }
+
+ public Object get(Object key)
+ {
+ return headers.get(new Header((String) key));
+ }
+
+ /**
+ * Returns the value of the specified header as a string.
+ */
+ public String getValue(String header)
+ {
+ return (String) headers.get(new Header(header));
+ }
+
+ /**
+ * Returns the value of the specified header as an integer,
+ * or -1 if the header is not present or not an integer.
+ */
+ public int getIntValue(String header)
+ {
+ String val = getValue(header);
+ if (val == null)
+ {
+ return -1;
+ }
+ try
+ {
+ return Integer.parseInt(val);
+ }
+ catch (NumberFormatException e)
+ {
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the value of the specified header as a date,
+ * or null
if the header is not present or not a date.
+ */
+ public Date getDateValue(String header)
+ {
+ String val = getValue(header);
+ if (val == null)
+ {
+ return null;
+ }
+ try
+ {
+ return dateFormat.parse(val);
+ }
+ catch (ParseException e)
+ {
+ return null;
+ }
+ }
+
+ public Object put(Object key, Object value)
+ {
+ return headers.put(new Header((String) key), value);
+ }
+
+ public Object remove(Object key)
+ {
+ return headers.remove(new Header((String) key));
+ }
+
+ public void putAll(Map t)
+ {
+ for (Iterator i = t.keySet().iterator(); i.hasNext(); )
+ {
+ String key = (String) i.next();
+ String value = (String) t.get(key);
+ headers.put(new Header(key), value);
+ }
+ }
+
+ public void clear()
+ {
+ headers.clear();
+ }
+
+ public Set keySet()
+ {
+ Set keys = headers.keySet();
+ Set ret = new LinkedHashSet();
+ for (Iterator i = keys.iterator(); i.hasNext(); )
+ {
+ ret.add(((Header) i.next()).name);
+ }
+ return ret;
+ }
+
+ public Collection values()
+ {
+ return headers.values();
+ }
+
+ public Set entrySet()
+ {
+ Set entries = headers.entrySet();
+ Set ret = new LinkedHashSet();
+ for (Iterator i = entries.iterator(); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ ret.add(new HeaderEntry(entry));
+ }
+ return ret;
+ }
+
+ public boolean equals(Object other)
+ {
+ return headers.equals(other);
+ }
+
+ public int hashCode()
+ {
+ return headers.hashCode();
+ }
+
+ /**
+ * Parse the specified input stream, adding headers to this collection.
+ */
+ public void parse(InputStream in)
+ throws IOException
+ {
+ LineInputStream lin = (in instanceof LineInputStream) ?
+ (LineInputStream) in : new LineInputStream(in);
+
+ String name = null;
+ StringBuffer value = new StringBuffer();
+ while (true)
+ {
+ String line = lin.readLine();
+ if (line == null)
+ {
+ if (name != null)
+ {
+ addValue(name, value.toString());
+ }
+ break;
+ }
+ int len = line.length();
+ if (len < 2)
+ {
+ if (name != null)
+ {
+ addValue(name, value.toString());
+ }
+ break;
+ }
+ char c1 = line.charAt(0);
+ if (c1 == ' ' || c1 == '\t')
+ {
+ // Continuation
+ int last = len - 1;
+ if (line.charAt(last) != '\r')
+ ++last;
+ value.append(line.substring(0, last));
+ }
+ else
+ {
+ if (name != null)
+ {
+ addValue(name, value.toString());
+ }
+
+ int di = line.indexOf(':');
+ name = line.substring(0, di);
+ value.setLength(0);
+ do
+ {
+ di++;
+ }
+ while (di < len && line.charAt(di) == ' ');
+ int last = len - 1;
+ if (line.charAt(last) != '\r')
+ ++last;
+ value.append(line.substring(di, last));
+ }
+ }
+ }
+
+ private void addValue(String name, String value)
+ {
+ Header key = new Header(name);
+ String old = (String) headers.get(key);
+ if (old == null)
+ {
+ headers.put(key, value);
+ }
+ else
+ {
+ headers.put(key, old + ", " + value);
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/Request.java b/libjava/classpath/gnu/java/net/protocol/http/Request.java
new file mode 100644
index 0000000..21205e6
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Request.java
@@ -0,0 +1,915 @@
+/* Request.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http;
+
+import gnu.java.net.BASE64;
+import gnu.java.net.LineInputStream;
+import gnu.java.net.protocol.http.event.RequestEvent;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ProtocolException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.InflaterInputStream;
+
+/**
+ * A single HTTP request.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Request
+{
+
+ /**
+ * The connection context in which this request is invoked.
+ */
+ protected final HTTPConnection connection;
+
+ /**
+ * The HTTP method to invoke.
+ */
+ protected final String method;
+
+ /**
+ * The path identifying the resource.
+ * This string must conform to the abs_path definition given in RFC2396,
+ * with an optional "?query" part, and must be URI-escaped by the caller.
+ */
+ protected final String path;
+
+ /**
+ * The headers in this request.
+ */
+ protected final Headers requestHeaders;
+
+ /**
+ * The request body provider.
+ */
+ protected RequestBodyWriter requestBodyWriter;
+
+ /**
+ * Request body negotiation threshold for 100-continue expectations.
+ */
+ protected int requestBodyNegotiationThreshold;
+
+ /**
+ * The response body reader.
+ */
+ protected ResponseBodyReader responseBodyReader;
+
+ /**
+ * Map of response header handlers.
+ */
+ protected Map responseHeaderHandlers;
+
+ /**
+ * The authenticator.
+ */
+ protected Authenticator authenticator;
+
+ /**
+ * Whether this request has been dispatched yet.
+ */
+ private boolean dispatched;
+
+ /**
+ * Constructor for a new request.
+ * @param connection the connection context
+ * @param method the HTTP method
+ * @param path the resource path including query part
+ */
+ protected Request(HTTPConnection connection, String method,
+ String path)
+ {
+ this.connection = connection;
+ this.method = method;
+ this.path = path;
+ requestHeaders = new Headers();
+ responseHeaderHandlers = new HashMap();
+ requestBodyNegotiationThreshold = 4096;
+ }
+
+ /**
+ * Returns the connection associated with this request.
+ * @see #connection
+ */
+ public HTTPConnection getConnection()
+ {
+ return connection;
+ }
+
+ /**
+ * Returns the HTTP method to invoke.
+ * @see #method
+ */
+ public String getMethod()
+ {
+ return method;
+ }
+
+ /**
+ * Returns the resource path.
+ * @see #path
+ */
+ public String getPath()
+ {
+ return path;
+ }
+
+ /**
+ * Returns the full request-URI represented by this request, as specified
+ * by HTTP/1.1.
+ */
+ public String getRequestURI()
+ {
+ return connection.getURI() + path;
+ }
+
+ /**
+ * Returns the headers in this request.
+ */
+ public Headers getHeaders()
+ {
+ return requestHeaders;
+ }
+
+ /**
+ * Returns the value of the specified header in this request.
+ * @param name the header name
+ */
+ public String getHeader(String name)
+ {
+ return requestHeaders.getValue(name);
+ }
+
+ /**
+ * Returns the value of the specified header in this request as an integer.
+ * @param name the header name
+ */
+ public int getIntHeader(String name)
+ {
+ return requestHeaders.getIntValue(name);
+ }
+
+ /**
+ * Returns the value of the specified header in this request as a date.
+ * @param name the header name
+ */
+ public Date getDateHeader(String name)
+ {
+ return requestHeaders.getDateValue(name);
+ }
+
+ /**
+ * Sets the specified header in this request.
+ * @param name the header name
+ * @param value the header value
+ */
+ public void setHeader(String name, String value)
+ {
+ requestHeaders.put(name, value);
+ }
+
+ /**
+ * Convenience method to set the entire request body.
+ * @param requestBody the request body content
+ */
+ public void setRequestBody(byte[] requestBody)
+ {
+ setRequestBodyWriter(new ByteArrayRequestBodyWriter(requestBody));
+ }
+
+ /**
+ * Sets the request body provider.
+ * @param requestBodyWriter the handler used to obtain the request body
+ */
+ public void setRequestBodyWriter(RequestBodyWriter requestBodyWriter)
+ {
+ this.requestBodyWriter = requestBodyWriter;
+ }
+
+ /**
+ * Sets the response body reader.
+ * @param responseBodyReader the handler to receive notifications of
+ * response body content
+ */
+ public void setResponseBodyReader(ResponseBodyReader responseBodyReader)
+ {
+ this.responseBodyReader = responseBodyReader;
+ }
+
+ /**
+ * Sets a callback handler to be invoked for the specified header name.
+ * @param name the header name
+ * @param handler the handler to receive the value for the header
+ */
+ public void setResponseHeaderHandler(String name,
+ ResponseHeaderHandler handler)
+ {
+ responseHeaderHandlers.put(name, handler);
+ }
+
+ /**
+ * Sets an authenticator that can be used to handle authentication
+ * automatically.
+ * @param authenticator the authenticator
+ */
+ public void setAuthenticator(Authenticator authenticator)
+ {
+ this.authenticator = authenticator;
+ }
+
+ /**
+ * Sets the request body negotiation threshold.
+ * If this is set, it determines the maximum size that the request body
+ * may be before body negotiation occurs(via the
+ * 100-continue
expectation). This ensures that a large
+ * request body is not sent when the server wouldn't have accepted it
+ * anyway.
+ * @param threshold the body negotiation threshold, or <=0 to disable
+ * request body negotation entirely
+ */
+ public void setRequestBodyNegotiationThreshold(int threshold)
+ {
+ requestBodyNegotiationThreshold = threshold;
+ }
+
+ /**
+ * Dispatches this request.
+ * A request can only be dispatched once; calling this method a second
+ * time results in a protocol exception.
+ * @exception IOException if an I/O error occurred
+ * @return an HTTP response object representing the result of the operation
+ */
+ public Response dispatch()
+ throws IOException
+ {
+ if (dispatched)
+ {
+ throw new ProtocolException("request already dispatched");
+ }
+ final String CRLF = "\r\n";
+ final String HEADER_SEP = ": ";
+ final String US_ASCII = "US-ASCII";
+ final String version = connection.getVersion();
+ Response response;
+ int contentLength = -1;
+ boolean retry = false;
+ int attempts = 0;
+ boolean expectingContinue = false;
+ if (requestBodyWriter != null)
+ {
+ contentLength = requestBodyWriter.getContentLength();
+ if (contentLength > requestBodyNegotiationThreshold)
+ {
+ expectingContinue = true;
+ setHeader("Expect", "100-continue");
+ }
+ else
+ {
+ setHeader("Content-Length", Integer.toString(contentLength));
+ }
+ }
+
+ try
+ {
+ // Loop while authentication fails or continue
+ do
+ {
+ retry = false;
+ // Send request
+ connection.fireRequestEvent(RequestEvent.REQUEST_SENDING, this);
+
+ // Get socket output and input streams
+ OutputStream out = connection.getOutputStream();
+ LineInputStream in =
+ new LineInputStream(connection.getInputStream());
+ // Request line
+ String requestUri = path;
+ if (connection.isUsingProxy() &&
+ !"*".equals(requestUri) &&
+ !"CONNECT".equals(method))
+ {
+ requestUri = getRequestURI();
+ }
+ String line = method + ' ' + requestUri + ' ' + version + CRLF;
+ out.write(line.getBytes(US_ASCII));
+ // Request headers
+ for (Iterator i = requestHeaders.keySet().iterator();
+ i.hasNext(); )
+ {
+ String name =(String) i.next();
+ String value =(String) requestHeaders.get(name);
+ line = name + HEADER_SEP + value + CRLF;
+ out.write(line.getBytes(US_ASCII));
+ }
+ out.write(CRLF.getBytes(US_ASCII));
+ // Request body
+ if (requestBodyWriter != null && !expectingContinue)
+ {
+ byte[] buffer = new byte[4096];
+ int len;
+ int count = 0;
+
+ requestBodyWriter.reset();
+ do
+ {
+ len = requestBodyWriter.write(buffer);
+ if (len > 0)
+ {
+ out.write(buffer, 0, len);
+ }
+ count += len;
+ }
+ while (len > -1 && count < contentLength);
+ out.write(CRLF.getBytes(US_ASCII));
+ }
+ out.flush();
+ // Sent event
+ connection.fireRequestEvent(RequestEvent.REQUEST_SENT, this);
+ // Get response
+ response = readResponse(in);
+ int sc = response.getCode();
+ if (sc == 401 && authenticator != null)
+ {
+ if (authenticate(response, attempts++))
+ {
+ retry = true;
+ }
+ }
+ else if (sc == 100 && expectingContinue)
+ {
+ requestHeaders.remove("Expect");
+ setHeader("Content-Length", Integer.toString(contentLength));
+ expectingContinue = false;
+ retry = true;
+ }
+ }
+ while (retry);
+ }
+ catch (IOException e)
+ {
+ connection.close();
+ throw e;
+ }
+ return response;
+ }
+
+ Response readResponse(LineInputStream in)
+ throws IOException
+ {
+ String line;
+ int len;
+
+ // Read response status line
+ line = in.readLine();
+ if (line == null)
+ {
+ throw new ProtocolException("Peer closed connection");
+ }
+ if (!line.startsWith("HTTP/"))
+ {
+ throw new ProtocolException(line);
+ }
+ len = line.length();
+ int start = 5, end = 6;
+ while (line.charAt(end) != '.')
+ {
+ end++;
+ }
+ int majorVersion = Integer.parseInt(line.substring(start, end));
+ start = end + 1;
+ end = start + 1;
+ while (line.charAt(end) != ' ')
+ {
+ end++;
+ }
+ int minorVersion = Integer.parseInt(line.substring(start, end));
+ start = end + 1;
+ end = start + 3;
+ int code = Integer.parseInt(line.substring(start, end));
+ String message = line.substring(end + 1, len - 1);
+ // Read response headers
+ Headers responseHeaders = new Headers();
+ responseHeaders.parse(in);
+ notifyHeaderHandlers(responseHeaders);
+ // Construct response
+ int codeClass = code / 100;
+ Response ret = new Response(majorVersion, minorVersion, code,
+ codeClass, message, responseHeaders);
+ switch (code)
+ {
+ case 204:
+ case 205:
+ case 304:
+ break;
+ default:
+ // Does response body reader want body?
+ boolean notify = (responseBodyReader != null);
+ if (notify)
+ {
+ if (!responseBodyReader.accept(this, ret))
+ {
+ notify = false;
+ }
+ }
+ readResponseBody(ret, in, notify);
+ }
+ return ret;
+ }
+
+ void notifyHeaderHandlers(Headers headers)
+ {
+ for (Iterator i = headers.entrySet().iterator(); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ String name =(String) entry.getKey();
+ // Handle Set-Cookie
+ if ("Set-Cookie".equalsIgnoreCase(name))
+ {
+ String value = (String) entry.getValue();
+ handleSetCookie(value);
+ }
+ ResponseHeaderHandler handler =
+ (ResponseHeaderHandler) responseHeaderHandlers.get(name);
+ if (handler != null)
+ {
+ String value = (String) entry.getValue();
+ handler.setValue(value);
+ }
+ }
+ }
+
+ void readResponseBody(Response response, InputStream in,
+ boolean notify)
+ throws IOException
+ {
+ byte[] buffer = new byte[4096];
+ int contentLength = -1;
+ Headers trailer = null;
+
+ String transferCoding = response.getHeader("Transfer-Encoding");
+ if ("chunked".equalsIgnoreCase(transferCoding))
+ {
+ trailer = new Headers();
+ in = new ChunkedInputStream(in, trailer);
+ }
+ else
+ {
+ contentLength = response.getIntHeader("Content-Length");
+ }
+ String contentCoding = response.getHeader("Content-Encoding");
+ if (contentCoding != null && !"identity".equals(contentCoding))
+ {
+ if ("gzip".equals(contentCoding))
+ {
+ in = new GZIPInputStream(in);
+ }
+ else if ("deflate".equals(contentCoding))
+ {
+ in = new InflaterInputStream(in);
+ }
+ else
+ {
+ throw new ProtocolException("Unsupported Content-Encoding: " +
+ contentCoding);
+ }
+ }
+
+ // Persistent connections are the default in HTTP/1.1
+ boolean doClose = "close".equalsIgnoreCase(getHeader("Connection")) ||
+ "close".equalsIgnoreCase(response.getHeader("Connection")) ||
+ (connection.majorVersion == 1 && connection.minorVersion == 0) ||
+ (response.majorVersion == 1 && response.minorVersion == 0);
+
+ int count = contentLength;
+ int len = (count > -1) ? count : buffer.length;
+ len = (len > buffer.length) ? buffer.length : len;
+ while (len > -1)
+ {
+ len = in.read(buffer, 0, len);
+ if (len < 0)
+ {
+ // EOF
+ connection.closeConnection();
+ break;
+ }
+ if (notify)
+ {
+ responseBodyReader.read(buffer, 0, len);
+ }
+ if (count > -1)
+ {
+ count -= len;
+ if (count < 1)
+ {
+ if (doClose)
+ {
+ connection.closeConnection();
+ }
+ break;
+ }
+ }
+ }
+ if (notify)
+ {
+ responseBodyReader.close();
+ }
+ if (trailer != null)
+ {
+ response.getHeaders().putAll(trailer);
+ notifyHeaderHandlers(trailer);
+ }
+ }
+
+ boolean authenticate(Response response, int attempts)
+ throws IOException
+ {
+ String challenge = response.getHeader("WWW-Authenticate");
+ if (challenge == null)
+ {
+ challenge = response.getHeader("Proxy-Authenticate");
+ }
+ int si = challenge.indexOf(' ');
+ String scheme = (si == -1) ? challenge : challenge.substring(0, si);
+ if ("Basic".equalsIgnoreCase(scheme))
+ {
+ Properties params = parseAuthParams(challenge.substring(si + 1));
+ String realm = params.getProperty("realm");
+ Credentials creds = authenticator.getCredentials(realm, attempts);
+ String userPass = creds.getUsername() + ':' + creds.getPassword();
+ byte[] b_userPass = userPass.getBytes("US-ASCII");
+ byte[] b_encoded = BASE64.encode(b_userPass);
+ String authorization =
+ scheme + " " + new String(b_encoded, "US-ASCII");
+ setHeader("Authorization", authorization);
+ return true;
+ }
+ else if ("Digest".equalsIgnoreCase(scheme))
+ {
+ Properties params = parseAuthParams(challenge.substring(si + 1));
+ String realm = params.getProperty("realm");
+ String nonce = params.getProperty("nonce");
+ String qop = params.getProperty("qop");
+ String algorithm = params.getProperty("algorithm");
+ String digestUri = getRequestURI();
+ Credentials creds = authenticator.getCredentials(realm, attempts);
+ String username = creds.getUsername();
+ String password = creds.getPassword();
+ connection.incrementNonce(nonce);
+ try
+ {
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ final byte[] COLON = { 0x3a };
+
+ // Calculate H(A1)
+ md5.reset();
+ md5.update(username.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(realm.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(password.getBytes("US-ASCII"));
+ byte[] ha1 = md5.digest();
+ if ("md5-sess".equals(algorithm))
+ {
+ byte[] cnonce = generateNonce();
+ md5.reset();
+ md5.update(ha1);
+ md5.update(COLON);
+ md5.update(nonce.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(cnonce);
+ ha1 = md5.digest();
+ }
+ String ha1Hex = toHexString(ha1);
+
+ // Calculate H(A2)
+ md5.reset();
+ md5.update(method.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(digestUri.getBytes("US-ASCII"));
+ if ("auth-int".equals(qop))
+ {
+ byte[] hEntity = null; // TODO hash of entity body
+ md5.update(COLON);
+ md5.update(hEntity);
+ }
+ byte[] ha2 = md5.digest();
+ String ha2Hex = toHexString(ha2);
+
+ // Calculate response
+ md5.reset();
+ md5.update(ha1Hex.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(nonce.getBytes("US-ASCII"));
+ if ("auth".equals(qop) || "auth-int".equals(qop))
+ {
+ String nc = getNonceCount(nonce);
+ byte[] cnonce = generateNonce();
+ md5.update(COLON);
+ md5.update(nc.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(cnonce);
+ md5.update(COLON);
+ md5.update(qop.getBytes("US-ASCII"));
+ }
+ md5.update(COLON);
+ md5.update(ha2Hex.getBytes("US-ASCII"));
+ String digestResponse = toHexString(md5.digest());
+
+ String authorization = scheme +
+ " username=\"" + username + "\"" +
+ " realm=\"" + realm + "\"" +
+ " nonce=\"" + nonce + "\"" +
+ " uri=\"" + digestUri + "\"" +
+ " response=\"" + digestResponse + "\"";
+ setHeader("Authorization", authorization);
+ return true;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ return false;
+ }
+ }
+ // Scheme not recognised
+ return false;
+ }
+
+ Properties parseAuthParams(String text)
+ {
+ int len = text.length();
+ String key = null;
+ StringBuffer buf = new StringBuffer();
+ Properties ret = new Properties();
+ boolean inQuote = false;
+ for (int i = 0; i < len; i++)
+ {
+ char c = text.charAt(i);
+ if (c == '"')
+ {
+ inQuote = !inQuote;
+ }
+ else if (c == '=' && key == null)
+ {
+ key = buf.toString().trim();
+ buf.setLength(0);
+ }
+ else if (c == ' ' && !inQuote)
+ {
+ String value = unquote(buf.toString().trim());
+ ret.put(key, value);
+ key = null;
+ buf.setLength(0);
+ }
+ else if (c != ',' || (i <(len - 1) && text.charAt(i + 1) != ' '))
+ {
+ buf.append(c);
+ }
+ }
+ if (key != null)
+ {
+ String value = unquote(buf.toString().trim());
+ ret.put(key, value);
+ }
+ return ret;
+ }
+
+ String unquote(String text)
+ {
+ int len = text.length();
+ if (len > 0 && text.charAt(0) == '"' && text.charAt(len - 1) == '"')
+ {
+ return text.substring(1, len - 1);
+ }
+ return text;
+ }
+
+ /**
+ * Returns the number of times the specified nonce value has been seen.
+ * This always returns an 8-byte 0-padded hexadecimal string.
+ */
+ String getNonceCount(String nonce)
+ {
+ int nc = connection.getNonceCount(nonce);
+ String hex = Integer.toHexString(nc);
+ StringBuffer buf = new StringBuffer();
+ for (int i = 8 - hex.length(); i > 0; i--)
+ {
+ buf.append('0');
+ }
+ buf.append(hex);
+ return buf.toString();
+ }
+
+ /**
+ * Client nonce value.
+ */
+ byte[] nonce;
+
+ /**
+ * Generates a new client nonce value.
+ */
+ byte[] generateNonce()
+ throws IOException, NoSuchAlgorithmException
+ {
+ if (nonce == null)
+ {
+ long time = System.currentTimeMillis();
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ md5.update(Long.toString(time).getBytes("US-ASCII"));
+ nonce = md5.digest();
+ }
+ return nonce;
+ }
+
+ String toHexString(byte[] bytes)
+ {
+ char[] ret = new char[bytes.length * 2];
+ for (int i = 0, j = 0; i < bytes.length; i++)
+ {
+ int c =(int) bytes[i];
+ if (c < 0)
+ {
+ c += 0x100;
+ }
+ ret[j++] = Character.forDigit(c / 0x10, 0x10);
+ ret[j++] = Character.forDigit(c % 0x10, 0x10);
+ }
+ return new String(ret);
+ }
+
+ /**
+ * Parse the specified cookie list and notify the cookie manager.
+ */
+ void handleSetCookie(String text)
+ {
+ CookieManager cookieManager = connection.getCookieManager();
+ if (cookieManager == null)
+ {
+ return;
+ }
+ String name = null;
+ String value = null;
+ String comment = null;
+ String domain = connection.getHostName();
+ String path = this.path;
+ int lsi = path.lastIndexOf('/');
+ if (lsi != -1)
+ {
+ path = path.substring(0, lsi);
+ }
+ boolean secure = false;
+ Date expires = null;
+
+ int len = text.length();
+ String attr = null;
+ StringBuffer buf = new StringBuffer();
+ boolean inQuote = false;
+ for (int i = 0; i <= len; i++)
+ {
+ char c =(i == len) ? '\u0000' : text.charAt(i);
+ if (c == '"')
+ {
+ inQuote = !inQuote;
+ }
+ else if (!inQuote)
+ {
+ if (c == '=' && attr == null)
+ {
+ attr = buf.toString().trim();
+ buf.setLength(0);
+ }
+ else if (c == ';' || i == len || c == ',')
+ {
+ String val = unquote(buf.toString().trim());
+ if (name == null)
+ {
+ name = attr;
+ value = val;
+ }
+ else if ("Comment".equalsIgnoreCase(attr))
+ {
+ comment = val;
+ }
+ else if ("Domain".equalsIgnoreCase(attr))
+ {
+ domain = val;
+ }
+ else if ("Path".equalsIgnoreCase(attr))
+ {
+ path = val;
+ }
+ else if ("Secure".equalsIgnoreCase(val))
+ {
+ secure = true;
+ }
+ else if ("Max-Age".equalsIgnoreCase(attr))
+ {
+ int delta = Integer.parseInt(val);
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(System.currentTimeMillis());
+ cal.add(Calendar.SECOND, delta);
+ expires = cal.getTime();
+ }
+ else if ("Expires".equalsIgnoreCase(attr))
+ {
+ DateFormat dateFormat = new HTTPDateFormat();
+ try
+ {
+ expires = dateFormat.parse(val);
+ }
+ catch (ParseException e)
+ {
+ // if this isn't a valid date, it may be that
+ // the value was returned unquoted; in that case, we
+ // want to continue buffering the value
+ buf.append(c);
+ continue;
+ }
+ }
+ attr = null;
+ buf.setLength(0);
+ // case EOL
+ if (i == len || c == ',')
+ {
+ Cookie cookie = new Cookie(name, value, comment, domain,
+ path, secure, expires);
+ cookieManager.setCookie(cookie);
+ }
+ if (c == ',')
+ {
+ // Reset cookie fields
+ name = null;
+ value = null;
+ comment = null;
+ domain = connection.getHostName();
+ path = this.path;
+ if (lsi != -1)
+ {
+ path = path.substring(0, lsi);
+ }
+ secure = false;
+ expires = null;
+ }
+ }
+ else
+ {
+ buf.append(c);
+ }
+ }
+ else
+ {
+ buf.append(c);
+ }
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java b/libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java
new file mode 100644
index 0000000..05d98eb
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java
@@ -0,0 +1,69 @@
+/* RequestBodyWriter.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http;
+
+/**
+ * Callback interface for writing request body content.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface RequestBodyWriter
+{
+
+ /**
+ * Returns the total number of bytes that will be written in a single pass
+ * by this writer.
+ */
+ int getContentLength();
+
+ /**
+ * Initialises the writer.
+ * This will be called before each pass.
+ */
+ void reset();
+
+ /**
+ * Writes body content to the supplied buffer.
+ * @param buffer the content buffer
+ * @return the number of bytes written
+ */
+ int write(byte[] buffer);
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/Response.java b/libjava/classpath/gnu/java/net/protocol/http/Response.java
new file mode 100644
index 0000000..29dc28b
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Response.java
@@ -0,0 +1,185 @@
+/* Response.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http;
+
+import java.util.Date;
+
+/**
+ * An HTTP response.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Response
+{
+
+ /**
+ * The HTTP major version of the server issuing the response.
+ */
+ protected final int majorVersion;
+
+ /**
+ * The HTTP minor version of the server issuing the response.
+ */
+ protected final int minorVersion;
+
+ /**
+ * The HTTP status code of the response.
+ */
+ protected final int code;
+
+ /**
+ * The class of the response. This is the most significant digit of the
+ * status code.
+ *
+ *
+ */
+ protected final int codeClass;
+
+ /**
+ * Human-readable text of the response.
+ */
+ protected final String message;
+
+ /**
+ * The response headers.
+ */
+ protected final Headers headers;
+
+ /**
+ * Constructs a new response with the specified parameters.
+ */
+ protected Response(int majorVersion, int minorVersion, int code,
+ int codeClass, String message,
+ Headers headers)
+ {
+ this.majorVersion = majorVersion;
+ this.minorVersion = minorVersion;
+ this.code = code;
+ this.codeClass = codeClass;
+ this.message = message;
+ this.headers = headers;
+ }
+
+ /**
+ * Returns the HTTP major version of the server issuing the response.
+ * @see #majorVersion
+ */
+ public int getMajorVersion()
+ {
+ return majorVersion;
+ }
+
+ /**
+ * Returns the HTTP minor version of the server issuing the response.
+ * @see #minorVersion
+ */
+ public int getMinorVersion()
+ {
+ return minorVersion;
+ }
+
+ /**
+ * Returns the HTTP status code of the response.
+ * @see #code
+ */
+ public int getCode()
+ {
+ return code;
+ }
+
+ /**
+ * Returns the class of the response.
+ * @see #codeClass
+ */
+ public int getCodeClass()
+ {
+ return codeClass;
+ }
+
+ /**
+ * Returns the human-readable text of the response.
+ * @see #message
+ */
+ public String getMessage()
+ {
+ return message;
+ }
+
+ /**
+ * Returns the headers in the response.
+ */
+ public Headers getHeaders()
+ {
+ return headers;
+ }
+
+ /**
+ * Returns the header value for the specified name.
+ * @param name the header name
+ */
+ public String getHeader(String name)
+ {
+ return headers.getValue(name);
+ }
+
+ /**
+ * Returns the header value for the specified name as an integer.
+ * @param name the header name
+ */
+ public int getIntHeader(String name)
+ {
+ return headers.getIntValue(name);
+ }
+
+ /**
+ * Returns the header value for the specified name as a date.
+ * @param name the header name
+ */
+ public Date getDateHeader(String name)
+ {
+ return headers.getDateValue(name);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/ResponseBodyReader.java b/libjava/classpath/gnu/java/net/protocol/http/ResponseBodyReader.java
new file mode 100644
index 0000000..49e1b37
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/ResponseBodyReader.java
@@ -0,0 +1,70 @@
+/* ResponseBodyReader.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http;
+
+/**
+ * Callback interface for receiving notification of response body content.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface ResponseBodyReader
+{
+
+ /**
+ * Indicate whether this reader is interested in the specified response.
+ * If it returns false, it will not receive body content notifications for
+ * that response.
+ */
+ boolean accept(Request request, Response response);
+
+ /**
+ * Receive notification of body content.
+ * @param buffer the content buffer
+ * @param offset the offset within the buffer that content starts
+ * @param length the length of the content
+ */
+ void read(byte[] buffer, int offset, int length);
+
+ /**
+ * Notifies the reader that the end of the content was reached.
+ */
+ void close();
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java b/libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java
new file mode 100644
index 0000000..8e4e649
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java
@@ -0,0 +1,57 @@
+/* ResponseHeaderHandler.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http;
+
+/**
+ * Callback interface for objects that wish to be notified of response
+ * header values.
+ * @see Request#setHeaderHandler(String)
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface ResponseHeaderHandler
+{
+
+ /**
+ * Sets the value for the header associated with this handler.
+ */
+ void setValue(String value);
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java b/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java
new file mode 100644
index 0000000..8947471
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java
@@ -0,0 +1,140 @@
+/* CookieManager.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A simple non-persistent cookie manager. This class can be extended to
+ * provide cookie persistence.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class SimpleCookieManager
+ implements CookieManager
+{
+
+ /**
+ * The cookie cache.
+ * This is a dictionary mapping domains to maps of cookies by name.
+ */
+ protected Map cookies;
+
+ /**
+ * Constructor.
+ */
+ public SimpleCookieManager()
+ {
+ cookies = new HashMap();
+ }
+
+ public void setCookie(Cookie cookie)
+ {
+ String domain = cookie.getDomain();
+ Map map =(Map) cookies.get(domain);
+ if (map == null)
+ {
+ map = new HashMap();
+ cookies.put(domain, map);
+ }
+ String name = cookie.getName();
+ map.put(name, cookie); // will replace a cookie of the same name
+ }
+
+ public Cookie[] getCookies(String host, boolean secure, String path)
+ {
+ List matches = new ArrayList();
+ Date now = new Date();
+ if (Character.isLetter(host.charAt(0)))
+ {
+ int di = host.indexOf('.');
+ while (di != -1)
+ {
+ addCookies(matches, host, secure, path, now);
+ host = host.substring(di);
+ di = host.indexOf('.', 1);
+ }
+ }
+ addCookies(matches, host, secure, path, now);
+ Cookie[] ret = new Cookie[matches.size()];
+ matches.toArray(ret);
+ return ret;
+ }
+
+ private void addCookies(List matches, String domain, boolean secure,
+ String path, Date now)
+ {
+ Map map = (Map) cookies.get(domain);
+ if (map != null)
+ {
+ List expired = new ArrayList();
+ for (Iterator i = map.entrySet().iterator(); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ Cookie cookie = (Cookie) entry.getValue();
+ Date expires = cookie.getExpiryDate();
+ if (expires != null && expires.before(now))
+ {
+ expired.add(entry.getKey());
+ continue;
+ }
+ if (secure && !cookie.isSecure())
+ {
+ continue;
+ }
+ if (path.startsWith(cookie.getPath()))
+ {
+ matches.add(cookie);
+ }
+ }
+ // Good housekeeping
+ for (Iterator i = expired.iterator(); i.hasNext(); )
+ {
+ map.remove(i.next());
+ }
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionEvent.java b/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionEvent.java
new file mode 100644
index 0000000..3f6f545
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionEvent.java
@@ -0,0 +1,81 @@
+/* ConnectionEvent.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http.event;
+
+import java.util.EventObject;
+
+/**
+ * A connection event.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class ConnectionEvent
+ extends EventObject
+{
+
+ /**
+ * The connection closed event type.
+ */
+ public static final int CONNECTION_CLOSED = 0;
+
+ /**
+ * The type of this event.
+ */
+ protected int type;
+
+ /**
+ * Constructs a connection event with the specified source and type.
+ */
+ public ConnectionEvent(Object source, int type)
+ {
+ super(source);
+ this.type = type;
+ }
+
+ /**
+ * Returns the type of this event.
+ * @see #type
+ */
+ public int getType()
+ {
+ return type;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionListener.java b/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionListener.java
new file mode 100644
index 0000000..073e89d
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionListener.java
@@ -0,0 +1,58 @@
+/* ConnectionListener.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http.event;
+
+import java.util.EventListener;
+
+/**
+ * A connection listener.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface ConnectionListener
+ extends EventListener
+{
+
+ /**
+ * Callback invoked when the associated connection is closed.
+ */
+ void connectionClosed(ConnectionEvent event);
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/event/RequestEvent.java b/libjava/classpath/gnu/java/net/protocol/http/event/RequestEvent.java
new file mode 100644
index 0000000..281c621
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/event/RequestEvent.java
@@ -0,0 +1,107 @@
+/* RequestEvent.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http.event;
+
+import gnu.java.net.protocol.http.Request;
+
+import java.util.EventObject;
+
+/**
+ * A request event.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class RequestEvent
+ extends EventObject
+{
+
+ /**
+ * The request created event type.
+ */
+ public static final int REQUEST_CREATED = 0;
+
+ /**
+ * The request sending event type.
+ */
+ public static final int REQUEST_SENDING = 1;
+
+ /**
+ * The request sent event type.
+ */
+ public static final int REQUEST_SENT = 2;
+
+ /**
+ * The type of this event.
+ */
+ protected int type;
+
+ /**
+ * The request associated with this event.
+ */
+ protected Request request;
+
+ /**
+ * Constructs a request event with the specified source, type, and request.
+ */
+ public RequestEvent(Object source, int type, Request request)
+ {
+ super(source);
+ this.type = type;
+ this.request = request;
+ }
+
+ /**
+ * Returns the type of this event.
+ * @see #type
+ */
+ public int getType()
+ {
+ return type;
+ }
+
+ /**
+ * Returns the request associated with this event.
+ */
+ public Request getRequest()
+ {
+ return request;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/event/RequestListener.java b/libjava/classpath/gnu/java/net/protocol/http/event/RequestListener.java
new file mode 100644
index 0000000..c880fbc
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/event/RequestListener.java
@@ -0,0 +1,70 @@
+/* RequestListener.java --
+ Copyright (C) 2004 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 gnu.java.net.protocol.http.event;
+
+import java.util.EventListener;
+
+/**
+ * A request listener.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface RequestListener
+ extends EventListener
+{
+
+ /**
+ * Callback invoked when a request is created from the associated
+ * connection.
+ */
+ void requestCreated(RequestEvent event);
+
+ /**
+ * Callback invoked when the request has been initialised with all data
+ * and before sending this data to the server.
+ */
+ void requestSending(RequestEvent event);
+
+ /**
+ * Callback invoked after all request data has been sent to the server.
+ */
+ void requestSent(RequestEvent event);
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/event/package.html b/libjava/classpath/gnu/java/net/protocol/http/event/package.html
new file mode 100644
index 0000000..6aed0fc
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/event/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+1xx
2xx
3xx
4xx
5xx
+
+
+The API is similar to the neon
+WebDAV/HTTP library. A logical connection to the server is instantiated,
+and multiple requests can be issued for this connection. Each request
+has an atomic dispatch
method which returns the response.
+All I/O, authentication, etc is handled by registering callback objects
+with the request prior to dispatch, which are notified during the dispatch
+procedure as necessary. Simple byte-array content callbacks are supplied
+which can manage any request/response content that fits in available memory.
+
+An URL stream handler is provided, supporting the full HttpURLConnection +specification. +
+ + diff --git a/libjava/classpath/gnu/java/net/protocol/https/Handler.java b/libjava/classpath/gnu/java/net/protocol/https/Handler.java new file mode 100644 index 0000000..2b13751 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/https/Handler.java @@ -0,0 +1,76 @@ +/* Handler.java -- + Copyright (C) 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 gnu.java.net.protocol.https; + +import gnu.java.net.protocol.http.HTTPConnection; +import gnu.java.net.protocol.http.HTTPURLConnection; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * An HTTPS URL stream handler. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class Handler + extends URLStreamHandler +{ + + /** + * Returns the default HTTPS port (443). + */ + protected int getDefaultPort() + { + return HTTPConnection.HTTPS_PORT; + } + + /** + * Returns an HTTPURLConnection for the given URL. + */ + public URLConnection openConnection(URL url) + throws IOException + { + return new HTTPURLConnection(url); + } + +} + diff --git a/libjava/classpath/gnu/java/net/protocol/jar/Connection.java b/libjava/classpath/gnu/java/net/protocol/jar/Connection.java new file mode 100644 index 0000000..bd7a80d --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/jar/Connection.java @@ -0,0 +1,170 @@ +/* Connection - jar url connection for java.net + Copyright (C) 1999, 2002, 2003, 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 gnu.java.net.protocol.jar; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.JarURLConnection; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Hashtable; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipFile; + +/** + * This subclass of java.net.JarURLConnection models a URLConnection via + * the "jar" protocol. + * + * @author Kresten Krab Thorup (krab@gnu.org) + */ +public final class Connection extends JarURLConnection +{ + private JarFile jar_file; + private JarEntry jar_entry; + private URL jar_url; + + public static class JarFileCache + { + private static Hashtable cache = new Hashtable(); + private static final int READBUFSIZE = 4*1024; + + public static synchronized JarFile get (URL url) throws IOException + { + JarFile jf = (JarFile) cache.get (url); + + if (jf != null) + return jf; + + if ("file".equals (url.getProtocol())) + { + File f = new File (url.getFile()); + jf = new JarFile (f, true, ZipFile.OPEN_READ); + } + else + { + URLConnection urlconn = url.openConnection(); + InputStream is = urlconn.getInputStream(); + byte[] buf = new byte [READBUFSIZE]; + File f = File.createTempFile ("cache", "jar"); + FileOutputStream fos = new FileOutputStream (f); + int len = 0; + + while ((len = is.read (buf)) != -1) + { + fos.write (buf, 0, len); + } + + fos.close(); + // Always verify the Manifest, open read only and delete when done. + jf = new JarFile (f, true, + ZipFile.OPEN_READ | ZipFile.OPEN_DELETE); + } + + cache.put (url, jf); + + return jf; + } + } + + protected Connection(URL url) + throws MalformedURLException + { + super(url); + } + + public synchronized void connect() throws IOException + { + // Call is ignored if already connected. + if (connected) + return; + + jar_url = getJarFileURL(); + jar_file = JarFileCache.get (jar_url); + String entry_name = getEntryName(); + + if (entry_name != null + && !entry_name.equals ("")) + { + jar_entry = (JarEntry) jar_file.getEntry (entry_name); + + if(jar_entry == null) + throw new IOException ("No entry for " + entry_name + " exists."); + } + + connected = true; + } + + public InputStream getInputStream() throws IOException + { + if (!connected) + connect(); + + if (! doInput) + throw new ProtocolException("Can't open InputStream if doInput is false"); + + if (jar_entry == null) + throw new IOException (jar_url + " couldn't be found."); + + return jar_file.getInputStream (jar_entry); + } + + public synchronized JarFile getJarFile() throws IOException + { + if (!connected) + connect(); + + if (! doInput) + throw new ProtocolException("Can't open JarFile if doInput is false"); + + return jar_file; + } + + public int getContentLength() + { + if (!connected) + return -1; + + return (int) jar_entry.getSize(); + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/jar/Handler.java b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java new file mode 100644 index 0000000..316d8cb --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java @@ -0,0 +1,173 @@ +/* gnu.java.net.protocol.jar.Handler - jar protocol handler for java.net + Copyright (C) 1999, 2002, 2003, 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 gnu.java.net.protocol.jar; + +import gnu.java.net.URLParseError; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * @author Kresten Krab Thorup (krab@gnu.org) + */ +public class Handler extends URLStreamHandler +{ + /** + * A do nothing constructor + */ + public Handler() + { + } + + /** + * This method returs a new JarURLConnection for the specified URL + * + * @param url The URL to return a connection for + * + * @return The URLConnection + * + * @exception IOException If an error occurs + */ + protected URLConnection openConnection(URL url) throws IOException + { + return new Connection(url); + } + + /** + * This method overrides URLStreamHandler's for parsing url of protocol "jar" + * + * @param url The URL object in which to store the results + * @param url_string The String-ized URL to parse + * @param start The position in the string to start scanning from + * @param end The position in the string to stop scanning + */ + protected void parseURL (URL url, String url_string, int start, int end) + { + // This method does not throw an exception or return a value. Thus our + // strategy when we encounter an error in parsing is to return without + // doing anything. + String file = url.getFile(); + + if (!file.equals("")) + { //has context url + url_string = url_string.substring (start, end); + if (url_string.startsWith("/")) + { //url string is an absolute path + int idx = file.lastIndexOf ("!/"); + + if (idx < 0) + throw new URLParseError("no !/ in spec"); + + file = file.substring (0, idx + 1) + url_string; + } + else if (url_string.length() > 0) + { + int idx = file.lastIndexOf ("/"); + if (idx == -1) //context path is weird + file = "/" + url_string; + else if (idx == (file.length() - 1)) + //just concatenate two parts + file = file + url_string; + else + // according to Java API Documentation, here is a little different + // with URLStreamHandler.parseURL + // but JDK seems doesn't handle it well + file = file.substring(0, idx + 1) + url_string; + } + + setURL (url, "jar", url.getHost(), url.getPort(), file, null); + return; + } + + // Bunches of things should be true. Make sure. + if (end < start) + return; + if (end - start < 2) + return; + if (start > url_string.length()) + return; + + // Skip remains of protocol + url_string = url_string.substring (start, end); + + int jar_stop; + if ((jar_stop = url_string.indexOf("!/")) < 0) + throw new URLParseError("no !/ in spec"); + + try + { + new URL(url_string.substring (0, jar_stop)); + } + catch (MalformedURLException e) + { + throw new URLParseError("invalid inner URL: " + e.getMessage()); + } + + if (!url.getProtocol().equals ("jar") ) + throw new URLParseError("unexpected protocol " + url.getProtocol()); + + setURL (url, "jar", url.getHost(), url.getPort(), url_string, null); + } + + /** + * This method converts a Jar URL object into a String. + * + * @param url The URL object to convert + */ + protected String toExternalForm (URL url) + { + String file = url.getFile(); + String ref = url.getRef(); + + // return "jar:" + file; + // Performance!!: + // Do the concatenation manually to avoid resize StringBuffer's + // internal buffer. The length of ref is not taken into consideration + // as it's a rare path. + StringBuffer sb = new StringBuffer (file.length() + 5); + sb.append ("jar:"); + sb.append (file); + if (ref != null) + sb.append('#').append(ref); + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/jar/package.html b/libjava/classpath/gnu/java/net/protocol/jar/package.html new file mode 100644 index 0000000..dcd263d --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/jar/package.html @@ -0,0 +1,46 @@ + + + + ++ * This is a bridge between NIO <-> IO character decoding. + *
+ * + * @author Robert Schuster + */ +public class ChannelReader extends Reader +{ + + private static final int DEFAULT_BUFFER_CAP = 8192; + + private ReadableByteChannel channel; + + private CharsetDecoder decoder; + + private ByteBuffer byteBuffer; + + private CharBuffer charBuffer; + + public ChannelReader(ReadableByteChannel channel, CharsetDecoder decoder, + int minBufferCap) + { + this.channel = channel; + this.decoder = decoder; + + // JDK reports errors, so we do the same. + decoder.onMalformedInput(CodingErrorAction.REPORT); + decoder.onUnmappableCharacter(CodingErrorAction.REPORT); + decoder.reset(); + + int size = (minBufferCap == -1) ? DEFAULT_BUFFER_CAP : minBufferCap; + + // Allocates the buffers and prepares them for reading, because that is the + // first operation being done on them. + byteBuffer = ByteBuffer.allocate(size); + byteBuffer.flip(); + charBuffer = CharBuffer.allocate((int) (size * decoder.averageCharsPerByte())); + } + + public int read(char[] buf, int offset, int count) throws IOException + { + // I declared channel being null meaning that the reader is closed. + if (!channel.isOpen()) + throw new IOException("Reader was already closed."); + + // I declared decoder being null meaning that there is no more data to read + // and convert. + if (decoder == null) + return -1; + + // Stores the amount of character being read. It -1 so that if no conversion + // occured the caller will see this as an 'end of file'. + int sum = -1; + + // Copies any characters which may be left from the last invocation into the + // destination array. + if (charBuffer.remaining() > 0) + { + sum = Math.min(count, charBuffer.remaining()); + charBuffer.get(buf, offset, sum); + + // Updates the control variables according to the latest copy operation. + offset += sum; + count -= sum; + } + + // Copies the character which have not been put in the destination array to + // the beginning. If data is actually copied count will be 0. If no data is + // copied count is >0 and we can now convert some more characters. + charBuffer.compact(); + + int converted = 0; + boolean last = false; + + while (count != 0) + { + // Tries to convert some bytes (Which will intentionally fail in the + // first place because we have not read any bytes yet.) + CoderResult result = decoder.decode(byteBuffer, charBuffer, last); + if (result.isMalformed() || result.isUnmappable()) + { + // JDK throws exception when bytes are malformed for sure. + // FIXME: Unsure what happens when a character is simply + // unmappable. + result.throwException(); + } + + // Marks that we should end this loop regardless whether the caller + // wants more chars or not, when this was the last conversion. + if (last) + { + decoder = null; + } + else if (result.isUnderflow()) + { + // We need more bytes to do the conversion. + + // Copies the not yet converted bytes to the beginning making it + // being able to receive more bytes. + byteBuffer.compact(); + + // Reads in another bunch of bytes for being converted. + if (channel.read(byteBuffer) == -1) + { + // If there is no more data available in the channel we mark + // that state for the final character conversion run which is + // done in the next loop iteration. + last = true; + } + + // Prepares the byteBuffer for the next character conversion run. + byteBuffer.flip(); + } + + // Prepares the charBuffer for being drained. + charBuffer.flip(); + + converted = Math.min(count, charBuffer.remaining()); + charBuffer.get(buf, offset, converted); + + // Copies characters which have not yet being copied into the char-Array + // to the beginning making it possible to read them later (If data is + // really copied here, then the caller has received enough characters so + // far.). + charBuffer.compact(); + + // Updates the control variables according to the latest copy operation. + offset += converted; + count -= converted; + + // Updates the amount of transferred characters. + sum += converted; + + if (decoder == null) + { + break; + } + + // Now that more characters have been transfered we let the loop decide + // what to do next. + } + + // Makes the charBuffer ready for reading on the next invocation. + charBuffer.flip(); + + return sum; + } + + public void close() throws IOException + { + channel.close(); + + // Makes sure all intermediate data is released by the decoder. + if (decoder != null) + decoder.reset(); + } + +} diff --git a/libjava/classpath/gnu/java/nio/DatagramChannelImpl.java b/libjava/classpath/gnu/java/nio/DatagramChannelImpl.java new file mode 100644 index 0000000..51c7031 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/DatagramChannelImpl.java @@ -0,0 +1,297 @@ +/* DatagramChannelImpl.java -- + Copyright (C) 2002, 2003, 2004 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 gnu.java.nio; + +import gnu.java.net.PlainDatagramSocketImpl; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.NotYetConnectedException; +import java.nio.channels.spi.SelectorProvider; + +/** + * @author Michael Koch + */ +public final class DatagramChannelImpl extends DatagramChannel +{ + private NIODatagramSocket socket; + + /** + * Indicates whether this channel initiated whatever operation + * is being invoked on our datagram socket. + */ + private boolean inChannelOperation; + + /** + * Indicates whether our datagram socket should ignore whether + * we are set to non-blocking mode. Certain operations on our + * socket throw anIllegalBlockingModeException
if
+ * we are in non-blocking mode, except if the operation
+ * is initiated by us.
+ */
+ public final boolean isInChannelOperation()
+ {
+ return inChannelOperation;
+ }
+
+ /**
+ * Sets our indicator of whether we are initiating an I/O operation
+ * on our socket.
+ */
+ public final void setInChannelOperation(boolean b)
+ {
+ inChannelOperation = b;
+ }
+
+ protected DatagramChannelImpl (SelectorProvider provider)
+ throws IOException
+ {
+ super (provider);
+ socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this);
+ configureBlocking(true);
+ }
+
+ public DatagramSocket socket ()
+ {
+ return socket;
+ }
+
+ protected void implCloseSelectableChannel ()
+ throws IOException
+ {
+ socket.close ();
+ }
+
+ protected void implConfigureBlocking (boolean blocking)
+ throws IOException
+ {
+ socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+ }
+
+ public DatagramChannel connect (SocketAddress remote)
+ throws IOException
+ {
+ if (!isOpen())
+ throw new ClosedChannelException();
+
+ socket.connect (remote);
+ return this;
+ }
+
+ public DatagramChannel disconnect ()
+ throws IOException
+ {
+ socket.disconnect ();
+ return this;
+ }
+
+ public boolean isConnected ()
+ {
+ return socket.isConnected ();
+ }
+
+ public int write (ByteBuffer src)
+ throws IOException
+ {
+ if (!isConnected ())
+ throw new NotYetConnectedException ();
+
+ return send (src, socket.getRemoteSocketAddress());
+ }
+
+ public long write (ByteBuffer[] srcs, int offset, int length)
+ throws IOException
+ {
+ if (!isConnected())
+ throw new NotYetConnectedException();
+
+ if ((offset < 0)
+ || (offset > srcs.length)
+ || (length < 0)
+ || (length > (srcs.length - offset)))
+ throw new IndexOutOfBoundsException();
+
+ long result = 0;
+
+ for (int index = offset; index < offset + length; index++)
+ result += write (srcs [index]);
+
+ return result;
+ }
+
+ public int read (ByteBuffer dst)
+ throws IOException
+ {
+ if (!isConnected ())
+ throw new NotYetConnectedException ();
+
+ int remaining = dst.remaining();
+ receive (dst);
+ return remaining - dst.remaining();
+ }
+
+ public long read (ByteBuffer[] dsts, int offset, int length)
+ throws IOException
+ {
+ if (!isConnected())
+ throw new NotYetConnectedException();
+
+ if ((offset < 0)
+ || (offset > dsts.length)
+ || (length < 0)
+ || (length > (dsts.length - offset)))
+ throw new IndexOutOfBoundsException();
+
+ long result = 0;
+
+ for (int index = offset; index < offset + length; index++)
+ result += read (dsts [index]);
+
+ return result;
+ }
+
+ public SocketAddress receive (ByteBuffer dst)
+ throws IOException
+ {
+ if (!isOpen())
+ throw new ClosedChannelException();
+
+ try
+ {
+ DatagramPacket packet;
+ int len = dst.capacity() - dst.position();
+
+ if (dst.hasArray())
+ {
+ packet = new DatagramPacket (dst.array(),
+ dst.arrayOffset() + dst.position(),
+ len);
+ }
+ else
+ {
+ packet = new DatagramPacket (new byte [len], len);
+ }
+
+ boolean completed = false;
+
+ try
+ {
+ begin();
+ setInChannelOperation(true);
+ socket.receive (packet);
+ completed = true;
+ }
+ finally
+ {
+ end (completed);
+ setInChannelOperation(false);
+ }
+
+ if (!dst.hasArray())
+ {
+ dst.put (packet.getData(), packet.getOffset(), packet.getLength());
+ }
+ else
+ {
+ dst.position (dst.position() + packet.getLength());
+ }
+
+ return packet.getSocketAddress();
+ }
+ catch (SocketTimeoutException e)
+ {
+ return null;
+ }
+ }
+
+ public int send (ByteBuffer src, SocketAddress target)
+ throws IOException
+ {
+ if (!isOpen())
+ throw new ClosedChannelException();
+
+ if (target instanceof InetSocketAddress
+ && ((InetSocketAddress) target).isUnresolved())
+ throw new IOException("Target address not resolved");
+
+ byte[] buffer;
+ int offset = 0;
+ int len = src.remaining();
+
+ if (src.hasArray())
+ {
+ buffer = src.array();
+ offset = src.arrayOffset() + src.position();
+ }
+ else
+ {
+ buffer = new byte [len];
+ src.get (buffer);
+ }
+
+ DatagramPacket packet = new DatagramPacket (buffer, offset, len, target);
+
+ boolean completed = false;
+ try
+ {
+ begin();
+ setInChannelOperation(true);
+ socket.send(packet);
+ completed = true;
+ }
+ finally
+ {
+ end (completed);
+ setInChannelOperation(false);
+ }
+
+ if (src.hasArray())
+ {
+ src.position (src.position() + len);
+ }
+
+ return len;
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java b/libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java
new file mode 100644
index 0000000..698e07e
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java
@@ -0,0 +1,61 @@
+/* DatagramChannelSelectionKey.java --
+ Copyright (C) 2003, 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 gnu.java.nio;
+
+import java.nio.channels.spi.AbstractSelectableChannel;
+
+/**
+ * @author Michael Koch
+ */
+public final class DatagramChannelSelectionKey
+ extends SelectionKeyImpl
+{
+ public DatagramChannelSelectionKey (AbstractSelectableChannel channel,
+ SelectorImpl selector)
+ {
+ super (channel, selector);
+ }
+
+ public int getNativeFD()
+ {
+ NIODatagramSocket socket =
+ (NIODatagramSocket) ((DatagramChannelImpl) ch).socket();
+ return socket.getPlainDatagramSocketImpl().getNativeFD();
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/FileLockImpl.java b/libjava/classpath/gnu/java/nio/FileLockImpl.java
new file mode 100644
index 0000000..245fa73
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/FileLockImpl.java
@@ -0,0 +1,82 @@
+/* FileLockImpl.java --
+ Copyright (C) 2002, 2004 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 gnu.java.nio;
+
+import gnu.java.nio.channels.FileChannelImpl;
+
+import java.io.IOException;
+import java.nio.channels.FileLock;
+
+/**
+ * @author Michael Koch
+ * @since 1.4
+ */
+public class FileLockImpl extends FileLock
+{
+ private FileChannelImpl ch;
+
+ public FileLockImpl (FileChannelImpl channel, long position,
+ long size, boolean shared)
+ {
+ super (channel, position, size, shared);
+ ch = channel;
+ }
+
+ protected void finalize()
+ {
+ try
+ {
+ release();
+ }
+ catch (IOException e)
+ {
+ // Ignore this.
+ }
+ }
+
+ public boolean isValid ()
+ {
+ return channel().isOpen();
+ }
+
+ public synchronized void release () throws IOException
+ {
+ ch.unlock(position(), size());
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/InputStreamChannel.java b/libjava/classpath/gnu/java/nio/InputStreamChannel.java
new file mode 100644
index 0000000..a3dffe2
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/InputStreamChannel.java
@@ -0,0 +1,88 @@
+/* InputStreamChannel.java --
+ Copyright (C) 2003 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 gnu.java.nio;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ReadableByteChannel;
+
+/**
+ * @author Michael Koch
+ */
+public final class InputStreamChannel implements ReadableByteChannel
+{
+ private boolean closed = false;
+ private InputStream in;
+
+ public InputStreamChannel (InputStream in)
+ {
+ super();
+ this.in = in;
+ }
+
+ public void close() throws IOException
+ {
+ if (!closed)
+ {
+ in.close();
+ closed = true;
+ }
+ }
+
+ public boolean isOpen()
+ {
+ return !closed;
+ }
+
+ public int read (ByteBuffer dst) throws IOException
+ {
+ if (!isOpen())
+ throw new ClosedChannelException();
+
+ byte[] buffer = new byte [dst.remaining()];
+ int readBytes = in.read (buffer);
+
+ if (readBytes > 0)
+ dst.put (buffer, 0, readBytes);
+
+ return readBytes;
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/NIOConstants.java b/libjava/classpath/gnu/java/nio/NIOConstants.java
new file mode 100644
index 0000000..bb5b3b7
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/NIOConstants.java
@@ -0,0 +1,47 @@
+/* NIOConstants.java --
+ Copyright (C) 2003 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 gnu.java.nio;
+
+/**
+ * @author Michael Koch
+ */
+public final class NIOConstants
+{
+ public static final int DEFAULT_TIMEOUT = 50;
+}
diff --git a/libjava/classpath/gnu/java/nio/NIODatagramSocket.java b/libjava/classpath/gnu/java/nio/NIODatagramSocket.java
new file mode 100644
index 0000000..f23236e
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/NIODatagramSocket.java
@@ -0,0 +1,71 @@
+/* NIODatagramSocket.java --
+ Copyright (C) 2003 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 gnu.java.nio;
+
+import gnu.java.net.PlainDatagramSocketImpl;
+
+import java.net.DatagramSocket;
+import java.nio.channels.DatagramChannel;
+
+/**
+ * @author Michael Koch
+ */
+public final class NIODatagramSocket extends DatagramSocket
+{
+ private PlainDatagramSocketImpl impl;
+ private DatagramChannelImpl channel;
+
+ public NIODatagramSocket (PlainDatagramSocketImpl impl,
+ DatagramChannelImpl channel)
+ {
+ super (impl);
+ this.impl = impl;
+ this.channel = channel;
+ }
+
+ public final PlainDatagramSocketImpl getPlainDatagramSocketImpl()
+ {
+ return impl;
+ }
+
+ public final DatagramChannel getChannel()
+ {
+ return channel;
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/NIOServerSocket.java b/libjava/classpath/gnu/java/nio/NIOServerSocket.java
new file mode 100644
index 0000000..fc4d0db
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/NIOServerSocket.java
@@ -0,0 +1,106 @@
+/* NIOServerSocket.java --
+ Copyright (C) 2003, 2004 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 gnu.java.nio;
+
+import gnu.java.net.PlainSocketImpl;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * @author Michael Koch (konqueror@gmx.de)
+ */
+public final class NIOServerSocket extends ServerSocket
+{
+ private ServerSocketChannelImpl channel;
+
+ protected NIOServerSocket (ServerSocketChannelImpl channel)
+ throws IOException
+ {
+ super();
+ this.channel = channel;
+ }
+
+ public PlainSocketImpl getPlainSocketImpl()
+ {
+ try
+ {
+ final Object t = this;
+ final Method method = ServerSocket.class.getDeclaredMethod("getImpl", new Class[0]);
+ method.setAccessible(true);
+ PrivilegedExceptionAction action = new PrivilegedExceptionAction()
+ {
+ public Object run() throws Exception
+ {
+ return method.invoke(t, new Object[0]);
+ }
+ };
+ return (PlainSocketImpl) AccessController.doPrivileged(action);
+ }
+ catch (Exception e)
+ {
+ // This should never happen.
+ Error error = new InternalError("unable to invoke method ServerSocket.getImpl()");
+ error.initCause(e);
+ throw error;
+ }
+ }
+
+ public ServerSocketChannel getChannel()
+ {
+ return channel;
+ }
+
+ public Socket accept() throws IOException
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkListen (getLocalPort());
+
+ SocketChannel socketChannel = channel.provider().openSocketChannel();
+ implAccept (socketChannel.socket());
+ return socketChannel.socket();
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/NIOSocket.java b/libjava/classpath/gnu/java/nio/NIOSocket.java
new file mode 100644
index 0000000..4d812bf
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/NIOSocket.java
@@ -0,0 +1,77 @@
+/* NIOSocket.java --
+ Copyright (C) 2003 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 gnu.java.nio;
+
+import gnu.java.net.PlainSocketImpl;
+import java.io.IOException;
+import java.net.Socket;
+import java.nio.channels.SocketChannel;
+
+/**
+ * @author Michael Koch
+ */
+public final class NIOSocket extends Socket
+{
+ private PlainSocketImpl impl;
+ private SocketChannelImpl channel;
+
+ protected NIOSocket (PlainSocketImpl impl, SocketChannelImpl channel)
+ throws IOException
+ {
+ super (impl);
+ this.impl = impl;
+ this.channel = channel;
+ }
+
+ public final PlainSocketImpl getPlainSocketImpl()
+ {
+ return impl;
+ }
+
+ final void setChannel (SocketChannelImpl channel)
+ {
+ this.impl = channel.getPlainSocketImpl();
+ this.channel = channel;
+ }
+
+ public final SocketChannel getChannel()
+ {
+ return channel;
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/OutputStreamChannel.java b/libjava/classpath/gnu/java/nio/OutputStreamChannel.java
new file mode 100644
index 0000000..8167426
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/OutputStreamChannel.java
@@ -0,0 +1,87 @@
+/* OutputStreamChannel.java --
+ Copyright (C) 2003 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 gnu.java.nio;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * @author Michael Koch
+ */
+public final class OutputStreamChannel implements WritableByteChannel
+{
+ private boolean closed = false;
+ private OutputStream out;
+
+ public OutputStreamChannel (OutputStream out)
+ {
+ super();
+
+ this.out = out;
+ }
+
+ public void close() throws IOException
+ {
+ if (!closed)
+ {
+ out.close();
+ closed = true;
+ }
+ }
+
+ public boolean isOpen()
+ {
+ return !closed;
+ }
+
+ public int write (ByteBuffer src) throws IOException
+ {
+ if (!isOpen())
+ throw new ClosedChannelException();
+
+ int len = src.remaining();
+ byte[] buffer = new byte [len];
+ src.get (buffer);
+ out.write (buffer);
+ return len;
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/PipeImpl.java b/libjava/classpath/gnu/java/nio/PipeImpl.java
new file mode 100644
index 0000000..f7b01c8
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/PipeImpl.java
@@ -0,0 +1,184 @@
+/* PipeImpl.java --
+ Copyright (C) 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 gnu.java.nio;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Pipe;
+import java.nio.channels.spi.SelectorProvider;
+
+class PipeImpl extends Pipe
+{
+ public static final class SourceChannelImpl extends Pipe.SourceChannel
+ {
+ private int native_fd;
+
+ public SourceChannelImpl (SelectorProvider selectorProvider,
+ int native_fd)
+ {
+ super (selectorProvider);
+ this.native_fd = native_fd;
+ }
+
+ protected final void implCloseSelectableChannel()
+ throws IOException
+ {
+ throw new Error ("Not implemented");
+ }
+
+ protected void implConfigureBlocking (boolean blocking)
+ throws IOException
+ {
+ throw new Error ("Not implemented");
+ }
+
+ public final int read (ByteBuffer src)
+ throws IOException
+ {
+ throw new Error ("Not implemented");
+ }
+
+ public final long read (ByteBuffer[] srcs)
+ throws IOException
+ {
+ return read (srcs, 0, srcs.length);
+ }
+
+ public final synchronized long read (ByteBuffer[] srcs, int offset,
+ int len)
+ throws IOException
+ {
+ if (offset < 0
+ || offset > srcs.length
+ || len < 0
+ || len > srcs.length - offset)
+ throw new IndexOutOfBoundsException();
+
+ long bytesRead = 0;
+
+ for (int index = 0; index < len; index++)
+ bytesRead += read (srcs [offset + index]);
+
+ return bytesRead;
+
+ }
+
+ public final int getNativeFD()
+ {
+ return native_fd;
+ }
+ }
+
+ public static final class SinkChannelImpl extends Pipe.SinkChannel
+ {
+ private int native_fd;
+
+ public SinkChannelImpl (SelectorProvider selectorProvider,
+ int native_fd)
+ {
+ super (selectorProvider);
+ this.native_fd = native_fd;
+ }
+
+ protected final void implCloseSelectableChannel()
+ throws IOException
+ {
+ throw new Error ("Not implemented");
+ }
+
+ protected final void implConfigureBlocking (boolean blocking)
+ throws IOException
+ {
+ throw new Error ("Not implemented");
+ }
+
+ public final int write (ByteBuffer dst)
+ throws IOException
+ {
+ throw new Error ("Not implemented");
+ }
+
+ public final long write (ByteBuffer[] srcs)
+ throws IOException
+ {
+ return write (srcs, 0, srcs.length);
+ }
+
+ public final synchronized long write (ByteBuffer[] srcs, int offset, int len)
+ throws IOException
+ {
+ if (offset < 0
+ || offset > srcs.length
+ || len < 0
+ || len > srcs.length - offset)
+ throw new IndexOutOfBoundsException();
+
+ long bytesWritten = 0;
+
+ for (int index = 0; index < len; index++)
+ bytesWritten += write (srcs [offset + index]);
+
+ return bytesWritten;
+ }
+
+ public final int getNativeFD()
+ {
+ return native_fd;
+ }
+ }
+
+ private SinkChannelImpl sink;
+ private SourceChannelImpl source;
+
+ public PipeImpl (SelectorProvider provider)
+ throws IOException
+ {
+ super();
+ VMPipe.init (this, provider);
+ }
+
+ public Pipe.SinkChannel sink()
+ {
+ return sink;
+ }
+
+ public Pipe.SourceChannel source()
+ {
+ return source;
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/SelectionKeyImpl.java b/libjava/classpath/gnu/java/nio/SelectionKeyImpl.java
new file mode 100644
index 0000000..a1f125e
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/SelectionKeyImpl.java
@@ -0,0 +1,104 @@
+/* SelectionKeyImpl.java --
+ Copyright (C) 2002, 2003 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 gnu.java.nio;
+
+import java.nio.channels.CancelledKeyException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectionKey;
+
+public abstract class SelectionKeyImpl extends AbstractSelectionKey
+{
+ private int readyOps;
+ private int interestOps;
+ private SelectorImpl impl;
+ SelectableChannel ch;
+
+ public SelectionKeyImpl (SelectableChannel ch, SelectorImpl impl)
+ {
+ this.ch = ch;
+ this.impl = impl;
+ }
+
+ public SelectableChannel channel ()
+ {
+ return ch;
+ }
+
+ public int readyOps ()
+ {
+ if (!isValid())
+ throw new CancelledKeyException();
+
+ return readyOps;
+ }
+
+ public SelectionKey readyOps (int ops)
+ {
+ if (!isValid())
+ throw new CancelledKeyException();
+
+ readyOps = ops;
+ return this;
+ }
+
+ public int interestOps ()
+ {
+ if (!isValid())
+ throw new CancelledKeyException();
+
+ return interestOps;
+ }
+
+ public SelectionKey interestOps (int ops)
+ {
+ if (!isValid())
+ throw new CancelledKeyException();
+
+ interestOps = ops;
+ return this;
+ }
+
+ public Selector selector ()
+ {
+ return impl;
+ }
+
+ public abstract int getNativeFD();
+}
diff --git a/libjava/classpath/gnu/java/nio/SelectorImpl.java b/libjava/classpath/gnu/java/nio/SelectorImpl.java
new file mode 100644
index 0000000..dcafede
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/SelectorImpl.java
@@ -0,0 +1,394 @@
+/* SelectorImpl.java --
+ Copyright (C) 2002, 2003, 2004 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 gnu.java.nio;
+
+import java.io.IOException;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.AbstractSelector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class SelectorImpl extends AbstractSelector
+{
+ private Set keys;
+ private Set selected;
+
+ /**
+ * A dummy object whose monitor regulates access to both our
+ * selectThread and unhandledWakeup fields.
+ */
+ private Object selectThreadMutex = new Object ();
+
+ /**
+ * Any thread that's currently blocked in a select operation.
+ */
+ private Thread selectThread;
+
+ /**
+ * Indicates whether we have an unhandled wakeup call. This can
+ * be due to either wakeup() triggering a thread interruption while
+ * a thread was blocked in a select operation (in which case we need
+ * to reset this thread's interrupt status after interrupting the
+ * select), or else that no thread was on a select operation at the
+ * time that wakeup() was called, in which case the following select()
+ * operation should return immediately with nothing selected.
+ */
+ private boolean unhandledWakeup;
+
+ public SelectorImpl (SelectorProvider provider)
+ {
+ super (provider);
+
+ keys = new HashSet ();
+ selected = new HashSet ();
+ }
+
+ protected void finalize() throws Throwable
+ {
+ close();
+ }
+
+ protected final void implCloseSelector()
+ throws IOException
+ {
+ // Cancel any pending select operation.
+ wakeup();
+
+ synchronized (keys)
+ {
+ synchronized (selected)
+ {
+ synchronized (cancelledKeys ())
+ {
+ // FIXME: Release resources here.
+ }
+ }
+ }
+ }
+
+ public final Set keys()
+ {
+ if (!isOpen())
+ throw new ClosedSelectorException();
+
+ return Collections.unmodifiableSet (keys);
+ }
+
+ public final int selectNow()
+ throws IOException
+ {
+ // FIXME: We're simulating an immediate select
+ // via a select with a timeout of one millisecond.
+ return select (1);
+ }
+
+ public final int select()
+ throws IOException
+ {
+ return select (0);
+ }
+
+ private final int[] getFDsAsArray (int ops)
+ {
+ int[] result;
+ int counter = 0;
+ Iterator it = keys.iterator ();
+
+ // Count the number of file descriptors needed
+ while (it.hasNext ())
+ {
+ SelectionKeyImpl key = (SelectionKeyImpl) it.next ();
+
+ if ((key.interestOps () & ops) != 0)
+ {
+ counter++;
+ }
+ }
+
+ result = new int[counter];
+
+ counter = 0;
+ it = keys.iterator ();
+
+ // Fill the array with the file descriptors
+ while (it.hasNext ())
+ {
+ SelectionKeyImpl key = (SelectionKeyImpl) it.next ();
+
+ if ((key.interestOps () & ops) != 0)
+ {
+ result[counter] = key.getNativeFD();
+ counter++;
+ }
+ }
+
+ return result;
+ }
+
+ public synchronized int select (long timeout)
+ throws IOException
+ {
+ if (!isOpen())
+ throw new ClosedSelectorException();
+
+ synchronized (keys)
+ {
+ synchronized (selected)
+ {
+ deregisterCancelledKeys();
+
+ // Set only keys with the needed interest ops into the arrays.
+ int[] read = getFDsAsArray (SelectionKey.OP_READ
+ | SelectionKey.OP_ACCEPT);
+ int[] write = getFDsAsArray (SelectionKey.OP_WRITE
+ | SelectionKey.OP_CONNECT);
+
+ // FIXME: We dont need to check this yet
+ int[] except = new int [0];
+
+ // Test to see if we've got an unhandled wakeup call,
+ // in which case we return immediately. Otherwise,
+ // remember our current thread and jump into the select.
+ // The monitor for dummy object selectThreadMutex regulates
+ // access to these fields.
+
+ // FIXME: Not sure from the spec at what point we should
+ // return "immediately". Is it here or immediately upon
+ // entry to this function?
+
+ // NOTE: There's a possibility of another thread calling
+ // wakeup() immediately after our thread releases
+ // selectThreadMutex's monitor here, in which case we'll
+ // do the select anyway. Since calls to wakeup() and select()
+ // among different threads happen in non-deterministic order,
+ // I don't think this is an issue.
+ synchronized (selectThreadMutex)
+ {
+ if (unhandledWakeup)
+ {
+ unhandledWakeup = false;
+ return 0;
+ }
+ else
+ {
+ selectThread = Thread.currentThread ();
+ }
+ }
+
+ // Call the native select() on all file descriptors.
+ int result = 0;
+ try
+ {
+ begin();
+ result = VMSelector.select (read, write, except, timeout);
+ }
+ finally
+ {
+ end();
+ }
+
+ // If our unhandled wakeup flag is set at this point,
+ // reset our thread's interrupt flag because we were
+ // awakened by wakeup() instead of an external thread
+ // interruption.
+ //
+ // NOTE: If we were blocked in a select() and one thread
+ // called Thread.interrupt() on the blocked thread followed
+ // by another thread calling Selector.wakeup(), then race
+ // conditions could make it so that the thread's interrupt
+ // flag is reset even though the Thread.interrupt() call
+ // "was there first". I don't think we need to care about
+ // this scenario.
+ synchronized (selectThreadMutex)
+ {
+ if (unhandledWakeup)
+ {
+ unhandledWakeup = false;
+ Thread.interrupted ();
+ }
+ selectThread = null;
+ }
+
+ Iterator it = keys.iterator ();
+
+ while (it.hasNext ())
+ {
+ int ops = 0;
+ SelectionKeyImpl key = (SelectionKeyImpl) it.next ();
+
+ // If key is already selected retrieve old ready ops.
+ if (selected.contains (key))
+ {
+ ops = key.readyOps ();
+ }
+
+ // Set new ready read/accept ops
+ for (int i = 0; i < read.length; i++)
+ {
+ if (key.getNativeFD() == read[i])
+ {
+ if (key.channel () instanceof ServerSocketChannelImpl)
+ {
+ ops = ops | SelectionKey.OP_ACCEPT;
+ }
+ else
+ {
+ ops = ops | SelectionKey.OP_READ;
+ }
+ }
+ }
+
+ // Set new ready write ops
+ for (int i = 0; i < write.length; i++)
+ {
+ if (key.getNativeFD() == write[i])
+ {
+ ops = ops | SelectionKey.OP_WRITE;
+
+ // if (key.channel ().isConnected ())
+ // {
+ // ops = ops | SelectionKey.OP_WRITE;
+ // }
+ // else
+ // {
+ // ops = ops | SelectionKey.OP_CONNECT;
+ // }
+ }
+ }
+
+ // FIXME: We dont handle exceptional file descriptors yet.
+
+ // If key is not yet selected add it.
+ if (!selected.contains (key))
+ {
+ selected.add (key);
+ }
+
+ // Set new ready ops
+ key.readyOps (key.interestOps () & ops);
+ }
+ deregisterCancelledKeys();
+
+ return result;
+ }
+ }
+ }
+
+ public final Set selectedKeys()
+ {
+ if (!isOpen())
+ throw new ClosedSelectorException();
+
+ return selected;
+ }
+
+ public final Selector wakeup()
+ {
+ // IMPLEMENTATION NOTE: Whereas the specification says that
+ // thread interruption should trigger a call to wakeup, we
+ // do the reverse under the covers: wakeup triggers a thread
+ // interrupt followed by a subsequent reset of the thread's
+ // interrupt status within select().
+
+ // First, acquire the monitor of the object regulating
+ // access to our selectThread and unhandledWakeup fields.
+ synchronized (selectThreadMutex)
+ {
+ unhandledWakeup = true;
+
+ // Interrupt any thread which is currently blocked in
+ // a select operation.
+ if (selectThread != null)
+ selectThread.interrupt ();
+ }
+
+ return this;
+ }
+
+ private final void deregisterCancelledKeys()
+ {
+ Set ckeys = cancelledKeys ();
+ synchronized (ckeys)
+ {
+ Iterator it = ckeys.iterator();
+
+ while (it.hasNext ())
+ {
+ keys.remove ((SelectionKeyImpl) it.next ());
+ it.remove ();
+ }
+ }
+ }
+
+ protected SelectionKey register (SelectableChannel ch, int ops, Object att)
+ {
+ return register ((AbstractSelectableChannel) ch, ops, att);
+ }
+
+ protected final SelectionKey register (AbstractSelectableChannel ch, int ops,
+ Object att)
+ {
+ SelectionKeyImpl result;
+
+ if (ch instanceof SocketChannelImpl)
+ result = new SocketChannelSelectionKey (ch, this);
+ else if (ch instanceof DatagramChannelImpl)
+ result = new DatagramChannelSelectionKey (ch, this);
+ else if (ch instanceof ServerSocketChannelImpl)
+ result = new ServerSocketChannelSelectionKey (ch, this);
+ else
+ throw new InternalError ("No known channel type");
+
+ synchronized (keys)
+ {
+ keys.add (result);
+ }
+
+ result.interestOps (ops);
+ result.attach (att);
+ return result;
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java b/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java
new file mode 100644
index 0000000..4752110
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java
@@ -0,0 +1,83 @@
+/* SelectorProviderImpl.java --
+ Copyright (C) 2002, 2003 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 gnu.java.nio;
+
+import java.io.IOException;
+import java.nio.channels.DatagramChannel;
+import java.nio.channels.Pipe;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.AbstractSelector;
+import java.nio.channels.spi.SelectorProvider;
+
+public class SelectorProviderImpl extends SelectorProvider
+{
+ public SelectorProviderImpl ()
+ {
+ }
+
+ public DatagramChannel openDatagramChannel ()
+ throws IOException
+ {
+ return new DatagramChannelImpl (this);
+ }
+
+ public Pipe openPipe ()
+ throws IOException
+ {
+ return new PipeImpl (this);
+ }
+
+ public AbstractSelector openSelector ()
+ throws IOException
+ {
+ return new SelectorImpl (this);
+ }
+
+ public ServerSocketChannel openServerSocketChannel ()
+ throws IOException
+ {
+ return new ServerSocketChannelImpl (this);
+ }
+
+ public SocketChannel openSocketChannel ()
+ throws IOException
+ {
+ return new SocketChannelImpl (this);
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java b/libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java
new file mode 100644
index 0000000..c538ea8
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java
@@ -0,0 +1,124 @@
+/* ServerSocketChannelImpl.java --
+ Copyright (C) 2002, 2003, 2004 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 gnu.java.nio;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.SocketTimeoutException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.NotYetBoundException;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.spi.SelectorProvider;
+
+public final class ServerSocketChannelImpl extends ServerSocketChannel
+{
+ private NIOServerSocket serverSocket;
+ private boolean connected;
+
+ protected ServerSocketChannelImpl (SelectorProvider provider)
+ throws IOException
+ {
+ super (provider);
+ serverSocket = new NIOServerSocket (this);
+ configureBlocking(true);
+ }
+
+ public void finalizer()
+ {
+ if (connected)
+ {
+ try
+ {
+ close ();
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ }
+
+ protected void implCloseSelectableChannel () throws IOException
+ {
+ connected = false;
+ serverSocket.close();
+ }
+
+ protected void implConfigureBlocking (boolean blocking) throws IOException
+ {
+ serverSocket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+ }
+
+ public SocketChannel accept () throws IOException
+ {
+ if (!isOpen())
+ throw new ClosedChannelException();
+
+ if (!serverSocket.isBound())
+ throw new NotYetBoundException();
+
+ boolean completed = false;
+
+ try
+ {
+ begin();
+ serverSocket.getPlainSocketImpl().setInChannelOperation(true);
+ // indicate that a channel is initiating the accept operation
+ // so that the socket ignores the fact that we might be in
+ // non-blocking mode.
+ NIOSocket socket = (NIOSocket) serverSocket.accept();
+ completed = true;
+ return socket.getChannel();
+ }
+ catch (SocketTimeoutException e)
+ {
+ return null;
+ }
+ finally
+ {
+ serverSocket.getPlainSocketImpl().setInChannelOperation(false);
+ end (completed);
+ }
+ }
+
+ public ServerSocket socket ()
+ {
+ return serverSocket;
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java b/libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java
new file mode 100644
index 0000000..d00c2b7
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java
@@ -0,0 +1,58 @@
+/* ServerSocketChannelSelectionKey.java --
+ Copyright (C) 2003 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 gnu.java.nio;
+
+import java.nio.channels.spi.AbstractSelectableChannel;
+
+public final class ServerSocketChannelSelectionKey
+ extends SelectionKeyImpl
+{
+ public ServerSocketChannelSelectionKey (AbstractSelectableChannel channel,
+ SelectorImpl selector)
+ {
+ super (channel, selector);
+ }
+
+ public int getNativeFD()
+ {
+ NIOServerSocket socket =
+ (NIOServerSocket) ((ServerSocketChannelImpl) ch).socket();
+ return socket.getPlainSocketImpl().getNativeFD();
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/SocketChannelImpl.java b/libjava/classpath/gnu/java/nio/SocketChannelImpl.java
new file mode 100644
index 0000000..9fb71c1
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/SocketChannelImpl.java
@@ -0,0 +1,351 @@
+/* SocketChannelImpl.java --
+ Copyright (C) 2002, 2003, 2004 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 gnu.java.nio;
+
+import gnu.java.net.PlainSocketImpl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketTimeoutException;
+import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyConnectedException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ConnectionPendingException;
+import java.nio.channels.NoConnectionPendingException;
+import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.UnresolvedAddressException;
+import java.nio.channels.UnsupportedAddressTypeException;
+import java.nio.channels.spi.SelectorProvider;
+
+public final class SocketChannelImpl extends SocketChannel
+{
+ private PlainSocketImpl impl;
+ private NIOSocket socket;
+ private boolean connectionPending;
+
+ SocketChannelImpl (SelectorProvider provider)
+ throws IOException
+ {
+ super (provider);
+ impl = new PlainSocketImpl();
+ socket = new NIOSocket (impl, this);
+ configureBlocking(true);
+ }
+
+ SocketChannelImpl (SelectorProvider provider,
+ NIOSocket socket)
+ throws IOException
+ {
+ super (provider);
+ this.impl = socket.getPlainSocketImpl();
+ this.socket = socket;
+ }
+
+ public void finalizer()
+ {
+ if (isConnected())
+ {
+ try
+ {
+ close ();
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ }
+
+ PlainSocketImpl getPlainSocketImpl()
+ {
+ return impl;
+ }
+
+ protected void implCloseSelectableChannel () throws IOException
+ {
+ socket.close();
+ }
+
+ protected void implConfigureBlocking (boolean blocking) throws IOException
+ {
+ socket.setSoTimeout (blocking ? 0 : NIOConstants.DEFAULT_TIMEOUT);
+ }
+
+ public boolean connect (SocketAddress remote) throws IOException
+ {
+ if (!isOpen())
+ throw new ClosedChannelException();
+
+ if (isConnected())
+ throw new AlreadyConnectedException();
+
+ if (connectionPending)
+ throw new ConnectionPendingException();
+
+ if (!(remote instanceof InetSocketAddress))
+ throw new UnsupportedAddressTypeException();
+
+ if (((InetSocketAddress) remote).isUnresolved())
+ throw new UnresolvedAddressException();
+
+ try
+ {
+ socket.getPlainSocketImpl().setInChannelOperation(true);
+ // indicate that a channel is initiating the accept operation
+ // so that the socket ignores the fact that we might be in
+ // non-blocking mode.
+
+ if (isBlocking())
+ {
+ // Do blocking connect.
+ socket.connect (remote);
+ return true;
+ }
+
+ // Do non-blocking connect.
+ try
+ {
+ socket.connect (remote, NIOConstants.DEFAULT_TIMEOUT);
+ return true;
+ }
+ catch (SocketTimeoutException e)
+ {
+ connectionPending = true;
+ return false;
+ }
+ }
+ finally
+ {
+ socket.getPlainSocketImpl().setInChannelOperation(false);
+ }
+ }
+
+ public boolean finishConnect ()
+ throws IOException
+ {
+ if (!isOpen())
+ throw new ClosedChannelException();
+
+ if (!isConnected() && !connectionPending)
+ throw new NoConnectionPendingException();
+
+ if (isConnected())
+ return true;
+
+ // FIXME: Handle blocking/non-blocking mode.
+
+ Selector selector = provider().openSelector();
+ register(selector, SelectionKey.OP_CONNECT);
+
+ if (isBlocking())
+ {
+ selector.select(); // blocking until channel is connected.
+ connectionPending = false;
+ return true;
+ }
+
+ int ready = selector.selectNow(); // non-blocking
+ if (ready == 1)
+ {
+ connectionPending = false;
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean isConnected ()
+ {
+ return socket.isConnected();
+ }
+
+ public boolean isConnectionPending ()
+ {
+ return connectionPending;
+ }
+
+ public Socket socket ()
+ {
+ return socket;
+ }
+
+ public int read(ByteBuffer dst) throws IOException
+ {
+ if (!isConnected())
+ throw new NotYetConnectedException();
+
+ byte[] data;
+ int offset = 0;
+ InputStream input = socket.getInputStream();
+ int available = input.available();
+ int len = dst.capacity() - dst.position();
+
+ if ((! isBlocking()) && available == 0)
+ return 0;
+
+ if (dst.hasArray())
+ {
+ offset = dst.arrayOffset() + dst.position();
+ data = dst.array();
+ }
+ else
+ {
+ data = new byte [len];
+ }
+
+ int readBytes = 0;
+ boolean completed = false;
+
+ try
+ {
+ begin();
+ socket.getPlainSocketImpl().setInChannelOperation(true);
+ readBytes = input.read (data, offset, len);
+ completed = true;
+ }
+ finally
+ {
+ end (completed);
+ socket.getPlainSocketImpl().setInChannelOperation(false);
+ }
+
+ if (readBytes > 0)
+ if (dst.hasArray())
+ {
+ dst.position (dst.position() + readBytes);
+ }
+ else
+ {
+ dst.put (data, offset, len);
+ }
+
+ return readBytes;
+ }
+
+ public long read (ByteBuffer[] dsts, int offset, int length)
+ throws IOException
+ {
+ if (!isConnected())
+ throw new NotYetConnectedException();
+
+ if ((offset < 0)
+ || (offset > dsts.length)
+ || (length < 0)
+ || (length > (dsts.length - offset)))
+ throw new IndexOutOfBoundsException();
+
+ long readBytes = 0;
+
+ for (int index = offset; index < length; index++)
+ readBytes += read (dsts [index]);
+
+ return readBytes;
+ }
+
+ public int write (ByteBuffer src)
+ throws IOException
+ {
+ if (!isConnected())
+ throw new NotYetConnectedException();
+
+ byte[] data;
+ int offset = 0;
+ int len = src.remaining();
+
+ if (!src.hasArray())
+ {
+ data = new byte [len];
+ src.get (data, 0, len);
+ }
+ else
+ {
+ offset = src.arrayOffset() + src.position();
+ data = src.array();
+ }
+
+ OutputStream output = socket.getOutputStream();
+ boolean completed = false;
+
+ try
+ {
+ begin();
+ socket.getPlainSocketImpl().setInChannelOperation(true);
+ output.write (data, offset, len);
+ completed = true;
+ }
+ finally
+ {
+ end (completed);
+ socket.getPlainSocketImpl().setInChannelOperation(false);
+ }
+
+ if (src.hasArray())
+ {
+ src.position (src.position() + len);
+ }
+
+ return len;
+ }
+
+ public long write (ByteBuffer[] srcs, int offset, int length)
+ throws IOException
+ {
+ if (!isConnected())
+ throw new NotYetConnectedException();
+
+ if ((offset < 0)
+ || (offset > srcs.length)
+ || (length < 0)
+ || (length > (srcs.length - offset)))
+ throw new IndexOutOfBoundsException();
+
+ long writtenBytes = 0;
+
+ for (int index = offset; index < length; index++)
+ writtenBytes += write (srcs [index]);
+
+ return writtenBytes;
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java b/libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java
new file mode 100644
index 0000000..75b4dfd
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java
@@ -0,0 +1,58 @@
+/* SocketChannelSelectionKey.java --
+ Copyright (C) 2003 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 gnu.java.nio;
+
+import java.nio.channels.spi.AbstractSelectableChannel;
+
+public final class SocketChannelSelectionKey
+ extends SelectionKeyImpl
+{
+ public SocketChannelSelectionKey (AbstractSelectableChannel channel,
+ SelectorImpl selector)
+ {
+ super (channel, selector);
+ }
+
+ public int getNativeFD()
+ {
+ NIOSocket socket =
+ (NIOSocket) ((SocketChannelImpl) ch).socket();
+ return socket.getPlainSocketImpl().getNativeFD();
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/channels/FileChannelImpl.java b/libjava/classpath/gnu/java/nio/channels/FileChannelImpl.java
new file mode 100644
index 0000000..a87a2e8
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/channels/FileChannelImpl.java
@@ -0,0 +1,535 @@
+/* FileChannelImpl.java --
+ Copyright (C) 2002, 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 gnu.java.nio.channels;
+
+import gnu.classpath.Configuration;
+import gnu.java.nio.FileLockImpl;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.NonReadableChannelException;
+import java.nio.channels.NonWritableChannelException;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * This file is not user visible !
+ * But alas, Java does not have a concept of friendly packages
+ * so this class is public.
+ * Instances of this class are created by invoking getChannel
+ * Upon a Input/Output/RandomAccessFile object.
+ */
+public final class FileChannelImpl extends FileChannel
+{
+ // These are mode values for open().
+ public static final int READ = 1;
+ public static final int WRITE = 2;
+ public static final int APPEND = 4;
+
+ // EXCL is used only when making a temp file.
+ public static final int EXCL = 8;
+ public static final int SYNC = 16;
+ public static final int DSYNC = 32;
+
+ private static native void init();
+
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary("javanio");
+ }
+
+ init();
+ }
+
+ /**
+ * This is the actual native file descriptor value
+ */
+ // System's notion of file descriptor. It might seem redundant to
+ // initialize this given that it is reassigned in the constructors.
+ // However, this is necessary because if open() throws an exception
+ // we want to make sure this has the value -1. This is the most
+ // efficient way to accomplish that.
+ private int fd = -1;
+
+ private int mode;
+
+ /* Open a file. MODE is a combination of the above mode flags. */
+ /* This is a static factory method, so that VM implementors can decide
+ * substitute subclasses of FileChannelImpl. */
+ public static FileChannelImpl create(File file, int mode)
+ throws FileNotFoundException
+ {
+ return new FileChannelImpl(file, mode);
+ }
+
+ private FileChannelImpl(File file, int mode)
+ throws FileNotFoundException
+ {
+ final String path = file.getPath();
+ fd = open (path, mode);
+ this.mode = mode;
+
+ // First open the file and then check if it is a a directory
+ // to avoid race condition.
+ if (file.isDirectory())
+ {
+ try
+ {
+ close();
+ }
+ catch (IOException e)
+ {
+ /* ignore it */
+ }
+
+ throw new FileNotFoundException(path + " is a directory");
+ }
+ }
+
+ /* Used by init() (native code) */
+ FileChannelImpl (int fd, int mode)
+ {
+ this.fd = fd;
+ this.mode = mode;
+ }
+
+ public static FileChannelImpl in;
+ public static FileChannelImpl out;
+ public static FileChannelImpl err;
+
+ private native int open (String path, int mode) throws FileNotFoundException;
+
+ public native int available () throws IOException;
+ private native long implPosition () throws IOException;
+ private native void seek (long newPosition) throws IOException;
+ private native void implTruncate (long size) throws IOException;
+
+ public native void unlock (long pos, long len) throws IOException;
+
+ public native long size () throws IOException;
+
+ protected native void implCloseChannel() throws IOException;
+
+ /**
+ * Makes sure the Channel is properly closed.
+ */
+ protected void finalize() throws IOException
+ {
+ this.close();
+ }
+
+ public int read (ByteBuffer dst) throws IOException
+ {
+ int result;
+ byte[] buffer = new byte [dst.remaining ()];
+
+ result = read (buffer, 0, buffer.length);
+
+ if (result > 0)
+ dst.put (buffer, 0, result);
+
+ return result;
+ }
+
+ public int read (ByteBuffer dst, long position)
+ throws IOException
+ {
+ if (position < 0)
+ throw new IllegalArgumentException ();
+ long oldPosition = implPosition ();
+ position (position);
+ int result = read(dst);
+ position (oldPosition);
+
+ return result;
+ }
+
+ public native int read ()
+ throws IOException;
+
+ public native int read (byte[] buffer, int offset, int length)
+ throws IOException;
+
+ public long read (ByteBuffer[] dsts, int offset, int length)
+ throws IOException
+ {
+ long result = 0;
+
+ for (int i = offset; i < offset + length; i++)
+ {
+ result += read (dsts [i]);
+ }
+
+ return result;
+ }
+
+ public int write (ByteBuffer src) throws IOException
+ {
+ int len = src.remaining ();
+ if (src.hasArray())
+ {
+ byte[] buffer = src.array();
+ write(buffer, src.arrayOffset() + src.position(), len);
+ src.position(src.position() + len);
+ }
+ else
+ {
+ // Use a more efficient native method! FIXME!
+ byte[] buffer = new byte [len];
+ src.get (buffer, 0, len);
+ write (buffer, 0, len);
+ }
+ return len;
+ }
+
+ public int write (ByteBuffer src, long position)
+ throws IOException
+ {
+ if (position < 0)
+ throw new IllegalArgumentException ();
+
+ if (!isOpen ())
+ throw new ClosedChannelException ();
+
+ if ((mode & WRITE) == 0)
+ throw new NonWritableChannelException ();
+
+ int result;
+ long oldPosition;
+
+ oldPosition = implPosition ();
+ seek (position);
+ result = write(src);
+ seek (oldPosition);
+
+ return result;
+ }
+
+ public native void write (byte[] buffer, int offset, int length)
+ throws IOException;
+
+ public native void write (int b) throws IOException;
+
+ public long write(ByteBuffer[] srcs, int offset, int length)
+ throws IOException
+ {
+ long result = 0;
+
+ for (int i = offset;i < offset + length;i++)
+ {
+ result += write (srcs[i]);
+ }
+
+ return result;
+ }
+
+ public native MappedByteBuffer mapImpl (char mode, long position, int size)
+ throws IOException;
+
+ public MappedByteBuffer map (FileChannel.MapMode mode,
+ long position, long size)
+ throws IOException
+ {
+ char nmode = 0;
+ if (mode == MapMode.READ_ONLY)
+ {
+ nmode = 'r';
+ if ((this.mode & READ) == 0)
+ throw new NonReadableChannelException();
+ }
+ else if (mode == MapMode.READ_WRITE || mode == MapMode.PRIVATE)
+ {
+ nmode = mode == MapMode.READ_WRITE ? '+' : 'c';
+ if ((this.mode & (READ|WRITE)) != (READ|WRITE))
+ throw new NonWritableChannelException();
+ }
+ else
+ throw new IllegalArgumentException ();
+
+ if (position < 0 || size < 0 || size > Integer.MAX_VALUE)
+ throw new IllegalArgumentException ();
+ return mapImpl(nmode, position, (int) size);
+ }
+
+ /**
+ * msync with the disk
+ */
+ public void force (boolean metaData) throws IOException
+ {
+ if (!isOpen ())
+ throw new ClosedChannelException ();
+
+ force ();
+ }
+
+ private native void force ();
+
+ // like transferTo, but with a count of less than 2Gbytes
+ private int smallTransferTo (long position, int count,
+ WritableByteChannel target)
+ throws IOException
+ {
+ ByteBuffer buffer;
+ try
+ {
+ // Try to use a mapped buffer if we can. If this fails for
+ // any reason we'll fall back to using a ByteBuffer.
+ buffer = map (MapMode.READ_ONLY, position, count);
+ }
+ catch (IOException e)
+ {
+ buffer = ByteBuffer.allocate (count);
+ read (buffer, position);
+ buffer.flip();
+ }
+
+ return target.write (buffer);
+ }
+
+ public long transferTo (long position, long count,
+ WritableByteChannel target)
+ throws IOException
+ {
+ if (position < 0
+ || count < 0)
+ throw new IllegalArgumentException ();
+
+ if (!isOpen ())
+ throw new ClosedChannelException ();
+
+ if ((mode & READ) == 0)
+ throw new NonReadableChannelException ();
+
+ final int pageSize = 65536;
+ long total = 0;
+
+ while (count > 0)
+ {
+ int transferred
+ = smallTransferTo (position, (int)Math.min (count, pageSize),
+ target);
+ if (transferred < 0)
+ break;
+ total += transferred;
+ position += transferred;
+ count -= transferred;
+ }
+
+ return total;
+ }
+
+ // like transferFrom, but with a count of less than 2Gbytes
+ private int smallTransferFrom (ReadableByteChannel src, long position,
+ int count)
+ throws IOException
+ {
+ ByteBuffer buffer = null;
+
+ if (src instanceof FileChannel)
+ {
+ try
+ {
+ // Try to use a mapped buffer if we can. If this fails
+ // for any reason we'll fall back to using a ByteBuffer.
+ buffer = ((FileChannel)src).map (MapMode.READ_ONLY, position,
+ count);
+ }
+ catch (IOException e)
+ {
+ }
+ }
+
+ if (buffer == null)
+ {
+ buffer = ByteBuffer.allocate ((int) count);
+ src.read (buffer);
+ buffer.flip();
+ }
+
+ return write (buffer, position);
+ }
+
+ public long transferFrom (ReadableByteChannel src, long position,
+ long count)
+ throws IOException
+ {
+ if (position < 0
+ || count < 0)
+ throw new IllegalArgumentException ();
+
+ if (!isOpen ())
+ throw new ClosedChannelException ();
+
+ if ((mode & WRITE) == 0)
+ throw new NonWritableChannelException ();
+
+ final int pageSize = 65536;
+ long total = 0;
+
+ while (count > 0)
+ {
+ int transferred = smallTransferFrom (src, position,
+ (int)Math.min (count, pageSize));
+ if (transferred < 0)
+ break;
+ total += transferred;
+ position += transferred;
+ count -= transferred;
+ }
+
+ return total;
+ }
+
+ public FileLock tryLock (long position, long size, boolean shared)
+ throws IOException
+ {
+ if (position < 0
+ || size < 0)
+ throw new IllegalArgumentException ();
+
+ if (!isOpen ())
+ throw new ClosedChannelException ();
+
+ if (shared && (mode & READ) == 0)
+ throw new NonReadableChannelException ();
+
+ if (!shared && (mode & WRITE) == 0)
+ throw new NonWritableChannelException ();
+
+ boolean completed = false;
+
+ try
+ {
+ begin();
+ boolean lockable = lock(position, size, shared, false);
+ completed = true;
+ return (lockable
+ ? new FileLockImpl(this, position, size, shared)
+ : null);
+ }
+ finally
+ {
+ end(completed);
+ }
+ }
+
+ /** Try to acquire a lock at the given position and size.
+ * On success return true.
+ * If wait as specified, block until we can get it.
+ * Otherwise return false.
+ */
+ private native boolean lock(long position, long size,
+ boolean shared, boolean wait) throws IOException;
+
+ public FileLock lock (long position, long size, boolean shared)
+ throws IOException
+ {
+ if (position < 0
+ || size < 0)
+ throw new IllegalArgumentException ();
+
+ if (!isOpen ())
+ throw new ClosedChannelException ();
+
+ boolean completed = false;
+
+ try
+ {
+ boolean lockable = lock(position, size, shared, true);
+ completed = true;
+ return (lockable
+ ? new FileLockImpl(this, position, size, shared)
+ : null);
+ }
+ finally
+ {
+ end(completed);
+ }
+ }
+
+ public long position ()
+ throws IOException
+ {
+ if (!isOpen ())
+ throw new ClosedChannelException ();
+
+ return implPosition ();
+ }
+
+ public FileChannel position (long newPosition)
+ throws IOException
+ {
+ if (newPosition < 0)
+ throw new IllegalArgumentException ();
+
+ if (!isOpen ())
+ throw new ClosedChannelException ();
+
+ // FIXME note semantics if seeking beyond eof.
+ // We should seek lazily - only on a write.
+ seek (newPosition);
+ return this;
+ }
+
+ public FileChannel truncate (long size)
+ throws IOException
+ {
+ if (size < 0)
+ throw new IllegalArgumentException ();
+
+ if (!isOpen ())
+ throw new ClosedChannelException ();
+
+ if ((mode & WRITE) == 0)
+ throw new NonWritableChannelException ();
+
+ if (size < size ())
+ implTruncate (size);
+
+ return this;
+ }
+}
diff --git a/libjava/classpath/gnu/java/nio/channels/package.html b/libjava/classpath/gnu/java/nio/channels/package.html
new file mode 100644
index 0000000..0c3821b
--- /dev/null
+++ b/libjava/classpath/gnu/java/nio/channels/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+The lookup is therefore case-insensitive.
+ * + * @returns The Charset havingcharsetName
+ * as its alias or null if no such Charset exist.
+ */
+ public Charset charsetForName (String charsetName)
+ {
+ Charset cs = (Charset) charsets.get(canonicalNames.get(charsetName.toLowerCase()));
+ if(cs == null && !extendedLoaded)
+ {
+ loadExtended();
+ cs = (Charset) charsets.get(canonicalNames.get(charsetName.toLowerCase()));
+ }
+ return cs;
+ }
+
+ /**
+ * Puts a Charset under its canonical name into the 'charsets' map.
+ * Then puts a mapping from all its alias names to the canonical name.
+ *
+ * All names are converted to lower-case
. + * + * @param cs + */ + private void addCharset (Charset cs) + { + String canonicalName = cs.name().toLowerCase(); + charsets.put (canonicalName, cs); + + /* Adds a mapping between the canonical name + * itself making a lookup using that name + * no special case. + */ + canonicalNames.put(canonicalName, canonicalName); + + for (Iterator i = cs.aliases ().iterator (); i.hasNext (); ) + canonicalNames.put (((String) i.next()).toLowerCase(), canonicalName); + } + + public static synchronized Provider provider () + { + if (singleton == null) + singleton = new Provider (); + return singleton; + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/US_ASCII.java b/libjava/classpath/gnu/java/nio/charset/US_ASCII.java new file mode 100644 index 0000000..d26f7ff --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/US_ASCII.java @@ -0,0 +1,161 @@ +/* US_ASCII.java -- + Copyright (C) 2002, 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 gnu.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * US-ASCII charset. + * + * @author Jesse Rosenstock + */ +final class US_ASCII extends Charset +{ + US_ASCII () + { + /* Canonical charset name chosen according to: + * http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html + */ + super ("US-ASCII", new String[] { + /* These names are provided by + * http://www.iana.org/assignments/character-sets + */ + "iso-ir-6", + "ANSI_X3.4-1986", + "ISO_646.irv:1991", + "ASCII", + "ISO646-US", + "ASCII", + "us", + "IBM367", + "cp367", + "csASCII", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "ANSI_X3.4-1968", "iso_646.irv:1983", "ascii7", "646", + "windows-20127" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII; + } + + public CharsetDecoder newDecoder () + { + return new Decoder (this); + } + + public CharsetEncoder newEncoder () + { + return new Encoder (this); + } + + private static final class Decoder extends CharsetDecoder + { + // Package-private to avoid a trampoline constructor. + Decoder (Charset cs) + { + super (cs, 1.0f, 1.0f); + } + + protected CoderResult decodeLoop (ByteBuffer in, CharBuffer out) + { + // TODO: Optimize this in the case in.hasArray() / out.hasArray() + while (in.hasRemaining ()) + { + byte b = in.get (); + + if (b < 0) + { + in.position (in.position () - 1); + return CoderResult.malformedForLength (1); + } + if (!out.hasRemaining ()) + { + in.position (in.position () - 1); + return CoderResult.OVERFLOW; + } + + out.put ((char) b); + } + + return CoderResult.UNDERFLOW; + } + } + + private static final class Encoder extends CharsetEncoder + { + // Package-private to avoid a trampoline constructor. + Encoder (Charset cs) + { + super (cs, 1.0f, 1.0f); + } + + protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out) + { + // TODO: Optimize this in the case in.hasArray() / out.hasArray() + while (in.hasRemaining ()) + { + char c = in.get (); + + if (c > Byte.MAX_VALUE) + { + in.position (in.position () - 1); + return CoderResult.unmappableForLength (1); + } + if (!out.hasRemaining ()) + { + in.position (in.position () - 1); + return CoderResult.OVERFLOW; + } + + out.put ((byte) c); + } + + return CoderResult.UNDERFLOW; + } + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16.java b/libjava/classpath/gnu/java/nio/charset/UTF_16.java new file mode 100644 index 0000000..b1d7705 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16.java @@ -0,0 +1,80 @@ +/* UTF_16.java -- + Copyright (C) 2002, 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 gnu.java.nio.charset; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +/** + * UTF-16 charset. + * + * @author Jesse Rosenstock + */ +final class UTF_16 extends Charset +{ + UTF_16 () + { + super ("UTF-16", new String[] { + // witnessed by the internet + "UTF16", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "ISO-10646-UCS-2", "unicode", "csUnicode", "ucs-2", "UnicodeBig" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1 + || cs instanceof UTF_8 || cs instanceof UTF_16BE + || cs instanceof UTF_16LE || cs instanceof UTF_16; + } + + public CharsetDecoder newDecoder () + { + return new UTF_16Decoder (this, UTF_16Decoder.UNKNOWN_ENDIAN); + } + + public CharsetEncoder newEncoder () + { + return new UTF_16Encoder (this, UTF_16Encoder.BIG_ENDIAN, true); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16BE.java b/libjava/classpath/gnu/java/nio/charset/UTF_16BE.java new file mode 100644 index 0000000..1fe3b5d --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16BE.java @@ -0,0 +1,84 @@ +/* UTF_16BE.java -- + Copyright (C) 2002, 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 gnu.java.nio.charset; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +/** + * UTF-16BE charset. + * + * @author Jesse Rosenstock + */ +final class UTF_16BE extends Charset +{ + UTF_16BE () + { + super ("UTF-16BE", new String[] { + // witnessed by the internet + "UTF16BE", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "x-utf-16be", "ibm-1200", "ibm-1201", "ibm-5297", + "ibm-13488", "ibm-17584", "windows-1201", "cp1200", "cp1201", + "UTF16_BigEndian", + // see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html + "UnicodeBigUnmarked" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1 + || cs instanceof UTF_8 || cs instanceof UTF_16BE + || cs instanceof UTF_16LE || cs instanceof UTF_16; + } + + public CharsetDecoder newDecoder () + { + return new UTF_16Decoder (this, UTF_16Decoder.BIG_ENDIAN); + } + + public CharsetEncoder newEncoder () + { + return new UTF_16Encoder (this, UTF_16Encoder.BIG_ENDIAN, false); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java b/libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java new file mode 100644 index 0000000..302c83e --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java @@ -0,0 +1,152 @@ +/* UTF_16Decoder.java -- + Copyright (C) 2002 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 gnu.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; + +/** + * Decoder for UTF-16, UTF-15LE, and UTF-16BE. + * + * @author Jesse Rosenstock + */ +final class UTF_16Decoder extends CharsetDecoder +{ + // byte orders + static final int BIG_ENDIAN = 0; + static final int LITTLE_ENDIAN = 1; + static final int UNKNOWN_ENDIAN = 2; + + private static final char BYTE_ORDER_MARK = 0xFEFF; + private static final char REVERSED_BYTE_ORDER_MARK = 0xFFFE; + + private final int originalByteOrder; + private int byteOrder; + + UTF_16Decoder (Charset cs, int byteOrder) + { + super (cs, 0.5f, 1.0f); + this.originalByteOrder = byteOrder; + this.byteOrder = byteOrder; + } + + protected CoderResult decodeLoop (ByteBuffer in, CharBuffer out) + { + // TODO: Optimize this in the case in.hasArray() / out.hasArray() + + int inPos = in.position (); + try + { + while (in.remaining () >= 2) + { + byte b1 = in.get (); + byte b2 = in.get (); + + // handle byte order mark + if (byteOrder == UNKNOWN_ENDIAN) + { + char c = (char) (((b1 & 0xFF) << 8) | (b2 & 0xFF)); + if (c == BYTE_ORDER_MARK) + { + byteOrder = BIG_ENDIAN; + inPos += 2; + continue; + } + else if (c == REVERSED_BYTE_ORDER_MARK) + { + byteOrder = LITTLE_ENDIAN; + inPos += 2; + continue; + } + else + { + // assume big endian, do not consume bytes, + // continue with normal processing + byteOrder = BIG_ENDIAN; + } + } + + // FIXME: Change so you only do a single comparison here. + char c = byteOrder == BIG_ENDIAN ? (char) ((b1 << 8) | b2) + : (char) ((b2 << 8) | b1); + + if (0xD800 <= c && c <= 0xDFFF) + { + // c is a surrogate + + // make sure c is a high surrogate + if (c > 0xDBFF) + return CoderResult.malformedForLength (2); + if (in.remaining () < 2) + return CoderResult.UNDERFLOW; + byte b3 = in.get (); + byte b4 = in.get (); + char d = byteOrder == BIG_ENDIAN ? (char) ((b3 << 8) | b4) + : (char) ((b4 << 8) | b3); + // make sure d is a low surrogate + if (d < 0xDC00 || d > 0xDFFF) + return CoderResult.malformedForLength (2); + out.put (c); + out.put (d); + inPos += 4; + } + else + { + if (!out.hasRemaining ()) + return CoderResult.UNDERFLOW; + out.put (c); + inPos += 2; + } + } + + return CoderResult.UNDERFLOW; + } + finally + { + in.position (inPos); + } + } + + protected void implReset () + { + byteOrder = originalByteOrder; + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java b/libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java new file mode 100644 index 0000000..d5ab744 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java @@ -0,0 +1,145 @@ +/* UTF_16Encoder.java -- + Copyright (C) 2002 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 gnu.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * Encoder for UTF-16, UTF-15LE, and UTF-16BE. + * + * @author Jesse Rosenstock + */ +final class UTF_16Encoder extends CharsetEncoder +{ + // byte orders + static final int BIG_ENDIAN = 0; + static final int LITTLE_ENDIAN = 1; + + private static final char BYTE_ORDER_MARK = 0xFEFF; + + private final ByteOrder byteOrder; + private final boolean useByteOrderMark; + private boolean needsByteOrderMark; + + UTF_16Encoder (Charset cs, int byteOrder, boolean useByteOrderMark) + { + super (cs, 2.0f, + useByteOrderMark ? 4.0f : 2.0f, + byteOrder == BIG_ENDIAN + ? new byte[] { (byte) 0xFF, (byte) 0xFD } + : new byte[] { (byte) 0xFD, (byte) 0xFF }); + this.byteOrder = (byteOrder == BIG_ENDIAN) ? + ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; + this.useByteOrderMark = useByteOrderMark; + this.needsByteOrderMark = useByteOrderMark; + } + + protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out) + { + // TODO: Optimize this in the case in.hasArray() / out.hasArray() + + ByteOrder originalBO = out.order(); + out.order(byteOrder); + + if (needsByteOrderMark) + { + if (out.remaining () < 2) + { + out.order(originalBO); + return CoderResult.OVERFLOW; + } + out.putChar (BYTE_ORDER_MARK); + needsByteOrderMark = false; + } + + int inPos = in.position (); + try + { + while (in.hasRemaining ()) + { + char c = in.get (); + if (0xD800 <= c && c <= 0xDFFF) + { + // c is a surrogate + + // make sure c is a high surrogate + if (c > 0xDBFF) + return CoderResult.malformedForLength (1); + if (in.remaining () < 1) + return CoderResult.UNDERFLOW; + char d = in.get (); + // make sure d is a low surrogate + if (d < 0xDC00 || d > 0xDFFF) + return CoderResult.malformedForLength (1); + out.putChar (c); + out.putChar (d); + inPos += 2; + } + else + { + if (out.remaining () < 2) + { + out.order(originalBO); + return CoderResult.OVERFLOW; + } + out.putChar (c); + inPos++; + } + } + out.order(originalBO); + return CoderResult.UNDERFLOW; + } + finally + { + in.position (inPos); + } + } + + protected void implReset () + { + needsByteOrderMark = useByteOrderMark; + } + + // TODO: override canEncode(char) and canEncode(CharSequence) + // for performance +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16LE.java b/libjava/classpath/gnu/java/nio/charset/UTF_16LE.java new file mode 100644 index 0000000..6d72a32 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16LE.java @@ -0,0 +1,83 @@ +/* UTF_16LE.java -- + Copyright (C) 2002, 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 gnu.java.nio.charset; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +/** + * UTF-16LE charset. + * + * @author Jesse Rosenstock + */ +final class UTF_16LE extends Charset +{ + UTF_16LE () + { + super ("UTF-16LE", new String[] { + // witnessed by the internet + "UTF16LE", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "x-utf-16le", "ibm-1202", "ibm-13490", "ibm-17586", + "UTF16_LittleEndian", + // see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html + "UnicodeLittleUnmarked" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1 + || cs instanceof UTF_8 || cs instanceof UTF_16BE + || cs instanceof UTF_16LE || cs instanceof UTF_16; + } + + public CharsetDecoder newDecoder () + { + return new UTF_16Decoder (this, UTF_16Decoder.LITTLE_ENDIAN); + } + + public CharsetEncoder newEncoder () + { + return new UTF_16Encoder (this, UTF_16Encoder.LITTLE_ENDIAN, false); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_8.java b/libjava/classpath/gnu/java/nio/charset/UTF_8.java new file mode 100644 index 0000000..0e0730e --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_8.java @@ -0,0 +1,311 @@ +/* UTF_8.java -- + Copyright (C) 2002, 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 gnu.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * UTF-8 charset. + * + *UTF-8 references: + *
+ * These classes ({@link java.security.Signature} for example) can be + * thought of as the "chrome, upholstery, and steering wheel", and the SPI + * (service provider interface, e.g. {@link java.security.SignatureSpi}) + * classes can be thought of as the "engine" -- providing the actual + * functionality of whatever cryptographic algorithm the instance + * represents. + * + * @see Provider + * @author Casey Marshall + */ +public final class Engine +{ + + // Constants. + // ------------------------------------------------------------------------ + + /** Prefix for aliases. */ + private static final String ALG_ALIAS = "Alg.Alias."; + + /** Maximum number of aliases to try. */ + private static final int MAX_ALIASES = 5; + + /** Argument list for no-argument constructors. */ + private static final Object[] NO_ARGS = new Object[0]; + + // Constructor. + // ------------------------------------------------------------------------ + + /** This class cannot be instantiated. */ + private Engine() { } + + // Class method. + // ------------------------------------------------------------------------ + + /** + * Get the implementation for algorithm for service + * service from provider. The service is e.g. + * "Signature", and the algorithm "DSA". + * + * @param service The service name. + * @param algorithm The name of the algorithm to get. + * @param provider The provider to get the implementation from. + * @return The engine class for the specified algorithm; the object + * returned is typically a subclass of the SPI class for that + * service, but callers should check that this is so. + * @throws NoSuchAlgorithmException If the implementation cannot be + * found or cannot be instantiated. + * @throws InvocationTargetException If the SPI class's constructor + * throws an exception. + * @throws IllegalArgumentException If any of the three arguments are null. + */ + public static Object getInstance(String service, String algorithm, + Provider provider) + throws InvocationTargetException, NoSuchAlgorithmException + { + return getInstance(service, algorithm, provider, NO_ARGS); + } + + /** + * Get the implementation for algorithm for service + * service from provider, passing initArgs to the + * SPI class's constructor (which cannot be null; pass a zero-length + * array if the SPI takes no arguments). The service is e.g. + * "Signature", and the algorithm "DSA". + * + * @param service The service name. + * @param algorithm The name of the algorithm to get. + * @param provider The provider to get the implementation from. + * @param initArgs The arguments to pass to the SPI class's + * constructor (cannot be null). + * @return The engine class for the specified algorithm; the object + * returned is typically a subclass of the SPI class for that + * service, but callers should check that this is so. + * @throws NoSuchAlgorithmException If the implementation cannot be + * found or cannot be instantiated. + * @throws InvocationTargetException If the SPI class's constructor + * throws an exception. + * @throws IllegalArgumentException If any of the four arguments are null. + */ + public static Object getInstance(String service, String algorithm, + Provider provider, Object[] initArgs) + throws InvocationTargetException, NoSuchAlgorithmException + { + if (service == null || algorithm == null + || provider == null || initArgs == null) + throw new IllegalArgumentException(); + + // If there is no property "service.algorithm" + if (provider.getProperty(service + "." + algorithm) == null) + { + // Iterate through aliases, until we find the class name or resolve + // too many aliases. + String alias = null; + int count = 0; + while ((alias = provider.getProperty( + ALG_ALIAS + service + "." + algorithm)) != null) + { + if (algorithm.equals(alias)) // Refers to itself! + break; + algorithm = alias; + if (count++ > MAX_ALIASES) + throw new NoSuchAlgorithmException("too many aliases"); + } + if (provider.getProperty(service + "." + algorithm) == null) + throw new NoSuchAlgorithmException(algorithm); + } + + // Find and instantiate the implementation. + Class clazz = null; + ClassLoader loader = provider.getClass().getClassLoader(); + Constructor constructor = null; + String error = algorithm; + + try + { + if (loader != null) + clazz = loader.loadClass(provider.getProperty(service+"."+algorithm)); + else + clazz = Class.forName(provider.getProperty(service+"."+algorithm)); + constructor = getCompatibleConstructor(clazz, initArgs); + return constructor.newInstance(initArgs); + } + catch (ClassNotFoundException cnfe) + { + error = "class not found: " + algorithm; + } + catch (IllegalAccessException iae) + { + error = "illegal access: " + iae.getMessage(); + } + catch (InstantiationException ie) + { + error = "instantiation exception: " + ie.getMessage(); + } + catch (ExceptionInInitializerError eiie) + { + error = "exception in initializer: " + eiie.getMessage(); + } + catch (SecurityException se) + { + error = "security exception: " + se.getMessage(); + } + catch (NoSuchMethodException nsme) + { + error = "no appropriate constructor found"; + } + + throw new NoSuchAlgorithmException(error); + } + + // Own methods. + // ------------------------------------------------------------------------ + + /** + * Find a constructor in the given class that can take the specified + * argument list, allowing any of which to be null. + * + * @param clazz The class from which to get the constructor. + * @param initArgs The argument list to be passed to the constructor. + * @return The constructor. + * @throws NoSuchMethodException If no constructor of the given class + * can take the specified argument array. + */ + private static Constructor getCompatibleConstructor(Class clazz, + Object[] initArgs) + throws NoSuchMethodException + { + Constructor[] c = clazz.getConstructors(); + outer:for (int i = 0; i < c.length; i++) + { + Class[] argTypes = c[i].getParameterTypes(); + if (argTypes.length != initArgs.length) + continue; + for (int j = 0; j < argTypes.length; j++) + { + if (initArgs[j] != null && + !argTypes[j].isAssignableFrom(initArgs[j].getClass())) + continue outer; + } + // If we reach this point, we know this constructor (c[i]) has + // the same number of parameters as the target parameter list, + // and all our parameters are either (1) null, or (2) assignable + // to the target parameter type. + return c[i]; + } + throw new NoSuchMethodException(); + } +} diff --git a/libjava/classpath/gnu/java/security/OID.java b/libjava/classpath/gnu/java/security/OID.java new file mode 100644 index 0000000..8cda43e --- /dev/null +++ b/libjava/classpath/gnu/java/security/OID.java @@ -0,0 +1,509 @@ +/* OID.java -- numeric representation of an object identifier + Copyright (C) 2003, 2004 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 gnu.java.security; + +import gnu.java.security.der.DEREncodingException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.StringTokenizer; + +/** + * This immutable class represents an object identifier, or OID. + * + *
OIDs are represented as a series of hierarcical tokens, each of + * which is usually represented as a single, unsigned integer. The + * hierarchy works so that later tokens are considered within the group + * of earlier tokens. Thus, the OID for the Serpent block cipher, + * 1.3.6.1.4.1.11591.13.2, is maintained by the GNU project, whose OID + * is 1.3.6.1.4.1.11591 (which is, in turn, part of bigger, more general + * bodies; the topmost, 1, stands for the OIDs assigned by the + * International Standards Organization, ISO). + * + *
OIDs can be represented in a variety of ways, including the + * dotted-decimal form we use here. + * + *
OIDs may be relative, in which case the first two elements of the + * OID are omitted. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class OID implements Cloneable, Comparable, java.io.Serializable +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** + * The numeric ID structure. + */ + private int[] components; + + /** + * The string representation of this OID, in dotted-decimal format. + */ + private transient String strRep; + + /** + * The DER encoding of this OID. + */ + private transient byte[] der; + + /** + * Whether or not this OID is relative. + */ + private boolean relative; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new OID from the given byte array. The argument (which can + * neither be null nor zero-length) is copied to prevent subsequent + * modification. + * + * @param components The numeric IDs. + * @throws IllegalArgumentException If components is null or empty. + */ + public OID(int[] components) + { + this(components, false); + } + + /** + * Create a new OID from the given byte array. The argument (which can + * neither be null nor zero-length) is copied to prevent subsequent + * modification. + * + * @param components The numeric IDs. + * @param relative The relative flag. + * @throws IllegalArgumentException If components is null or empty. + */ + public OID(int[] components, boolean relative) + { + if (components == null || components.length == 0) + throw new IllegalArgumentException(); + this.components = (int[]) components.clone(); + this.relative = relative; + } + + /** + * Create a new OID from the given dotted-decimal representation. + * + * @param strRep The string representation of the OID. + * @throws IllegalArgumentException If the string does not contain at + * least one integer. + * @throws NumberFormatException If the string does not contain only + * numbers and periods ('.'). + */ + public OID(String strRep) + { + this(strRep, false); + } + + /** + * Create a new OID from the given dotted-decimal representation. + * + * @param strRep The string representation of the OID. + * @param relative The relative flag. + * @throws IllegalArgumentException If the string does not contain at + * least one integer. + * @throws NumberFormatException If the string does not contain only + * numbers and periods ('.'). + */ + public OID(String strRep, boolean relative) + { + this.relative = relative; + this.strRep = strRep; + components = fromString(strRep); + } + + /** + * Construct a new OID from the DER bytes in an input stream. This method + * does not read the tag or the length field from the input stream, so + * the caller must supply the number of octets in this OID's encoded + * form. + * + * @param derIn The DER input stream. + * @param len The number of bytes in the encoded form. + * @throws IOException If an error occurs reading the OID. + */ + public OID(InputStream derIn, int len) throws IOException + { + this(derIn, len, false); + } + + /** + * Construct a new OID from the DER bytes in an input stream. This method + * does not read the tag or the length field from the input stream, so + * the caller must supply the number of octets in this OID's encoded + * form. + * + * @param derIn The DER input stream. + * @param len The number of bytes in the encoded form. + * @param relative The relative flag. + * @throws IOException If an error occurs reading the OID. + */ + public OID(InputStream derIn, int len, boolean relative) throws IOException + { + der = new byte[len]; + derIn.read(der); + this.relative = relative; + try + { + components = fromDER(der, relative); + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + aioobe.printStackTrace(); + throw aioobe; + } + } + + /** + * Construct a new OID from the given DER bytes. + * + * @param encoded The DER encoded OID. + * @throws IOException If an error occurs reading the OID. + */ + public OID(byte[] encoded) throws IOException + { + this(encoded, false); + } + + /** + * Construct a new OID from the given DER bytes. + * + * @param root The root OID. + * @param encoded The encoded relative OID. + * @param relative The relative flag. + */ + public OID(byte[] encoded, boolean relative) throws IOException + { + der = (byte[]) encoded.clone(); + this.relative = relative; + try + { + components = fromDER(der, relative); + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + aioobe.printStackTrace(); + throw aioobe; + } + } + + /** + * Our private constructor. + */ + private OID() + { + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Return the numeric IDs of this OID. The value returned is copied to + * prevent modification. + * + * @return The IDs in a new integer array. + */ + public int[] getIDs() + { + return (int[]) components.clone(); + } + + /** + * Get the DER encoding of this OID, minus the tag and length fields. + * + * @return The DER bytes. + */ + public byte[] getDER() + { + if (der == null) + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + int i = 0; + if (!relative) + { + int b = components[i++] * 40 + (components.length > 1 + ? components[i++] : 0); + encodeSubID(bout, b); + } + for ( ; i < components.length; i++) + encodeSubID(bout, components[i]); + der = bout.toByteArray(); + } + return (byte[]) der.clone(); + } + + /** + * Get the parent OID of this OID. That is, if this OID is "1.2.3.4", + * then the parent OID will be "1.2.3". If this OID is a top-level + * OID, this method returns null. + * + * @return The parent OID, or null. + */ + public OID getParent() + { + if (components.length == 1) + return null; + int[] parent = new int[components.length - 1]; + System.arraycopy(components, 0, parent, 0, parent.length); + return new OID(parent); + } + + public OID getChild(int id) + { + int[] child = new int[components.length + 1]; + System.arraycopy(components, 0, child, 0, components.length); + child[child.length - 1] = id; + return new OID(child); + } + + /** + * Get the root OID of this OID. That is, the first two components. + * + * @return The root OID. + */ + public OID getRoot() + { + if (components.length <= 2) + return this; + int[] root = new int[2]; + root[0] = components[0]; + root[1] = components[1]; + return new OID(root); + } + + public boolean isRelative() + { + return relative; + } + + /** + * Returns a copy of this OID. + * + * @return The copy. + */ + public Object clone() + { + OID oid = new OID(); + oid.components = this.components; + oid.strRep = this.strRep; + return oid; + } + + /* Nice idea, but possibly too expensive for whatever benefit it + * provides. + + public String getShortName() + { + return OIDTable.getShortName(this); + } + + public String getLongName() + { + return OIDTable.getLongName(this); + } + + */ + + /** + * Returns the value of this OID in dotted-decimal format. + * + * @return The string representation. + */ + public String toString() + { + if (strRep != null) + return strRep; + else + { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < components.length; i++) + { + buf.append((long) components[i] & 0xFFFFFFFFL); + if (i < components.length - 1) + buf.append('.'); + } + return (strRep = buf.toString()); + } + } + + /** + * Computes a hash code for this OID. + * + * @return The hash code. + */ + public int hashCode() + { + int ret = 0; + for (int i = 0; i < components.length; i++) + ret += components[i] << (i & 31); + return ret; + } + + /** + * Tests whether or not this OID equals another. + * + * @return Whether or not this OID equals the other. + */ + public boolean equals(Object o) + { + if (!(o instanceof OID)) + return false; + return java.util.Arrays.equals(components, ((OID) o).components); + } + + /** + * Compares this OID to another. The comparison is essentially + * lexicographic, where the two OIDs are compared until their + * first difference, then that difference is returned. If one OID is + * shorter, but all elements equal between the two for the shorter + * length, then the shorter OID is lesser than the longer. + * + * @param o The object to compare. + * @return An integer less than, equal to, or greater than zero if + * this object is less than, equal to, or greater than the + * argument. + * @throws ClassCastException If o is not an OID. + */ + public int compareTo(Object o) + { + if (equals(o)) + return 0; + int[] components2 = ((OID) o).components; + int len = Math.min(components.length, components2.length); + for (int i = 0; i < len; i++) + { + if (components[i] != components2[i]) + return (components[i] < components2[i]) ? -1 : 1; + } + if (components.length == components2.length) + return 0; + return (components.length < components2.length) ? -1 : 1; + } + + // Own methods. + // ------------------------------------------------------------------------ + + private static int[] fromDER(byte[] der, boolean relative) + throws DEREncodingException + { + // cannot be longer than this. + int[] components = new int[der.length + 1]; + int count = 0; + int i = 0; + if (!relative && i < der.length) + { + // Non-relative OIDs have the first two arcs coded as: + // + // i = first_arc * 40 + second_arc; + // + int j = (der[i] & 0xFF); + components[count++] = j / 40; + components[count++] = j % 40; + i++; + } + while (i < der.length) + { + int j = 0; + do + { + j = der[i++] & 0xFF; + components[count] <<= 7; + components[count] |= j & 0x7F; + if (i >= der.length && (j & 0x80) != 0) + throw new DEREncodingException("malformed OID"); + } + while ((j & 0x80) != 0); + count++; + } + if (count == components.length) + return components; + int[] ret = new int[count]; + System.arraycopy(components, 0, ret, 0, count); + return ret; + } + + private static int[] fromString(String strRep) throws NumberFormatException + { + if (strRep.startsWith("OID.") || strRep.startsWith("oid.")) + strRep = strRep.substring(4); + StringTokenizer tok = new StringTokenizer(strRep, "."); + if (tok.countTokens() == 0) + throw new IllegalArgumentException(); + int[] components = new int[tok.countTokens()]; + int i = 0; + while (tok.hasMoreTokens()) + { + components[i++] = Integer.parseInt(tok.nextToken()); + } + return components; + } + + private static void encodeSubID(ByteArrayOutputStream out, int id) + { + if (id < 128) + { + out.write(id); + } + else if (id < 16384) + { + out.write((id >>> 7) | 0x80); + out.write(id & 0x7F); + } + else if (id < 2097152) + { + out.write((id >>> 14) | 0x80); + out.write(((id >>> 7) | 0x80) & 0xFF); + out.write(id & 0x7F); + } + else if (id < 268435456) + { + out.write( (id >>> 21) | 0x80); + out.write(((id >>> 14) | 0x80) & 0xFF); + out.write(((id >>> 7) | 0x80) & 0xFF); + out.write(id & 0x7F); + } + } +} diff --git a/libjava/classpath/gnu/java/security/PolicyFile.java b/libjava/classpath/gnu/java/security/PolicyFile.java new file mode 100644 index 0000000..dd3a4de --- /dev/null +++ b/libjava/classpath/gnu/java/security/PolicyFile.java @@ -0,0 +1,667 @@ +/* PolicyFile.java -- policy file reader + Copyright (C) 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 gnu.java.security; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StreamTokenizer; +import java.lang.reflect.Constructor; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.Policy; +import java.security.Principal; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.Security; +import java.security.UnresolvedPermission; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * An implementation of a {@link java.security.Policy} object whose + * permissions are specified by a policy file. + * + *
The approximate syntax of policy files is:
+ * + *+ * policyFile ::= keystoreOrGrantEntries ; + * + * keystoreOrGrantEntries ::= keystoreOrGrantEntry | + * keystoreOrGrantEntries keystoreOrGrantEntry | + * EMPTY ; + * + * keystoreOrGrantEntry ::= keystoreEntry | grantEntry ; + * + * keystoreEntry ::= "keystore" keystoreUrl ';' | + * "keystore" keystoreUrl ',' keystoreAlgorithm ';' ; + * + * keystoreUrl ::= URL ; + * keystoreAlgorithm ::= STRING ; + * + * grantEntry ::= "grant" domainParameters '{' permissions '}' ';' + * + * domainParameters ::= domainParameter | + * domainParameter ',' domainParameters ; + * + * domainParameter ::= "signedBy" signerNames | + * "codeBase" codeBaseUrl | + * "principal" principalClassName principalName | + * "principal" principalName ; + * + * signerNames ::= quotedString ; + * codeBaseUrl ::= URL ; + * principalClassName ::= STRING ; + * principalName ::= quotedString ; + * + * quotedString ::= quoteChar STRING quoteChar ; + * quoteChar ::= '"' | '\''; + * + * permissions ::= permission | permissions permission ; + * + * permission ::= "permission" permissionClassName permissionTarget permissionAction | + * "permission" permissionClassName permissionTarget | + * "permission" permissionClassName; + *+ * + *
Comments are either form of Java comments. Keystore entries only
+ * affect subsequent grant entries, so if a grant entry preceeds a
+ * keystore entry, that grant entry is not affected by that keystore
+ * entry. Certian instances of ${property-name}
will be
+ * replaced with System.getProperty("property-name")
in
+ * quoted strings.
This class will load the following files when created or + * refreshed, in order:
+ * + *${java.home}/lib/security/java.policy
."policy.file.n"
, for increasing n
+ * starting from 1. The sequence stops at the first undefined
+ * property, so you must set "policy.file.1"
if you also
+ * set "policy.file.2"
, and so on."java.security.policy"
."${property-name}"
into
+ * System.getProperty("property-name")
.
+ */
+ private static String expand(final String s)
+ {
+ final StringBuffer result = new StringBuffer();
+ final StringBuffer prop = new StringBuffer();
+ int state = 0;
+ for (int i = 0; i < s.length(); i++)
+ {
+ switch (state)
+ {
+ case 0:
+ if (s.charAt(i) == '$')
+ state = 1;
+ else
+ result.append(s.charAt(i));
+ break;
+ case 1:
+ if (s.charAt(i) == '{')
+ state = 2;
+ else
+ {
+ state = 0;
+ result.append('$').append(s.charAt(i));
+ }
+ break;
+ case 2:
+ if (s.charAt(i) == '}')
+ {
+ String p = prop.toString();
+ if (p.equals("/"))
+ p = "file.separator";
+ p = System.getProperty(p);
+ if (p == null)
+ p = "";
+ result.append(p);
+ prop.setLength(0);
+ state = 0;
+ }
+ else
+ prop.append(s.charAt(i));
+ break;
+ }
+ }
+ if (state != 0)
+ result.append('$').append('{').append(prop);
+ return result.toString();
+ }
+
+ /**
+ * I miss macros.
+ */
+ private static void error(URL base, StreamTokenizer in, String msg)
+ throws IOException
+ {
+ throw new IOException(base+":"+in.lineno()+": "+msg);
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/action/GetPropertyAction.java b/libjava/classpath/gnu/java/security/action/GetPropertyAction.java
new file mode 100644
index 0000000..2886deb
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/action/GetPropertyAction.java
@@ -0,0 +1,89 @@
+/* GetPropertyAction.java
+ Copyright (C) 2004 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 gnu.java.security.action;
+
+import java.security.PrivilegedAction;
+
+/**
+ * PrivilegedAction implementation that calls System.getProperty() with
+ * the property name passed to its constructor.
+ *
+ * Example of use:
+ *
+ * GetPropertyAction action = new GetPropertyAction("http.proxyPort");
+ * String port = AccessController.doPrivileged(action);
+ *
+ */
+public class GetPropertyAction implements PrivilegedAction
+{
+ String name;
+ String value = null;
+
+ public GetPropertyAction()
+ {
+ }
+
+ public GetPropertyAction(String propName)
+ {
+ setParameters(propName);
+ }
+
+ public GetPropertyAction(String propName, String defaultValue)
+ {
+ setParameters(propName, defaultValue);
+ }
+
+ public Object run()
+ {
+ return System.getProperty(name, value);
+ }
+
+ public GetPropertyAction setParameters(String propName)
+ {
+ this.name = propName;
+ this.value = null;
+ return this;
+ }
+
+ public GetPropertyAction setParameters(String propName, String defaultValue)
+ {
+ this.name = propName;
+ this.value = defaultValue;
+ return this;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java b/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java
new file mode 100644
index 0000000..97fa15d
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java
@@ -0,0 +1,93 @@
+/* GetSecurityPropertyAction.java
+ Copyright (C) 2004 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 gnu.java.security.action;
+
+import java.security.PrivilegedAction;
+import java.security.Security;
+
+/**
+ * PrivilegedAction implementation that calls Security.getProperty()
+ * with the property name passed to its constructor.
+ *
+ * Example of use:
+ *
+ * GetSecurityPropertyAction action = new GetSecurityPropertyAction("javax.net.ssl.trustStorePassword");
+ * String passwd = AccessController.doPrivileged(action);
+ *
+ */
+public class GetSecurityPropertyAction implements PrivilegedAction
+{
+ private String name;
+ private String value;
+
+ public GetSecurityPropertyAction()
+ {
+ }
+
+ public GetSecurityPropertyAction(String propName)
+ {
+ setParameters(propName);
+ }
+
+ public GetSecurityPropertyAction(String propName, String defaultValue)
+ {
+ setParameters(propName, defaultValue);
+ }
+
+ public GetSecurityPropertyAction setParameters(String propName)
+ {
+ this.name = propName;
+ this.value = null;
+ return this;
+ }
+
+ public GetSecurityPropertyAction setParameters(String propName, String defaultValue)
+ {
+ this.name = propName;
+ this.value = defaultValue;
+ return this;
+ }
+
+ public Object run()
+ {
+ String val = Security.getProperty(name);
+ if (val == null)
+ val = value;
+ return val;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/action/SetAccessibleAction.java b/libjava/classpath/gnu/java/security/action/SetAccessibleAction.java
new file mode 100644
index 0000000..77e5fc9
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/action/SetAccessibleAction.java
@@ -0,0 +1,77 @@
+/* SetAccessibleAction.java
+ Copyright (C) 2004 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 gnu.java.security.action;
+
+import java.lang.reflect.AccessibleObject;
+import java.security.PrivilegedAction;
+
+/**
+ * PrivilegedAction implementation that calls setAccessible(true) on the
+ * AccessibleObject passed to its constructor.
+ *
+ * Example of use:
+ *
+ * Field dataField = cl.getDeclaredField("data");
+ * AccessController.doPrivileged(new SetAccessibleAction(dataField));
+ *
+ */
+public class SetAccessibleAction implements PrivilegedAction
+{
+ AccessibleObject member;
+
+ public SetAccessibleAction()
+ {
+ }
+
+ public SetAccessibleAction(AccessibleObject member)
+ {
+ this.member = member;
+ }
+
+ public Object run()
+ {
+ member.setAccessible(true);
+ return null;
+ }
+
+ public SetAccessibleAction setMember(AccessibleObject member)
+ {
+ this.member = member;
+ return this;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/action/package.html b/libjava/classpath/gnu/java/security/action/package.html
new file mode 100644
index 0000000..fc3dfa2
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/action/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+00010101 11101101 11010xxx+ * + *
Where the "xxx" represents three bits that should be ignored, and
+ * can have any value.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class BitString implements Cloneable, Comparable
+{
+
+ // Fields.
+ // ------------------------------------------------------------------------
+
+ /** The bits themselves. */
+ private final byte[] bytes;
+
+ /**
+ * The exportable byte array. This array has the ignored bits
+ * removed.
+ */
+ private transient byte[] externBytes;
+
+ /** The number of bits ignored at the end of the byte array. */
+ private final int ignoredBits;
+
+ /** This bit string as a boolean array. */
+ private transient boolean[] boolVal;
+
+ // Constructors.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a new bit string, shifting the given byte array if needed.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @param ignoredBits The number of bits to ignore.
+ * @param doShift Pass true in this parameter if the byte array has
+ * not yet been shifted left by ignoredBits.
+ * @throws IllegalArgumentException If ignoredBits is negative
+ * or greater than 7.
+ * @throws NullPointerException If bytes is null.
+ */
+ public BitString(byte[] bytes, int ignoredBits, boolean doShift)
+ {
+ this(bytes, 0, bytes.length, ignoredBits, doShift);
+ }
+
+ /**
+ * Create a new bit string, shifting the given byte array if needed.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @param offset The offset where the meaningful bytes begin.
+ * @param length The number of meaningful bytes.
+ * @param ignoredBits The number of bits to ignore.
+ * @param doShift Pass true in this parameter if the byte array has
+ * not yet been shifted left by ignoredBits.
+ * @throws IllegalArgumentException If ignoredBits is negative
+ * or greater than 7.
+ * @throws NullPointerException If bytes is null.
+ */
+ public BitString(byte[] bytes, int offset, int length,
+ int ignoredBits, boolean doShift)
+ {
+ if (ignoredBits < 0 || ignoredBits > 7)
+ throw new IllegalArgumentException();
+ if (bytes == null)
+ throw new NullPointerException();
+ if (doShift && ignoredBits > 0)
+ {
+ this.externBytes = new byte[length];
+ System.arraycopy(bytes, offset, externBytes, 0, length);
+ this.bytes = new BigInteger(externBytes).shiftLeft(ignoredBits)
+ .toByteArray();
+ }
+ else
+ {
+ this.bytes = new byte[length];
+ System.arraycopy(bytes, offset, this.bytes, 0, length);
+ }
+ this.ignoredBits = ignoredBits;
+ }
+
+ /**
+ * Create a new bit string.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @param offset The offset where the meaningful bytes begin.
+ * @param length The number of meaningful bytes.
+ * @param ignoredBits The number of bits to ignore.
+ * @throws IllegalArgumentException If ignoredBits is negative
+ * or greater than 7.
+ * @throws NullPointerException If bytes is null.
+ */
+ public BitString(byte[] bytes, int offset, int length, int ignoredBits)
+ {
+ this(bytes, offset, length, ignoredBits, false);
+ }
+
+ /**
+ * Create a new bit string.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @param ignoredBits The number of bits to ignore.
+ * @throws IllegalArgumentException If ignoredBits is negative
+ * or greater than 7.
+ * @throws NullPointerException If bytes is null.
+ */
+ public BitString(byte[] bytes, int ignoredBits)
+ {
+ this(bytes, 0, bytes.length, ignoredBits, false);
+ }
+
+ /**
+ * Create a new bit string.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @param offset The offset where the meaningful bytes begin.
+ * @param length The number of meaningful bytes.
+ * @throws NullPointerException If bytes is null.
+ */
+ public BitString(byte[] bytes, int offset, int length)
+ {
+ this(bytes, offset, length, 0, false);
+ }
+
+ /**
+ * Create a new bit string.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @throws NullPointerException If bytes is null.
+ */
+ public BitString(byte[] bytes)
+ {
+ this(bytes, 0, bytes.length, 0, false);
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Return this bit string as a byte array, with the ignored bits
+ * trimmed off. The byte array is cloned every time this method is
+ * called to prevent modification.
+ *
+ * @return The trimmed byte array.
+ */
+ public byte[] toByteArray()
+ {
+ if (ignoredBits == 0)
+ return (byte[]) bytes.clone();
+ if (externBytes == null)
+ externBytes = new BigInteger(bytes).shiftRight(ignoredBits).toByteArray();
+ return (byte[]) externBytes.clone();
+ }
+
+ /**
+ * Returns this bit string as a byte array, with the ignored bits
+ * present. The byte array is cloned every time this method is
+ * called to prevent modification.
+ *
+ * @return The byte array.
+ */
+ public byte[] getShiftedByteArray()
+ {
+ return (byte[]) bytes.clone();
+ }
+
+ /**
+ * Returns the number of ignored bits.
+ *
+ * @return The number of ignored bits.
+ */
+ public int getIgnoredBits()
+ {
+ return ignoredBits;
+ }
+
+ /**
+ * Returns the size, in bits, of this bit string.
+ *
+ * @return The size of this bit string.
+ */
+ public int size()
+ {
+ return (bytes.length << 3) - ignoredBits;
+ }
+
+ /**
+ * Return this bit string as a boolean array. The value returned is of
+ * size {@link #size()}, and each true
value
+ * corresponding to each "1" in this bit string. The boolean array is
+ * cloned before it is returned.
+ *
+ * @return The boolean array.
+ */
+ public boolean[] toBooleanArray()
+ {
+ if (boolVal == null)
+ {
+ boolVal = new boolean[size()];
+ for (int i = 0, j = 7, k = 0; i < boolVal.length; i++)
+ {
+ boolVal[i] = (bytes[k] & 1 << j--) != 0;
+ if (j < 0)
+ {
+ j = 7;
+ k++;
+ }
+ }
+ }
+ return (boolean[]) boolVal.clone();
+ }
+
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException cce)
+ {
+ throw new InternalError(cce.getMessage());
+ }
+ }
+
+ public int compareTo(Object o)
+ {
+ BitString that = (BitString) o;
+ if (this.equals(that))
+ return 0;
+ if (this.bytes.length != that.bytes.length)
+ return (this.bytes.length < that.bytes.length) ? -1 : 1;
+ if (this.ignoredBits != that.ignoredBits)
+ return (this.ignoredBits < that.ignoredBits) ? -1 : 1;
+ for (int i = 0; i < this.bytes.length; i++)
+ if (this.bytes[i] != that.bytes[i])
+ return (this.bytes[i] < that.bytes[i]) ? -1 : 1;
+ return 0; // not reached.
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BitString))
+ return false;
+ BitString that = (BitString) o;
+ // True for cloned instances.
+ if (this.bytes == that.bytes && this.ignoredBits == that.ignoredBits)
+ return true;
+ if (this.ignoredBits == that.ignoredBits)
+ return Arrays.equals(this.bytes, that.bytes);
+ return false;
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0, j = 7, k = 0; i < size(); i++)
+ {
+ sb.append((bytes[k] & 1 << j) != 0 ? "1" : "0");
+ j--;
+ if (j < 0)
+ {
+ j = 7;
+ k++;
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/der/DER.java b/libjava/classpath/gnu/java/security/der/DER.java
new file mode 100644
index 0000000..a7eb4a6
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/der/DER.java
@@ -0,0 +1,86 @@
+/* DER.java -- Basic constants in DER sequences.
+ Copyright (C) 2003 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 gnu.java.security.der;
+
+/**
+ * The set of tags for DER types.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public interface DER
+{
+ int UNIVERSAL = 0x00;
+ int APPLICATION = 0x40;
+ int CONTEXT = 0x80;
+ int PRIVATE = 0xC0;
+
+ int CONSTRUCTED = 0x20;
+
+ int ANY = 0x00;
+ int BOOLEAN = 0x01;
+ int INTEGER = 0x02;
+ int BIT_STRING = 0x03;
+ int OCTET_STRING = 0x04;
+ int NULL = 0x05;
+ int OBJECT_IDENTIFIER = 0x06;
+ int REAL = 0x09;
+ int ENUMERATED = 0x0a;
+ int RELATIVE_OID = 0x0d;
+
+ int SEQUENCE = 0x10;
+ int SET = 0x11;
+
+ Object CONSTRUCTED_VALUE = new Object();
+
+ int NUMERIC_STRING = 0x12;
+ int PRINTABLE_STRING = 0x13;
+ int T61_STRING = 0x14;
+ int VIDEOTEX_STRING = 0x15;
+ int IA5_STRING = 0x16;
+ int GRAPHIC_STRING = 0x19;
+ int ISO646_STRING = 0x1A;
+ int GENERAL_STRING = 0x1B;
+
+ int UTF8_STRING = 0x0C;
+ int UNIVERSAL_STRING = 0x1C;
+ int BMP_STRING = 0x1E;
+
+ int UTC_TIME = 0x17;
+ int GENERALIZED_TIME = 0x18;
+}
diff --git a/libjava/classpath/gnu/java/security/der/DEREncodingException.java b/libjava/classpath/gnu/java/security/der/DEREncodingException.java
new file mode 100644
index 0000000..90042a3
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/der/DEREncodingException.java
@@ -0,0 +1,54 @@
+/* DEREncodingException.java --- DER Encoding Exception
+ Copyright (C) 1999,2003 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 gnu.java.security.der;
+
+import java.io.IOException;
+
+public class DEREncodingException extends IOException
+{
+ public DEREncodingException()
+ {
+ super ();
+ }
+
+ public DEREncodingException (String msg)
+ {
+ super (msg);
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/der/DERReader.java b/libjava/classpath/gnu/java/security/der/DERReader.java
new file mode 100644
index 0000000..cb07f14
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/der/DERReader.java
@@ -0,0 +1,437 @@
+/* DERReader.java -- parses ASN.1 DER sequences
+ Copyright (C) 2003 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 gnu.java.security.der;
+
+import gnu.java.security.OID;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * This class decodes DER sequences into Java objects. The methods of
+ * this class do not have knowledge of higher-levels of structure in the
+ * DER stream -- such as ASN.1 constructions -- and it is therefore up
+ * to the calling application to determine if the data are structured
+ * properly by inspecting the {@link DERValue} that is returned.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class DERReader implements DER
+{
+
+ // Fields.
+ // ------------------------------------------------------------------------
+
+ protected InputStream in;
+
+ protected final ByteArrayOutputStream encBuf;
+
+ // Constructor.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a new DER reader from a byte array.
+ *
+ * @param in The encoded bytes.
+ */
+ public DERReader(byte[] in)
+ {
+ this(new ByteArrayInputStream(in));
+ }
+
+ public DERReader (byte[] in, int off, int len)
+ {
+ this (new ByteArrayInputStream (in, off, len));
+ }
+
+ /**
+ * Create a new DER readed from an input stream.
+ *
+ * @param in The encoded bytes.
+ */
+ public DERReader(InputStream in)
+ {
+ if (!in.markSupported())
+ this.in = new BufferedInputStream(in, 16384);
+ else
+ this.in = in;
+ encBuf = new ByteArrayOutputStream(2048);
+ }
+
+ // Class methods.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Convenience method for reading a single primitive value from the
+ * given byte array.
+ *
+ * @param encoded The encoded bytes.
+ * @throws IOException If the bytes do not represent an encoded
+ * object.
+ */
+ public static DERValue read(byte[] encoded) throws IOException
+ {
+ return new DERReader(encoded).read();
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ public void skip (int bytes) throws IOException
+ {
+ in.skip (bytes);
+ }
+
+ /**
+ * Decode a single value from the input stream, returning it in a new
+ * {@link DERValue}. By "single value" we mean any single type in its
+ * entirety -- including constructed types such as SEQUENCE and all
+ * the values they contain. Usually it is sufficient to call this
+ * method once to parse and return the top-level structure, then to
+ * inspect the returned value for the proper contents.
+ *
+ * @return The parsed DER structure.
+ * @throws IOException If an error occurs reading from the input
+ * stream.
+ * @throws DEREncodingException If the input does not represent a
+ * valid DER stream.
+ */
+ public DERValue read() throws IOException
+ {
+ int tag = in.read();
+ if (tag == -1)
+ throw new EOFException();
+ encBuf.write(tag);
+ int len = readLength();
+ DERValue value = null;
+ if ((tag & CONSTRUCTED) == CONSTRUCTED)
+ {
+ in.mark(2048);
+ byte[] encoded = new byte[len];
+ in.read(encoded);
+ encBuf.write(encoded);
+ value = new DERValue(tag, len, CONSTRUCTED_VALUE, encBuf.toByteArray());
+ in.reset();
+ encBuf.reset();
+ return value;
+ }
+ switch (tag & 0xC0)
+ {
+ case UNIVERSAL:
+ value = new DERValue(tag, len, readUniversal(tag, len),
+ encBuf.toByteArray());
+ encBuf.reset();
+ break;
+ case CONTEXT:
+ byte[] encoded = new byte[len];
+ in.read(encoded);
+ encBuf.write(encoded);
+ value = new DERValue(tag, len, encoded, encBuf.toByteArray());
+ encBuf.reset();
+ break;
+ case APPLICATION:
+ // This should not be reached, since (I think) APPLICATION is
+ // always constructed.
+ throw new DEREncodingException("non-constructed APPLICATION data");
+ default:
+ throw new DEREncodingException("PRIVATE class not supported");
+ }
+ return value;
+ }
+
+ protected int readLength() throws IOException
+ {
+ int i = in.read();
+ if (i == -1)
+ throw new EOFException();
+ encBuf.write(i);
+ if ((i & ~0x7F) == 0)
+ {
+ return i;
+ }
+ else if (i < 0xFF)
+ {
+ byte[] octets = new byte[i & 0x7F];
+ in.read(octets);
+ encBuf.write(octets);
+ return new BigInteger(1, octets).intValue();
+ }
+ throw new DEREncodingException();
+ }
+
+ // Own methods.
+ // ------------------------------------------------------------------------
+
+ private Object readUniversal(int tag, int len) throws IOException
+ {
+ byte[] value = new byte[len];
+ in.read(value);
+ encBuf.write(value);
+ switch (tag & 0x1F)
+ {
+ case BOOLEAN:
+ if (value.length != 1)
+ throw new DEREncodingException();
+ return Boolean.valueOf(value[0] != 0);
+ case NULL:
+ if (len != 0)
+ throw new DEREncodingException();
+ return null;
+ case INTEGER:
+ case ENUMERATED:
+ return new BigInteger(value);
+ case BIT_STRING:
+ byte[] bits = new byte[len - 1];
+ System.arraycopy(value, 1, bits, 0, bits.length);
+ return new BitString(bits, value[0] & 0xFF);
+ case OCTET_STRING:
+ return value;
+ case NUMERIC_STRING:
+ case PRINTABLE_STRING:
+ case T61_STRING:
+ case VIDEOTEX_STRING:
+ case IA5_STRING:
+ case GRAPHIC_STRING:
+ case ISO646_STRING:
+ case GENERAL_STRING:
+ case UNIVERSAL_STRING:
+ case BMP_STRING:
+ case UTF8_STRING:
+ return makeString(tag, value);
+ case UTC_TIME:
+ case GENERALIZED_TIME:
+ return makeTime(tag, value);
+ case OBJECT_IDENTIFIER:
+ return new OID(value);
+ case RELATIVE_OID:
+ return new OID(value, true);
+ default:
+ throw new DEREncodingException("unknown tag " + tag);
+ }
+ }
+
+ private static String makeString(int tag, byte[] value)
+ throws IOException
+ {
+ switch (tag & 0x1F)
+ {
+ case NUMERIC_STRING:
+ case PRINTABLE_STRING:
+ case T61_STRING:
+ case VIDEOTEX_STRING:
+ case IA5_STRING:
+ case GRAPHIC_STRING:
+ case ISO646_STRING:
+ case GENERAL_STRING:
+ return fromIso88591(value);
+
+ case UNIVERSAL_STRING:
+ // XXX The docs say UniversalString is encoded in four bytes
+ // per character, but Java has no support (yet) for UTF-32.
+ //return new String(buf, "UTF-32");
+ case BMP_STRING:
+ return fromUtf16Be(value);
+
+ case UTF8_STRING:
+ return fromUtf8(value);
+
+ default:
+ throw new DEREncodingException("unknown string tag");
+ }
+ }
+
+ private static String fromIso88591(byte[] bytes)
+ {
+ StringBuffer str = new StringBuffer(bytes.length);
+ for (int i = 0; i < bytes.length; i++)
+ str.append((char) (bytes[i] & 0xFF));
+ return str.toString();
+ }
+
+ private static String fromUtf16Be(byte[] bytes) throws IOException
+ {
+ if ((bytes.length & 0x01) != 0)
+ throw new IOException("UTF-16 bytes are odd in length");
+ StringBuffer str = new StringBuffer(bytes.length / 2);
+ for (int i = 0; i < bytes.length; i += 2)
+ {
+ char c = (char) ((bytes[i] << 8) & 0xFF);
+ c |= (char) (bytes[i+1] & 0xFF);
+ str.append(c);
+ }
+ return str.toString();
+ }
+
+ private static String fromUtf8(byte[] bytes) throws IOException
+ {
+ StringBuffer str = new StringBuffer((int)(bytes.length / 1.5));
+ for (int i = 0; i < bytes.length; )
+ {
+ char c = 0;
+ if ((bytes[i] & 0xE0) == 0xE0)
+ {
+ if ((i + 2) >= bytes.length)
+ throw new IOException("short UTF-8 input");
+ c = (char) ((bytes[i++] & 0x0F) << 12);
+ if ((bytes[i] & 0x80) != 0x80)
+ throw new IOException("malformed UTF-8 input");
+ c |= (char) ((bytes[i++] & 0x3F) << 6);
+ if ((bytes[i] & 0x80) != 0x80)
+ throw new IOException("malformed UTF-8 input");
+ c |= (char) (bytes[i++] & 0x3F);
+ }
+ else if ((bytes[i] & 0xC0) == 0xC0)
+ {
+ if ((i + 1) >= bytes.length)
+ throw new IOException("short input");
+ c = (char) ((bytes[i++] & 0x1F) << 6);
+ if ((bytes[i] & 0x80) != 0x80)
+ throw new IOException("malformed UTF-8 input");
+ c |= (char) (bytes[i++] & 0x3F);
+ }
+ else if ((bytes[i] & 0xFF) < 0x80)
+ {
+ c = (char) (bytes[i++] & 0xFF);
+ }
+ else
+ throw new IOException("badly formed UTF-8 sequence");
+ str.append(c);
+ }
+ return str.toString();
+ }
+
+ private Date makeTime(int tag, byte[] value) throws IOException
+ {
+ Calendar calendar = Calendar.getInstance();
+ String str = makeString(PRINTABLE_STRING, value);
+
+ // Classpath's SimpleDateFormat does not work for parsing these
+ // types of times, so we do this by hand.
+ String date = str;
+ String tz = "";
+ if (str.indexOf("+") > 0)
+ {
+ date = str.substring(0, str.indexOf("+"));
+ tz = str.substring(str.indexOf("+"));
+ }
+ else if (str.indexOf("-") > 0)
+ {
+ date = str.substring(0, str.indexOf("-"));
+ tz = str.substring(str.indexOf("-"));
+ }
+ else if (str.endsWith("Z"))
+ {
+ date = str.substring(0, str.length()-2);
+ tz = "Z";
+ }
+ if (!tz.equals("Z") && tz.length() > 0)
+ calendar.setTimeZone(TimeZone.getTimeZone(tz));
+ else
+ calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+ if ((tag & 0x1F) == UTC_TIME)
+ {
+ if (date.length() < 10) // must be at least 10 chars long
+ throw new DEREncodingException("cannot parse date");
+ // UTCTime is of the form "yyMMddHHmm[ss](Z|(+|-)hhmm)"
+ try
+ {
+ int year = Integer.parseInt(str.substring(0, 2));
+ if (year < 50)
+ year += 2000;
+ else
+ year += 1900;
+ calendar.set(year,
+ Integer.parseInt(str.substring( 2, 4))-1, // month
+ Integer.parseInt(str.substring( 4, 6)), // day
+ Integer.parseInt(str.substring( 6, 8)), // hour
+ Integer.parseInt(str.substring( 8, 10))); // minute
+ if (date.length() == 12);
+ calendar.set(Calendar.SECOND,
+ Integer.parseInt(str.substring(10, 12)));
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw new DEREncodingException("cannot parse date");
+ }
+ }
+ else
+ {
+ if (date.length() < 10) // must be at least 10 chars long
+ throw new DEREncodingException("cannot parse date");
+ // GeneralTime is of the form "yyyyMMddHH[mm[ss[(.|,)SSSS]]]"
+ // followed by "Z" or "(+|-)hh[mm]"
+ try
+ {
+ calendar.set(
+ Integer.parseInt(date.substring(0, 4)), // year
+ Integer.parseInt(date.substring(4, 6))-1, // month
+ Integer.parseInt(date.substring(6, 8)), // day
+ Integer.parseInt(date.substring(8, 10)), 0); // hour, min
+ switch (date.length())
+ {
+ case 19:
+ case 18:
+ case 17:
+ case 16:
+ calendar.set(Calendar.MILLISECOND,
+ Integer.parseInt(date.substring(15)));
+ case 14:
+ calendar.set(Calendar.SECOND,
+ Integer.parseInt(date.substring(12, 14)));
+ case 12:
+ calendar.set(Calendar.MINUTE,
+ Integer.parseInt(date.substring(10, 12)));
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw new DEREncodingException("cannot parse date");
+ }
+ }
+ return calendar.getTime();
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/der/DERValue.java b/libjava/classpath/gnu/java/security/der/DERValue.java
new file mode 100644
index 0000000..9a597d7
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/der/DERValue.java
@@ -0,0 +1,170 @@
+/* DERValue.java -- a value read or written to a DER encoding.
+ Copyright (C) 2003 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 gnu.java.security.der;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class DERValue implements DER
+{
+
+ // Fields.
+ // ------------------------------------------------------------------------
+
+ private final int tagClass;
+ private final boolean constructed;
+ private final int tag;
+ private int length;
+ private final Object value;
+ private byte[] encoded;
+
+ // Constructor.
+ // ------------------------------------------------------------------------
+
+ public DERValue(int tag, int length, Object value, byte[] encoded)
+ {
+ tagClass = tag & 0xC0;
+ this.tag = tag & 0x1F;
+ constructed = (tag & CONSTRUCTED) == CONSTRUCTED;
+ this.length = length;
+ this.value = value;
+ if (encoded != null)
+ this.encoded = (byte[]) encoded.clone();
+ }
+
+ public DERValue(int tag, Object value)
+ {
+ this(tag, 0, value, null);
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ public int getExternalTag()
+ {
+ return tagClass | tag | (constructed ? 0x20 : 0x00);
+ }
+
+ public int getTag()
+ {
+ return tag;
+ }
+
+ public int getTagClass()
+ {
+ return tagClass;
+ }
+
+ public boolean isConstructed()
+ {
+ return constructed;
+ }
+
+ public int getLength()
+ {
+ if (encoded == null)
+ {
+ try
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ length = DERWriter.write(out, this);
+ encoded = out.toByteArray();
+ }
+ catch (IOException ioe)
+ {
+ encoded = new byte[0];
+ }
+ }
+ return length;
+ }
+
+ public Object getValue()
+ {
+ return value;
+ }
+
+ public Object getValueAs (final int derType) throws IOException
+ {
+ byte[] encoded = getEncoded ();
+ encoded[0] = (byte) derType;
+ return DERReader.read (encoded).getValue ();
+ }
+
+ public byte[] getEncoded()
+ {
+ if (encoded == null)
+ {
+ try
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ length = DERWriter.write(out, this);
+ encoded = out.toByteArray();
+ }
+ catch (IOException ioe)
+ {
+ encoded = new byte[0];
+ }
+ }
+ return (byte[]) encoded.clone();
+ }
+
+ public int getEncodedLength()
+ {
+ if (encoded == null)
+ {
+ try
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ length = DERWriter.write(out, this);
+ encoded = out.toByteArray();
+ }
+ catch (IOException ioe)
+ {
+ encoded = new byte[0];
+ }
+ }
+ return encoded.length;
+ }
+
+ public String toString()
+ {
+ return "DERValue [ tag=" + tag + ", class=" + tagClass + ", constructed="
+ + constructed + ", value=" + value + " ]";
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/der/DERWriter.java b/libjava/classpath/gnu/java/security/der/DERWriter.java
new file mode 100644
index 0000000..78524fc
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/der/DERWriter.java
@@ -0,0 +1,349 @@
+/* DERWriter.java -- write Java types in DER format.
+ Copyright (C) 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 gnu.java.security.der;
+
+import gnu.java.security.OID;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.math.BigInteger;
+
+import java.text.SimpleDateFormat;
+
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.TimeZone;
+
+/**
+ * Methods that allow various Java types to be written as a DER
+ * (Distinguished Encoding Rules) stream to the specified output stream.
+ * DER is used to encode ASN.1 constructions, but this class provides no
+ * methods for interacting with ASN.1. Rather, callers should construct
+ * their output objects properly for whatever ASN.1 construct is being
+ * output.
+ *
+ *
This class only defines static methods; there are no instance + * variables needed. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class DERWriter implements DER +{ + + // Constructors. + // ------------------------------------------------------------------------ + + /** This class only has static methods. */ + private DERWriter() + { + } + + // Class methods. + // ------------------------------------------------------------------------ + + public static int write(OutputStream out, DERValue object) + throws IOException + { + out.write(object.getExternalTag()); + Object value = object.getValue(); + if (value == null) + { + writeLength(out, 0); + return 0; + } + if (value instanceof Boolean) + return writeBoolean(out, (Boolean) value); + else if (value instanceof BigInteger) + return writeInteger(out, (BigInteger) value); + else if (value instanceof Date) + return writeDate(out, object.getExternalTag(), (Date) value); + else if (value instanceof String) + return writeString(out, object.getExternalTag(), (String) value); + else if (value instanceof List) + return writeSequence(out, (List) value); + else if (value instanceof Set) + return writeSet(out, (Set) value); + else if (value instanceof BitString) + return writeBitString(out, (BitString) value); + else if (value instanceof OID) + return writeOID(out, (OID) value); + else if (value instanceof byte[]) + { + writeLength(out, ((byte[]) value).length); + out.write((byte[]) value); + return ((byte[]) value).length; + } + else if (value instanceof DERValue) + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + write(bout, (DERValue) value); + byte[] buf = bout.toByteArray(); + writeLength(out, buf.length); + out.write(buf); + return buf.length; + } + else + throw new DEREncodingException("cannot encode " + value.getClass().getName()); + } + + public static int definiteEncodingSize(int length) + { + if (length < 128) + return 1; + else if (length < 256) + return 2; + else if (length < 65536) + return 3; + else if (length < 16777216) + return 4; + else + return 5; + } + + // Own methods. + // ------------------------------------------------------------------------ + + /** + * Write a BOOLEAN type to the given output stream. + * + * @param out The sink output stream. + * @param b The boolean value to write. + */ + private static int writeBoolean(OutputStream out, Boolean b) + throws IOException + { + writeLength(out, 1); + if (b.booleanValue()) + out.write(0xFF); + else + out.write(0); + return 1; + } + + /** + * Write an INTEGER type to the given output stream. + * + * @param out The sink output stream. + * @param integer The integer to write. + */ + private static int writeInteger(OutputStream out, BigInteger integer) + throws IOException + { + byte[] bytes = integer.toByteArray(); + writeLength(out, bytes.length); + out.write(bytes); + return bytes.length; + } + + private static int writeSequence(OutputStream out, List sequence) + throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + for (Iterator i = sequence.iterator(); i.hasNext(); ) + { + write(bout, (DERValue) i.next()); + } + byte[] buf = bout.toByteArray(); + writeLength(out, buf.length); + out.write(buf); + return buf.length; + } + + private static int writeSet(OutputStream out, Set set) + throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + for (Iterator i = set.iterator(); i.hasNext(); ) + { + write(bout, (DERValue) i.next()); + } + byte[] buf = bout.toByteArray(); + writeLength(out, buf.length); + out.write(buf); + return buf.length; + } + + private static int writeOID(OutputStream out, OID oid) + throws IOException + { + byte[] der = oid.getDER(); + writeLength(out, der.length); + out.write(der); + return der.length; + } + + private static int writeBitString(OutputStream out, BitString bs) + throws IOException + { + byte[] buf = bs.getShiftedByteArray(); + out.write(buf.length + 1); + out.write(bs.getIgnoredBits()); + out.write(buf); + return buf.length; + } + + private static int writeString(OutputStream out, int tag, String str) + throws IOException + { + byte[] b = null; + switch (tag & 0x1F) + { + case NUMERIC_STRING: + case PRINTABLE_STRING: + case T61_STRING: + case VIDEOTEX_STRING: + case IA5_STRING: + case GRAPHIC_STRING: + case ISO646_STRING: + case GENERAL_STRING: + b = toIso88591(str); + break; + + case UNIVERSAL_STRING: + case BMP_STRING: + b = toUtf16Be(str); + break; + + case UTF8_STRING: + default: + b = toUtf8(str); + break; + } + writeLength(out, b.length); + out.write(b); + return b.length; + } + + private static byte[] toIso88591(String string) + { + byte[] result = new byte[string.length()]; + for (int i = 0; i < string.length(); i++) + result[i] = (byte) string.charAt(i); + return result; + } + + private static byte[] toUtf16Be(String string) + { + byte[] result = new byte[string.length() * 2]; + for (int i = 0; i < string.length(); i++) + { + result[i*2 ] = (byte) ((string.charAt(i) >>> 8) & 0xFF); + result[i*2+1] = (byte) (string.charAt(i) & 0xFF); + } + return result; + } + + private static byte[] toUtf8(String string) + { + ByteArrayOutputStream buf = + new ByteArrayOutputStream((int)(string.length() * 1.5)); + for (int i = 0; i < string.length(); i++) + { + char c = string.charAt(i); + if (c < 0x0080) + buf.write(c & 0xFF); + else if (c < 0x0800) + { + buf.write(0xC0 | ((c >>> 6) & 0x3F)); + buf.write(0x80 | (c & 0x3F)); + } + else + { + buf.write(0xE0 | ((c >>> 12) & 0x0F)); + buf.write(0x80 | ((c >>> 6) & 0x3F)); + buf.write(0x80 | (c & 0x3F)); + } + } + return buf.toByteArray(); + } + + private static int writeDate(OutputStream out, int tag, Date date) + throws IOException + { + SimpleDateFormat sdf = null; + if ((tag & 0x1F) == UTC_TIME) + sdf = new SimpleDateFormat("yyMMddHHmmss'Z'"); + else + sdf = new SimpleDateFormat("yyyyMMddHHmmss'.'SSS'Z'"); + sdf.setTimeZone(TimeZone.getTimeZone("UTC")); + byte[] b = sdf.format(date).getBytes("ISO-8859-1"); + writeLength(out, b.length); + out.write(b); + return b.length; + } + + // Package method. + // ------------------------------------------------------------------------ + + static void writeLength(OutputStream out, int len) throws IOException + { + if (len < 128) + out.write(len); + else if (len < 256) + { + out.write(0x81); + out.write(len); + } + else if (len < 65536) + { + out.write(0x82); + out.write(len >> 8); + out.write(len); + } + else if (len < 16777216) + { + out.write(0x83); + out.write(len >> 16); + out.write(len >> 8); + out.write(len); + } + else + { + out.write(0x84); + out.write(len >> 24); + out.write(len >> 16); + out.write(len >> 8); + out.write(len); + } + } +} diff --git a/libjava/classpath/gnu/java/security/der/package.html b/libjava/classpath/gnu/java/security/der/package.html new file mode 100644 index 0000000..e74b0db --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/package.html @@ -0,0 +1,46 @@ + + + + +
+ * SignedData ::= SEQUENCE { + * version Version, + * digestAlgorithms DigestAlgorithmIdentifiers, + * contentInfo ContentInfo, + * certificates + * [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL, + * crls + * [1] IMPLICIT CertificateRevocationLists OPTIONAL, + * signerInfos SignerInfos } + * + * Version ::= INTEGER + * + * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + * + * ContentType ::= OBJECT IDENTIFIER + * + * ExtendedCertificatesAndCertificates ::= + * SET OF ExtendedCertificatesAndCertificate + * + * ExtendedCertificatesAndCertificate ::= CHOICE { + * certificate Certificate, -- from X.509 + * extendedCertificate [0] IMPLICIT ExtendedCertificate } + * + * CertificateRevocationLists ::= SET OF CertificateRevocationList + * -- from X.509 + * + * SignerInfos ::= SET OF SignerInfo + * + * SignerInfo ::= SEQUENCE { + * version Version, + * issuerAndSerialNumber IssuerAndSerialNumber, + * digestAlgorithm DigestAlgorithmIdentifier, + * authenticatedAttributes + * [0] IMPLICIT Attributes OPTIONAL, + * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + * encryptedDigest EncryptedDigest, + * unauthenticatedAttributes + * [1] IMPLICIT Attributes OPTIONAL } + * + * EncryptedDigest ::= OCTET STRING + *+ * + *
(Readers who are confused as to why it takes 40 levels of indirection + * to specify "data with a signature", rest assured that the present author + * is as confused as you are).
+ */ + public PKCS7SignedData(BERReader ber) + throws CRLException, CertificateException, IOException + { + CertificateFactory x509 = CertificateFactory.getInstance("X509"); + DERValue val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed ContentInfo"); + + val = ber.read(); + if (val.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed ContentType"); + + if (!PKCS7_SIGNED_DATA.equals(val.getValue())) + throw new BEREncodingException("content is not SignedData"); + + val = ber.read(); + if (val.getTag() != 0) + throw new BEREncodingException("malformed Content"); + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed SignedData"); + + if (DEBUG) + debug("SignedData: " + val); + + val = ber.read(); + if (val.getTag() != BER.INTEGER) + throw new BEREncodingException("expecting Version"); + version = (BigInteger) val.getValue(); + + if (DEBUG) + debug(" Version: " + version); + + digestAlgorithms = new HashSet(); + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed DigestAlgorithmIdentifiers"); + if (DEBUG) + debug(" DigestAlgorithmIdentifiers: " + val); + int count = 0; + DERValue val2 = ber.read(); + while (val2 != BER.END_OF_SEQUENCE && + (val.getLength() > 0 && val.getLength() > count)) + { + if (!val2.isConstructed()) + throw new BEREncodingException("malformed AlgorithmIdentifier"); + if (DEBUG) + debug(" AlgorithmIdentifier: " + val2); + count += val2.getEncodedLength(); + val2 = ber.read(); + if (val2.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed AlgorithmIdentifier"); + if (DEBUG) + debug(" ID: " + val2.getValue()); + List algId = new ArrayList(2); + algId.add(val2.getValue()); + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + { + count += val2.getEncodedLength(); + if (val2.getTag() == BER.NULL) + algId.add(null); + else + algId.add(val2.getEncoded()); + if (DEBUG) + debug(" params: " + new BigInteger(1, val2.getEncoded()).toString(16)); + if (val2.isConstructed()) + ber.skip(val2.getLength()); + if (BERValue.isIndefinite(val)) + val2 = ber.read(); + } + else + algId.add(null); + digestAlgorithms.add(algId); + } + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed ContentInfo"); + if (DEBUG) + debug(" ContentInfo: " + val); + val2 = ber.read(); + if (val2.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed ContentType"); + contentType = (OID) val2.getValue(); + if (DEBUG) + debug(" ContentType: " + contentType); + if (BERValue.isIndefinite(val) + || (val.getLength() > 0 && val.getLength() > val2.getEncodedLength())) + { + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + { + content = val2.getEncoded(); + if (BERValue.isIndefinite(val)) + val2 = ber.read(); + if (DEBUG) + debug(" Content: " + new BigInteger(1, content).toString(16)); + } + } + + val = ber.read(); + if (val.getTag() == 0) + { + if (!val.isConstructed()) + throw new BEREncodingException("malformed ExtendedCertificatesAndCertificates"); + if (DEBUG) + debug(" ExtendedCertificatesAndCertificates: " + val); + count = 0; + val2 = ber.read(); + List certs = new LinkedList(); + while (val2 != BER.END_OF_SEQUENCE && + (val.getLength() > 0 && val.getLength() > count)) + { + Certificate cert = + x509.generateCertificate(new ByteArrayInputStream(val2.getEncoded())); + if (DEBUG) + debug(" Certificate: " + cert); + certs.add(cert); + count += val2.getEncodedLength(); + ber.skip(val2.getLength()); + if (BERValue.isIndefinite(val) || val.getLength() > count) + val2 = ber.read(); + } + certificates = (Certificate[]) certs.toArray(new Certificate[certs.size()]); + val = ber.read(); + } + + if (val.getTag() == 1) + { + if (!val.isConstructed()) + throw new BEREncodingException("malformed CertificateRevocationLists"); + if (DEBUG) + debug(" CertificateRevocationLists: " + val); + count = 0; + val2 = ber.read(); + List crls = new LinkedList(); + while (val2 != BER.END_OF_SEQUENCE && + (val.getLength() > 0 && val.getLength() > count)) + { + CRL crl = x509.generateCRL(new ByteArrayInputStream(val2.getEncoded())); + if (DEBUG) + debug (" CRL: " + crl); + crls.add(crl); + count += val2.getEncodedLength(); + ber.skip(val2.getLength()); + if (BERValue.isIndefinite(val) || val.getLength() > count) + val2 = ber.read(); + } + this.crls = (CRL[]) crls.toArray(new CRL[crls.size()]); + val = ber.read(); + } + + signerInfos = new HashSet(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed SignerInfos"); + + if (DEBUG) + debug(" SignerInfos: " + val); + + // FIXME read this more carefully. + // Since we are just reading a file (probably) we just read until we + // reach the end. + while (true) + { + int i = ber.peek(); + if (i == 0 || i == -1) + break; + signerInfos.add(new SignerInfo(ber)); + } + } + + public BigInteger getVersion() + { + return version; + } + + public Certificate[] getCertificates() + { + return (certificates != null ? (Certificate[]) certificates.clone() + : null); + } + + public OID getContentType() + { + return contentType; + } + + public byte[] getContent() + { + return (content != null ? (byte[]) content.clone() : null); + } + + public Set getDigestAlgorithms() + { + // FIXME copy contents too, they are mutable!!! + return Collections.unmodifiableSet(digestAlgorithms); + } + + public Set getSignerInfos() + { + Set copy = new HashSet(); + for (Iterator it = signerInfos.iterator(); it.hasNext(); ) + copy.add(it.next()); + return Collections.unmodifiableSet(copy); + } +} diff --git a/libjava/classpath/gnu/java/security/pkcs/SignerInfo.java b/libjava/classpath/gnu/java/security/pkcs/SignerInfo.java new file mode 100644 index 0000000..c976799 --- /dev/null +++ b/libjava/classpath/gnu/java/security/pkcs/SignerInfo.java @@ -0,0 +1,279 @@ +/* SignerInfo.java -- a SignerInfo object, from PKCS #7 + Copyright (C) 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 gnu.java.security.pkcs; + +import gnu.java.security.OID; +import gnu.java.security.ber.BER; +import gnu.java.security.ber.BEREncodingException; +import gnu.java.security.ber.BERReader; +import gnu.java.security.ber.BERValue; +import gnu.java.security.der.DERValue; + +import java.io.IOException; + +import java.math.BigInteger; + +import javax.security.auth.x500.X500Principal; + +public class SignerInfo +{ + private final BigInteger version; + private final BigInteger serialNumber; + private final X500Principal issuer; + private final OID digestAlgorithmId; + private final byte[] digestAlgorithmParams; + private final byte[] authenticatedAttributes; + private final OID digestEncryptionAlgorithmId; + private final byte[] digestEncryptionAlgorithmParams; + private final byte[] encryptedDigest; + private final byte[] unauthenticatedAttributes; + + private static final boolean DEBUG = false; + private static void debug(String msg) + { + System.err.print("SignerInfo >> "); + System.err.println(msg); + } + + /** + * Parse a SignerInfo object. + */ + public SignerInfo(BERReader ber) throws IOException + { + DERValue val = ber.read(); + if (DEBUG) + debug("SignerInfo: " + val); + if (!val.isConstructed()) + throw new BEREncodingException("malformed SignerInfo"); + + val = ber.read(); + if (val.getTag() != BER.INTEGER) + throw new BEREncodingException("malformed Version"); + version = (BigInteger) val.getValue(); + + if (DEBUG) + debug(" Version: " + version); + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed IssuerAndSerialNumber"); + + if (DEBUG) + debug(" IssuerAndSerialNumber: " + val); + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed Issuer"); + issuer = new X500Principal(val.getEncoded()); + ber.skip(val.getLength()); + if (DEBUG) + debug(" Issuer: " + issuer); + + val = ber.read(); + if (val.getTag() != BER.INTEGER) + throw new BEREncodingException("malformed SerialNumber"); + serialNumber = (BigInteger) val.getValue(); + if (DEBUG) + debug(" SerialNumber: " + serialNumber); + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed DigestAlgorithmIdentifier"); + if (DEBUG) + debug(" DigestAlgorithmIdentifier: " + val); + + int count = 0; + DERValue val2 = ber.read(); + if (val2.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed AlgorithmIdentifier"); + digestAlgorithmId = (OID) val2.getValue(); + if (DEBUG) + debug(" OID: " + digestAlgorithmId); + + if (BERValue.isIndefinite(val)) + { + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + { + digestAlgorithmParams = val2.getEncoded(); + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + throw new BEREncodingException("expecting BER end-of-sequence"); + } + else + digestAlgorithmParams = null; + } + else if (val2.getEncodedLength() < val.getLength()) + { + val2 = ber.read(); + digestAlgorithmParams = val2.getEncoded(); + if (val2.isConstructed()) + ber.skip(val2.getLength()); + } + else + digestAlgorithmParams = null; + if(DEBUG) + debug(" params: " + (digestAlgorithmParams == null ? null + : new BigInteger(digestAlgorithmParams).toString(16))); + + val = ber.read(); + if (val.getTag() == 0) + { + authenticatedAttributes = val.getEncoded(); + val = ber.read(); + if (val.isConstructed()) + ber.skip(val.getLength()); + if (DEBUG) + debug(" AuthenticatedAttributes: " + val); + val = ber.read(); + } + else + authenticatedAttributes = null; + + if (!val.isConstructed()) + throw new BEREncodingException("malformed DigestEncryptionAlgorithmIdentifier"); + if (DEBUG) + debug(" DigestEncryptionAlgorithmIdentifier: " + val); + count = 0; + val2 = ber.read(); + if (val2.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed AlgorithmIdentifier"); + digestEncryptionAlgorithmId = (OID) val2.getValue(); + if (DEBUG) + debug(" OID: " + digestEncryptionAlgorithmId); + + if (BERValue.isIndefinite(val)) + { + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + { + digestEncryptionAlgorithmParams = val2.getEncoded(); + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + throw new BEREncodingException("expecting BER end-of-sequence"); + } + else + digestEncryptionAlgorithmParams = null; + } + else if (val2.getEncodedLength() < val.getLength()) + { + val2 = ber.read(); + digestEncryptionAlgorithmParams = val2.getEncoded(); + if (val2.isConstructed()) + ber.skip(val2.getLength()); + } + else + digestEncryptionAlgorithmParams = null; + if(DEBUG) + debug(" params: " + (digestEncryptionAlgorithmParams == null ? null + : new BigInteger(digestEncryptionAlgorithmParams).toString(16))); + + val = ber.read(); + if (val.getTag() != BER.OCTET_STRING) + throw new BEREncodingException("malformed EncryptedDigest"); + encryptedDigest = (byte[]) val.getValue(); + if (DEBUG) + debug(" EncryptedDigest: " + new BigInteger(1, encryptedDigest).toString(16)); + + if (ber.peek() == 1) + unauthenticatedAttributes = ber.read().getEncoded(); + else + unauthenticatedAttributes = null; + + if (ber.peek() == 0) + ber.read(); + } + + public BigInteger getVersion() + { + return version; + } + + public BigInteger getSerialNumber() + { + return serialNumber; + } + + public X500Principal getIssuer() + { + return issuer; + } + + public OID getDigestAlgorithmId() + { + return digestAlgorithmId; + } + + public byte[] getDigestAlgorithmParams() + { + return (digestAlgorithmParams != null + ? (byte[]) digestAlgorithmParams.clone() + : null); + } + + public byte[] getAuthenticatedAttributes() + { + return (authenticatedAttributes != null + ? (byte[]) authenticatedAttributes.clone() + : null); + } + + public OID getDigestEncryptionAlgorithmId() + { + return digestEncryptionAlgorithmId; + } + + public byte[] getDigestEncryptionAlgorithmParams() + { + return (digestEncryptionAlgorithmParams != null + ? (byte[]) digestEncryptionAlgorithmParams.clone() + : null); + } + + public byte[] getEncryptedDigest() + { + return (encryptedDigest != null ? (byte[]) encryptedDigest.clone() : null); + } + + public byte[] getUnauthenticatedAttributes() + { + return (unauthenticatedAttributes != null + ? (byte[]) unauthenticatedAttributes.clone() + : null); + } +} diff --git a/libjava/classpath/gnu/java/security/pkcs/package.html b/libjava/classpath/gnu/java/security/pkcs/package.html new file mode 100644 index 0000000..60d658f --- /dev/null +++ b/libjava/classpath/gnu/java/security/pkcs/package.html @@ -0,0 +1,46 @@ + + + + +PrivateKeyInfo
, as described in
+ * PKCS #8. The ASN.1 specification for this structure is:
+ *
+ * + * + *+ * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] IMPLICIT Attributes OPTIONAL } + * + * Version ::= INTEGER + * + * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + * + * PrivateKey ::= OCTET STRING + * + * Attributes ::= SET OF Attribute + *
DSA private keys (in Classpath at least) have no attributes. + */ + public byte[] getEncoded() + { + if (encodedKey != null) + return (byte[]) encodedKey.clone(); + try + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ArrayList pki = new ArrayList(3); + pki.add(new DERValue(DER.INTEGER, BigInteger.ZERO)); + ArrayList algId = new ArrayList(2); + algId.add(new DERValue(DER.OBJECT_IDENTIFIER, + new OID("1.2.840.10040.4.1"))); + ArrayList algParams = new ArrayList(3); + algParams.add(new DERValue(DER.INTEGER, p)); + algParams.add(new DERValue(DER.INTEGER, q)); + algParams.add(new DERValue(DER.INTEGER, g)); + algId.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, algParams)); + pki.add(new DERValue(DER.OCTET_STRING, x.toByteArray())); + DERWriter.write(out, new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, pki)); + return (byte[]) (encodedKey = out.toByteArray()).clone(); + } + catch (IOException ioe) + { + return null; + } + } + + public DSAParams getParams() + { + return (DSAParams)(new DSAParameterSpec(p,q,g)); + } + + public BigInteger getX() + { + return x; + } + + public String toString() + { + return "GnuDSAPrivateKey: x=" + + (x != null ? x.toString(16) : "null") + " p=" + + (p != null ? p.toString(16) : "null") + " q=" + + (q != null ? q.toString(16) : "null") + " g=" + + (g != null ? g.toString(16) : "null"); + } +} diff --git a/libjava/classpath/gnu/java/security/provider/GnuDSAPublicKey.java b/libjava/classpath/gnu/java/security/provider/GnuDSAPublicKey.java new file mode 100644 index 0000000..41195fa --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/GnuDSAPublicKey.java @@ -0,0 +1,137 @@ +/* GnuDSAPublicKey.java --- Gnu DSA Public Key + Copyright (C) 1999,2003,2004 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 gnu.java.security.provider; + +import gnu.java.security.OID; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; +import java.security.spec.DSAParameterSpec; +import java.util.ArrayList; + +public class GnuDSAPublicKey implements DSAPublicKey +{ + private byte[] encodedKey; + BigInteger y; + BigInteger p; + BigInteger q; + BigInteger g; + + public GnuDSAPublicKey(BigInteger y, BigInteger p, BigInteger q, BigInteger g ) + { + this.y = y; + this.p = p; + this.q = q; + this.g = g; + } + + public String getAlgorithm() + { + return "DSA"; + } + + public String getFormat() + { + return "X.509"; + } + + /** + * The encoded form of DSA public keys is: + * + *
+ */ + public byte[] getEncoded() + { + if (encodedKey != null) + return (byte[]) encodedKey.clone(); + try + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ArrayList spki = new ArrayList(2); + ArrayList alg = new ArrayList(2); + alg.add(new DERValue(DER.OBJECT_IDENTIFIER, + new OID("1.2.840.113549.1.1.1"))); + ArrayList params = new ArrayList(3); + params.add(new DERValue(DER.INTEGER, p)); + params.add(new DERValue(DER.INTEGER, q)); + params.add(new DERValue(DER.INTEGER, g)); + alg.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, params)); + spki.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, alg)); + spki.add(new DERValue(DER.BIT_STRING, new BitString(y.toByteArray()))); + DERWriter.write(out, new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, spki)); + return (byte[]) (encodedKey = out.toByteArray()).clone(); + } + catch (IOException ioe) + { + return null; + } + } + + public DSAParams getParams() + { + if (p == null || q == null || g == null) + return null; + return (DSAParams)(new DSAParameterSpec(p,q,g)); + } + + public BigInteger getY() + { + return y; + } + + public String toString() + { + return + "GnuDSAPublicKey: y=" + (y != null ? y.toString(16) : "(null)") + + " p=" + (p != null ? p.toString(16) : "(null)") + + " q=" + (q != null ? q.toString(16) : "(null)") + + " g=" + (g != null ? g.toString(16) : "(null)"); + } +} diff --git a/libjava/classpath/gnu/java/security/provider/GnuRSAPrivateKey.java b/libjava/classpath/gnu/java/security/provider/GnuRSAPrivateKey.java new file mode 100644 index 0000000..b09fc88 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/GnuRSAPrivateKey.java @@ -0,0 +1,164 @@ +/* GnuRSAPrivateKey.java -- GNU RSA private key. + Copyright (C) 2004 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 gnu.java.security.provider; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERValue; + +import java.math.BigInteger; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.util.ArrayList; + +class GnuRSAPrivateKey implements RSAPrivateCrtKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final RSAPrivateCrtKeySpec spec; + private byte[] encodedKey; + + // Constructor. + // ------------------------------------------------------------------------- + + public GnuRSAPrivateKey(RSAPrivateCrtKeySpec spec) + { + this.spec = spec; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public BigInteger getModulus() + { + return spec.getModulus(); + } + + public BigInteger getPrivateExponent() + { + return spec.getPrivateExponent(); + } + + public BigInteger getCrtCoefficient() + { + return spec.getCrtCoefficient(); + } + + public BigInteger getPrimeExponentP() + { + return spec.getPrimeExponentP(); + } + + public BigInteger getPrimeExponentQ() + { + return spec.getPrimeExponentQ(); + } + + public BigInteger getPrimeP() + { + return spec.getPrimeP(); + } + + public BigInteger getPrimeQ() + { + return spec.getPrimeQ(); + } + + public BigInteger getPublicExponent() + { + return spec.getPublicExponent(); + } + + public String getAlgorithm() + { + return "RSA"; + } + + public String getFormat() + { + return "PKCS#8"; + } + + /** + * The encoded form is: + * + *+ * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + *
+ * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER -- (inverse of q) mod p } + *+ * + *
Which is in turn encoded in a PrivateKeyInfo structure from PKCS#8. + */ + public byte[] getEncoded() + { + if (encodedKey != null) + return (byte[]) encodedKey.clone(); + ArrayList key = new ArrayList(9); + key.add(new DERValue(DER.INTEGER, BigInteger.ZERO)); + key.add(new DERValue(DER.INTEGER, getModulus())); + key.add(new DERValue(DER.INTEGER, getPublicExponent())); + key.add(new DERValue(DER.INTEGER, getPrivateExponent())); + key.add(new DERValue(DER.INTEGER, getPrimeP())); + key.add(new DERValue(DER.INTEGER, getPrimeQ())); + key.add(new DERValue(DER.INTEGER, getPrimeExponentP())); + key.add(new DERValue(DER.INTEGER, getPrimeExponentQ())); + key.add(new DERValue(DER.INTEGER, getCrtCoefficient())); + DERValue pk = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, key); + ArrayList pki = new ArrayList(3); + pki.add(new DERValue(DER.INTEGER, BigInteger.ZERO)); + ArrayList alg = new ArrayList(2); + alg.add(new DERValue(DER.OBJECT_IDENTIFIER, + new OID("1.2.840.113549.1.1.1"))); + alg.add(new DERValue(DER.NULL, null)); + pki.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, alg)); + pki.add(new DERValue(DER.OCTET_STRING, pk.getEncoded())); + encodedKey = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, pki).getEncoded(); + return (byte[]) encodedKey.clone(); + } +} diff --git a/libjava/classpath/gnu/java/security/provider/GnuRSAPublicKey.java b/libjava/classpath/gnu/java/security/provider/GnuRSAPublicKey.java new file mode 100644 index 0000000..a35e761 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/GnuRSAPublicKey.java @@ -0,0 +1,109 @@ +/* GnuRSAPublicKey.java -- GNU RSA public key. + Copyright (C) 2004 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 gnu.java.security.provider; + +import gnu.java.security.OID; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERValue; + +import java.math.BigInteger; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.RSAPublicKeySpec; +import java.util.ArrayList; + +class GnuRSAPublicKey implements RSAPublicKey +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final RSAPublicKeySpec spec; + private byte[] encodedKey; + + // Constructor. + // ------------------------------------------------------------------------- + + public GnuRSAPublicKey(RSAPublicKeySpec spec) + { + this.spec = spec; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public BigInteger getModulus() + { + return spec.getModulus(); + } + + public BigInteger getPublicExponent() + { + return spec.getPublicExponent(); + } + + public String getAlgorithm() + { + return "RSA"; + } + + public String getFormat() + { + return "X.509"; + } + + public byte[] getEncoded() + { + if (encodedKey != null) + return (byte[]) encodedKey.clone(); + ArrayList key = new ArrayList(2); + key.add(new DERValue(DER.INTEGER, getModulus())); + key.add(new DERValue(DER.INTEGER, getPublicExponent())); + DERValue rsapk = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, key); + ArrayList alg = new ArrayList(2); + alg.add(new DERValue(DER.OBJECT_IDENTIFIER, + new OID("1.2.840.113549.1.1.1"))); + alg.add(new DERValue(DER.NULL, null)); + ArrayList spki = new ArrayList(2); + spki.add(new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, alg)); + spki.add(new DERValue(DER.BIT_STRING, new BitString(rsapk.getEncoded()))); + encodedKey = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, spki).getEncoded(); + return (byte[]) encodedKey.clone(); + } +} diff --git a/libjava/classpath/gnu/java/security/provider/MD2withRSA.java b/libjava/classpath/gnu/java/security/provider/MD2withRSA.java new file mode 100644 index 0000000..a72ae55 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/MD2withRSA.java @@ -0,0 +1,54 @@ +/* MD2withRSA.java -- MD2 with RSA encryption signatures. + Copyright (C) 2004 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 gnu.java.security.provider; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD2withRSA extends RSA +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public MD2withRSA() throws NoSuchAlgorithmException + { + super(MessageDigest.getInstance("MD2"), DIGEST_ALGORITHM.getChild(2)); + } +} diff --git a/libjava/classpath/gnu/java/security/provider/MD4withRSA.java b/libjava/classpath/gnu/java/security/provider/MD4withRSA.java new file mode 100644 index 0000000..76a6a1a --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/MD4withRSA.java @@ -0,0 +1,54 @@ +/* MD4withRSA.java -- MD4 with RSA encryption signatures. + Copyright (C) 2004 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 gnu.java.security.provider; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD4withRSA extends RSA +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public MD4withRSA() throws NoSuchAlgorithmException + { + super(MessageDigest.getInstance("MD4"), DIGEST_ALGORITHM.getChild(4)); + } +} diff --git a/libjava/classpath/gnu/java/security/provider/MD5.java b/libjava/classpath/gnu/java/security/provider/MD5.java new file mode 100644 index 0000000..1534eb9 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/MD5.java @@ -0,0 +1,338 @@ +/* MD5.java -- Class implementing the MD5 algorithm as specified in RFC1321. + Copyright (C) 1999, 2002 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 gnu.java.security.provider; +import java.security.MessageDigest; + +/** + This class implements the MD5 algorithm as described in RFC1321. + + @see java.security.MessageDigest +*/ +public class MD5 extends MessageDigest implements Cloneable +{ + private final int W[] = new int[16]; + private long bytecount; + private int A; + private int B; + private int C; + private int D; + + public MD5() + { + super("MD5"); + engineReset (); + } + + public Object clone() + { + return new MD5 (this); + } + + private MD5 (MD5 copy) + { + this (); + bytecount = copy.bytecount; + A = copy.A; + B = copy.B; + C = copy.C; + D = copy.D; + System.arraycopy (copy.W, 0, W, 0, 16); + } + + public int engineGetDigestLength() + { + return 16; + } + + // Intialize the A,B,C,D needed for the hash + public void engineReset() + { + bytecount = 0; + A = 0x67452301; + B = 0xefcdab89; + C = 0x98badcfe; + D = 0x10325476; + for(int i = 0; i < 16; i++) + W[i] = 0; + } + + public void engineUpdate (byte b) + { + int i = (int)bytecount % 64; + int shift = (3 - i % 4) * 8; + int idx = i / 4; + + // if you could index ints, this would be: W[idx][shift/8] = b + W[idx] = (W[idx] & ~(0xff << shift)) | ((b & 0xff) << shift); + + // if we've filled up a block, then process it + if ((++ bytecount) % 64 == 0) + munch (); + } + + public void engineUpdate (byte bytes[], int off, int len) + { + if (len < 0) + throw new ArrayIndexOutOfBoundsException (); + + int end = off + len; + while (off < end) + engineUpdate (bytes[off++]); + } + + public byte[] engineDigest() + { + long bitcount = bytecount * 8; + engineUpdate ((byte)0x80); // 10000000 in binary; the start of the padding + + // add the rest of the padding to fill this block out, but leave 8 + // bytes to put in the original bytecount + while ((int)bytecount % 64 != 56) + engineUpdate ((byte)0); + + // add the length of the original, unpadded block to the end of + // the padding + W[14] = SWAP((int)(0xffffffff & bitcount)); + W[15] = SWAP((int)(0xffffffff & (bitcount >>> 32))); + bytecount += 8; + + // digest the fully padded block + munch (); + + A = SWAP(A); + B = SWAP(B); + C = SWAP(C); + D = SWAP(D); + byte[] result = new byte[] {(byte)(A >>> 24), (byte)(A >>> 16), + (byte)(A >>> 8), (byte)A, + (byte)(B >>> 24), (byte)(B >>> 16), + (byte)(B >>> 8), (byte)B, + (byte)(C >>> 24), (byte)(C >>> 16), + (byte)(C >>> 8), (byte)C, + (byte)(D >>> 24), (byte)(D >>> 16), + (byte)(D >>> 8), (byte)D}; + + engineReset (); + return result; + } + + private int F( int X, int Y, int Z) + { + return ((X & Y) | (~X & Z)); + } + + private int G( int X, int Y, int Z) + { + return ((X & Z) | (Y & ~Z)); + } + + private int H( int X, int Y, int Z) + { + return (X ^ Y ^ Z); + } + + private int I( int X, int Y, int Z) + { + return (Y ^ (X | ~Z)); + } + + private int rotateLeft( int i, int count) + { + //Taken from FIPS 180-1 + return ( (i << count) | (i >>> (32 - count)) ) ; + } + + /* Round 1. */ + private int FF( int a, int b, int c, int d, int k, int s, int i) + { + /* Let [abcd k s i] denote the operation */ + a += F(b,c,d) + k + i; + return b + rotateLeft(a, s); + } + /* Round 2. */ + private int GG( int a, int b, int c, int d, int k, int s, int i) + { + /* Let [abcd k s i] denote the operation */ + a += G(b,c,d) + k + i; + return b + rotateLeft(a, s); + } + /* Round 3. */ + private int HH( int a, int b, int c, int d, int k, int s, int i) + { + /* Let [abcd k s t] denote the operation */ + a += H(b,c,d) + k + i; + return b + rotateLeft(a, s); + } + + /* Round 4. */ + private int II( int a, int b, int c, int d, int k, int s, int i) + { + /* Let [abcd k s t] denote the operation */ + a += I(b,c,d) + k + i; + return b + rotateLeft(a, s); + } + + private int SWAP(int n) + { + //Copied from md5.c in FSF Gnu Privacy Guard 0.9.2 + return (( (0xff & n) << 24) | ((n & 0xff00) << 8) | ((n >>> 8) & 0xff00) | (n >>> 24)); + } + + private void munch() + { + int AA,BB,CC,DD, j; + int X[] = new int[16]; + + /* Copy block i into X. */ + for(j = 0; j < 16; j++) + X[j] = SWAP(W[j]); + + /* Save A as AA, B as BB, C as CC, and D as DD. */ + AA = A; + BB = B; + CC = C; + DD = D; + + /* The hex constants are from md5.c + in FSF Gnu Privacy Guard 0.9.2 */ + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ + /* Do the following 16 operations. */ + A = FF(A,B,C,D, X[0], 7, 0xd76aa478); + D = FF(D,A,B,C, X[1], 12, 0xe8c7b756); + C = FF(C,D,A,B, X[2], 17, 0x242070db); + B = FF(B,C,D,A, X[3], 22, 0xc1bdceee); + + A = FF(A,B,C,D, X[4], 7, 0xf57c0faf); + D = FF(D,A,B,C, X[5], 12, 0x4787c62a); + C = FF(C,D,A,B, X[6], 17, 0xa8304613); + B = FF(B,C,D,A, X[7], 22, 0xfd469501); + + A = FF(A,B,C,D, X[8], 7, 0x698098d8); + D = FF(D,A,B,C, X[9], 12, 0x8b44f7af); + C = FF(C,D,A,B, X[10], 17, 0xffff5bb1); + B = FF(B,C,D,A, X[11], 22, 0x895cd7be); + + A = FF(A,B,C,D, X[12], 7, 0x6b901122); + D = FF(D,A,B,C, X[13], 12, 0xfd987193); + C = FF(C,D,A,B, X[14], 17, 0xa679438e); + B = FF(B,C,D,A, X[15], 22, 0x49b40821); + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ + /* Do the following 16 operations. */ + A = GG(A,B,C,D, X[1], 5, 0xf61e2562); + D = GG(D,A,B,C, X[6], 9, 0xc040b340); + C = GG(C,D,A,B, X[11], 14, 0x265e5a51); + B = GG(B,C,D,A, X[0], 20, 0xe9b6c7aa); + + A = GG(A,B,C,D, X[5], 5, 0xd62f105d); + D = GG(D,A,B,C, X[10], 9, 0x02441453); + C = GG(C,D,A,B, X[15], 14, 0xd8a1e681); + B = GG(B,C,D,A, X[4], 20, 0xe7d3fbc8); + + A = GG(A,B,C,D, X[9], 5, 0x21e1cde6); + D = GG(D,A,B,C, X[14], 9, 0xc33707d6); + C = GG(C,D,A,B, X[3], 14, 0xf4d50d87); + B = GG(B,C,D,A, X[8], 20, 0x455a14ed); + + A = GG(A,B,C,D, X[13], 5, 0xa9e3e905); + D = GG(D,A,B,C, X[2], 9, 0xfcefa3f8); + C = GG(C,D,A,B, X[7], 14, 0x676f02d9); + B = GG(B,C,D,A, X[12], 20, 0x8d2a4c8a); + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ + /* Do the following 16 operations. */ + A = HH(A,B,C,D, X[5], 4, 0xfffa3942); + D = HH(D,A,B,C, X[8], 11, 0x8771f681); + C = HH(C,D,A,B, X[11], 16, 0x6d9d6122); + B = HH(B,C,D,A, X[14], 23, 0xfde5380c); + + A = HH(A,B,C,D, X[1], 4, 0xa4beea44); + D = HH(D,A,B,C, X[4], 11, 0x4bdecfa9); + C = HH(C,D,A,B, X[7], 16, 0xf6bb4b60); + B = HH(B,C,D,A, X[10], 23, 0xbebfbc70); + + A = HH(A,B,C,D, X[13], 4, 0x289b7ec6); + D = HH(D,A,B,C, X[0], 11, 0xeaa127fa); + C = HH(C,D,A,B, X[3], 16, 0xd4ef3085); + B = HH(B,C,D,A, X[6], 23, 0x04881d05); + + A = HH(A,B,C,D, X[9], 4, 0xd9d4d039); + D = HH(D,A,B,C, X[12], 11, 0xe6db99e5); + C = HH(C,D,A,B, X[15], 16, 0x1fa27cf8); + B = HH(B,C,D,A, X[2], 23, 0xc4ac5665); + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ + /* Do the following 16 operations. */ + A = II(A,B,C,D, X[0], 6, 0xf4292244); + D = II(D,A,B,C, X[7], 10, 0x432aff97); + C = II(C,D,A,B, X[14], 15, 0xab9423a7); + B = II(B,C,D,A, X[5], 21, 0xfc93a039); + + A = II(A,B,C,D, X[12], 6, 0x655b59c3); + D = II(D,A,B,C, X[3], 10, 0x8f0ccc92); + C = II(C,D,A,B, X[10], 15, 0xffeff47d); + B = II(B,C,D,A, X[1], 21, 0x85845dd1); + + A = II(A,B,C,D, X[8], 6, 0x6fa87e4f); + D = II(D,A,B,C, X[15], 10, 0xfe2ce6e0); + C = II(C,D,A,B, X[6], 15, 0xa3014314); + B = II(B,C,D,A, X[13], 21, 0x4e0811a1); + + A = II(A,B,C,D, X[4], 6, 0xf7537e82); + D = II(D,A,B,C, X[11], 10, 0xbd3af235); + C = II(C,D,A,B, X[2], 15, 0x2ad7d2bb); + B = II(B,C,D,A, X[9], 21, 0xeb86d391); + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + A = A + AA; + B = B + BB; + C = C + CC; + D = D + DD; + } +} diff --git a/libjava/classpath/gnu/java/security/provider/MD5withRSA.java b/libjava/classpath/gnu/java/security/provider/MD5withRSA.java new file mode 100644 index 0000000..721d897 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/MD5withRSA.java @@ -0,0 +1,54 @@ +/* MD5withRSA.java -- MD5 with RSA encryption signatures. + Copyright (C) 2004 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 gnu.java.security.provider; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD5withRSA extends RSA +{ + + // Constructor. + // ------------------------------------------------------------------------- + + public MD5withRSA() throws NoSuchAlgorithmException + { + super(MessageDigest.getInstance("MD5"), DIGEST_ALGORITHM.getChild(5)); + } +} diff --git a/libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java b/libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java new file mode 100644 index 0000000..1268b16 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java @@ -0,0 +1,701 @@ +/* PKIXCertPathValidatorImpl.java -- PKIX certificate path validator. + Copyright (C) 2004 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 gnu.java.security.provider; + +import gnu.java.security.OID; +import gnu.java.security.x509.GnuPKIExtension; +import gnu.java.security.x509.PolicyNodeImpl; +import gnu.java.security.x509.X509CRLSelectorImpl; +import gnu.java.security.x509.X509CertSelectorImpl; +import gnu.java.security.x509.ext.BasicConstraints; +import gnu.java.security.x509.ext.CertificatePolicies; +import gnu.java.security.x509.ext.Extension; +import gnu.java.security.x509.ext.KeyUsage; +import gnu.java.security.x509.ext.PolicyConstraint; + +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.PublicKey; +import java.security.cert.CRL; +import java.security.cert.CertPath; +import java.security.cert.CertPathParameters; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorResult; +import java.security.cert.CertPathValidatorSpi; +import java.security.cert.CertStore; +import java.security.cert.CertStoreException; +import java.security.cert.CertificateException; +import java.security.cert.PKIXCertPathChecker; +import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * An implementation of the Public Key Infrastructure's X.509 + * certificate path validation algorithm. + * + *
See RFC 3280: + * Internet X.509 Public Key Infrastructure Certificate and + * Certificate Revocation List (CRL) Profile. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class PKIXCertPathValidatorImpl extends CertPathValidatorSpi +{ + + // Constants. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG = false; + private static void debug (String msg) + { + System.err.print (">> PKIXCertPathValidatorImpl: "); + System.err.println (msg); + } + + public static final String ANY_POLICY = "2.5.29.32.0"; + + // Constructor. + // ------------------------------------------------------------------------- + + public PKIXCertPathValidatorImpl() + { + super(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public CertPathValidatorResult engineValidate(CertPath path, + CertPathParameters params) + throws CertPathValidatorException, InvalidAlgorithmParameterException + { + if (!(params instanceof PKIXParameters)) + throw new InvalidAlgorithmParameterException("not a PKIXParameters object"); + + // First check if the certificate path is valid. + // + // This means that: + // + // (a) for all x in {1, ..., n-1}, the subject of certificate x is + // the issuer of certificate x+1; + // + // (b) for all x in {1, ..., n}, the certificate was valid at the + // time in question. + // + // Because this is the X.509 algorithm, we also check if all + // cerificates are of type X509Certificate. + + PolicyNodeImpl rootNode = new PolicyNodeImpl(); + Set initPolicies = ((PKIXParameters) params).getInitialPolicies(); + rootNode.setValidPolicy(ANY_POLICY); + rootNode.setCritical(false); + rootNode.setDepth(0); + if (initPolicies != null) + rootNode.addAllExpectedPolicies(initPolicies); + else + rootNode.addExpectedPolicy(ANY_POLICY); + List checks = ((PKIXParameters) params).getCertPathCheckers(); + List l = path.getCertificates(); + if (l == null || l.size() == 0) + throw new CertPathValidatorException(); + X509Certificate[] p = null; + try + { + p = (X509Certificate[]) l.toArray(new X509Certificate[l.size()]); + } + catch (ClassCastException cce) + { + throw new CertPathValidatorException("invalid certificate path"); + } + + String sigProvider = ((PKIXParameters) params).getSigProvider(); + PublicKey prevKey = null; + Date now = ((PKIXParameters) params).getDate(); + if (now == null) + now = new Date(); + LinkedList policyConstraints = new LinkedList(); + for (int i = p.length - 1; i >= 0; i--) + { + try + { + p[i].checkValidity(now); + } + catch (CertificateException ce) + { + throw new CertPathValidatorException(ce.toString()); + } + Set uce = getCritExts(p[i]); + for (Iterator check = checks.iterator(); check.hasNext(); ) + { + try + { + ((PKIXCertPathChecker) check.next()).check(p[i], uce); + } + catch (Exception x) + { + } + } + + PolicyConstraint constr = null; + if (p[i] instanceof GnuPKIExtension) + { + Extension pcx = + ((GnuPKIExtension) p[i]).getExtension (PolicyConstraint.ID); + if (pcx != null) + constr = (PolicyConstraint) pcx.getValue(); + } + else + { + byte[] pcx = p[i].getExtensionValue (PolicyConstraint.ID.toString()); + if (pcx != null) + { + try + { + constr = new PolicyConstraint (pcx); + } + catch (Exception x) + { + } + } + } + if (constr != null && constr.getRequireExplicitPolicy() >= 0) + { + policyConstraints.add (new int[] + { p.length-i, constr.getRequireExplicitPolicy() }); + } + + updatePolicyTree(p[i], rootNode, p.length-i, (PKIXParameters) params, + checkExplicitPolicy (p.length-i, policyConstraints)); + + // The rest of the tests involve this cert's relationship with the + // next in the path. If this cert is the end entity, we can stop. + if (i == 0) + break; + + basicSanity(p, i); + PublicKey pubKey = null; + try + { + pubKey = p[i].getPublicKey(); + if (pubKey instanceof DSAPublicKey) + { + DSAParams dsa = ((DSAPublicKey) pubKey).getParams(); + // If the DSA public key is missing its parameters, use those + // from the previous cert's key. + if (dsa == null || dsa.getP() == null || dsa.getG() == null + || dsa.getQ() == null) + { + if (prevKey == null) + throw new InvalidKeyException("DSA keys not chainable"); + if (!(prevKey instanceof DSAPublicKey)) + throw new InvalidKeyException("DSA keys not chainable"); + dsa = ((DSAPublicKey) prevKey).getParams(); + pubKey = new GnuDSAPublicKey(((DSAPublicKey) pubKey).getY(), + dsa.getP(), dsa.getQ(), dsa.getG()); + } + } + if (sigProvider == null) + p[i-1].verify(pubKey); + else + p[i-1].verify(pubKey, sigProvider); + prevKey = pubKey; + } + catch (Exception e) + { + throw new CertPathValidatorException(e.toString()); + } + if (!p[i].getSubjectDN().equals(p[i-1].getIssuerDN())) + throw new CertPathValidatorException("issuer DN mismatch"); + boolean[] issuerUid = p[i-1].getIssuerUniqueID(); + boolean[] subjectUid = p[i].getSubjectUniqueID(); + if (issuerUid != null && subjectUid != null) + if (!Arrays.equals(issuerUid, subjectUid)) + throw new CertPathValidatorException("UID mismatch"); + + // Check the certificate against the revocation lists. + if (((PKIXParameters) params).isRevocationEnabled()) + { + X509CRLSelectorImpl selector = new X509CRLSelectorImpl(); + try + { + selector.addIssuerName(p[i].getSubjectDN()); + } + catch (IOException ioe) + { + throw new CertPathValidatorException("error selecting CRLs"); + } + List certStores = ((PKIXParameters) params).getCertStores(); + List crls = new LinkedList(); + for (Iterator it = certStores.iterator(); it.hasNext(); ) + { + CertStore cs = (CertStore) it.next(); + try + { + Collection c = cs.getCRLs(selector); + crls.addAll(c); + } + catch (CertStoreException cse) + { + } + } + if (crls.isEmpty()) + throw new CertPathValidatorException("no CRLs for issuer"); + boolean certOk = false; + for (Iterator it = crls.iterator(); it.hasNext(); ) + { + CRL crl = (CRL) it.next(); + if (!(crl instanceof X509CRL)) + continue; + X509CRL xcrl = (X509CRL) crl; + if (!checkCRL(xcrl, p, now, p[i], pubKey, certStores)) + continue; + if (xcrl.isRevoked(p[i-1])) + throw new CertPathValidatorException("certificate is revoked"); + else + certOk = true; + } + if (!certOk) + throw new CertPathValidatorException("certificate's validity could not be determined"); + } + } + rootNode.setReadOnly(); + + // Now ensure that the first certificate in the chain was issued + // by a trust anchor. + Exception cause = null; + Set anchors = ((PKIXParameters) params).getTrustAnchors(); + for (Iterator i = anchors.iterator(); i.hasNext(); ) + { + TrustAnchor anchor = (TrustAnchor) i.next(); + X509Certificate anchorCert = null; + PublicKey anchorKey = null; + if (anchor.getTrustedCert() != null) + { + anchorCert = anchor.getTrustedCert(); + anchorKey = anchorCert.getPublicKey(); + } + else + anchorKey = anchor.getCAPublicKey(); + if (anchorKey == null) + continue; + try + { + if (anchorCert == null) + anchorCert.checkValidity(now); + p[p.length-1].verify(anchorKey); + if (anchorCert != null && anchorCert.getBasicConstraints() >= 0 + && anchorCert.getBasicConstraints() < p.length) + continue; + + if (((PKIXParameters) params).isRevocationEnabled()) + { + X509CRLSelectorImpl selector = new X509CRLSelectorImpl(); + if (anchorCert != null) + try + { + selector.addIssuerName(anchorCert.getSubjectDN()); + } + catch (IOException ioe) + { + } + else + selector.addIssuerName(anchor.getCAName()); + List certStores = ((PKIXParameters) params).getCertStores(); + List crls = new LinkedList(); + for (Iterator it = certStores.iterator(); it.hasNext(); ) + { + CertStore cs = (CertStore) it.next(); + try + { + Collection c = cs.getCRLs(selector); + crls.addAll(c); + } + catch (CertStoreException cse) + { + } + } + if (crls.isEmpty()) + continue; + for (Iterator it = crls.iterator(); it.hasNext(); ) + { + CRL crl = (CRL) it.next(); + if (!(crl instanceof X509CRL)) + continue; + X509CRL xcrl = (X509CRL) crl; + try + { + xcrl.verify(anchorKey); + } + catch (Exception x) + { + continue; + } + Date nextUpdate = xcrl.getNextUpdate(); + if (nextUpdate != null && nextUpdate.compareTo(now) < 0) + continue; + if (xcrl.isRevoked(p[p.length-1])) + throw new CertPathValidatorException("certificate is revoked"); + } + } + + // The chain is valid; return the result. + return new PKIXCertPathValidatorResult(anchor, rootNode, + p[0].getPublicKey()); + } + catch (Exception ignored) + { + cause = ignored; + continue; + } + } + + // The path is not valid. + CertPathValidatorException cpve = + new CertPathValidatorException("path validation failed"); + if (cause != null) + cpve.initCause (cause); + throw cpve; + } + + // Own methods. + // ------------------------------------------------------------------------- + + /** + * Check if a given CRL is acceptable for checking the revocation status + * of certificates in the path being checked. + * + *
The CRL is accepted iff:
+ * + *index
.
+ */
+ private static void basicSanity(X509Certificate[] path, int index)
+ throws CertPathValidatorException
+ {
+ X509Certificate cert = path[index];
+ int pathLen = 0;
+ for (int i = index - 1; i > 0; i--)
+ {
+ if (!path[i].getIssuerDN().equals(path[i].getSubjectDN()))
+ pathLen++;
+ }
+ Extension e = null;
+ if (cert instanceof GnuPKIExtension)
+ {
+ e = ((GnuPKIExtension) cert).getExtension(BasicConstraints.ID);
+ }
+ else
+ {
+ try
+ {
+ e = new Extension(cert.getExtensionValue(BasicConstraints.ID.toString()));
+ }
+ catch (Exception x)
+ {
+ }
+ }
+ if (e == null)
+ throw new CertPathValidatorException("no basicConstraints");
+ BasicConstraints bc = (BasicConstraints) e.getValue();
+ if (!bc.isCA())
+ throw new CertPathValidatorException("certificate cannot be used to verify signatures");
+ if (bc.getPathLengthConstraint() >= 0 && bc.getPathLengthConstraint() < pathLen)
+ throw new CertPathValidatorException("path is too long");
+
+ boolean[] keyUsage = cert.getKeyUsage();
+ if (keyUsage != null)
+ {
+ if (!keyUsage[KeyUsage.KEY_CERT_SIGN])
+ throw new CertPathValidatorException("certificate cannot be used to sign certificates");
+ }
+ }
+
+ private static void updatePolicyTree(X509Certificate cert, PolicyNodeImpl root,
+ int depth, PKIXParameters params,
+ boolean explicitPolicy)
+ throws CertPathValidatorException
+ {
+ if (DEBUG) debug("updatePolicyTree depth == " + depth);
+ Set nodes = new HashSet();
+ LinkedList stack = new LinkedList();
+ Iterator current = null;
+ stack.addLast(Collections.singleton(root).iterator());
+ do
+ {
+ current = (Iterator) stack.removeLast();
+ while (current.hasNext())
+ {
+ PolicyNodeImpl p = (PolicyNodeImpl) current.next();
+ if (DEBUG) debug("visiting node == " + p);
+ if (p.getDepth() == depth - 1)
+ {
+ if (DEBUG) debug("added node");
+ nodes.add(p);
+ }
+ else
+ {
+ if (DEBUG) debug("skipped node");
+ stack.addLast(current);
+ current = p.getChildren();
+ }
+ }
+ }
+ while (!stack.isEmpty());
+
+ Extension e = null;
+ CertificatePolicies policies = null;
+ List qualifierInfos = null;
+ if (cert instanceof GnuPKIExtension)
+ {
+ e = ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID);
+ if (e != null)
+ policies = (CertificatePolicies) e.getValue();
+ }
+
+ List cp = null;
+ if (policies != null)
+ cp = policies.getPolicies();
+ else
+ cp = Collections.EMPTY_LIST;
+ boolean match = false;
+ if (DEBUG) debug("nodes are == " + nodes);
+ if (DEBUG) debug("cert policies are == " + cp);
+ for (Iterator it = nodes.iterator(); it.hasNext(); )
+ {
+ PolicyNodeImpl parent = (PolicyNodeImpl) it.next();
+ if (DEBUG) debug("adding policies to " + parent);
+ for (Iterator it2 = cp.iterator(); it2.hasNext(); )
+ {
+ OID policy = (OID) it2.next();
+ if (DEBUG) debug("trying to add policy == " + policy);
+ if (policy.toString().equals(ANY_POLICY) &&
+ params.isAnyPolicyInhibited())
+ continue;
+ PolicyNodeImpl child = new PolicyNodeImpl();
+ child.setValidPolicy(policy.toString());
+ child.addExpectedPolicy(policy.toString());
+ if (parent.getExpectedPolicies().contains(policy.toString()))
+ {
+ parent.addChild(child);
+ match = true;
+ }
+ else if (parent.getExpectedPolicies().contains(ANY_POLICY))
+ {
+ parent.addChild(child);
+ match = true;
+ }
+ else if (ANY_POLICY.equals (policy.toString()))
+ {
+ parent.addChild (child);
+ match = true;
+ }
+ if (match && policies != null)
+ {
+ List qualifiers = policies.getPolicyQualifierInfos (policy);
+ if (qualifiers != null)
+ child.addAllPolicyQualifiers (qualifiers);
+ }
+ }
+ }
+ if (!match && (params.isExplicitPolicyRequired() || explicitPolicy))
+ throw new CertPathValidatorException("policy tree building failed");
+ }
+
+ private boolean checkExplicitPolicy (int depth, List explicitPolicies)
+ {
+ if (DEBUG) debug ("checkExplicitPolicy depth=" + depth);
+ for (Iterator it = explicitPolicies.iterator(); it.hasNext(); )
+ {
+ int[] i = (int[]) it.next();
+ int caDepth = i[0];
+ int limit = i[1];
+ if (DEBUG) debug (" caDepth=" + caDepth + " limit=" + limit);
+ if (depth - caDepth >= limit)
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/provider/RSA.java b/libjava/classpath/gnu/java/security/provider/RSA.java
new file mode 100644
index 0000000..c3cfbbf
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/provider/RSA.java
@@ -0,0 +1,311 @@
+/* RSA.java -- RSA PKCS#1 signatures.
+ Copyright (C) 2004 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 gnu.java.security.provider;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.ArrayList;
+
+public abstract class RSA extends SignatureSpi implements Cloneable
+{
+
+ // Constants and fields.
+ // -------------------------------------------------------------------------
+
+ /**
+ * digestAlgorithm OBJECT IDENTIFIER ::=
+ * { iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) }
+ */
+ protected static final OID DIGEST_ALGORITHM = new OID("1.2.840.113549.2");
+
+ protected final OID digestAlgorithm;
+ protected final MessageDigest md;
+ protected RSAPrivateKey signerKey;
+ protected RSAPublicKey verifierKey;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ protected RSA(MessageDigest md, OID digestAlgorithm)
+ {
+ super();
+ this.md = md;
+ this.digestAlgorithm = digestAlgorithm;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public Object clone() throws CloneNotSupportedException
+ {
+ return super.clone();
+ }
+
+ protected Object engineGetParameter(String param)
+ {
+ throw new UnsupportedOperationException("deprecated");
+ }
+
+ protected void engineSetParameter(String param, Object value)
+ {
+ throw new UnsupportedOperationException("deprecated");
+ }
+
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ throw new InvalidKeyException();
+ verifierKey = null;
+ signerKey = (RSAPrivateKey) privateKey;
+ }
+
+ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException
+ {
+ // This class does not need random bytes.
+ engineInitSign(privateKey);
+ }
+
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (!(publicKey instanceof RSAPublicKey))
+ throw new InvalidKeyException();
+ signerKey = null;
+ verifierKey = (RSAPublicKey) publicKey;
+ }
+
+ protected void engineUpdate(byte b) throws SignatureException
+ {
+ if (signerKey == null && verifierKey == null)
+ throw new SignatureException("not initialized");
+ md.update(b);
+ }
+
+ protected void engineUpdate(byte[] buf, int off, int len)
+ throws SignatureException
+ {
+ if (signerKey == null && verifierKey == null)
+ throw new SignatureException("not initialized");
+ md.update(buf, off, len);
+ }
+
+ protected byte[] engineSign() throws SignatureException
+ {
+ if (signerKey == null)
+ throw new SignatureException("not initialized for signing");
+ //
+ // The signature will be the RSA encrypted BER representation of
+ // the following:
+ //
+ // DigestInfo ::= SEQUENCE {
+ // digestAlgorithm DigestAlgorithmIdentifier,
+ // digest Digest }
+ //
+ // DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ //
+ // Digest ::= OCTET STRING
+ //
+ ArrayList digestAlg = new ArrayList(2);
+ digestAlg.add(new DERValue(DER.OBJECT_IDENTIFIER, digestAlgorithm));
+ digestAlg.add(new DERValue(DER.NULL, null));
+ ArrayList digestInfo = new ArrayList(2);
+ digestInfo.add(new DERValue(DER.SEQUENCE, digestAlg));
+ digestInfo.add(new DERValue(DER.OCTET_STRING, md.digest()));
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try
+ {
+ DERWriter.write(out, new DERValue(DER.SEQUENCE, digestInfo));
+ }
+ catch (IOException ioe)
+ {
+ throw new SignatureException(ioe.toString());
+ }
+ byte[] buf = out.toByteArray();
+ md.reset();
+
+ // k = octect length of the modulus.
+ int k = signerKey.getModulus().bitLength();
+ k = (k >>> 3) + ((k & 7) == 0 ? 0 : 1);
+ if (buf.length < k - 3)
+ {
+ throw new SignatureException("RSA modulus too small");
+ }
+ byte[] d = new byte[k];
+
+ // Padding type 1:
+ // 00 | 01 | FF | ... | FF | 00 | D
+ d[1] = 0x01;
+ for (int i = 2; i < k - buf.length - 1; i++)
+ d[i] = (byte) 0xFF;
+ System.arraycopy(buf, 0, d, k - buf.length, buf.length);
+
+ BigInteger eb = new BigInteger(d);
+
+ byte[] ed = eb.modPow(signerKey.getPrivateExponent(),
+ signerKey.getModulus()).toByteArray();
+
+ // Ensure output is k octets long.
+ if (ed.length < k)
+ {
+ byte[] b = new byte[k];
+ System.arraycopy(eb, 0, b, k - ed.length, ed.length);
+ ed = b;
+ }
+ else if (ed.length > k)
+ {
+ if (ed.length != k + 1)
+ {
+ throw new SignatureException("modPow result is larger than the modulus");
+ }
+ // Maybe an extra 00 octect.
+ byte[] b = new byte[k];
+ System.arraycopy(ed, 1, b, 0, k);
+ ed = b;
+ }
+
+ return ed;
+ }
+
+ protected int engineSign(byte[] out, int off, int len)
+ throws SignatureException
+ {
+ if (out == null || off < 0 || len < 0 || off+len > out.length)
+ throw new SignatureException("illegal output argument");
+ byte[] result = engineSign();
+ if (result.length > len)
+ throw new SignatureException("not enough space for signature");
+ System.arraycopy(result, 0, out, off, result.length);
+ return result.length;
+ }
+
+ protected boolean engineVerify(byte[] sig) throws SignatureException
+ {
+ if (verifierKey == null)
+ throw new SignatureException("not initialized for verifying");
+ if (sig == null)
+ throw new SignatureException("no signature specified");
+ int k = verifierKey.getModulus().bitLength();
+ k = (k >>> 3) + ((k & 7) == 0 ? 0 : 1);
+ if (sig.length != k)
+ throw new SignatureException("signature is the wrong size (expecting "
+ + k + " bytes, got " + sig.length + ")");
+ BigInteger ed = new BigInteger(1, sig);
+ byte[] eb = ed.modPow(verifierKey.getPublicExponent(),
+ verifierKey.getModulus()).toByteArray();
+
+ int i = 0;
+ if (eb[0] == 0x00)
+ {
+ for (i = 1; i < eb.length && eb[i] == 0x00; i++);
+ if (i == 1)
+ throw new SignatureException("wrong RSA padding");
+ i--;
+ }
+ else if (eb[0] == 0x01)
+ {
+ for (i = 1; i < eb.length && eb[i] != 0x00; i++)
+ if (eb[i] != (byte) 0xFF)
+ throw new IllegalArgumentException("wrong RSA padding");
+ }
+ else
+ throw new SignatureException("wrong RSA padding type");
+
+ byte[] d = new byte[eb.length-i-1];
+ System.arraycopy(eb, i+1, d, 0, eb.length-i-1);
+
+ DERReader der = new DERReader(d);
+ try
+ {
+ DERValue val = der.read();
+ if (val.getTag() != DER.SEQUENCE)
+ throw new SignatureException("failed to parse DigestInfo");
+ val = der.read();
+ if (val.getTag() != DER.SEQUENCE)
+ throw new SignatureException("failed to parse DigestAlgorithmIdentifier");
+ boolean sequenceIsBer = val.getLength() == 0;
+ val = der.read();
+ if (val.getTag() != DER.OBJECT_IDENTIFIER)
+ throw new SignatureException("failed to parse object identifier");
+ if (!val.getValue().equals(digestAlgorithm))
+ throw new SignatureException("digest algorithms do not match");
+ val = der.read();
+ // We should never see parameters here, since they are never used.
+ if (val.getTag() != DER.NULL)
+ throw new SignatureException("cannot handle digest parameters");
+ if (sequenceIsBer)
+ der.skip(1); // end-of-sequence byte.
+ val = der.read();
+ if (val.getTag() != DER.OCTET_STRING)
+ throw new SignatureException("failed to parse Digest");
+ return MessageDigest.isEqual(md.digest(), (byte[]) val.getValue());
+ }
+ catch (IOException ioe)
+ {
+ throw new SignatureException(ioe.toString());
+ }
+ }
+
+ protected boolean engineVerify(byte[] sig, int off, int len)
+ throws SignatureException
+ {
+ if (sig == null || off < 0 || len < 0 || off+len > sig.length)
+ throw new SignatureException("illegal parameter");
+ byte[] buf = new byte[len];
+ System.arraycopy(sig, off, buf, 0, len);
+ return engineVerify(buf);
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/provider/RSAKeyFactory.java b/libjava/classpath/gnu/java/security/provider/RSAKeyFactory.java
new file mode 100644
index 0000000..d13cbe5
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/provider/RSAKeyFactory.java
@@ -0,0 +1,181 @@
+/* RSAKeyFactory.java -- RSA key factory.
+ Copyright (C) 2004 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 gnu.java.security.provider;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+public class RSAKeyFactory extends KeyFactorySpi
+{
+
+ // Default constructor.
+ // -------------------------------------------------------------------------
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ protected PrivateKey engineGeneratePrivate(KeySpec spec)
+ throws InvalidKeySpecException
+ {
+ if (spec instanceof RSAPrivateCrtKeySpec)
+ {
+ return new GnuRSAPrivateKey((RSAPrivateCrtKeySpec) spec);
+ }
+ if (spec instanceof RSAPrivateKeySpec)
+ {
+ return new GnuRSAPrivateKey(new RSAPrivateCrtKeySpec(
+ ((RSAPrivateKeySpec) spec).getModulus(), null,
+ ((RSAPrivateKeySpec) spec).getPrivateExponent(), null,
+ null, null, null, null));
+ }
+ if (spec instanceof PKCS8EncodedKeySpec)
+ {
+ EncodedKeyFactory ekf = new EncodedKeyFactory();
+ PrivateKey pk = ekf.engineGeneratePrivate(spec);
+ if (pk instanceof RSAPrivateKey)
+ return pk;
+ }
+ throw new InvalidKeySpecException();
+ }
+
+ protected PublicKey engineGeneratePublic(KeySpec spec)
+ throws InvalidKeySpecException
+ {
+ if (spec instanceof RSAPublicKeySpec)
+ {
+ return new GnuRSAPublicKey((RSAPublicKeySpec) spec);
+ }
+ if (spec instanceof X509EncodedKeySpec)
+ {
+ EncodedKeyFactory ekf = new EncodedKeyFactory();
+ PublicKey pk = ekf.engineGeneratePublic(spec);
+ if (pk instanceof RSAPublicKey)
+ return pk;
+ }
+ throw new InvalidKeySpecException();
+ }
+
+ protected KeySpec engineGetKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec.isAssignableFrom(RSAPrivateCrtKeySpec.class)
+ && (key instanceof RSAPrivateCrtKey))
+ {
+ return new RSAPrivateCrtKeySpec(
+ ((RSAPrivateCrtKey) key).getModulus(),
+ ((RSAPrivateCrtKey) key).getPublicExponent(),
+ ((RSAPrivateCrtKey) key).getPrivateExponent(),
+ ((RSAPrivateCrtKey) key).getPrimeP(),
+ ((RSAPrivateCrtKey) key).getPrimeQ(),
+ ((RSAPrivateCrtKey) key).getPrimeExponentP(),
+ ((RSAPrivateCrtKey) key).getPrimeExponentQ(),
+ ((RSAPrivateCrtKey) key).getCrtCoefficient());
+ }
+ if (keySpec.isAssignableFrom(RSAPrivateKeySpec.class)
+ && (key instanceof RSAPrivateKey))
+ {
+ return new RSAPrivateKeySpec(
+ ((RSAPrivateCrtKey) key).getModulus(),
+ ((RSAPrivateCrtKey) key).getPrivateExponent());
+ }
+ if (keySpec.isAssignableFrom(RSAPublicKeySpec.class)
+ && (key instanceof RSAPublicKey))
+ {
+ return new RSAPublicKeySpec(
+ ((RSAPrivateCrtKey) key).getModulus(),
+ ((RSAPrivateCrtKey) key).getPublicExponent());
+ }
+ if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)
+ && key.getFormat().equalsIgnoreCase("PKCS#8"))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)
+ && key.getFormat().equalsIgnoreCase("X.509"))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+ throw new InvalidKeySpecException();
+ }
+
+ protected Key engineTranslateKey(Key key) throws InvalidKeyException
+ {
+ if (key instanceof RSAPrivateCrtKey)
+ {
+ return new GnuRSAPrivateKey(new RSAPrivateCrtKeySpec(
+ ((RSAPrivateCrtKey) key).getModulus(),
+ ((RSAPrivateCrtKey) key).getPublicExponent(),
+ ((RSAPrivateCrtKey) key).getPrivateExponent(),
+ ((RSAPrivateCrtKey) key).getPrimeP(),
+ ((RSAPrivateCrtKey) key).getPrimeQ(),
+ ((RSAPrivateCrtKey) key).getPrimeExponentP(),
+ ((RSAPrivateCrtKey) key).getPrimeExponentQ(),
+ ((RSAPrivateCrtKey) key).getCrtCoefficient()));
+ }
+ if (key instanceof RSAPrivateKey)
+ {
+ return new GnuRSAPrivateKey(new RSAPrivateCrtKeySpec(
+ ((RSAPrivateKey) key).getModulus(), null,
+ ((RSAPrivateKey) key).getPrivateExponent(), null,
+ null, null, null, null));
+ }
+ if (key instanceof RSAPublicKey)
+ {
+ return new GnuRSAPublicKey(new RSAPublicKeySpec(
+ ((RSAPrivateCrtKey) key).getModulus(),
+ ((RSAPrivateCrtKey) key).getPublicExponent()));
+ }
+ throw new InvalidKeyException();
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/provider/SHA.java b/libjava/classpath/gnu/java/security/provider/SHA.java
new file mode 100644
index 0000000..e3b09bc
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/provider/SHA.java
@@ -0,0 +1,242 @@
+/* SHA.java -- Class implementing the SHA-1 algorithm as specified in [1].
+ Copyright (C) 1999, 2000, 2002 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 gnu.java.security.provider;
+
+import java.security.MessageDigest;
+
+/**
+ This class implements the SHA-1 algorithm as described in [1].
+
+ [1] Federal Information Processing Standards Publication 180-1.
+ Specifications for the Secure Hash Standard. April 17, 1995.
+
+ @see java.security.MessageDigest
+*/
+public class SHA extends MessageDigest implements Cloneable
+{
+ public SHA ()
+ {
+ super("SHA");
+ engineReset ();
+ }
+
+ public int engineGetDigestLength()
+ {
+ return 20;
+ }
+
+ public void engineUpdate (byte b)
+ {
+ int i = ((int)bytecount) & 0x3f; //wgs
+ int shift = (3 - i % 4) << 3;
+ int idx = i / 4;
+
+ i = (int)b;
+ W[idx] = (W[idx] & ~(0xff << shift)) | ((i & 0xff) << shift);
+
+ // if we've filled up a block, then process it
+ if (((++bytecount) & 0x3f) == 0)
+ munch ();
+ }
+
+ // This could be optimized.
+ public void engineUpdate (byte bytes[], int off, int len)
+ {
+ if (len < 0)
+ throw new ArrayIndexOutOfBoundsException ();
+
+ int end = off + len;
+ while (off < end)
+ engineUpdate (bytes[off++]);
+ }
+
+ public void engineReset ()
+ {
+ bytecount = 0;
+ // magic numbers from [1] p. 10.
+ H0 = 0x67452301;
+ H1 = 0xefcdab89;
+ H2 = 0x98badcfe;
+ H3 = 0x10325476;
+ H4 = 0xc3d2e1f0;
+ }
+
+ public byte[] engineDigest ()
+ {
+ long bitcount = bytecount << 3;
+ engineUpdate ((byte)0x80); // 10000000 in binary; the start of the padding
+
+ // add the rest of the padding to fill this block out, but leave 8
+ // bytes to put in the original bytecount
+ while ((bytecount & 0x3f) != 56)
+ engineUpdate ((byte)0);
+
+ // add the length of the original, unpadded block to the end of
+ // the padding
+ W[14] = (int)(bitcount >>> 32);
+ W[15] = (int)bitcount;
+ bytecount += 8;
+
+ // digest the fully padded block
+ munch ();
+
+ byte[] result
+ = new byte[] {(byte)(H0 >>> 24), (byte)(H0 >>> 16),
+ (byte)(H0 >>> 8), (byte)H0,
+ (byte)(H1 >>> 24), (byte)(H1 >>> 16),
+ (byte)(H1 >>> 8), (byte)H1,
+ (byte)(H2 >>> 24), (byte)(H2 >>> 16),
+ (byte)(H2 >>> 8), (byte)H2,
+ (byte)(H3 >>> 24), (byte)(H3 >>> 16),
+ (byte)(H3 >>> 8), (byte)H3,
+ (byte)(H4 >>> 24), (byte)(H4 >>> 16),
+ (byte)(H4 >>> 8), (byte)H4};
+
+ engineReset ();
+ return result;
+ }
+
+ // Process a single block. This is pretty much copied verbatim from
+ // [1] pp. 9, 10.
+ private void munch ()
+ {
+ for (int t = 16; t < 80; ++ t)
+ {
+ int Wt = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
+ W[t] = Wt << 1 | Wt >>> 31;
+ }
+
+ int A = H0;
+ int B = H1;
+ int C = H2;
+ int D = H3;
+ int E = H4;
+
+ for (int t = 0; t < 20; ++ t)
+ {
+ int TEMP = (A << 5 | A >>> 27) // S^5(A)
+ + ((B & C) | (~B & D)) // f_t(B,C,D)
+ + E + W[t]
+ + 0x5a827999; // K_t
+
+ E = D;
+ D = C;
+ C = B << 30 | B >>> 2; // S^30(B)
+ B = A;
+ A = TEMP;
+ }
+
+ for (int t = 20; t < 40; ++ t)
+ {
+ int TEMP = (A << 5 | A >>> 27) // S^5(A)
+ + (B ^ C ^ D) // f_t(B,C,D)
+ + E + W[t]
+ + 0x6ed9eba1; // K_t
+
+ E = D;
+ D = C;
+ C = B << 30 | B >>> 2; // S^30(B)
+ B = A;
+ A = TEMP;
+ }
+
+ for (int t = 40; t < 60; ++ t)
+ {
+ int TEMP = (A << 5 | A >>> 27) // S^5(A)
+ + (B & C | B & D | C & D) // f_t(B,C,D)
+ + E + W[t]
+ + 0x8f1bbcdc; // K_t
+
+ E = D;
+ D = C;
+ C = B << 30 | B >>> 2; // S^30(B)
+ B = A;
+ A = TEMP;
+ }
+
+ for (int t = 60; t < 80; ++ t)
+ {
+ int TEMP = (A << 5 | A >>> 27) // S^5(A)
+ + (B ^ C ^ D) // f_t(B,C,D)
+ + E + W[t]
+ + 0xca62c1d6; // K_t
+
+ E = D;
+ D = C;
+ C = B << 30 | B >>> 2; // S^30(B)
+ B = A;
+ A = TEMP;
+ }
+
+ H0 += A;
+ H1 += B;
+ H2 += C;
+ H3 += D;
+ H4 += E;
+
+ // Reset W by clearing it.
+ for (int t = 0; t < 80; ++ t)
+ W[t] = 0;
+ }
+
+ public Object clone ()
+ {
+ return new SHA (this);
+ }
+
+ private SHA (SHA copy)
+ {
+ this ();
+ bytecount = copy.bytecount;
+ H0 = copy.H0;
+ H1 = copy.H1;
+ H2 = copy.H2;
+ H3 = copy.H3;
+ H4 = copy.H4;
+ System.arraycopy (copy.W, 0, W, 0, 80);
+ }
+
+ private final int W[] = new int[80];
+ private long bytecount;
+ private int H0;
+ private int H1;
+ private int H2;
+ private int H3;
+ private int H4;
+}
diff --git a/libjava/classpath/gnu/java/security/provider/SHA1PRNG.java b/libjava/classpath/gnu/java/security/provider/SHA1PRNG.java
new file mode 100644
index 0000000..e4058e3
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/provider/SHA1PRNG.java
@@ -0,0 +1,137 @@
+/* SHA1PRNG.java --- Secure Random SPI SHA1PRNG
+ Copyright (C) 1999, 2001, 2003, 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 gnu.java.security.provider;
+
+import java.io.Serializable;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandomSpi;
+import java.util.Random;
+
+public class SHA1PRNG extends SecureRandomSpi implements Serializable
+{
+ MessageDigest digest;
+ byte seed[];
+ byte data[];
+ int seedpos;
+ int datapos;
+ private boolean seeded = false; // set to true when we seed this
+ /**
+ * The size of seed.
+ */
+ private static final int SEED_SIZE = 20;
+ /**
+ * The size of data.
+ */
+ private static final int DATA_SIZE = 40;
+
+ /**
+ * Create a new SHA-1 pseudo-random number generator.
+ */
+ public SHA1PRNG()
+ {
+ try {
+ digest = MessageDigest.getInstance("SHA");
+ } catch ( NoSuchAlgorithmException nsae) {
+// System.out.println("Failed to find SHA Message Digest: " + nsae);
+// nsae.printStackTrace();
+ throw new InternalError ("no SHA implementation found");
+ }
+
+ seed = new byte[SEED_SIZE];
+ seedpos = 0;
+ data = new byte[DATA_SIZE];
+ datapos = SEED_SIZE; // try to force hashing a first block
+ }
+
+ public void engineSetSeed(byte[] seed)
+ {
+ for(int i = 0; i < seed.length; i++)
+ this.seed[seedpos++ % SEED_SIZE] ^= seed[i];
+ seedpos %= SEED_SIZE;
+
+ }
+
+ public void engineNextBytes(byte[] bytes)
+ {
+ ensureIsSeeded ();
+ int loc = 0;
+ while (loc < bytes.length)
+ {
+ int copy = Math.min (bytes.length - loc, SEED_SIZE - datapos);
+
+ if (copy > 0)
+ {
+ System.arraycopy (data, datapos, bytes, loc, copy);
+ datapos += copy;
+ loc += copy;
+ }
+ else
+ {
+ // No data ready for copying, so refill our buffer.
+ System.arraycopy( seed, 0, data, SEED_SIZE, SEED_SIZE);
+ byte[] digestdata = digest.digest( data );
+ System.arraycopy( digestdata, 0, data, 0, SEED_SIZE);
+ datapos = 0;
+ }
+ }
+ }
+
+ public byte[] engineGenerateSeed(int numBytes)
+ {
+ byte tmp[] = new byte[numBytes];
+
+ engineNextBytes( tmp );
+ return tmp;
+ }
+
+ private void ensureIsSeeded()
+ {
+ if (!seeded)
+ {
+ new Random(0L).nextBytes(seed);
+
+ byte[] digestdata = digest.digest(data);
+ System.arraycopy(digestdata, 0, data, 0, SEED_SIZE);
+
+ seeded = true;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/security/provider/SHA1withRSA.java b/libjava/classpath/gnu/java/security/provider/SHA1withRSA.java
new file mode 100644
index 0000000..0e63fde
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/provider/SHA1withRSA.java
@@ -0,0 +1,61 @@
+/* SHA1withRSA.java -- SHA-1 with RSA encryption signatures.
+ Copyright (C) 2004 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 gnu.java.security.provider;
+
+import gnu.java.security.OID;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class SHA1withRSA extends RSA
+{
+
+ // Constant.
+ // -------------------------------------------------------------------------
+
+ private static final OID SHA1 = new OID("1.3.14.3.2.26");
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public SHA1withRSA() throws NoSuchAlgorithmException
+ {
+ super(MessageDigest.getInstance("SHA-160"), SHA1);
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java b/libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java
new file mode 100644
index 0000000..1a415ea
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java
@@ -0,0 +1,305 @@
+/* X509CertificateFactory.java -- generates X.509 certificates.
+ Copyright (C) 2003 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 gnu.java.security.provider;
+
+import gnu.java.io.Base64InputStream;
+import gnu.java.security.x509.X509CRL;
+import gnu.java.security.x509.X509CertPath;
+import gnu.java.security.x509.X509Certificate;
+
+import java.io.BufferedInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+public class X509CertificateFactory extends CertificateFactorySpi
+{
+
+ // Constants.
+ // ------------------------------------------------------------------------
+
+ public static final String BEGIN_CERTIFICATE = "-----BEGIN CERTIFICATE-----";
+ public static final String END_CERTIFICATE = "-----END CERTIFICATE-----";
+ public static final String BEGIN_X509_CRL = "-----BEGIN X509 CRL-----";
+ public static final String END_X509_CRL = "-----END X509 CRL-----";
+
+ // Constructors.
+ // ------------------------------------------------------------------------
+
+ public X509CertificateFactory()
+ {
+ super();
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ public Certificate engineGenerateCertificate(InputStream inStream)
+ throws CertificateException
+ {
+ try
+ {
+ return generateCert(inStream);
+ }
+ catch (IOException ioe)
+ {
+ CertificateException ce = new CertificateException(ioe.getMessage());
+ ce.initCause (ioe);
+ throw ce;
+ }
+ }
+
+ public Collection engineGenerateCertificates(InputStream inStream)
+ throws CertificateException
+ {
+ LinkedList certs = new LinkedList();
+ while (true)
+ {
+ try
+ {
+ certs.add(generateCert(inStream));
+ }
+ catch (EOFException eof)
+ {
+ break;
+ }
+ catch (IOException ioe)
+ {
+ CertificateException ce = new CertificateException(ioe.getMessage());
+ ce.initCause (ioe);
+ throw ce;
+ }
+ }
+ return certs;
+ }
+
+ public CRL engineGenerateCRL(InputStream inStream) throws CRLException
+ {
+ try
+ {
+ return generateCRL(inStream);
+ }
+ catch (IOException ioe)
+ {
+ CRLException crle = new CRLException(ioe.getMessage());
+ crle.initCause (ioe);
+ throw crle;
+ }
+ }
+
+ public Collection engineGenerateCRLs(InputStream inStream)
+ throws CRLException
+ {
+ LinkedList crls = new LinkedList();
+ while (true)
+ {
+ try
+ {
+ crls.add(generateCRL(inStream));
+ }
+ catch (EOFException eof)
+ {
+ break;
+ }
+ catch (IOException ioe)
+ {
+ CRLException crle = new CRLException(ioe.getMessage());
+ crle.initCause (ioe);
+ throw crle;
+ }
+ }
+ return crls;
+ }
+
+ public CertPath engineGenerateCertPath(List certs)
+ {
+ return new X509CertPath(certs);
+ }
+
+ public CertPath engineGenerateCertPath(InputStream in)
+ throws CertificateEncodingException
+ {
+ return new X509CertPath(in);
+ }
+
+ public CertPath engineGenerateCertPath(InputStream in, String encoding)
+ throws CertificateEncodingException
+ {
+ return new X509CertPath(in, encoding);
+ }
+
+ public Iterator engineGetCertPathEncodings()
+ {
+ return X509CertPath.ENCODINGS.iterator();
+ }
+
+ // Own methods.
+ // ------------------------------------------------------------------------
+
+ private X509Certificate generateCert(InputStream inStream)
+ throws IOException, CertificateException
+ {
+ if (inStream == null)
+ throw new CertificateException("missing input stream");
+ if (!inStream.markSupported())
+ inStream = new BufferedInputStream(inStream, 8192);
+ inStream.mark(20);
+ int i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+
+ // If the input is in binary DER format, the first byte MUST be
+ // 0x30, which stands for the ASN.1 [UNIVERSAL 16], which is the
+ // UNIVERSAL SEQUENCE, with the CONSTRUCTED bit (0x20) set.
+ //
+ // So if we do not see 0x30 here we will assume it is in Base-64.
+ if (i != 0x30)
+ {
+ inStream.reset();
+ StringBuffer line = new StringBuffer(80);
+ do
+ {
+ line.setLength(0);
+ do
+ {
+ i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+ if (i != '\n' && i != '\r')
+ line.append((char) i);
+ }
+ while (i != '\n' && i != '\r');
+ }
+ while (!line.toString().equals(BEGIN_CERTIFICATE));
+ X509Certificate ret = new X509Certificate(
+ new BufferedInputStream(new Base64InputStream(inStream), 8192));
+ line.setLength(0);
+ line.append('-'); // Base64InputStream will eat this.
+ do
+ {
+ i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+ if (i != '\n' && i != '\r')
+ line.append((char) i);
+ }
+ while (i != '\n' && i != '\r');
+ // XXX ???
+ if (!line.toString().equals(END_CERTIFICATE))
+ throw new CertificateException("no end-of-certificate marker");
+ return ret;
+ }
+ else
+ {
+ inStream.reset();
+ return new X509Certificate(inStream);
+ }
+ }
+
+ private X509CRL generateCRL(InputStream inStream)
+ throws IOException, CRLException
+ {
+ if (inStream == null)
+ throw new CRLException("missing input stream");
+ if (!inStream.markSupported())
+ inStream = new BufferedInputStream(inStream, 8192);
+ inStream.mark(20);
+ int i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+
+ // If the input is in binary DER format, the first byte MUST be
+ // 0x30, which stands for the ASN.1 [UNIVERSAL 16], which is the
+ // UNIVERSAL SEQUENCE, with the CONSTRUCTED bit (0x20) set.
+ //
+ // So if we do not see 0x30 here we will assume it is in Base-64.
+ if (i != 0x30)
+ {
+ inStream.reset();
+ StringBuffer line = new StringBuffer(80);
+ do
+ {
+ line.setLength(0);
+ do
+ {
+ i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+ if (i != '\n' && i != '\r')
+ line.append((char) i);
+ }
+ while (i != '\n' && i != '\r');
+ }
+ while (!line.toString().startsWith(BEGIN_X509_CRL));
+ X509CRL ret = new X509CRL(
+ new BufferedInputStream(new Base64InputStream(inStream), 8192));
+ line.setLength(0);
+ line.append('-'); // Base64InputStream will eat this.
+ do
+ {
+ i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+ if (i != '\n' && i != '\r')
+ line.append((char) i);
+ }
+ while (i != '\n' && i != '\r');
+ // XXX ???
+ if (!line.toString().startsWith(END_X509_CRL))
+ throw new CRLException("no end-of-CRL marker");
+ return ret;
+ }
+ else
+ {
+ inStream.reset();
+ return new X509CRL(inStream);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/security/provider/package.html b/libjava/classpath/gnu/java/security/provider/package.html
new file mode 100644
index 0000000..641a22a
--- /dev/null
+++ b/libjava/classpath/gnu/java/security/provider/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+OFFSET SIXTEEN-BYTES-IN-HEX PRINTABLE-BYTES+ * + *
The printable bytes show up as-is if they are printable and + * not a newline character, otherwise showing as '.'. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to encode. + * @return The formatted string. + */ + public static String hexDump(byte[] buf, int off, int len, String prefix) + { + String nl = System.getProperty("line.separator"); + StringBuffer str = new StringBuffer(); + int i = 0; + while (i < len) + { + str.append(prefix); + str.append(Util.formatInt(i+off, 16, 8)); + str.append(" "); + String s = Util.toHexString(buf, i+off, Math.min(16, len-i), ' '); + str.append(s); + for (int j = 56 - (56 - s.length()); j < 56; j++) + str.append(" "); + for (int j = 0; j < Math.min(16, len - i); j++) + { + if ((buf[i+off+j] & 0xFF) < 0x20 || (buf[i+off+j] & 0xFF) > 0x7E) + str.append('.'); + else + str.append((char) (buf[i+off+j] & 0xFF)); + } + str.append(nl); + i += 16; + } + return str.toString(); + } + + /** + * See {@link #hexDump(byte[],int,int)}. + */ + public static String hexDump(byte[] buf, String prefix) + { + return hexDump(buf, 0, buf.length, prefix); + } + + /** + * Format an integer into the specified radix, zero-filled. + * + * @param i The integer to format. + * @param radix The radix to encode to. + * @param len The target length of the string. The string is + * zero-padded to this length, but may be longer. + * @return The formatted integer. + */ + public static String formatInt(int i, int radix, int len) + { + String s = Integer.toString(i, radix); + StringBuffer buf = new StringBuffer(); + for (int j = 0; j < len - s.length(); j++) + buf.append("0"); + buf.append(s); + return buf.toString(); + } + + /** + * Convert a hexadecimal string into its byte representation. + * + * @param hex The hexadecimal string. + * @return The converted bytes. + */ + public static byte[] toByteArray(String hex) + { + hex = hex.toLowerCase(); + byte[] buf = new byte[hex.length() / 2]; + int j = 0; + for (int i = 0; i < buf.length; i++) + { + buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) | + Character.digit(hex.charAt(j++), 16)); + } + return buf; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X500DistinguishedName.java b/libjava/classpath/gnu/java/security/x509/X500DistinguishedName.java new file mode 100644 index 0000000..daf746f --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X500DistinguishedName.java @@ -0,0 +1,548 @@ +/* X500DistinguishedName.java -- X.500 distinguished name. + Copyright (C) 2004 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 gnu.java.security.x509; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class X500DistinguishedName implements Principal +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID CN = new OID("2.5.4.3"); + public static final OID C = new OID("2.5.4.6"); + public static final OID L = new OID("2.5.4.7"); + public static final OID ST = new OID("2.5.4.8"); + public static final OID STREET = new OID("2.5.4.9"); + public static final OID O = new OID("2.5.4.10"); + public static final OID OU = new OID("2.5.4.11"); + public static final OID T = new OID("2.5.4.12"); + public static final OID DNQ = new OID("2.5.4.46"); + public static final OID NAME = new OID("2.5.4.41"); + public static final OID GIVENNAME = new OID("2.5.4.42"); + public static final OID INITIALS = new OID("2.5.4.43"); + public static final OID GENERATION = new OID("2.5.4.44"); + public static final OID EMAIL = new OID("1.2.840.113549.1.9.1"); + public static final OID DC = new OID("0.9.2342.19200300.100.1.25"); + public static final OID UID = new OID("0.9.2342.19200300.100.1.1"); + + private List components; + private Map currentRdn; + private boolean fixed; + private String stringRep; + private byte[] encoded; + + // Constructors. + // ------------------------------------------------------------------------- + + public X500DistinguishedName() + { + components = new LinkedList(); + currentRdn = new LinkedHashMap(); + components.add(currentRdn); + } + + public X500DistinguishedName(String name) + { + this(); + try + { + parseString(name); + } + catch (IOException ioe) + { + throw new IllegalArgumentException(ioe.toString()); + } + } + + public X500DistinguishedName(byte[] encoded) throws IOException + { + this(); + parseDer(new DERReader(encoded)); + } + + public X500DistinguishedName(InputStream encoded) throws IOException + { + this(); + parseDer(new DERReader(encoded)); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getName() + { + return toString(); + } + + public void newRelativeDistinguishedName() + { + if (fixed || currentRdn.isEmpty()) return; + currentRdn = new LinkedHashMap(); + components.add(currentRdn); + } + + public int size() + { + return components.size(); + } + + public int countComponents() + { + int count = 0; + for (Iterator it = components.iterator(); it.hasNext(); ) + { + count += ((Map) it.next()).size(); + } + return count; + } + + public boolean containsComponent(OID oid, String value) + { + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map rdn = (Map) it.next(); + String s = (String) rdn.get(oid); + if (s == null) + continue; + if (compressWS(value).equalsIgnoreCase(compressWS(s))) + return true; + } + return false; + } + + public String getComponent(OID oid) + { + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map rdn = (Map) it.next(); + if (rdn.containsKey(oid)) + return (String) rdn.get(oid); + } + return null; + } + + public String getComponent(OID oid, int rdn) + { + if (rdn >= size()) + return null; + return (String) ((Map) components.get(rdn)).get(oid); + } + + public void putComponent(OID oid, String value) + { + currentRdn.put(oid, value); + } + + public void putComponent(String name, String value) + { + name = name.trim().toLowerCase(); + if (name.equals("cn")) + putComponent(CN, value); + else if (name.equals("c")) + putComponent(C, value); + else if (name.equals("l")) + putComponent(L, value); + else if (name.equals("street")) + putComponent(STREET, value); + else if (name.equals("st")) + putComponent(ST, value); + else if (name.equals("t")) + putComponent(T, value); + else if (name.equals("dnq")) + putComponent(DNQ, value); + else if (name.equals("name")) + putComponent(NAME, value); + else if (name.equals("givenname")) + putComponent(GIVENNAME, value); + else if (name.equals("initials")) + putComponent(INITIALS, value); + else if (name.equals("generation")) + putComponent(GENERATION, value); + else if (name.equals("email")) + putComponent(EMAIL, value); + else if (name.equals("dc")) + putComponent(DC, value); + else if (name.equals("uid")) + putComponent(UID, value); + else + putComponent(new OID(name), value); + } + + public void setUnmodifiable() + { + if (fixed) return; + fixed = true; + List newComps = new ArrayList(components.size()); + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map rdn = (Map) it.next(); + rdn = Collections.unmodifiableMap(rdn); + newComps.add(rdn); + } + components = Collections.unmodifiableList(newComps); + currentRdn = Collections.EMPTY_MAP; + } + + public int hashCode() + { + int sum = 0; + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map m = (Map) it.next(); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry e = (Map.Entry) it2.next(); + sum += e.getKey().hashCode(); + sum += e.getValue().hashCode(); + } + } + return sum; + } + + public boolean equals(Object o) + { + if (!(o instanceof X500DistinguishedName)) + return false; + if (size() != ((X500DistinguishedName) o).size()) + return false; + for (int i = 0; i < size(); i++) + { + Map m = (Map) components.get(i); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry e = (Map.Entry) it2.next(); + OID oid = (OID) e.getKey(); + String v1 = (String) e.getValue(); + String v2 = ((X500DistinguishedName) o).getComponent(oid, i); + if (!compressWS(v1).equalsIgnoreCase(compressWS(v2))) + return false; + } + } + return true; + } + + public String toString() + { + if (fixed && stringRep != null) + return stringRep; + StringBuffer str = new StringBuffer(); + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map m = (Map) it.next(); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry entry = (Map.Entry) it2.next(); + OID oid = (OID) entry.getKey(); + String value = (String) entry.getValue(); + if (oid.equals(CN)) + str.append("CN"); + else if (oid.equals(C)) + str.append("C"); + else if (oid.equals(L)) + str.append("L"); + else if (oid.equals(ST)) + str.append("ST"); + else if (oid.equals(STREET)) + str.append("STREET"); + else if (oid.equals(O)) + str.append("O"); + else if (oid.equals(OU)) + str.append("OU"); + else if (oid.equals(T)) + str.append("T"); + else if (oid.equals(DNQ)) + str.append("DNQ"); + else if (oid.equals(NAME)) + str.append("NAME"); + else + str.append(oid.toString()); + str.append('='); + str.append(value); + if (it2.hasNext()) + str.append("+"); + } + if (it.hasNext()) + str.append(','); + } + return (stringRep = str.toString()); + } + + public byte[] getDer() + { + if (fixed && encoded != null) + return (byte[]) encoded.clone(); + ArrayList name = new ArrayList(components.size()); + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map m = (Map) it.next(); + if (m.isEmpty()) + continue; + Set rdn = new HashSet(); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + ArrayList atav = new ArrayList(2); + atav.add(new DERValue(DER.OBJECT_IDENTIFIER, e.getKey())); + atav.add(new DERValue(DER.UTF8_STRING, e.getValue())); + rdn.add(new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, atav)); + } + name.add(new DERValue(DER.SET|DER.CONSTRUCTED, rdn)); + } + DERValue val = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, name); + return (byte[]) (encoded = val.getEncoded()).clone(); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private int sep; + + private void parseString(String str) throws IOException + { + Reader in = new StringReader(str); + while (true) + { + String key = readAttributeType(in); + if (key == null) + break; + String value = readAttributeValue(in); + putComponent(key, value); + if (sep == ',') + newRelativeDistinguishedName(); + } + setUnmodifiable(); + } + + private String readAttributeType(Reader in) throws IOException + { + StringBuffer buf = new StringBuffer(); + int ch; + while ((ch = in.read()) != '=') + { + if (ch == -1) + { + if (buf.length() > 0) + throw new EOFException(); + return null; + } + if (ch > 127) + throw new IOException("Invalid char: " + (char) ch); + if (Character.isLetterOrDigit((char) ch) || ch == '-' || ch == '.') + buf.append((char) ch); + else + throw new IOException("Invalid char: " + (char) ch); + } + return buf.toString(); + } + + private String readAttributeValue(Reader in) throws IOException + { + StringBuffer buf = new StringBuffer(); + int ch = in.read(); + if (ch == '#') + { + while (true) + { + ch = in.read(); + if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch)) + buf.append((char) ch); + else if (ch == '+' || ch == ',') + { + sep = ch; + String hex = buf.toString(); + return new String(Util.toByteArray(hex)); + } + else + throw new IOException("illegal character: " + (char) ch); + } + } + else if (ch == '"') + { + while (true) + { + ch = in.read(); + if (ch == '"') + break; + else if (ch == '\\') + { + ch = in.read(); + if (ch == -1) + throw new EOFException(); + if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch)) + { + int i = Character.digit((char) ch, 16) << 4; + ch = in.read(); + if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch))) + throw new IOException("illegal hex char"); + i |= Character.digit((char) ch, 16); + buf.append((char) i); + } + else + buf.append((char) ch); + } + else + buf.append((char) ch); + } + sep = in.read(); + if (sep != '+' || sep != ',') + throw new IOException("illegal character: " + (char) ch); + return buf.toString(); + } + else + { + while (true) + { + switch (ch) + { + case '+': + case ',': + sep = ch; + return buf.toString(); + case '\\': + ch = in.read(); + if (ch == -1) + throw new EOFException(); + if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch)) + { + int i = Character.digit((char) ch, 16) << 4; + ch = in.read(); + if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch))) + throw new IOException("illegal hex char"); + i |= Character.digit((char) ch, 16); + buf.append((char) i); + } + else + buf.append((char) ch); + break; + case '=': + case '<': + case '>': + case '#': + case ';': + throw new IOException("illegal character: " + (char) ch); + case -1: + throw new EOFException(); + default: + buf.append((char) ch); + } + } + } + } + + private void parseDer(DERReader der) throws IOException + { + DERValue name = der.read(); + if (!name.isConstructed()) + throw new IOException("malformed Name"); + encoded = name.getEncoded(); + int len = 0; + while (len < name.getLength()) + { + DERValue rdn = der.read(); + if (!rdn.isConstructed()) + throw new IOException("badly formed RDNSequence"); + int len2 = 0; + while (len2 < rdn.getLength()) + { + DERValue atav = der.read(); + if (!atav.isConstructed()) + throw new IOException("badly formed AttributeTypeAndValue"); + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("badly formed AttributeTypeAndValue"); + OID oid = (OID) val.getValue(); + val = der.read(); + if (!(val.getValue() instanceof String)) + throw new IOException("badly formed AttributeTypeAndValue"); + String value = (String) val.getValue(); + putComponent(oid, value); + len2 += atav.getEncodedLength(); + } + len += rdn.getEncodedLength(); + if (len < name.getLength()) + newRelativeDistinguishedName(); + } + setUnmodifiable(); + } + + private static String compressWS(String str) + { + StringBuffer buf = new StringBuffer(); + char lastChar = 0; + for (int i = 0; i < str.length(); i++) + { + char c = str.charAt(i); + if (Character.isWhitespace(c)) + { + if (!Character.isWhitespace(lastChar)) + buf.append(' '); + } + else + buf.append(c); + lastChar = c; + } + return buf.toString().trim(); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X509CRL.java b/libjava/classpath/gnu/java/security/x509/X509CRL.java new file mode 100644 index 0000000..5b2d3b1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509CRL.java @@ -0,0 +1,476 @@ +/* X509CRL.java -- X.509 certificate revocation list. + Copyright (C) 2003, 2004 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 gnu.java.security.x509; + +import gnu.java.security.OID; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.ext.Extension; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CRLException; +import java.security.cert.Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +/** + * X.509 certificate revocation lists. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class X509CRL extends java.security.cert.X509CRL + implements GnuPKIExtension +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + private static final boolean DEBUG = false; + private static void debug(String msg) + { + if (DEBUG) + { + System.err.print(">> X509CRL: "); + System.err.println(msg); + } + } + + private static final OID ID_DSA = new OID("1.2.840.10040.4.1"); + private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3"); + private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1"); + private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2"); + private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4"); + private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5"); + + private byte[] encoded; + + private byte[] tbsCRLBytes; + private int version; + private OID algId; + private byte[] algParams; + private Date thisUpdate; + private Date nextUpdate; + private X500DistinguishedName issuerDN; + private HashMap revokedCerts; + private HashMap extensions; + + private OID sigAlg; + private byte[] sigAlgParams; + private byte[] rawSig; + private byte[] signature; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new X.509 CRL. + * + * @param encoded The DER encoded CRL. + * @throws CRLException If the input bytes are incorrect. + * @throws IOException If the input bytes cannot be read. + */ + public X509CRL(InputStream encoded) throws CRLException, IOException + { + super(); + revokedCerts = new HashMap(); + extensions = new HashMap(); + try + { + parse(encoded); + } + catch (IOException ioe) + { + ioe.printStackTrace(); + throw ioe; + } + catch (Exception x) + { + x.printStackTrace(); + throw new CRLException(x.toString()); + } + } + + // X509CRL methods. + // ------------------------------------------------------------------------ + + public boolean equals(Object o) + { + if (!(o instanceof X509CRL)) + return false; + return ((X509CRL) o).getRevokedCertificates().equals(revokedCerts.values()); + } + + public int hashCode() + { + return revokedCerts.hashCode(); + } + + public byte[] getEncoded() throws CRLException + { + return (byte[]) encoded.clone(); + } + + public void verify(PublicKey key) + throws CRLException, NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException + { + Signature sig = Signature.getInstance(sigAlg.toString()); + doVerify(sig, key); + } + + public void verify(PublicKey key, String provider) + throws CRLException, NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException + { + Signature sig = Signature.getInstance(sigAlg.toString(), provider); + doVerify(sig, key); + } + + public int getVersion() + { + return version; + } + + public Principal getIssuerDN() + { + return issuerDN; + } + + public X500Principal getIssuerX500Principal() + { + return new X500Principal(issuerDN.getDer()); + } + + public Date getThisUpdate() + { + return (Date) thisUpdate.clone(); + } + + public Date getNextUpdate() + { + if (nextUpdate != null) + return (Date) nextUpdate.clone(); + return null; + } + + public java.security.cert.X509CRLEntry getRevokedCertificate(BigInteger serialNo) + { + return (java.security.cert.X509CRLEntry) revokedCerts.get(serialNo); + } + + public Set getRevokedCertificates() + { + return Collections.unmodifiableSet(new HashSet(revokedCerts.values())); + } + + public byte[] getTBSCertList() throws CRLException + { + return (byte[]) tbsCRLBytes.clone(); + } + + public byte[] getSignature() + { + return (byte[]) rawSig.clone(); + } + + public String getSigAlgName() + { + if (sigAlg.equals(ID_DSA_WITH_SHA1)) + return "SHA1withDSA"; + if (sigAlg.equals(ID_RSA_WITH_MD2)) + return "MD2withRSA"; + if (sigAlg.equals(ID_RSA_WITH_MD5)) + return "MD5withRSA"; + if (sigAlg.equals(ID_RSA_WITH_SHA1)) + return "SHA1withRSA"; + return "unknown"; + } + + public String getSigAlgOID() + { + return sigAlg.toString(); + } + + public byte[] getSigAlgParams() + { + if (sigAlgParams != null) + return (byte[]) sigAlgParams.clone(); + return null; + } + + // X509Extension methods. + // ------------------------------------------------------------------------ + + public boolean hasUnsupportedCriticalExtension() + { + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical() && !e.isSupported()) + return true; + } + return false; + } + + public Set getCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public Set getNonCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (!e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public byte[] getExtensionValue(String oid) + { + Extension e = getExtension(new OID(oid)); + if (e != null) + { + return e.getValue().getEncoded(); + } + return null; + } + + // GnuPKIExtension method. + // ------------------------------------------------------------------------- + + public Extension getExtension(OID oid) + { + return (Extension) extensions.get(oid); + } + + public Collection getExtensions() + { + return extensions.values(); + } + + // CRL methods. + // ------------------------------------------------------------------------- + + public String toString() + { + return X509CRL.class.getName(); + } + + public boolean isRevoked(Certificate cert) + { + if (!(cert instanceof java.security.cert.X509Certificate)) + throw new IllegalArgumentException("not a X.509 certificate"); + BigInteger certSerial = + ((java.security.cert.X509Certificate) cert).getSerialNumber(); + X509CRLEntry ent = (X509CRLEntry) revokedCerts.get(certSerial); + if (ent == null) + return false; + return ent.getRevocationDate().compareTo(new Date()) < 0; + } + + // Own methods. + // ------------------------------------------------------------------------ + + private void doVerify(Signature sig, PublicKey key) + throws CRLException, InvalidKeyException, SignatureException + { + sig.initVerify(key); + sig.update(tbsCRLBytes); + if (!sig.verify(signature)) + throw new CRLException("signature not verified"); + } + + private void parse(InputStream in) throws Exception + { + // CertificateList ::= SEQUENCE { + DERReader der = new DERReader(in); + DERValue val = der.read(); + debug("start CertificateList len == " + val.getLength()); + if (!val.isConstructed()) + throw new IOException("malformed CertificateList"); + encoded = val.getEncoded(); + + // tbsCertList ::= SEQUENCE { -- TBSCertList + val = der.read(); + if (!val.isConstructed()) + throw new IOException("malformed TBSCertList"); + debug("start tbsCertList len == " + val.getLength()); + tbsCRLBytes = val.getEncoded(); + + // version Version OPTIONAL, + // -- If present must be v2 + val = der.read(); + if (val.getValue() instanceof BigInteger) + { + version = ((BigInteger) val.getValue()).intValue() + 1; + val = der.read(); + } + else + version = 1; + debug("read version == " + version); + + // signature AlgorithmIdentifier, + debug("start AlgorithmIdentifier len == " + val.getLength()); + if (!val.isConstructed()) + throw new IOException("malformed AlgorithmIdentifier"); + DERValue algIdVal = der.read(); + algId = (OID) algIdVal.getValue(); + debug("read object identifier == " + algId); + if (val.getLength() > algIdVal.getEncodedLength()) + { + val = der.read(); + debug("read parameters len == " + val.getEncodedLength()); + algParams = val.getEncoded(); + if (val.isConstructed()) + in.skip(val.getLength()); + } + + // issuer Name, + val = der.read(); + issuerDN = new X500DistinguishedName(val.getEncoded()); + der.skip(val.getLength()); + debug("read issuer == " + issuerDN); + + // thisUpdate Time, + thisUpdate = (Date) der.read().getValue(); + debug("read thisUpdate == " + thisUpdate); + + // nextUpdate Time OPTIONAL, + val = der.read(); + if (val.getValue() instanceof Date) + { + nextUpdate = (Date) val.getValue(); + debug("read nextUpdate == " + nextUpdate); + val = der.read(); + } + + // revokedCertificates SEQUENCE OF SEQUENCE { + // -- X509CRLEntry objects... + // } OPTIONAL, + if (val.getTag() != 0) + { + int len = 0; + while (len < val.getLength()) + { + X509CRLEntry entry = new X509CRLEntry(version, der); + revokedCerts.put(entry.getSerialNumber(), entry); + len += entry.getEncoded().length; + } + val = der.read(); + } + + // crlExtensions [0] EXPLICIT Extensions OPTIONAL + // -- if present MUST be v2 + if (val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0) + { + if (version < 2) + throw new IOException("extra data in CRL"); + DERValue exts = der.read(); + if (!exts.isConstructed()) + throw new IOException("malformed Extensions"); + debug("start Extensions len == " + exts.getLength()); + int len = 0; + while (len < exts.getLength()) + { + DERValue ext = der.read(); + if (!ext.isConstructed()) + throw new IOException("malformed Extension"); + Extension e = new Extension(ext.getEncoded()); + extensions.put(e.getOid(), e); + der.skip(ext.getLength()); + len += ext.getEncodedLength(); + debug("current count == " + len); + } + val = der.read(); + } + + debug("read tag == " + val.getTag()); + if (!val.isConstructed()) + throw new IOException("malformed AlgorithmIdentifier"); + debug("start AlgorithmIdentifier len == " + val.getLength()); + DERValue sigAlgVal = der.read(); + debug("read tag == " + sigAlgVal.getTag()); + if (sigAlgVal.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed AlgorithmIdentifier"); + sigAlg = (OID) sigAlgVal.getValue(); + debug("signature id == " + sigAlg); + debug("sigAlgVal length == " + sigAlgVal.getEncodedLength()); + if (val.getLength() > sigAlgVal.getEncodedLength()) + { + val = der.read(); + debug("sig params tag = " + val.getTag() + " len == " + val.getEncodedLength()); + sigAlgParams = (byte[]) val.getEncoded(); + if (val.isConstructed()) + in.skip(val.getLength()); + } + val = der.read(); + debug("read tag = " + val.getTag()); + rawSig = val.getEncoded(); + signature = ((BitString) val.getValue()).toByteArray(); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X509CRLEntry.java b/libjava/classpath/gnu/java/security/x509/X509CRLEntry.java new file mode 100644 index 0000000..a3bcfde --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509CRLEntry.java @@ -0,0 +1,278 @@ +/* X509CRLEntry.java -- an entry in a X.509 CRL. + Copyright (C) 2003, 2004 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 gnu.java.security.x509; + +import gnu.java.security.OID; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.ext.Extension; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CRLException; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A single entry in a X.509 certificate revocation list. + * + * @see X509CRL + * @author Casey Marshall + */ +class X509CRLEntry extends java.security.cert.X509CRLEntry + implements GnuPKIExtension +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + private static final boolean DEBUG = false; + private static void debug(String msg) + { + if (DEBUG) + { + System.err.print(">> X509CRLEntry: "); + System.err.println(msg); + } + } + + /** The DER encoded form of this CRL entry. */ + private byte[] encoded; + + /** The revoked certificate's serial number. */ + private BigInteger serialNo; + + /** The date the certificate was revoked. */ + private Date revocationDate; + + /** The CRL entry extensions. */ + private HashMap extensions; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Create a new X.509 certificate revocation list entry from the given + * input stream and CRL version number. + * + * @param version The CRL version. + * @param encoded The stream of DER bytes. + * @throws CRLException If the ASN.1 structure is invalid. + * @throws IOException If the bytes cannot be read. + */ + X509CRLEntry(int version, DERReader encoded) + throws CRLException, IOException + { + super(); + extensions = new HashMap(); + try + { + parse(version, encoded); + } + catch (IOException ioe) + { + throw ioe; + } + catch (Exception x) + { + throw new CRLException(x.toString()); + } + } + + // X509CRLEntry methods. + // ------------------------------------------------------------------------ + + public boolean equals(Object o) + { + if (!(o instanceof X509CRLEntry)) + return false; + return ((X509CRLEntry) o).getSerialNumber().equals(serialNo) && + ((X509CRLEntry) o).getRevocationDate().equals(revocationDate); + } + + public int hashCode() + { + return serialNo.hashCode(); + } + + public byte[] getEncoded() throws CRLException + { + return (byte[]) encoded.clone(); + } + + public BigInteger getSerialNumber() + { + return serialNo; + } + + public Date getRevocationDate() + { + return (Date) revocationDate.clone(); + } + + public boolean hasExtensions() + { + return ! extensions.isEmpty(); + } + + public String toString() + { + return "X509CRLEntry serial=" + serialNo + " revocation date=" + + revocationDate + " ext=" + extensions; + } + + // X509Extension methods. + // ------------------------------------------------------------------------- + + public boolean hasUnsupportedCriticalExtension() + { + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical() && !e.isSupported()) + return true; + } + return false; + } + + public Set getCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public Set getNonCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (!e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public byte[] getExtensionValue(String oid) + { + Extension e = getExtension(new OID(oid)); + if (e != null) + { + return e.getValue().getEncoded(); + } + return null; + } + + // GnuPKIExtension method. + // ------------------------------------------------------------------------- + + public Extension getExtension(OID oid) + { + return (Extension) extensions.get(oid); + } + + public Collection getExtensions() + { + return extensions.values(); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private void parse(int version, DERReader der) throws Exception + { + // RevokedCertificate ::= SEQUENCE { + DERValue entry = der.read(); + debug("start CRL entry len == " + entry.getLength()); + if (!entry.isConstructed()) + throw new IOException("malformed revokedCertificate"); + encoded = entry.getEncoded(); + int len = 0; + + debug("encoded entry:\n" + Util.hexDump(encoded, ">>>> ")); + + // userCertificate CertificateSerialNumber, + DERValue val = der.read(); + serialNo = (BigInteger) val.getValue(); + len += val.getEncodedLength(); + debug("userCertificate == " + serialNo + " current count == " + len); + + // revocationDate Time, + val = der.read(); + revocationDate = (Date) val.getValue(); + len += val.getEncodedLength(); + debug("revocationDate == " + revocationDate + " current count == " + len); + + // crlEntryExtensions Extensions OPTIONAL + // -- if present MUST be v2 + if (len < entry.getLength()) + { + if (version < 2) + throw new IOException("extra data in CRL entry"); + DERValue exts = der.read(); + if (!exts.isConstructed()) + throw new IOException("malformed Extensions"); + debug("start Extensions len == " + exts.getLength()); + len = 0; + while (len < exts.getLength()) + { + val = der.read(); + if (!val.isConstructed()) + throw new IOException("malformed Extension"); + debug("start Extension len == " + val.getLength()); + Extension e = new Extension(val.getEncoded()); + extensions.put(e.getOid(), e); + der.skip(val.getLength()); + len += val.getEncodedLength(); + debug("current count == " + len); + } + } + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X509CRLSelectorImpl.java b/libjava/classpath/gnu/java/security/x509/X509CRLSelectorImpl.java new file mode 100644 index 0000000..0ada550 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509CRLSelectorImpl.java @@ -0,0 +1,138 @@ +/* X509CRLSelectorImpl.java -- implementation of an X509CRLSelector. + Copyright (C) 2004 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 gnu.java.security.x509; + +import java.io.IOException; + +import java.security.Principal; +import java.security.cert.CRL; +import java.security.cert.CRLSelector; +import java.security.cert.X509CRL; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +/** + * Sun's implementation of X509CRLSelector sucks. This one tries to work + * better. + */ +public class X509CRLSelectorImpl implements CRLSelector +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Set issuerNames; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509CRLSelectorImpl() + { + issuerNames = new HashSet(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void addIssuerName(byte[] issuerName) throws IOException + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(String issuerName) + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(Principal issuerName) throws IOException + { + if (issuerName instanceof X500DistinguishedName) + issuerNames.add(issuerName); + else if (issuerName instanceof X500Principal) + issuerNames.add(new X500DistinguishedName(((X500Principal) issuerName).getEncoded())); + else + issuerNames.add(new X500DistinguishedName(issuerName.getName())); + } + + public Collection getIssuerNames() + { + return Collections.unmodifiableSet(issuerNames); + } + + public Object clone() + { + X509CRLSelectorImpl copy = new X509CRLSelectorImpl(); + copy.issuerNames.addAll(issuerNames); + return copy; + } + + public boolean match(CRL crl) + { + if (!(crl instanceof X509CRL)) + return false; + try + { + Principal p = ((X509CRL) crl).getIssuerDN(); + X500DistinguishedName thisName = null; + if (p instanceof X500DistinguishedName) + thisName = (X500DistinguishedName) p; + else if (p instanceof X500Principal) + thisName = new X500DistinguishedName(((X500Principal) p).getEncoded()); + else + thisName = new X500DistinguishedName(p.getName()); + for (Iterator it = issuerNames.iterator(); it.hasNext(); ) + { + X500DistinguishedName name = (X500DistinguishedName) it.next(); + if (thisName.equals(name)) + return true; + } + } + catch (Exception x) + { + } + return false; + } +} + diff --git a/libjava/classpath/gnu/java/security/x509/X509CertPath.java b/libjava/classpath/gnu/java/security/x509/X509CertPath.java new file mode 100644 index 0000000..e8ed6bf --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509CertPath.java @@ -0,0 +1,303 @@ +/* X509CertPath.java -- an X.509 certificate path. + Copyright (C) 2004 Free Software Fonudation, 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 gnu.java.security.x509; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DEREncodingException; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +/** + * A certificate path (or certificate chain) of X509Certificates. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class X509CertPath extends CertPath +{ + + // Fields. + // ------------------------------------------------------------------------- + + public static final List ENCODINGS = Collections.unmodifiableList( + Arrays.asList(new String[] { "PkiPath", "PKCS7" })); + + private static final OID PKCS7_SIGNED_DATA = new OID("1.2.840.113549.1.7.2"); + private static final OID PKCS7_DATA = new OID("1.2.840.113549.1.7.1"); + + /** The certificate path. */ + private List path; + + /** The cached PKCS #7 encoded bytes. */ + private byte[] pkcs_encoded; + + /** The cached PkiPath encoded bytes. */ + private byte[] pki_encoded; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509CertPath(List path) + { + super("X.509"); + this.path = Collections.unmodifiableList(path); + } + + public X509CertPath(InputStream in) throws CertificateEncodingException + { + this(in, (String) ENCODINGS.get(0)); + } + + public X509CertPath(InputStream in, String encoding) + throws CertificateEncodingException + { + super("X.509"); + try + { + parse(in, encoding); + } + catch (IOException ioe) + { + throw new CertificateEncodingException(); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public List getCertificates() + { + return path; // already unmodifiable + } + + public byte[] getEncoded() throws CertificateEncodingException + { + return getEncoded((String) ENCODINGS.get(0)); + } + + public byte[] getEncoded(String encoding) throws CertificateEncodingException + { + if (encoding.equalsIgnoreCase("PkiPath")) + { + if (pki_encoded == null) + { + try + { + pki_encoded = encodePki(); + } + catch (IOException ioe) + { + throw new CertificateEncodingException(); + } + } + return (byte[]) pki_encoded.clone(); + } + else if (encoding.equalsIgnoreCase("PKCS7")) + { + if (pkcs_encoded == null) + { + try + { + pkcs_encoded = encodePKCS(); + } + catch (IOException ioe) + { + throw new CertificateEncodingException(); + } + } + return (byte[]) pkcs_encoded.clone(); + } + else + throw new CertificateEncodingException("unknown encoding: " + encoding); + } + + public Iterator getEncodings() + { + return ENCODINGS.iterator(); // already unmodifiable + } + + // Own methods. + // ------------------------------------------------------------------------- + + private void parse(InputStream in, String encoding) + throws CertificateEncodingException, IOException + { + DERReader der = new DERReader(in); + DERValue path = null; + if (encoding.equalsIgnoreCase("PkiPath")) + { + // PKI encoding is just a SEQUENCE of X.509 certificates. + path = der.read(); + if (!path.isConstructed()) + throw new DEREncodingException("malformed PkiPath"); + } + else if (encoding.equalsIgnoreCase("PKCS7")) + { + // PKCS #7 encoding means that the certificates are contained in a + // SignedData PKCS #7 type. + // + // ContentInfo ::= SEQUENCE { + // contentType ::= ContentType, + // content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + // + // ContentType ::= OBJECT IDENTIFIER + // + // SignedData ::= SEQUENCE { + // version Version, + // digestAlgorithms DigestAlgorithmIdentifiers, + // contentInfo ContentInfo, + // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates + // OPTIONAL, + // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + // signerInfos SignerInfos } + // + // Version ::= INTEGER + // + DERValue value = der.read(); + if (!value.isConstructed()) + throw new DEREncodingException("malformed ContentInfo"); + value = der.read(); + if (!(value.getValue() instanceof OID) || + ((OID) value.getValue()).equals(PKCS7_SIGNED_DATA)) + throw new DEREncodingException("not a SignedData"); + value = der.read(); + if (!value.isConstructed() || value.getTag() != 0) + throw new DEREncodingException("malformed content"); + value = der.read(); + if (value.getTag() != DER.INTEGER) + throw new DEREncodingException("malformed Version"); + value = der.read(); + if (!value.isConstructed() || value.getTag() != DER.SET) + throw new DEREncodingException("malformed DigestAlgorithmIdentifiers"); + der.skip(value.getLength()); + value = der.read(); + if (!value.isConstructed()) + throw new DEREncodingException("malformed ContentInfo"); + der.skip(value.getLength()); + path = der.read(); + if (!path.isConstructed() || path.getTag() != 0) + throw new DEREncodingException("no certificates"); + } + else + throw new CertificateEncodingException("unknown encoding: " + encoding); + + LinkedList certs = new LinkedList(); + int len = 0; + while (len < path.getLength()) + { + DERValue cert = der.read(); + try + { + certs.add(new X509Certificate(new ByteArrayInputStream(cert.getEncoded()))); + } + catch (CertificateException ce) + { + throw new CertificateEncodingException(ce.getMessage()); + } + len += cert.getEncodedLength(); + der.skip(cert.getLength()); + } + + this.path = Collections.unmodifiableList(certs); + } + + private byte[] encodePki() + throws CertificateEncodingException, IOException + { + synchronized (path) + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (Iterator i = path.iterator(); i.hasNext(); ) + { + out.write(((Certificate) i.next()).getEncoded()); + } + byte[] b = out.toByteArray(); + DERValue val = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + b.length, b, null); + return val.getEncoded(); + } + } + + private byte[] encodePKCS() + throws CertificateEncodingException, IOException + { + synchronized (path) + { + ArrayList signedData = new ArrayList(5); + signedData.add(new DERValue(DER.INTEGER, BigInteger.ONE)); + signedData.add(new DERValue(DER.CONSTRUCTED | DER.SET, + Collections.EMPTY_SET)); + signedData.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + Collections.singletonList( + new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_DATA)))); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (Iterator i = path.iterator(); i.hasNext(); ) + { + out.write(((Certificate) i.next()).getEncoded()); + } + byte[] b = out.toByteArray(); + signedData.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT, + b.length, b, null)); + DERValue sdValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + signedData); + + ArrayList contentInfo = new ArrayList(2); + contentInfo.add(new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_SIGNED_DATA)); + contentInfo.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT, sdValue)); + return new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + contentInfo).getEncoded(); + } + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X509CertSelectorImpl.java b/libjava/classpath/gnu/java/security/x509/X509CertSelectorImpl.java new file mode 100644 index 0000000..36187ad --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509CertSelectorImpl.java @@ -0,0 +1,197 @@ +/* X509CertSelectorImpl.java -- implementation of an X509CertSelector. + Copyright (C) 2004 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 gnu.java.security.x509; + +import java.io.IOException; +import java.security.Principal; +import java.security.cert.CertSelector; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +/** + * Sun's implementation of X509CertSelector sucks. This one tries to work + * better. + */ +public class X509CertSelectorImpl implements CertSelector +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Set issuerNames; + private Set subjectNames; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509CertSelectorImpl() + { + issuerNames = new HashSet(); + subjectNames = new HashSet(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void addIssuerName(byte[] issuerName) throws IOException + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(String issuerName) + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(Principal issuerName) throws IOException + { + if (issuerName instanceof X500DistinguishedName) + issuerNames.add(issuerName); + else if (issuerName instanceof X500Principal) + issuerNames.add(new X500DistinguishedName(((X500Principal) issuerName).getEncoded())); + else + issuerNames.add(new X500DistinguishedName(issuerName.getName())); + } + + public Collection getIssuerNames() + { + return Collections.unmodifiableSet(issuerNames); + } + + public void addSubjectName(byte[] subjectName) throws IOException + { + subjectNames.add(new X500DistinguishedName(subjectName)); + } + + public void addSubjectName(String subjectName) throws IOException + { + subjectNames.add(new X500DistinguishedName(subjectName)); + } + + public void addSubjectName(Principal subjectName) throws IOException + { + if (subjectName instanceof X500DistinguishedName) + subjectNames.add(subjectName); + else if (subjectName instanceof X500Principal) + subjectNames.add(new X500DistinguishedName(((X500Principal) subjectName).getEncoded())); + else + subjectNames.add(new X500DistinguishedName(subjectName.getName())); + } + + public Collection getSubjectNames() + { + return Collections.unmodifiableSet(subjectNames); + } + + public Object clone() + { + X509CertSelectorImpl copy = new X509CertSelectorImpl(); + copy.issuerNames.addAll(issuerNames); + copy.subjectNames.addAll(subjectNames); + return copy; + } + + public boolean match(Certificate cert) + { + if (!(cert instanceof X509Certificate)) + return false; + boolean matchIssuer = false; + boolean matchSubject = false; + try + { + Principal p = ((X509Certificate) cert).getIssuerDN(); + X500DistinguishedName thisName = null; + if (p instanceof X500DistinguishedName) + thisName = (X500DistinguishedName) p; + else if (p instanceof X500Principal) + thisName = new X500DistinguishedName(((X500Principal) p).getEncoded()); + else + thisName = new X500DistinguishedName(p.getName()); + if (issuerNames.isEmpty()) + matchIssuer = true; + else + { + for (Iterator it = issuerNames.iterator(); it.hasNext(); ) + { + X500DistinguishedName name = (X500DistinguishedName) it.next(); + if (thisName.equals(name)) + { + matchIssuer = true; + break; + } + } + } + + p = ((X509Certificate) cert).getSubjectDN(); + thisName = null; + if (p instanceof X500DistinguishedName) + thisName = (X500DistinguishedName) p; + else if (p instanceof X500Principal) + thisName = new X500DistinguishedName(((X500Principal) p).getEncoded()); + else + thisName = new X500DistinguishedName(p.getName()); + if (subjectNames.isEmpty()) + matchSubject = true; + else + { + for (Iterator it = subjectNames.iterator(); it.hasNext(); ) + { + X500DistinguishedName name = (X500DistinguishedName) it.next(); + if (thisName.equals(name)) + { + matchSubject = true; + break; + } + } + } + } + catch (Exception x) + { + } + return matchIssuer && matchSubject; + } +} + diff --git a/libjava/classpath/gnu/java/security/x509/X509Certificate.java b/libjava/classpath/gnu/java/security/x509/X509Certificate.java new file mode 100644 index 0000000..14ac43a --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509Certificate.java @@ -0,0 +1,745 @@ +/* X509Certificate.java -- X.509 certificate. + Copyright (C) 2003, 2004 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 gnu.java.security.x509; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import gnu.java.security.OID; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.ext.BasicConstraints; +import gnu.java.security.x509.ext.ExtendedKeyUsage; +import gnu.java.security.x509.ext.Extension; +import gnu.java.security.x509.ext.IssuerAlternativeNames; +import gnu.java.security.x509.ext.KeyUsage; +import gnu.java.security.x509.ext.SubjectAlternativeNames; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.io.StringWriter; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertificateParsingException; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; +import java.security.spec.DSAParameterSpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.security.auth.x500.X500Principal; + +/** + * An implementation of X.509 certificates. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class X509Certificate extends java.security.cert.X509Certificate + implements Serializable, GnuPKIExtension +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + private static final Logger logger = SystemLogger.SYSTEM; + + protected static final OID ID_DSA = new OID ("1.2.840.10040.4.1"); + protected static final OID ID_DSA_WITH_SHA1 = new OID ("1.2.840.10040.4.3"); + protected static final OID ID_RSA = new OID ("1.2.840.113549.1.1.1"); + protected static final OID ID_RSA_WITH_MD2 = new OID ("1.2.840.113549.1.1.2"); + protected static final OID ID_RSA_WITH_MD5 = new OID ("1.2.840.113549.1.1.4"); + protected static final OID ID_RSA_WITH_SHA1 = new OID ("1.2.840.113549.1.1.5"); + protected static final OID ID_ECDSA_WITH_SHA1 = new OID ("1.2.840.10045.4.1"); + + // This object SHOULD be serialized with an instance of + // java.security.cert.Certificate.CertificateRep, thus all fields are + // transient. + + // The encoded certificate. + protected transient byte[] encoded; + + // TBSCertificate part. + protected transient byte[] tbsCertBytes; + protected transient int version; + protected transient BigInteger serialNo; + protected transient OID algId; + protected transient byte[] algVal; + protected transient X500DistinguishedName issuer; + protected transient Date notBefore; + protected transient Date notAfter; + protected transient X500DistinguishedName subject; + protected transient PublicKey subjectKey; + protected transient BitString issuerUniqueId; + protected transient BitString subjectUniqueId; + protected transient Map extensions; + + // Signature. + protected transient OID sigAlgId; + protected transient byte[] sigAlgVal; + protected transient byte[] signature; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new X.509 certificate from the encoded data. The input + * data are expected to be the ASN.1 DER encoding of the certificate. + * + * @param encoded The encoded certificate data. + * @throws IOException If the certificate cannot be read, possibly + * from a formatting error. + * @throws CertificateException If the data read is not an X.509 + * certificate. + */ + public X509Certificate(InputStream encoded) + throws CertificateException, IOException + { + super(); + extensions = new HashMap(); + try + { + parse(encoded); + } + catch (IOException ioe) + { + logger.log (Component.X509, "", ioe); + throw ioe; + } + catch (Exception e) + { + logger.log (Component.X509, "", e); + CertificateException ce = new CertificateException(e.getMessage()); + ce.initCause (e); + throw ce; + } + } + + protected X509Certificate() + { + extensions = new HashMap(); + } + + // X509Certificate methods. + // ------------------------------------------------------------------------ + + public void checkValidity() + throws CertificateExpiredException, CertificateNotYetValidException + { + checkValidity(new Date()); + } + + public void checkValidity(Date date) + throws CertificateExpiredException, CertificateNotYetValidException + { + if (date.compareTo(notBefore) < 0) + { + throw new CertificateNotYetValidException(); + } + if (date.compareTo(notAfter) > 0) + { + throw new CertificateExpiredException(); + } + } + + public int getVersion() + { + return version; + } + + public BigInteger getSerialNumber() + { + return serialNo; + } + + public Principal getIssuerDN() + { + return issuer; + } + + public X500Principal getIssuerX500Principal() + { + return new X500Principal(issuer.getDer()); + } + + public Principal getSubjectDN() + { + return subject; + } + + public X500Principal getSubjectX500Principal() + { + return new X500Principal(subject.getDer()); + } + + public Date getNotBefore() + { + return (Date) notBefore.clone(); + } + + public Date getNotAfter() + { + return (Date) notAfter.clone(); + } + + public byte[] getTBSCertificate() throws CertificateEncodingException + { + return (byte[]) tbsCertBytes.clone(); + } + + public byte[] getSignature() + { + return (byte[]) signature.clone(); + } + + public String getSigAlgName() + { + if (sigAlgId.equals(ID_DSA_WITH_SHA1)) + { + return "SHA1withDSA"; + } + if (sigAlgId.equals(ID_RSA_WITH_MD2)) + { + return "MD2withRSA"; + } + if (sigAlgId.equals(ID_RSA_WITH_MD5)) + { + return "MD5withRSA"; + } + if (sigAlgId.equals(ID_RSA_WITH_SHA1)) + { + return "SHA1withRSA"; + } + return "unknown"; + } + + public String getSigAlgOID() + { + return sigAlgId.toString(); + } + + public byte[] getSigAlgParams() + { + return (byte[]) sigAlgVal.clone(); + } + + public boolean[] getIssuerUniqueID() + { + if (issuerUniqueId != null) + { + return issuerUniqueId.toBooleanArray(); + } + return null; + } + + public boolean[] getSubjectUniqueID() + { + if (subjectUniqueId != null) + { + return subjectUniqueId.toBooleanArray(); + } + return null; + } + + public boolean[] getKeyUsage() + { + Extension e = getExtension(KeyUsage.ID); + if (e != null) + { + KeyUsage ku = (KeyUsage) e.getValue(); + boolean[] result = new boolean[9]; + boolean[] b = ku.getKeyUsage().toBooleanArray(); + System.arraycopy(b, 0, result, 0, b.length); + return result; + } + return null; + } + + public List getExtendedKeyUsage() throws CertificateParsingException + { + Extension e = getExtension(ExtendedKeyUsage.ID); + if (e != null) + { + List a = ((ExtendedKeyUsage) e.getValue()).getPurposeIds(); + List b = new ArrayList(a.size()); + for (Iterator it = a.iterator(); it.hasNext(); ) + { + b.add(it.next().toString()); + } + return Collections.unmodifiableList(b); + } + return null; + } + + public int getBasicConstraints() + { + Extension e = getExtension(BasicConstraints.ID); + if (e != null) + { + return ((BasicConstraints) e.getValue()).getPathLengthConstraint(); + } + return -1; + } + + public Collection getSubjectAlternativeNames() + throws CertificateParsingException + { + Extension e = getExtension(SubjectAlternativeNames.ID); + if (e != null) + { + return ((SubjectAlternativeNames) e.getValue()).getNames(); + } + return null; + } + + public Collection getIssuerAlternativeNames() + throws CertificateParsingException + { + Extension e = getExtension(IssuerAlternativeNames.ID); + if (e != null) + { + return ((IssuerAlternativeNames) e.getValue()).getNames(); + } + return null; + } + +// X509Extension methods. + // ------------------------------------------------------------------------ + + public boolean hasUnsupportedCriticalExtension() + { + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical() && !e.isSupported()) + return true; + } + return false; + } + + public Set getCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public Set getNonCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (!e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public byte[] getExtensionValue(String oid) + { + Extension e = getExtension(new OID(oid)); + if (e != null) + { + return e.getValue().getEncoded(); + } + return null; + } + + // GnuPKIExtension method. + // ------------------------------------------------------------------------- + + public Extension getExtension(OID oid) + { + return (Extension) extensions.get(oid); + } + + public Collection getExtensions() + { + return extensions.values(); + } + + // Certificate methods. + // ------------------------------------------------------------------------- + + public byte[] getEncoded() throws CertificateEncodingException + { + return (byte[]) encoded.clone(); + } + + public void verify(PublicKey key) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + Signature sig = Signature.getInstance(sigAlgId.toString()); + doVerify(sig, key); + } + + public void verify(PublicKey key, String provider) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + Signature sig = Signature.getInstance(sigAlgId.toString(), provider); + doVerify(sig, key); + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println(X509Certificate.class.getName() + " {"); + out.println(" TBSCertificate {"); + out.println(" version = " + version + ";"); + out.println(" serialNo = " + serialNo + ";"); + out.println(" signature = {"); + out.println(" algorithm = " + getSigAlgName() + ";"); + out.print(" parameters ="); + if (sigAlgVal != null) + { + out.println(); + out.print(Util.hexDump(sigAlgVal, " ")); + } + else + { + out.println(" null;"); + } + out.println(" }"); + out.println(" issuer = " + issuer.getName() + ";"); + out.println(" validity = {"); + out.println(" notBefore = " + notBefore + ";"); + out.println(" notAfter = " + notAfter + ";"); + out.println(" }"); + out.println(" subject = " + subject.getName() + ";"); + out.println(" subjectPublicKeyInfo = {"); + out.println(" algorithm = " + subjectKey.getAlgorithm()); + out.println(" key ="); + out.print(Util.hexDump(subjectKey.getEncoded(), " ")); + out.println(" };"); + out.println(" issuerUniqueId = " + issuerUniqueId + ";"); + out.println(" subjectUniqueId = " + subjectUniqueId + ";"); + out.println(" extensions = {"); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + out.println(" " + it.next()); + } + out.println(" }"); + out.println(" }"); + out.println(" signatureAlgorithm = " + getSigAlgName() + ";"); + out.println(" signatureValue ="); + out.print(Util.hexDump(signature, " ")); + out.println("}"); + return str.toString(); + } + + public PublicKey getPublicKey() + { + return subjectKey; + } + + public boolean equals(Object other) + { + if (!(other instanceof X509Certificate)) + return false; + try + { + if (other instanceof X509Certificate) + return Arrays.equals(encoded, ((X509Certificate) other).encoded); + byte[] enc = ((X509Certificate) other).getEncoded(); + if (enc == null) + return false; + return Arrays.equals(encoded, enc); + } + catch (CertificateEncodingException cee) + { + return false; + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + /** + * Verify this certificate's signature. + */ + private void doVerify(Signature sig, PublicKey key) + throws CertificateException, InvalidKeyException, SignatureException + { + logger.log (Component.X509, "verifying sig={0} key={1}", + new Object[] { sig, key }); + sig.initVerify(key); + sig.update(tbsCertBytes); + if (!sig.verify(signature)) + { + throw new CertificateException("signature not validated"); + } + } + + /** + * Parse a DER stream into an X.509 certificate. + * + * @param encoded The encoded bytes. + */ + private void parse(InputStream encoded) throws Exception + { + DERReader der = new DERReader(encoded); + + // Certificate ::= SEQUENCE { + DERValue cert = der.read(); + logger.log (Component.X509, "start Certificate len == {0}", + new Integer (cert.getLength())); + + this.encoded = cert.getEncoded(); + if (!cert.isConstructed()) + { + throw new IOException("malformed Certificate"); + } + + // TBSCertificate ::= SEQUENCE { + DERValue tbsCert = der.read(); + if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE) + { + throw new IOException("malformed TBSCertificate"); + } + tbsCertBytes = tbsCert.getEncoded(); + logger.log (Component.X509, "start TBSCertificate len == {0}", + new Integer (tbsCert.getLength())); + + // Version ::= INTEGER [0] { v1(0), v2(1), v3(2) } + DERValue val = der.read(); + if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0) + { + version = ((BigInteger) der.read().getValue()).intValue() + 1; + val = der.read(); + } + else + { + version = 1; + } + logger.log (Component.X509, "read version == {0}", + new Integer (version)); + + // SerialNumber ::= INTEGER + serialNo = (BigInteger) val.getValue(); + logger.log (Component.X509, "read serial number == {0}", serialNo); + + // AlgorithmIdentifier ::= SEQUENCE { + val = der.read(); + if (!val.isConstructed()) + { + throw new IOException("malformed AlgorithmIdentifier"); + } + int certAlgLen = val.getLength(); + logger.log (Component.X509, "start AlgorithmIdentifier len == {0}", + new Integer (certAlgLen)); + val = der.read(); + + // algorithm OBJECT IDENTIFIER, + algId = (OID) val.getValue(); + logger.log (Component.X509, "read algorithm ID == {0}", algId); + + // parameters ANY DEFINED BY algorithm OPTIONAL } + if (certAlgLen > val.getEncodedLength()) + { + val = der.read(); + if (val == null) + { + algVal = null; + } + else + { + algVal = val.getEncoded(); + + if (val.isConstructed()) + encoded.skip(val.getLength()); + } + logger.log (Component.X509, "read algorithm parameters == {0}", algVal); + } + + // issuer Name, + val = der.read(); + issuer = new X500DistinguishedName(val.getEncoded()); + der.skip(val.getLength()); + logger.log (Component.X509, "read issuer == {0}", issuer); + + // Validity ::= SEQUENCE { + // notBefore Time, + // notAfter Time } + if (!der.read().isConstructed()) + { + throw new IOException("malformed Validity"); + } + notBefore = (Date) der.read().getValue(); + logger.log (Component.X509, "read notBefore == {0}", notBefore); + notAfter = (Date) der.read().getValue(); + logger.log (Component.X509, "read notAfter == {0}", notAfter); + + // subject Name, + val = der.read(); + subject = new X500DistinguishedName(val.getEncoded()); + der.skip(val.getLength()); + logger.log (Component.X509, "read subject == {0}", subject); + + // SubjectPublicKeyInfo ::= SEQUENCE { + // algorithm AlgorithmIdentifier, + // subjectPublicKey BIT STRING } + DERValue spki = der.read(); + if (!spki.isConstructed()) + { + throw new IOException("malformed SubjectPublicKeyInfo"); + } + KeyFactory spkFac = KeyFactory.getInstance("X.509"); + subjectKey = spkFac.generatePublic(new X509EncodedKeySpec(spki.getEncoded())); + der.skip(spki.getLength()); + logger.log (Component.X509, "read subjectPublicKey == {0}", subjectKey); + + if (version > 1) + { + val = der.read(); + } + if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1) + { + byte[] b = (byte[]) val.getValue(); + issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF); + logger.log (Component.X509, "read issuerUniqueId == {0}", issuerUniqueId); + val = der.read(); + } + if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2) + { + byte[] b = (byte[]) val.getValue(); + subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF); + logger.log (Component.X509, "read subjectUniqueId == {0}", subjectUniqueId); + val = der.read(); + } + if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3) + { + val = der.read(); + logger.log (Component.X509, "start Extensions len == {0}", + new Integer (val.getLength())); + int len = 0; + while (len < val.getLength()) + { + DERValue ext = der.read(); + logger.log (Component.X509, "start extension len == {0}", + new Integer (ext.getLength())); + Extension e = new Extension(ext.getEncoded()); + extensions.put(e.getOid(), e); + der.skip(ext.getLength()); + len += ext.getEncodedLength(); + logger.log (Component.X509, "read extension {0} == {1}", + new Object[] { e.getOid (), e }); + logger.log (Component.X509, "count == {0}", new Integer (len)); + } + + val = der.read (); + } + + logger.log (Component.X509, "read value {0}", val); + if (!val.isConstructed()) + { + throw new CertificateException ("malformed AlgorithmIdentifier"); + } + int sigAlgLen = val.getLength(); + logger.log (Component.X509, "start AlgorithmIdentifier len == {0}", + new Integer (sigAlgLen)); + val = der.read(); + sigAlgId = (OID) val.getValue(); + logger.log (Component.X509, "read algorithm id == {0}", sigAlgId); + if (sigAlgLen > val.getEncodedLength()) + { + val = der.read(); + if (val.getValue() == null) + { + if (subjectKey instanceof DSAPublicKey) + { + AlgorithmParameters params = + AlgorithmParameters.getInstance("DSA"); + DSAParams dsap = ((DSAPublicKey) subjectKey).getParams(); + DSAParameterSpec spec = + new DSAParameterSpec(dsap.getP(), dsap.getQ(), dsap.getG()); + params.init(spec); + sigAlgVal = params.getEncoded(); + } + } + else + { + sigAlgVal = (byte[]) val.getEncoded(); + } + if (val.isConstructed()) + { + encoded.skip(val.getLength()); + } + logger.log (Component.X509, "read parameters == {0}", sigAlgVal); + } + signature = ((BitString) der.read().getValue()).toByteArray(); + logger.log (Component.X509, "read signature ==\n{0}", Util.hexDump(signature, ">>>> ")); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java b/libjava/classpath/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java new file mode 100644 index 0000000..a94b76f --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java @@ -0,0 +1,133 @@ +/* AuthorityKeyIdentifier.java -- Authority key identifier extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.Util; + +import java.io.IOException; +import java.math.BigInteger; + +public class AuthorityKeyIdentifier extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.35"); + + private final byte[] keyIdentifier; + private final GeneralNames authorityCertIssuer; + private final BigInteger authorityCertSerialNumber; + + // Contstructor. + // ------------------------------------------------------------------------- + + public AuthorityKeyIdentifier(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + + // AuthorityKeyIdentifier ::= SEQUENCE { + DERValue val = der.read(); + if (!val.isConstructed()) + throw new IOException("malformed AuthorityKeyIdentifier"); + if (val.getLength() > 0) + val = der.read(); + + // keyIdentifier [0] KeyIdentifier OPTIONAL, + // KeyIdentifier ::= OCTET STRING + if (val.getTagClass() == DER.APPLICATION && val.getTag() == 0) + { + keyIdentifier = (byte[]) val.getValue(); + val = der.read(); + } + else + keyIdentifier = null; + + // authorityCertIssuer [1] GeneralNames OPTIONAL, + if (val.getTagClass() == DER.APPLICATION && val.getTag() == 1) + { + byte[] b = val.getEncoded(); + b[0] = (byte) (DER.CONSTRUCTED|DER.SEQUENCE); + authorityCertIssuer = new GeneralNames(b); + der.skip(val.getLength()); + val = der.read(); + } + else + authorityCertIssuer = null; + + // authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + if (val.getTagClass() == DER.APPLICATION && val.getTag() == 2) + { + authorityCertSerialNumber = new BigInteger((byte[]) val.getValue()); + } + else + authorityCertSerialNumber = null; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getKeyIdentifier() + { + return keyIdentifier != null ? (byte[]) keyIdentifier.clone() : null; + } + + public GeneralNames getAuthorityCertIssuer() + { + return authorityCertIssuer; + } + + public BigInteger getAuthorityCertSerialNumber() + { + return authorityCertSerialNumber; + } + + public String toString() + { + return AuthorityKeyIdentifier.class.getName() + " [ keyId=" + + (keyIdentifier != null ? Util.toHexString (keyIdentifier, ':') : "nil") + + " authorityCertIssuer=" + authorityCertIssuer + + " authorityCertSerialNumbe=" + authorityCertSerialNumber + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/BasicConstraints.java b/libjava/classpath/gnu/java/security/x509/ext/BasicConstraints.java new file mode 100644 index 0000000..00f7a6e --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/BasicConstraints.java @@ -0,0 +1,129 @@ +/* BasicConstraints.java -- the basic constraints extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class BasicConstraints extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.19"); + + private final boolean ca; + private final int pathLenConstraint; + + // Constructor. + // ------------------------------------------------------------------------- + + public BasicConstraints(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue bc = der.read(); + if (!bc.isConstructed()) + throw new IOException("malformed BasicConstraints"); + DERValue val = bc; + if (bc.getLength() > 0) + val = der.read(); + if (val.getTag() == DER.BOOLEAN) + { + ca = ((Boolean) val.getValue()).booleanValue(); + if (val.getEncodedLength() < bc.getLength()) + val = der.read(); + } + else + ca = false; + if (val.getTag() == DER.INTEGER) + { + pathLenConstraint = ((BigInteger) val.getValue()).intValue(); + } + else + pathLenConstraint = -1; + } + + public BasicConstraints (final boolean ca, final int pathLenConstraint) + { + this.ca = ca; + this.pathLenConstraint = pathLenConstraint; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public boolean isCA() + { + return ca; + } + + public int getPathLengthConstraint() + { + return pathLenConstraint; + } + + public byte[] getEncoded() + { + if (encoded == null) + { + List bc = new ArrayList (2); + bc.add (new DERValue (DER.BOOLEAN, new Boolean (ca))); + if (pathLenConstraint >= 0) + bc.add (new DERValue (DER.INTEGER, + BigInteger.valueOf ((long) pathLenConstraint))); + encoded = new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, bc).getEncoded(); + } + return (byte[]) encoded.clone(); + } + + public String toString() + { + return BasicConstraints.class.getName() + " [ isCA=" + ca + + " pathLen=" + pathLenConstraint + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/CRLNumber.java b/libjava/classpath/gnu/java/security/x509/ext/CRLNumber.java new file mode 100644 index 0000000..36b1c7b --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/CRLNumber.java @@ -0,0 +1,97 @@ +/* CRLNumber.java -- CRL number extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.math.BigInteger; + +public class CRLNumber extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.20"); + + private final BigInteger number; + + // Constructor. + // ------------------------------------------------------------------------- + + public CRLNumber(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.INTEGER) + throw new IOException("malformed CRLNumber"); + number = (BigInteger) val.getValue(); + } + + public CRLNumber (final BigInteger number) + { + this.number = number; + } + + // Instance method. + // ------------------------------------------------------------------------- + + public BigInteger getNumber() + { + return number; + } + + public byte[] getEncoded() + { + if (encoded == null) + { + encoded = new DERValue (DER.INTEGER, number).getEncoded(); + } + return (byte[]) encoded.clone(); + } + + public String toString() + { + return CRLNumber.class.getName() + " [ " + number + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java b/libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java new file mode 100644 index 0000000..50bc6d3 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java @@ -0,0 +1,189 @@ +/* CertificatePolicies.java -- certificate policy extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.security.cert.PolicyQualifierInfo; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class CertificatePolicies extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.32"); + + private final List policies; + private final Map policyQualifierInfos; + + // Constructor. + // ------------------------------------------------------------------------- + + public CertificatePolicies(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue pol = der.read(); + if (!pol.isConstructed()) + throw new IOException("malformed CertificatePolicies"); + + int len = 0; + LinkedList policyList = new LinkedList(); + HashMap qualifierMap = new HashMap(); + while (len < pol.getLength()) + { + DERValue policyInfo = der.read(); + if (!policyInfo.isConstructed()) + throw new IOException("malformed PolicyInformation"); + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed CertPolicyId"); + OID policyId = (OID) val.getValue(); + policyList.add(policyId); + if (val.getEncodedLength() < policyInfo.getLength()) + { + DERValue qual = der.read(); + int len2 = 0; + LinkedList quals = new LinkedList(); + while (len2 < qual.getLength()) + { + val = der.read(); + quals.add(new PolicyQualifierInfo(val.getEncoded())); + der.skip(val.getLength()); + len2 += val.getEncodedLength(); + } + qualifierMap.put(policyId, quals); + } + len += policyInfo.getEncodedLength(); + } + + policies = Collections.unmodifiableList(policyList); + policyQualifierInfos = Collections.unmodifiableMap(qualifierMap); + } + + public CertificatePolicies (final List policies, + final Map policyQualifierInfos) + { + for (Iterator it = policies.iterator(); it.hasNext(); ) + if (!(it.next() instanceof OID)) + throw new IllegalArgumentException ("policies must be OIDs"); + for (Iterator it = policyQualifierInfos.entrySet().iterator(); it.hasNext();) + { + Map.Entry e = (Map.Entry) it.next(); + if (!(e.getKey() instanceof OID) || !policies.contains (e.getKey())) + throw new IllegalArgumentException + ("policyQualifierInfos keys must be OIDs"); + if (!(e.getValue() instanceof List)) + throw new IllegalArgumentException + ("policyQualifierInfos values must be Lists of PolicyQualifierInfos"); + for (Iterator it2 = ((List) e.getValue()).iterator(); it.hasNext(); ) + if (!(it2.next() instanceof PolicyQualifierInfo)) + throw new IllegalArgumentException + ("policyQualifierInfos values must be Lists of PolicyQualifierInfos"); + } + this.policies = Collections.unmodifiableList (new ArrayList (policies)); + this.policyQualifierInfos = Collections.unmodifiableMap + (new HashMap (policyQualifierInfos)); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public List getPolicies() + { + return policies; + } + + public List getPolicyQualifierInfos(OID oid) + { + return (List) policyQualifierInfos.get(oid); + } + + public byte[] getEncoded() + { + if (encoded == null) + { + List pol = new ArrayList (policies.size()); + for (Iterator it = policies.iterator(); it.hasNext(); ) + { + OID policy = (OID) it.next(); + List qualifiers = getPolicyQualifierInfos (policy); + List l = new ArrayList (qualifiers == null ? 1 : 2); + l.add (new DERValue (DER.OBJECT_IDENTIFIER, policy)); + if (qualifiers != null) + { + List ll = new ArrayList (qualifiers.size()); + for (Iterator it2 = qualifiers.iterator(); it.hasNext(); ) + { + PolicyQualifierInfo info = (PolicyQualifierInfo) it2.next(); + try + { + ll.add (DERReader.read (info.getEncoded())); + } + catch (IOException ioe) + { + } + } + l.add (new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, ll)); + } + pol.add (new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, l)); + } + encoded = new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, pol).getEncoded(); + } + return (byte[]) encoded.clone(); + } + + public String toString() + { + return CertificatePolicies.class.getName() + " [ policies=" + policies + + " policyQualifierInfos=" + policyQualifierInfos + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java b/libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java new file mode 100644 index 0000000..37b08ac --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java @@ -0,0 +1,95 @@ +/* ExtendedKeyUsage.java -- the extended key usage extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class ExtendedKeyUsage extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.37"); + + private final List purposeIds; + + // Constructor. + // ------------------------------------------------------------------------- + + public ExtendedKeyUsage(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue usageList = der.read(); + if (!usageList.isConstructed()) + throw new IOException("malformed ExtKeyUsageSyntax"); + int len = 0; + purposeIds = new LinkedList(); + while (len < usageList.getLength()) + { + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed KeyPurposeId"); + purposeIds.add(val.getValue()); + len += val.getEncodedLength(); + } + } + + // Instance method. + // ------------------------------------------------------------------------- + + public List getPurposeIds() + { + return Collections.unmodifiableList(purposeIds); + } + + public String toString() + { + return ExtendedKeyUsage.class.getName() + " [ " + purposeIds + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/Extension.java b/libjava/classpath/gnu/java/security/x509/ext/Extension.java new file mode 100644 index 0000000..5ca9ac3 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/Extension.java @@ -0,0 +1,289 @@ +/* Extension.java -- an X.509 certificate or CRL extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.Util; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Extension +{ + + // Fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG = false; + private static void debug(String msg) + { + System.err.print(">> Extension: "); + System.err.println(msg); + } + + /** + * This extension's object identifier. + */ + protected final OID oid; + + /** + * The criticality flag. + */ + protected final boolean critical; + + /** + * Whether or not this extension is locally supported. + */ + protected boolean isSupported; + + /** + * The extension value. + */ + protected final Value value; + + /** + * The DER encoded form. + */ + protected byte[] encoded; + + // Constructors. + // ------------------------------------------------------------------------- + + public Extension(byte[] encoded) throws IOException + { + this.encoded = (byte[]) encoded.clone(); + DERReader der = new DERReader(encoded); + + // Extension ::= SEQUENCE { + DERValue val = der.read(); + if (DEBUG) debug("read val tag == " + val.getTag() + " len == " + val.getLength()); + if (!val.isConstructed()) + throw new IOException("malformed Extension"); + + // extnID OBJECT IDENTIFIER, + val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("expecting OBJECT IDENTIFIER"); + oid = (OID) val.getValue(); + if (DEBUG) debug("read oid == " + oid); + + // critical BOOLEAN DEFAULT FALSE, + val = der.read(); + if (val.getTag() == DER.BOOLEAN) + { + critical = ((Boolean) val.getValue()).booleanValue(); + val = der.read(); + } + else + critical = false; + if (DEBUG) debug("is critical == " + critical); + + // extnValue OCTET STRING } + if (val.getTag() != DER.OCTET_STRING) + throw new IOException("expecting OCTET STRING"); + byte[] encval = (byte[]) val.getValue(); + isSupported = true; + if (oid.equals(AuthorityKeyIdentifier.ID)) + { + value = new AuthorityKeyIdentifier(encval); + } + else if (oid.equals(SubjectKeyIdentifier.ID)) + { + value = new SubjectKeyIdentifier(encval); + } + else if (oid.equals(KeyUsage.ID)) + { + value = new KeyUsage(encval); + } + else if (oid.equals(PrivateKeyUsagePeriod.ID)) + { + value = new PrivateKeyUsagePeriod(encval); + } + else if (oid.equals(CertificatePolicies.ID)) + { + value = new CertificatePolicies(encval); + } + else if (oid.equals (PolicyConstraint.ID)) + { + value = new PolicyConstraint (encval); + } + else if (oid.equals(PolicyMappings.ID)) + { + value = new PolicyMappings(encval); + } + else if (oid.equals(SubjectAlternativeNames.ID)) + { + value = new SubjectAlternativeNames(encval); + } + else if (oid.equals(IssuerAlternativeNames.ID)) + { + value = new IssuerAlternativeNames(encval); + } + else if (oid.equals(BasicConstraints.ID)) + { + value = new BasicConstraints(encval); + } + else if (oid.equals(ExtendedKeyUsage.ID)) + { + value = new ExtendedKeyUsage(encval); + } + else if (oid.equals(CRLNumber.ID)) + { + value = new CRLNumber(encval); + } + else if (oid.equals(ReasonCode.ID)) + { + value = new ReasonCode(encval); + } + else + { + value = new Value(encval); + isSupported = false; + } + if (DEBUG) debug("read value == " + value); + } + + public Extension (final OID oid, final Value value, final boolean critical) + { + this.oid = oid; + this.value = value; + this.critical = critical; + isSupported = true; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public OID getOid() + { + return oid; + } + + public boolean isCritical() + { + return critical; + } + + public boolean isSupported() + { + return isSupported; + } + + public Value getValue() + { + return value; + } + + public byte[] getEncoded() + { + if (encoded == null) + encode(); + return (byte[]) encoded.clone(); + } + + public String toString() + { + return Extension.class.getName() + " [ id=" + oid + " critical=" + + critical + " value=" + value + " ]"; + } + + public DERValue getDerValue() + { + List ext = new ArrayList (3); + ext.add (new DERValue (DER.OBJECT_IDENTIFIER, oid)); + ext.add (new DERValue (DER.BOOLEAN, new Boolean (critical))); + ext.add (new DERValue (DER.OCTET_STRING, value.getEncoded())); + return new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, ext); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private void encode() + { + encoded = getDerValue().getEncoded(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + public static class Value + { + + // Fields. + // ----------------------------------------------------------------------- + + protected byte[] encoded; + + // Constructor. + // ----------------------------------------------------------------------- + + public Value(byte[] encoded) + { + this.encoded = (byte[]) encoded.clone(); + } + + protected Value() { } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return (byte[]) encoded; + } + + public boolean equals(Object o) + { + if (!(o instanceof Value)) + return false; + return Arrays.equals(encoded, ((Value) o).encoded); + } + + public String toString() + { + return Util.toHexString(encoded, ':'); + } + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java b/libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java new file mode 100644 index 0000000..e92aeda --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java @@ -0,0 +1,155 @@ +/* GeneralNames.java -- the GeneralNames object + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.X500DistinguishedName; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class GeneralNames +{ + + // Instance methods. + // ------------------------------------------------------------------------- + + public static final int OTHER_NAME = 0; + public static final int RFC822_NAME = 1; + public static final int DNS_NAME = 2; + public static final int X400_ADDRESS = 3; + public static final int DIRECTORY_NAME = 4; + public static final int EDI_PARTY_NAME = 5; + public static final int URI = 6; + public static final int IP_ADDRESS = 7; + public static final int REGISTERED_ID = 8; + + private List names; + + // Constructor. + // ------------------------------------------------------------------------- + + public GeneralNames(final byte[] encoded) throws IOException + { + names = new LinkedList(); + DERReader der = new DERReader(encoded); + DERValue nameList = der.read(); + if (!nameList.isConstructed()) + throw new IOException("malformed GeneralNames"); + int len = 0; + while (len < nameList.getLength()) + { + DERValue name = der.read(); + List namePair = new ArrayList(2); + if (name.getTagClass() != DER.APPLICATION) + throw new IOException("malformed GeneralName"); + namePair.add(new Integer(name.getTag())); + DERValue val = null; + switch (name.getTag()) + { + case RFC822_NAME: + case DNS_NAME: + case X400_ADDRESS: + case URI: + namePair.add(new String((byte[]) name.getValue())); + break; + + case OTHER_NAME: + case EDI_PARTY_NAME: + namePair.add(name.getValue()); + break; + + case DIRECTORY_NAME: + byte[] b = name.getEncoded(); + b[0] = (byte) (DER.CONSTRUCTED|DER.SEQUENCE); + namePair.add(new X500DistinguishedName(b).toString()); + break; + + case IP_ADDRESS: + namePair.add(InetAddress.getByAddress((byte[]) name.getValue()) + .getHostAddress()); + break; + + case REGISTERED_ID: + byte[] bb = name.getEncoded(); + bb[0] = (byte) DER.OBJECT_IDENTIFIER; + namePair.add(new OID(bb).toString()); + break; + + default: + throw new IOException("unknown tag " + name.getTag()); + } + names.add(namePair); + len += name.getEncodedLength(); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public List getNames() + { + List l = new ArrayList(names.size()); + for (Iterator it = names.iterator(); it.hasNext(); ) + { + List ll = (List) it.next(); + List pair = new ArrayList(2); + pair.add(ll.get(0)); + if (ll.get(1) instanceof byte[]) + pair.add(((byte[]) ll.get(1)).clone()); + else + pair.add(ll.get(1)); + l.add(Collections.unmodifiableList(pair)); + } + return Collections.unmodifiableList(l); + } + + public String toString() + { + return GeneralNames.class.getName() + " [ " + names + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java b/libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java new file mode 100644 index 0000000..8b017dc --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java @@ -0,0 +1,77 @@ +/* IssuerAlternatuveNames.java -- issuer alternative names extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; + +import java.io.IOException; +import java.util.List; + +public class IssuerAlternativeNames extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.18"); + + private final GeneralNames names; + + // Constructor. + // ------------------------------------------------------------------------- + + public IssuerAlternativeNames(final byte[] encoded) throws IOException + { + super(encoded); + names = new GeneralNames(encoded); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public List getNames() + { + return names.getNames(); + } + + public String toString() + { + return IssuerAlternativeNames.class.getName() + " [ " + names + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/KeyUsage.java b/libjava/classpath/gnu/java/security/x509/ext/KeyUsage.java new file mode 100644 index 0000000..dcd9818 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/KeyUsage.java @@ -0,0 +1,92 @@ +/* KeyUsage.java -- the key usage extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.BitString; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; + +public class KeyUsage extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.15"); + public static final int DIGITAL_SIGNATURE = 0; + public static final int NON_REPUDIATION = 1; + public static final int KEY_ENCIPHERMENT = 2; + public static final int DATA_ENCIPHERMENT = 3; + public static final int KEY_AGREEMENT = 4; + public static final int KEY_CERT_SIGN = 5; + public static final int CRL_SIGN = 6; + public static final int ENCIPHER_ONLY = 7; + public static final int DECIPHER_ONLY = 8; + + private final BitString keyUsage; + + // Constructor. + // ------------------------------------------------------------------------- + + public KeyUsage(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.BIT_STRING) + throw new IOException("malformed KeyUsage"); + keyUsage = (BitString) val.getValue(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public BitString getKeyUsage() + { + return keyUsage; + } + + public String toString() + { + return KeyUsage.class.getName() + " [ " + keyUsage + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/PolicyConstraint.java b/libjava/classpath/gnu/java/security/x509/ext/PolicyConstraint.java new file mode 100644 index 0000000..20cf552 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/PolicyConstraint.java @@ -0,0 +1,107 @@ +/* PolicyConstraint.java -- policyConstraint extension + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.math.BigInteger; + +public class PolicyConstraint extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID ("2.5.29.36"); + + private final int requireExplicitPolicy; + private final int inhibitPolicyMapping; + + // Constructors. + // ------------------------------------------------------------------------- + + public PolicyConstraint (final byte[] encoded) throws IOException + { + super (encoded); + int rpc = -1, ipm = -1; + DERReader der = new DERReader(encoded); + DERValue pc = der.read(); + if (!pc.isConstructed()) + throw new IOException("malformed PolicyConstraints"); + DERValue val; + int len = pc.getLength(); + while (len > 0) + { + val = der.read(); + if (val.getTag() == 0) + rpc = new BigInteger ((byte[]) val.getValue()).intValue(); + else if (val.getTag() == 1) + ipm = new BigInteger ((byte[]) val.getValue()).intValue(); + else + throw new IOException ("invalid policy constraint"); + len -= val.getEncodedLength(); + } + + requireExplicitPolicy = rpc; + inhibitPolicyMapping = ipm; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int getRequireExplicitPolicy() + { + return requireExplicitPolicy; + } + + public int getInhibitPolicyMapping() + { + return inhibitPolicyMapping; + } + + public String toString() + { + return PolicyConstraint.class.getName() + " [ requireExplicitPolicy=" + + requireExplicitPolicy + " inhibitPolicyMapping=" + inhibitPolicyMapping + + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/PolicyMappings.java b/libjava/classpath/gnu/java/security/x509/ext/PolicyMappings.java new file mode 100644 index 0000000..0493ed8 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/PolicyMappings.java @@ -0,0 +1,104 @@ +/* PolicyMappings.java -- policy mappings extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class PolicyMappings extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.33"); + + private final Map mappings; + + // Constructor. + // ------------------------------------------------------------------------- + + public PolicyMappings(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue maps = der.read(); + if (!maps.isConstructed()) + throw new IOException("malformed PolicyMappings"); + int len = 0; + HashMap _mappings = new HashMap(); + while (len < maps.getLength()) + { + DERValue map = der.read(); + if (!map.isConstructed()) + throw new IOException("malformed PolicyMapping"); + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed PolicyMapping"); + OID issuerPolicy = (OID) val.getValue(); + val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed PolicyMapping"); + OID subjectPolicy = (OID) val.getValue(); + _mappings.put(issuerPolicy, subjectPolicy); + len += map.getEncodedLength(); + } + mappings = Collections.unmodifiableMap(_mappings); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public OID getSubjectDomainPolicy(OID issuerDomainPolicy) + { + return (OID) mappings.get(issuerDomainPolicy); + } + + public String toString() + { + return PolicyMappings.class.getName() + " [ " + mappings + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java b/libjava/classpath/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java new file mode 100644 index 0000000..3b531c0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java @@ -0,0 +1,105 @@ +/* PrivateKeyUsagePeriod.java -- private key usage period extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.util.Date; + +public class PrivateKeyUsagePeriod extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.16"); + + private final Date notBefore; + private final Date notAfter; + + // Constructor. + // ------------------------------------------------------------------------- + + public PrivateKeyUsagePeriod(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue val = der.read(); + if (!val.isConstructed()) + throw new IOException("malformed PrivateKeyUsagePeriod"); + if (val.getLength() > 0) + val = der.read(); + if (val.getTagClass() == DER.APPLICATION || val.getTag() == 0) + { + notBefore = (Date) val.getValueAs (DER.GENERALIZED_TIME); + val = der.read(); + } + else + notBefore = null; + if (val.getTagClass() == DER.APPLICATION || val.getTag() == 1) + { + notAfter = (Date) val.getValueAs (DER.GENERALIZED_TIME); + } + else + notAfter = null; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Date getNotBefore() + { + return notBefore != null ? (Date) notBefore.clone() : null; + } + + public Date getNotAfter() + { + return notAfter != null ? (Date) notAfter.clone() : null; + } + + public String toString() + { + return PrivateKeyUsagePeriod.class.getName() + " [ notBefore=" + notBefore + + " notAfter=" + notAfter + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/ReasonCode.java b/libjava/classpath/gnu/java/security/x509/ext/ReasonCode.java new file mode 100644 index 0000000..a6d59e4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/ReasonCode.java @@ -0,0 +1,85 @@ +/* ReasonCode.java -- a reason code for a certificate revocation. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.math.BigInteger; + +public class ReasonCode extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.21"); + + public final int reason; + + // Constructor. + // ------------------------------------------------------------------------- + + public ReasonCode(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.ENUMERATED) + throw new IOException("malformed CRLReason"); + reason = ((BigInteger) val.getValue()).intValue(); + if (reason < 0 || reason == 7 || reason > 10) + throw new IOException("illegal reason: " + reason); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public int getReasonCode() + { + return reason; + } + + public String toString() + { + return ReasonCode.class.getName() + " [ " + reason + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java b/libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java new file mode 100644 index 0000000..f88e854 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java @@ -0,0 +1,77 @@ +/* SubjectAlternatuveNames.java -- subject alternative names extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; + +import java.io.IOException; +import java.util.List; + +public class SubjectAlternativeNames extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.17"); + + private final GeneralNames names; + + // Constructor. + // ------------------------------------------------------------------------- + + public SubjectAlternativeNames(final byte[] encoded) throws IOException + { + super(encoded); + names = new GeneralNames(encoded); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public List getNames() + { + return names.getNames(); + } + + public String toString() + { + return SubjectAlternativeNames.class.getName() + " [ " + names + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/SubjectKeyIdentifier.java b/libjava/classpath/gnu/java/security/x509/ext/SubjectKeyIdentifier.java new file mode 100644 index 0000000..fc65abe --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/SubjectKeyIdentifier.java @@ -0,0 +1,84 @@ +/* SubjectKeyIdentifier.java -- subject key identifier extension. + Copyright (C) 2004 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 gnu.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.Util; + +import java.io.IOException; + +public class SubjectKeyIdentifier extends Extension.Value +{ + + // Constant. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.14"); + + private final byte[] keyIdentifier; + + // Constructor. + // ------------------------------------------------------------------------- + + public SubjectKeyIdentifier(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.OCTET_STRING) + throw new IOException("malformed SubjectKeyIdentifier"); + keyIdentifier = (byte[]) val.getValue(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getKeyIdentifier() + { + return (byte[]) keyIdentifier.clone(); + } + + public String toString() + { + return SubjectKeyIdentifier.class.getName() + " [ " + + Util.toHexString (keyIdentifier, ':') + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/package.html b/libjava/classpath/gnu/java/security/x509/ext/package.html new file mode 100644 index 0000000..cc44e55c --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/package.html @@ -0,0 +1,46 @@ + + + + +
s
, a set of ranges
+ * and the corresponding attributes. This is used to build an iterator.
+ * The array ranges
should be formatted as follow:
+ * each element of ranges
specifies the index in the string
+ * until which the corresponding map of attributes at the same position
+ * is applied. For example, if you have:
+ * + * s = "hello"; + * ranges = new int[] { 2, 6 }; + * attributes = new HashMap[2]; + *+ *
"he"
will have the attributes attributes[0]
,
+ * "llo"
the attributes[1]
.
+ */
+ public FormatCharacterIterator (String s, int[] ranges, HashMap[] attributes)
+ {
+ formattedString = s;
+ this.ranges = ranges;
+ this.attributes = attributes;
+ }
+
+ /*
+ * The following methods are inherited from AttributedCharacterIterator,
+ * and thus are already documented.
+ */
+
+ public Set getAllAttributeKeys()
+ {
+ if (attributes != null && attributes[attributeIndex] != null)
+ return attributes[attributeIndex].keySet();
+ else
+ return new HashSet();
+ }
+
+ public Map getAttributes()
+ {
+ if (attributes != null && attributes[attributeIndex] != null)
+ return attributes[attributeIndex];
+ else
+ return new HashMap();
+ }
+
+ public Object getAttribute (AttributedCharacterIterator.Attribute attrib)
+ {
+ if (attributes != null && attributes[attributeIndex] != null)
+ return attributes[attributeIndex].get (attrib);
+ else
+ return null;
+ }
+
+ public int getRunLimit(Set reqAttrs)
+ {
+ if (attributes == null)
+ return formattedString.length();
+
+ int currentAttrIndex = attributeIndex;
+ Set newKeys;
+
+ do
+ {
+ currentAttrIndex++;
+ if (currentAttrIndex == attributes.length)
+ return formattedString.length();
+ if (attributes[currentAttrIndex] == null)
+ break;
+ newKeys = attributes[currentAttrIndex].keySet();
+ }
+ while (newKeys.containsAll (reqAttrs));
+
+ return ranges[currentAttrIndex-1];
+ }
+
+ public int getRunLimit (AttributedCharacterIterator.Attribute attribute)
+ {
+ Set s = new HashSet();
+
+ s.add (attribute);
+ return getRunLimit (s);
+ }
+
+ public int getRunLimit()
+ {
+ if (attributes == null)
+ return formattedString.length();
+ if (attributes[attributeIndex] == null)
+ {
+ for (int i=attributeIndex+1;inull
.
+ *
+ * @param text The string to append to the iterator.
+ */
+ public void append (String text)
+ {
+ append (text, null);
+ }
+
+ /**
+ * This method adds a set of attributes to a range of character. The
+ * bounds are always inclusive. In the case many attributes have to
+ * be added it is advised to directly use {@link #mergeAttributes([Ljava.util.HashMap;[I}
+ *
+ * @param attributes Attributes to merge into the iterator.
+ * @param range_start Lower bound of the range of characters which will receive the
+ * attribute.
+ * @param range_end Upper bound of the range of characters which will receive the
+ * attribute.
+ *
+ * @throws IllegalArgumentException if ranges are out of bounds.
+ */
+ public void addAttributes(HashMap attributes, int range_start, int range_end)
+ {
+ if (range_start == 0)
+ mergeAttributes(new HashMap[] { attributes }, new int[] { range_end });
+ else
+ mergeAttributes(new HashMap[] { null, attributes }, new int[] { range_start, range_end });
+ }
+
+ private void debug(String s)
+ {
+ if (DEBUG)
+ System.out.println(s);
+ }
+
+ private void dumpTable()
+ {
+ int start_range = 0;
+
+ if (!DEBUG)
+ return;
+
+ System.out.println("Dumping internal table:");
+ for (int i = 0; i < ranges.length; i++)
+ {
+ System.out.print("\t" + start_range + " => " + ranges[i] + ":");
+ if (attributes[i] == null)
+ System.out.println("null");
+ else
+ {
+ Set keyset = attributes[i].keySet();
+ if (keyset != null)
+ {
+ Iterator keys = keyset.iterator();
+
+ while (keys.hasNext())
+ System.out.print(" " + keys.next());
+ }
+ else
+ System.out.println("keySet null");
+ System.out.println();
+ }
+ }
+ System.out.println();
+ System.out.flush();
+ }
+}
diff --git a/libjava/classpath/gnu/java/text/LineBreakIterator.java b/libjava/classpath/gnu/java/text/LineBreakIterator.java
new file mode 100644
index 0000000..ad07479
--- /dev/null
+++ b/libjava/classpath/gnu/java/text/LineBreakIterator.java
@@ -0,0 +1,194 @@
+/* LineBreakIterator.java - Default word BreakIterator.
+ Copyright (C) 1999, 2001, 2004 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 gnu.java.text;
+
+import java.text.CharacterIterator;
+
+/**
+ * @author Tom Tromey + * doubleEnum = new DoubleEnumeration(enum1, enum2); + * while (doubleEnum.hasMoreElements()) { + * Object o = doubleEnum.nextElement(); + * do_something(o); + * } + *+ * it calls hasMoreElements of the Enumerations as few times as + * possible. + * The references to the Enumerations are cleared as soon as they have no + * more elements to help garbage collecting. + * + * @author Jochen Hoenicke + * @author Mark Wielaard (mark@klomp.org) + */ +public class DoubleEnumeration implements Enumeration +{ + /** + * This is true as long as one of the enumerations has more + * elements. + * Only valid when hasChecked is true. + * Set in
hasMoreElements()
+ */
+ private boolean hasMore;
+ /**
+ * This is true, if it is sure that hasMore indicates wether there are
+ * more elements.
+ * Set to true in hasMoreElements()
.
+ * Set to false in getNextElement()
.
+ */
+ private boolean hasChecked;
+ /**
+ * The first enumeration.
+ */
+ private Enumeration e1;
+ /**
+ * The second enumeration.
+ */
+ private Enumeration e2;
+
+ /**
+ * Creates a new Enumeration combining the given two enumerations.
+ * The enumerations mustn't be accessed by other classes.
+ */
+ public DoubleEnumeration(Enumeration e1, Enumeration e2)
+ {
+ this.e1 = e1;
+ this.e2 = e2;
+ hasChecked = false;
+ }
+
+ /**
+ * Returns true, if at least one of the two enumerations has more
+ * elements.
+ */
+ public boolean hasMoreElements()
+ {
+ if (hasChecked)
+ return hasMore;
+
+ hasMore = (e1 != null && e1.hasMoreElements());
+
+ if (!hasMore) {
+ e1 = e2;
+ e2 = null;
+ hasMore = (e1 != null && e1.hasMoreElements());
+ }
+
+ hasChecked = true;
+ return hasMore;
+ }
+
+ /**
+ * Returns the next element. This returns the next element of the
+ * first enumeration, if it has more elements, otherwise the next
+ * element of the second enumeration. If both enumeration don't have
+ * any elements it throws a NoSuchElementException
.
+ */
+ public Object nextElement()
+ {
+ if (!hasMoreElements())
+ throw new NoSuchElementException();
+ else {
+ hasChecked = false;
+ return e1.nextElement();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/util/EmptyEnumeration.java b/libjava/classpath/gnu/java/util/EmptyEnumeration.java
new file mode 100644
index 0000000..46a82d6
--- /dev/null
+++ b/libjava/classpath/gnu/java/util/EmptyEnumeration.java
@@ -0,0 +1,96 @@
+/* EmptyEnumeration.java -- a constant empty enumeration
+ Copyright (C) 2001, 2002 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 gnu.java.util;
+
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * This is a helper class that produces an empty Enumerations. There is only
+ * one instance of this class that can be used whenever one needs a
+ * non-null but empty enumeration. Using this class prevents multiple
+ * small objects and inner classes. getInstance()
returns
+ * the only instance of this class. It can be shared by multiple objects and
+ * threads.
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public final class EmptyEnumeration implements Enumeration, Serializable
+{
+ /** The only instance of this class */
+ private static final EmptyEnumeration instance = new EmptyEnumeration();
+
+ /**
+ * Private constructor that creates a new empty Enumeration.
+ */
+ private EmptyEnumeration()
+ {
+ }
+
+ /**
+ * Returns the only instance of this class.
+ * It can be shared by multiple objects and threads.
+ *
+ * @return the common empty enumeration
+ */
+ public static EmptyEnumeration getInstance()
+ {
+ return instance;
+ }
+
+ /**
+ * Returns false, since there are no elements.
+ *
+ * @return false
+ */
+ public boolean hasMoreElements()
+ {
+ return false;
+ }
+
+ /**
+ * Always throws NoSuchElementException
, since it is empty.
+ *
+ * @throws NoSuchElementException this is empty
+ */
+ public Object nextElement()
+ {
+ throw new NoSuchElementException();
+ }
+}
diff --git a/libjava/classpath/gnu/java/util/package.html b/libjava/classpath/gnu/java/util/package.html
new file mode 100644
index 0000000..d90fa59
--- /dev/null
+++ b/libjava/classpath/gnu/java/util/package.html
@@ -0,0 +1,46 @@
+
+
+
+
+newNode
field to true
+ * since there is no real backing store, so all nodes are new.
+ */
+ public MemoryBasedPreferences(MemoryBasedPreferences parent,
+ String name,
+ boolean isUser) {
+ super(parent, name);
+ this.isUser = isUser;
+
+ // Since we do not have a real backing store all nodes are new
+ newNode = true;
+ }
+
+ /**
+ * Returns true if this node was created as a user node.
+ */
+ public boolean isUserNode() {
+ return isUser;
+ }
+
+ /**
+ * Returns an empty array since all children names are always already
+ * chached.
+ */
+ protected String[] childrenNamesSpi() throws BackingStoreException {
+ return new String[0];
+ }
+
+ /**
+ * Returns a new node with the given name with as parent this node and
+ * with the isUser
flag set to the same value as this node.
+ */
+ protected AbstractPreferences childSpi(String childName) {
+ return new MemoryBasedPreferences(this, childName, isUser);
+ }
+
+ /**
+ * Returns a (possibly empty) array of keys of the preferences entries of
+ * this node.
+ */
+ protected String[] keysSpi() throws BackingStoreException {
+ return (String[]) entries.keySet().toArray(new String[entries.size()]);
+ }
+
+ /**
+ * Returns the associated value from this nodes preferences entries or
+ * null when the key has not been set.
+ */
+ protected String getSpi(String key) {
+ return (String) entries.get(key);
+ }
+
+ /**
+ * Sets the value for the given key.
+ */
+ protected void putSpi(String key, String value) {
+ entries.put(key, value);
+ }
+
+ /**
+ * Removes the entry with the given key.
+ */
+ protected void removeSpi(String key) {
+ entries.remove(key);
+ }
+
+ /**
+ * Does nothing since we do not have any backing store.
+ */
+ protected void flushSpi() {
+ }
+
+ /**
+ * Does nothing since we do not have any backing store.
+ */
+ protected void syncSpi() {
+ }
+
+ /**
+ * Just removes the entries map of this node.
+ */
+ protected void removeNodeSpi() {
+ entries = null;
+ }
+}
diff --git a/libjava/classpath/gnu/java/util/prefs/NodeReader.java b/libjava/classpath/gnu/java/util/prefs/NodeReader.java
new file mode 100644
index 0000000..4cd52e5
--- /dev/null
+++ b/libjava/classpath/gnu/java/util/prefs/NodeReader.java
@@ -0,0 +1,223 @@
+/* NodeReader - Reads and imports preferences nodes from files
+ Copyright (C) 2001 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 gnu.java.util.prefs;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.prefs.InvalidPreferencesFormatException;
+import java.util.prefs.Preferences;
+import java.util.prefs.PreferencesFactory;
+
+/**
+ * Reads and imports preferences nodes from files.
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public class NodeReader {
+
+ private final BufferedReader br;
+ private String line = "";
+
+ private final PreferencesFactory factory;
+
+ public NodeReader(Reader r, PreferencesFactory factory) {
+ if(r instanceof BufferedReader) {
+ br = (BufferedReader) r;
+ } else {
+ br = new BufferedReader(r);
+ }
+ this.factory = factory;
+ }
+
+ public NodeReader(InputStream is, PreferencesFactory factory) {
+ this(new InputStreamReader(is), factory);
+ }
+
+ public void importPreferences()
+ throws InvalidPreferencesFormatException, IOException
+ {
+ readPreferences();
+ }
+
+ private void readPreferences()
+ throws InvalidPreferencesFormatException, IOException
+ {
+ // Begin starting tag
+ skipTill("writeCloseParents()
after writing the node
+ * itself.
+ */
+ private int writeParents() throws IOException {
+ int parents;
+ String path = prefs.absolutePath();
+ int lastslash = path.lastIndexOf("/");
+ if (lastslash > 0) {
+ path = path.substring(1, lastslash);
+ StringTokenizer st = new StringTokenizer(path);
+ parents = st.countTokens();
+
+ System.out.println("path: " + path);
+ System.out.println("parents: " + parents);
+
+ for (int i=0; iString
here as the
+ * original look and feel if only a few changes are being made rather
+ * than something completely new and different.
+ */
+ public String getID()
+ {
+ return "Gtk";
+ }
+
+ public boolean isNativeLookAndFeel()
+ {
+ return false;
+ }
+
+ public boolean isSupportedLookAndFeel()
+ {
+ return true;
+ }
+
+ protected void initClassDefaults(UIDefaults table)
+ {
+ super.initClassDefaults(table);
+
+ String gtkPkgName = "gnu.javax.swing.plaf.gtk.";
+
+
+ Object[] defaults = {
+ "SliderUI", gtkPkgName + "GtkSliderUI"
+ };
+ /*
+ "CheckBoxUI", gtkPkgName + "GtkCheckBoxUI",
+ "ButtonUI", gtkPkgName + "GtkButtonUI"
+ "ColorChooserUI", "MetalColorChooserUI",
+ "MenuBarUI", "MetalMenuBarUI",
+ "MenuUI", "MetalMenuUI",
+ "MenuItemUI", "MetalMenuItemUI",
+ "CheckBoxMenuItemUI", "MetalCheckBoxMenuItemUI",
+ "RadioButtonMenuItemUI", "MetalRadioButtonMenuItemUI",
+ "RadioButtonUI", "MetalRadioButtonUI",
+ "ToggleButtonUI", "MetalToggleButtonUI",
+ "PopupMenuUI", "MetalPopupMenuUI",
+ "ProgressBarUI", "MetalProgressBarUI",
+ "ScrollBarUI", "MetalScrollBarUI",
+ "ScrollPaneUI", "MetalScrollPaneUI",
+ "SplitPaneUI", "MetalSplitPaneUI",
+ "SeparatorUI", "MetalSeparatorUI",
+ "ToolBarSeparatorUI", "MetalToolBarSeparatorUI",
+ "PopupMenuSeparatorUI", "MetalPopupMenuSeparatorUI",
+ "TabbedPaneUI", "MetalTabbedPaneUI",
+ "TextAreaUI", "MetalTextAreaUI",
+ "TextFieldUI", "MetalTextFieldUI",
+ "PasswordFieldUI", "MetalPasswordFieldUI",
+ "TextPaneUI", "MetalTextPaneUI",
+ "EditorPaneUI", "MetalEditorPaneUI",
+ "TreeUI", "MetalTreeUI",
+ "LabelUI", "MetalLabelUI",
+ "ListUI", "MetalListUI",
+ "ToolBarUI", "MetalToolBarUI",
+ "ToolTipUI", "MetalToolTipUI",
+ "ComboBoxUI", "MetalComboBoxUI",
+ "TableUI", "MetalTableUI",
+ "TableHeaderUI", "MetalTableHeaderUI",
+ "InternalFrameUI", "GtkInternalFrameUI",
+ "StandardDialogUI", "GtkStandardDialogUI",
+ "DesktopPaneUI", "GtkDesktopPaneUI",
+ "DesktopIconUI", "GtkDesktopIconUI",
+ "DirectoryPaneUI", "GtkDirectoryPaneUI",
+ "FileChooserUI", "GtkFileChooserUI",
+ "OptionPaneUI", "GtkOptionPaneUI" }
+ */
+ table.putDefaults(defaults);
+
+ }
+
+ protected void initSystemColorDefaults(UIDefaults table)
+ {
+ String[] colors = {
+ "desktop", "#000000",
+ "activeCaption", "#163555",
+ "activeCaptionText", "#FFFFFF",
+ "activeCaptionBorder", "#000000",
+ "inactiveCaption", "#375676",
+ "inactiveCaptionText", "#999999",
+ "inactiveCaptionBorder", "#000000",
+ "window", "#FFFFFF",
+ "windowBorder", "#969696",
+ "windowText", "#000000",
+ "menu", "#d6d6d6",
+ "menuText", "#000000",
+ "text", "#FFFFFF",
+ "textText", "#000000",
+ "textHighlight", "#00009c",
+ "textHighlightText", "#FFFFFF",
+ "textInactiveText", "#999999",
+ "control", "#d6d6d6",
+ "controlText", "#000000",
+ "controlHighlight", "#eaeaea",
+ "controlLtHighlight", "#eaeaea",
+ "controlShadow", "#c3c3c3",
+ "controlDkShadow", "#888888",
+ "scrollbar", "#c3c3c3",
+ "info", "#d6d6d6",
+ "infoText", "#000000"
+ };
+
+ loadSystemColors(table, colors, false);
+ }
+
+ protected void initComponentDefaults(UIDefaults table)
+ {
+ super.initComponentDefaults(table);
+
+ // define common resources
+ // fonts
+ FontUIResource sansSerifPlain10 =
+ new FontUIResource("SansSerif", Font.PLAIN, 10);
+ FontUIResource serifPlain10 =
+ new FontUIResource("Serif", Font.PLAIN, 10);
+ // insets
+ // borders
+ // colors
+ ColorUIResource controlDkShadow = new ColorUIResource(table.getColor("controlDkShadow"));
+ ColorUIResource controlShadow = new ColorUIResource(table.getColor("controlShadow"));
+ ColorUIResource control = new ColorUIResource(table.getColor("control"));
+ ColorUIResource scrollbar = new ColorUIResource(table.getColor("scrollbar"));
+ ColorUIResource controlHighlight = new ColorUIResource(table.getColor("controlHighlight"));
+ if (scrollbar == null)
+ System.out.println("scrollbar is null");
+
+ ColorUIResource white = new ColorUIResource(Color.white);
+ ColorUIResource black = new ColorUIResource(Color.black);
+ ColorUIResource blue = new ColorUIResource(Color.blue);
+
+ // icons
+ Object errorIcon = LookAndFeel.makeIcon(getClass(), "icons/error.gif");
+ // any other resources like dimensions and integer values
+
+ // define defaults
+ Object[] defaults =
+ {
+ "Button.font", sansSerifPlain10,
+ "CheckBox.font", sansSerifPlain10,
+ "RadioButton.pressed", black,
+ "Slider.focus", blue,
+ "Slider.foreground", control,
+ "Slider.highlight", controlHighlight,
+ "Slider.shadow", controlShadow,
+ "Slider.background", controlDkShadow
+
+// "Slider.background", "#888888",
+// "Slider.focus", "#c3c3c3",
+// "Slider.foreground", "#d6d6d6",
+// "Slider.highlight", "#ffffff",
+// "Slider.shadow", "#000000"
+
+
+ };
+
+ table.putDefaults(defaults);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/GtkRadioButtonUI.java b/libjava/classpath/gnu/javax/swing/plaf/gtk/GtkRadioButtonUI.java
new file mode 100644
index 0000000..19d5338
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/GtkRadioButtonUI.java
@@ -0,0 +1,69 @@
+/* GtkRadioButtonUI.java
+ Copyright (c) 1999 by 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 gnu.javax.swing.plaf.gtk;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.plaf.*;
+import javax.swing.plaf.basic.*;
+
+/**
+ *
+ * @author Brian Jones
+ * @see javax.swing.LookAndFeel
+ */
+public class GtkRadioButtonUI extends BasicRadioButtonUI
+{
+ public GtkRadioButtonUI()
+ {
+ super();
+ }
+
+ public static ComponentUI createUI(JComponent c)
+ {
+ return new GtkRadioButtonUI();
+ }
+
+ public String getPropertyPrefix()
+ {
+ // FIXME
+ System.err.println(super.getPropertyPrefix());
+ return super.getPropertyPrefix();
+ }
+}
+
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/GtkSliderUI.java b/libjava/classpath/gnu/javax/swing/plaf/gtk/GtkSliderUI.java
new file mode 100644
index 0000000..c576b3d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/GtkSliderUI.java
@@ -0,0 +1,230 @@
+/* GtkSliderUI.java
+ Copyright (c) 1999 by 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 gnu.javax.swing.plaf.gtk;
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.plaf.*;
+import javax.swing.plaf.basic.*;
+
+/**
+ * Gtk-like slider
+ *
+ * @author Brian Jones
+ * @see javax.swing.LookAndFeel
+ */
+public class GtkSliderUI extends BasicSliderUI
+{
+ private static Color thumbFgColor;
+ private static Color thumbBgColor;
+ private static Color thumbHighlight;
+ private static Color thumbFocus;
+
+ private static Color bgColor;
+ private static Color fgColor;
+ private static Color focusColor;
+ private static Color highlight;
+ private static Color shadow;
+
+ private static final Dimension PREF_HORIZ = new Dimension(250, 15);
+ private static final Dimension PREF_VERT = new Dimension(15, 250);
+ private static final Dimension MIN_HORIZ = new Dimension(25, 15);
+ private static final Dimension MIN_VERT = new Dimension(15, 25);
+
+ public GtkSliderUI()
+ {
+ super(null);
+ bgColor = UIManager.getColor("Slider.background");
+ fgColor = UIManager.getColor("Slider.foreground");
+ focusColor = UIManager.getColor("Slider.focus");
+ highlight = UIManager.getColor("Slider.highlight");
+ shadow = UIManager.getColor("Slider.shadow");
+
+ System.out.println("bgColor: " + bgColor);
+ System.out.println("fgColor: " + fgColor);
+ System.out.println("focusColor: " + focusColor);
+ System.out.println("highlight: " + highlight);
+ System.out.println("shadow: " + shadow);
+ }
+
+ public static ComponentUI createUI(JComponent c)
+ {
+ return new GtkSliderUI();
+ }
+
+ // methods not overridden here, using Basic defaults
+ // installUI()
+ // uninstall()
+
+ public Dimension getPreferredHorizontalSize()
+ {
+ /*
+ Dimension thumbSize = getThumbSize();
+ Dimenstion labelSize = getLabelSize();
+ // getTickLength()
+ int width = thumbSize.width +
+ getWidthOfWidestLabel
+ */
+ return PREF_HORIZ;
+ }
+
+ public Dimension getPreferredVerticalSize()
+ {
+ return PREF_VERT;
+ }
+
+ public Dimension getMinimumHorizontalSize()
+ {
+ return MIN_HORIZ;
+ }
+
+ public Dimension getMinimumVerticalSize()
+ {
+ return MIN_VERT;
+ }
+
+ /**
+ * Returns thumb size based on slider orientation
+ */
+ protected Dimension getThumbSize()
+ {
+ Dimension size = new Dimension();
+
+ if (slider.getOrientation() == JSlider.VERTICAL) {
+ size.width = 15;
+ size.height = 33;
+ }
+ else {
+ size.width = 33;
+ size.height = 15;
+ }
+ return size;
+ }
+
+ /**
+ * Reserved width or height for ticks, as appropriate to the slider
+ * orientation.
+ */
+ protected int getTickLength()
+ {
+ return 10;
+ }
+
+ public void paintFocus(Graphics g)
+ {
+ super.paintFocus(g);
+ System.err.println("focus " + focusRect);
+ }
+
+ /**
+ * Must account for Unicode when drawing text.
+ */
+ public void paintLabels(Graphics g)
+ {
+ super.paintLabels(g);
+ System.err.println("label " + labelRect);
+ }
+
+ /**
+ * A drawRect() generated slider has ghosting when moving left on
+ * a horizontal slider and the bottom is not painted when moving
+ * right.
+ */
+ public void paintThumb(Graphics g)
+ {
+ int x = thumbRect.x;
+ int y = thumbRect.y;
+ int h = thumbRect.height;
+ int w = thumbRect.width;
+
+// "Slider.background", "#888888",
+// "Slider.focus", "#c3c3c3",
+// "Slider.foreground", "#d6d6d6",
+// "Slider.highlight", "#ffffff",
+// "Slider.shadow", "#000000"
+
+ g.setColor(fgColor);
+ g.fillRect(x,y,w,h);
+ g.setColor(bgColor);
+
+ if (slider.getOrientation() == JSlider.HORIZONTAL) {
+ g.drawRect(x, y, w, h);
+ g.setColor(highlight);
+ g.drawLine(x+1, y+h-1, x+w, y+h-1);
+ g.setColor(focusColor);
+ g.drawLine(x+2, y+h-2, x+w, y+h-2);
+ g.setColor(Color.black);
+ g.drawLine(x+1, y+h-2, x+1, y+h-2);
+ g.drawRect(x+1, y+1, w-1, 12);
+ }
+ else
+ g.drawRect(x, y, w, h);
+
+ System.err.println("thumb " + thumbRect);
+ }
+
+ // public void paintTicks(Graphics g)
+
+ public void paintTrack(Graphics g)
+ {
+// super.paintTrack(g);
+ int x = trackRect.x;
+ int y = trackRect.y;
+ int h = trackRect.height;
+ int w = trackRect.width;
+
+ System.err.println("track " + trackRect);
+
+ g.setColor(Color.black);
+ g.fillRect(x,y,w,h);
+
+// if (slider.getOrientation() == JSlider.HORIZONTAL)
+// g.drawLine(x, y+h-1, x+w-1, y+h-1);
+// else
+// g.drawLine(x+w-1, y, x+w-1, y+h-1);
+
+// System.err.println("track " + trackRect);
+// System.err.println("content " + contentRect);
+ }
+
+ // the four methods below allow you to control tick painting without
+ // worrying about what paintTicks does, look for in other UI delegates
+ // protected void paintMajorTickForHorizSlider(Graphics g, Rectangle tickBounds, int x)
+ // protected void paintMajorTickForVertSlider(Graphics g, Rectangle tickBounds, int y)
+ // protected void paintMinorTickForHorizSlider(Graphics g, Rectangle tickBounds, int x)
+ // protected void paintMinorTickForVertSlider(Graphics g, Rectangle tickBounds, int y)
+}
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/README b/libjava/classpath/gnu/javax/swing/plaf/gtk/README
new file mode 100644
index 0000000..2b3f001
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/README
@@ -0,0 +1,37 @@
+This is a start at a GTK look and feel for Java.
+It is usable already, but it mainly just defaults back to Basic Look and
+Feel for everything.
+
+Sliders are currently broken. I haven't figured out why yet.
+
+A bunch of system colors defined in GtkLookandFeel though I have a feeling
+I'll be defining more ColorUIResources shortly.
+
+Based on Gnome File Manager colors... or my Window Manager setup
+
+desktop #000000 (gtk)
+activeCaption #163555 (window manager)
+activeCaptionText #FFFFFF (window manager)
+activeCaptionBorder #000000 (unsure of this)
+inactiveCaption #375676 (window manager)
+inactiveCaptionText #999999 (window manager)
+inactiveCaptionBorder #000000 (unsure of this)
+window #FFFFFF (gtk)
+windowBorder #969696 (gtk)
+windowText #000000 (gtk)
+menu #d6d6d6 (gtk)
+menuText #000000 (gtk)
+text #FFFFFF (gtk)
+textText #000000 (gtk)
+textHighlight #00009c (gtk)
+textHighlightText #FFFFFF (gtk)
+textInactiveText #999999 (unsure of this)
+control #d6d6d6 (gtk)
+controlText #000000 (gtk)
+controlHighlight #eaeaea (gtk)
+controlLtHighlight #eaeaea (unsure of this)
+controlShadow #c3c3c3 (gtk)
+controlDkShadow #888888 (unsure of this)
+scrollbar #c3c3c3 (gtk)
+info #d6d6d6 (gtk)
+infoText #000000 (gtk)
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/SliderTest.java b/libjava/classpath/gnu/javax/swing/plaf/gtk/SliderTest.java
new file mode 100644
index 0000000..a838444
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/SliderTest.java
@@ -0,0 +1,82 @@
+import javax.swing.*;
+import javax.swing.event.*;
+import java.awt.*;
+import java.awt.event.*;
+import gnu.javax.swing.plaf.gtk.*;
+
+public class SliderTest extends JFrame
+{
+ public SliderTest()
+ {
+ super("JSlider Test");
+ Container c = getContentPane();
+ c.setLayout(new BorderLayout());
+ this.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) { System.exit(0); }
+ });
+
+ JSlider s = new JSlider();
+ s.createStandardLabels(10);
+ s.setMinorTickSpacing(10);
+ s.setMajorTickSpacing(20);
+ s.setPaintTicks(true);
+ s.setPaintTrack(true);
+ s.setPaintLabels(true);
+ s.setRequestFocusEnabled(true);
+
+ // turning off double buffering in repaint manager
+ // in order to use debug graphics
+ RepaintManager repaintManager = RepaintManager.currentManager(s);
+ repaintManager.setDoubleBufferingEnabled(false);
+
+ s.setDebugGraphicsOptions(DebugGraphics.BUFFERED_OPTION | DebugGraphics.FLASH_OPTION);
+ DebugGraphics.setFlashColor(Color.red); // color of flash
+ DebugGraphics.setFlashTime(4); // time delay of drawing operation flashing
+ DebugGraphics.setFlashCount(3); // number of time to draw
+
+ this.setSize(250, 100);
+ c.add(new JLabel("Default Slider"), "North");
+ c.add(s, "Center");
+
+ try {
+ UIManager.setLookAndFeel("gnu.javax.swing.plaf.gtk.GtkLookAndFeel");
+ SwingUtilities.updateComponentTreeUI(this);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(0);
+ }
+
+ center();
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ System.exit(0);
+ }
+
+ public void center()
+ {
+ // Centering the frame
+ Toolkit t = this.getToolkit();
+ Dimension framesize = this.getSize();
+ Dimension screensize = t.getScreenSize();
+
+ // Calculate point for frame (main)
+ Point pframe = new Point();
+ pframe.x = (screensize.width - framesize.width) / 2;
+ pframe.y = (screensize.height - framesize.height) / 2;
+
+ // Set the location of each to be centered
+ this.setLocation(pframe);
+ }
+
+ public static void main(String [] argv)
+ {
+ SliderTest t = new SliderTest();
+ t.show();
+ }
+
+}
+
+
+
+
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png
new file mode 100644
index 0000000..9d6f122
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png differ
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png
new file mode 100644
index 0000000..89931d5
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png differ
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png
new file mode 100644
index 0000000..d2cff62
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png differ
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png
new file mode 100644
index 0000000..6a4f792
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png differ
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png
new file mode 100644
index 0000000..89931d5
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png differ
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README
new file mode 100644
index 0000000..755f318
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README
@@ -0,0 +1,20 @@
+Images required by Basic Look and Feel
+
+Information based on images from Swing 1.1.1b2
+JavaCup.gif - a picture of the steaming cup of Java - 16x16 - 3 colors
+
+TreeOpen.gif - a picture of an open file folder - 16x13 - 8 colors
+TreeClosed.gif - a picture of a closed file folder - 16x13 - 7 colors
+TreeLeaf.gif - a picture of a small circle with points in four
+ directions - 16x13 - 2 colors
+
+Information on images used by Gtk Look and Feel, really need to work the
+number of colors down I think.
+
+JavaCup.gif - a picture of Classpath's mascot - 16x16 - 58 colors
+
+TreeOpen.gif - taken from Gnome File Manager - 16x12 - 34 colors
+TreeClosed.gif - taken from Gnome File Manager 14x12 - 28 colors
+TreeLeaf.gif - a blank gif - 16x12 - 1 color
+
+Error.gif - think this will be needed later (taken from gnome)
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png
new file mode 100644
index 0000000..e2edbf7
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png differ
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png
new file mode 100644
index 0000000..fb8dbc9
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png differ
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png
new file mode 100644
index 0000000..cdf058f
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png differ
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png
new file mode 100644
index 0000000..fba8258
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png differ
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png
new file mode 100644
index 0000000..9d6f122
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png differ
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png
new file mode 100644
index 0000000..e1a03d0
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png differ
diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png
new file mode 100644
index 0000000..ac429b1
Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png differ
diff --git a/libjava/classpath/gnu/javax/swing/text/html/package.html b/libjava/classpath/gnu/javax/swing/text/html/package.html
new file mode 100644
index 0000000..c7e7744
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/package.html
@@ -0,0 +1,50 @@
+
+
+
+
+Provides supporting classes for web browsers, + web robots, web page content analysers, web editors and + other applications applications working with Hypertext + Markup Language (HTML). +
+ + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java b/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java new file mode 100644 index 0000000..1ed42a2 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java @@ -0,0 +1,3729 @@ +/* HTML_401F.java -- HTML 4.01 FRAMESET DTD java conception. + Copyright (C) 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 gnu.javax.swing.text.html.parser; + +import gnu.javax.swing.text.html.parser.models.PCDATAonly_model; +import gnu.javax.swing.text.html.parser.models.TableRowContentModel; +import gnu.javax.swing.text.html.parser.models.noTagModel; + +import java.io.IOException; +import java.io.Serializable; + +import javax.swing.text.html.parser.*; +import javax.swing.text.html.parser.ContentModel; +import javax.swing.text.html.parser.DTDConstants; + +/** + * This class represents the java implementation of the HTML 4.01 + * ( -//W3C//DTD HTML 4.01 Frameset//EN ) Frameset version. The + * Frameset version includes as recommended, as obsoleted features and + * also the frameset support. This the default DTD to parse HTML + * documents in this implementation, containing 315 pre-defined general + * entities and 92 elements. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class HTML_401F + extends gnuDTD + implements DTDConstants, Serializable +{ + private static final long serialVersionUID = 1; + + /** + * The standard name of this DTD, + * '-//W3C//DTD HTML 4.01 Frameset//EN' + */ + public static final String DTD_NAME = "-//W3C//DTD HTML 4.01 Frameset//EN"; + + /** + * The integer representing length in pixels. + */ + static final int PIXELS = NUMBER; + + static final String[] NONE = new String[0]; + + /* Define the HTML tags. */ + static final String PCDATA = "#pcdata"; + static final String A = "a"; + static final String ABBR = "abbr"; + static final String ACRONYM = "acronym"; + static final String ADDRESS = "address"; + static final String APPLET = "applet"; + static final String AREA = "area"; + static final String B = "b"; + static final String BASE = "base"; + static final String BASEFONT = "basefont"; + static final String BDO = "bdo"; + static final String BIG = "big"; + static final String BLOCKQUOTE = "blockquote"; + static final String BODY = "body"; + static final String BR = "br"; + static final String BUTTON = "button"; + static final String CAPTION = "caption"; + static final String CENTER = "center"; + static final String CITE = "cite"; + static final String CODE = "code"; + static final String COL = "col"; + static final String COLGROUP = "colgroup"; + static final String DEFAULTS = "default"; + static final String DD = "dd"; + static final String DEL = "del"; + static final String DFN = "dfn"; + static final String DIR = "dir"; + static final String DIV = "div"; + static final String DL = "dl"; + static final String DT = "dt"; + static final String EM = "em"; + static final String FIELDSET = "fieldset"; + static final String FONT = "font"; + static final String FORM = "form"; + static final String FRAME = "frame"; + static final String FRAMESET = "frameset"; + static final String H1 = "h1"; + static final String H2 = "h2"; + static final String H3 = "h3"; + static final String H4 = "h4"; + static final String H5 = "h5"; + static final String H6 = "h6"; + static final String HEAD = "head"; + static final String HR = "hr"; + static final String HTML = "html"; + static final String I = "i"; + static final String IFRAME = "iframe"; + static final String IMG = "img"; + static final String INPUT = "input"; + static final String INS = "ins"; + static final String ISINDEX = "isindex"; + static final String KBD = "kbd"; + static final String LABEL = "label"; + static final String LEGEND = "legend"; + static final String LI = "li"; + static final String LINK = "link"; + static final String MAP = "map"; + static final String MENU = "menu"; + static final String META = "meta"; + static final String NOFRAMES = "noframes"; + static final String NOSCRIPT = "noscript"; + static final String NONES = "none"; + static final String sNAME = "name"; + static final String OBJECT = "object"; + static final String OL = "ol"; + static final String OPTGROUP = "optgroup"; + static final String OPTION = "option"; + static final String P = "p"; + static final String PARAM = "param"; + static final String PRE = "pre"; + static final String Q = "q"; + static final String S = "s"; + static final String SAMP = "samp"; + static final String SCRIPT = "script"; + static final String SELECT = "select"; + static final String SMALL = "small"; + static final String SPAN = "span"; + static final String STRIKE = "strike"; + static final String STRONG = "strong"; + static final String STYLE = "style"; + static final String SUB = "sub"; + static final String SUP = "sup"; + static final String TABLE = "table"; + static final String TBODY = "tbody"; + static final String TD = "td"; + static final String TEXTAREA = "textarea"; + static final String TFOOT = "tfoot"; + static final String TH = "th"; + static final String THEAD = "thead"; + static final String TITLE = "title"; + static final String TR = "tr"; + static final String TT = "tt"; + static final String U = "u"; + static final String UL = "ul"; + static final String VAR = "var"; + + /* Define the attribute constants. */ + static final String C_0 = "0"; + static final String C_1 = "1"; + static final String CHECKBOX = "checkbox"; + static final String DATA = "data"; + static final String FILE = "file"; + static final String GET = "get"; + static final String HIDDEN = "hidden"; + static final String IMAGE = "image"; + static final String PASSWORD = "password"; + static final String POST = "post"; + static final String RADIO = "radio"; + static final String REF = "ref"; + static final String RESET = "reset"; + static final String SUBMIT = "submit"; + static final String TEXT = "text"; + static final String ABOVE = "above"; + static final String ACCEPT = "accept"; + static final String ACCEPTCHARSET = "accept-charset"; + static final String ACCESSKEY = "accesskey"; + static final String ACTION = "action"; + static final String ALIGN = "align"; + static final String ALINK = "alink"; + static final String ALL = "all"; + static final String ALT = "alt"; + static final String APPLICATION_X_WWW_FORM_URLENCODED + = "application/x-www-form-urlencoded"; + static final String ARCHIVE = "archive"; + static final String AUTO = "auto"; + static final String AXIS = "axis"; + static final String BACKGROUND = "background"; + static final String BASELINE = "baseline"; + static final String BELOW = "below"; + static final String BGCOLOR = "bgcolor"; + static final String BORDER = "border"; + static final String BOTTOM = "bottom"; + static final String BOX = "box"; + static final String CELLPADDING = "cellpadding"; + static final String CELLSPACING = "cellspacing"; + static final String CHAR = "char"; + static final String CHAROFF = "charoff"; + static final String CHARSET = "charset"; + static final String CHECKED = "checked"; + static final String CIRCLE = "circle"; + static final String CLASS = "class"; + static final String CLASSID = "classid"; + static final String CLEAR = "clear"; + static final String CODEBASE = "codebase"; + static final String CODETYPE = "codetype"; + static final String COLOR = "color"; + static final String COLS = "cols"; + static final String COLSPAN = "colspan"; + static final String COMPACT = "compact"; + static final String CONTENT = "content"; + static final String COORDS = "coords"; + static final String DATAPAGESIZE = "datapagesize"; + static final String DATETIME = "datetime"; + static final String DECLARE = "declare"; + static final String DEFER = "defer"; + static final String DISABLED = "disabled"; + static final String DISC = "disc"; + static final String ENCTYPE = "enctype"; + static final String EVENT = "event"; + static final String FACE = "face"; + static final String FOR = "for"; + static final String FRAMEBORDER = "frameborder"; + static final String GROUPS = "groups"; + static final String HEADERS = "headers"; + static final String HEIGHT = "height"; + static final String HREF = "href"; + static final String HREFLANG = "hreflang"; + static final String HSIDES = "hsides"; + static final String HSPACE = "hspace"; + static final String HTTPEQUIV = "http-equiv"; + static final String sID = "id"; + static final String ISMAP = "ismap"; + static final String JUSTIFY = "justify"; + static final String LANG = "lang"; + static final String LANGUAGE = "language"; + static final String LEFT = "left"; + static final String LHS = "lhs"; + static final String LONGDESC = "longdesc"; + static final String LTR = "ltr"; + static final String MARGINHEIGHT = "marginheight"; + static final String MARGINWIDTH = "marginwidth"; + static final String MAXLENGTH = "maxlength"; + static final String MEDIA = "media"; + static final String METHOD = "method"; + static final String MIDDLE = "middle"; + static final String MULTIPLE = "multiple"; + static final String NO = "no"; + static final String NOHREF = "nohref"; + static final String NORESIZE = "noresize"; + static final String NOSHADE = "noshade"; + static final String NOWRAP = "nowrap"; + static final String ONBLUR = "onblur"; + static final String ONCHANGE = "onchange"; + static final String ONCLICK = "onclick"; + static final String ONDBLCLICK = "ondblclick"; + static final String ONFOCUS = "onfocus"; + static final String ONKEYDOWN = "onkeydown"; + static final String ONKEYPRESS = "onkeypress"; + static final String ONKEYUP = "onkeyup"; + static final String ONLOAD = "onload"; + static final String ONMOUSEDOWN = "onmousedown"; + static final String ONMOUSEMOVE = "onmousemove"; + static final String ONMOUSEOUT = "onmouseout"; + static final String ONMOUSEOVER = "onmouseover"; + static final String ONMOUSEUP = "onmouseup"; + static final String ONRESET = "onreset"; + static final String ONSELECT = "onselect"; + static final String ONSUBMIT = "onsubmit"; + static final String ONUNLOAD = "onunload"; + static final String POLY = "poly"; + static final String PROFILE = "profile"; + static final String PROMPT = "prompt"; + static final String READONLY = "readonly"; + static final String RECT = "rect"; + static final String REL = "rel"; + static final String REV = "rev"; + static final String RHS = "rhs"; + static final String RIGHT = "right"; + static final String ROW = "row"; + static final String ROWGROUP = "rowgroup"; + static final String ROWS = "rows"; + static final String ROWSPAN = "rowspan"; + static final String RTL = "rtl"; + static final String RULES = "rules"; + static final String SCHEME = "scheme"; + static final String SCOPE = "scope"; + static final String SCROLLING = "scrolling"; + static final String SELECTED = "selected"; + static final String SHAPE = "shape"; + static final String SIZE = "size"; + static final String SQUARE = "square"; + static final String SRC = "src"; + static final String STANDBY = "standby"; + static final String START = "start"; + static final String SUMMARY = "summary"; + static final String TABINDEX = "tabindex"; + static final String TARGET = "target"; + static final String TOP = "top"; + static final String TYPE = "type"; + static final String USEMAP = "usemap"; + static final String VALIGN = "valign"; + static final String VALUE = "value"; + static final String VALUETYPE = "valuetype"; + static final String VERSION = "version"; + static final String VLINK = "vlink"; + static final String VOID = "void"; + static final String VSIDES = "vsides"; + static final String VSPACE = "vspace"; + static final String WIDTH = "width"; + static final String YES = "yes"; + + static final String[] BLOCK = + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, + H1, H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL + }; + + /** + * Creates this DTD, filling in the entities and attributes data + * as defined in -//W3C//DTD HTML 4.01 Frameset//EN. + */ + protected HTML_401F() + { + super(DTD_NAME); + defineEntities(); + defineElements(); + } + + /** + * Either takes the document (by name) from DTD table, or + * creates a new instance and registers it in the tabe. + * The document is registerd under name "-//W3C//DTD HTML 4.01 Frameset//EN". + * @return The new or existing DTD for parsing HTML 4.01 Frameset. + */ + public static DTD getInstance() + { + try + { + DTD dtd = getDTD(DTD_NAME); + if (dtd == null || dtd.getClass().equals(DTD.class)) + { + dtd = new HTML_401F(); + putDTDHash(DTD_NAME, dtd); + } + return dtd; + } + catch (IOException ex) + { + throw new Error("This should never happen. Report the bug.", ex); + } + } + + /** + * Define all elements of this DTD. + */ + protected void defineElements() + { + /* Define the elements. */ + defElement(PCDATA, 0, false, false, null, NONE, NONE, + new AttributeList[ 0 ]); + + defElement(A, 0, false, false, null, + new String[] { + A + } + , + new String[] { + PCDATA, ABBR, ACRONYM, APPLET, + B, BASEFONT, BDO, BIG, BR, + BUTTON, CITE, CODE, DFN, EM, + FONT, I, IFRAME, IMG, INPUT, + KBD, LABEL, MAP, OBJECT, Q, + S, SAMP, SCRIPT, SELECT, SMALL, + SPAN, STRIKE, STRONG, SUB, SUP, + TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CHARSET, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(HREF, null, null, 0, IMPLIED), + attr(HREFLANG, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED), + attr(REL, null, null, 0, IMPLIED), + attr(REV, null, null, 0, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(SHAPE, RECT, new String[] { RECT, CIRCLE, POLY, DEFAULTS }, + 0, DEFAULT), + attr(COORDS, null, null, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(ABBR, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(ACRONYM, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(ADDRESS, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + P + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(APPLET, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL, PARAM + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(CODEBASE, null, null, 0, IMPLIED), + attr(ARCHIVE, null, null, 0, IMPLIED), + attr(CODE, null, null, 0, IMPLIED), + attr(OBJECT, null, null, 0, IMPLIED), + attr(ALT, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, REQUIRED), + attr(HEIGHT, null, null, 0, REQUIRED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(HSPACE, null, null, 0, IMPLIED), + attr(VSPACE, null, null, 0, IMPLIED) + } + ); + defElement(AREA, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SHAPE, RECT, new String[] { RECT, CIRCLE, POLY, DEFAULTS }, + 0, DEFAULT), + attr(COORDS, null, null, 0, IMPLIED), + attr(HREF, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED), + attr(NOHREF, null, new String[] { NOHREF }, 0, IMPLIED), + attr(ALT, null, null, 0, REQUIRED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(B, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(BASE, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(HREF, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED) + } + ); + defElement(BASEFONT, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(SIZE, null, null, 0, REQUIRED), + attr(COLOR, null, null, 0, IMPLIED), + attr(FACE, null, null, 0, IMPLIED) + } + ); + defElement(BDO, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, REQUIRED) + } + ); + defElement(BIG, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(BLOCKQUOTE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED) + } + ); + defElement(BODY, 0, true, true, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DEL, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, INS, ISINDEX, MENU, NOFRAMES, + NOSCRIPT, OL, P, PRE, TABLE, + UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ONLOAD, null, null, 0, IMPLIED), + attr(ONUNLOAD, null, null, 0, IMPLIED), + attr(BACKGROUND, null, null, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(TEXT, null, null, 0, IMPLIED), + attr(LINK, null, null, 0, IMPLIED), + attr(VLINK, null, null, 0, IMPLIED), + attr(ALINK, null, null, 0, IMPLIED) + } + ); + defElement(BR, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(CLEAR, "NONE", new String[] { LEFT, ALL, RIGHT, NONES }, + 0, DEFAULT) + } + ); + defElement(BUTTON, 0, false, false, null, + new String[] { + A, BUTTON, IFRAME, INPUT, + LABEL, SELECT, TEXTAREA, FIELDSET, FORM, + ISINDEX + } + , + new String[] { + PCDATA, ABBR, ACRONYM, APPLET, + B, BASEFONT, BDO, BIG, BR, + CITE, CODE, DFN, EM, FONT, + I, IMG, KBD, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SMALL, + SPAN, STRIKE, STRONG, SUB, SUP, + TT, U, VAR, ADDRESS, BLOCKQUOTE, + CENTER, DIR, DIV, DL, H1, + H2, H3, H4, H5, H6, + HR, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(VALUE, null, null, 0, IMPLIED), + attr(TYPE, SUBMIT, new String[] { BUTTON, SUBMIT, RESET }, 0, DEFAULT), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(CAPTION, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED) + } + ); + defElement(CENTER, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(CITE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(CODE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(COL, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SPAN, C_1, null, NUMBER, DEFAULT), + attr(WIDTH, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(COLGROUP, 0, false, true, null, + NONE + , + new String[] { + COL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SPAN, C_1, null, NUMBER, DEFAULT), + attr(WIDTH, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(DD, 0, false, true, new ContentModel(0, + new noTagModel( new String[] { DD, DT } ), null ), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(DEL, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED), + attr(DATETIME, null, null, 0, IMPLIED) + } + ); + defElement(DFN, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(DIR, 0, false, false, createListModel(), + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL + } + , + new String[] { + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(DIV, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(DL, 0, false, false, createDefListModel(), + NONE + , + new String[] { + DD, DT + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(DT, 0, false, true, + new ContentModel(0, + new noTagModel( new String[] { DT, DD } ), null), + BLOCK + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(EM, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(FIELDSET, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL, LEGEND + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(FONT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(SIZE, null, null, 0, IMPLIED), + attr(COLOR, null, null, 0, IMPLIED), + attr(FACE, null, null, 0, IMPLIED) + } + ); + defElement(FORM, 0, false, false, null, + new String[] { + FORM + } + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, H1, H2, H3, + H4, H5, H6, HR, ISINDEX, + MENU, NOFRAMES, NOSCRIPT, OL, P, + PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ACTION, null, null, 0, REQUIRED), + attr(METHOD, GET, new String[] { GET, POST }, 0, DEFAULT), + attr(ENCTYPE, APPLICATION_X_WWW_FORM_URLENCODED, null, 0, DEFAULT), + attr(ACCEPT, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(ONSUBMIT, null, null, 0, IMPLIED), + attr(ONRESET, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED), + attr(ACCEPTCHARSET, null, null, 0, IMPLIED) + } + ); + defElement(FRAME, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LONGDESC, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(FRAMEBORDER, C_1, new String[] { C_1, C_0 }, 0, DEFAULT), + attr(MARGINWIDTH, null, null, PIXELS, IMPLIED), + attr(MARGINHEIGHT, null, null, PIXELS, IMPLIED), + attr(NORESIZE, null, new String[] { NORESIZE }, 0, IMPLIED), + attr(SCROLLING, AUTO, new String[] { YES, NO, AUTO }, 0, DEFAULT) + } + ); + defElement(FRAMESET, 0, false, false, null, + NONE + , + new String[] { + NOFRAMES, FRAME, FRAMESET + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(ROWS, null, null, 0, IMPLIED), + attr(COLS, null, null, 0, IMPLIED), + attr(ONLOAD, null, null, 0, IMPLIED), + attr(ONUNLOAD, null, null, 0, IMPLIED) + } + ); + defElement(H1, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H2, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H3, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H4, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H5, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H6, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(HEAD, 0, true, true, null, + new String[] { + BODY + } + , + new String[] { + TITLE, ISINDEX, BASE, + SCRIPT, STYLE, META, LINK, OBJECT + } + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(PROFILE, null, null, 0, IMPLIED) + } + ); + + defElement(HR, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT }, 0, IMPLIED), + attr(NOSHADE, null, new String[] { NOSHADE }, 0, IMPLIED), + attr(SIZE, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED) + } + ); + defElement(HTML, 0, true, true, createHtmlContentModel(), + NONE + , + new String[] { + HEAD, BODY + } + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(VERSION, DTD_NAME, null, 0, FIXED) + } + ); + defElement(I, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(IFRAME, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LONGDESC, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(FRAMEBORDER, C_1, new String[] { C_1, C_0 }, 0, DEFAULT), + attr(MARGINWIDTH, null, null, PIXELS, IMPLIED), + attr(MARGINHEIGHT, null, null, PIXELS, IMPLIED), + attr(SCROLLING, AUTO, new String[] { YES, NO, AUTO }, 0, DEFAULT), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED) + } + ); + defElement(IMG, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, REQUIRED), + attr(ALT, null, null, 0, REQUIRED), + attr(LONGDESC, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(USEMAP, null, null, 0, IMPLIED), + attr(ISMAP, null, new String[] { ISMAP }, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(BORDER, null, null, PIXELS, IMPLIED), + attr(HSPACE, null, null, 0, IMPLIED), + attr(VSPACE, null, null, 0, IMPLIED) + } + ); + defElement(INPUT, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, TEXT, new String[] { TEXT, PASSWORD, CHECKBOX, RADIO, + SUBMIT, RESET, FILE, HIDDEN, IMAGE, BUTTON }, 0, DEFAULT), + attr(sNAME, null, null, 0, IMPLIED), + attr(VALUE, null, null, 0, IMPLIED), + attr(CHECKED, null, new String[] { CHECKED }, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(READONLY, null, new String[] { READONLY }, 0, IMPLIED), + attr(SIZE, null, null, 0, IMPLIED), + attr(MAXLENGTH, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(ALT, null, null, 0, IMPLIED), + attr(USEMAP, null, null, 0, IMPLIED), + attr(ISMAP, null, new String[] { ISMAP }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED), + attr(ONSELECT, null, null, 0, IMPLIED), + attr(ONCHANGE, null, null, 0, IMPLIED), + attr(ACCEPT, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED) + } + ); + defElement(INS, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED), + attr(DATETIME, null, null, 0, IMPLIED) + } + ); + defElement(ISINDEX, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(PROMPT, null, null, 0, IMPLIED) + } + ); + defElement(KBD, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(LABEL, 0, false, false, null, + new String[] { + LABEL + } + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, MAP, OBJECT, Q, + S, SAMP, SCRIPT, SELECT, SMALL, + SPAN, STRIKE, STRONG, SUB, SUP, + TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(FOR, null, null, 0, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(LEGEND, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED) + } + ); + // LI has a special content model that will be resolved into + // by transformer. + defElement(LI, 0, false, true, + new ContentModel(0, + new noTagModel(LI), null), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(VALUE, null, null, NUMBER, IMPLIED) + } + ); + defElement(LINK, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CHARSET, null, null, 0, IMPLIED), + attr(HREF, null, null, 0, IMPLIED), + attr(HREFLANG, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(REL, null, null, 0, IMPLIED), + attr(REV, null, null, 0, IMPLIED), + attr(MEDIA, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED) + } + ); + defElement(MAP, 0, false, false, null, + NONE + , + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL, + AREA + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, REQUIRED) + } + ); + defElement(MENU, 0, false, false, createListModel(), + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL + } + , + new String[] { + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(META, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(HTTPEQUIV, null, null, 0, IMPLIED), + attr(sNAME, null, null, NAME, IMPLIED), + attr(CONTENT, null, null, 0, REQUIRED), + attr(SCHEME, null, null, 0, IMPLIED) + } + ); + defElement(NOFRAMES, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(NOSCRIPT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(OBJECT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL, PARAM + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(DECLARE, null, new String[] { DECLARE }, 0, IMPLIED), + attr(CLASSID, null, null, 0, IMPLIED), + attr(CODEBASE, null, null, 0, IMPLIED), + attr(DATA, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(CODETYPE, null, null, 0, IMPLIED), + attr(ARCHIVE, null, null, 0, IMPLIED), + attr(STANDBY, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(USEMAP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(BORDER, null, null, PIXELS, IMPLIED), + attr(HSPACE, null, null, 0, IMPLIED), + attr(VSPACE, null, null, 0, IMPLIED) + } + ); + defElement(OL, 0, false, false, createListModel(), + NONE + , + new String[] { + // See note on the createListModel method + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED), + attr(START, null, null, 0, IMPLIED) + } + ); + defElement(OPTGROUP, 0, false, false, null, + NONE + , + new String[] { + OPTION + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(LABEL, null, null, 0, REQUIRED) + } + ); + defElement(OPTION, 0, false, true, new ContentModel(0, + new PCDATAonly_model(), null), + NONE, + new String[] { + PCDATA + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SELECTED, null, new String[] { SELECTED }, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(LABEL, null, null, 0, IMPLIED), + attr(VALUE, null, null, 0, IMPLIED) + } + ); + defElement(P, 0, false, true, new ContentModel( 0, + new noTagModel(P), null), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(PARAM, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(sNAME, null, null, 0, REQUIRED), + attr(VALUE, null, null, 0, IMPLIED), + attr(VALUETYPE, DATA, new String[] { DATA, REF, OBJECT }, 0, DEFAULT), + attr(TYPE, null, null, 0, IMPLIED) + } + ); + defElement(PRE, 0, false, false, null, + new String[] { + APPLET, BASEFONT, BIG, FONT, + IMG, OBJECT, SMALL, SUB, SUP + } + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + B, BDO, BR, BUTTON, CITE, + CODE, DFN, EM, I, IFRAME, + INPUT, KBD, LABEL, MAP, Q, + S, SAMP, SCRIPT, SELECT, SPAN, + STRIKE, STRONG, TEXTAREA, TT, U, + VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(WIDTH, null, null, NUMBER, IMPLIED) + } + ); + defElement(Q, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED) + } + ); + defElement(S, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(SAMP, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(SCRIPT, CDATA, false, false, null, + NONE + , + NONE + , + new AttributeList[] { + attr(CHARSET, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, REQUIRED), + attr(LANGUAGE, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(DEFER, null, new String[] { DEFER }, 0, IMPLIED), + attr(EVENT, null, null, 0, IMPLIED), + attr(FOR, null, null, 0, IMPLIED) + } + ); + defElement(SELECT, 0, false, false, null, + NONE + , + new String[] { + OPTGROUP, OPTION + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(SIZE, null, null, NUMBER, IMPLIED), + attr(MULTIPLE, null, new String[] { MULTIPLE }, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED), + attr(ONCHANGE, null, null, 0, IMPLIED) + } + ); + defElement(SMALL, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(SPAN, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(STRIKE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(STRONG, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(STYLE, CDATA, false, false, null, + NONE + , + NONE + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(TYPE, null, null, 0, REQUIRED), + attr(MEDIA, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED) + } + ); + defElement(SUB, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(SUP, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(TABLE, 0, false, false, createTableContentModel(), + NONE + , + new String[] { + CAPTION, COL, COLGROUP, TBODY, + TFOOT, THEAD + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SUMMARY, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(BORDER, null, null, PIXELS, IMPLIED), + attr(FRAME, null, new String[] { VOID, ABOVE, BELOW, HSIDES, LHS, RHS, + VSIDES, BOX, BORDER }, 0, IMPLIED), + attr(RULES, null, new String[] { NONES, GROUPS, ROWS, COLS, ALL }, + 0, IMPLIED), + attr(CELLSPACING, null, null, 0, IMPLIED), + attr(CELLPADDING, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT }, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(DATAPAGESIZE, null, null, 0, IMPLIED) + } + ); + defElement(TBODY, 0, true, true, model(TR,'+'), + NONE + , + new String[] { + TR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + + defElement(TD, 0, false, true, + new ContentModel(0, + new noTagModel(new String[] {"TD", "TH", "TR" } ), null), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ABBR, null, null, 0, IMPLIED), + attr(AXIS, null, null, 0, IMPLIED), + attr(HEADERS, null, null, 0, IMPLIED), + attr(SCOPE, null, new String[] { ROW, COL, ROWGROUP, COLGROUP }, + 0, IMPLIED), + attr(ROWSPAN, C_1, null, NUMBER, DEFAULT), + attr(COLSPAN, C_1, null, NUMBER, DEFAULT), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED), + attr(NOWRAP, null, new String[] { NOWRAP }, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED) + } + ); + defElement(TEXTAREA, 0, false, false, null, + NONE + , + new String[] { + PCDATA + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(ROWS, null, null, NUMBER, REQUIRED), + attr(COLS, null, null, NUMBER, REQUIRED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(READONLY, null, new String[] { READONLY }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED), + attr(ONSELECT, null, null, 0, IMPLIED), + attr(ONCHANGE, null, null, 0, IMPLIED) + } + ); + defElement(TFOOT, 0, false, true, model(TR,'+'), + NONE + , + new String[] { + TR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(TH, 0, false, true, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ABBR, null, null, 0, IMPLIED), + attr(AXIS, null, null, 0, IMPLIED), + attr(HEADERS, null, null, 0, IMPLIED), + attr(SCOPE, null, new String[] { ROW, COL, ROWGROUP, COLGROUP }, + 0, IMPLIED), + attr(ROWSPAN, C_1, null, NUMBER, DEFAULT), + attr(COLSPAN, C_1, null, NUMBER, DEFAULT), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED), + attr(NOWRAP, null, new String[] { NOWRAP }, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED) + } + ); + defElement(THEAD, 0, false, true, model(TR,'+'), + NONE + , + new String[] { + TR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(TITLE, 0, false, false, null, + new String[] { + OBJECT, SCRIPT, LINK, META, + STYLE + } + , + new String[] { + PCDATA + } + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED) + } + ); + defElement(TR, 0, false, true, + new ContentModel(0, new TableRowContentModel(this), null), + NONE + , + new String[] { + TD, TH + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED) + } + ); + defElement(TT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(U, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(UL, 0, false, false, createListModel(), + NONE + , + new String[] { + // See note on the createListModel method + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, null, new String[] { DISC, SQUARE, CIRCLE }, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(VAR, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + + } + + /** + * Define all entities in this DTD. + */ + protected void defineEntities() + { + /* Define general entities */ + defineEntity("AElig", 198); + defineEntity("Aacute", 193); + defineEntity("Acirc", 194); + defineEntity("Agrave", 192); + defineEntity("Alpha", 913); + defineEntity("Aring", 197); + defineEntity("Atilde", 195); + defineEntity("Auml", 196); + defineEntity("Beta", 914); + defineEntity("Ccedil", 199); + defineEntity("Chi", 935); + defineEntity("Dagger", 8225); + defineEntity("Delta", 916); + defineEntity("ETH", 208); + defineEntity("Eacute", 201); + defineEntity("Ecirc", 202); + defineEntity("Egrave", 200); + defineEntity("Epsilon", 917); + defineEntity("Eta", 919); + defineEntity("Euml", 203); + defineEntity("Gamma", 915); + defineEntity("Iacute", 205); + defineEntity("Icirc", 206); + defineEntity("Igrave", 204); + defineEntity("Iota", 921); + defineEntity("Iuml", 207); + defineEntity("Kappa", 922); + defineEntity("Lambda", 923); + defineEntity("Mu", 924); + defineEntity("Ntilde", 209); + defineEntity("Nu", 925); + defineEntity("OElig", 338); + defineEntity("Oacute", 211); + defineEntity("Ocirc", 212); + defineEntity("Ograve", 210); + defineEntity("Omega", 937); + defineEntity("Omicron", 927); + defineEntity("Oslash", 216); + defineEntity("Otilde", 213); + defineEntity("Ouml", 214); + defineEntity("Phi", 934); + defineEntity("Pi", 928); + defineEntity("Prime", 8243); + defineEntity("Psi", 936); + defineEntity("Rho", 929); + defineEntity("Scaron", 352); + defineEntity("Sigma", 931); + defineEntity("THORN", 222); + defineEntity("Tau", 932); + defineEntity("Theta", 920); + defineEntity("Uacute", 218); + defineEntity("Ucirc", 219); + defineEntity("Ugrave", 217); + defineEntity("Upsilon", 933); + defineEntity("Uuml", 220); + defineEntity("Xi", 926); + defineEntity("Yacute", 221); + defineEntity("Yuml", 376); + defineEntity("Zeta", 918); + defineEntity("aacute", 225); + defineEntity("acirc", 226); + defineEntity("acute", 180); + defineEntity("aelig", 230); + defineEntity("agrave", 224); + defineEntity("alefsym", 8501); + defineEntity("alpha", 945); + defineEntity("amp", 38); + defineEntity("and", 8743); + defineEntity("ang", 8736); + defineEntity("aring", 229); + defineEntity("asymp", 8776); + defineEntity("atilde", 227); + defineEntity("auml", 228); + defineEntity("bdquo", 8222); + defineEntity("beta", 946); + defineEntity("brvbar", 166); + defineEntity("bull", 8226); + defineEntity("cap", 8745); + defineEntity("ccedil", 231); + defineEntity("cedil", 184); + defineEntity("cent", 162); + defineEntity("chi", 967); + defineEntity("circ", 710); + defineEntity("clubs", 9827); + defineEntity("cong", 8773); + defineEntity("copy", 169); + defineEntity("crarr", 8629); + defineEntity("cup", 8746); + defineEntity("curren", 164); + defineEntity("dArr", 8659); + defineEntity("dagger", 8224); + defineEntity("darr", 8595); + defineEntity("deg", 176); + defineEntity("delta", 948); + defineEntity("diams", 9830); + defineEntity("divide", 247); + defineEntity("eacute", 233); + defineEntity("ecirc", 234); + defineEntity("egrave", 232); + defineEntity("empty", 8709); + defineEntity("emsp", 8195); + defineEntity("ensp", 8194); + defineEntity("epsilon", 949); + defineEntity("equiv", 8801); + defineEntity("eta", 951); + defineEntity("eth", 240); + defineEntity("euml", 235); + defineEntity("euro", 8364); + defineEntity("exist", 8707); + defineEntity("fnof", 402); + defineEntity("forall", 8704); + defineEntity("frac12", 189); + defineEntity("frac14", 188); + defineEntity("frac34", 190); + defineEntity("frasl", 8260); + defineEntity("gamma", 947); + defineEntity("ge", 8805); + defineEntity("gt", 62); + defineEntity("hArr", 8660); + defineEntity("harr", 8596); + defineEntity("hearts", 9829); + defineEntity("hellip", 8230); + defineEntity("iacute", 237); + defineEntity("icirc", 238); + defineEntity("iexcl", 161); + defineEntity("igrave", 236); + defineEntity("image", 8465); + defineEntity("infin", 8734); + defineEntity("int", 8747); + defineEntity("iota", 953); + defineEntity("iquest", 191); + defineEntity("isin", 8712); + defineEntity("iuml", 239); + defineEntity("kappa", 954); + defineEntity("lArr", 8656); + defineEntity("lambda", 955); + defineEntity("lang", 9001); + defineEntity("laquo", 171); + defineEntity("larr", 8592); + defineEntity("lceil", 8968); + defineEntity("ldquo", 8220); + defineEntity("le", 8804); + defineEntity("lfloor", 8970); + defineEntity("lowast", 8727); + defineEntity("loz", 9674); + defineEntity("lrm", 8206); + defineEntity("lsaquo", 8249); + defineEntity("lsquo", 8216); + defineEntity("lt", 60); + defineEntity("macr", 175); + defineEntity("mdash", 8212); + defineEntity("micro", 181); + defineEntity("middot", 183); + defineEntity("minus", 8722); + defineEntity("mu", 956); + defineEntity("nabla", 8711); + defineEntity("nbsp", 160); + defineEntity("ndash", 8211); + defineEntity("ne", 8800); + defineEntity("ni", 8715); + defineEntity("not", 172); + defineEntity("notin", 8713); + defineEntity("nsub", 8836); + defineEntity("ntilde", 241); + defineEntity("nu", 957); + defineEntity("oacute", 243); + defineEntity("ocirc", 244); + defineEntity("oelig", 339); + defineEntity("ograve", 242); + defineEntity("oline", 8254); + defineEntity("omega", 969); + defineEntity("omicron", 959); + defineEntity("oplus", 8853); + defineEntity("or", 8744); + defineEntity("ordf", 170); + defineEntity("ordm", 186); + defineEntity("oslash", 248); + defineEntity("otilde", 245); + defineEntity("otimes", 8855); + defineEntity("ouml", 246); + defineEntity("para", 182); + defineEntity("part", 8706); + defineEntity("permil", 8240); + defineEntity("perp", 8869); + defineEntity("phi", 966); + defineEntity("pi", 960); + defineEntity("piv", 982); + defineEntity("plusmn", 177); + defineEntity("pound", 163); + defineEntity("prime", 8242); + defineEntity("prod", 8719); + defineEntity("prop", 8733); + defineEntity("psi", 968); + defineEntity("quot", 34); + defineEntity("rArr", 8658); + defineEntity("radic", 8730); + defineEntity("rang", 9002); + defineEntity("raquo", 187); + defineEntity("rarr", 8594); + defineEntity("rceil", 8969); + defineEntity("rdquo", 8221); + defineEntity("real", 8476); + defineEntity("reg", 174); + defineEntity("rfloor", 8971); + defineEntity("rho", 961); + defineEntity("rlm", 8207); + defineEntity("rsaquo", 8250); + defineEntity("rsquo", 8217); + defineEntity("sbquo", 8218); + defineEntity("scaron", 353); + defineEntity("sdot", 8901); + defineEntity("sect", 167); + defineEntity("shy", 173); + defineEntity("sigma", 963); + defineEntity("sigmaf", 962); + defineEntity("sim", 8764); + defineEntity("spades", 9824); + defineEntity("sub", 8834); + defineEntity("sube", 8838); + defineEntity("sum", 8721); + defineEntity("sup", 8835); + defineEntity("sup1", 185); + defineEntity("sup2", 178); + defineEntity("sup3", 179); + defineEntity("supe", 8839); + defineEntity("szlig", 223); + defineEntity("tau", 964); + defineEntity("there4", 8756); + defineEntity("theta", 952); + defineEntity("thetasym", 977); + defineEntity("thinsp", 8201); + defineEntity("thorn", 254); + defineEntity("tilde", 732); + defineEntity("times", 215); + defineEntity("trade", 8482); + defineEntity("uArr", 8657); + defineEntity("uacute", 250); + defineEntity("uarr", 8593); + defineEntity("ucirc", 251); + defineEntity("ugrave", 249); + defineEntity("uml", 168); + defineEntity("upsih", 978); + defineEntity("upsilon", 965); + defineEntity("uuml", 252); + defineEntity("weierp", 8472); + defineEntity("xi", 958); + defineEntity("yacute", 253); + defineEntity("yen", 165); + defineEntity("yuml", 255); + defineEntity("zeta", 950); + defineEntity("zwj", 8205); + defineEntity("zwnj", 8204); + } + + /** + * Crate a content model, consisting of the single + * element, specified by name. + */ + private ContentModel model(String element) + { + return new ContentModel(getElement(element)); + } + + /** + * Crate a chain from the two content models, + * the last containing the given element and + * the specified unary operation. + */ + private ContentModel model(String element, int unary) + { + ContentModel ct = model(element); + ct.type = unary; + return new ContentModel(0, ct); + } + + /** + * Create the model HEAD, BODY + * @return + */ + protected ContentModel createHtmlContentModel() + { + ContentModel head = model(HEAD); + ContentModel body = model(BODY); + head.next = body; + head.type = ','; + return head; + } + + /** + * Create the model + * ( CAPTION ? , ( COL * | COLGROUP * ) , THEAD ? , TFOOT ? , TBODY + ) + */ + protected ContentModel createTableContentModel() + { + ContentModel col_colgroup = new ContentModel + ('|', model(COL,'*'), model(COLGROUP,'*') ); + + col_colgroup = new ContentModel('*', col_colgroup); + col_colgroup = new ContentModel(',', col_colgroup); + + ContentModel caption = model(CAPTION,'?'); + ContentModel thead = model(THEAD, '?'); + ContentModel tfoot = model(TFOOT, '?'); + ContentModel tbody = model(TBODY, '+'); + + caption.next = col_colgroup; + col_colgroup.next = thead; + thead.next = tfoot; + tfoot.next = tbody; + + caption.type = col_colgroup.type = thead.type = tfoot.type = + tbody.type = ','; + + return caption; + } + + /** + * Creates a model for <DL> tag: + * DT+ | DL+
.
+ * @return
+ */
+ protected ContentModel createDefListModel()
+ {
+ ContentModel dt = model(DT, '+');
+ ContentModel dd = model(DD, '+');
+
+ dt.next = dd;
+ dt.type = dd.type = '|';
+ return dt;
+ }
+
+ /**
+ * This model is used for UL, OL, MENU and DIR.
+ * HTML 4.01 specifies LI only, but the nested
+ * list seems rendered correctly only if
+ * it is not enclosed into + * The class is derived from {@link gnu.javax.swing.text.html.parser.DTD } + * making structure creation methods public. This is required when + * creating the DTD by SGML parser that must have access to the structure. + * + * SGML DTD representation. Provides basis for describing a syntax of the + * HTML documents. The fields of this class are NOT initialized in + * constructor. You need to do this separately before passing this data + * structure to the parser constructor.
+ * + *This implementation also provides you the derived class
+ * gnu.javax.swing.text.html.parser.DTD.HTML_4_0_1
, where
+ * all fields are initialized to the values, representing HTML 4.01
+ * ("-//W3C//DTD HTML 4.01 Frameset//EN") DTD. You can use it if you do not care
+ * about the portability between different implementations of the core
+ * class libraries.
Use {@link javax.swing.HTML.HTMLEditorKit.Parser#parse } + * for parsing in accordance with "-//W3C//DTD HTML 4.01 Frameset//EN" + * without specifying DTD separately.
+ * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDTD + extends javax.swing.text.html.parser.DTD + implements javax.swing.text.html.parser.DTDConstants, Serializable +{ + /* The undocumented element types, used to specify types, not defined + in DTDConstants. */ + + /** + * The URI element type (not defined in DTDConstants). + */ + public static final int URI = 512; + + /** + * The Length element type + */ + public static final int Length = 513; + + /** + * The Char element type + */ + public static final int Char = 514; + + /** + * The Color element type + */ + public static final int Color = 515; + + /** + * Creates a new instance of gnuDTD. + * @param name the name of the DTD. + */ + public gnuDTD(String name) + { + super(name); + } + + /** + * Creates and returns new attribute (not an attribute list). + * @param name the name of this attribute + * @param type the type of this attribute (FIXED, IMPLIED or + * REQUIRED fromDTDConstants
).
+ * @param modifier the modifier of this attribute
+ * @param default_value the default value of this attribute or null if
+ * it is not specified.
+ * @param allowed_values the allowed values of this attribute. The multiple
+ * possible values in this parameter are supposed to be separated by
+ * '|', same as in SGML DTD <!ATTLIST
tag. This parameter
+ * can be null if no list of allowed values is specified.
+ * @param atts the previous attribute of this element. This is
+ * placed to the field
+ * {@link javax.swing.text.html.parser.AttributeList#next },
+ * creating a linked list.
+ * @return
+ */
+ public AttributeList defAttributeList(String name, int type, int modifier,
+ String default_value,
+ String allowed_values,
+ AttributeList atts
+ )
+ {
+ return super.defAttributeList(name, type, modifier, default_value,
+ allowed_values, atts
+ );
+ }
+
+ /**
+ * Define the attributes for the element with the given name.
+ * If the element is not exist, it is created. This method is
+ * needed if the element attributes are defined befor the
+ * element itself.
+ * @param forElement
+ * @param attributes
+ */
+ public void defAttrsFor(String forElement, AttributeList attributes)
+ {
+ super.defineAttributes(forElement, attributes);
+ }
+
+ /**
+ * Creates a new content model.
+ * @param type specifies the BNF operation for this content model.
+ * The valid operations are documented in the
+ * {@link javax.swing.text.html.parser.ContentModel#type }.
+ * @param content the content of this content model
+ * @param next if the content model is specified by BNF-like
+ * expression, contains the rest of this expression.
+ * @return The newly created content model.
+ */
+ public ContentModel defContentModel(int type, Object content,
+ ContentModel next
+ )
+ {
+ return super.defContentModel(type, content, next);
+ }
+
+ /**
+ * Defines a new element and adds it to the element table.
+ * If the element alredy exists,
+ * overrides it settings with the specified values.
+ * @param name the name of the new element
+ * @param type the type of the element
+ * @param headless true if the element needs no starting tag
+ * @param tailless true if the element needs no closing tag
+ * @param content the element content.
+ * @param exclusions the elements that must be excluded from the
+ * content of this element, in all levels of the hierarchy.
+ * @param inclusions the elements that can be included as the
+ * content of this element.
+ * @param attributes the element attributes.
+ * @return the created or updated element.
+ */
+ public Element defElement(String name, int type, boolean headless,
+ boolean tailless, ContentModel content,
+ String[] exclusions, String[] inclusions,
+ AttributeList attributes
+ )
+ {
+ return super.defElement(name, type, headless, tailless, content,
+ exclusions, inclusions, attributes
+ );
+ }
+
+ /**
+ * Defines a new element and adds it to the element table.
+ * If the element alredy exists,
+ * overrides it settings with the specified values.
+ * @param name the name of the new element
+ * @param type the type of the element
+ * @param headless true if the element needs no starting tag
+ * @param tailless true if the element needs no closing tag
+ * @param content the element content.
+ * @param exclusions the elements that must be excluded from the
+ * content of this element, in all levels of the hierarchy.
+ * @param inclusions the elements that can be included as the
+ * content of this element.
+ * @param attributes the element attributes.
+ * @return the created or updated element.
+ */
+ public Element defElement(String name, int type, boolean headless,
+ boolean tailless, ContentModel content,
+ Collection exclusions, Collection inclusions,
+ AttributeList attributes
+ )
+ {
+ return super.defElement(name, type, headless, tailless, content,
+ toStringArray(exclusions),
+ toStringArray(inclusions), attributes
+ );
+ }
+
+ /**
+ * Defines a new element and adds it to the element table.
+ * If the element alredy exists,
+ * overrides it settings with the specified values.
+ * @param name the name of the new element
+ * @param type the type of the element
+ * @param headless true if the element needs no starting tag
+ * @param tailless true if the element needs no closing tag
+ * @param content the element content.
+ * @param exclusions the elements that must be excluded from the
+ * content of this element, in all levels of the hierarchy.
+ * @param inclusions the elements that can be included as the
+ * content of this element.
+ * @param attributes the element attributes (an array and not a
+ * linked list). The attributes are chained into the linked list
+ * inside this method.
+ * @return the created or updated element.
+ */
+ public Element defElement(String name, int type, boolean headless,
+ boolean tailless, ContentModel content,
+ String[] exclusions, String[] inclusions,
+ AttributeList[] attributes
+ )
+ {
+ AttributeList list;
+
+ if (attributes == null || attributes.length == 0)
+ list = null;
+ else
+ {
+ if (attributes.length > 1)
+ for (int i = 1; i < attributes.length; i++)
+ {
+ attributes [ i - 1 ].next = attributes [ i ];
+ }
+ list = attributes [ 0 ];
+ }
+
+ Element e =
+ super.defElement(name, type, headless, tailless, content, exclusions,
+ inclusions, list
+ );
+ return e;
+ }
+
+ /**
+ * Creates, adds into the internal table and returns the
+ * character entity like <
+ * (means '<
' );
+ * This method inactivates the recursive refenrences to the same
+ * entity.
+ * @param name The entity name (without heading & and closing ;)
+ * @param type The entity type
+ * @param character The entity value (single character)
+ * @return The created entity
+ */
+ public Entity defEntity(String name, int type, String data)
+ {
+ int r;
+ String eref = "%" + name + ";";
+ do
+ {
+ r = data.indexOf(eref);
+ if (r > 0)
+ {
+ data = data.substring(0, r) + data.substring(r + 1);
+ }
+ }
+ while (r > 0);
+
+ return super.defEntity(name, type, data);
+ }
+
+ /**
+ * Summarises the document content into the given PrintStream.
+ */
+ public void dump(PrintStream p)
+ {
+ Iterator iter = entityHash.entrySet().iterator();
+ while (iter.hasNext())
+ {
+ Map.Entry item = (Map.Entry) iter.next();
+ Entity e = (Entity) item.getValue();
+ if (e.isGeneral())
+ p.println("Entity " + e.getName() + ": " + e.getString());
+ }
+
+ iter = elementHash.entrySet().iterator();
+ while (iter.hasNext())
+ {
+ Map.Entry item = (Map.Entry) iter.next();
+ Element e = (Element) item.getValue();
+ p.println("Element " + e.getName());
+
+ System.out.println(" includes:");
+ dump(e.inclusions);
+ System.out.println(" excludes:");
+ dump(e.exclusions);
+ System.out.println(" attributes:");
+
+ AttributeList atts = e.atts;
+ while (atts != null)
+ {
+ p.print(" " + atts.name + " = " + atts.value);
+ if (atts.values == null || atts.values.size() == 0)
+ p.println();
+ else
+ {
+ Iterator viter = atts.values.iterator();
+ System.out.print(" ( ");
+ while (viter.hasNext())
+ {
+ System.out.print(viter.next());
+ if (viter.hasNext())
+ System.out.print(" | ");
+ }
+ System.out.println(" ) ");
+ }
+ atts = atts.next;
+ }
+ }
+ }
+
+ /**
+ * Prints the content of the given attribute set to the System.out.
+ * @param b
+ */
+ public void dump(BitSet b)
+ {
+ if (b != null)
+ {
+ for (int i = 0; i < b.size(); i++)
+ {
+ if (b.get(i))
+ System.out.println(" " + elements.get(i));
+ }
+ }
+ else
+ System.out.println(" NULL set");
+ }
+
+ /**
+ * Creates the attribute.
+ * @param name The attribute name.
+ * @param type The attribute type.
+ * @param modifier The attribute modifier.
+ * @param defaultValue Default value (or null)
+ * @param allowed_values Allowed values (or null)
+ * @return The newly created AttributeList. The next
+ * field is initialized to null.
+ */
+ protected AttributeList attr(String name, String default_value,
+ String[] allowed_values, int type, int modifier
+ )
+ {
+ Vector allowed = null;
+
+ if (allowed_values != null)
+ {
+ allowed = new Vector(allowed_values.length);
+ for (int i = 0; i < allowed_values.length; i++)
+ {
+ allowed.add(allowed_values [ i ]);
+ }
+ }
+ ;
+
+ AttributeList attr =
+ new AttributeList(name, type, modifier, default_value, allowed, null);
+
+ return attr;
+ }
+
+ /**
+ * Define the general entity, holding a single character.
+ * @param name The entity name (for example, 'amp').
+ * The defined entity is stored into the entity table.
+ * @param character The entity character (for example, '&').
+ */
+ protected void defineEntity(String name, int character)
+ {
+ super.defEntity(name, GENERAL, character);
+ }
+
+ private String[] toStringArray(Collection c)
+ {
+ String[] s = new String[ c.size() ];
+ Iterator iter = c.iterator();
+ for (int i = 0; i < s.length; i++)
+ {
+ s [ i ] = iter.next().toString();
+ }
+ return s;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java
new file mode 100644
index 0000000..a4e6f73
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java
@@ -0,0 +1,133 @@
+/* htmlAttributeSet.java -- A set to store HTML attributes
+ Copyright (C) 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 gnu.javax.swing.text.html.parser;
+
+import java.util.Enumeration;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.html.HTML;
+
+/**
+ * A set, adapted to store HTML attributes.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class htmlAttributeSet
+ extends SimpleAttributeSet
+{
+ public static final htmlAttributeSet EMPTY_HTML_ATTRIBUTE_SET =
+ new htmlAttributeSet();
+ AttributeSet parent;
+
+ /**
+ * Looks in this set and, if not found, later looks in the parent set.
+ * Calls toString(), allowing to pass as HTML.Attribute, as String
+ * to this method.
+ * @param key A key to search for a value.
+ * @return The value, if one is defined.
+ */
+ public Object getAttribute(Object _key)
+ {
+ Object key = _key.toString().toLowerCase();
+
+ Object v = super.getAttribute(key);
+ if (v != null)
+ return v;
+ else if (parent != null)
+ return parent.getAttribute(key);
+ else
+ return null;
+ }
+
+ /**
+ * The name set must return HTML.Attribute and not a string,
+ * where applicable.
+ */
+ public Enumeration getAttributeNames()
+ {
+ // Replace the string keys by HTML.attribute, where applicable
+ final Enumeration enumeration = super.getAttributeNames();
+
+ return new Enumeration()
+ {
+ public boolean hasMoreElements()
+ {
+ return enumeration.hasMoreElements();
+ }
+
+ public Object nextElement()
+ {
+ Object key = enumeration.nextElement();
+ HTML.Attribute hKey = HTML.getAttributeKey((String) key);
+ if (hKey != null)
+ return hKey;
+ else
+ return key;
+ }
+ };
+ }
+
+ /**
+ * Set the parent set, containing the default values.
+ * @param a_parent
+ */
+ public void setResolveParent(AttributeSet a_parent)
+ {
+ parent = a_parent;
+ }
+
+ /**
+ * Get the parent set, containing the default values.
+ * @return
+ */
+ public AttributeSet getResolveParent()
+ {
+ return parent;
+ }
+
+ /**
+ * Add the attribute to this attribute set.
+ * @param key Attribute key (will be case insensitive)
+ * @param value Attribute value
+ */
+ public void addAttribute(Object key, Object value)
+ {
+ super.addAttribute(key.toString().toLowerCase(), value);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java
new file mode 100644
index 0000000..1f9eee0
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java
@@ -0,0 +1,610 @@
+/* tagStack.java -- The HTML tag stack.
+ Copyright (C) 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 gnu.javax.swing.text.html.parser;
+
+import gnu.javax.swing.text.html.parser.models.node;
+import gnu.javax.swing.text.html.parser.models.transformer;
+
+import java.util.BitSet;
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.parser.*;
+
+/**
+ * The HTML content validator, is responsible for opening and + * closing elements with optional start/end tags, detecting + * the wrongly placed html tags and reporting errors. The working instance + * is the inner class inside the {@link javax.swing.text.html.parser.Parser } + *
+ *This class could potentially
+ * provide basis for automated closing and insertion of the html tags,
+ * correcting the found html errors.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public abstract class htmlValidator
+{
+ /**
+ * The tag reference, holding additional information that the tag
+ * has been forcibly closed.
+ */
+ protected class hTag
+ {
+ protected final Element element;
+ protected final HTML.Tag tag;
+ protected final TagElement tgElement;
+ protected boolean forcibly_closed;
+ protected node validationTrace;
+
+ protected hTag(TagElement an_element)
+ {
+ element = an_element.getElement();
+ tag = an_element.getHTMLTag();
+ tgElement = an_element;
+
+ if (element.content != null)
+ validationTrace = transformer.transform(element.content, dtd);
+ }
+
+ /**
+ * This is called when the tag must be forcibly closed because
+ * it would make the newly appearing tag invalid.
+ * The parser is not notified about such event (just the error
+ * is reported). For such tags, the closing message does not
+ * appear when later reaching the end of stream. The exception is
+ * the <head> tag: the parser is notified about its silent closing
+ * when <body> or other html content appears.
+ */
+ protected void forciblyCloseDueContext()
+ {
+ forcibly_closed = true;
+ }
+
+ /**
+ * This is called when the tag must be forcibly closed after
+ * reaching the end of stream. The parser is notified as if
+ * closing the tag explicitly.
+ */
+ protected void forciblyCloseDueEndOfStream()
+ {
+ forcibly_closed = true;
+ handleSupposedEndTag(element);
+ }
+ }
+
+ /**
+ * The DTD, providing information about the valid document structure.
+ */
+ protected final DTD dtd;
+
+ /**
+ * The stack, holding the current tag context.
+ */
+ protected final LinkedList stack = new LinkedList();
+
+ /**
+ * Creates a new tag stack, using the given DTD.
+ * @param a_dtd A DTD, providing the information about the valid
+ * tag content.
+ */
+ public htmlValidator(DTD a_dtd)
+ {
+ dtd = a_dtd;
+ }
+
+ /**
+ * Close all opened tags (called at the end of parsing).
+ */
+ public void closeAll()
+ {
+ hTag h;
+ while (!stack.isEmpty())
+ {
+ h = (hTag) stack.getLast();
+ if (!h.forcibly_closed && !h.element.omitEnd())
+ s_error("Unclosed <" + h.tag + ">, closing at the end of stream");
+
+ handleSupposedEndTag(h.element);
+
+ closeTag(h.tgElement);
+ }
+ }
+
+ /**
+ * Remove the given tag from the stack or (if found) from the list
+ * of the forcibly closed tags.
+ */
+ public void closeTag(TagElement tElement)
+ {
+ HTML.Tag tag = tElement.getHTMLTag();
+ hTag x;
+ hTag close;
+
+ if (!stack.isEmpty())
+ {
+ ListIterator iter = stack.listIterator(stack.size());
+
+ while (iter.hasPrevious())
+ {
+ x = (hTag) iter.previous();
+ if (tag.equals(x.tag))
+ {
+ if (x.forcibly_closed && !x.element.omitEnd())
+ s_error("The tag <" + x.tag +
+ "> has already been forcibly closed"
+ );
+
+
+ // If the tag has a content model defined, forcibly close all
+ // tags that were opened after the tag being currently closed.
+ closing:
+ if (x.element.content != null)
+ {
+ iter = stack.listIterator(stack.size());
+ while (iter.hasPrevious())
+ {
+ close = (hTag) iter.previous();
+ if (close == x)
+ break closing;
+ handleSupposedEndTag(close.element);
+ iter.remove();
+ }
+ }
+
+ stack.remove(x);
+ return;
+ }
+ }
+ }
+ s_error("Closing unopened <" + tag + ">");
+ }
+
+ /**
+ * Add the given HTML tag to the stack of the opened tags. Forcibly closes
+ * all tags in the stack that does not allow this tag in they content (error
+ * is reported).
+ * @param element
+ */
+ public void openTag(TagElement tElement, htmlAttributeSet parameters)
+ {
+ // If this is a fictional call, the message from the parser
+ // has recursively returned - ignore.
+ if (tElement.fictional())
+ return;
+
+ validateParameters(tElement, parameters);
+
+ // If the stack is empty, start from HTML
+ if (stack.isEmpty() && tElement.getHTMLTag() != HTML.Tag.HTML)
+ {
+ Element html = dtd.getElement(HTML.Tag.HTML.toString());
+ openFictionalTag(html);
+ }
+
+ Object v = tagIsValidForContext(tElement);
+ if (v != Boolean.TRUE)
+ {
+ // The tag is not valid for context, the content
+ // model suggest to open another tag.
+ if (v instanceof Element)
+ {
+ int n = 0;
+ while (v instanceof Element && (n++ < 100))
+ {
+ Element fe = (Element) v;
+
+ // notify the content model that we add the proposed tag
+ getCurrentContentModel().show(fe);
+ openFictionalTag(fe);
+
+ Object vv = tagIsValidForContext(tElement);
+ if (vv instanceof Element) // One level of nesting is supported.
+ {
+ openFictionalTag((Element) vv);
+
+ Object vx = tagIsValidForContext(tElement);
+ if (vx instanceof Element)
+ openFictionalTag((Element) vx);
+ }
+ else if (vv == Boolean.FALSE)
+ {
+ // The tag is still not valid for the current
+ // content after opening a fictional element.
+ if (fe.omitEnd())
+ {
+ // close the previously opened fictional tag.
+ closeLast();
+ vv = tagIsValidForContext(tElement);
+ if (vv instanceof Element)
+
+ // another tag was suggested by the content model
+ openFictionalTag((Element) vv);
+ }
+ }
+ v = tagIsValidForContext(tElement);
+ }
+ }
+ else // If the current element has the optional end tag, close it.
+ {
+ if (!stack.isEmpty())
+ {
+ closing:
+ do
+ {
+ hTag last = (hTag) stack.getLast();
+ if (last.element.omitEnd())
+ {
+ closeLast();
+ v = tagIsValidForContext(tElement);
+ if (v instanceof Element) // another tag was suggested by the content model
+ {
+ openFictionalTag((Element) v);
+ break closing;
+ }
+ }
+ else
+ break closing;
+ }
+ while (v == Boolean.FALSE && !stack.isEmpty());
+ }
+ }
+ }
+
+ stack.add(new hTag(tElement));
+ }
+
+ /**
+ * Clear the stack.
+ */
+ public void restart()
+ {
+ stack.clear();
+ }
+
+ /**
+ * Check if this tag is valid for the current context.
+ * Return Boolean.True if it is OK, Boolean.False
+ * if it is surely not OK or the Element that the
+ * content model recommends to insert making the situation
+ * ok. If Boolean.True is returned, the content model current
+ * position is moved forward. Otherwise this position remains
+ * the same.
+ * @param tElement
+ * @return
+ */
+ public Object tagIsValidForContext(TagElement tElement)
+ {
+ // Check the current content model, if one is available.
+ node cv = getCurrentContentModel();
+
+ if (cv != null)
+ return cv.show(tElement.getElement());
+
+ // Check exclusions and inclusions.
+ ListIterator iter = stack.listIterator(stack.size());
+ hTag t;
+ final int idx = tElement.getElement().index;
+
+ // Check only known tags.
+ if (idx >= 0)
+ {
+ BitSet inclusions = new BitSet();
+ while (iter.hasPrevious())
+ {
+ t = (hTag) iter.previous();
+ if (!t.forcibly_closed)
+ {
+ if (t.element.exclusions != null &&
+ t.element.exclusions.get(idx)
+ )
+ return Boolean.FALSE;
+
+ if (t.element.inclusions != null)
+ inclusions.or(t.element.inclusions);
+ }
+ }
+ if (!inclusions.get(idx))
+ return Boolean.FALSE;
+ }
+ return Boolean.TRUE;
+ }
+
+ /**
+ * Validate tag without storing in into the tag stack. This is called
+ * for the empty tags and results the subsequent calls to the openTag
+ * and closeTag.
+ */
+ public void validateTag(TagElement tElement, htmlAttributeSet parameters)
+ {
+ openTag(tElement, parameters);
+ closeTag(tElement);
+ }
+
+ /**
+ * Check for mandatory elements, subsequent to the last tag:
+ * @param tElement The element that will be inserted next.
+ */
+ protected void checkContentModel(TagElement tElement, boolean first)
+ {
+ if (stack.isEmpty())
+ return;
+
+ hTag last = (hTag) stack.getLast();
+ if (last.validationTrace == null)
+ return;
+
+ Object r = last.validationTrace.show(tElement.getElement());
+ if (r == Boolean.FALSE)
+ s_error("The <" + last.element + "> does not match the content model " +
+ last.validationTrace
+ );
+ else if (r instanceof Element) // The content model recommends insertion of this element
+ {
+ if (!first)
+ closeTag(last.tgElement);
+ handleSupposedStartTag((Element) r);
+ openTag(new TagElement((Element) r), null);
+ }
+ }
+
+ /**
+ * The method is called when the tag must be closed because
+ * it does not allow the subsequent elements inside its context
+ * or the end of stream has been reached. The parser is only
+ * informed if the element being closed does not require the
+ * end tag (the "omitEnd" flag is set).
+ * The closing message must be passed to the parser mechanism
+ * before passing message about the opening the next tag.
+ *
+ * @param element The tag being fictionally (forcibly) closed.
+ */
+ protected abstract void handleSupposedEndTag(Element element);
+
+ /**
+ * The method is called when the validator decides to open the
+ * tag on its own initiative. This may happen if the content model
+ * includes the element with the optional (supposed) start tag.
+ *
+ * @param element The tag being opened.
+ */
+ protected abstract void handleSupposedStartTag(Element element);
+
+ /**
+ * Handles the error message. This method must be overridden to pass
+ * the message where required.
+ * @param msg The message text.
+ */
+ protected abstract void s_error(String msg);
+
+ /**
+ * Validate the parameters, report the error if the given parameter is
+ * not in the parameter set, valid for the given attribute. The information
+ * about the valid parameter set is taken from the Element, enclosed
+ * inside the tag. The method does not validate the default parameters.
+ * @param tag The tag
+ * @param parameters The parameters of this tag.
+ */
+ protected void validateParameters(TagElement tag, htmlAttributeSet parameters)
+ {
+ if (parameters == null ||
+ parameters == htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET ||
+ parameters == SimpleAttributeSet.EMPTY
+ )
+ return;
+
+ Enumeration enumeration = parameters.getAttributeNames();
+
+ while (enumeration.hasMoreElements())
+ {
+ validateAttribute(tag, parameters, enumeration);
+ }
+
+ // Check for missing required values.
+ AttributeList a = tag.getElement().getAttributes();
+
+ while (a != null)
+ {
+ if (a.getModifier() == DTDConstants.REQUIRED)
+ if (parameters.getAttribute(a.getName()) == null)
+ {
+ s_error("Missing required attribute '" + a.getName() + "' for <" +
+ tag.getHTMLTag() + ">"
+ );
+ }
+ a = a.next;
+ }
+ }
+
+ private node getCurrentContentModel()
+ {
+ if (!stack.isEmpty())
+ {
+ hTag last = (hTag) stack.getLast();
+ return last.validationTrace;
+ }
+ else
+ return null;
+ }
+
+ private void closeLast()
+ {
+ handleSupposedEndTag(((hTag) stack.getLast()).element);
+ stack.removeLast();
+ }
+
+ private void openFictionalTag(Element e)
+ {
+ handleSupposedStartTag(e);
+ stack.add(new hTag(new TagElement(e, true)));
+ if (!e.omitStart())
+ s_error("<" + e + "> is expected (supposing it)");
+ }
+
+ private void validateAttribute(TagElement tag, htmlAttributeSet parameters,
+ Enumeration enumeration
+ )
+ {
+ Object foundAttribute;
+ AttributeList dtdAttribute;
+ foundAttribute = enumeration.nextElement();
+ dtdAttribute = tag.getElement().getAttribute(foundAttribute.toString());
+ if (dtdAttribute == null)
+ {
+ StringBuffer valid =
+ new StringBuffer("The tag <" + tag.getHTMLTag() +
+ "> cannot contain the attribute '" + foundAttribute +
+ "'. The valid attributes for this tag are: "
+ );
+
+ AttributeList a = tag.getElement().getAttributes();
+
+ while (a != null)
+ {
+ valid.append(a.name.toUpperCase());
+ valid.append(' ');
+ a = a.next;
+ }
+ s_error(valid.toString());
+ }
+
+ else
+ {
+ String value = parameters.getAttribute(foundAttribute).toString();
+
+ if (dtdAttribute.type == DTDConstants.NUMBER)
+ validateNumberAttribute(tag, foundAttribute, value);
+
+ if (dtdAttribute.type == DTDConstants.NAME ||
+ dtdAttribute.type == DTDConstants.ID
+ )
+ validateNameOrIdAttribute(tag, foundAttribute, value);
+
+ if (dtdAttribute.values != null)
+ validateAttributeWithValueList(tag, foundAttribute, dtdAttribute,
+ value
+ );
+ }
+ }
+
+ private void validateAttributeWithValueList(TagElement tag,
+ Object foundAttribute,
+ AttributeList dtdAttribute,
+ String value
+ )
+ {
+ if (!dtdAttribute.values.contains(value.toLowerCase()) &&
+ !dtdAttribute.values.contains(value.toUpperCase())
+ )
+ {
+ StringBuffer valid;
+ if (dtdAttribute.values.size() == 1)
+ valid =
+ new StringBuffer("The attribute '" + foundAttribute +
+ "' of the tag <" + tag.getHTMLTag() +
+ "> cannot have the value '" + value +
+ "'. The only valid value is "
+ );
+ else
+ valid =
+ new StringBuffer("The attribute '" + foundAttribute +
+ "' of the tag <" + tag.getHTMLTag() +
+ "> cannot have the value '" + value + "'. The " +
+ dtdAttribute.values.size() +
+ " valid values are: "
+ );
+
+ Enumeration vv = dtdAttribute.values.elements();
+ while (vv.hasMoreElements())
+ {
+ valid.append('"');
+ valid.append(vv.nextElement());
+ valid.append("\" ");
+ }
+ s_error(valid.toString());
+ }
+ }
+
+ private void validateNameOrIdAttribute(TagElement tag, Object foundAttribute,
+ String value
+ )
+ {
+ boolean ok = true;
+
+ if (!Character.isLetter(value.charAt(0)))
+ ok = false;
+
+ char c;
+ for (int i = 0; i < value.length(); i++)
+ {
+ c = value.charAt(i);
+ if (!(
+ Character.isLetter(c) || Character.isDigit(c) ||
+ "".indexOf(c) >= 0
+ )
+ )
+ ok = false;
+ }
+ if (!ok)
+ s_error("The '" + foundAttribute + "' attribute of the tag <" +
+ tag.getHTMLTag() + "> must start from letter and consist of " +
+ "letters, digits, hypens, colons, underscores and periods. " +
+ "It cannot be '" + value + "'"
+ );
+ }
+
+ private void validateNumberAttribute(TagElement tag, Object foundAttribute,
+ String value
+ )
+ {
+ try
+ {
+ Integer.parseInt(value);
+ }
+ catch (NumberFormatException ex)
+ {
+ s_error("The '" + foundAttribute + "' attribute of the tag <" +
+ tag.getHTMLTag() + "> must be a valid number and not '" +
+ value + "'"
+ );
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java
new file mode 100644
index 0000000..5a19a1b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java
@@ -0,0 +1,62 @@
+/* PCDATAonly_model.java --
+ Copyright (C) 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 gnu.javax.swing.text.html.parser.models;
+
+import java.io.Serializable;
+
+/**
+ * The model, allowing only PCDATA in it (like for element OPTION).
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class PCDATAonly_model
+ extends node
+ implements Serializable
+{
+ private static final long serialVersionUID = 1;
+
+ public PCDATAonly_model()
+ {
+ super((char) 0, (char) 0, null);
+ }
+
+ public Object show(Object x)
+ {
+ return x.toString().equalsIgnoreCase("#pcdata") ? Boolean.TRUE : Boolean.FALSE;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java
new file mode 100644
index 0000000..14514d5
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java
@@ -0,0 +1,77 @@
+/* TableRowContentModel.java --
+ Copyright (C) 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 gnu.javax.swing.text.html.parser.models;
+
+import java.io.Serializable;
+
+import javax.swing.text.html.parser.DTD;
+import javax.swing.text.html.parser.Element;
+
+/**
+ * Table row content model.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class TableRowContentModel
+ extends node
+ implements Serializable
+{
+ private static final long serialVersionUID = 1;
+ final Element TD;
+
+ public TableRowContentModel(DTD dtd)
+ {
+ super((char) 0, (char) 0, null);
+ TD = dtd.getElement("TD");
+ }
+
+ public Object show(Object x)
+ {
+ // Always accept TD and TH
+ String s = x.toString();
+ if (s.equalsIgnoreCase("TD") || s.equalsIgnoreCase("TH"))
+ return Boolean.TRUE;
+
+ // Suggest closing in response to TR:
+ if (s.equalsIgnoreCase("TR"))
+ return Boolean.FALSE;
+
+ // Recommend TD for other cases:
+ return TD;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java
new file mode 100644
index 0000000..b77ef7f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java
@@ -0,0 +1,382 @@
+/* list.java --
+ Copyright (C) 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 gnu.javax.swing.text.html.parser.models;
+
+import java.io.Serializable;
+
+/**
+ * Part of the internal representation of the content model.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class list
+ extends node
+ implements Serializable
+{
+ private static final long serialVersionUID = 1;
+
+ /**
+ * Setting to true means that the list nodes must always be connected
+ * by the same operation. This is far safer and clearer, but not
+ * required by default standard.
+ */
+ public static boolean CLEAR;
+
+ /**
+ * A list of nodes.
+ */
+ public final node[] nodes;
+
+ /**
+ * Creates a new model list that is a member of some enclosing list.
+ * @param binary_operator An operator with that this list is connected
+ * with other members of the enclosing list.
+ * @param unary_operator The unary operator for this list.
+ * @param a_nodes The nodes inside this list.
+ */
+ public list(char binary_operator, char unary_operator, node[] a_nodes)
+ {
+ super(binary_operator, unary_operator, a_nodes);
+ nodes = a_nodes;
+ }
+
+ /**
+ * Creates a new model list. Assigns the previous field.
+ * @param a_nodes The nodes for this list.
+ * @throws an error if the node elements are connected by the
+ * different operations. This is not supported, use grouping.
+ */
+ public list(node[] a_nodes)
+ throws Error
+ {
+ this(',', (char) 0, a_nodes);
+
+ int operation = nodes [ 0 ].binary;
+
+ for (int i = 0; i < nodes.length; i++)
+ {
+ if (CLEAR && nodes [ i ].binary != operation)
+ throw new Error("List members can only be connected by " +
+ "the same operation, use grouping"
+ );
+
+ if (i > 0)
+ nodes [ i ].previous = nodes [ i - 1 ];
+ }
+ }
+
+ /**
+ * Returns true if all members in the list are closed.
+ */
+ public boolean isClosed()
+ {
+ if (super.isClosed())
+ return true;
+ for (int i = 0; i < nodes.length; i++)
+ {
+ if (!nodes [ i ].isClosed())
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Find the token that could match as the next token in
+ * the token list.
+ *
+ * @return Such token object or null if none is found.
+ */
+ public Object findFreeNode()
+ {
+ Object fn;
+ for (int j = 0; j < nodes.length; j++)
+ {
+ if (!nodes [ j ].isClosed())
+ {
+ fn = nodes [ j ].findFreeNode();
+ if (fn != null)
+ return fn;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Tries to match this list agains the given token sequence.
+ * @param tokens the sequence of the tokens to match.
+ * @return true if the valid match is found.
+ */
+ public boolean matches(Object[] tokens)
+ {
+ reset();
+
+ Object x;
+ boolean m;
+ boolean matched = false;
+
+ for (int i = 0; i < tokens.length; i++)
+ {
+ matched = false;
+ x = tokens [ i ];
+
+ nodescan:
+ for (int j = 0; j < nodes.length; j++)
+ {
+ if (!nodes [ j ].isClosed())
+ {
+ m = nodes [ j ].performMatch(x);
+
+ if (m)
+ {
+ matched = true;
+ break nodescan;
+ }
+ }
+ }
+ if (!matched)
+ return false;
+ }
+
+ boolean valid = true;
+
+ for (int i = 0; i < nodes.length; i++)
+ {
+ if (!nodes [ i ].valid())
+ valid = false;
+ }
+
+ return valid;
+ }
+
+ /**
+ * The list never closes, despite it is trated as closed
+ * if all members in the list are closed.
+ * @return false.
+ */
+ public boolean mustClose()
+ {
+ return false;
+ }
+
+ /**
+ * Perform a match operation for the single token
+ * against this list.
+ * @param token a token to match.
+ * @return true if the match is found.
+ */
+ public boolean performMatch(Object token)
+ {
+ boolean ok = false;
+ Matching:
+ for (int i = 0; i < nodes.length; i++)
+ {
+ ok = nodes [ i ].performMatch(token);
+
+ if (ok)
+ break Matching;
+ }
+
+ if (ok)
+ matches();
+
+ return ok;
+ }
+
+ /**
+ * Prepeares the list for the next matching operation.
+ */
+ public void reset()
+ {
+ super.reset();
+ for (int i = 0; i < nodes.length; i++)
+ nodes [ i ].reset();
+ }
+
+ /**
+ * Check if the provided token can match as a next token in the
+ * list. In the case of match, the list state changes, moving
+ * current position after the matched token. However if this method
+ * returns a suggested new token to insert before the provided one,
+ * the state of the list does not change.
+ * @return Boolean.TRUE if the match is found,
+ * Boolean.FALSE if the match is not possible and no token can be
+ * inserted to make the match valid. Otherwise, returns the
+ * token object that can be inserted before the last token in the
+ * list, probably (not for sure) making the match valid.
+ * If the object is an instance of Element or TagElement,
+ * it is first ensured that the object flag "omit start" is set.
+ */
+ public Object show(Object x)
+ {
+ boolean m;
+ boolean matched = false;
+
+ nodescan:
+ for (int j = 0; j < nodes.length; j++)
+ {
+ if (!nodes [ j ].isClosed())
+ {
+ m = nodes [ j ].performMatch(x);
+
+ if (m)
+ {
+ matched = true;
+ break nodescan;
+ }
+ else
+ {
+ // For comma operation, only first not closed
+ // node must be tested for a match.
+ // unless it allows matching zero times.
+ if (binary == ',' &&
+ !(nodes [ j ].unary == '?' || nodes [ j ].unary == '*')
+ )
+ break nodescan;
+ }
+ }
+ }
+
+ if (!matched)
+ {
+ // Find and return that would be matched.
+ Object freeNode = findFreeNode();
+ if (freeNode == null)
+ return Boolean.FALSE;
+ else
+ return freeNode;
+ }
+
+ for (int i = 0; i < nodes.length; i++)
+ if (!nodes [ i ].validPreliminary())
+ {
+ return Boolean.FALSE;
+ }
+
+ return Boolean.TRUE;
+ }
+
+ /**
+ * Returns a string representation of the list.
+ * @return String representation, similar to BNF expression.
+ */
+ public String toString()
+ {
+ StringBuffer b = new StringBuffer();
+ b.append(" ( ");
+ for (int i = 0; i < nodes.length; i++)
+ {
+ if (i > 0)
+ b.append(" " + (char) nodes [ i ].binary + " ");
+ b.append(nodes [ i ]);
+ }
+
+ b.append(" )");
+ if (unary != 0)
+ b.append((char) unary);
+ else
+ b.append(' ');
+ return b.toString();
+ }
+
+ /**
+ * Returns true if all memebers in the list are valid.
+ */
+ public boolean valid()
+ {
+ for (int i = 0; i < nodes.length; i++)
+ {
+ if (!nodes [ i ].valid())
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if all memebers in the list are either valid
+ * or unvisited. The unvisited members can become valid after
+ * more tokens will be shown.
+ */
+ public boolean validPreliminary()
+ {
+ if (silenceAllowed())
+ {
+ boolean everVisited = false;
+ for (int i = 0; i < nodes.length; i++)
+ {
+ if (nodes [ i ].visits > 0)
+ {
+ everVisited = true;
+ break;
+ }
+ }
+ if (!everVisited)
+ return true;
+ }
+
+ for (int i = 0; i < nodes.length; i++)
+ {
+ if (!nodes [ i ].validPreliminary())
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Closes all members in the list.
+ */
+ protected void close()
+ {
+ super.close();
+ for (int i = 0; i < nodes.length; i++)
+ {
+ nodes [ i ].close();
+ }
+ }
+
+ /**
+ * Compare given token with the token of this node.
+ * If the token represents a list
, the call may be
+ * delegeted to the child subnodes.
+ * @param a_token A token to compare.
+ * @return True if the token matches the token of this node.
+ */
+ protected boolean compare(Object a_token)
+ {
+ return performMatch(a_token);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java
new file mode 100644
index 0000000..8aac14d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java
@@ -0,0 +1,75 @@
+/* noTagModel.java --
+ Copyright (C) 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 gnu.javax.swing.text.html.parser.models;
+
+import java.io.Serializable;
+
+/**
+ * Disallows a single given tag at the current content level only.
+ *
@author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */ +public class noTagModel + extends node + implements Serializable +{ + private static final long serialVersionUID = 1; + final String[] no; + + public noTagModel(String[] noTag) + { + super((char) 0, (char) 0, null); + no = noTag; + } + + public noTagModel(String noTag) + { + super((char) 0, (char) 0, null); + no = new String[] { noTag }; + } + + public Object show(Object x) + { + for (int i = 0; i < no.length; i++) + { + if (x.toString().equalsIgnoreCase(no [ i ])) + return Boolean.FALSE; + } + return Boolean.TRUE; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java new file mode 100644 index 0000000..c615ddf --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java @@ -0,0 +1,337 @@ +/* node.java -- + Copyright (C) 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 gnu.javax.swing.text.html.parser.models; + +import java.io.Serializable; + +/** + * Part of the internal representation of the content model. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class node + implements Serializable +{ + private static final long serialVersionUID = 1; + + /** + * The token to match (can be instance of list). + */ + public Object token; + + /** + * True for the node that cannot be visited again. + */ + public boolean _closed; + + /** + * The binary operation for this node. + */ + public char binary; + + /** + * The unary opeation for this node. + */ + public char unary; + + /** + * The number of times the node already was visited. + */ + public int visits; + + /** + * The previous node in content model (used for closing nodes). + */ + public node previous; + + /** + * Creates a new node. + * @param binary_operator The operator, connecting all nodes in the list. + * The nodes, connected by the different operators, must be arranged into + * the different lists. + * @param unary_operator The unary operator for this node or zero if + * no such was specified. + * @param token The token to match. This can be either a string or + * the new instance of the list. + * @param a_previous The previous node in the list, null for the first + * node. This is used for propagating the closing operation for the + * comma delimited list. + */ + public node(char binary_operator, char unary_operator, Object a_token) + { + if (a_token != null) + if (a_token.getClass().equals(node.class)) + throw new Error("Creating node in node is redundant and ineffective."); + + binary = binary_operator; + unary = unary_operator; + token = a_token; + } + + /** + * Checks if this node is in the closed state. + * @return True if the node is closed. + */ + public boolean isClosed() + { + return _closed; + } + + /** + * Check if closing this node means closing the previous node. + */ + public boolean closePrevious() + { + return binary == ','; + } + + /** + * Return the token object if it could match as a next token in + * a token list of null if it could not. + * @return + */ + public Object findFreeNode() + { + boolean ok; + if (isClosed() || silenceAllowed()) + return null; + + // Try if the node would stay valid after a one more visit. + visits++; + ok = valid(); + visits--; + + if (ok) + { + if (token instanceof node) + return ((node) token).findFreeNode(); + else + return token; + } + else + return null; + } + + /** + * Check if the current situation is such that the node must be closed + * now. + */ + public boolean mustClose() + { + switch (unary) + { + case 0 : + return true; + + case '*' : + return false; + + case '+' : + return false; + + case '?' : + return visits <= 1; + + default : + throw new Error("Invalid unary operation " + unary + " ( '" + + (char) unary + "' )" + ); + } + } + + /** + * Do the match operation with the given token. This sets various + * flags. + * @param token The token to match. + * @return true if the the token matches node, false if it does not match + * or if the node is closed. + */ + public boolean performMatch(Object a_token) + { + if (isClosed()) + return false; + + boolean matches = compare(a_token); + if (matches) + matches(); + + return matches; + } + + /** + * Prepares the node for matching against a new list of tokens. + */ + public void reset() + { + _closed = false; + visits = 0; + } + + /** + * Check if the provided token can match this node. + * In the case of match, the node state changes, moving + * current position after the matched token. However if this method + * returns a suggested new token to insert before the provided one, + * the state of the list does not change. + * @return Boolean.TRUE if the match is found, + * Boolean.FALSE if the match is not possible and no token can be + * inserted to make the match valid. Otherwise, returns the + * token object that can be inserted before the last token in the + * list, probably (not for sure) making the match valid. + */ + public Object show(Object x) + { + if (compare(x)) + return performMatch(x) ? Boolean.TRUE : Boolean.FALSE; + + Object recommended = findFreeNode(); + return recommended != null ? recommended : Boolean.FALSE; + } + + /** + * Check if it would be a valid case if this node is visited zero times. + * Nodes with unary operator * or ? need not be matched to make a + * model valid. + */ + public boolean silenceAllowed() + { + return unary == '?' || unary == '*'; + } + + /** + * Returns a string representation of the list. + * @return String representation, similar to BNF expression. + */ + public String toString() + { + StringBuffer b = new StringBuffer(); + + b.append(token); + if (unary != 0) + b.append((char) unary); + else + b.append('\''); + + return b.toString(); + } + + /** + * Check if the node state is valid. + */ + public boolean valid() + { + switch (unary) + { + case 0 : + if (binary == '|') + return true; + else + return visits == 1; + + case '*' : + return true; + + case '+' : + return visits > 0; + + case '?' : + return visits <= 1; + + default : + throw new Error("Invalid unary operation " + unary + " ( '" + + (char) unary + "' )" + ); + } + } + + public boolean validPreliminary() + { + return visits == 0 || valid(); + } + + /** + * Closes this node and, if closePrevious() returs true, calls close() for + * the previous node. + */ + protected void close() + { + _closed = true; + if (previous != null && closePrevious()) + previous.close(); + } + + /** + * Compare the provided token object with the token object of this node. + */ + protected boolean compare(Object a_token) + { + if (token instanceof Object[]) + throw new Error("Invalid token object, probably the 'list' " + + "should be used. " + ); + + if (token instanceof node[]) + throw new Error("Do not use 'node' for the array of nodes, use 'list'. "); + + if (token instanceof node) + { + return ((node) token).performMatch(a_token); + } + + boolean rt = false; + + if (token == a_token) + rt = true; + if (token.equals(a_token)) + rt = true; + if (token.toString().equalsIgnoreCase(a_token.toString())) + rt = true; + + return rt; + } + + /** + * Fire the changes that must happen then the token matches this node. + */ + protected void matches() + { + visits++; + if (mustClose()) + close(); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html b/libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html new file mode 100644 index 0000000..18e61ae --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html @@ -0,0 +1,53 @@ + + + + +This package contains classes for working with content models. In this implementation, the
+standardized content model is pre-processed by transformer
into an instance of
+node
. Node holds a single element of the content model with the optional unary operation.
+The derived class list
holds multiple nodes connected by the same binary operation.
+As the members of this list
can also be lists itself, these structures support
+the most of required operations. Several cases when the model cannot be expressed using
+BNF syntax are handled providing specialised classes that are also derived from node
.
+
Provides the error tolerant, DTD-driven HTML 4.01 parser. +The parser that is used in web robots, html content analysers, +web browsers, web editors and other related applications. +It should compativle with the older HTML versions, supporting +obsoleted HTML featues. This package also includes some +supporting classes.
+@author Audrius Meskauskas, Lithuania + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java new file mode 100644 index 0000000..cef9494 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java @@ -0,0 +1,1443 @@ +/* Parser.java -- HTML parser. + Copyright (C) 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 gnu.javax.swing.text.html.parser.support; + +import gnu.javax.swing.text.html.parser.htmlAttributeSet; +import gnu.javax.swing.text.html.parser.htmlValidator; +import gnu.javax.swing.text.html.parser.support.low.Constants; +import gnu.javax.swing.text.html.parser.support.low.ParseException; +import gnu.javax.swing.text.html.parser.support.low.ReaderTokenizer; +import gnu.javax.swing.text.html.parser.support.low.Token; +import gnu.javax.swing.text.html.parser.support.low.node; +import gnu.javax.swing.text.html.parser.support.low.pattern; + +import java.io.IOException; +import java.io.Reader; + +import java.util.Comparator; +import java.util.Set; +import java.util.TreeSet; +import java.util.Vector; + +import javax.swing.text.ChangedCharSetException; +import javax.swing.text.html.HTML; +import javax.swing.text.html.parser.AttributeList; +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.DTDConstants; +import javax.swing.text.html.parser.Element; +import javax.swing.text.html.parser.Entity; +import javax.swing.text.html.parser.TagElement; + +/** + *A simple error-tolerant HTML parser that uses a DTD document + * to access data on the possible tokens, arguments and syntax.
+ *The parser reads an HTML content from a Reader and calls various + * notifying methods (which should be overridden in a subclass) + * when tags or data are encountered.
+ *Some HTML elements need no opening or closing tags. The + * task of this parser is to invoke the tag handling methods also when + * the tags are not explicitly specified and must be supposed using + * information, stored in the DTD. + * For example, parsing the document + *
<table><tr><td>a<td>b<td>c</tr>
+ * will invoke exactly the handling methods exactly in the same order
+ * (and with the same parameters) as if parsing the document:
+ * <html><head></head><body><table><
+ * tbody><tr><td>a</td><td>b
+ * </td><td>c</td></tr><
+ * /tbody></table></body></html>
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Parser + extends ReaderTokenizer + implements DTDConstants +{ + /** + * The current html tag. + */ + public Token hTag = new Token(); + + /** + * The document template description that will be used to parse the documents. + */ + protected DTD dtd; + + /** + * The value of this field determines whether or not the Parser will be + * strict in enforcing SGML compatibility. The default value is false, + * stating that the parser should do everything to parse and get at least + * some information even from the incorrectly written HTML input. + */ + protected boolean strict; + + /** + * This fields has positive values in preformatted tags. + */ + protected int preformatted = 0; + + /** + * The set of the document tags. This field is used for supporting + * markFirstTime(). + */ + private Set documentTags = + new TreeSet(new Comparator() + { + public int compare(Object a, Object b) + { + return ((String) a).compareToIgnoreCase((String) b); + } + } + ); + + /** + * The buffer to collect the incremental output like text or coment. + */ + private StringBuffer buffer = new StringBuffer(); + + /** + * The buffer to store the document title. + */ + private StringBuffer title = new StringBuffer(); + + /** + * The current token. + */ + private Token t; + + /** + * True means that the 'title' tag of this document has + * already been handled. + */ + private boolean titleHandled; + + /** + * True means that the 'title' tag is currently open and all + * text is also added to the title buffer. + */ + private boolean titleOpen; + + /** + * The attributes of the current HTML element. + * Package-private to avoid an accessor method. + */ + htmlAttributeSet attributes = + htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET; + + /** + * The validator, controlling the forcible closing of the tags that + * (in accordance to dtd) are not allowed in the current context. + */ + private htmlValidator validator; + + /** + * Provides the default values for parameters in the case when these + * values are defined in the DTD. + */ + private parameterDefaulter defaulter; + + /** + * The text pre-processor for handling line ends and tabs. + */ + private textPreProcessor textProcessor = new textPreProcessor(); + + /** + * Creates a new Parser that uses the given + * {@link javax.swing.text.html.parser.DTD }. The only standard way + * to get an instance of DTD is to construct it manually, filling in + * all required fields. + * @param a_dtd The DTD to use. The parser behaviour after passing null + * as an argument is not documented and may vary between implementations. + */ + public Parser(DTD a_dtd) + { + if (a_dtd == null) + dtd = gnu.javax.swing.text.html.parser.HTML_401F.getInstance(); + else + dtd = a_dtd; + + defaulter = new parameterDefaulter(dtd); + + validator = + new htmlValidator(dtd) + { + /** + * Handles the error message. This method must be overridden to pass + * the message where required. + * @param msg The message text. + */ + protected void s_error(String msg) + { + error(msg); + } + + /** + * The method is called when the tag validator decides to close the + * tag on its own initiative. After reaching the end of stream, + * The tag validator closes all unclosed elements that are required + * to have the end (closing) tag. + * + * @param element The tag being fictionally (forcibly) closed. + */ + protected void handleSupposedEndTag(Element tElement) + { + // The tag is cloned as the original tElement is the + // element from the starting tag - may be accidently used + // somewhere else. + TagElement tag = makeTag(tElement, true); + _handleEndTag_remaining(tag); + } + + /** + * The method is called when the the tag validator decides to open + * the new tag on its own initiative. The tags, opened in this + * way, are HTML, HEAD and BODY. The attribute set is temporary + * assigned to the empty one, the previous value is + * restored before return. + * + * @param element The tag being fictionally (forcibly) closed. + */ + protected void handleSupposedStartTag(Element tElement) + { + TagElement tag = makeTag(tElement, true); + htmlAttributeSet were = attributes; + attributes = htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET; + _handleStartTag(tag); + attributes = were; + } + }; + } + + /** + * Get the attributes of the current tag. + * @return The attribute set, representing the attributes of the current tag. + */ + public htmlAttributeSet getAttributes() + { + return attributes; + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to handleError, also providing the current line. + */ + public void error(String msg) + { + error(msg, getTokenAhead()); + } + + public void error(String msg, Token atToken) + { + if (atToken != null) + handleError(atToken.where.beginLine, + msg + ": line " + atToken.where.beginLine + + ", absolute pos " + atToken.where.startPosition + ); + else + handleError(0, msg); + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to error (parm1+": '"+parm2+"'"). + */ + public void error(String msg, String invalid) + { + error(msg + ": '" + invalid + "'"); + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to error (parm1+" "+ parm2+" "+ parm3). + */ + public void error(String parm1, String parm2, String parm3) + { + error(parm1 + " " + parm2 + " " + parm3); + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to error (parm1+" "+ parm2+" "+ parm3+" "+ parm4). + */ + public void error(String parm1, String parm2, String parm3, String parm4) + { + error(parm1 + " " + parm2 + " " + parm3 + " " + parm4); + } + + public void flushAttributes() + { + } + + /** + * Parse the HTML text, calling various methods in response to the + * occurence of the corresponding HTML constructions. + * @param reader The reader to read the source HTML from. + * @throws IOException If the reader throws one. + */ + public synchronized void parse(Reader reader) + throws IOException + { + reset(reader); + restart(); + try + { + parseDocument(); + validator.closeAll(); + } + catch (ParseException ex) + { + if (ex != null) + { + error("Unable to continue parsing the document", ex.getMessage()); + + Throwable cause = ex.getCause(); + if (cause instanceof IOException) + throw (IOException) cause; + } + } + } + + /** + * Parses DTD markup declaration. Currently returns null without action. + * @return null. + * @throws IOException + */ + public String parseDTDMarkup() + throws IOException + { + return null; + } + + /** + * Parse SGML insertion ( <! ... > ). When the + * the SGML insertion is found, this method is called, passing + * SGML in the string buffer as a parameter. The default method + * returns false without action and can be overridden to + * implement user - defined SGML support. + *+ * If you need more information about SGML insertions in HTML documents, + * the author suggests to read SGML tutorial on + * {@link http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html}. + * We also recommend Goldfarb C.F (1991) The SGML Handbook, + * Oxford University Press, 688 p, ISBN: 0198537379. + *
+ * @param strBuff + * @return true if this is a valid DTD markup declaration. + * @throws IOException + */ + public boolean parseMarkupDeclarations(StringBuffer strBuff) + throws IOException + { + return false; + } + + /** + * Get the first line of the last parsed token. + */ + protected int getCurrentLine() + { + return hTag.where.beginLine; + } + + /** + * Read parseable character data, add to buffer. + * @param clearBuffer If true, buffer if filled by CDATA section, + * otherwise the section is appended to the existing content of the + * buffer. + * + * @throws ParseException + */ + protected void CDATA(boolean clearBuffer) + throws ParseException + { + Token start = hTag = getTokenAhead(); + + if (clearBuffer) + buffer.setLength(0); + + // Handle expected EOF. + if (start.kind == EOF) + return; + + read: + while (true) + { + t = getTokenAhead(); + if (t.kind == EOF) + { + error("unexpected eof", t); + break read; + } + else if (t.kind == BEGIN) + break read; + else if (t.kind == Constants.ENTITY) + { + resolveAndAppendEntity(t); + getNextToken(); + } + else + { + append(t); + getNextToken(); + } + } + hTag = new Token(start, getTokenAhead(0)); + if (buffer.length() != 0) + _handleText(); + } + + /** + * Process Comment. This method skips till --> without + * taking SGML constructs into consideration. The supported SGML + * constructs are handled separately. + */ + protected void Comment() + throws ParseException + { + buffer.setLength(0); + + Token start = hTag = mustBe(BEGIN); + optional(WS); + mustBe(EXCLAMATION); + optional(WS); + mustBe(DOUBLE_DASH); + + Token t; + Token last; + + comment: + while (true) + { + t = getTokenAhead(); + if (t.kind == EOF) + { + handleEOFInComment(); + last = t; + break comment; + } + else if (COMMENT_END.matches(this)) + { + mustBe(DOUBLE_DASH); + optional(WS); + last = mustBe(END); + break comment; + } + else if (COMMENT_TRIPLEDASH_END.matches(this)) + { + mustBe(DOUBLE_DASH); + t = mustBe(NUMTOKEN); + if (t.getImage().equals("-")) + { + append(t); + last = mustBe(END); + break comment; + } + else + { + buffer.append("--"); + append(t); + t = getTokenAhead(); + } + } + else + /* The lllll-- can match as NUMTOKEN */ + if ((t.getImage().endsWith("--")) && + ( + getTokenAhead(1).kind == END || + (getTokenAhead(1).kind == WS && getTokenAhead(2).kind == END) + ) + ) + { + buffer.append(t.getImage().substring(0, t.getImage().length() - 2)); + + /* Skip the closing > that we have already checked. */ + last = mustBe(t.kind); + break comment; + } + else + append(t); + mustBe(t.kind); + } + hTag = new Token(start, last); + handleComment(); + } + + /** + * Read a script. The text, returned without any changes, + * is terminated only by the closing tag SCRIPT. + */ + protected void Script() + throws ParseException + { + Token name; + + Token start = hTag = mustBe(BEGIN); + optional(WS); + + name = mustBe(SCRIPT); + + optional(WS); + + restOfTag(false, name, start); + + buffer.setLength(0); + + script: + while (!SCRIPT_CLOSE.matches(this)) + { + append(getNextToken()); + } + + consume(SCRIPT_CLOSE); + + _handleText(); + + endTag(false); + _handleEndTag(makeTagElement(name.getImage(), false)); + } + + /** + * Process SGML insertion that is not a comment. + */ + protected void Sgml() + throws ParseException + { + if (COMMENT_OPEN.matches(this)) + Comment(); + else // skip till ">" + { + Token start = hTag = mustBe(BEGIN); + optional(WS); + mustBe(EXCLAMATION); + + buffer.setLength(0); + read: + while (true) + { + t = getNextToken(); + if (t.kind == Constants.ENTITY) + { + resolveAndAppendEntity(t); + } + else if (t.kind == EOF) + { + error("unexpected eof", t); + break read; + } + else if (t.kind == END) + break read; + else + append(t); + } + + try + { + parseMarkupDeclarations(buffer); + } + catch (IOException ex) + { + error("Unable to parse SGML insertion: '" + buffer + "'", + new Token(start, t) + ); + } + } + } + + /** + * Read a style definition. The text, returned without any changes, + * is terminated only by the closing tag STYLE. + */ + protected void Style() + throws ParseException + { + Token name; + + Token start = hTag = mustBe(BEGIN); + optional(WS); + + name = mustBe(STYLE); + + optional(WS); + + restOfTag(false, name, start); + + buffer.setLength(0); + + style: + while (!STYLE_CLOSE.matches(this)) + { + append(getNextToken()); + } + + consume(STYLE_CLOSE); + + _handleText(); + + endTag(false); + _handleEndTag(makeTagElement(name.getImage(), false)); + } + + /** + * Read a html tag. + */ + protected void Tag() + throws ParseException + { + mark(true); + + boolean closing = false; + Token name; + Token start = hTag = mustBe(BEGIN); + + optional(WS); + name = getNextToken(); + optional(WS); + + if (name.kind == SLASH) + { + closing = true; + name = getNextToken(); + } + + restOfTag(closing, name, start); + } + + /** + * A hook, for operations, preceeding call to handleText. + * Handle text in a string buffer. + * In non - preformatted mode, all line breaks immediately following the + * start tag and immediately before an end tag is discarded, + * \r, \n and \t are replaced by spaces, multiple space are replaced + * by the single one and the result is moved into array, + * passing it to handleText(). + */ + protected void _handleText() + { + char[] text; + + if (preformatted > 0) + text = textProcessor.preprocessPreformatted(buffer); + else + text = textProcessor.preprocess(buffer); + + if (text != null && text.length > 0) + { + TagElement pcdata = new TagElement(dtd.getElement("#pcdata")); + attributes = htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET; + _handleEmptyTag(pcdata); + + handleText(text); + if (titleOpen) + title.append(text); + } + } + + /** + * Add the image of this token to the buffer. + * @param t A token to append. + */ + protected final void append(Token t) + { + if (t.kind != EOF) + t.appendTo(buffer); + } + + /** + * Consume pattern that must match. + * @param p A pattern to consume. + */ + protected final void consume(pattern p) + { + node n; + for (int i = 0; i < p.nodes.length; i++) + { + n = p.nodes [ i ]; + if (n.optional) + optional(n.kind); + else + mustBe(n.kind); + } + } + + /** + * The method is called when the HTML end (closing) tag is found or if + * the parser concludes that the one should be present in the + * current position. The method is called immediatly + * before calling the handleEndTag(). + * @param omitted True if the tag is no actually present in the document, + * but is supposed by the parser (like </html> at the end of the + * document). + */ + protected void endTag(boolean omitted) + { + } + + /** + * Handle HTML comment. The default method returns without action. + * @param comment + */ + protected void handleComment(char[] comment) + { + } + + /** + * This is additionally called in when the HTML content terminates + * without closing the HTML comment. This can only happen if the + * HTML document contains errors (for example, the closing --;gt is + * missing. + */ + protected void handleEOFInComment() + { + error("Unclosed comment"); + } + + /** + * Handle the tag with no content, like <br>. The method is + * called for the elements that, in accordance with the current DTD, + * has an empty content. + * @param The tag being handled. + * @throws javax.swing.text.ChangedCharSetException + */ + protected void handleEmptyTag(TagElement tag) + throws javax.swing.text.ChangedCharSetException + { + } + + /** + * The method is called when the HTML closing tag ((like </table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param The tag + */ + protected void handleEndTag(TagElement tag) + { + } + + /* Handle error that has occured in the given line. */ + protected void handleError(int line, String message) + { + } + + /** + * The method is called when the HTML opening tag ((like <table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param The tag + */ + protected void handleStartTag(TagElement tag) + { + } + + /** + * Handle the text section. + *For non-preformatted section, the parser replaces + * \t, \r and \n by spaces and then multiple spaces + * by a single space. Additionaly, all whitespace around + * tags is discarded. + *
+ *For pre-formatted text (inside TEXAREA and PRE), the parser preserves + * all tabs and spaces, but removes one bounding \r, \n or \r\n, + * if it is present. Additionally, it replaces each occurence of \r or \r\n + * by a single \n.
+ * + * @param text A section text. + */ + protected void handleText(char[] text) + { + } + + /** + * Handle HTML <title> tag. This method is invoked when + * both title starting and closing tags are already behind. + * The passed argument contains the concatenation of all + * title text sections. + * @param The title text. + */ + protected void handleTitle(char[] title) + { + } + + /** + * Constructs the tag from the given element. In this implementation, + * this is defined, but never called. + * @return the tag + */ + protected TagElement makeTag(Element element) + { + return makeTag(element, false); + } + + /** + * Constructs the tag from the given element. + * @param the tag base {@link javax.swing.text.html.parser.Element} + * @param isSupposed true if the tag is not actually present in the + * html input, but the parser supposes that it should to occur in + * the current location. + * @return the tag + */ + protected TagElement makeTag(Element element, boolean isSupposed) + { + return new TagElement(element, isSupposed); + } + + /** + * This is called when the tag, representing the given element, + * occurs first time in the document. + * @param element + */ + protected void markFirstTime(Element element) + { + } + + /** + * Consume the token that was checked before and hence MUST be present. + * @param kind The kind of token to consume. + */ + protected Token mustBe(int kind) + { + if (getTokenAhead().kind == kind) + return getNextToken(); + else + { + String ei = ""; + if (kind < 1000) + ei = " ('" + (char) kind + "') "; + throw new AssertionError("The token of kind " + kind + ei + + " MUST be here," + ); + } + } + + /** + * Handle attribute without value. The default method uses + * the only allowed attribute value from DTD. + * If the attribute is unknown or allows several values, + * the HTML.NULL_ATTRIBUTE_VALUE is used. The attribute with + * this value is added to the attribute set. + * @param element The name of element. + * @param attribute The name of attribute without value. + */ + protected void noValueAttribute(String element, String attribute) + { + Object value = HTML.NULL_ATTRIBUTE_VALUE; + + Element e = (Element) dtd.elementHash.get(element.toLowerCase()); + if (e != null) + { + AttributeList attr = e.getAttribute(attribute); + if (attr != null) + { + Vector values = attr.values; + if (values != null && values.size() == 1) + value = values.get(0); + } + } + attributes.addAttribute(attribute, value); + } + + /** + * Consume the optional token, if present. + * @param kind The kind of token to consume. + */ + protected Token optional(int kind) + { + if (getTokenAhead().kind == kind) + return getNextToken(); + else + return null; + } + + /** Parse the html document. */ + protected void parseDocument() + throws ParseException + { + while (getTokenAhead().kind != EOF) + { + advanced = false; + if (TAG.matches(this)) + Tag(); + else if (COMMENT_OPEN.matches(this)) + Comment(); + else if (STYLE_OPEN.matches(this)) + Style(); + else if (SCRIPT_OPEN.matches(this)) + Script(); + else if (SGML.matches(this)) + Sgml(); + else + CDATA(true); + + // Surely HTML error, treat as a text. + if (!advanced) + { + Token wrong = getNextToken(); + error("unexpected '" + wrong.getImage() + "'", wrong); + buffer.setLength(0); + buffer.append(wrong.getImage()); + _handleText(); + } + } + } + + /** + * Read the element attributes, adding them into attribute set. + * @param element The element name (needed to access attribute + * information in dtd). + */ + protected void readAttributes(String element) + { + Token name; + Token value; + Token next; + String attrValue; + + attributes = new htmlAttributeSet(); + + optional(WS); + + attributeReading: + while (getTokenAhead().kind == NUMTOKEN) + { + name = getNextToken(); + optional(WS); + + next = getTokenAhead(); + if (next.kind == EQ) + { + mustBe(EQ); + optional(WS); + + next = getNextToken(); + + switch (next.kind) + { + case QUOT : + + // read "quoted" attribute. + buffer.setLength(0); + readTillTokenE(QUOT); + attrValue = buffer.toString(); + break; + + case AP : + + // read 'quoted' attribute. + buffer.setLength(0); + readTillTokenE(AP); + attrValue = buffer.toString(); + break; + + // read unquoted attribute. + case NUMTOKEN : + value = next; + optional(WS); + + // Check maybe the opening quote is missing. + next = getTokenAhead(); + if (bQUOTING.get(next.kind)) + { + hTag = next; + error("The value without opening quote is closed with '" + + next.getImage() + "'" + ); + } + attrValue = value.getImage(); + break; + + default : + break attributeReading; + } + attributes.addAttribute(name.getImage(), attrValue); + optional(WS); + } + else // The '=' is missing: attribute without value. + { + noValueAttribute(element, name.getImage()); + } + } + } + + /** + * Return string, corresponding the given named entity. + * The name is passed with the preceeding &, but without + * the ending semicolon. + */ + protected String resolveNamedEntity(final String a_tag) + { + // Discard & + if (!a_tag.startsWith("&")) + throw new AssertionError("Named entity " + a_tag + + " must start witn '&'." + ); + + String tag = a_tag.substring(1); + + try + { + Entity entity = dtd.getEntity(tag); + if (entity != null) + return entity.getString(); + + entity = dtd.getEntity(tag.toLowerCase()); + + if (entity != null) + { + error("The name of this entity should be in lowercase", a_tag); + return entity.getString(); + } + } + catch (IndexOutOfBoundsException ibx) + { + /* The error will be reported. */ + } + + error("Unknown named entity", a_tag); + return a_tag; + } + + /** + * Return char, corresponding the given numeric entity. + * The name is passed with the preceeding , but without + * the ending semicolon. + */ + protected char resolveNumericEntity(final String a_tag) + { + // Discard + if (!a_tag.startsWith("")) + throw new AssertionError("Numeric entity " + a_tag + + " must start witn ''." + ); + + String tag = a_tag.substring(2); + + try + { + // Determine the encoding type: + char cx = tag.charAt(0); + if (cx == 'x' || cx == 'X') // Hexadecimal nnn; + + return (char) Integer.parseInt(tag.substring(1), 16); + + return (char) Integer.parseInt(tag); + } + + /* The error will be reported. */ + catch (NumberFormatException nex) + { + } + catch (IndexOutOfBoundsException ix) + { + } + + error("Invalid numeric entity", a_tag); + return '?'; + } + + /** + * Reset all fields into the intial default state, preparing the + * parset for parsing the next document. + */ + protected void restart() + { + documentTags.clear(); + titleHandled = false; + titleOpen = false; + buffer.setLength(0); + title.setLength(0); + validator.restart(); + } + + /** + * The method is called when the HTML opening tag ((like <table>) + * is found or if the parser concludes that the one should be present + * in the current position. The method is called immediately before + * calling the handleStartTag. + * @param The tag + */ + protected void startTag(TagElement tag) + throws ChangedCharSetException + { + } + + /** + * Handle a complete element, when the tag content is already present in the + * buffer and both starting and heading tags behind. This is called + * in the case when the tag text must not be parsed for the nested + * elements (elements STYLE and SCRIPT). + */ + private void _handleCompleteElement(TagElement tag) + { + _handleStartTag(tag); + + // Suppress inclusion of the SCRIPT ans STYLE texts into the title. + HTML.Tag h = tag.getHTMLTag(); + if (h == HTML.Tag.SCRIPT || h == HTML.Tag.STYLE) + { + boolean tmp = titleOpen; + titleOpen = false; + _handleText(); + titleOpen = tmp; + } + else + _handleText(); + + _handleEndTag(tag); + } + + /** + * A hooks for operations, preceeding call to handleEmptyTag(). + * Handle the tag with no content, like <br>. As no any + * nested tags are expected, the tag validator is not involved. + * @param The tag being handled. + */ + private void _handleEmptyTag(TagElement tag) + { + try + { + validator.validateTag(tag, attributes); + handleEmptyTag(tag); + } + catch (ChangedCharSetException ex) + { + error("Changed charset exception:", ex.getMessage()); + } + } + + /** + * A hooks for operations, preceeding call to handleEndTag(). + * The method is called when the HTML closing tag + * is found. Calls handleTitle after closing the 'title' tag. + * @param The tag + */ + private void _handleEndTag(TagElement tag) + { + validator.closeTag(tag); + _handleEndTag_remaining(tag); + } + + /** + * Actions that are also required if the closing action was + * initiated by the tag validator. + * Package-private to avoid an accessor method. + */ + void _handleEndTag_remaining(TagElement tag) + { + HTML.Tag h = tag.getHTMLTag(); + + handleEndTag(tag); + endTag(tag.fictional()); + + if (h.isPreformatted()) + preformatted--; + if (preformatted < 0) + preformatted = 0; + + if (h == HTML.Tag.TITLE) + { + titleOpen = false; + titleHandled = true; + + char[] a = new char[ title.length() ]; + title.getChars(0, a.length, a, 0); + handleTitle(a); + } + } + + /** + * A hooks for operations, preceeding call to handleStartTag(). + * The method is called when the HTML opening tag ((like <table>) + * is found. + * Package-private to avoid an accessor method. + * @param The tag + */ + void _handleStartTag(TagElement tag) + { + validator.openTag(tag, attributes); + startingTag(tag); + handleStartTag(tag); + + HTML.Tag h = tag.getHTMLTag(); + + if (h.isPreformatted()) + preformatted++; + + if (h == HTML.Tag.TITLE) + { + if (titleHandled) + error("Repetetiveget
method. Use add
to
+ * create a map for a concrete instance.
+ */
+ protected abstract void create();
+
+ /**
+ * Add an id/string pair to this mapper. This is called from
+ * the method create
only.
+ */
+ protected void add(String name, int id)
+ {
+ Integer i = new Integer(id);
+ si_Map.put(name, i);
+ is_Map.put(i, name);
+ }
+
+ private void createTheMap()
+ {
+ is_Map = new HashMap();
+ si_Map = new TreeMap();
+ create();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java
new file mode 100644
index 0000000..a39330a
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java
@@ -0,0 +1,238 @@
+/* Buffer.java --
+ Copyright (C) 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 gnu.javax.swing.text.html.parser.support.low;
+
+/**
+ * A string buffer that additionally holds line and absolute postion
+ * information.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class Buffer
+{
+ public static int INITIAL_SIZE = 2048;
+
+ /**
+ * True if the \n symbol has been seen.
+ */
+ public boolean n_seen;
+
+ /**
+ * True if the \r symbol has been seen.
+ */
+ public boolean r_seen;
+ char[] chr = new char[ INITIAL_SIZE ];
+ int[] line = new int[ INITIAL_SIZE ];
+ int[] position = new int[ INITIAL_SIZE ];
+
+ /**
+ * Current line.
+ */
+ int current_line = 0;
+
+ /**
+ * Point to the next free position.
+ */
+ int length;
+
+ public Buffer()
+ {
+ }
+
+ public Buffer(String content)
+ {
+ for (int i = 0; i < content.length(); i++)
+ {
+ append(content.charAt(i), i);
+ }
+ }
+
+ /**
+ * Get the characters into array.
+ * @param srcBegin From, inclusive
+ * @param srcEnd To, exclusive.
+ * @param dst Into
+ * @param dstBegin Offset.
+ */
+ public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
+ {
+ System.arraycopy(chr, srcBegin, dst, dstBegin, (srcEnd - srcBegin));
+ }
+
+ /**
+ * Return the sequence, used to separate lines in the document.
+ * @return one of \n, \r or \r\n.
+ */
+ public String getEndOfLineSequence()
+ {
+ if (r_seen && n_seen)
+ return "\r\n";
+ else if (r_seen)
+ return "\r";
+ else
+
+ // This also is returned for single-line document.
+ return "\n";
+ }
+
+ /**
+ * Truncate.
+ * @param n The length to truncate till.
+ */
+ public void setLength(int n)
+ {
+ length = n;
+ }
+
+ /**
+ * Get location information for the given region.
+ * @param from Region start, inclusive.
+ * @param to Region end, exclusive.
+ * @return The location, covering the region.
+ */
+ public Location getLocation(int from, int to)
+ {
+ Location l = new Location();
+ l.beginLine = line [ from ];
+ l.endLine = line [ to - 1 ];
+
+ l.startPosition = position [ from ];
+ l.endPosition = position [ to - 1 ] + 1;
+
+ return l;
+ }
+
+ /**
+ * Add the character.
+ * @param c The character.
+ * @param pos The character position in the stream (the line number
+ * is handled internally in the buffer).
+ */
+ public void append(char c, int pos)
+ {
+ if (length >= chr.length)
+ expand();
+ chr [ length ] = c;
+ position [ length ] = pos;
+
+ if (c == '\n')
+ {
+ if (!r_seen)
+ current_line++;
+ n_seen = true;
+ }
+ else if (c == '\r')
+ {
+ current_line++;
+ r_seen = true;
+ }
+
+ line [ length ] = current_line;
+
+ length++;
+ }
+
+ /**
+ * Return char at the given positon.
+ */
+ public char charAt(int i)
+ {
+ return chr [ i ];
+ }
+
+ /**
+ * Delete the range
+ * @param from Start position, inclusive.
+ * @param to End position, exclusive.
+ */
+ public void delete(int from, int to)
+ {
+ int len = to - from;
+ if (len < 1)
+ throw new AssertionError("Deleting " + from + " till " + to);
+
+ int tail = length - to;
+
+ System.arraycopy(chr, to, chr, from, tail);
+ System.arraycopy(position, to, position, from, tail);
+ System.arraycopy(line, to, line, from, tail);
+ length = length - len;
+ }
+
+ /**
+ * Double the buffer size.
+ */
+ public void expand()
+ {
+ int nSize = 2 * chr.length;
+
+ char[] nchr = new char[ nSize ];
+ int[] nposition = new int[ nSize ];
+ int[] nline = new int[ nSize ];
+
+ System.arraycopy(chr, 0, nchr, 0, chr.length);
+ System.arraycopy(position, 0, nposition, 0, position.length);
+ System.arraycopy(line, 0, nline, 0, line.length);
+
+ chr = nchr;
+ position = nposition;
+ line = nline;
+ }
+
+ /**
+ * Return length of the occupied part of the buffer.
+ */
+ public int length()
+ {
+ return length;
+ }
+
+ /**
+ * Prepare for parsing the new document.
+ */
+ public void reset()
+ {
+ setLength(0);
+ r_seen = n_seen = false;
+ }
+
+ public String toString()
+ {
+ return new String(chr, 0, length);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java
new file mode 100644
index 0000000..283d323
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java
@@ -0,0 +1,422 @@
+/* Constants.java --
+ Copyright (C) 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 gnu.javax.swing.text.html.parser.support.low;
+
+import java.util.BitSet;
+
+/**
+ * The parser constants and operations, directly related to the parser
+ * constants.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class Constants
+{
+ /* Single character tokens are reflected into they ASCII codes. */
+
+ /**
+ * Start of HTML token.
+ */
+ public static final int BEGIN = '<';
+
+ /**
+ * End of HTML token.
+ */
+ public static final int END = '>';
+
+ /**
+ * Exclamation (indicates SGML or comment).
+ */
+ public static final int EXCLAMATION = '!';
+
+ /**
+ * Slash (indicates closing tag).
+ */
+ public static final int SLASH = '/';
+
+ /**
+ * Equals sign.
+ */
+ public static final int EQ = '=';
+
+ /**
+ * Quoting sign.
+ */
+ public static final int AP = '\'';
+
+ /**
+ * Quoting sign.
+ */
+ public static final int QUOT = '"';
+
+ /* The numbers of other tokens start outside the ascii space. */
+ /* String tokens */
+
+ /**
+ * Double dash (--)
+ */
+ public static final int DOUBLE_DASH = 1000;
+
+ /**
+ * The STYLE tag (needs special handling).
+ */
+ public static final int STYLE = 1001;
+
+ /**
+ * The SCRIPT tag (needs special handling).
+ */
+ public static final int SCRIPT = 1002;
+
+ /* Pattern tokens */
+
+ /**
+ * HTML whitespace.
+ */
+ public static final int WS = 1003;
+
+ /**
+ * Named or numeric entity,
+ */
+ public static final int ENTITY = 1004;
+
+ /**
+ * Sequence of valid name characters (can start from digit).
+ */
+ public static final int NUMTOKEN = 1005;
+
+ /* Complex tokens */
+
+ /**
+ * Comment opening sequence.
+ */
+ public static final pattern COMMENT_OPEN =
+ new pattern(new node[]
+ {
+ new node(BEGIN), new node(WS, true), new node(EXCLAMATION),
+ new node(WS, true), new node(DOUBLE_DASH),
+ }
+ );
+
+ /**
+ * Comment closing sequence
+ */
+ public static final pattern COMMENT_END =
+ new pattern(new node[]
+ {
+ new node(DOUBLE_DASH), new node(WS, true), new node(END)
+ }
+ );
+
+ /**
+ * Special case ---> (also is treated as end of comment).
+ */
+ public static final pattern COMMENT_TRIPLEDASH_END =
+ new pattern(new node[]
+ {
+ new node(DOUBLE_DASH), new node(NUMTOKEN), new node(END)
+ }
+ );
+
+ /**
+ * STYLE element heading pattern.
+ */
+ public static final pattern STYLE_OPEN =
+ new pattern(new node[] { new node(BEGIN), new node(WS, true), new node(STYLE) });
+
+ /**
+ * SCRIPT element heading pattern.
+ */
+ public static final pattern SCRIPT_OPEN =
+ new pattern(new node[] { new node(BEGIN), new node(WS, true), new node(SCRIPT) });
+
+ /**
+ * SGML element heading pattern.
+ */
+ public static final pattern SGML =
+ new pattern(new node[]
+ {
+ new node(BEGIN), new node(WS, true), new node(EXCLAMATION)
+ }
+ );
+
+ /**
+ * SCRIPT element closing pattern.
+ */
+ public static final pattern SCRIPT_CLOSE =
+ new pattern(new node[]
+ {
+ new node(BEGIN), new node(WS, true), new node(SLASH),
+ new node(WS, true), new node(SCRIPT), new node(WS, true),
+ new node(END)
+ }
+ );
+
+ /**
+ * STYLE element closing pattern.
+ */
+ public static final pattern STYLE_CLOSE =
+ new pattern(new node[]
+ {
+ new node(BEGIN), new node(WS, true), new node(SLASH),
+ new node(WS, true), new node(STYLE), new node(WS, true),
+ new node(END)
+ }
+ );
+
+ /**
+ * Ordinary HTML tag heading pattern.
+ */
+ public static final pattern TAG =
+ new pattern(new node[]
+ {
+ new node(BEGIN), new node(WS, true), new node(SLASH, true),
+ new node(WS, true), new node(NUMTOKEN)
+ }
+ );
+
+ /* Special tokens */
+
+ /**
+ * All other tokens.
+ */
+ public static final int OTHER = 1999;
+
+ /**
+ * The UNICODE "end of text" control code
+ */
+ static final char ETX = 3;
+
+ /**
+ * End of file.
+ */
+ public static final int EOF = ETX;
+
+ /* Character categories */
+
+ /**
+ * All single char tokens.
+ */
+ public static final BitSet bSINGLE_CHAR_TOKEN = new BitSet();
+
+ /**
+ * Non letters and non numbers, allowed in HTML names.
+ */
+ public static final BitSet bSPECIAL = new BitSet();
+
+ /**
+ * All letters, used in HTML names.
+ */
+ public static final BitSet bLETTER = new BitSet();
+
+ /**
+ * Digits.
+ */
+ public static final BitSet bDIGIT = new BitSet();
+
+ /**
+ * Both line breaks.
+ */
+ public static final BitSet bLINEBREAK = new BitSet();
+
+ /**
+ * All whitespace.
+ */
+ public static final BitSet bWHITESPACE = new BitSet();
+
+ /**
+ * Both quoting characters.
+ */
+ public static final BitSet bQUOTING = new BitSet();
+
+ /**
+ * Valid name characters.
+ */
+ public static final BitSet bNAME = new BitSet();
+
+ /* Entity subcategories */
+
+ /**
+ * Named entity.
+ */
+ public static final int ENTITY_NAMED = 1;
+
+ /**
+ * Numeric entity.
+ */
+ public static final int ENTITY_NUMERIC = 2;
+
+ static
+ {
+ bQUOTING.set(AP);
+ bQUOTING.set(QUOT);
+
+ bSINGLE_CHAR_TOKEN.set(BEGIN);
+ bSINGLE_CHAR_TOKEN.set(END);
+ bSINGLE_CHAR_TOKEN.set(EXCLAMATION);
+ bSINGLE_CHAR_TOKEN.set(SLASH);
+ bSINGLE_CHAR_TOKEN.set(EQ);
+ bSINGLE_CHAR_TOKEN.set(EOF);
+
+ bSINGLE_CHAR_TOKEN.or(bQUOTING);
+
+ bLINEBREAK.set('\r');
+ bLINEBREAK.set('\n');
+
+ bWHITESPACE.set(' ');
+ bWHITESPACE.set('\t');
+ bWHITESPACE.set(0xC);
+ bWHITESPACE.or(bLINEBREAK);
+
+ for (char i = '0'; i <= '9'; i++)
+ {
+ bDIGIT.set(i);
+ }
+
+ for (char i = 'a'; i <= 'z'; i++)
+ {
+ bLETTER.set(i);
+ }
+
+ for (char i = 'A'; i <= 'Z'; i++)
+ {
+ bLETTER.set(i);
+ }
+
+ bSPECIAL.set('-');
+ bSPECIAL.set('_');
+ bSPECIAL.set(':');
+ bSPECIAL.set('.');
+
+ bNAME.or(bLETTER);
+ bNAME.or(bDIGIT);
+ bNAME.or(bSPECIAL);
+ }
+
+ /**
+ * Verifies if one of the tokens matches the end of string
+ * buffer. The last character in the string buffer is the
+ * "future character", some tokens needs to verify it the
+ * token does not continue "towards the future". If the token
+ * matches, it matches till "pre-last" character in the buffer.
+ * @param b
+ * @return
+ */
+ public Token endMatches(Buffer b)
+ {
+ if (b.length() < 2)
+ return null;
+
+ int p = b.length() - 2;
+
+ if (b.length() > 2 && b.charAt(p) == '-' && b.charAt(p - 1) == '-')
+ return new Token(DOUBLE_DASH, "--", b.getLocation(p - 1, p + 1));
+
+ char last = b.charAt(p);
+
+ if (bSINGLE_CHAR_TOKEN.get(last))
+ return new Token(last, last, b.getLocation(p, p + 1));
+
+ char future = b.charAt(p + 1);
+
+ // Check for numtokens, script and style:
+ if (bNAME.get(last) && !bNAME.get(future))
+ {
+ // Scan the history up:
+ int u = p - 1;
+ while (u >= 0 && bNAME.get(b.charAt(u)))
+ u--;
+ u++;
+
+ char[] token = new char[ p - u + 1 ];
+
+ // Found a numtoken
+ b.getChars(u, p + 1, token, 0);
+
+ // Verify for the built-in tokens:
+ String e = new String(token);
+
+ // found the entity reference
+ if (u > 0 && b.charAt(u - 1) == '&')
+ {
+ // The subsequent semicolon may be the part of the token
+ // as well. The semicolon must be ignored. This must be
+ // handled elsewhere.
+ return new Token(ENTITY, ENTITY_NAMED, "&" + e,
+ b.getLocation(u - 1, p + 1)
+ );
+ }
+
+ // found the numeric entity reference
+ if (u > 1 && b.charAt(u - 1) == '#' && b.charAt(u - 2) == '&')
+ {
+ // The subsequent semicolon may be the part of the token
+ // as well. The semicolon must be ignored. This must be
+ // handled elsewhere.
+ return new Token(ENTITY, ENTITY_NUMERIC, "" + e,
+ b.getLocation(u - 2, p + 2)
+ );
+ }
+
+ Location le = b.getLocation(u, p + 1);
+
+ if (e.equalsIgnoreCase("SCRIPT"))
+ return new Token(SCRIPT, e, le);
+ else if (e.equalsIgnoreCase("STYLE"))
+ return new Token(STYLE, e, le);
+ else
+ return new Token(NUMTOKEN, e, le);
+ }
+
+ // Check for whitespace
+ if (bWHITESPACE.get(last) && !bWHITESPACE.get(future))
+ {
+ // Scan the history up:
+ int u = p - 1;
+ while (u >= 0 && bWHITESPACE.get(b.charAt(u)))
+ u--;
+ u++;
+
+ char[] token = new char[ p - u + 1 ];
+ b.getChars(u, p + 1, token, 0);
+
+ return new Token(WS, new String(token), b.getLocation(u, p + 1));
+ }
+
+ return null;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java
new file mode 100644
index 0000000..8a1cde1
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java
@@ -0,0 +1,83 @@
+/* Location.java --
+ Copyright (C) 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 gnu.javax.swing.text.html.parser.support.low;
+
+/**
+ * Defines a region in the text: its bounding positions and the line number.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class Location
+{
+ /**
+ * The line number, where the token starts.
+ */
+ public int beginLine;
+
+ /**
+ * The line, where the token ends.
+ */
+ public int endLine;
+
+ /**
+ * The absolute token end position in the input stream,
+ * exclusive.
+ */
+ public int endPosition;
+
+ /**
+ * The absolute token start position in the input stream,
+ * inclusive.
+ */
+ public int startPosition;
+
+ public Location()
+ {
+ }
+
+ /**
+ * Special case, used to mark EOF.
+ * @param p The total stream length.
+ */
+ public Location(int p)
+ {
+ startPosition = p;
+ endPosition = p + 1;
+ beginLine = endLine = -1;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java
new file mode 100644
index 0000000..e71c0c1
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java
@@ -0,0 +1,51 @@
+/* ParseException.java --
+ Copyright (C) 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 gnu.javax.swing.text.html.parser.support.low;
+
+/**
+ * This can be thrown from various parsing methods.
+ */
+public class ParseException
+ extends RuntimeException
+{
+ public ParseException(String s, Throwable cause)
+ {
+ super(s, cause);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java
new file mode 100644
index 0000000..31cf4bb
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java
@@ -0,0 +1,142 @@
+/* Queue.java -- a token queue.
+ Copyright (C) 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 gnu.javax.swing.text.html.parser.support.low;
+
+import java.util.Arrays;
+
+/**
+ * A token queue.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class Queue
+{
+ Token[] m = new Token[ 64 ];
+ int a = 0;
+ int b = 0;
+
+ /**
+ * True for the empty queue.
+ */
+ public boolean isEmpty()
+ {
+ return size() == 0;
+ }
+
+ /**
+ * Add this trace to the end of the queue.
+ */
+ public void add(Token u)
+ {
+ if (a < m.length)
+ {
+ m [ a ] = u;
+ a++;
+ }
+ else // The end of array has been reached.
+ {
+ if (b > 0) // If some elements were deleted from the start of the queue, shift.
+ {
+ int d = b;
+ System.arraycopy(m, b, m, 0, a - b);
+ b = b - d;
+ a = a - d;
+ m [ a ] = u;
+ a++;
+ }
+ else // Enlarge the queue, doubling the size.
+ {
+ int n = m.length * 2;
+ Token[] nm = new Token[ 2 * n ];
+ System.arraycopy(m, 0, nm, 0, m.length);
+ Arrays.fill(m, null);
+
+ nm [ a ] = u;
+ m = nm;
+ a++;
+ }
+ }
+ }
+
+ /**
+ * Clear the queue.
+ */
+ public void clear()
+ {
+ a = b = 0;
+ Arrays.fill(m, null);
+ }
+
+ /**
+ * Read the value ahead. 0 is the value that will be returned with
+ * the following next. This method does not remove values from the
+ * queue. To test if there is enough tokens in the queue, size() must
+ * be checked before calling this method.
+ */
+ public Token get(int ahead)
+ {
+ int p = b + ahead;
+ if (p < a)
+ return m [ p ];
+ else
+ throw new ArrayIndexOutOfBoundsException("Not enough tokens");
+ }
+
+ /**
+ * Read the oldest value from the queue and remove this value from
+ * the queue.
+ */
+ public Token next()
+ {
+ if (a == b)
+ throw new ArrayIndexOutOfBoundsException("queue empty");
+
+ Token r = m [ b ];
+ m [ b ] = null;
+ b++;
+ return r;
+ }
+
+ /**
+ * Size of the queue.
+ */
+ public int size()
+ {
+ return a - b;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java
new file mode 100644
index 0000000..0ffc6c8
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java
@@ -0,0 +1,374 @@
+/* ReaderTokenizer.java -- splits the input char sequence int tokens.
+ Copyright (C) 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 gnu.javax.swing.text.html.parser.support.low;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * Reader splits the input char sequence into tokens.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class ReaderTokenizer
+ extends Constants
+{
+ /**
+ * This is set to true each time the getNextToken is called.
+ * Used in preventing loops when all patterns refuse to accept
+ * the invalid input.
+ */
+ protected boolean advanced;
+
+ /**
+ * If true, the returned tokens are also placed in the backup
+ * queue.
+ */
+ protected boolean backupMode;
+
+ /**
+ * The buffer to read document into.
+ */
+ Buffer buffer = new Buffer();
+
+ /**
+ * The queue for supporting mark().
+ */
+ Queue backup = new Queue();
+
+ /**
+ * The queue of found tokens.
+ */
+ Queue queue = new Queue();
+
+ /**
+ * The reader to read the document from.
+ */
+ Reader reader;
+
+ /**
+ * Array of char tokens
+ */
+ char[] charTokens;
+
+ /**
+ * Array of string tokens.
+ */
+ String[] stringTokens;
+
+ /**
+ * The current reader position.
+ */
+ int readerPosition = -1;
+
+ /**
+ * Creates a new ReaderTokenizer. The reset(...) method must be
+ * subsequently called to set the reader.
+ */
+ public ReaderTokenizer()
+ {
+ }
+
+ /**
+ * Return the sequence, used to separate lines in the document.
+ * @return one of \n, \r or \r\n.
+ */
+ public String getEndOfLineSequence()
+ {
+ return buffer.getEndOfLineSequence();
+ }
+
+ /**
+ * Get the next token.
+ * @return
+ */
+ public Token getNextToken()
+ {
+ Token rt;
+ advanced = true;
+ try
+ {
+ if (queue.isEmpty())
+ read(1);
+
+ if (!queue.isEmpty())
+ rt = queue.next();
+ else
+ rt = new Token(EOF, new Location(readerPosition));
+ }
+ catch (IOException ex)
+ {
+ throw new ParseException("IO Exception", ex);
+ }
+ if (backupMode)
+ backup.add(rt);
+ return rt;
+ }
+
+ /**
+ * Get a token, lying the given number of tokens
+ * ahead. getToken(0) will return the same token,
+ * what would be returned by getNextToken().
+ * getToken(..) does change the current position
+ * in the input stream. If the end of stream is
+ * reached, the EOF token is always returned.
+ */
+ public Token getTokenAhead(int ahead)
+ {
+ try
+ {
+ read(ahead - queue.size() + 1);
+ return queue.size() >= ahead ? queue.get(ahead) : eofToken();
+ }
+ catch (IOException ex)
+ {
+ throw new ParseException("IO Exception", ex);
+ }
+ }
+
+ /**
+ * Get a token, bein immediatley ahead.
+ * If the end of stream is
+ * reached, the EOF token is always returned.
+ * The method is equivalent calling getTokenAhead(0).
+ */
+ public Token getTokenAhead()
+ {
+ try
+ {
+ if (queue.isEmpty())
+ read(1);
+ if (!queue.isEmpty())
+ return queue.get(0);
+ else
+ return eofToken();
+ }
+ catch (IOException ex)
+ {
+ throw new ParseException("IO Exception", ex);
+ }
+ }
+
+ /**
+ * Invokes the error handler.
+ */
+ public void error(String msg, Token at)
+ {
+ System.out.println(msg);
+ }
+
+ /**
+ * Turns the backup mode on or off.
+ * It is possible to return where the mark(true) was last called
+ * by calling reset().
+ * @param mode True if it is required to save tokens, making
+ * returning to the current point possible.
+ */
+ public void mark(boolean mode)
+ {
+ backup.clear();
+ backupMode = mode;
+ }
+
+ /**
+ * Prepare for new parsing from the given stream.
+ * @param a_reader A reader to parse from.
+ */
+ public void reset(Reader a_reader)
+ {
+ reader = a_reader;
+ readerPosition = -1;
+ buffer.reset();
+ queue.clear();
+ }
+
+ /**
+ * Reset the internal cursor to the position where the mark()
+ * was last time called. Switches the backup mode off.
+ */
+ public void reset()
+ {
+ if (!backupMode)
+ throw new AssertionError("Call mark(true) before using reset()!");
+ backupMode = false;
+
+ // That is now in the queue, will be appended to the end of backup.
+ while (!queue.isEmpty())
+ backup.add(queue.next());
+
+ Queue t = queue;
+ queue = backup;
+ backup = t;
+ backup.clear();
+ }
+
+ /**
+ * Read the given number of the tokens. Add the needed number of EOF
+ * tokens if there are no more data in the stream.
+ * @param amount The number of additional tokens to read.
+ */
+ void read(int numberOfTokens)
+ throws IOException
+ {
+ if (numberOfTokens <= 0)
+ return;
+
+ reading:
+ for (int i = 0; i < numberOfTokens; i++)
+ readToken();
+ }
+
+ /**
+ * Read next token from the reader, add it to the queue
+ */
+ void readToken()
+ throws IOException
+ {
+ Token t;
+ int ch;
+
+ enlarging:
+ while (true)
+ {
+ t = tokenMatches();
+ if (t != null)
+ break enlarging;
+ else
+ {
+ ch = reader.read();
+ readerPosition++;
+ if (ch == ETX)
+ ch = ' ';
+ if (ch < 0)
+ {
+ if (buffer.length() == 0)
+ {
+ queue.add(eofToken());
+ return;
+ }
+ else
+ {
+ if (buffer.charAt(buffer.length() - 1) != ETX)
+ buffer.append(ETX, readerPosition++);
+ else
+ {
+ // Discard terminating ETX
+ buffer.setLength(buffer.length() - 1);
+ if (buffer.length() > 0)
+ {
+ t = new Token(OTHER, buffer.toString(),
+ buffer.getLocation(0, buffer.length())
+ );
+ queue.add(t);
+ buffer.setLength(0);
+ }
+ return;
+ }
+ }
+ }
+ else
+ buffer.append((char) ch, readerPosition);
+ }
+ }
+ }
+
+ /**
+ * Check if the end of buffer matches one of the tokens. If it does,
+ * return this token and remove the token sequence from the end of
+ * buffer.
+ * @return The matching token.
+ */
+ Token tokenMatches()
+ {
+ Token rt = endMatches(buffer);
+ if (rt != null) // Remove the matched image
+ {
+ // Consume future character if it was an entity and the future
+ // character is semicolon.
+ if (rt.kind == ENTITY)
+ {
+ if (buffer.charAt(buffer.length() - 1) == ';')
+ buffer.setLength(buffer.length() - rt.getImage().length() - 1);
+ else
+ {
+ error("Missing closing semicolon for entity '" + rt.getImage() +
+ "'", rt
+ );
+ consumeBuffer(rt);
+ }
+ }
+ else
+ {
+ consumeBuffer(rt);
+ }
+ }
+
+ // If the buffer is not empty, some sequence does not match any tokens.
+ // Add it to the queue as "OTHER".
+ if (rt != null)
+ {
+ if (buffer.length() > 1)
+ {
+ String rest = buffer.toString();
+ rest = rest.substring(0, rest.length() - 1);
+
+ Token other =
+ new Token(OTHER, rest, buffer.getLocation(0, buffer.length));
+ queue.add(other);
+ consumeBuffer(other);
+ }
+ queue.add(rt);
+ }
+ return rt;
+ }
+
+ private void consumeBuffer(Token rt)
+ {
+ buffer.delete(buffer.length() - rt.getImage().length() - 1,
+ buffer.length() - 1
+ );
+ }
+
+ /**
+ * Create EOF token.
+ */
+ private Token eofToken()
+ {
+ return new Token(EOF, "#", new Location(readerPosition));
+ }
+}
diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java
new file mode 100644
index 0000000..d91adf4
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java
@@ -0,0 +1,169 @@
+/* Token.java --
+ Copyright (C) 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 gnu.javax.swing.text.html.parser.support.low;
+
+/**
+ * A token.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class Token
+{
+ /**
+ * The place of this token in the document.
+ */
+ public Location where;
+
+ /**
+ * The additional category of token.
+ */
+ public int category;
+
+ /**
+ * An integer that describes the kind of this token.
+ */
+ public int kind;
+
+ /**
+ * The string image of the token, null if the char image must be used.
+ */
+ private String stringImage;
+
+ /**
+ * The char image of the token.
+ */
+ private char charImage;
+
+ /**
+ * Creates a new token with fields, initialized to the default values.
+ */
+ public Token()
+ {
+ }
+
+ /**
+ * Creates a new token of the given kind.
+ */
+ public Token(int _kind, Location _where)
+ {
+ kind = _kind;
+ where = _where;
+ }
+
+ /**
+ * Creates a new token of the given kind and given single char image.
+ */
+ public Token(int _kind, char _image, Location _where)
+ {
+ kind = _kind;
+ charImage = _image;
+ where = _where;
+ }
+
+ /**
+ * Creates a new token of the given kind and given string image.
+ */
+ public Token(int _kind, String _image, Location _where)
+ {
+ kind = _kind;
+ stringImage = _image;
+ where = _where;
+ }
+
+ /**
+ * Creates a new token of the given kind, category and given string image.
+ */
+ public Token(int _kind, int _category, String _image, Location _where)
+ {
+ kind = _kind;
+ category = _category;
+ stringImage = _image;
+ where = _where;
+ }
+
+ /**
+ * Creates a new token, where location fields are set as for token,
+ * spanning over two provided tokens and any tokens between them.
+ * The image field is initialized to null, the kind field is set to -1.
+ */
+ public Token(Token fromInclusive, Token toInclusive)
+ {
+ where = new Location();
+ where.beginLine = fromInclusive.where.beginLine;
+ where.startPosition = fromInclusive.where.startPosition;
+
+ where.endLine = toInclusive.where.endLine;
+ where.endPosition = toInclusive.where.endPosition;
+ }
+
+ public String getImage()
+ {
+ if (kind == 3)
+ return "#";
+ if (stringImage == null)
+ {
+ if (charImage == 0)
+ return null;
+ stringImage = new String(new char[] { charImage });
+ }
+ return stringImage;
+ }
+
+ /**
+ * Append the token image to the given string buffer.
+ * This may be more effective that buffer.append(this.getImage()).
+ * @param buffer A buffer to append.
+ */
+ public void appendTo(StringBuffer buffer)
+ {
+ if (charImage == 0)
+ buffer.append(getImage());
+ else
+ buffer.append(charImage);
+ }
+
+ /**
+ * Returns the string image or, if null, the bounding positions.
+ */
+ public String toString()
+ {
+ return getImage() != null ? kind + "'" + getImage()
+ : "@author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */ +public class node +{ + /** + * True for node that is optional for the given position. + */ + public boolean optional; + + /** + * The kind of the token to match. + */ + public int kind; + + /** + * Creates the new node for matching a given kind of the token. + * @param kind The kind of the token to match. + * @param modifier The modifier (*?+). + */ + public node(int kind, boolean _optional) + { + this.kind = kind; + optional = _optional; + } + + /** + * Creates the node, indicating that token must match exactluy one time. + * @param kind The kind of token to match. + */ + public node(int kind) + { + this.kind = kind; + optional = false; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html new file mode 100644 index 0000000..1735830 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html @@ -0,0 +1,47 @@ + + + + +This package contains classes that are directly used to process +the text input: adapted stream tokenizer, specialized buffer and text-level content models .
+@author Audrius Meskauskas, Lithuania + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java new file mode 100644 index 0000000..0fe03fd --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java @@ -0,0 +1,105 @@ +/* pattern.java -- + Copyright (C) 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 gnu.javax.swing.text.html.parser.support.low; + + +/** + * The simple pattern, consisting from the sequence of tokens that + * may have the unary modifier '?'. Choices and grouping + * are not required here. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class pattern +{ + /** + * The nodes of this pattern. + */ + public final node[] nodes; + + /** + * Create a pattern, containing the given list of nodes. + * @param a_nodes + */ + public pattern(node[] a_nodes) + { + nodes = a_nodes; + } + + /** + * Checks if the pattern can match the tokens in this + * tokenizer. Does not change the state of tokenizer. + * @param stream The tokenizer to read data from + * @return True if the pattern sequence matches the + * beginning of the tokenizer content. + */ + public boolean matches(ReaderTokenizer stream) + { + try + { + int pt = 0; + int pn = 0; + Token t; + node n; + + while (pn < nodes.length) + { + n = nodes [ pn ]; + t = stream.getTokenAhead(pt); + + if (t.kind == n.kind) + { + pn++; + pt++; + } + else + { + if (!n.optional) + return false; + else + pn++; + } + } + return true; + } + catch (Exception ex) + { + throw new ParseException("Exception", ex); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html b/libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html new file mode 100644 index 0000000..97c6439 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html @@ -0,0 +1,47 @@ + + + + +This package provides various specialised classes, needed by HTML parser. +
+@author Audrius Meskauskas, Lithuania + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java new file mode 100644 index 0000000..654acbb --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java @@ -0,0 +1,106 @@ +/* parameterDefaulter.java -- + Copyright (C) 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 gnu.javax.swing.text.html.parser.support; + +import gnu.javax.swing.text.html.parser.htmlAttributeSet; + +import java.util.Hashtable; + +import javax.swing.text.html.parser.AttributeList; +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.Element; + +/** + * Returns an attribute set, containing default + * parameters for the given element. Caches sets of default + * parameters. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class parameterDefaulter +{ + public final DTD dtd; + Hashtable sets = new Hashtable(); + + /** + * Create a parameterDefaulter that looks for the default attribute + * values in the given DTD. + * @param a_dtd + */ + public parameterDefaulter(DTD a_dtd) + { + dtd = a_dtd; + } + + /** + * Get the default parameter set for the given element. + * @param element The element name (case insensitive). + * @return the default attrbute set. + */ + public htmlAttributeSet getDefaultParameters(String element) + { + String key = element.toLowerCase(); + htmlAttributeSet atts = (htmlAttributeSet) sets.get(key); + + if (atts == null) + { + htmlAttributeSet set = new htmlAttributeSet(); + Element e = (Element) dtd.elementHash.get(element.toLowerCase()); + + if (e != null) + { + AttributeList a = e.getAttributes(); + + while (a != null) + { + if (a.value != null) + set.addAttribute(a.name, a.value); + a = a.next; + } + } + + if (set.getAttributeCount() > 0) + sets.put(key, set); + else + sets.put(key, htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET); + + atts = set; + } + return atts; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java new file mode 100644 index 0000000..cc16105 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java @@ -0,0 +1,193 @@ +/* textPreProcessor.java -- + Copyright (C) 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 gnu.javax.swing.text.html.parser.support; + +import gnu.javax.swing.text.html.parser.support.low.Constants; + +/** + * Pre - processes text in text parts of the html document. + * Not thread - safe. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class textPreProcessor +{ + /** + * Pre - process non-preformatted text. + * \t, \r and \n mutate into spaces, then multiple spaces mutate + * into single one, all whitespace around tags is consumed. + * The content of the passed buffer is destroyed. + * @param text A text to pre-process. + */ + public char[] preprocess(StringBuffer a_text) + { + if (a_text.length() == 0) + return null; + + char[] text = toCharArray(a_text); + + int a = 0; + int b = text.length - 1; + + try + { + while (Constants.bWHITESPACE.get(text [ a ])) + a++; + while (Constants.bWHITESPACE.get(text [ b ])) + b--; + } + catch (ArrayIndexOutOfBoundsException sx) + { + // A text fragment, consisting from line breaks only. + return null; + } + + a_text.setLength(0); + + boolean spacesWere = false; + boolean spaceNow; + char c; + + chars: + for (int i = a; i <= b; i++) + { + c = text [ i ]; + spaceNow = Constants.bWHITESPACE.get(c); + if (spacesWere && spaceNow) + continue chars; + if (spaceNow) + a_text.append(' '); + else + a_text.append(c); + spacesWere = spaceNow; + } + + if (a_text.length() == text.length) + { + a_text.getChars(0, a_text.length(), text, 0); + return text; + } + else + return toCharArray(a_text); + } + + /** + * Pre - process pre-formatted text. + * Heading/closing spaces and tabs preserved. + * ONE bounding \r, \n or \r\n is removed. + * \r or \r\n mutate into \n. Tabs are + * preserved. + * The content of the passed buffer is destroyed. + * @param text + * @return + */ + public char[] preprocessPreformatted(StringBuffer a_text) + { + if (a_text.length() == 0) + return null; + + char[] text = toCharArray(a_text); + + int a = 0; + int n = text.length - 1; + int b = n; + + if (text [ 0 ] == '\n') + a++; + else + { + if (text [ 0 ] == '\r') + { + a++; + if (text.length > 1 && text [ 1 ] == '\n') + a++; + } + } + + if (text [ n ] == '\r') + b--; + else + { + if (text [ n ] == '\n') + { + b--; + if (n > 0 && text [ n - 1 ] == '\r') + b--; + } + } + + a_text.setLength(0); + + if (a > b) + return null; + + char c; + + for (int i = a; i <= b; i++) + { + c = text [ i ]; + if (c == '\r') + { + if (i == b || text [ i + 1 ] != '\n') + a_text.append('\n'); + } + else + a_text.append(c); + } + + if (a_text.length() == text.length) + { + a_text.getChars(0, a_text.length(), text, 0); + return text; + } + else + return toCharArray(a_text); + } + + /** + * Return array of chars, present in the given buffer. + * @param a_text The buffer + * @return + */ + private static char[] toCharArray(StringBuffer a_text) + { + char[] text = new char[ a_text.length() ]; + a_text.getChars(0, text.length, text, 0); + return text; + } +} diff --git a/libjava/classpath/gnu/regexp/CharIndexed.java b/libjava/classpath/gnu/regexp/CharIndexed.java new file mode 100644 index 0000000..a0d7106 --- /dev/null +++ b/libjava/classpath/gnu/regexp/CharIndexed.java @@ -0,0 +1,84 @@ +/* gnu/regexp/CharIndexed.java + Copyright (C) 1998-2001, 2004 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 gnu.regexp; + +/** + * Defines the interface used internally so that different types of source + * text can be accessed in the same way. Built-in concrete classes provide + * support for String, StringBuffer, InputStream and char[] types. + * A class that is CharIndexed supports the notion of a cursor within a + * block of text. The cursor must be able to be advanced via the move() + * method. The charAt() method returns the character at the cursor position + * plus a given offset. + * + * @author Wes Biggs + */ +public interface CharIndexed { + /** + * Defines a constant (0xFFFF was somewhat arbitrarily chosen) + * that can be returned by the charAt() function indicating that + * the specified index is out of range. + */ + char OUT_OF_BOUNDS = '\uFFFF'; + + /** + * Returns the character at the given offset past the current cursor + * position in the input. The index of the current position is zero. + * It is possible for this method to be called with a negative index. + * This happens when using the '^' operator in multiline matching mode + * or the '\b' or '\<' word boundary operators. In any case, the lower + * bound is currently fixed at -2 (for '^' with a two-character newline). + * + * @param index the offset position in the character field to examine + * @return the character at the specified index, or the OUT_OF_BOUNDS + * character defined by this interface. + */ + char charAt(int index); + + /** + * Shifts the input buffer by a given number of positions. Returns + * true if the new cursor position is valid. + */ + boolean move(int index); + + /** + * Returns true if the most recent move() operation placed the cursor + * position at a valid position in the input. + */ + boolean isValid(); +} diff --git a/libjava/classpath/gnu/regexp/CharIndexedCharArray.java b/libjava/classpath/gnu/regexp/CharIndexedCharArray.java new file mode 100644 index 0000000..63d858c --- /dev/null +++ b/libjava/classpath/gnu/regexp/CharIndexedCharArray.java @@ -0,0 +1,62 @@ +/* gnu/regexp/CharIndexedCharArray.java + Copyright (C) 1998-2001, 2004 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 gnu.regexp; +import java.io.Serializable; + +class CharIndexedCharArray implements CharIndexed, Serializable { + private char[] s; + private int anchor; + + CharIndexedCharArray(char[] str, int index) { + s = str; + anchor = index; + } + + public char charAt(int index) { + int pos = anchor + index; + return ((pos < s.length) && (pos >= 0)) ? s[pos] : OUT_OF_BOUNDS; + } + + public boolean isValid() { + return (anchor < s.length); + } + + public boolean move(int index) { + return ((anchor += index) < s.length); + } +} diff --git a/libjava/classpath/gnu/regexp/CharIndexedInputStream.java b/libjava/classpath/gnu/regexp/CharIndexedInputStream.java new file mode 100644 index 0000000..145fe11 --- /dev/null +++ b/libjava/classpath/gnu/regexp/CharIndexedInputStream.java @@ -0,0 +1,149 @@ +/* gnu/regexp/CharIndexedInputStream.java + Copyright (C) 1998-2001, 2004 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 gnu.regexp; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + +// TODO: move(x) shouldn't rely on calling next() x times + +class CharIndexedInputStream implements CharIndexed { + private static final int BUFFER_INCREMENT = 1024; + private static final int UNKNOWN = Integer.MAX_VALUE; // value for end + + private BufferedInputStream br; + + // so that we don't try to reset() right away + private int index = -1; + + private int bufsize = BUFFER_INCREMENT; + + private int end = UNKNOWN; + + private char cached = OUT_OF_BOUNDS; + + // Big enough for a \r\n pair + // lookBehind[0] = most recent + // lookBehind[1] = second most recent + private char[] lookBehind = new char[] { OUT_OF_BOUNDS, OUT_OF_BOUNDS }; + + CharIndexedInputStream(InputStream str, int index) { + if (str instanceof BufferedInputStream) br = (BufferedInputStream) str; + else br = new BufferedInputStream(str,BUFFER_INCREMENT); + next(); + if (index > 0) move(index); + } + + private boolean next() { + if (end == 1) return false; + end--; // closer to end + + try { + if (index != -1) { + br.reset(); + } + int i = br.read(); + br.mark(bufsize); + if (i == -1) { + end = 1; + cached = OUT_OF_BOUNDS; + return false; + } + cached = (char) i; + index = 1; + } catch (IOException e) { + e.printStackTrace(); + cached = OUT_OF_BOUNDS; + return false; + } + return true; + } + + public char charAt(int index) { + if (index == 0) { + return cached; + } else if (index >= end) { + return OUT_OF_BOUNDS; + } else if (index == -1) { + return lookBehind[0]; + } else if (index == -2) { + return lookBehind[1]; + } else if (index < -2) { + return OUT_OF_BOUNDS; + } else if (index >= bufsize) { + // Allocate more space in the buffer. + try { + while (bufsize <= index) bufsize += BUFFER_INCREMENT; + br.reset(); + br.mark(bufsize); + br.skip(index-1); + } catch (IOException e) { } + } else if (this.index != index) { + try { + br.reset(); + br.skip(index-1); + } catch (IOException e) { } + } + char ch = OUT_OF_BOUNDS; + + try { + int i = br.read(); + this.index = index+1; // this.index is index of next pos relative to charAt(0) + if (i == -1) { + // set flag that next should fail next time? + end = index; + return ch; + } + ch = (char) i; + } catch (IOException ie) { } + + return ch; + } + + public boolean move(int index) { + // move read position [index] clicks from 'charAt(0)' + boolean retval = true; + while (retval && (index-- > 0)) retval = next(); + return retval; + } + + public boolean isValid() { + return (cached != OUT_OF_BOUNDS); + } +} + diff --git a/libjava/classpath/gnu/regexp/CharIndexedString.java b/libjava/classpath/gnu/regexp/CharIndexedString.java new file mode 100644 index 0000000..05be07a --- /dev/null +++ b/libjava/classpath/gnu/regexp/CharIndexedString.java @@ -0,0 +1,64 @@ +/* gnu/regexp/CharIndexedString.java + Copyright (C) 1998-2001, 2004 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 gnu.regexp; +import java.io.Serializable; + +class CharIndexedString implements CharIndexed, Serializable { + private String s; + private int anchor; + private int len; + + CharIndexedString(String str, int index) { + s = str; + len = s.length(); + anchor = index; + } + + public char charAt(int index) { + int pos = anchor + index; + return ((pos < len) && (pos >= 0)) ? s.charAt(pos) : OUT_OF_BOUNDS; + } + + public boolean isValid() { + return (anchor < len); + } + + public boolean move(int index) { + return ((anchor += index) < len); + } +} diff --git a/libjava/classpath/gnu/regexp/CharIndexedStringBuffer.java b/libjava/classpath/gnu/regexp/CharIndexedStringBuffer.java new file mode 100644 index 0000000..1b88e39 --- /dev/null +++ b/libjava/classpath/gnu/regexp/CharIndexedStringBuffer.java @@ -0,0 +1,62 @@ +/* gnu/regexp/CharIndexedStringBuffer.java + Copyright (C) 1998-2001, 2004 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 gnu.regexp; +import java.io.Serializable; + +class CharIndexedStringBuffer implements CharIndexed, Serializable { + private StringBuffer s; + private int anchor; + + CharIndexedStringBuffer(StringBuffer str, int index) { + s = str; + anchor = index; + } + + public char charAt(int index) { + int pos = anchor + index; + return ((pos < s.length()) && (pos >= 0)) ? s.charAt(pos) : OUT_OF_BOUNDS; + } + + public boolean isValid() { + return (anchor < s.length()); + } + + public boolean move(int index) { + return ((anchor += index) < s.length()); + } +} diff --git a/libjava/classpath/gnu/regexp/RE.java b/libjava/classpath/gnu/regexp/RE.java new file mode 100644 index 0000000..16427c7 --- /dev/null +++ b/libjava/classpath/gnu/regexp/RE.java @@ -0,0 +1,1396 @@ +/* gnu/regexp/RE.java + Copyright (C) 1998-2001, 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 gnu.regexp; +import java.io.InputStream; +import java.io.Serializable; +import java.util.Locale; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; +import java.util.Vector; + +/** + * RE provides the user interface for compiling and matching regular + * expressions. + *
+ * A regular expression object (class RE) is compiled by constructing it
+ * from a String, StringBuffer or character array, with optional
+ * compilation flags (below)
+ * and an optional syntax specification (see RESyntax; if not specified,
+ * RESyntax.RE_SYNTAX_PERL5
is used).
+ *
+ * Once compiled, a regular expression object is reusable as well as + * threadsafe: multiple threads can use the RE instance simultaneously + * to match against different input text. + *
+ * Various methods attempt to match input text against a compiled + * regular expression. These methods are: + *
isMatch
: returns true if the input text in its
+ * entirety matches the regular expression pattern.
+ * getMatch
: returns the first match found in the
+ * input text, or null if no match is found.
+ * getAllMatches
: returns an array of all
+ * non-overlapping matches found in the input text. If no matches are
+ * found, the array is zero-length.
+ * substitute
: substitute the first occurence of the
+ * pattern in the input text with a replacement string (which may
+ * include metacharacters $0-$9, see REMatch.substituteInto).
+ * substituteAll
: same as above, but repeat for each
+ * match before returning.
+ * getMatchEnumeration
: returns an REMatchEnumeration
+ * object that allows iteration over the matches (see
+ * REMatchEnumeration for some reasons why you may want to do this
+ * instead of using getAllMatches
.
+ * + * + * These methods all have similar argument lists. The input can be a + * String, a character array, a StringBuffer, or an + * InputStream of some sort. Note that when using an + * InputStream, the stream read position cannot be guaranteed after + * attempting a match (this is not a bug, but a consequence of the way + * regular expressions work). Using an REMatchEnumeration can + * eliminate most positioning problems. + * + *
+ * + * The optional index argument specifies the offset from the beginning + * of the text at which the search should start (see the descriptions + * of some of the execution flags for how this can affect positional + * pattern operators). For an InputStream, this means an + * offset from the current read position, so subsequent calls with the + * same index argument on an InputStream will not + * necessarily access the same position on the stream, whereas + * repeated searches at a given index in a fixed string will return + * consistent results. + * + *
+ * You can optionally affect the execution environment by using a + * combination of execution flags (constants listed below). + * + *
+ * All operations on a regular expression are performed in a + * thread-safe manner. + * + * @author Wes Biggs + * @version 1.1.5-dev, to be released + */ + +public class RE extends REToken { + + private static final class IntPair implements Serializable { + public int first, second; + } + + private static final class CharUnit implements Serializable { + public char ch; + public boolean bk; + } + + // This String will be returned by getVersion() + private static final String VERSION = "1.1.5-dev"; + + // The localized strings are kept in a separate file + private static ResourceBundle messages = PropertyResourceBundle.getBundle("gnu/regexp/MessagesBundle", Locale.getDefault()); + + // These are, respectively, the first and last tokens in our linked list + // If there is only one token, firstToken == lastToken + private REToken firstToken, lastToken; + + // This is the number of subexpressions in this regular expression, + // with a minimum value of zero. Returned by getNumSubs() + private int numSubs; + + /** Minimum length, in characters, of any possible match. */ + private int minimumLength; + + /** + * Compilation flag. Do not differentiate case. Subsequent + * searches using this RE will be case insensitive. + */ + public static final int REG_ICASE = 2; + + /** + * Compilation flag. The match-any-character operator (dot) + * will match a newline character. When set this overrides the syntax + * bit RE_DOT_NEWLINE (see RESyntax for details). This is equivalent to + * the "/s" operator in Perl. + */ + public static final int REG_DOT_NEWLINE = 4; + + /** + * Compilation flag. Use multiline mode. In this mode, the ^ and $ + * anchors will match based on newlines within the input. This is + * equivalent to the "/m" operator in Perl. + */ + public static final int REG_MULTILINE = 8; + + /** + * Execution flag. + * The match-beginning operator (^) will not match at the beginning + * of the input string. Useful for matching on a substring when you + * know the context of the input is such that position zero of the + * input to the match test is not actually position zero of the text. + *
+ * This example demonstrates the results of various ways of matching on + * a substring. + *
+ *
+ * // Results:
+ * String s = "food bar fool";
+ */
+ public static final int REG_NOTBOL = 16;
+
+ /**
+ * Execution flag.
+ * The match-end operator ($) does not match at the end
+ * of the input string. Useful for matching on substrings.
+ */
+ public static final int REG_NOTEOL = 32;
+
+ /**
+ * Execution flag.
+ * When a match method is invoked that starts matching at a non-zero
+ * index into the input, treat the input as if it begins at the index
+ * given. The effect of this flag is that the engine does not "see"
+ * any text in the input before the given index. This is useful so
+ * that the match-beginning operator (^) matches not at position 0
+ * in the input string, but at the position the search started at
+ * (based on the index input given to the getMatch function). See
+ * the example under REG_NOTBOL. It also affects the use of the \<
+ * and \b operators.
+ */
+ public static final int REG_ANCHORINDEX = 64;
+
+ /**
+ * Execution flag.
+ * The substitute and substituteAll methods will not attempt to
+ * interpolate occurrences of $1-$9 in the replacement text with
+ * the corresponding subexpressions. For example, you may want to
+ * replace all matches of "one dollar" with "$1".
+ */
+ public static final int REG_NO_INTERPOLATE = 128;
+
+ /** Returns a string representing the version of the gnu.regexp package. */
+ public static final String version() {
+ return VERSION;
+ }
+
+ // Retrieves a message from the ResourceBundle
+ static final String getLocalizedMessage(String key) {
+ return messages.getString(key);
+ }
+
+ /**
+ * Constructs a regular expression pattern buffer without any compilation
+ * flags set, and using the default syntax (RESyntax.RE_SYNTAX_PERL5).
+ *
+ * @param pattern A regular expression pattern, in the form of a String,
+ * StringBuffer or char[]. Other input types will be converted to
+ * strings using the toString() method.
+ * @exception REException The input pattern could not be parsed.
+ * @exception NullPointerException The pattern was null.
+ */
+ public RE(Object pattern) throws REException {
+ this(pattern,0,RESyntax.RE_SYNTAX_PERL5,0,0);
+ }
+
+ /**
+ * Constructs a regular expression pattern buffer using the specified
+ * compilation flags and the default syntax (RESyntax.RE_SYNTAX_PERL5).
+ *
+ * @param pattern A regular expression pattern, in the form of a String,
+ * StringBuffer, or char[]. Other input types will be converted to
+ * strings using the toString() method.
+ * @param cflags The logical OR of any combination of the compilation flags listed above.
+ * @exception REException The input pattern could not be parsed.
+ * @exception NullPointerException The pattern was null.
+ */
+ public RE(Object pattern, int cflags) throws REException {
+ this(pattern,cflags,RESyntax.RE_SYNTAX_PERL5,0,0);
+ }
+
+ /**
+ * Constructs a regular expression pattern buffer using the specified
+ * compilation flags and regular expression syntax.
+ *
+ * @param pattern A regular expression pattern, in the form of a String,
+ * StringBuffer, or char[]. Other input types will be converted to
+ * strings using the toString() method.
+ * @param cflags The logical OR of any combination of the compilation flags listed above.
+ * @param syntax The type of regular expression syntax to use.
+ * @exception REException The input pattern could not be parsed.
+ * @exception NullPointerException The pattern was null.
+ */
+ public RE(Object pattern, int cflags, RESyntax syntax) throws REException {
+ this(pattern,cflags,syntax,0,0);
+ }
+
+ // internal constructor used for alternation
+ private RE(REToken first, REToken last,int subs, int subIndex, int minLength) {
+ super(subIndex);
+ firstToken = first;
+ lastToken = last;
+ numSubs = subs;
+ minimumLength = minLength;
+ addToken(new RETokenEndSub(subIndex));
+ }
+
+ private RE(Object patternObj, int cflags, RESyntax syntax, int myIndex, int nextSub) throws REException {
+ super(myIndex); // Subexpression index of this token.
+ initialize(patternObj, cflags, syntax, myIndex, nextSub);
+ }
+
+ // For use by subclasses
+ protected RE() { super(0); }
+
+ // The meat of construction
+ protected void initialize(Object patternObj, int cflags, RESyntax syntax, int myIndex, int nextSub) throws REException {
+ char[] pattern;
+ if (patternObj instanceof String) {
+ pattern = ((String) patternObj).toCharArray();
+ } else if (patternObj instanceof char[]) {
+ pattern = (char[]) patternObj;
+ } else if (patternObj instanceof StringBuffer) {
+ pattern = new char [((StringBuffer) patternObj).length()];
+ ((StringBuffer) patternObj).getChars(0,pattern.length,pattern,0);
+ } else {
+ pattern = patternObj.toString().toCharArray();
+ }
+
+ int pLength = pattern.length;
+
+ numSubs = 0; // Number of subexpressions in this token.
+ Vector branches = null;
+
+ // linked list of tokens (sort of -- some closed loops can exist)
+ firstToken = lastToken = null;
+
+ // Precalculate these so we don't pay for the math every time we
+ // need to access them.
+ boolean insens = ((cflags & REG_ICASE) > 0);
+
+ // Parse pattern into tokens. Does anyone know if it's more efficient
+ // to use char[] than a String.charAt()? I'm assuming so.
+
+ // index tracks the position in the char array
+ int index = 0;
+
+ // this will be the current parse character (pattern[index])
+ CharUnit unit = new CharUnit();
+
+ // This is used for {x,y} calculations
+ IntPair minMax = new IntPair();
+
+ // Buffer a token so we can create a TokenRepeated, etc.
+ REToken currentToken = null;
+ char ch;
+ boolean quot = false;
+
+ while (index < pLength) {
+ // read the next character unit (including backslash escapes)
+ index = getCharUnit(pattern,index,unit,quot);
+
+ if (unit.bk)
+ if (unit.ch == 'Q') {
+ quot = true;
+ continue;
+ } else if (unit.ch == 'E') {
+ quot = false;
+ continue;
+ }
+ if (quot)
+ unit.bk = false;
+
+ // ALTERNATION OPERATOR
+ // \| or | (if RE_NO_BK_VBAR) or newline (if RE_NEWLINE_ALT)
+ // not available if RE_LIMITED_OPS is set
+
+ // TODO: the '\n' literal here should be a test against REToken.newline,
+ // which unfortunately may be more than a single character.
+ if ( ( (unit.ch == '|' && (syntax.get(RESyntax.RE_NO_BK_VBAR) ^ (unit.bk || quot)))
+ || (syntax.get(RESyntax.RE_NEWLINE_ALT) && (unit.ch == '\n') && !(unit.bk || quot)) )
+ && !syntax.get(RESyntax.RE_LIMITED_OPS)) {
+ // make everything up to here be a branch. create vector if nec.
+ addToken(currentToken);
+ RE theBranch = new RE(firstToken, lastToken, numSubs, subIndex, minimumLength);
+ minimumLength = 0;
+ if (branches == null) {
+ branches = new Vector();
+ }
+ branches.addElement(theBranch);
+ firstToken = lastToken = currentToken = null;
+ }
+
+ // INTERVAL OPERATOR:
+ // {x} | {x,} | {x,y} (RE_INTERVALS && RE_NO_BK_BRACES)
+ // \{x\} | \{x,\} | \{x,y\} (RE_INTERVALS && !RE_NO_BK_BRACES)
+ //
+ // OPEN QUESTION:
+ // what is proper interpretation of '{' at start of string?
+
+ else if ((unit.ch == '{') && syntax.get(RESyntax.RE_INTERVALS) && (syntax.get(RESyntax.RE_NO_BK_BRACES) ^ (unit.bk || quot))) {
+ int newIndex = getMinMax(pattern,index,minMax,syntax);
+ if (newIndex > index) {
+ if (minMax.first > minMax.second)
+ throw new REException(getLocalizedMessage("interval.order"),REException.REG_BADRPT,newIndex);
+ if (currentToken == null)
+ throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,newIndex);
+ if (currentToken instanceof RETokenRepeated)
+ throw new REException(getLocalizedMessage("repeat.chained"),REException.REG_BADRPT,newIndex);
+ if (currentToken instanceof RETokenWordBoundary || currentToken instanceof RETokenWordBoundary)
+ throw new REException(getLocalizedMessage("repeat.assertion"),REException.REG_BADRPT,newIndex);
+ if ((currentToken.getMinimumLength() == 0) && (minMax.second == Integer.MAX_VALUE))
+ throw new REException(getLocalizedMessage("repeat.empty.token"),REException.REG_BADRPT,newIndex);
+ index = newIndex;
+ currentToken = setRepeated(currentToken,minMax.first,minMax.second,index);
+ }
+ else {
+ addToken(currentToken);
+ currentToken = new RETokenChar(subIndex,unit.ch,insens);
+ }
+ }
+
+ // LIST OPERATOR:
+ // [...] | [^...]
+
+ else if ((unit.ch == '[') && !(unit.bk || quot)) {
+ Vector options = new Vector();
+ boolean negative = false;
+ char lastChar = 0;
+ if (index == pLength) throw new REException(getLocalizedMessage("unmatched.bracket"),REException.REG_EBRACK,index);
+
+ // Check for initial caret, negation
+ if ((ch = pattern[index]) == '^') {
+ negative = true;
+ if (++index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index);
+ ch = pattern[index];
+ }
+
+ // Check for leading right bracket literal
+ if (ch == ']') {
+ lastChar = ch;
+ if (++index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index);
+ }
+
+ while ((ch = pattern[index++]) != ']') {
+ if ((ch == '-') && (lastChar != 0)) {
+ if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index);
+ if ((ch = pattern[index]) == ']') {
+ options.addElement(new RETokenChar(subIndex,lastChar,insens));
+ lastChar = '-';
+ } else {
+ options.addElement(new RETokenRange(subIndex,lastChar,ch,insens));
+ lastChar = 0;
+ index++;
+ }
+ } else if ((ch == '\\') && syntax.get(RESyntax.RE_BACKSLASH_ESCAPE_IN_LISTS)) {
+ if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index);
+ int posixID = -1;
+ boolean negate = false;
+ char asciiEsc = 0;
+ if (("dswDSW".indexOf(pattern[index]) != -1) && syntax.get(RESyntax.RE_CHAR_CLASS_ESC_IN_LISTS)) {
+ switch (pattern[index]) {
+ case 'D':
+ negate = true;
+ case 'd':
+ posixID = RETokenPOSIX.DIGIT;
+ break;
+ case 'S':
+ negate = true;
+ case 's':
+ posixID = RETokenPOSIX.SPACE;
+ break;
+ case 'W':
+ negate = true;
+ case 'w':
+ posixID = RETokenPOSIX.ALNUM;
+ break;
+ }
+ }
+ else if ("nrt".indexOf(pattern[index]) != -1) {
+ switch (pattern[index]) {
+ case 'n':
+ asciiEsc = '\n';
+ break;
+ case 't':
+ asciiEsc = '\t';
+ break;
+ case 'r':
+ asciiEsc = '\r';
+ break;
+ }
+ }
+ if (lastChar != 0) options.addElement(new RETokenChar(subIndex,lastChar,insens));
+
+ if (posixID != -1) {
+ options.addElement(new RETokenPOSIX(subIndex,posixID,insens,negate));
+ } else if (asciiEsc != 0) {
+ lastChar = asciiEsc;
+ } else {
+ lastChar = pattern[index];
+ }
+ ++index;
+ } else if ((ch == '[') && (syntax.get(RESyntax.RE_CHAR_CLASSES)) && (index < pLength) && (pattern[index] == ':')) {
+ StringBuffer posixSet = new StringBuffer();
+ index = getPosixSet(pattern,index+1,posixSet);
+ int posixId = RETokenPOSIX.intValue(posixSet.toString());
+ if (posixId != -1)
+ options.addElement(new RETokenPOSIX(subIndex,posixId,insens,false));
+ } else {
+ if (lastChar != 0) options.addElement(new RETokenChar(subIndex,lastChar,insens));
+ lastChar = ch;
+ }
+ if (index == pLength) throw new REException(getLocalizedMessage("class.no.end"),REException.REG_EBRACK,index);
+ } // while in list
+ // Out of list, index is one past ']'
+
+ if (lastChar != 0) options.addElement(new RETokenChar(subIndex,lastChar,insens));
+
+ // Create a new RETokenOneOf
+ addToken(currentToken);
+ options.trimToSize();
+ currentToken = new RETokenOneOf(subIndex,options,negative);
+ }
+
+ // SUBEXPRESSIONS
+ // (...) | \(...\) depending on RE_NO_BK_PARENS
+
+ else if ((unit.ch == '(') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot))) {
+ boolean pure = false;
+ boolean comment = false;
+ boolean lookAhead = false;
+ boolean negativelh = false;
+ if ((index+1 < pLength) && (pattern[index] == '?')) {
+ switch (pattern[index+1]) {
+ case '!':
+ if (syntax.get(RESyntax.RE_LOOKAHEAD)) {
+ pure = true;
+ negativelh = true;
+ lookAhead = true;
+ index += 2;
+ }
+ break;
+ case '=':
+ if (syntax.get(RESyntax.RE_LOOKAHEAD)) {
+ pure = true;
+ lookAhead = true;
+ index += 2;
+ }
+ break;
+ case ':':
+ if (syntax.get(RESyntax.RE_PURE_GROUPING)) {
+ pure = true;
+ index += 2;
+ }
+ break;
+ case '#':
+ if (syntax.get(RESyntax.RE_COMMENTS)) {
+ comment = true;
+ }
+ break;
+ default:
+ throw new REException(getLocalizedMessage("repeat.no.token"), REException.REG_BADRPT, index);
+ }
+ }
+
+ if (index >= pLength) {
+ throw new REException(getLocalizedMessage("unmatched.paren"), REException.REG_ESUBREG,index);
+ }
+
+ // find end of subexpression
+ int endIndex = index;
+ int nextIndex = index;
+ int nested = 0;
+
+ while ( ((nextIndex = getCharUnit(pattern,endIndex,unit,false)) > 0)
+ && !(nested == 0 && (unit.ch == ')') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot))) )
+ if ((endIndex = nextIndex) >= pLength)
+ throw new REException(getLocalizedMessage("subexpr.no.end"),REException.REG_ESUBREG,nextIndex);
+ else if (unit.ch == '(' && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot)))
+ nested++;
+ else if (unit.ch == ')' && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot)))
+ nested--;
+
+ // endIndex is now position at a ')','\)'
+ // nextIndex is end of string or position after ')' or '\)'
+
+ if (comment) index = nextIndex;
+ else { // not a comment
+ // create RE subexpression as token.
+ addToken(currentToken);
+ if (!pure) {
+ numSubs++;
+ }
+
+ int useIndex = (pure || lookAhead) ? 0 : nextSub + numSubs;
+ currentToken = new RE(String.valueOf(pattern,index,endIndex-index).toCharArray(),cflags,syntax,useIndex,nextSub + numSubs);
+ numSubs += ((RE) currentToken).getNumSubs();
+
+ if (lookAhead) {
+ currentToken = new RETokenLookAhead(currentToken,negativelh);
+ }
+
+ index = nextIndex;
+ } // not a comment
+ } // subexpression
+
+ // UNMATCHED RIGHT PAREN
+ // ) or \) throw exception if
+ // !syntax.get(RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD)
+ else if (!syntax.get(RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD) && ((unit.ch == ')') && (syntax.get(RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot)))) {
+ throw new REException(getLocalizedMessage("unmatched.paren"),REException.REG_EPAREN,index);
+ }
+
+ // START OF LINE OPERATOR
+ // ^
+
+ else if ((unit.ch == '^') && !(unit.bk || quot)) {
+ addToken(currentToken);
+ currentToken = null;
+ addToken(new RETokenStart(subIndex,((cflags & REG_MULTILINE) > 0) ? syntax.getLineSeparator() : null));
+ }
+
+ // END OF LINE OPERATOR
+ // $
+
+ else if ((unit.ch == '$') && !(unit.bk || quot)) {
+ addToken(currentToken);
+ currentToken = null;
+ addToken(new RETokenEnd(subIndex,((cflags & REG_MULTILINE) > 0) ? syntax.getLineSeparator() : null));
+ }
+
+ // MATCH-ANY-CHARACTER OPERATOR (except possibly newline and null)
+ // .
+
+ else if ((unit.ch == '.') && !(unit.bk || quot)) {
+ addToken(currentToken);
+ currentToken = new RETokenAny(subIndex,syntax.get(RESyntax.RE_DOT_NEWLINE) || ((cflags & REG_DOT_NEWLINE) > 0),syntax.get(RESyntax.RE_DOT_NOT_NULL));
+ }
+
+ // ZERO-OR-MORE REPEAT OPERATOR
+ // *
+
+ else if ((unit.ch == '*') && !(unit.bk || quot)) {
+ if (currentToken == null)
+ throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index);
+ if (currentToken instanceof RETokenRepeated)
+ throw new REException(getLocalizedMessage("repeat.chained"),REException.REG_BADRPT,index);
+ if (currentToken instanceof RETokenWordBoundary || currentToken instanceof RETokenWordBoundary)
+ throw new REException(getLocalizedMessage("repeat.assertion"),REException.REG_BADRPT,index);
+ if (currentToken.getMinimumLength() == 0)
+ throw new REException(getLocalizedMessage("repeat.empty.token"),REException.REG_BADRPT,index);
+ currentToken = setRepeated(currentToken,0,Integer.MAX_VALUE,index);
+ }
+
+ // ONE-OR-MORE REPEAT OPERATOR / POSSESSIVE MATCHING OPERATOR
+ // + | \+ depending on RE_BK_PLUS_QM
+ // not available if RE_LIMITED_OPS is set
+
+ else if ((unit.ch == '+') && !syntax.get(RESyntax.RE_LIMITED_OPS) && (!syntax.get(RESyntax.RE_BK_PLUS_QM) ^ (unit.bk || quot))) {
+ if (currentToken == null)
+ throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index);
+
+ // Check for possessive matching on RETokenRepeated
+ if (currentToken instanceof RETokenRepeated) {
+ RETokenRepeated tokenRep = (RETokenRepeated)currentToken;
+ if (syntax.get(RESyntax.RE_POSSESSIVE_OPS) && !tokenRep.isPossessive() && !tokenRep.isStingy())
+ tokenRep.makePossessive();
+ else
+ throw new REException(getLocalizedMessage("repeat.chained"),REException.REG_BADRPT,index);
+
+ }
+ else if (currentToken instanceof RETokenWordBoundary || currentToken instanceof RETokenWordBoundary)
+ throw new REException(getLocalizedMessage("repeat.assertion"),REException.REG_BADRPT,index);
+ else if (currentToken.getMinimumLength() == 0)
+ throw new REException(getLocalizedMessage("repeat.empty.token"),REException.REG_BADRPT,index);
+ else
+ currentToken = setRepeated(currentToken,1,Integer.MAX_VALUE,index);
+ }
+
+ // ZERO-OR-ONE REPEAT OPERATOR / STINGY MATCHING OPERATOR
+ // ? | \? depending on RE_BK_PLUS_QM
+ // not available if RE_LIMITED_OPS is set
+ // stingy matching if RE_STINGY_OPS is set and it follows a quantifier
+
+ else if ((unit.ch == '?') && !syntax.get(RESyntax.RE_LIMITED_OPS) && (!syntax.get(RESyntax.RE_BK_PLUS_QM) ^ (unit.bk || quot))) {
+ if (currentToken == null) throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index);
+
+ // Check for stingy matching on RETokenRepeated
+ if (currentToken instanceof RETokenRepeated) {
+ RETokenRepeated tokenRep = (RETokenRepeated)currentToken;
+ if (syntax.get(RESyntax.RE_STINGY_OPS) && !tokenRep.isStingy() && !tokenRep.isPossessive())
+ tokenRep.makeStingy();
+ else
+ throw new REException(getLocalizedMessage("repeat.chained"),REException.REG_BADRPT,index);
+ }
+ else if (currentToken instanceof RETokenWordBoundary || currentToken instanceof RETokenWordBoundary)
+ throw new REException(getLocalizedMessage("repeat.assertion"),REException.REG_BADRPT,index);
+ else
+ currentToken = setRepeated(currentToken,0,1,index);
+ }
+
+ // BACKREFERENCE OPERATOR
+ // \1 \2 ... \9
+ // not available if RE_NO_BK_REFS is set
+
+ else if (unit.bk && Character.isDigit(unit.ch) && !syntax.get(RESyntax.RE_NO_BK_REFS)) {
+ addToken(currentToken);
+ currentToken = new RETokenBackRef(subIndex,Character.digit(unit.ch,10),insens);
+ }
+
+ // START OF STRING OPERATOR
+ // \A if RE_STRING_ANCHORS is set
+
+ else if (unit.bk && (unit.ch == 'A') && syntax.get(RESyntax.RE_STRING_ANCHORS)) {
+ addToken(currentToken);
+ currentToken = new RETokenStart(subIndex,null);
+ }
+
+ // WORD BREAK OPERATOR
+ // \b if ????
+
+ else if (unit.bk && (unit.ch == 'b') && syntax.get(RESyntax.RE_STRING_ANCHORS)) {
+ addToken(currentToken);
+ currentToken = new RETokenWordBoundary(subIndex, RETokenWordBoundary.BEGIN | RETokenWordBoundary.END, false);
+ }
+
+ // WORD BEGIN OPERATOR
+ // \< if ????
+ else if (unit.bk && (unit.ch == '<')) {
+ addToken(currentToken);
+ currentToken = new RETokenWordBoundary(subIndex, RETokenWordBoundary.BEGIN, false);
+ }
+
+ // WORD END OPERATOR
+ // \> if ????
+ else if (unit.bk && (unit.ch == '>')) {
+ addToken(currentToken);
+ currentToken = new RETokenWordBoundary(subIndex, RETokenWordBoundary.END, false);
+ }
+
+ // NON-WORD BREAK OPERATOR
+ // \B if ????
+
+ else if (unit.bk && (unit.ch == 'B') && syntax.get(RESyntax.RE_STRING_ANCHORS)) {
+ addToken(currentToken);
+ currentToken = new RETokenWordBoundary(subIndex, RETokenWordBoundary.BEGIN | RETokenWordBoundary.END, true);
+ }
+
+
+ // DIGIT OPERATOR
+ // \d if RE_CHAR_CLASS_ESCAPES is set
+
+ else if (unit.bk && (unit.ch == 'd') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) {
+ addToken(currentToken);
+ currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.DIGIT,insens,false);
+ }
+
+ // NON-DIGIT OPERATOR
+ // \D
+
+ else if (unit.bk && (unit.ch == 'D') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) {
+ addToken(currentToken);
+ currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.DIGIT,insens,true);
+ }
+
+ // NEWLINE ESCAPE
+ // \n
+
+ else if (unit.bk && (unit.ch == 'n')) {
+ addToken(currentToken);
+ currentToken = new RETokenChar(subIndex,'\n',false);
+ }
+
+ // RETURN ESCAPE
+ // \r
+
+ else if (unit.bk && (unit.ch == 'r')) {
+ addToken(currentToken);
+ currentToken = new RETokenChar(subIndex,'\r',false);
+ }
+
+ // WHITESPACE OPERATOR
+ // \s if RE_CHAR_CLASS_ESCAPES is set
+
+ else if (unit.bk && (unit.ch == 's') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) {
+ addToken(currentToken);
+ currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.SPACE,insens,false);
+ }
+
+ // NON-WHITESPACE OPERATOR
+ // \S
+
+ else if (unit.bk && (unit.ch == 'S') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) {
+ addToken(currentToken);
+ currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.SPACE,insens,true);
+ }
+
+ // TAB ESCAPE
+ // \t
+
+ else if (unit.bk && (unit.ch == 't')) {
+ addToken(currentToken);
+ currentToken = new RETokenChar(subIndex,'\t',false);
+ }
+
+ // ALPHANUMERIC OPERATOR
+ // \w
+
+ else if (unit.bk && (unit.ch == 'w') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) {
+ addToken(currentToken);
+ currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.ALNUM,insens,false);
+ }
+
+ // NON-ALPHANUMERIC OPERATOR
+ // \W
+
+ else if (unit.bk && (unit.ch == 'W') && syntax.get(RESyntax.RE_CHAR_CLASS_ESCAPES)) {
+ addToken(currentToken);
+ currentToken = new RETokenPOSIX(subIndex,RETokenPOSIX.ALNUM,insens,true);
+ }
+
+ // END OF STRING OPERATOR
+ // \Z
+
+ else if (unit.bk && (unit.ch == 'Z') && syntax.get(RESyntax.RE_STRING_ANCHORS)) {
+ addToken(currentToken);
+ currentToken = new RETokenEnd(subIndex,null);
+ }
+
+ // NON-SPECIAL CHARACTER (or escape to make literal)
+ // c | \* for example
+
+ else { // not a special character
+ addToken(currentToken);
+ currentToken = new RETokenChar(subIndex,unit.ch,insens);
+ }
+ } // end while
+
+ // Add final buffered token and an EndSub marker
+ addToken(currentToken);
+
+ if (branches != null) {
+ branches.addElement(new RE(firstToken,lastToken,numSubs,subIndex,minimumLength));
+ branches.trimToSize(); // compact the Vector
+ minimumLength = 0;
+ firstToken = lastToken = null;
+ addToken(new RETokenOneOf(subIndex,branches,false));
+ }
+ else addToken(new RETokenEndSub(subIndex));
+
+ }
+
+ private static int getCharUnit(char[] input, int index, CharUnit unit, boolean quot) throws REException {
+ unit.ch = input[index++];
+ unit.bk = (unit.ch == '\\'
+ && (!quot || index >= input.length || input[index] == 'E'));
+ if (unit.bk)
+ if (index < input.length)
+ unit.ch = input[index++];
+ else throw new REException(getLocalizedMessage("ends.with.backslash"),REException.REG_ESCAPE,index);
+ return index;
+ }
+
+ /**
+ * Checks if the regular expression matches the input in its entirety.
+ *
+ * @param input The input text.
+ */
+ public boolean isMatch(Object input) {
+ return isMatch(input,0,0);
+ }
+
+ /**
+ * Checks if the input string, starting from index, is an exact match of
+ * this regular expression.
+ *
+ * @param input The input text.
+ * @param index The offset index at which the search should be begin.
+ */
+ public boolean isMatch(Object input,int index) {
+ return isMatch(input,index,0);
+ }
+
+
+ /**
+ * Checks if the input, starting from index and using the specified
+ * execution flags, is an exact match of this regular expression.
+ *
+ * @param input The input text.
+ * @param index The offset index at which the search should be begin.
+ * @param eflags The logical OR of any execution flags above.
+ */
+ public boolean isMatch(Object input,int index,int eflags) {
+ return isMatchImpl(makeCharIndexed(input,index),index,eflags);
+ }
+
+ private boolean isMatchImpl(CharIndexed input, int index, int eflags) {
+ if (firstToken == null) // Trivial case
+ return (input.charAt(0) == CharIndexed.OUT_OF_BOUNDS);
+ REMatch m = new REMatch(numSubs, index, eflags);
+ if (firstToken.match(input, m)) {
+ while (m != null) {
+ if (input.charAt(m.index) == CharIndexed.OUT_OF_BOUNDS) {
+ return true;
+ }
+ m = m.next;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the maximum number of subexpressions in this regular expression.
+ * If the expression contains branches, the value returned will be the
+ * maximum subexpressions in any of the branches.
+ */
+ public int getNumSubs() {
+ return numSubs;
+ }
+
+ // Overrides REToken.setUncle
+ void setUncle(REToken uncle) {
+ if (lastToken != null) {
+ lastToken.setUncle(uncle);
+ } else super.setUncle(uncle); // to deal with empty subexpressions
+ }
+
+ // Overrides REToken.chain
+
+ boolean chain(REToken next) {
+ super.chain(next);
+ setUncle(next);
+ return true;
+ }
+
+ /**
+ * Returns the minimum number of characters that could possibly
+ * constitute a match of this regular expression.
+ */
+ public int getMinimumLength() {
+ return minimumLength;
+ }
+
+ /**
+ * Returns an array of all matches found in the input.
+ *
+ * If the regular expression allows the empty string to match, it will
+ * substitute matches at all positions except the end of the input.
+ *
+ * @param input The input text.
+ * @return a non-null (but possibly zero-length) array of matches
+ */
+ public REMatch[] getAllMatches(Object input) {
+ return getAllMatches(input,0,0);
+ }
+
+ /**
+ * Returns an array of all matches found in the input,
+ * beginning at the specified index position.
+ *
+ * If the regular expression allows the empty string to match, it will
+ * substitute matches at all positions except the end of the input.
+ *
+ * @param input The input text.
+ * @param index The offset index at which the search should be begin.
+ * @return a non-null (but possibly zero-length) array of matches
+ */
+ public REMatch[] getAllMatches(Object input, int index) {
+ return getAllMatches(input,index,0);
+ }
+
+ /**
+ * Returns an array of all matches found in the input string,
+ * beginning at the specified index position and using the specified
+ * execution flags.
+ *
+ * If the regular expression allows the empty string to match, it will
+ * substitute matches at all positions except the end of the input.
+ *
+ * @param input The input text.
+ * @param index The offset index at which the search should be begin.
+ * @param eflags The logical OR of any execution flags above.
+ * @return a non-null (but possibly zero-length) array of matches
+ */
+ public REMatch[] getAllMatches(Object input, int index, int eflags) {
+ return getAllMatchesImpl(makeCharIndexed(input,index),index,eflags);
+ }
+
+ // this has been changed since 1.03 to be non-overlapping matches
+ private REMatch[] getAllMatchesImpl(CharIndexed input, int index, int eflags) {
+ Vector all = new Vector();
+ REMatch m = null;
+ while ((m = getMatchImpl(input,index,eflags,null)) != null) {
+ all.addElement(m);
+ index = m.getEndIndex();
+ if (m.end[0] == 0) { // handle pathological case of zero-length match
+ index++;
+ input.move(1);
+ } else {
+ input.move(m.end[0]);
+ }
+ if (!input.isValid()) break;
+ }
+ REMatch[] mset = new REMatch[all.size()];
+ all.copyInto(mset);
+ return mset;
+ }
+
+ /* Implements abstract method REToken.match() */
+ boolean match(CharIndexed input, REMatch mymatch) {
+ if (firstToken == null) return next(input, mymatch);
+
+ // Note the start of this subexpression
+ mymatch.start[subIndex] = mymatch.index;
+
+ return firstToken.match(input, mymatch);
+ }
+
+ /**
+ * Returns the first match found in the input. If no match is found,
+ * null is returned.
+ *
+ * @param input The input text.
+ * @return An REMatch instance referencing the match, or null if none.
+ */
+ public REMatch getMatch(Object input) {
+ return getMatch(input,0,0);
+ }
+
+ /**
+ * Returns the first match found in the input, beginning
+ * the search at the specified index. If no match is found,
+ * returns null.
+ *
+ * @param input The input text.
+ * @param index The offset within the text to begin looking for a match.
+ * @return An REMatch instance referencing the match, or null if none.
+ */
+ public REMatch getMatch(Object input, int index) {
+ return getMatch(input,index,0);
+ }
+
+ /**
+ * Returns the first match found in the input, beginning
+ * the search at the specified index, and using the specified
+ * execution flags. If no match is found, returns null.
+ *
+ * @param input The input text.
+ * @param index The offset index at which the search should be begin.
+ * @param eflags The logical OR of any execution flags above.
+ * @return An REMatch instance referencing the match, or null if none.
+ */
+ public REMatch getMatch(Object input, int index, int eflags) {
+ return getMatch(input,index,eflags,null);
+ }
+
+ /**
+ * Returns the first match found in the input, beginning the search
+ * at the specified index, and using the specified execution flags.
+ * If no match is found, returns null. If a StringBuffer is
+ * provided and is non-null, the contents of the input text from the
+ * index to the beginning of the match (or to the end of the input,
+ * if there is no match) are appended to the StringBuffer.
+ *
+ * @param input The input text.
+ * @param index The offset index at which the search should be begin.
+ * @param eflags The logical OR of any execution flags above.
+ * @param buffer The StringBuffer to save pre-match text in.
+ * @return An REMatch instance referencing the match, or null if none. */
+ public REMatch getMatch(Object input, int index, int eflags, StringBuffer buffer) {
+ return getMatchImpl(makeCharIndexed(input,index),index,eflags,buffer);
+ }
+
+ REMatch getMatchImpl(CharIndexed input, int anchor, int eflags, StringBuffer buffer) {
+ // Create a new REMatch to hold results
+ REMatch mymatch = new REMatch(numSubs, anchor, eflags);
+ do {
+ // Optimization: check if anchor + minimumLength > length
+ if (minimumLength == 0 || input.charAt(minimumLength-1) != CharIndexed.OUT_OF_BOUNDS) {
+ if (match(input, mymatch)) {
+ // Find longest match of them all to observe leftmost longest
+ REMatch longest = mymatch;
+ while ((mymatch = mymatch.next) != null) {
+ if (mymatch.index > longest.index) {
+ longest = mymatch;
+ }
+ }
+
+ longest.end[0] = longest.index;
+ longest.finish(input);
+ return longest;
+ }
+ }
+ mymatch.clear(++anchor);
+ // Append character to buffer if needed
+ if (buffer != null && input.charAt(0) != CharIndexed.OUT_OF_BOUNDS) {
+ buffer.append(input.charAt(0));
+ }
+ } while (input.move(1));
+
+ // Special handling at end of input for e.g. "$"
+ if (minimumLength == 0) {
+ if (match(input, mymatch)) {
+ mymatch.finish(input);
+ return mymatch;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns an REMatchEnumeration that can be used to iterate over the
+ * matches found in the input text.
+ *
+ * @param input The input text.
+ * @return A non-null REMatchEnumeration instance.
+ */
+ public REMatchEnumeration getMatchEnumeration(Object input) {
+ return getMatchEnumeration(input,0,0);
+ }
+
+
+ /**
+ * Returns an REMatchEnumeration that can be used to iterate over the
+ * matches found in the input text.
+ *
+ * @param input The input text.
+ * @param index The offset index at which the search should be begin.
+ * @return A non-null REMatchEnumeration instance, with its input cursor
+ * set to the index position specified.
+ */
+ public REMatchEnumeration getMatchEnumeration(Object input, int index) {
+ return getMatchEnumeration(input,index,0);
+ }
+
+ /**
+ * Returns an REMatchEnumeration that can be used to iterate over the
+ * matches found in the input text.
+ *
+ * @param input The input text.
+ * @param index The offset index at which the search should be begin.
+ * @param eflags The logical OR of any execution flags above.
+ * @return A non-null REMatchEnumeration instance, with its input cursor
+ * set to the index position specified.
+ */
+ public REMatchEnumeration getMatchEnumeration(Object input, int index, int eflags) {
+ return new REMatchEnumeration(this,makeCharIndexed(input,index),index,eflags);
+ }
+
+
+ /**
+ * Substitutes the replacement text for the first match found in the input.
+ *
+ * @param input The input text.
+ * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto).
+ * @return A String interpolating the substituted text.
+ * @see REMatch#substituteInto
+ */
+ public String substitute(Object input,String replace) {
+ return substitute(input,replace,0,0);
+ }
+
+ /**
+ * Substitutes the replacement text for the first match found in the input
+ * beginning at the specified index position. Specifying an index
+ * effectively causes the regular expression engine to throw away the
+ * specified number of characters.
+ *
+ * @param input The input text.
+ * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto).
+ * @param index The offset index at which the search should be begin.
+ * @return A String containing the substring of the input, starting
+ * at the index position, and interpolating the substituted text.
+ * @see REMatch#substituteInto
+ */
+ public String substitute(Object input,String replace,int index) {
+ return substitute(input,replace,index,0);
+ }
+
+ /**
+ * Substitutes the replacement text for the first match found in the input
+ * string, beginning at the specified index position and using the
+ * specified execution flags.
+ *
+ * @param input The input text.
+ * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto).
+ * @param index The offset index at which the search should be begin.
+ * @param eflags The logical OR of any execution flags above.
+ * @return A String containing the substring of the input, starting
+ * at the index position, and interpolating the substituted text.
+ * @see REMatch#substituteInto
+ */
+ public String substitute(Object input,String replace,int index,int eflags) {
+ return substituteImpl(makeCharIndexed(input,index),replace,index,eflags);
+ }
+
+ private String substituteImpl(CharIndexed input,String replace,int index,int eflags) {
+ StringBuffer buffer = new StringBuffer();
+ REMatch m = getMatchImpl(input,index,eflags,buffer);
+ if (m==null) return buffer.toString();
+ buffer.append( ((eflags & REG_NO_INTERPOLATE) > 0) ?
+ replace : m.substituteInto(replace) );
+ if (input.move(m.end[0])) {
+ do {
+ buffer.append(input.charAt(0));
+ } while (input.move(1));
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Substitutes the replacement text for each non-overlapping match found
+ * in the input text.
+ *
+ * @param input The input text.
+ * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto).
+ * @return A String interpolating the substituted text.
+ * @see REMatch#substituteInto
+ */
+ public String substituteAll(Object input,String replace) {
+ return substituteAll(input,replace,0,0);
+ }
+
+ /**
+ * Substitutes the replacement text for each non-overlapping match found
+ * in the input text, starting at the specified index.
+ *
+ * If the regular expression allows the empty string to match, it will
+ * substitute matches at all positions except the end of the input.
+ *
+ * @param input The input text.
+ * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto).
+ * @param index The offset index at which the search should be begin.
+ * @return A String containing the substring of the input, starting
+ * at the index position, and interpolating the substituted text.
+ * @see REMatch#substituteInto
+ */
+ public String substituteAll(Object input,String replace,int index) {
+ return substituteAll(input,replace,index,0);
+ }
+
+ /**
+ * Substitutes the replacement text for each non-overlapping match found
+ * in the input text, starting at the specified index and using the
+ * specified execution flags.
+ *
+ * @param input The input text.
+ * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto).
+ * @param index The offset index at which the search should be begin.
+ * @param eflags The logical OR of any execution flags above.
+ * @return A String containing the substring of the input, starting
+ * at the index position, and interpolating the substituted text.
+ * @see REMatch#substituteInto
+ */
+ public String substituteAll(Object input,String replace,int index,int eflags) {
+ return substituteAllImpl(makeCharIndexed(input,index),replace,index,eflags);
+ }
+
+ private String substituteAllImpl(CharIndexed input,String replace,int index,int eflags) {
+ StringBuffer buffer = new StringBuffer();
+ REMatch m;
+ while ((m = getMatchImpl(input,index,eflags,buffer)) != null) {
+ buffer.append( ((eflags & REG_NO_INTERPOLATE) > 0) ?
+ replace : m.substituteInto(replace) );
+ index = m.getEndIndex();
+ if (m.end[0] == 0) {
+ char ch = input.charAt(0);
+ if (ch != CharIndexed.OUT_OF_BOUNDS)
+ buffer.append(ch);
+ input.move(1);
+ } else {
+ input.move(m.end[0]);
+ }
+
+ if (!input.isValid()) break;
+ }
+ return buffer.toString();
+ }
+
+ /* Helper function for constructor */
+ private void addToken(REToken next) {
+ if (next == null) return;
+ minimumLength += next.getMinimumLength();
+ if (firstToken == null) {
+ lastToken = firstToken = next;
+ } else {
+ // if chain returns false, it "rejected" the token due to
+ // an optimization, and next was combined with lastToken
+ if (lastToken.chain(next)) {
+ lastToken = next;
+ }
+ }
+ }
+
+ private static REToken setRepeated(REToken current, int min, int max, int index) throws REException {
+ if (current == null) throw new REException(getLocalizedMessage("repeat.no.token"),REException.REG_BADRPT,index);
+ return new RETokenRepeated(current.subIndex,current,min,max);
+ }
+
+ private static int getPosixSet(char[] pattern,int index,StringBuffer buf) {
+ // Precondition: pattern[index-1] == ':'
+ // we will return pos of closing ']'.
+ int i;
+ for (i=index; i<(pattern.length-1); i++) {
+ if ((pattern[i] == ':') && (pattern[i+1] == ']'))
+ return i+2;
+ buf.append(pattern[i]);
+ }
+ return index; // didn't match up
+ }
+
+ private int getMinMax(char[] input,int index,IntPair minMax,RESyntax syntax) throws REException {
+ // Precondition: input[index-1] == '{', minMax != null
+
+ boolean mustMatch = !syntax.get(RESyntax.RE_NO_BK_BRACES);
+ int startIndex = index;
+ if (index == input.length) {
+ if (mustMatch)
+ throw new REException(getLocalizedMessage("unmatched.brace"),REException.REG_EBRACE,index);
+ else
+ return startIndex;
+ }
+
+ int min,max=0;
+ CharUnit unit = new CharUnit();
+ StringBuffer buf = new StringBuffer();
+
+ // Read string of digits
+ do {
+ index = getCharUnit(input,index,unit,false);
+ if (Character.isDigit(unit.ch))
+ buf.append(unit.ch);
+ } while ((index != input.length) && Character.isDigit(unit.ch));
+
+ // Check for {} tomfoolery
+ if (buf.length() == 0) {
+ if (mustMatch)
+ throw new REException(getLocalizedMessage("interval.error"),REException.REG_EBRACE,index);
+ else
+ return startIndex;
+ }
+
+ min = Integer.parseInt(buf.toString());
+
+ if ((unit.ch == '}') && (syntax.get(RESyntax.RE_NO_BK_BRACES) ^ unit.bk))
+ max = min;
+ else if (index == input.length)
+ if (mustMatch)
+ throw new REException(getLocalizedMessage("interval.no.end"),REException.REG_EBRACE,index);
+ else
+ return startIndex;
+ else if ((unit.ch == ',') && !unit.bk) {
+ buf = new StringBuffer();
+ // Read string of digits
+ while (((index = getCharUnit(input,index,unit,false)) != input.length) && Character.isDigit(unit.ch))
+ buf.append(unit.ch);
+
+ if (!((unit.ch == '}') && (syntax.get(RESyntax.RE_NO_BK_BRACES) ^ unit.bk)))
+ if (mustMatch)
+ throw new REException(getLocalizedMessage("interval.error"),REException.REG_EBRACE,index);
+ else
+ return startIndex;
+
+ // This is the case of {x,}
+ if (buf.length() == 0) max = Integer.MAX_VALUE;
+ else max = Integer.parseInt(buf.toString());
+ } else
+ if (mustMatch)
+ throw new REException(getLocalizedMessage("interval.error"),REException.REG_EBRACE,index);
+ else
+ return startIndex;
+
+ // We know min and max now, and they are valid.
+
+ minMax.first = min;
+ minMax.second = max;
+
+ // return the index following the '}'
+ return index;
+ }
+
+ /**
+ * Return a human readable form of the compiled regular expression,
+ * useful for debugging.
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ dump(sb);
+ return sb.toString();
+ }
+
+ void dump(StringBuffer os) {
+ os.append('(');
+ if (subIndex == 0)
+ os.append("?:");
+ if (firstToken != null)
+ firstToken.dumpAll(os);
+ os.append(')');
+ }
+
+ // Cast input appropriately or throw exception
+ private static CharIndexed makeCharIndexed(Object input, int index) {
+ // We could let a String fall through to final input, but since
+ // it's the most likely input type, we check it first.
+ if (input instanceof String)
+ return new CharIndexedString((String) input,index);
+ else if (input instanceof char[])
+ return new CharIndexedCharArray((char[]) input,index);
+ else if (input instanceof StringBuffer)
+ return new CharIndexedStringBuffer((StringBuffer) input,index);
+ else if (input instanceof InputStream)
+ return new CharIndexedInputStream((InputStream) input,index);
+ else if (input instanceof CharIndexed)
+ return (CharIndexed) input; // do we lose index info?
+ else
+ return new CharIndexedString(input.toString(), index);
+ }
+}
diff --git a/libjava/classpath/gnu/regexp/REException.java b/libjava/classpath/gnu/regexp/REException.java
new file mode 100644
index 0000000..73f86fa
--- /dev/null
+++ b/libjava/classpath/gnu/regexp/REException.java
@@ -0,0 +1,182 @@
+/* gnu/regexp/REException.java
+ Copyright (C) 1998-2001, 2004 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 gnu.regexp;
+
+import java.text.MessageFormat;
+
+/**
+ * This is the regular expression exception class. An exception of this type
+ * defines the three attributes:
+ *
+ * RE exp = new RE("^foo.");
+ * REMatch m0 = exp.getMatch(s);
+ * REMatch m1 = exp.getMatch(s.substring(8));
+ * REMatch m2 = exp.getMatch(s.substring(8),0,RE.REG_NOTBOL);
+ * REMatch m3 = exp.getMatch(s,8);
+ * REMatch m4 = exp.getMatch(s,8,RE.REG_ANCHORINDEX);
+ *
+ * // m0.toString(): "food"
+ * // m1.toString(): "fool"
+ * // m2.toString(): null
+ * // m3.toString(): null
+ * // m4.toString(): "fool"
+ *
+ *
+ * REMatch myMatch = myExpression.getMatch(myString);
+ */
+ public String toString() {
+ return matchedText;
+ }
+
+ /**
+ * Returns the index within the input text where the match in its entirety
+ * began.
+ */
+ public int getStartIndex() {
+ return offset + start[0];
+ }
+
+ /**
+ * Returns the index within the input string where the match in
+ * its entirety ends. The return value is the next position after
+ * the end of the string; therefore, a match created by the
+ * following call:
+ *
+ *
+ * if (myMatch != null) System.out.println("Regexp found: "+myMatch);
+ *
+ * REMatch myMatch = myExpression.getMatch(myString);
+ *
+ * can be viewed (given that myMatch is not null) by creating + *
+ * String theMatch = myString.substring(myMatch.getStartIndex(),
+ * myMatch.getEndIndex());
+ *
+ * But you can save yourself that work, since the toString()
+ * method (above) does exactly that for you.
+ */
+ public int getEndIndex() {
+ return offset + end[0];
+ }
+
+ /**
+ * Returns the string matching the given subexpression. The subexpressions
+ * are indexed starting with one, not zero. That is, the subexpression
+ * identified by the first set of parentheses in a regular expression
+ * could be retrieved from an REMatch by calling match.toString(1).
+ *
+ * @param sub Index of the subexpression.
+ */
+ public String toString(int sub) {
+ if ((sub >= start.length) || (start[sub] == -1)) return "";
+ return (matchedText.substring(start[sub],end[sub]));
+ }
+
+ /**
+ * Returns the index within the input string used to generate this match
+ * where subexpression number sub begins, or -1
if
+ * the subexpression does not exist. The initial position is zero.
+ *
+ * @param sub Subexpression index
+ * @deprecated Use getStartIndex(int) instead.
+ */
+ public int getSubStartIndex(int sub) {
+ if (sub >= start.length) return -1;
+ int x = start[sub];
+ return (x == -1) ? x : offset + x;
+ }
+
+ /**
+ * Returns the index within the input string used to generate this match
+ * where subexpression number sub begins, or -1
if
+ * the subexpression does not exist. The initial position is zero.
+ *
+ * @param sub Subexpression index
+ * @since gnu.regexp 1.1.0
+ */
+ public int getStartIndex(int sub) {
+ if (sub >= start.length) return -1;
+ int x = start[sub];
+ return (x == -1) ? x : offset + x;
+ }
+
+ /**
+ * Returns the index within the input string used to generate this match
+ * where subexpression number sub ends, or -1
if
+ * the subexpression does not exist. The initial position is zero.
+ *
+ * @param sub Subexpression index
+ * @deprecated Use getEndIndex(int) instead
+ */
+ public int getSubEndIndex(int sub) {
+ if (sub >= start.length) return -1;
+ int x = end[sub];
+ return (x == -1) ? x : offset + x;
+ }
+
+ /**
+ * Returns the index within the input string used to generate this match
+ * where subexpression number sub ends, or -1
if
+ * the subexpression does not exist. The initial position is zero.
+ *
+ * @param sub Subexpression index
+ */
+ public int getEndIndex(int sub) {
+ if (sub >= start.length) return -1;
+ int x = end[sub];
+ return (x == -1) ? x : offset + x;
+ }
+
+ /**
+ * Substitute the results of this match to create a new string.
+ * This is patterned after PERL, so the tokens to watch out for are
+ * $0
through $9
. $0
matches
+ * the full substring matched; $n
matches
+ * subexpression number n.
+ *
+ * @param input A string consisting of literals and $n
tokens.
+ */
+ public String substituteInto(String input) {
+ // a la Perl, $0 is whole thing, $1 - $9 are subexpressions
+ StringBuffer output = new StringBuffer();
+ int pos;
+ for (pos = 0; pos < input.length()-1; pos++) {
+ if ((input.charAt(pos) == '$') && (Character.isDigit(input.charAt(pos+1)))) {
+ int val = Character.digit(input.charAt(++pos),10);
+ if (val < start.length) {
+ output.append(toString(val));
+ }
+ } else output.append(input.charAt(pos));
+ }
+ if (pos < input.length()) output.append(input.charAt(pos));
+ return output.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/regexp/REMatchEnumeration.java b/libjava/classpath/gnu/regexp/REMatchEnumeration.java
new file mode 100644
index 0000000..f164a69
--- /dev/null
+++ b/libjava/classpath/gnu/regexp/REMatchEnumeration.java
@@ -0,0 +1,135 @@
+/* gnu/regexp/REMatchEnumeration.java
+ Copyright (C) 1998-2001, 2004 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 gnu.regexp;
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * An REMatchEnumeration enumerates regular expression matches over a
+ * given input text. You obtain a reference to an enumeration using
+ * the getMatchEnumeration()
methods on an instance of
+ * RE.
+ *
+ *
+ *
+ * REMatchEnumeration does lazy computation; that is, it will not
+ * search for a match until it needs to. If you'd rather just get all
+ * the matches at once in a big array, use the
+ * getAllMatches()
methods on RE. However, using an
+ * enumeration can help speed performance when the entire text does
+ * not need to be searched immediately.
+ *
+ *
+ *
+ * The enumerated type is especially useful when searching on a Reader
+ * or InputStream, because the InputStream read position cannot be
+ * guaranteed after calling
+ * Note that this makes UncheckedRE dangerous if constructed with
+ * dynamic data. Do not use UncheckedRE unless you are completely sure
+ * that all input being passed to it contains valid, well-formed
+ * regular expressions for the syntax specified.
+ *
+ * @author Wes Biggs
+ * @see gnu.regexp.RE
+ * @since gnu.regexp 1.1.4
+ */
+
+public final class UncheckedRE extends RE {
+ /**
+ * Constructs a regular expression pattern buffer without any compilation
+ * flags set, and using the default syntax (RESyntax.RE_SYNTAX_PERL5).
+ *
+ * @param pattern A regular expression pattern, in the form of a String,
+ * StringBuffer or char[]. Other input types will be converted to
+ * strings using the toString() method.
+ * @exception RuntimeException The input pattern could not be parsed.
+ * @exception NullPointerException The pattern was null.
+ */
+ public UncheckedRE(Object pattern) {
+ this(pattern,0,RESyntax.RE_SYNTAX_PERL5);
+ }
+
+ /**
+ * Constructs a regular expression pattern buffer using the specified
+ * compilation flags and the default syntax (RESyntax.RE_SYNTAX_PERL5).
+ *
+ * @param pattern A regular expression pattern, in the form of a String,
+ * StringBuffer, or char[]. Other input types will be converted to
+ * strings using the toString() method.
+ * @param cflags The logical OR of any combination of the compilation flags in the RE class.
+ * @exception RuntimeException The input pattern could not be parsed.
+ * @exception NullPointerException The pattern was null.
+ */
+ public UncheckedRE(Object pattern, int cflags) {
+ this(pattern,cflags,RESyntax.RE_SYNTAX_PERL5);
+ }
+
+ /**
+ * Constructs a regular expression pattern buffer using the specified
+ * compilation flags and regular expression syntax.
+ *
+ * @param pattern A regular expression pattern, in the form of a String,
+ * StringBuffer, or char[]. Other input types will be converted to
+ * strings using the toString() method.
+ * @param cflags The logical OR of any combination of the compilation flags in the RE class.
+ * @param syntax The type of regular expression syntax to use.
+ * @exception RuntimeException The input pattern could not be parsed.
+ * @exception NullPointerException The pattern was null.
+ */
+ public UncheckedRE(Object pattern, int cflags, RESyntax syntax) {
+ try {
+ initialize(pattern,cflags,syntax,0,0);
+ } catch (REException e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+}
+
+
diff --git a/libjava/classpath/gnu/test/.cvsignore b/libjava/classpath/gnu/test/.cvsignore
new file mode 100644
index 0000000..70845e0
--- /dev/null
+++ b/libjava/classpath/gnu/test/.cvsignore
@@ -0,0 +1 @@
+Makefile.in
diff --git a/libjava/classpath/gnu/test/Fail.java b/libjava/classpath/gnu/test/Fail.java
new file mode 100644
index 0000000..f1c4a0c
--- /dev/null
+++ b/libjava/classpath/gnu/test/Fail.java
@@ -0,0 +1,57 @@
+/* Fail.java -- Result code returned when test failed but was expected to
+ Copyright (c) 1998 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 gnu.test;
+
+/**
+ * Test failed but was expected to pass.
+ */
+public class Fail extends Result
+{
+ /**
+ * Constructs a Fail result code with additional information.
+ */
+ public Fail(String msg) {
+ super("FAIL", msg);
+ }
+ /**
+ * Constructs a Fail result code.
+ */
+ public Fail() {
+ this("");
+ }
+}
diff --git a/libjava/classpath/gnu/test/Makefile.am b/libjava/classpath/gnu/test/Makefile.am
new file mode 100644
index 0000000..49bc669
--- /dev/null
+++ b/libjava/classpath/gnu/test/Makefile.am
@@ -0,0 +1,5 @@
+## Input file for automake to generate the Makefile.in used by configure
+
+##gnutestdir = $(datadir)/gnu/test/
+
+##gnutest_JAVA = Fail.java Test.java Untested.java Pass.java Unresolved.java XFail.java Result.java Unsupported.java XPass.java
diff --git a/libjava/classpath/gnu/test/Pass.java b/libjava/classpath/gnu/test/Pass.java
new file mode 100644
index 0000000..abec54e
--- /dev/null
+++ b/libjava/classpath/gnu/test/Pass.java
@@ -0,0 +1,57 @@
+/* Pass.java -- Result code returned when test passed and was excepted to
+ Copyright (c) 1998 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 gnu.test;
+
+/**
+ * Test passed and was excepted to pass.
+ */
+public class Pass extends Result
+{
+ /**
+ * Constructs a Pass result code with additional information.
+ */
+ public Pass(String msg) {
+ super("PASS", msg);
+ }
+ /**
+ * Constructs a Pass result code.
+ */
+ public Pass() {
+ this("");
+ }
+}
diff --git a/libjava/classpath/gnu/test/Result.java b/libjava/classpath/gnu/test/Result.java
new file mode 100644
index 0000000..908d4b4
--- /dev/null
+++ b/libjava/classpath/gnu/test/Result.java
@@ -0,0 +1,85 @@
+/* Result.java -- Abstract base class for all Result types.
+ Copyright (c) 1998 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 gnu.test;
+
+/**
+ * Class which all usable Result objects extend.
+ */
+public abstract class Result
+{
+ String name, msg;
+
+ /**
+ * Create a result of a given type, with a given message.
+ *
+ * @param name name of type
+ * @param msg message
+ */
+ public Result(String name, String msg) {
+ this.name = name;
+ this.msg = msg;
+ }
+
+ /**
+ * Create a result of a given type.
+ *
+ * @param name name of type
+ */
+ public Result(String name) {
+ this(name, "");
+ }
+
+ /**
+ * Returns the name of the type.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the message associated with this instance of Result, or
+ * the empty string if no message exists.
+ */
+ public String getMsg() {
+ return (msg != null) ? msg : "";
+ }
+
+ public String toString() {
+ return getName() + ":" + getMsg();
+ }
+}
diff --git a/libjava/classpath/gnu/test/Test.java b/libjava/classpath/gnu/test/Test.java
new file mode 100644
index 0000000..6b2e18d
--- /dev/null
+++ b/libjava/classpath/gnu/test/Test.java
@@ -0,0 +1,57 @@
+/* Test.java -- Interface representing a single test.
+ Copyright (c) 1998 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 gnu.test;
+
+/**
+ * Interface which all GNU Classpath tests must implement.
+ * The method This parser currently implements the SAX1 Parser API, but
+ * it may not continue to do so in the future.
+ *
+ * @author Written by David Megginson (version 1.2a from Microstar)
+ * @author Updated by David Brownell <dbrownell@users.sourceforge.net>
+ * @see org.xml.sax.Parser
+ */
+final public class SAXDriver
+ implements Locator, Attributes2, XMLReader, Parser, AttributeList
+{
+
+ private final DefaultHandler2 base = new DefaultHandler2();
+ private XmlParser parser;
+
+ private EntityResolver entityResolver = base;
+ private EntityResolver2 resolver2 = null;
+ private ContentHandler contentHandler = base;
+ private DTDHandler dtdHandler = base;
+ private ErrorHandler errorHandler = base;
+ private DeclHandler declHandler = base;
+ private LexicalHandler lexicalHandler = base;
+
+ private String elementName;
+ private Stack entityStack;
+
+ // one vector (of object/struct): faster, smaller
+ private List attributesList;
+
+ private boolean namespaces = true;
+ private boolean xmlNames = false;
+ private boolean extGE = true;
+ private boolean extPE = true;
+ private boolean resolveAll = true;
+ private boolean useResolver2 = true;
+
+ // package private to allow (read-only) access in XmlParser
+ boolean stringInterning = true;
+
+ private int attributeCount;
+ private boolean attributes;
+ private String[] nsTemp;
+ private NamespaceSupport prefixStack;
+
+ //
+ // Constructor.
+ //
+
+ /**
+ * Constructs a SAX Parser.
+ */
+ public SAXDriver()
+ {
+ reset();
+ }
+
+ private void reset()
+ {
+ elementName = null;
+ entityStack = new Stack();
+ attributesList = Collections.synchronizedList(new ArrayList());
+ attributeCount = 0;
+ attributes = false;
+ nsTemp = new String[3];
+ prefixStack = null;
+ }
+
+
+ //
+ // Implementation of org.xml.sax.Parser.
+ //
+
+ /**
+ * SAX1: Sets the locale used for diagnostics; currently,
+ * only locales using the English language are supported.
+ * @param locale The locale for which diagnostics will be generated
+ */
+ public void setLocale(Locale locale)
+ throws SAXException
+ {
+ if ("en".equals(locale.getLanguage()))
+ {
+ return;
+ }
+ throw new SAXException ("AElfred2 only supports English locales.");
+ }
+
+ /**
+ * SAX2: Returns the object used when resolving external
+ * entities during parsing (both general and parameter entities).
+ */
+ public EntityResolver getEntityResolver()
+ {
+ return (entityResolver == base) ? null : entityResolver;
+ }
+
+ /**
+ * SAX1, SAX2: Set the entity resolver for this parser.
+ * @param handler The object to receive entity events.
+ */
+ public void setEntityResolver(EntityResolver resolver)
+ {
+ if (resolver instanceof EntityResolver2)
+ {
+ resolver2 = (EntityResolver2) resolver;
+ }
+ else
+ {
+ resolver2 = null;
+ }
+ if (resolver == null)
+ {
+ resolver = base;
+ }
+ entityResolver = resolver;
+ }
+
+ /**
+ * SAX2: Returns the object used to process declarations related
+ * to notations and unparsed entities.
+ */
+ public DTDHandler getDTDHandler()
+ {
+ return (dtdHandler == base) ? null : dtdHandler;
+ }
+
+ /**
+ * SAX1, SAX2: Set the DTD handler for this parser.
+ * @param handler The object to receive DTD events.
+ */
+ public void setDTDHandler(DTDHandler handler)
+ {
+ if (handler == null)
+ {
+ handler = base;
+ }
+ this.dtdHandler = handler;
+ }
+
+
+ /**
+ * SAX1: Set the document handler for this parser. If a
+ * content handler was set, this document handler will supplant it.
+ * The parser is set to report all XML 1.0 names rather than to
+ * filter out "xmlns" attributes (the "namespace-prefixes" feature
+ * is set to true).
+ *
+ * @deprecated SAX2 programs should use the XMLReader interface
+ * and a ContentHandler.
+ *
+ * @param handler The object to receive document events.
+ */
+ public void setDocumentHandler(DocumentHandler handler)
+ {
+ contentHandler = new Adapter(handler);
+ xmlNames = true;
+ }
+
+ /**
+ * SAX2: Returns the object used to report the logical
+ * content of an XML document.
+ */
+ public ContentHandler getContentHandler()
+ {
+ return (contentHandler == base) ? null : contentHandler;
+ }
+
+ /**
+ * SAX2: Assigns the object used to report the logical
+ * content of an XML document. If a document handler was set,
+ * this content handler will supplant it (but XML 1.0 style name
+ * reporting may remain enabled).
+ */
+ public void setContentHandler(ContentHandler handler)
+ {
+ if (handler == null)
+ {
+ handler = base;
+ }
+ contentHandler = handler;
+ }
+
+ /**
+ * SAX1, SAX2: Set the error handler for this parser.
+ * @param handler The object to receive error events.
+ */
+ public void setErrorHandler(ErrorHandler handler)
+ {
+ if (handler == null)
+ {
+ handler = base;
+ }
+ this.errorHandler = handler;
+ }
+
+ /**
+ * SAX2: Returns the object used to receive callbacks for XML
+ * errors of all levels (fatal, nonfatal, warning); this is never null;
+ */
+ public ErrorHandler getErrorHandler()
+ {
+ return (errorHandler == base) ? null : errorHandler;
+ }
+
+ /**
+ * SAX1, SAX2: Auxiliary API to parse an XML document, used mostly
+ * when no URI is available.
+ * If you want anything useful to happen, you should set
+ * at least one type of handler.
+ * @param source The XML input source. Don't set 'encoding' unless
+ * you know for a fact that it's correct.
+ * @see #setEntityResolver
+ * @see #setDTDHandler
+ * @see #setContentHandler
+ * @see #setErrorHandler
+ * @exception SAXException The handlers may throw any SAXException,
+ * and the parser normally throws SAXParseException objects.
+ * @exception IOException IOExceptions are normally through through
+ * the parser if there are problems reading the source document.
+ */
+ public void parse(InputSource source)
+ throws SAXException, IOException
+ {
+ synchronized (base)
+ {
+ parser = new XmlParser();
+ if (namespaces)
+ {
+ prefixStack = new NamespaceSupport();
+ }
+ else if (!xmlNames)
+ {
+ throw new IllegalStateException();
+ }
+ parser.setHandler(this);
+
+ try
+ {
+ Reader r = source.getCharacterStream();
+ InputStream in = source.getByteStream();
+
+ parser.doParse(source.getSystemId(),
+ source.getPublicId(),
+ r,
+ in,
+ source.getEncoding());
+ }
+ catch (SAXException e)
+ {
+ throw e;
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new SAXParseException(e.getMessage(), this, e);
+ }
+ finally
+ {
+ contentHandler.endDocument();
+ reset();
+ }
+ }
+ }
+
+ /**
+ * SAX1, SAX2: Preferred API to parse an XML document, using a
+ * system identifier (URI).
+ */
+ public void parse(String systemId)
+ throws SAXException, IOException
+ {
+ parse(new InputSource(systemId));
+ }
+
+ //
+ // Implementation of SAX2 "XMLReader" interface
+ //
+ static final String FEATURE = "http://xml.org/sax/features/";
+ static final String PROPERTY = "http://xml.org/sax/properties/";
+
+ /**
+ * SAX2: Tells the value of the specified feature flag.
+ *
+ * @exception SAXNotRecognizedException thrown if the feature flag
+ * is neither built in, nor yet assigned.
+ */
+ public boolean getFeature(String featureId)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ if ((FEATURE + "validation").equals(featureId))
+ {
+ return false;
+ }
+
+ // external entities (both types) are optionally included
+ if ((FEATURE + "external-general-entities").equals(featureId))
+ {
+ return extGE;
+ }
+ if ((FEATURE + "external-parameter-entities").equals(featureId))
+ {
+ return extPE;
+ }
+
+ // element/attribute names are as written in document; no mangling
+ if ((FEATURE + "namespace-prefixes").equals(featureId))
+ {
+ return xmlNames;
+ }
+
+ // report element/attribute namespaces?
+ if ((FEATURE + "namespaces").equals(featureId))
+ {
+ return namespaces;
+ }
+
+ // all PEs and GEs are reported
+ if ((FEATURE + "lexical-handler/parameter-entities").equals(featureId))
+ {
+ return true;
+ }
+
+ // default is true
+ if ((FEATURE + "string-interning").equals(featureId))
+ {
+ return stringInterning;
+ }
+
+ // EXTENSIONS 1.1
+
+ // always returns isSpecified info
+ if ((FEATURE + "use-attributes2").equals(featureId))
+ {
+ return true;
+ }
+
+ // meaningful between startDocument/endDocument
+ if ((FEATURE + "is-standalone").equals(featureId))
+ {
+ if (parser == null)
+ {
+ throw new SAXNotSupportedException(featureId);
+ }
+ return parser.isStandalone();
+ }
+
+ // optionally don't absolutize URIs in declarations
+ if ((FEATURE + "resolve-dtd-uris").equals(featureId))
+ {
+ return resolveAll;
+ }
+
+ // optionally use resolver2 interface methods, if possible
+ if ((FEATURE + "use-entity-resolver2").equals(featureId))
+ {
+ return useResolver2;
+ }
+
+ throw new SAXNotRecognizedException(featureId);
+ }
+
+ // package private
+ DeclHandler getDeclHandler()
+ {
+ return declHandler;
+ }
+
+ // package private
+ boolean resolveURIs()
+ {
+ return resolveAll;
+ }
+
+ /**
+ * SAX2: Returns the specified property.
+ *
+ * @exception SAXNotRecognizedException thrown if the property value
+ * is neither built in, nor yet stored.
+ */
+ public Object getProperty(String propertyId)
+ throws SAXNotRecognizedException
+ {
+ if ((PROPERTY + "declaration-handler").equals(propertyId))
+ {
+ return (declHandler == base) ? null : declHandler;
+ }
+
+ if ((PROPERTY + "lexical-handler").equals(propertyId))
+ {
+ return (lexicalHandler == base) ? null : lexicalHandler;
+ }
+
+ // unknown properties
+ throw new SAXNotRecognizedException(propertyId);
+ }
+
+ /**
+ * SAX2: Sets the state of feature flags in this parser. Some
+ * built-in feature flags are mutable.
+ */
+ public void setFeature(String featureId, boolean value)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ boolean state;
+
+ // Features with a defined value, we just change it if we can.
+ state = getFeature (featureId);
+
+ if (state == value)
+ {
+ return;
+ }
+ if (parser != null)
+ {
+ throw new SAXNotSupportedException("not while parsing");
+ }
+
+ if ((FEATURE + "namespace-prefixes").equals(featureId))
+ {
+ // in this implementation, this only affects xmlns reporting
+ xmlNames = value;
+ // forcibly prevent illegal parser state
+ if (!xmlNames)
+ {
+ namespaces = true;
+ }
+ return;
+ }
+
+ if ((FEATURE + "namespaces").equals(featureId))
+ {
+ namespaces = value;
+ // forcibly prevent illegal parser state
+ if (!namespaces)
+ {
+ xmlNames = true;
+ }
+ return;
+ }
+
+ if ((FEATURE + "external-general-entities").equals(featureId))
+ {
+ extGE = value;
+ return;
+ }
+ if ((FEATURE + "external-parameter-entities").equals(featureId))
+ {
+ extPE = value;
+ return;
+ }
+ if ((FEATURE + "resolve-dtd-uris").equals(featureId))
+ {
+ resolveAll = value;
+ return;
+ }
+
+ if ((FEATURE + "use-entity-resolver2").equals(featureId))
+ {
+ useResolver2 = value;
+ return;
+ }
+
+ throw new SAXNotRecognizedException(featureId);
+ }
+
+ /**
+ * SAX2: Assigns the specified property. Like SAX1 handlers,
+ * these may be changed at any time.
+ */
+ public void setProperty(String propertyId, Object value)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ // see if the property is recognized
+ getProperty(propertyId);
+
+ // Properties with a defined value, we just change it if we can.
+
+ if ((PROPERTY + "declaration-handler").equals(propertyId))
+ {
+ if (value == null)
+ {
+ declHandler = base;
+ }
+ else if (!(value instanceof DeclHandler))
+ {
+ throw new SAXNotSupportedException(propertyId);
+ }
+ else
+ {
+ declHandler = (DeclHandler) value;
+ }
+ return ;
+ }
+
+ if ((PROPERTY + "lexical-handler").equals(propertyId))
+ {
+ if (value == null)
+ {
+ lexicalHandler = base;
+ }
+ else if (!(value instanceof LexicalHandler))
+ {
+ throw new SAXNotSupportedException(propertyId);
+ }
+ else
+ {
+ lexicalHandler = (LexicalHandler) value;
+ }
+ return;
+ }
+
+ throw new SAXNotSupportedException(propertyId);
+ }
+
+ //
+ // This is where the driver receives XmlParser callbacks and translates
+ // them into SAX callbacks. Some more callbacks have been added for
+ // SAX2 support.
+ //
+
+ void startDocument()
+ throws SAXException
+ {
+ contentHandler.setDocumentLocator(this);
+ contentHandler.startDocument();
+ attributesList.clear();
+ }
+
+ void xmlDecl(String version,
+ String encoding,
+ boolean standalone,
+ String inputEncoding)
+ throws SAXException
+ {
+ if (contentHandler instanceof ContentHandler2)
+ {
+ ((ContentHandler2) contentHandler).xmlDecl(version,
+ encoding,
+ standalone,
+ inputEncoding);
+ }
+ }
+
+ void skippedEntity(String name)
+ throws SAXException
+ {
+ contentHandler.skippedEntity(name);
+ }
+
+ InputSource getExternalSubset(String name, String baseURI)
+ throws SAXException, IOException
+ {
+ if (resolver2 == null || !useResolver2 || !extPE)
+ {
+ return null;
+ }
+ return resolver2.getExternalSubset(name, baseURI);
+ }
+
+ InputSource resolveEntity(boolean isPE, String name,
+ InputSource in, String baseURI)
+ throws SAXException, IOException
+ {
+ InputSource source;
+
+ // external entities might be skipped
+ if (isPE && !extPE)
+ {
+ return null;
+ }
+ if (!isPE && !extGE)
+ {
+ return null;
+ }
+
+ // ... or not
+ lexicalHandler.startEntity(name);
+ if (resolver2 != null && useResolver2)
+ {
+ source = resolver2.resolveEntity(name, in.getPublicId(),
+ baseURI, in.getSystemId());
+ if (source == null)
+ {
+ in.setSystemId(absolutize(baseURI,
+ in.getSystemId(), false));
+ source = in;
+ }
+ }
+ else
+ {
+ in.setSystemId(absolutize(baseURI, in.getSystemId(), false));
+ source = entityResolver.resolveEntity(in.getPublicId(),
+ in.getSystemId());
+ if (source == null)
+ {
+ source = in;
+ }
+ }
+ startExternalEntity(name, source.getSystemId(), true);
+ return source;
+ }
+
+ // absolutize a system ID relative to the specified base URI
+ // (temporarily) package-visible for external entity decls
+ String absolutize(String baseURI, String systemId, boolean nice)
+ throws MalformedURLException, SAXException
+ {
+ // FIXME normalize system IDs -- when?
+ // - Convert to UTF-8
+ // - Map reserved and non-ASCII characters to %HH
+
+ try
+ {
+ if (baseURI == null)
+ {
+ if (XmlParser.uriWarnings)
+ {
+ warn ("No base URI; hope this SYSTEM id is absolute: "
+ + systemId);
+ }
+ return new URL(systemId).toString();
+ }
+ else
+ {
+ return new URL(new URL(baseURI), systemId).toString();
+ }
+ }
+ catch (MalformedURLException e)
+ {
+ // Let unknown URI schemes pass through unless we need
+ // the JVM to map them to i/o streams for us...
+ if (!nice)
+ {
+ throw e;
+ }
+
+ // sometimes sysids for notations or unparsed entities
+ // aren't really URIs...
+ warn("Can't absolutize SYSTEM id: " + e.getMessage());
+ return systemId;
+ }
+ }
+
+ void startExternalEntity(String name, String systemId, boolean stackOnly)
+ throws SAXException
+ {
+ // The following warning was deleted because the application has the
+ // option of not setting systemId. Sun's JAXP or Xerces seems to
+ // ignore this case.
+ /*
+ if (systemId == null)
+ warn ("URI was not reported to parser for entity " + name);
+ */
+ if (!stackOnly) // spliced [dtd] needs startEntity
+ {
+ lexicalHandler.startEntity(name);
+ }
+ entityStack.push(systemId);
+ }
+
+ void endExternalEntity(String name)
+ throws SAXException
+ {
+ if (!"[document]".equals(name))
+ {
+ lexicalHandler.endEntity(name);
+ }
+ entityStack.pop();
+ }
+
+ void startInternalEntity(String name)
+ throws SAXException
+ {
+ lexicalHandler.startEntity(name);
+ }
+
+ void endInternalEntity(String name)
+ throws SAXException
+ {
+ lexicalHandler.endEntity(name);
+ }
+
+ void doctypeDecl(String name, String publicId, String systemId)
+ throws SAXException
+ {
+ lexicalHandler.startDTD(name, publicId, systemId);
+
+ // ... the "name" is a declaration and should be given
+ // to the DeclHandler (but sax2 doesn't).
+
+ // the IDs for the external subset are lexical details,
+ // as are the contents of the internal subset; but sax2
+ // doesn't provide the internal subset "pre-parse"
+ }
+
+ void notationDecl(String name, String publicId, String systemId,
+ String baseUri)
+ throws SAXException
+ {
+ try
+ {
+ dtdHandler.notationDecl(name, publicId,
+ (resolveAll && systemId != null)
+ ? absolutize(baseUri, systemId, true)
+ : systemId);
+ }
+ catch (IOException e)
+ {
+ // "can't happen"
+ throw new SAXParseException(e.getMessage(), this, e);
+ }
+ }
+
+ void unparsedEntityDecl(String name, String publicId, String systemId,
+ String baseUri, String notation)
+ throws SAXException
+ {
+ try
+ {
+ dtdHandler.unparsedEntityDecl(name, publicId,
+ resolveAll
+ ? absolutize(baseUri, systemId, true)
+ : systemId,
+ notation);
+ }
+ catch (IOException e)
+ {
+ // "can't happen"
+ throw new SAXParseException(e.getMessage(), this, e);
+ }
+ }
+
+ void endDoctype()
+ throws SAXException
+ {
+ lexicalHandler.endDTD();
+ }
+
+ private void declarePrefix(String prefix, String uri)
+ throws SAXException
+ {
+ int index = uri.indexOf(':');
+
+ // many versions of nwalsh docbook stylesheets
+ // have bogus URLs; so this can't be an error...
+ if (index < 1 && uri.length() != 0)
+ {
+ warn("relative URI for namespace: " + uri);
+ }
+
+ // FIXME: char [0] must be ascii alpha; chars [1..index]
+ // must be ascii alphanumeric or in "+-." [RFC 2396]
+
+ //Namespace Constraints
+ //name for xml prefix must be http://www.w3.org/XML/1998/namespace
+ boolean prefixEquality = prefix.equals("xml");
+ boolean uriEquality = uri.equals("http://www.w3.org/XML/1998/namespace");
+ if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality))
+ {
+ fatal("xml is by definition bound to the namespace name " +
+ "http://www.w3.org/XML/1998/namespace");
+ }
+
+ //xmlns prefix declaration is illegal but xml prefix declaration is llegal...
+ if (prefixEquality && uriEquality)
+ {
+ return;
+ }
+
+ //name for xmlns prefix must be http://www.w3.org/2000/xmlns/
+ prefixEquality = prefix.equals("xmlns");
+ uriEquality = uri.equals("http://www.w3.org/2000/xmlns/");
+ if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality))
+ {
+ fatal("http://www.w3.org/2000/xmlns/ is by definition bound" +
+ " to prefix xmlns");
+ }
+
+ //even if the uri is http://www.w3.org/2000/xmlns/
+ // it is illegal to declare it
+ if (prefixEquality && uriEquality)
+ {
+ fatal ("declaring the xmlns prefix is illegal");
+ }
+
+ uri = uri.intern();
+ prefixStack.declarePrefix(prefix, uri);
+ contentHandler.startPrefixMapping(prefix, uri);
+ }
+
+ void attribute(String qname, String value, boolean isSpecified)
+ throws SAXException
+ {
+ if (!attributes)
+ {
+ attributes = true;
+ if (namespaces)
+ {
+ prefixStack.pushContext();
+ }
+ }
+
+ // process namespace decls immediately;
+ // then maybe forget this as an attribute
+ if (namespaces)
+ {
+ int index;
+
+ // default NS declaration?
+ if (stringInterning)
+ {
+ if ("xmlns" == qname)
+ {
+ declarePrefix("", value);
+ if (!xmlNames)
+ {
+ return;
+ }
+ }
+ // NS prefix declaration?
+ else if ((index = qname.indexOf(':')) == 5
+ && qname.startsWith("xmlns"))
+ {
+ String prefix = qname.substring(6);
+
+ if (prefix.equals(""))
+ {
+ fatal("missing prefix " +
+ "in namespace declaration attribute");
+ }
+ if (value.length() == 0)
+ {
+ verror("missing URI in namespace declaration attribute: "
+ + qname);
+ }
+ else
+ {
+ declarePrefix(prefix, value);
+ }
+ if (!xmlNames)
+ {
+ return;
+ }
+ }
+ }
+ else
+ {
+ if ("xmlns".equals(qname))
+ {
+ declarePrefix("", value);
+ if (!xmlNames)
+ {
+ return;
+ }
+ }
+ // NS prefix declaration?
+ else if ((index = qname.indexOf(':')) == 5
+ && qname.startsWith("xmlns"))
+ {
+ String prefix = qname.substring(6);
+
+ if (value.length() == 0)
+ {
+ verror("missing URI in namespace decl attribute: "
+ + qname);
+ }
+ else
+ {
+ declarePrefix(prefix, value);
+ }
+ if (!xmlNames)
+ {
+ return;
+ }
+ }
+ }
+ }
+ // remember this attribute ...
+ attributeCount++;
+
+ // attribute type comes from querying parser's DTD records
+ attributesList.add(new Attribute(qname, value, isSpecified));
+
+ }
+
+ void startElement(String elname)
+ throws SAXException
+ {
+ ContentHandler handler = contentHandler;
+
+ //
+ // NOTE: this implementation of namespace support adds something
+ // like six percent to parsing CPU time, in a large (~50 MB)
+ // document that doesn't use namespaces at all. (Measured by PC
+ // sampling, with a bug where endElement processing was omitted.)
+ // [Measurement referred to older implementation, older JVM ...]
+ //
+ // It ought to become notably faster in such cases. Most
+ // costs are the prefix stack calling Hashtable.get() (2%),
+ // String.hashCode() (1.5%) and about 1.3% each for pushing
+ // the context, and two chunks of name processing.
+ //
+
+ if (!attributes)
+ {
+ if (namespaces)
+ {
+ prefixStack.pushContext();
+ }
+ }
+ else if (namespaces)
+ {
+
+ // now we can patch up namespace refs; we saw all the
+ // declarations, so now we'll do the Right Thing
+ Iterator itt = attributesList.iterator();
+ while (itt.hasNext())
+ {
+ Attribute attribute = (Attribute) itt.next();
+ String qname = attribute.name;
+ int index;
+
+ // default NS declaration?
+ if (stringInterning)
+ {
+ if ("xmlns" == qname)
+ {
+ continue;
+ }
+ }
+ else
+ {
+ if ("xmlns".equals(qname))
+ {
+ continue;
+ }
+ }
+ //Illegal in the new Namespaces Draft
+ //should it be only in 1.1 docs??
+ if (qname.equals (":"))
+ {
+ fatal("namespace names consisting of a single colon " +
+ "character are invalid");
+ }
+ index = qname.indexOf(':');
+
+ // NS prefix declaration?
+ if (index == 5 && qname.startsWith("xmlns"))
+ {
+ continue;
+ }
+
+ // it's not a NS decl; patch namespace info items
+ if (prefixStack.processName(qname, nsTemp, true) == null)
+ {
+ fatal("undeclared attribute prefix in: " + qname);
+ }
+ else
+ {
+ attribute.nameSpace = nsTemp[0];
+ attribute.localName = nsTemp[1];
+ }
+ }
+ }
+
+ // save element name so attribute callbacks work
+ elementName = elname;
+ if (namespaces)
+ {
+ if (prefixStack.processName(elname, nsTemp, false) == null)
+ {
+ fatal("undeclared element prefix in: " + elname);
+ nsTemp[0] = nsTemp[1] = "";
+ }
+ handler.startElement(nsTemp[0], nsTemp[1], elname, this);
+ }
+ else
+ {
+ handler.startElement("", "", elname, this);
+ }
+ // elementName = null;
+
+ // elements with no attributes are pretty common!
+ if (attributes)
+ {
+ attributesList.clear();
+ attributeCount = 0;
+ attributes = false;
+ }
+ }
+
+ void endElement(String elname)
+ throws SAXException
+ {
+ ContentHandler handler = contentHandler;
+
+ if (!namespaces)
+ {
+ handler.endElement("", "", elname);
+ return;
+ }
+ prefixStack.processName(elname, nsTemp, false);
+ handler.endElement(nsTemp[0], nsTemp[1], elname);
+
+ Enumeration prefixes = prefixStack.getDeclaredPrefixes();
+
+ while (prefixes.hasMoreElements())
+ {
+ handler.endPrefixMapping((String) prefixes.nextElement());
+ }
+ prefixStack.popContext();
+ }
+
+ void startCDATA()
+ throws SAXException
+ {
+ lexicalHandler.startCDATA();
+ }
+
+ void charData(char[] ch, int start, int length)
+ throws SAXException
+ {
+ contentHandler.characters(ch, start, length);
+ }
+
+ void endCDATA()
+ throws SAXException
+ {
+ lexicalHandler.endCDATA();
+ }
+
+ void ignorableWhitespace(char[] ch, int start, int length)
+ throws SAXException
+ {
+ contentHandler.ignorableWhitespace(ch, start, length);
+ }
+
+ void processingInstruction(String target, String data)
+ throws SAXException
+ {
+ contentHandler.processingInstruction(target, data);
+ }
+
+ void comment(char[] ch, int start, int length)
+ throws SAXException
+ {
+ if (lexicalHandler != base)
+ {
+ lexicalHandler.comment(ch, start, length);
+ }
+ }
+
+ void fatal(String message)
+ throws SAXException
+ {
+ SAXParseException fatal;
+
+ fatal = new SAXParseException(message, this);
+ errorHandler.fatalError(fatal);
+
+ // Even if the application can continue ... we can't!
+ throw fatal;
+ }
+
+ // We can safely report a few validity errors that
+ // make layered SAX2 DTD validation more conformant
+ void verror(String message)
+ throws SAXException
+ {
+ SAXParseException err;
+
+ err = new SAXParseException(message, this);
+ errorHandler.error(err);
+ }
+
+ void warn(String message)
+ throws SAXException
+ {
+ SAXParseException err;
+
+ err = new SAXParseException(message, this);
+ errorHandler.warning(err);
+ }
+
+ //
+ // Implementation of org.xml.sax.Attributes.
+ //
+
+ /**
+ * SAX1 AttributeList, SAX2 Attributes method
+ * (don't invoke on parser);
+ */
+ public int getLength()
+ {
+ return attributesList.size();
+ }
+
+ /**
+ * SAX2 Attributes method (don't invoke on parser);
+ */
+ public String getURI(int index)
+ {
+ if (index < 0 || index >= attributesList.size())
+ {
+ return null;
+ }
+ return ((Attribute) attributesList.get(index)).nameSpace;
+ }
+
+ /**
+ * SAX2 Attributes method (don't invoke on parser);
+ */
+ public String getLocalName(int index)
+ {
+ if (index < 0 || index >= attributesList.size())
+ {
+ return null;
+ }
+ Attribute attr = (Attribute) attributesList.get(index);
+ // FIXME attr.localName is sometimes null, why?
+ if (namespaces && attr.localName == null)
+ {
+ // XXX fix this here for now
+ int ci = attr.name.indexOf(':');
+ attr.localName = (ci == -1) ? attr.name :
+ attr.name.substring(ci + 1);
+ }
+ return (attr.localName == null) ? "" : attr.localName;
+ }
+
+ /**
+ * SAX2 Attributes method (don't invoke on parser);
+ */
+ public String getQName(int index)
+ {
+ if (index < 0 || index >= attributesList.size())
+ {
+ return null;
+ }
+ Attribute attr = (Attribute) attributesList.get(index);
+ return (attr.name == null) ? "" : attr.name;
+ }
+
+ /**
+ * SAX1 AttributeList method (don't invoke on parser);
+ */
+ public String getName(int index)
+ {
+ return getQName(index);
+ }
+
+ /**
+ * SAX1 AttributeList, SAX2 Attributes method
+ * (don't invoke on parser);
+ */
+ public String getType(int index)
+ {
+ if (index < 0 || index >= attributesList.size())
+ {
+ return null;
+ }
+ String type = parser.getAttributeType(elementName, getQName(index));
+ if (type == null)
+ {
+ return "CDATA";
+ }
+ // ... use DeclHandler.attributeDecl to see enumerations
+ if (type == "ENUMERATION")
+ {
+ return "NMTOKEN";
+ }
+ return type;
+ }
+
+ /**
+ * SAX1 AttributeList, SAX2 Attributes method
+ * (don't invoke on parser);
+ */
+ public String getValue(int index)
+ {
+ if (index < 0 || index >= attributesList.size())
+ {
+ return null;
+ }
+ return ((Attribute) attributesList.get(index)).value;
+ }
+
+ /**
+ * SAX2 Attributes method (don't invoke on parser);
+ */
+ public int getIndex(String uri, String local)
+ {
+ int length = getLength();
+
+ for (int i = 0; i < length; i++)
+ {
+ if (!getURI(i).equals(uri))
+ {
+ continue;
+ }
+ if (getLocalName(i).equals(local))
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * SAX2 Attributes method (don't invoke on parser);
+ */
+ public int getIndex(String xmlName)
+ {
+ int length = getLength();
+
+ for (int i = 0; i < length; i++)
+ {
+ if (getQName(i).equals(xmlName))
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * SAX2 Attributes method (don't invoke on parser);
+ */
+ public String getType(String uri, String local)
+ {
+ int index = getIndex(uri, local);
+
+ if (index < 0)
+ {
+ return null;
+ }
+ return getType(index);
+ }
+
+ /**
+ * SAX1 AttributeList, SAX2 Attributes method
+ * (don't invoke on parser);
+ */
+ public String getType(String xmlName)
+ {
+ int index = getIndex(xmlName);
+
+ if (index < 0)
+ {
+ return null;
+ }
+ return getType(index);
+ }
+
+ /**
+ * SAX Attributes method (don't invoke on parser);
+ */
+ public String getValue(String uri, String local)
+ {
+ int index = getIndex(uri, local);
+
+ if (index < 0)
+ {
+ return null;
+ }
+ return getValue(index);
+ }
+
+ /**
+ * SAX1 AttributeList, SAX2 Attributes method
+ * (don't invoke on parser);
+ */
+ public String getValue(String xmlName)
+ {
+ int index = getIndex(xmlName);
+
+ if (index < 0)
+ {
+ return null;
+ }
+ return getValue(index);
+ }
+
+ //
+ // Implementation of org.xml.sax.ext.Attributes2
+ //
+
+ /** @return false unless the attribute was declared in the DTD.
+ * @throws java.lang.ArrayIndexOutOfBoundsException
+ * When the supplied index does not identify an attribute.
+ */
+ public boolean isDeclared(int index)
+ {
+ if (index < 0 || index >= attributeCount)
+ {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ String type = parser.getAttributeType(elementName, getQName(index));
+ return (type != null);
+ }
+
+ /** @return false unless the attribute was declared in the DTD.
+ * @throws java.lang.IllegalArgumentException
+ * When the supplied names do not identify an attribute.
+ */
+ public boolean isDeclared(String qName)
+ {
+ int index = getIndex(qName);
+ if (index < 0)
+ {
+ throw new IllegalArgumentException();
+ }
+ String type = parser.getAttributeType(elementName, qName);
+ return (type != null);
+ }
+
+ /** @return false unless the attribute was declared in the DTD.
+ * @throws java.lang.IllegalArgumentException
+ * When the supplied names do not identify an attribute.
+ */
+ public boolean isDeclared(String uri, String localName)
+ {
+ int index = getIndex(uri, localName);
+ return isDeclared(index);
+ }
+
+ /**
+ * SAX-ext Attributes2 method (don't invoke on parser);
+ */
+ public boolean isSpecified(int index)
+ {
+ return ((Attribute) attributesList.get(index)).specified;
+ }
+
+ /**
+ * SAX-ext Attributes2 method (don't invoke on parser);
+ */
+ public boolean isSpecified(String uri, String local)
+ {
+ int index = getIndex (uri, local);
+ return isSpecified(index);
+ }
+
+ /**
+ * SAX-ext Attributes2 method (don't invoke on parser);
+ */
+ public boolean isSpecified(String xmlName)
+ {
+ int index = getIndex (xmlName);
+ return isSpecified(index);
+ }
+
+ //
+ // Implementation of org.xml.sax.Locator.
+ //
+
+ /**
+ * SAX Locator method (don't invoke on parser);
+ */
+ public String getPublicId()
+ {
+ return null; // FIXME track public IDs too
+ }
+
+ /**
+ * SAX Locator method (don't invoke on parser);
+ */
+ public String getSystemId()
+ {
+ if (entityStack.empty())
+ {
+ return null;
+ }
+ else
+ {
+ return (String) entityStack.peek();
+ }
+ }
+
+ /**
+ * SAX Locator method (don't invoke on parser);
+ */
+ public int getLineNumber()
+ {
+ return parser.getLineNumber();
+ }
+
+ /**
+ * SAX Locator method (don't invoke on parser);
+ */
+ public int getColumnNumber()
+ {
+ return parser.getColumnNumber();
+ }
+
+ // adapter between SAX2 content handler and SAX1 document handler callbacks
+ private static class Adapter
+ implements ContentHandler
+ {
+
+ private DocumentHandler docHandler;
+
+ Adapter(DocumentHandler dh)
+ {
+ docHandler = dh;
+ }
+
+ public void setDocumentLocator(Locator l)
+ {
+ docHandler.setDocumentLocator(l);
+ }
+
+ public void startDocument()
+ throws SAXException
+ {
+ docHandler.startDocument();
+ }
+
+ public void processingInstruction(String target, String data)
+ throws SAXException
+ {
+ docHandler.processingInstruction(target, data);
+ }
+
+ public void startPrefixMapping(String prefix, String uri)
+ {
+ /* ignored */
+ }
+
+ public void startElement(String namespace,
+ String local,
+ String name,
+ Attributes attrs)
+ throws SAXException
+ {
+ docHandler.startElement(name, (AttributeList) attrs);
+ }
+
+ public void characters(char[] buf, int offset, int len)
+ throws SAXException
+ {
+ docHandler.characters(buf, offset, len);
+ }
+
+ public void ignorableWhitespace(char[] buf, int offset, int len)
+ throws SAXException
+ {
+ docHandler.ignorableWhitespace(buf, offset, len);
+ }
+
+ public void skippedEntity(String name)
+ {
+ /* ignored */
+ }
+
+ public void endElement(String u, String l, String name)
+ throws SAXException
+ {
+ docHandler.endElement(name);
+ }
+
+ public void endPrefixMapping(String prefix)
+ {
+ /* ignored */
+ }
+
+ public void endDocument()
+ throws SAXException
+ {
+ docHandler.endDocument();
+ }
+ }
+
+ private static class Attribute
+ {
+
+ String name;
+ String value;
+ String nameSpace;
+ String localName;
+ boolean specified;
+
+ Attribute(String name, String value, boolean specified)
+ {
+ this.name = name;
+ this.value = value;
+ this.nameSpace = "";
+ this.specified = specified;
+ }
+
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/aelfred2/XmlParser.java b/libjava/classpath/gnu/xml/aelfred2/XmlParser.java
new file mode 100644
index 0000000..f2abb88
--- /dev/null
+++ b/libjava/classpath/gnu/xml/aelfred2/XmlParser.java
@@ -0,0 +1,5835 @@
+/* XmlParser.java --
+ Copyright (C) 1999,2000,2001 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.
+
+Partly derived from code which carried the following notice:
+
+ Copyright (c) 1997, 1998 by Microstar Software Ltd.
+
+ AElfred is free for both commercial and non-commercial use and
+ redistribution, provided that Microstar's copyright and disclaimer are
+ retained intact. You are free to modify AElfred for your own use and
+ to redistribute AElfred with your modifications, provided that the
+ modifications are clearly documented.
+
+ This program 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. Please use it AT
+ YOUR OWN RISK.
+*/
+
+package gnu.xml.aelfred2;
+
+import gnu.java.security.action.GetPropertyAction;
+
+import java.io.BufferedInputStream;
+import java.io.CharConversionException;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.AccessController;
+
+import java.util.Iterator;
+import java.util.HashMap;
+import java.util.LinkedList;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Parse XML documents and return parse events through call-backs.
+ * Use the Only one thread at a time may use this parser; since it is
+ * private to this package, post-parse cleanup is done by the caller,
+ * which MUST NOT REUSE the parser (just null it).
+ *
+ * @param systemId Absolute URI of the document; should never be null,
+ * but may be so iff a reader or a stream is provided.
+ * @param publicId The public identifier of the document, or null.
+ * @param reader A character stream; must be null if stream isn't.
+ * @param stream A byte input stream; must be null if reader isn't.
+ * @param encoding The suggested encoding, or null if unknown.
+ * @exception java.lang.Exception Basically SAXException or IOException
+ */
+ // package private
+ void doParse(String systemId, String publicId, Reader reader,
+ InputStream stream, String encoding)
+ throws Exception
+ {
+ if (handler == null)
+ {
+ throw new IllegalStateException("no callback handler");
+ }
+
+ initializeVariables();
+
+ // predeclare the built-in entities here (replacement texts)
+ // we don't need to intern(), since we're guaranteed literals
+ // are always (globally) interned.
+ setInternalEntity("amp", "&");
+ setInternalEntity("lt", "<");
+ setInternalEntity("gt", ">");
+ setInternalEntity("apos", "'");
+ setInternalEntity("quot", """);
+
+ try
+ {
+ // pushURL first to ensure locator is correct in startDocument
+ // ... it might report an IO or encoding exception.
+ handler.startDocument();
+ pushURL(false, "[document]",
+ // default baseURI: null
+ new ExternalIdentifiers(publicId, systemId, null),
+ reader, stream, encoding, false);
+
+ parseDocument();
+ }
+ catch (EOFException e)
+ {
+ //empty input
+ error("empty document, with no root element.");
+ }
+ finally
+ {
+ if (reader != null)
+ {
+ try
+ {
+ reader.close();
+ }
+ catch (IOException e)
+ {
+ /* ignore */
+ }
+ }
+ if (stream != null)
+ {
+ try
+ {
+ stream.close();
+ }
+ catch (IOException e)
+ {
+ /* ignore */
+ }
+ }
+ if (is != null)
+ {
+ try
+ {
+ is.close();
+ }
+ catch (IOException e)
+ {
+ /* ignore */
+ }
+ }
+ scratch = null;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // Error reporting.
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Report an error.
+ * @param message The error message.
+ * @param textFound The text that caused the error (or null).
+ * @see SAXDriver#error
+ * @see #line
+ */
+ private void error(String message, String textFound, String textExpected)
+ throws SAXException
+ {
+ if (textFound != null)
+ {
+ message = message + " (found \"" + textFound + "\")";
+ }
+ if (textExpected != null)
+ {
+ message = message + " (expected \"" + textExpected + "\")";
+ }
+ handler.fatal(message);
+
+ // "can't happen"
+ throw new SAXException(message);
+ }
+
+ /**
+ * Report a serious error.
+ * @param message The error message.
+ * @param textFound The text that caused the error (or null).
+ */
+ private void error(String message, char textFound, String textExpected)
+ throws SAXException
+ {
+ error(message, new Character(textFound).toString(), textExpected);
+ }
+
+ /**
+ * Report typical case fatal errors.
+ */
+ private void error(String message)
+ throws SAXException
+ {
+ handler.fatal(message);
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // Major syntactic productions.
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Parse an XML document.
+ * This is the top-level parsing function for a single XML
+ * document. As a minimum, a well-formed document must have
+ * a document element, and a valid document must have a prolog
+ * (one with doctype) as well.
+ */
+ private void parseDocument()
+ throws Exception
+ {
+ try
+ { // added by MHK
+ boolean sawDTD = parseProlog();
+ require('<');
+ parseElement(!sawDTD);
+ }
+ catch (EOFException ee)
+ { // added by MHK
+ error("premature end of file", "[EOF]", null);
+ }
+
+ try
+ {
+ parseMisc(); //skip all white, PIs, and comments
+ char c = readCh(); //if this doesn't throw an exception...
+ error("unexpected characters after document end", c, null);
+ }
+ catch (EOFException e)
+ {
+ return;
+ }
+ }
+
+ static final char[] startDelimComment = { '<', '!', '-', '-' };
+ static final char[] endDelimComment = { '-', '-' };
+
+ /**
+ * Skip a comment.
+ * (The (The (The '<![CDATA[' has already been read.)
+ */
+ private void parseCDSect()
+ throws Exception
+ {
+ parseUntil(endDelimCDATA);
+ dataBufferFlush();
+ }
+
+ /**
+ * Parse the prolog of an XML document.
+ * We do not look for the XML declaration here, because it was
+ * handled by pushURL ().
+ * @see pushURL
+ * @return true if a DTD was read.
+ */
+ private boolean parseProlog()
+ throws Exception
+ {
+ parseMisc();
+
+ if (tryRead("
+ * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
+ * [24] VersionInfo ::= S 'version' Eq
+ * ("'" VersionNum "'" | '"' VersionNum '"' )
+ * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')*
+ * [32] SDDecl ::= S 'standalone' Eq
+ * ( "'"" ('yes' | 'no') "'"" | '"' ("yes" | "no") '"' )
+ * [80] EncodingDecl ::= S 'encoding' Eq
+ * ( "'" EncName "'" | "'" EncName "'" )
+ * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
+ *
+ * (The (The It is also used after autodetection, at which point only very
+ * limited adjustments to the encoding may be used (switching between
+ * related builtin decoders).
+ *
+ * @param encodingName The name of the encoding specified by the user.
+ * @exception IOException if the encoding isn't supported either
+ * internally to this parser, or by the hosting JVM.
+ * @see #parseXMLDecl
+ * @see #parseTextDecl
+ */
+ private void setupDecoding(String encodingName)
+ throws SAXException, IOException
+ {
+ encodingName = encodingName.toUpperCase();
+
+ // ENCODING_EXTERNAL indicates an encoding that wasn't
+ // autodetected ... we can use builtin decoders, or
+ // ones from the JVM (InputStreamReader).
+
+ // Otherwise we can only tweak what was autodetected, and
+ // only for single byte (ASCII derived) builtin encodings.
+
+ // ASCII-derived encodings
+ if (encoding == ENCODING_UTF_8 || encoding == ENCODING_EXTERNAL)
+ {
+ if (encodingName.equals("ISO-8859-1")
+ || encodingName.equals("8859_1")
+ || encodingName.equals("ISO8859_1"))
+ {
+ encoding = ENCODING_ISO_8859_1;
+ return;
+ }
+ else if (encodingName.equals("US-ASCII")
+ || encodingName.equals("ASCII"))
+ {
+ encoding = ENCODING_ASCII;
+ return;
+ }
+ else if (encodingName.equals("UTF-8")
+ || encodingName.equals("UTF8"))
+ {
+ encoding = ENCODING_UTF_8;
+ return;
+ }
+ else if (encoding != ENCODING_EXTERNAL)
+ {
+ // used to start with a new reader ...
+ throw new UnsupportedEncodingException(encodingName);
+ }
+ // else fallthrough ...
+ // it's ASCII-ish and something other than a builtin
+ }
+
+ // Unicode and such
+ if (encoding == ENCODING_UCS_2_12 || encoding == ENCODING_UCS_2_21)
+ {
+ if (!(encodingName.equals("ISO-10646-UCS-2")
+ || encodingName.equals("UTF-16")
+ || encodingName.equals("UTF-16BE")
+ || encodingName.equals("UTF-16LE")))
+ {
+ error("unsupported Unicode encoding", encodingName, "UTF-16");
+ }
+ return;
+ }
+
+ // four byte encodings
+ if (encoding == ENCODING_UCS_4_1234
+ || encoding == ENCODING_UCS_4_4321
+ || encoding == ENCODING_UCS_4_2143
+ || encoding == ENCODING_UCS_4_3412)
+ {
+ // Strictly: "UCS-4" == "UTF-32BE"; also, "UTF-32LE" exists
+ if (!encodingName.equals("ISO-10646-UCS-4"))
+ {
+ error("unsupported 32-bit encoding", encodingName,
+ "ISO-10646-UCS-4");
+ }
+ return;
+ }
+
+ // assert encoding == ENCODING_EXTERNAL
+ // if (encoding != ENCODING_EXTERNAL)
+ // throw new RuntimeException ("encoding = " + encoding);
+
+ if (encodingName.equals("UTF-16BE"))
+ {
+ encoding = ENCODING_UCS_2_12;
+ return;
+ }
+ if (encodingName.equals("UTF-16LE"))
+ {
+ encoding = ENCODING_UCS_2_21;
+ return;
+ }
+
+ // We couldn't use the builtin decoders at all. But we can try to
+ // create a reader, since we haven't messed up buffering. Tweak
+ // the encoding name if necessary.
+
+ if (encodingName.equals("UTF-16")
+ || encodingName.equals("ISO-10646-UCS-2"))
+ {
+ encodingName = "Unicode";
+ }
+ // Ignoring all the EBCDIC aliases here
+
+ reader = new InputStreamReader(is, encodingName);
+ sourceType = INPUT_READER;
+ }
+
+ /**
+ * Parse miscellaneous markup outside the document element and DOCTYPE
+ * declaration.
+ * (The Reading toplevel PE references is handled as a lexical issue
+ * by the caller, as is whitespace.
+ */
+ private void parseMarkupdecl()
+ throws Exception
+ {
+ char[] saved = null;
+ boolean savedPE = expandPE;
+
+ // prevent "<%foo;" and ensures saved entity is right
+ require('<');
+ unread('<');
+ expandPE = false;
+
+ if (tryRead(" 0)
+ {
+ parseConditionalSect(saved);
+ }
+ else
+ {
+ error("conditional sections illegal in internal subset");
+ }
+ }
+ else
+ {
+ error("expected markup declaration");
+ }
+
+ // VC: Proper Decl/PE Nesting
+ if (readBuffer != saved)
+ {
+ handler.verror("Illegal Declaration/PE nesting");
+ }
+ }
+
+ /**
+ * Parse an element, with its tags.
+ * (The '<' has already been read.)
+ * NOTE: this method actually chains onto parseContent (), if necessary,
+ * and parseContent () will take care of calling parseETag ().
+ */
+ private void parseElement(boolean maybeGetSubset)
+ throws Exception
+ {
+ String gi;
+ char c;
+ int oldElementContent = currentElementContent;
+ String oldElement = currentElement;
+ ElementDecl element;
+
+ // This is the (global) counter for the
+ // array of specified attributes.
+ tagAttributePos = 0;
+
+ // Read the element type name.
+ gi = readNmtoken(true);
+
+ // If we saw no DTD, and this is the document root element,
+ // let the application modify the input stream by providing one.
+ if (maybeGetSubset)
+ {
+ InputSource subset = handler.getExternalSubset(gi,
+ handler.getSystemId());
+ if (subset != null)
+ {
+ String publicId = subset.getPublicId();
+ String systemId = subset.getSystemId();
+
+ handler.warn("modifying document by adding DTD");
+ handler.doctypeDecl(gi, publicId, systemId);
+ pushString(null, ">");
+
+ // NOTE: [dtd] is so we say what SAX2 expects,
+ // though it's misleading (subset, not entire dtd)
+ pushURL(true, "[dtd]",
+ new ExternalIdentifiers(publicId, systemId, null),
+ subset.getCharacterStream(),
+ subset.getByteStream(),
+ subset.getEncoding(),
+ false);
+
+ // Loop until we end up back at '>'
+ while (true)
+ {
+ doReport = expandPE = true;
+ skipWhitespace();
+ doReport = expandPE = false;
+ if (tryRead('>'))
+ {
+ break;
+ }
+ else
+ {
+ expandPE = true;
+ parseMarkupdecl();
+ expandPE = false;
+ }
+ }
+
+ // the ">" string isn't popped yet
+ if (inputStack.size() != 1)
+ {
+ error("external subset has unmatched '>'");
+ }
+
+ handler.endDoctype();
+ }
+ }
+
+ // Determine the current content type.
+ currentElement = gi;
+ element = (ElementDecl) elementInfo.get(gi);
+ currentElementContent = getContentType(element, CONTENT_ANY);
+
+ // Read the attributes, if any.
+ // After this loop, "c" is the closing delimiter.
+ boolean white = tryWhitespace();
+ c = readCh();
+ while (c != '/' && c != '>')
+ {
+ unread(c);
+ if (!white)
+ {
+ error("need whitespace between attributes");
+ }
+ parseAttribute(gi);
+ white = tryWhitespace();
+ c = readCh();
+ }
+
+ // Supply any defaulted attributes.
+ Iterator atts = declaredAttributes(element);
+ if (atts != null)
+ {
+ String aname;
+loop:
+ while (atts.hasNext())
+ {
+ aname = (String) atts.next();
+ // See if it was specified.
+ for (int i = 0; i < tagAttributePos; i++)
+ {
+ if (tagAttributes[i] == aname)
+ {
+ continue loop;
+ }
+ }
+ // ... or has a default
+ String value = getAttributeDefaultValue(gi, aname);
+
+ if (value == null)
+ {
+ continue;
+ }
+ handler.attribute(aname, value, false);
+ }
+ }
+
+ // Figure out if this is a start tag
+ // or an empty element, and dispatch an
+ // event accordingly.
+ switch (c)
+ {
+ case '>':
+ handler.startElement(gi);
+ parseContent();
+ break;
+ case '/':
+ require('>');
+ handler.startElement(gi);
+ handler.endElement(gi);
+ break;
+ }
+
+ // Restore the previous state.
+ currentElement = oldElement;
+ currentElementContent = oldElementContent;
+ }
+
+ /**
+ * Parse an attribute assignment.
+ * NOTE: parseContent () chains to here, we already read the
+ * "</".
+ */
+ private void parseETag()
+ throws Exception
+ {
+ require(currentElement);
+ skipWhitespace();
+ require('>');
+ handler.endElement(currentElement);
+ // not re-reporting any SAXException re bogus end tags,
+ // even though that diagnostic might be clearer ...
+ }
+
+ /**
+ * Parse the content of an element.
+ * NOTE: consumes ETtag.
+ */
+ private void parseContent()
+ throws Exception
+ {
+ char c;
+
+ while (true)
+ {
+ // consume characters (or ignorable whitspace) until delimiter
+ parseCharData();
+
+ // Handle delimiters
+ c = readCh();
+ switch (c)
+ {
+ case '&': // Found "&"
+ c = readCh();
+ if (c == '#')
+ {
+ parseCharRef();
+ }
+ else
+ {
+ unread(c);
+ parseEntityRef(true);
+ }
+ isDirtyCurrentElement = true;
+ break;
+
+ case '<': // Found "<"
+ dataBufferFlush();
+ c = readCh();
+ switch (c)
+ {
+ case '!': // Found "
+ * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
+ *
+ * NOTE: the '<!ELEMENT' has already been read.
+ */
+ private void parseElementDecl()
+ throws Exception
+ {
+ String name;
+
+ requireWhitespace();
+ // Read the element type name.
+ name = readNmtoken(true);
+
+ requireWhitespace();
+ // Read the content model.
+ parseContentspec(name);
+
+ skipWhitespace();
+ require('>');
+ }
+
+ /**
+ * Content specification.
+ * NOTE: the opening '(' and S have already been read.
+ *
+ * @param saved Buffer for entity that should have the terminal ')'
+ */
+ private void parseElements(char[] saved)
+ throws Exception
+ {
+ char c;
+ char sep;
+
+ // Parse the first content particle
+ skipWhitespace();
+ parseCp();
+
+ // Check for end or for a separator.
+ skipWhitespace();
+ c = readCh();
+ switch (c)
+ {
+ case ')':
+ // VC: Proper Group/PE Nesting
+ if (readBuffer != saved)
+ {
+ handler.verror("Illegal Group/PE nesting");
+ }
+
+ dataBufferAppend(')');
+ c = readCh();
+ switch (c)
+ {
+ case '*':
+ case '+':
+ case '?':
+ dataBufferAppend(c);
+ break;
+ default:
+ unread(c);
+ }
+ return;
+ case ',': // Register the separator.
+ case '|':
+ sep = c;
+ dataBufferAppend(c);
+ break;
+ default:
+ error("bad separator in content model", c, null);
+ return;
+ }
+
+ // Parse the rest of the content model.
+ while (true)
+ {
+ skipWhitespace();
+ parseCp();
+ skipWhitespace();
+ c = readCh();
+ if (c == ')')
+ {
+ // VC: Proper Group/PE Nesting
+ if (readBuffer != saved)
+ {
+ handler.verror("Illegal Group/PE nesting");
+ }
+
+ dataBufferAppend(')');
+ break;
+ }
+ else if (c != sep)
+ {
+ error("bad separator in content model", c, null);
+ return;
+ }
+ else
+ {
+ dataBufferAppend(c);
+ }
+ }
+
+ // Check for the occurrence indicator.
+ c = readCh();
+ switch (c)
+ {
+ case '?':
+ case '*':
+ case '+':
+ dataBufferAppend(c);
+ return;
+ default:
+ unread(c);
+ return;
+ }
+ }
+
+ /**
+ * Parse a content particle.
+ * NOTE: the '<!ATTLIST' has already been read.
+ */
+ private void parseAttlistDecl()
+ throws Exception
+ {
+ String elementName;
+
+ requireWhitespace();
+ elementName = readNmtoken(true);
+ boolean white = tryWhitespace();
+ while (!tryRead('>'))
+ {
+ if (!white)
+ {
+ error("whitespace required before attribute definition");
+ }
+ parseAttDef(elementName);
+ white = tryWhitespace();
+ }
+ }
+
+ /**
+ * Parse a single attribute definition.
+ * NOTE: the '(' has already been read.
+ */
+ private void parseEnumeration(boolean isNames)
+ throws Exception
+ {
+ dataBufferAppend('(');
+
+ // Read the first token.
+ skipWhitespace();
+ dataBufferAppend(readNmtoken(isNames));
+ // Read the remaining tokens.
+ skipWhitespace();
+ while (!tryRead(')'))
+ {
+ require('|');
+ dataBufferAppend('|');
+ skipWhitespace();
+ dataBufferAppend(readNmtoken (isNames));
+ skipWhitespace();
+ }
+ dataBufferAppend(')');
+ }
+
+ /**
+ * Parse a notation type for an attribute.
+ * NOTE: the 'NOTATION' has already been read
+ */
+ private void parseNotationType()
+ throws Exception
+ {
+ requireWhitespace();
+ require('(');
+
+ parseEnumeration(true);
+ }
+
+ /**
+ * Parse the default value for an attribute.
+ * NOTE: the '>![' has already been read.
+ */
+ private void parseConditionalSect(char[] saved)
+ throws Exception
+ {
+ skipWhitespace();
+ if (tryRead("INCLUDE"))
+ {
+ skipWhitespace();
+ require('[');
+ // VC: Proper Conditional Section/PE Nesting
+ if (readBuffer != saved)
+ {
+ handler.verror("Illegal Conditional Section/PE nesting");
+ }
+ skipWhitespace();
+ while (!tryRead("]]>"))
+ {
+ parseMarkupdecl();
+ skipWhitespace();
+ }
+ }
+ else if (tryRead("IGNORE"))
+ {
+ skipWhitespace();
+ require('[');
+ // VC: Proper Conditional Section/PE Nesting
+ if (readBuffer != saved)
+ {
+ handler.verror("Illegal Conditional Section/PE nesting");
+ }
+ int nesting = 1;
+ char c;
+ expandPE = false;
+ for (int nest = 1; nest > 0; )
+ {
+ c = readCh();
+ switch (c)
+ {
+ case '<':
+ if (tryRead("!["))
+ {
+ nest++;
+ }
+ case ']':
+ if (tryRead("]>"))
+ {
+ nest--;
+ }
+ }
+ }
+ expandPE = true;
+ }
+ else
+ {
+ error("conditional section must begin with INCLUDE or IGNORE");
+ }
+ }
+
+ private void parseCharRef()
+ throws SAXException, IOException
+ {
+ parseCharRef(true /* do flushDataBuffer by default */);
+ }
+
+ /**
+ * Try to read a character reference without consuming data from buffer.
+ * NOTE: the '' has already been read.
+ */
+ private void tryReadCharRef()
+ throws SAXException, IOException
+ {
+ int value = 0;
+ char c;
+
+ if (tryRead('x'))
+ {
+loop1:
+ while (true)
+ {
+ c = readCh();
+ if (c == ';')
+ {
+ break loop1;
+ }
+ else
+ {
+ int n = Character.digit(c, 16);
+ if (n == -1)
+ {
+ error("illegal character in character reference", c, null);
+ break loop1;
+ }
+ value *= 16;
+ value += n;
+ }
+ }
+ }
+ else
+ {
+loop2:
+ while (true)
+ {
+ c = readCh();
+ if (c == ';')
+ {
+ break loop2;
+ }
+ else
+ {
+ int n = Character.digit(c, 10);
+ if (n == -1)
+ {
+ error("illegal character in character reference", c, null);
+ break loop2;
+ }
+ value *= 10;
+ value += n;
+ }
+ }
+ }
+
+ // check for character refs being legal XML
+ if ((value < 0x0020
+ && ! (value == '\n' || value == '\t' || value == '\r'))
+ || (value >= 0xD800 && value <= 0xDFFF)
+ || value == 0xFFFE || value == 0xFFFF
+ || value > 0x0010ffff)
+ {
+ error("illegal XML character reference U+"
+ + Integer.toHexString(value));
+ }
+
+ // Check for surrogates: 00000000 0000xxxx yyyyyyyy zzzzzzzz
+ // (1101|10xx|xxyy|yyyy + 1101|11yy|zzzz|zzzz:
+ if (value > 0x0010ffff)
+ {
+ // too big for surrogate
+ error("character reference " + value + " is too large for UTF-16",
+ new Integer(value).toString(), null);
+ }
+
+ }
+
+ /**
+ * Read and interpret a character reference.
+ * NOTE: the '' has already been read.
+ */
+ private void parseCharRef(boolean doFlush)
+ throws SAXException, IOException
+ {
+ int value = 0;
+ char c;
+
+ if (tryRead('x'))
+ {
+loop1:
+ while (true)
+ {
+ c = readCh();
+ if (c == ';')
+ {
+ break loop1;
+ }
+ else
+ {
+ int n = Character.digit(c, 16);
+ if (n == -1)
+ {
+ error("illegal character in character reference", c, null);
+ break loop1;
+ }
+ value *= 16;
+ value += n;
+ }
+ }
+ }
+ else
+ {
+loop2:
+ while (true)
+ {
+ c = readCh();
+ if (c == ';')
+ {
+ break loop2;
+ }
+ else
+ {
+ int n = Character.digit(c, 10);
+ if (n == -1)
+ {
+ error("illegal character in character reference", c, null);
+ break loop2;
+ }
+ value *= 10;
+ value += c - '0';
+ }
+ }
+ }
+
+ // check for character refs being legal XML
+ if ((value < 0x0020
+ && ! (value == '\n' || value == '\t' || value == '\r'))
+ || (value >= 0xD800 && value <= 0xDFFF)
+ || value == 0xFFFE || value == 0xFFFF
+ || value > 0x0010ffff)
+ {
+ error("illegal XML character reference U+"
+ + Integer.toHexString(value));
+ }
+
+ // Check for surrogates: 00000000 0000xxxx yyyyyyyy zzzzzzzz
+ // (1101|10xx|xxyy|yyyy + 1101|11yy|zzzz|zzzz:
+ if (value <= 0x0000ffff)
+ {
+ // no surrogates needed
+ dataBufferAppend((char) value);
+ }
+ else if (value <= 0x0010ffff)
+ {
+ value -= 0x10000;
+ // > 16 bits, surrogate needed
+ dataBufferAppend((char) (0xd800 | (value >> 10)));
+ dataBufferAppend((char) (0xdc00 | (value & 0x0003ff)));
+ }
+ else
+ {
+ // too big for surrogate
+ error("character reference " + value + " is too large for UTF-16",
+ new Integer(value).toString(), null);
+ }
+ if (doFlush)
+ {
+ dataBufferFlush();
+ }
+ }
+
+ /**
+ * Parse and expand an entity reference.
+ * NOTE: the '&' has already been read.
+ * @param externalAllowed External entities are allowed here.
+ */
+ private void parseEntityRef(boolean externalAllowed)
+ throws SAXException, IOException
+ {
+ String name;
+
+ name = readNmtoken(true);
+ require(';');
+ switch (getEntityType(name))
+ {
+ case ENTITY_UNDECLARED:
+ // NOTE: XML REC describes amazingly convoluted handling for
+ // this case. Nothing as meaningful as being a WFness error
+ // unless the processor might _legitimately_ not have seen a
+ // declaration ... which is what this implements.
+ String message;
+
+ message = "reference to undeclared general entity " + name;
+ if (skippedPE && !docIsStandalone)
+ {
+ handler.verror(message);
+ // we don't know this entity, and it might be external...
+ if (externalAllowed)
+ {
+ handler.skippedEntity(name);
+ }
+ }
+ else
+ {
+ error(message);
+ }
+ break;
+ case ENTITY_INTERNAL:
+ pushString(name, getEntityValue(name));
+
+ //workaround for possible input pop before marking
+ //the buffer reading position
+ char t = readCh();
+ unread(t);
+ int bufferPosMark = readBufferPos;
+
+ int end = readBufferPos + getEntityValue(name).length();
+ for (int k = readBufferPos; k < end; k++)
+ {
+ t = readCh();
+ if (t == '&')
+ {
+ t = readCh();
+ if (t == '#')
+ {
+ //try to match a character ref
+ tryReadCharRef();
+
+ //everything has been read
+ if (readBufferPos >= end)
+ {
+ break;
+ }
+ k = readBufferPos;
+ continue;
+ }
+ else if (Character.isLetter(t))
+ {
+ //looks like an entity ref
+ unread(t);
+ readNmtoken(true);
+ require(';');
+
+ //everything has been read
+ if (readBufferPos >= end)
+ {
+ break;
+ }
+ k = readBufferPos;
+ continue;
+ }
+ error(" malformed entity reference");
+ }
+
+ }
+ readBufferPos = bufferPosMark;
+ break;
+ case ENTITY_TEXT:
+ if (externalAllowed)
+ {
+ pushURL(false, name, getEntityIds(name),
+ null, null, null, true);
+ }
+ else
+ {
+ error("reference to external entity in attribute value.",
+ name, null);
+ }
+ break;
+ case ENTITY_NDATA:
+ if (externalAllowed)
+ {
+ error("unparsed entity reference in content", name, null);
+ }
+ else
+ {
+ error("reference to external entity in attribute value.",
+ name, null);
+ }
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+
+ /**
+ * Parse and expand a parameter entity reference.
+ * NOTE: the '%' has already been read.
+ */
+ private void parsePEReference()
+ throws SAXException, IOException
+ {
+ String name;
+
+ name = "%" + readNmtoken(true);
+ require(';');
+ switch (getEntityType(name))
+ {
+ case ENTITY_UNDECLARED:
+ // VC: Entity Declared
+ handler.verror("reference to undeclared parameter entity " + name);
+
+ // we should disable handling of all subsequent declarations
+ // unless this is a standalone document (info discarded)
+ break;
+ case ENTITY_INTERNAL:
+ if (inLiteral)
+ {
+ pushString(name, getEntityValue(name));
+ }
+ else
+ {
+ pushString(name, ' ' + getEntityValue(name) + ' ');
+ }
+ break;
+ case ENTITY_TEXT:
+ if (!inLiteral)
+ {
+ pushString(null, " ");
+ }
+ pushURL(true, name, getEntityIds(name), null, null, null, true);
+ if (!inLiteral)
+ {
+ pushString(null, " ");
+ }
+ break;
+ }
+ }
+
+ /**
+ * Parse an entity declaration.
+ * NOTE: the '<!ENTITY' has already been read.
+ */
+ private void parseEntityDecl()
+ throws Exception
+ {
+ boolean peFlag = false;
+ int flags = 0;
+
+ // Check for a parameter entity.
+ expandPE = false;
+ requireWhitespace();
+ if (tryRead('%'))
+ {
+ peFlag = true;
+ requireWhitespace();
+ }
+ expandPE = true;
+
+ // Read the entity name, and prepend
+ // '%' if necessary.
+ String name = readNmtoken(true);
+ //NE08
+ if (name.indexOf(':') >= 0)
+ {
+ error("Illegal character(':') in entity name ", name, null);
+ }
+ if (peFlag)
+ {
+ name = "%" + name;
+ }
+
+ // Read the entity value.
+ requireWhitespace();
+ char c = readCh();
+ unread (c);
+ if (c == '"' || c == '\'')
+ {
+ // Internal entity ... replacement text has expanded refs
+ // to characters and PEs, but not to general entities
+ String value = readLiteral(flags);
+ setInternalEntity(name, value);
+ }
+ else
+ {
+ // Read the external IDs
+ ExternalIdentifiers ids = readExternalIds(false, false);
+
+ // Check for NDATA declaration.
+ boolean white = tryWhitespace();
+ if (!peFlag && tryRead("NDATA"))
+ {
+ if (!white)
+ {
+ error("whitespace required before NDATA");
+ }
+ requireWhitespace();
+ String notationName = readNmtoken(true);
+ if (!skippedPE)
+ {
+ setExternalEntity(name, ENTITY_NDATA, ids, notationName);
+ handler.unparsedEntityDecl(name, ids.publicId, ids.systemId,
+ ids.baseUri, notationName);
+ }
+ }
+ else if (!skippedPE)
+ {
+ setExternalEntity(name, ENTITY_TEXT, ids, null);
+ handler.getDeclHandler()
+ .externalEntityDecl(name, ids.publicId,
+ handler.resolveURIs()
+ // FIXME: ASSUMES not skipped
+ // "false" forces error on bad URI
+ ? handler.absolutize(ids.baseUri,
+ ids.systemId,
+ false)
+ : ids.systemId);
+ }
+ }
+
+ // Finish the declaration.
+ skipWhitespace();
+ require('>');
+ }
+
+ /**
+ * Parse a notation declaration.
+ * NOTE: the '<!NOTATION' has already been read.
+ */
+ private void parseNotationDecl()
+ throws Exception
+ {
+ String nname;
+ ExternalIdentifiers ids;
+
+ requireWhitespace();
+ nname = readNmtoken(true);
+ //NE08
+ if (nname.indexOf(':') >= 0)
+ {
+ error("Illegal character(':') in notation name ", nname, null);
+ }
+ requireWhitespace();
+
+ // Read the external identifiers.
+ ids = readExternalIds(true, false);
+
+ // Register the notation.
+ setNotation(nname, ids);
+
+ skipWhitespace();
+ require('>');
+ }
+
+ /**
+ * Parse character data.
+ * Precondition: Entity expansion is not required.
+ * Precondition: data buffer has no characters that
+ * will get sent to the application.
+ */
+ private void require(String delim)
+ throws SAXException, IOException
+ {
+ int length = delim.length();
+ char[] ch;
+
+ if (length < dataBuffer.length)
+ {
+ ch = dataBuffer;
+ delim.getChars(0, length, ch, 0);
+ }
+ else
+ {
+ ch = delim.toCharArray();
+ }
+
+ if (USE_CHEATS && length <= (readBufferLength - readBufferPos))
+ {
+ int offset = readBufferPos;
+
+ for (int i = 0; i < length; i++, offset++)
+ {
+ if (ch[i] != readBuffer[offset])
+ {
+ error ("required string", null, delim);
+ }
+ }
+ readBufferPos = offset;
+
+ }
+ else
+ {
+ for (int i = 0; i < length; i++)
+ {
+ require(ch[i]);
+ }
+ }
+ }
+
+ /**
+ * Require a character to appear, or throw an exception.
+ */
+ private void require(char delim)
+ throws SAXException, IOException
+ {
+ char c = readCh();
+
+ if (c != delim)
+ {
+ error("required character", c, new Character(delim).toString());
+ }
+ }
+
+ /**
+ * Create an interned string from a character array.
+ * Ælfred uses this method to create an interned version
+ * of all names and name tokens, so that it can test equality
+ * with This is much more efficient than constructing a non-interned
+ * string first, and then interning it.
+ *
+ * @param ch an array of characters for building the string.
+ * @param start the starting position in the array.
+ * @param length the number of characters to place in the string.
+ * @return an interned string.
+ * @see #intern (String)
+ * @see java.lang.String#intern
+ */
+ public String intern(char[] ch, int start, int length)
+ {
+ int index = 0;
+ int hash = 0;
+ Object[] bucket;
+
+ // Generate a hash code. This is a widely used string hash,
+ // often attributed to Brian Kernighan.
+ for (int i = start; i < start + length; i++)
+ {
+ hash = 31 * hash + ch[i];
+ }
+ hash = (hash & 0x7fffffff) % SYMBOL_TABLE_LENGTH;
+
+ // Get the bucket -- consists of {array,String} pairs
+ if ((bucket = symbolTable[hash]) == null)
+ {
+ // first string in this bucket
+ bucket = new Object[8];
+
+ // Search for a matching tuple, and
+ // return the string if we find one.
+ }
+ else
+ {
+ while (index < bucket.length)
+ {
+ char[] chFound = (char[]) bucket[index];
+
+ // Stop when we hit an empty entry.
+ if (chFound == null)
+ {
+ break;
+ }
+
+ // If they're the same length, check for a match.
+ if (chFound.length == length)
+ {
+ for (int i = 0; i < chFound.length; i++)
+ {
+ // continue search on failure
+ if (ch[start + i] != chFound[i])
+ {
+ break;
+ }
+ else if (i == length - 1)
+ {
+ // That's it, we have a match!
+ return (String) bucket[index + 1];
+ }
+ }
+ }
+ index += 2;
+ }
+ // Not found -- we'll have to add it.
+
+ // Do we have to grow the bucket?
+ bucket = (Object[]) extendArray(bucket, bucket.length, index);
+ }
+ symbolTable[hash] = bucket;
+
+ // OK, add it to the end of the bucket -- "local" interning.
+ // Intern "globally" to let applications share interning benefits.
+ // That is, "!=" and "==" work on our strings, not just equals().
+ String s = new String(ch, start, length).intern();
+ bucket[index] = s.toCharArray();
+ bucket[index + 1] = s;
+ return s;
+ }
+
+ /**
+ * Ensure the capacity of an array, allocating a new one if
+ * necessary. Usually extends only for name hash collisions.
+ */
+ private Object extendArray(Object array, int currentSize, int requiredSize)
+ {
+ if (requiredSize < currentSize)
+ {
+ return array;
+ }
+ else
+ {
+ Object newArray = null;
+ int newSize = currentSize * 2;
+
+ if (newSize <= requiredSize)
+ {
+ newSize = requiredSize + 1;
+ }
+
+ if (array instanceof char[])
+ {
+ newArray = new char[newSize];
+ }
+ else if (array instanceof Object[])
+ {
+ newArray = new Object[newSize];
+ }
+ else
+ {
+ throw new RuntimeException();
+ }
+
+ System.arraycopy(array, 0, newArray, 0, currentSize);
+ return newArray;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // XML query routines.
+ //////////////////////////////////////////////////////////////////////
+
+ boolean isStandalone()
+ {
+ return docIsStandalone;
+ }
+
+ //
+ // Elements
+ //
+
+ private int getContentType(ElementDecl element, int defaultType)
+ {
+ int retval;
+
+ if (element == null)
+ {
+ return defaultType;
+ }
+ retval = element.contentType;
+ if (retval == CONTENT_UNDECLARED)
+ {
+ retval = defaultType;
+ }
+ return retval;
+ }
+
+ /**
+ * Look up the content type of an element.
+ * @param name The element type name.
+ * @return An integer constant representing the content type.
+ * @see #CONTENT_UNDECLARED
+ * @see #CONTENT_ANY
+ * @see #CONTENT_EMPTY
+ * @see #CONTENT_MIXED
+ * @see #CONTENT_ELEMENTS
+ */
+ public int getElementContentType(String name)
+ {
+ ElementDecl element = (ElementDecl) elementInfo.get(name);
+ return getContentType(element, CONTENT_UNDECLARED);
+ }
+
+ /**
+ * Register an element.
+ * Array format:
+ * [0] element type name
+ * [1] content model (mixed, elements only)
+ * [2] attribute hash table
+ */
+ private void setElement(String name, int contentType,
+ String contentModel, HashMap attributes)
+ throws SAXException
+ {
+ if (skippedPE)
+ {
+ return;
+ }
+
+ ElementDecl element = (ElementDecl) elementInfo.get(name);
+
+ // first or for this type?
+ if (element == null)
+ {
+ element = new ElementDecl();
+ element.contentType = contentType;
+ element.contentModel = contentModel;
+ element.attributes = attributes;
+ elementInfo.put(name, element);
+ return;
+ }
+
+ // declaration?
+ if (contentType != CONTENT_UNDECLARED)
+ {
+ // ... following an associated
+ if (element.contentType == CONTENT_UNDECLARED)
+ {
+ element.contentType = contentType;
+ element.contentModel = contentModel;
+ }
+ else
+ {
+ // VC: Unique Element Type Declaration
+ handler.verror("multiple declarations for element type: "
+ + name);
+ }
+ }
+
+ // first , before ?
+ else if (attributes != null)
+ {
+ element.attributes = attributes;
+ }
+ }
+
+ /**
+ * Look up the attribute hash table for an element.
+ * The hash table is the second item in the element array.
+ */
+ private HashMap getElementAttributes(String name)
+ {
+ ElementDecl element = (ElementDecl) elementInfo.get(name);
+ return (element == null) ? null : element.attributes;
+ }
+
+ //
+ // Attributes
+ //
+
+ /**
+ * Get the declared attributes for an element type.
+ * @param elname The name of the element type.
+ * @return An iterator over all the attributes declared for
+ * a specific element type. The results will be valid only
+ * after the DTD (if any) has been parsed.
+ * @see #getAttributeType
+ * @see #getAttributeEnumeration
+ * @see #getAttributeDefaultValueType
+ * @see #getAttributeDefaultValue
+ * @see #getAttributeExpandedValue
+ */
+ private Iterator declaredAttributes(ElementDecl element)
+ {
+ HashMap attlist;
+
+ if (element == null)
+ {
+ return null;
+ }
+ if ((attlist = element.attributes) == null)
+ {
+ return null;
+ }
+ return attlist.keySet().iterator();
+ }
+
+ /**
+ * Get the declared attributes for an element type.
+ * @param elname The name of the element type.
+ * @return An iterator over all the attributes declared for
+ * a specific element type. The results will be valid only
+ * after the DTD (if any) has been parsed.
+ * @see #getAttributeType
+ * @see #getAttributeEnumeration
+ * @see #getAttributeDefaultValueType
+ * @see #getAttributeDefaultValue
+ * @see #getAttributeExpandedValue
+ */
+ public Iterator declaredAttributes(String elname)
+ {
+ return declaredAttributes((ElementDecl) elementInfo.get(elname));
+ }
+
+ /**
+ * Retrieve the declared type of an attribute.
+ * @param name The name of the associated element.
+ * @param aname The name of the attribute.
+ * @return An interend string denoting the type, or null
+ * indicating an undeclared attribute.
+ */
+ public String getAttributeType(String name, String aname)
+ {
+ AttributeDecl attribute = getAttribute(name, aname);
+ return (attribute == null) ? null : attribute.type;
+ }
+
+ /**
+ * Retrieve the allowed values for an enumerated attribute type.
+ * @param name The name of the associated element.
+ * @param aname The name of the attribute.
+ * @return A string containing the token list.
+ */
+ public String getAttributeEnumeration(String name, String aname)
+ {
+ AttributeDecl attribute = getAttribute(name, aname);
+ // assert: attribute.enumeration is "ENUMERATION" or "NOTATION"
+ return (attribute == null) ? null : attribute.enumeration;
+ }
+
+ /**
+ * Retrieve the default value of a declared attribute.
+ * @param name The name of the associated element.
+ * @param aname The name of the attribute.
+ * @return The default value, or null if the attribute was
+ * #IMPLIED or simply undeclared and unspecified.
+ * @see #getAttributeExpandedValue
+ */
+ public String getAttributeDefaultValue(String name, String aname)
+ {
+ AttributeDecl attribute = getAttribute(name, aname);
+ return (attribute == null) ? null : attribute.value;
+ }
+
+ /*
+
+// FIXME: Leaving this in, until W3C finally resolves the confusion
+// between parts of the XML 2nd REC about when entity declararations
+// are guaranteed to be known. Current code matches what section 5.1
+// (conformance) describes, but some readings of the self-contradicting
+// text in 4.1 (the "Entity Declared" WFC and VC) seem to expect that
+// attribute expansion/normalization must be deferred in some cases
+// (just TRY to identify them!).
+
+ * Retrieve the expanded value of a declared attribute.
+ * General entities (and char refs) will be expanded (once).
+ * @param name The name of the associated element.
+ * @param aname The name of the attribute.
+ * @return The expanded default value, or null if the attribute was
+ * #IMPLIED or simply undeclared
+ * @see #getAttributeDefaultValue
+ public String getAttributeExpandedValue (String name, String aname)
+ throws Exception
+ {
+ AttributeDecl attribute = getAttribute (name, aname);
+
+ if (attribute == null) {
+ return null;
+ } else if (attribute.defaultValue == null && attribute.value != null) {
+ // we MUST use the same buf for both quotes else the literal
+ // can't be properly terminated
+ char buf [] = new char [1];
+ int flags = LIT_ENTITY_REF | LIT_ATTRIBUTE;
+ String type = getAttributeType (name, aname);
+
+ if (type != "CDATA" && type != null)
+ flags |= LIT_NORMALIZE;
+ buf [0] = '"';
+ pushCharArray (null, buf, 0, 1);
+ pushString (null, attribute.value);
+ pushCharArray (null, buf, 0, 1);
+ attribute.defaultValue = readLiteral (flags);
+ }
+ return attribute.defaultValue;
+ }
+ */
+
+ /**
+ * Retrieve the default value mode of a declared attribute.
+ * @see #ATTRIBUTE_DEFAULT_SPECIFIED
+ * @see #ATTRIBUTE_DEFAULT_IMPLIED
+ * @see #ATTRIBUTE_DEFAULT_REQUIRED
+ * @see #ATTRIBUTE_DEFAULT_FIXED
+ */
+ public int getAttributeDefaultValueType(String name, String aname)
+ {
+ AttributeDecl attribute = getAttribute(name, aname);
+ return (attribute == null) ? ATTRIBUTE_DEFAULT_UNDECLARED :
+ attribute.valueType;
+ }
+
+ /**
+ * Register an attribute declaration for later retrieval.
+ * Format:
+ * - String type
+ * - String default value
+ * - int value type
+ * - enumeration
+ * - processed default value
+ */
+ private void setAttribute(String elName, String name, String type,
+ String enumeration, String value, int valueType)
+ throws Exception
+ {
+ HashMap attlist;
+
+ if (skippedPE)
+ {
+ return;
+ }
+
+ // Create a new hashtable if necessary.
+ attlist = getElementAttributes(elName);
+ if (attlist == null)
+ {
+ attlist = new HashMap();
+ }
+
+ // ignore multiple attribute declarations!
+ if (attlist.get(name) != null)
+ {
+ // warn ...
+ return;
+ }
+ else
+ {
+ AttributeDecl attribute = new AttributeDecl();
+ attribute.type = type;
+ attribute.value = value;
+ attribute.valueType = valueType;
+ attribute.enumeration = enumeration;
+ attlist.put(name, attribute);
+
+ // save; but don't overwrite any existing
+ setElement(elName, CONTENT_UNDECLARED, null, attlist);
+ }
+ }
+
+ /**
+ * Retrieve the attribute declaration for the given element name and name.
+ */
+ private AttributeDecl getAttribute(String elName, String name)
+ {
+ HashMap attlist = getElementAttributes(elName);
+ return (attlist == null) ? null : (AttributeDecl) attlist.get(name);
+ }
+
+ //
+ // Entities
+ //
+
+ /**
+ * Find the type of an entity.
+ * @returns An integer constant representing the entity type.
+ * @see #ENTITY_UNDECLARED
+ * @see #ENTITY_INTERNAL
+ * @see #ENTITY_NDATA
+ * @see #ENTITY_TEXT
+ */
+ public int getEntityType(String ename)
+ {
+ EntityInfo entity = (EntityInfo) entityInfo.get(ename);
+ return (entity == null) ? ENTITY_UNDECLARED : entity.type;
+ }
+
+ /**
+ * Return an external entity's identifiers.
+ * @param ename The name of the external entity.
+ * @return The entity's public identifier, system identifier, and base URI.
+ * Null if the entity was not declared as an external entity.
+ * @see #getEntityType
+ */
+ public ExternalIdentifiers getEntityIds(String ename)
+ {
+ EntityInfo entity = (EntityInfo) entityInfo.get(ename);
+ return (entity == null) ? null : entity.ids;
+ }
+
+ /**
+ * Return an internal entity's replacement text.
+ * @param ename The name of the internal entity.
+ * @return The entity's replacement text, or null if
+ * the entity was not declared as an internal entity.
+ * @see #getEntityType
+ */
+ public String getEntityValue(String ename)
+ {
+ EntityInfo entity = (EntityInfo) entityInfo.get(ename);
+ return (entity == null) ? null : entity.value;
+ }
+
+ /**
+ * Register an entity declaration for later retrieval.
+ */
+ private void setInternalEntity(String eName, String value)
+ throws SAXException
+ {
+ if (skippedPE)
+ {
+ return;
+ }
+
+ if (entityInfo.get(eName) == null)
+ {
+ EntityInfo entity = new EntityInfo();
+ entity.type = ENTITY_INTERNAL;
+ entity.value = value;
+ entityInfo.put(eName, entity);
+ }
+ if (handler.stringInterning)
+ {
+ if ("lt" == eName || "gt" == eName || "quot" == eName
+ || "apos" == eName || "amp" == eName)
+ {
+ return;
+ }
+ }
+ else
+ {
+ if ("lt".equals(eName) || "gt".equals(eName) || "quot".equals(eName)
+ || "apos".equals(eName) || "amp".equals(eName))
+ {
+ return;
+ }
+ }
+ handler.getDeclHandler().internalEntityDecl(eName, value);
+ }
+
+ /**
+ * Register an external entity declaration for later retrieval.
+ */
+ private void setExternalEntity(String eName, int eClass,
+ ExternalIdentifiers ids, String nName)
+ {
+ if (entityInfo.get(eName) == null)
+ {
+ EntityInfo entity = new EntityInfo();
+ entity.type = eClass;
+ entity.ids = ids;
+ entity.notationName = nName;
+ entityInfo.put(eName, entity);
+ }
+ }
+
+ //
+ // Notations.
+ //
+
+ /**
+ * Report a notation declaration, checking for duplicates.
+ */
+ private void setNotation(String nname, ExternalIdentifiers ids)
+ throws SAXException
+ {
+ if (skippedPE)
+ {
+ return;
+ }
+
+ handler.notationDecl(nname, ids.publicId, ids.systemId, ids.baseUri);
+ if (notationInfo.get(nname) == null)
+ {
+ notationInfo.put(nname, nname);
+ }
+ else
+ {
+ // VC: Unique Notation Name
+ handler.verror("Duplicate notation name decl: " + nname);
+ }
+ }
+
+ //
+ // Location.
+ //
+
+ /**
+ * Return the current line number.
+ */
+ public int getLineNumber()
+ {
+ return line;
+ }
+
+ /**
+ * Return the current column number.
+ */
+ public int getColumnNumber()
+ {
+ return column;
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // High-level I/O.
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Read a single character from the readBuffer.
+ * The readDataChunk () method maintains the buffer.
+ * If we hit the end of an entity, try to pop the stack and
+ * keep going.
+ * (This approach doesn't really enforce XML's rules about
+ * entity boundaries, but this is not currently a validating
+ * parser).
+ * This routine also attempts to keep track of the current
+ * position in external entities, but it's not entirely accurate.
+ * @return The next available input character.
+ * @see #unread (char)
+ * @see #readDataChunk
+ * @see #readBuffer
+ * @see #line
+ * @return The next character from the current input source.
+ */
+ private char readCh()
+ throws SAXException, IOException
+ {
+ // As long as there's nothing in the
+ // read buffer, try reading more data
+ // (for an external entity) or popping
+ // the entity stack (for either).
+ while (readBufferPos >= readBufferLength)
+ {
+ switch (sourceType)
+ {
+ case INPUT_READER:
+ case INPUT_STREAM:
+ readDataChunk();
+ while (readBufferLength < 1)
+ {
+ popInput();
+ if (readBufferLength < 1)
+ {
+ readDataChunk();
+ }
+ }
+ break;
+
+ default:
+
+ popInput();
+ break;
+ }
+ }
+
+ char c = readBuffer[readBufferPos++];
+
+ if (c == '\n')
+ {
+ line++;
+ column = 0;
+ }
+ else
+ {
+ if (c == '<')
+ {
+ /* the most common return to parseContent () ... NOP */
+ }
+ else if (((c < 0x0020 && (c != '\t') && (c != '\r')) || c > 0xFFFD)
+ || ((c >= 0x007f) && (c <= 0x009f) && (c != 0x0085)
+ && xmlVersion == XML_11))
+ {
+ error("illegal XML character U+" + Integer.toHexString(c));
+ }
+
+ // If we're in the DTD and in a context where PEs get expanded,
+ // do so ... 1/14/2000 errata identify those contexts. There
+ // are also spots in the internal subset where PE refs are fatal
+ // errors, hence yet another flag.
+ else if (c == '%' && expandPE)
+ {
+ if (peIsError)
+ {
+ error("PE reference within decl in internal subset.");
+ }
+ parsePEReference();
+ return readCh();
+ }
+ column++;
+ }
+
+ return c;
+ }
+
+ /**
+ * Push a single character back onto the current input stream.
+ * This method usually pushes the character back onto
+ * the readBuffer.
+ * I don't think that this would ever be called with
+ * readBufferPos = 0, because the methods always reads a character
+ * before unreading it, but just in case, I've added a boundary
+ * condition.
+ * @param c The character to push back.
+ * @see #readCh
+ * @see #unread (char[])
+ * @see #readBuffer
+ */
+ private void unread(char c)
+ throws SAXException
+ {
+ // Normal condition.
+ if (c == '\n')
+ {
+ line--;
+ column = -1;
+ }
+ if (readBufferPos > 0)
+ {
+ readBuffer[--readBufferPos] = c;
+ }
+ else
+ {
+ pushString(null, new Character(c).toString());
+ }
+ }
+
+ /**
+ * Push a char array back onto the current input stream.
+ * NOTE: you must never push back characters that you
+ * haven't actually read: use pushString () instead.
+ * @see #readCh
+ * @see #unread (char)
+ * @see #readBuffer
+ * @see #pushString
+ */
+ private void unread(char[] ch, int length)
+ throws SAXException
+ {
+ for (int i = 0; i < length; i++)
+ {
+ if (ch[i] == '\n')
+ {
+ line--;
+ column = -1;
+ }
+ }
+ if (length < readBufferPos)
+ {
+ readBufferPos -= length;
+ }
+ else
+ {
+ pushCharArray(null, ch, 0, length);
+ }
+ }
+
+ /**
+ * Push, or skip, a new external input source.
+ * The source will be some kind of parsed entity, such as a PE
+ * (including the external DTD subset) or content for the body.
+ *
+ * @param url The java.net.URL object for the entity.
+ * @see SAXDriver#resolveEntity
+ * @see #pushString
+ * @see #sourceType
+ * @see #pushInput
+ * @see #detectEncoding
+ * @see #sourceType
+ * @see #readBuffer
+ */
+ private void pushURL(boolean isPE,
+ String ename,
+ ExternalIdentifiers ids,
+ Reader reader,
+ InputStream stream,
+ String encoding,
+ boolean doResolve)
+ throws SAXException, IOException
+ {
+ boolean ignoreEncoding;
+ String systemId;
+ InputSource source;
+
+ if (!isPE)
+ {
+ dataBufferFlush();
+ }
+
+ scratch.setPublicId(ids.publicId);
+ scratch.setSystemId(ids.systemId);
+
+ // See if we should skip or substitute the entity.
+ // If we're not skipping, resolving reports startEntity()
+ // and updates the (handler's) stack of URIs.
+ if (doResolve)
+ {
+ // assert (stream == null && reader == null && encoding == null)
+ source = handler.resolveEntity(isPE, ename, scratch, ids.baseUri);
+ if (source == null)
+ {
+ handler.warn("skipping entity: " + ename);
+ handler.skippedEntity(ename);
+ if (isPE)
+ {
+ skippedPE = true;
+ }
+ return;
+ }
+
+ // we might be using alternate IDs/encoding
+ systemId = source.getSystemId();
+ // The following warning and setting systemId was deleted bcause
+ // the application has the option of not setting systemId
+ // provided that it has set the characte/byte stream.
+ /*
+ if (systemId == null) {
+ handler.warn ("missing system ID, using " + ids.systemId);
+ systemId = ids.systemId;
+ }
+ */
+ }
+ else
+ {
+ // "[document]", or "[dtd]" via getExternalSubset()
+ scratch.setCharacterStream(reader);
+ scratch.setByteStream(stream);
+ scratch.setEncoding(encoding);
+ source = scratch;
+ systemId = ids.systemId;
+ if (handler.stringInterning)
+ {
+ handler.startExternalEntity(ename, systemId,
+ "[document]" == ename);
+ }
+ else
+ {
+ handler.startExternalEntity(ename, systemId,
+ "[document]".equals(ename));
+ }
+ }
+
+ // we may have been given I/O streams directly
+ if (source.getCharacterStream() != null)
+ {
+ if (source.getByteStream() != null)
+ error("InputSource has two streams!");
+ reader = source.getCharacterStream();
+ }
+ else if (source.getByteStream() != null)
+ {
+ encoding = source.getEncoding();
+ if (encoding == null)
+ {
+ stream = source.getByteStream();
+ }
+ else
+ {
+ try
+ {
+ reader = new InputStreamReader(source.getByteStream(),
+ encoding);
+ }
+ catch (IOException e)
+ {
+ stream = source.getByteStream();
+ }
+ }
+ }
+ else if (systemId == null)
+ {
+ error("InputSource has no URI!");
+ }
+ scratch.setCharacterStream(null);
+ scratch.setByteStream(null);
+ scratch.setEncoding(null);
+
+ // Push the existing status.
+ pushInput(ename);
+
+ // Create a new read buffer.
+ // (Note the four-character margin)
+ readBuffer = new char[READ_BUFFER_MAX + 4];
+ readBufferPos = 0;
+ readBufferLength = 0;
+ readBufferOverflow = -1;
+ is = null;
+ line = 1;
+ column = 0;
+ currentByteCount = 0;
+
+ // If there's an explicit character stream, just
+ // ignore encoding declarations.
+ if (reader != null)
+ {
+ sourceType = INPUT_READER;
+ this.reader = reader;
+ tryEncodingDecl(true);
+ return;
+ }
+
+ // Else we handle the conversion, and need to ensure
+ // it's done right.
+ sourceType = INPUT_STREAM;
+ if (stream != null)
+ {
+ is = stream;
+ }
+ else
+ {
+ // We have to open our own stream to the URL.
+ URL url = new URL(systemId);
+
+ externalEntity = url.openConnection();
+ externalEntity.connect();
+ is = externalEntity.getInputStream();
+ }
+
+ // If we get to here, there must be
+ // an InputStream available.
+ if (!is.markSupported())
+ {
+ is = new BufferedInputStream(is);
+ }
+
+ // Get any external encoding label.
+ if (encoding == null && externalEntity != null)
+ {
+ // External labels can be untrustworthy; filesystems in
+ // particular often have the wrong default for content
+ // that wasn't locally originated. Those we autodetect.
+ if (!"file".equals(externalEntity.getURL().getProtocol()))
+ {
+ int temp;
+
+ // application/xml;charset=something;otherAttr=...
+ // ... with many variants on 'something'
+ encoding = externalEntity.getContentType();
+
+ // MHK code (fix for Saxon 5.5.1/007):
+ // protect against encoding==null
+ if (encoding == null)
+ {
+ temp = -1;
+ }
+ else
+ {
+ temp = encoding.indexOf("charset");
+ }
+
+ // RFC 2376 sez MIME text defaults to ASCII, but since the
+ // JDK will create a MIME type out of thin air, we always
+ // autodetect when there's no explicit charset attribute.
+ if (temp < 0)
+ {
+ encoding = null; // autodetect
+ }
+ else
+ {
+ // only this one attribute
+ if ((temp = encoding.indexOf(';')) > 0)
+ {
+ encoding = encoding.substring(0, temp);
+ }
+
+ if ((temp = encoding.indexOf('=', temp + 7)) > 0)
+ {
+ encoding = encoding.substring(temp + 1);
+
+ // attributes can have comment fields (RFC 822)
+ if ((temp = encoding.indexOf('(')) > 0)
+ {
+ encoding = encoding.substring(0, temp);
+ }
+ // ... and values may be quoted
+ if ((temp = encoding.indexOf('"')) > 0)
+ {
+ encoding =
+ encoding.substring(temp + 1,
+ encoding.indexOf('"', temp + 2));
+ }
+ encoding = encoding.trim();
+ }
+ else
+ {
+ handler.warn("ignoring illegal MIME attribute: "
+ + encoding);
+ encoding = null;
+ }
+ }
+ }
+ }
+
+ // if we got an external encoding label, use it ...
+ if (encoding != null)
+ {
+ this.encoding = ENCODING_EXTERNAL;
+ setupDecoding(encoding);
+ ignoreEncoding = true;
+
+ // ... else autodetect from first bytes.
+ }
+ else
+ {
+ detectEncoding();
+ ignoreEncoding = false;
+ }
+
+ // Read any XML or text declaration.
+ // If we autodetected, it may tell us the "real" encoding.
+ try
+ {
+ tryEncodingDecl(ignoreEncoding);
+ }
+ catch (UnsupportedEncodingException x)
+ {
+ encoding = x.getMessage();
+
+ // if we don't handle the declared encoding,
+ // try letting a JVM InputStreamReader do it
+ try
+ {
+ if (sourceType != INPUT_STREAM)
+ {
+ throw x;
+ }
+
+ is.reset();
+ readBufferPos = 0;
+ readBufferLength = 0;
+ readBufferOverflow = -1;
+ line = 1;
+ currentByteCount = column = 0;
+
+ sourceType = INPUT_READER;
+ this.reader = new InputStreamReader(is, encoding);
+ is = null;
+
+ tryEncodingDecl(true);
+
+ }
+ catch (IOException e)
+ {
+ error("unsupported text encoding",
+ encoding,
+ null);
+ }
+ }
+ }
+
+ /**
+ * Check for an encoding declaration. This is the second part of the
+ * XML encoding autodetection algorithm, relying on detectEncoding to
+ * get to the point that this part can read any encoding declaration
+ * in the document (using only US-ASCII characters).
+ *
+ * Because this part starts to fill parser buffers with this data,
+ * it's tricky to setup a reader so that Java's built-in decoders can be
+ * used for the character encodings that aren't built in to this parser
+ * (such as EUC-JP, KOI8-R, Big5, etc).
+ *
+ * @return any encoding in the declaration, uppercased; or null
+ * @see detectEncoding
+ */
+ private String tryEncodingDecl(boolean ignoreEncoding)
+ throws SAXException, IOException
+ {
+ // Read the XML/text declaration.
+ if (tryRead(" 0)
+ {
+ return parseTextDecl(ignoreEncoding);
+ }
+ else
+ {
+ return parseXMLDecl(ignoreEncoding);
+ }
+ }
+ else
+ {
+ // or similar
+ unread('l');
+ unread('m');
+ unread('x');
+ unread('?');
+ unread('<');
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Attempt to detect the encoding of an entity.
+ * The trick here (as suggested in the XML standard) is that
+ * any entity not in UTF-8, or in UCS-2 with a byte-order mark,
+ * must begin with an XML declaration or an encoding
+ * declaration; we simply have to look for "<?xml" in various
+ * encodings.
+ * This method has no way to distinguish among 8-bit encodings.
+ * Instead, it sets up for UTF-8, then (possibly) revises its assumption
+ * later in setupDecoding (). Any ASCII-derived 8-bit encoding
+ * should work, but most will be rejected later by setupDecoding ().
+ * @see #tryEncoding (byte[], byte, byte, byte, byte)
+ * @see #tryEncoding (byte[], byte, byte)
+ * @see #setupDecoding
+ */
+ private void detectEncoding()
+ throws SAXException, IOException
+ {
+ byte[] signature = new byte[4];
+
+ // Read the first four bytes for
+ // autodetection.
+ is.mark(4);
+ is.read(signature);
+ is.reset();
+
+ //
+ // FIRST: four byte encodings (who uses these?)
+ //
+ if (tryEncoding(signature, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x3c))
+ {
+ // UCS-4 must begin with "Utility routine for detectEncoding ().
+ * Always looks for some part of "Looks for a UCS-2 byte-order mark.
+ * Utility routine for detectEncoding ().
+ * @param sig The first four bytes read.
+ * @param b1 The first byte of the signature
+ * @param b2 The second byte of the signature
+ * @see #detectEncoding
+ */
+ private static boolean tryEncoding(byte[] sig, byte b1, byte b2)
+ {
+ return ((sig[0] == b1) && (sig[1] == b2));
+ }
+
+ /**
+ * This method pushes a string back onto input.
+ * It is useful either as the expansion of an internal entity,
+ * or for backtracking during the parse.
+ * Call pushCharArray () to do the actual work.
+ * @param s The string to push back onto input.
+ * @see #pushCharArray
+ */
+ private void pushString(String ename, String s)
+ throws SAXException
+ {
+ char[] ch = s.toCharArray();
+ pushCharArray(ename, ch, 0, ch.length);
+ }
+
+ /**
+ * Push a new internal input source.
+ * This method is useful for expanding an internal entity,
+ * or for unreading a string of characters. It creates a new
+ * readBuffer containing the characters in the array, instead
+ * of characters converted from an input byte stream.
+ * @param ch The char array to push.
+ * @see #pushString
+ * @see #pushURL
+ * @see #readBuffer
+ * @see #sourceType
+ * @see #pushInput
+ */
+ private void pushCharArray(String ename, char[] ch, int start, int length)
+ throws SAXException
+ {
+ // Push the existing status
+ pushInput(ename);
+ if (ename != null && doReport)
+ {
+ dataBufferFlush();
+ handler.startInternalEntity(ename);
+ }
+ sourceType = INPUT_INTERNAL;
+ readBuffer = ch;
+ readBufferPos = start;
+ readBufferLength = length;
+ readBufferOverflow = -1;
+ }
+
+ /**
+ * Save the current input source onto the stack.
+ * This method saves all of the global variables associated with
+ * the current input source, so that they can be restored when a new
+ * input source has finished. It also tests for entity recursion.
+ * The method saves the following global variables onto a stack
+ * using a fixed-length array:
+ * This method restores all of the global variables associated with
+ * the current input source.
+ * @exception java.io.EOFException
+ * If there are no more entries on the input stack.
+ * @see #pushInput
+ * @see #sourceType
+ * @see #externalEntity
+ * @see #readBuffer
+ * @see #readBufferPos
+ * @see #readBufferLength
+ * @see #line
+ * @see #encoding
+ */
+ private void popInput()
+ throws SAXException, IOException
+ {
+ String ename = (String) entityStack.removeLast();
+
+ if (ename != null && doReport)
+ {
+ dataBufferFlush();
+ }
+ switch (sourceType)
+ {
+ case INPUT_STREAM:
+ handler.endExternalEntity(ename);
+ is.close();
+ break;
+ case INPUT_READER:
+ handler.endExternalEntity(ename);
+ reader.close();
+ break;
+ case INPUT_INTERNAL:
+ if (ename != null && doReport)
+ {
+ handler.endInternalEntity(ename);
+ }
+ break;
+ }
+
+ // Throw an EOFException if there
+ // is nothing else to pop.
+ if (inputStack.isEmpty())
+ {
+ throw new EOFException("no more input");
+ }
+
+ Input input = (Input) inputStack.removeLast();
+
+ sourceType = input.sourceType;
+ externalEntity = input.externalEntity;
+ readBuffer = input.readBuffer;
+ readBufferPos = input.readBufferPos;
+ readBufferLength = input.readBufferLength;
+ line = input.line;
+ encoding = input.encoding;
+ readBufferOverflow = input.readBufferOverflow;
+ is = input.is;
+ currentByteCount = input.currentByteCount;
+ column = input.column;
+ reader = input.reader;
+ }
+
+ /**
+ * Return true if we can read the expected character.
+ * Note that the character will be removed from the input stream
+ * on success, but will be put back on failure. Do not attempt to
+ * read the character again if the method succeeds.
+ * @param delim The character that should appear next. For a
+ * insensitive match, you must supply this in upper-case.
+ * @return true if the character was successfully read, or false if
+ * it was not.
+ * @see #tryRead (String)
+ */
+ private boolean tryRead(char delim)
+ throws SAXException, IOException
+ {
+ char c;
+
+ // Read the character
+ c = readCh();
+
+ // Test for a match, and push the character
+ // back if the match fails.
+ if (c == delim)
+ {
+ return true;
+ }
+ else
+ {
+ unread(c);
+ return false;
+ }
+ }
+
+ /**
+ * Return true if we can read the expected string.
+ * This is simply a convenience method.
+ * Note that the string will be removed from the input stream
+ * on success, but will be put back on failure. Do not attempt to
+ * read the string again if the method succeeds.
+ * This method will push back a character rather than an
+ * array whenever possible (probably the majority of cases).
+ * @param delim The string that should appear next.
+ * @return true if the string was successfully read, or false if
+ * it was not.
+ * @see #tryRead (char)
+ */
+ private boolean tryRead(String delim)
+ throws SAXException, IOException
+ {
+ return tryRead(delim.toCharArray());
+ }
+
+ private boolean tryRead(char[] ch)
+ throws SAXException, IOException
+ {
+ char c;
+
+ // Compare the input, character-
+ // by character.
+
+ for (int i = 0; i < ch.length; i++)
+ {
+ c = readCh();
+ if (c != ch[i])
+ {
+ unread(c);
+ if (i != 0)
+ {
+ unread(ch, i);
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return true if we can read some whitespace.
+ * This is simply a convenience method.
+ * This method will push back a character rather than an
+ * array whenever possible (probably the majority of cases).
+ * @return true if whitespace was found.
+ */
+ private boolean tryWhitespace()
+ throws SAXException, IOException
+ {
+ char c;
+ c = readCh();
+ if (isWhitespace(c))
+ {
+ skipWhitespace();
+ return true;
+ }
+ else
+ {
+ unread(c);
+ return false;
+ }
+ }
+
+ /**
+ * Read all data until we find the specified string.
+ * This is useful for scanning CDATA sections and PIs.
+ * This is inefficient right now, since it calls tryRead ()
+ * for every character.
+ * @param delim The string delimiter
+ * @see #tryRead (String, boolean)
+ * @see #readCh
+ */
+ private void parseUntil(String delim)
+ throws SAXException, IOException
+ {
+ parseUntil(delim.toCharArray());
+ }
+
+ private void parseUntil(char[] delim)
+ throws SAXException, IOException
+ {
+ char c;
+ int startLine = line;
+
+ try
+ {
+ while (!tryRead(delim))
+ {
+ c = readCh();
+ dataBufferAppend(c);
+ }
+ }
+ catch (EOFException e)
+ {
+ error("end of input while looking for delimiter "
+ + "(started on line " + startLine
+ + ')', null, new String(delim));
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // Low-level I/O.
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Prefetch US-ASCII XML/text decl from input stream into read buffer.
+ * Doesn't buffer more than absolutely needed, so that when an encoding
+ * decl says we need to create an InputStreamReader, we can discard our
+ * buffer and reset(). Caller knows the first chars of the decl exist
+ * in the input stream.
+ */
+ private void prefetchASCIIEncodingDecl()
+ throws SAXException, IOException
+ {
+ int ch;
+ readBufferPos = readBufferLength = 0;
+
+ is.mark(readBuffer.length);
+ while (true)
+ {
+ ch = is.read();
+ readBuffer[readBufferLength++] = (char) ch;
+ switch (ch)
+ {
+ case (int) '>':
+ return;
+ case -1:
+ error("file ends before end of XML or encoding declaration.",
+ null, "?>");
+ }
+ if (readBuffer.length == readBufferLength)
+ {
+ error("unfinished XML or encoding declaration");
+ }
+ }
+ }
+
+ /**
+ * Read a chunk of data from an external input source.
+ * This is simply a front-end that fills the rawReadBuffer
+ * with bytes, then calls the appropriate encoding handler.
+ * @see #encoding
+ * @see #rawReadBuffer
+ * @see #readBuffer
+ * @see #filterCR
+ * @see #copyUtf8ReadBuffer
+ * @see #copyIso8859_1ReadBuffer
+ * @see #copyUcs_2ReadBuffer
+ * @see #copyUcs_4ReadBuffer
+ */
+ private void readDataChunk()
+ throws SAXException, IOException
+ {
+ int count;
+
+ // See if we have any overflow (filterCR sets for CR at end)
+ if (readBufferOverflow > -1)
+ {
+ readBuffer[0] = (char) readBufferOverflow;
+ readBufferOverflow = -1;
+ readBufferPos = 1;
+ sawCR = true;
+ }
+ else
+ {
+ readBufferPos = 0;
+ sawCR = false;
+ }
+
+ // input from a character stream.
+ if (sourceType == INPUT_READER)
+ {
+ count = reader.read(readBuffer,
+ readBufferPos, READ_BUFFER_MAX - readBufferPos);
+ if (count < 0)
+ {
+ readBufferLength = readBufferPos;
+ }
+ else
+ {
+ readBufferLength = readBufferPos + count;
+ }
+ if (readBufferLength > 0)
+ {
+ filterCR(count >= 0);
+ }
+ sawCR = false;
+ return;
+ }
+
+ // Read as many bytes as possible into the raw buffer.
+ count = is.read(rawReadBuffer, 0, READ_BUFFER_MAX);
+
+ // Dispatch to an encoding-specific reader method to populate
+ // the readBuffer. In most parser speed profiles, these routines
+ // show up at the top of the CPU usage chart.
+ if (count > 0)
+ {
+ switch (encoding)
+ {
+ // one byte builtins
+ case ENCODING_ASCII:
+ copyIso8859_1ReadBuffer(count, (char) 0x0080);
+ break;
+ case ENCODING_UTF_8:
+ copyUtf8ReadBuffer(count);
+ break;
+ case ENCODING_ISO_8859_1:
+ copyIso8859_1ReadBuffer(count, (char) 0);
+ break;
+
+ // two byte builtins
+ case ENCODING_UCS_2_12:
+ copyUcs2ReadBuffer(count, 8, 0);
+ break;
+ case ENCODING_UCS_2_21:
+ copyUcs2ReadBuffer(count, 0, 8);
+ break;
+
+ // four byte builtins
+ case ENCODING_UCS_4_1234:
+ copyUcs4ReadBuffer(count, 24, 16, 8, 0);
+ break;
+ case ENCODING_UCS_4_4321:
+ copyUcs4ReadBuffer(count, 0, 8, 16, 24);
+ break;
+ case ENCODING_UCS_4_2143:
+ copyUcs4ReadBuffer(count, 16, 24, 0, 8);
+ break;
+ case ENCODING_UCS_4_3412:
+ copyUcs4ReadBuffer(count, 8, 0, 24, 16);
+ break;
+ }
+ }
+ else
+ {
+ readBufferLength = readBufferPos;
+ }
+
+ readBufferPos = 0;
+
+ // Filter out all carriage returns if we've seen any
+ // (including any saved from a previous read)
+ if (sawCR)
+ {
+ filterCR(count >= 0);
+ sawCR = false;
+
+ // must actively report EOF, lest some CRs get lost.
+ if (readBufferLength == 0 && count >= 0)
+ {
+ readDataChunk();
+ }
+ }
+
+ if (count > 0)
+ {
+ currentByteCount += count;
+ }
+ }
+
+ /**
+ * Filter carriage returns in the read buffer.
+ * CRLF becomes LF; CR becomes LF.
+ * @param moreData true iff more data might come from the same source
+ * @see #readDataChunk
+ * @see #readBuffer
+ * @see #readBufferOverflow
+ */
+ private void filterCR(boolean moreData)
+ {
+ int i, j;
+
+ readBufferOverflow = -1;
+
+loop:
+ for (i = j = readBufferPos; j < readBufferLength; i++, j++)
+ {
+ switch (readBuffer[j])
+ {
+ case '\r':
+ if (j == readBufferLength - 1)
+ {
+ if (moreData)
+ {
+ readBufferOverflow = '\r';
+ readBufferLength--;
+ }
+ else // CR at end of buffer
+ {
+ readBuffer[i++] = '\n';
+ }
+ break loop;
+ }
+ else if (readBuffer[j + 1] == '\n')
+ {
+ j++;
+ }
+ readBuffer[i] = '\n';
+ break;
+
+ case '\n':
+ default:
+ readBuffer[i] = readBuffer[j];
+ break;
+ }
+ }
+ readBufferLength = i;
+ }
+
+ /**
+ * Convert a buffer of UTF-8-encoded bytes into UTF-16 characters.
+ * When readDataChunk () calls this method, the raw bytes are in
+ * rawReadBuffer, and the final characters will appear in
+ * readBuffer.
+ * Note that as of Unicode 3.1, good practice became a requirement,
+ * so that each Unicode character has exactly one UTF-8 representation.
+ * @param count The number of bytes to convert.
+ * @see #readDataChunk
+ * @see #rawReadBuffer
+ * @see #readBuffer
+ * @see #getNextUtf8Byte
+ */
+ private void copyUtf8ReadBuffer(int count)
+ throws SAXException, IOException
+ {
+ int i = 0;
+ int j = readBufferPos;
+ int b1;
+ char c = 0;
+
+ /*
+ // check once, so the runtime won't (if it's smart enough)
+ if (count < 0 || count > rawReadBuffer.length)
+ throw new ArrayIndexOutOfBoundsException (Integer.toString (count));
+ */
+
+ while (i < count)
+ {
+ b1 = rawReadBuffer[i++];
+
+ // Determine whether we are dealing
+ // with a one-, two-, three-, or four-
+ // byte sequence.
+ if (b1 < 0)
+ {
+ if ((b1 & 0xe0) == 0xc0)
+ {
+ // 2-byte sequence: 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
+ c = (char) (((b1 & 0x1f) << 6)
+ | getNextUtf8Byte(i++, count));
+ if (c < 0x0080)
+ {
+ encodingError("Illegal two byte UTF-8 sequence",
+ c, 0);
+ }
+
+ //Sec 2.11
+ // [1] the two-character sequence #xD #xA
+ // [2] the two-character sequence #xD #x85
+ if ((c == 0x0085 || c == 0x000a) && sawCR)
+ {
+ continue;
+ }
+
+ // Sec 2.11
+ // [3] the single character #x85
+
+ if (c == 0x0085 && xmlVersion == XML_11)
+ {
+ readBuffer[j++] = '\r';
+ }
+ }
+ else if ((b1 & 0xf0) == 0xe0)
+ {
+ // 3-byte sequence:
+ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
+ // most CJKV characters
+ c = (char) (((b1 & 0x0f) << 12) |
+ (getNextUtf8Byte(i++, count) << 6) |
+ getNextUtf8Byte(i++, count));
+ //sec 2.11
+ //[4] the single character #x2028
+ if (c == 0x2028 && xmlVersion == XML_11)
+ {
+ readBuffer[j++] = '\r';
+ sawCR = true;
+ continue;
+ }
+ if (c < 0x0800 || (c >= 0xd800 && c <= 0xdfff))
+ {
+ encodingError("Illegal three byte UTF-8 sequence",
+ c, 0);
+ }
+ }
+ else if ((b1 & 0xf8) == 0xf0)
+ {
+ // 4-byte sequence: 11101110wwwwzzzzyy + 110111yyyyxxxxxx
+ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
+ // (uuuuu = wwww + 1)
+ // "Surrogate Pairs" ... from the "Astral Planes"
+ // Unicode 3.1 assigned the first characters there
+ int iso646 = b1 & 07;
+ iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count);
+ iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count);
+ iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count);
+
+ if (iso646 <= 0xffff)
+ {
+ encodingError("Illegal four byte UTF-8 sequence",
+ iso646, 0);
+ }
+ else
+ {
+ if (iso646 > 0x0010ffff)
+ {
+ encodingError("UTF-8 value out of range for Unicode",
+ iso646, 0);
+ }
+ iso646 -= 0x010000;
+ readBuffer[j++] = (char) (0xd800 | (iso646 >> 10));
+ readBuffer[j++] = (char) (0xdc00 | (iso646 & 0x03ff));
+ continue;
+ }
+ }
+ else
+ {
+ // The five and six byte encodings aren't supported;
+ // they exceed the Unicode (and XML) range.
+ encodingError("unsupported five or six byte UTF-8 sequence",
+ 0xff & b1, i);
+ // NOTREACHED
+ c = 0;
+ }
+ }
+ else
+ {
+ // 1-byte sequence: 000000000xxxxxxx = 0xxxxxxx
+ // (US-ASCII character, "common" case, one branch to here)
+ c = (char) b1;
+ }
+ readBuffer[j++] = c;
+ if (c == '\r')
+ {
+ sawCR = true;
+ }
+ }
+ // How many characters have we read?
+ readBufferLength = j;
+ }
+
+ /**
+ * Return the next byte value in a UTF-8 sequence.
+ * If it is not possible to get a byte from the current
+ * entity, throw an exception.
+ * @param pos The current position in the rawReadBuffer.
+ * @param count The number of bytes in the rawReadBuffer
+ * @return The significant six bits of a non-initial byte in
+ * a UTF-8 sequence.
+ * @exception EOFException If the sequence is incomplete.
+ */
+ private int getNextUtf8Byte(int pos, int count)
+ throws SAXException, IOException
+ {
+ int val;
+
+ // Take a character from the buffer
+ // or from the actual input stream.
+ if (pos < count)
+ {
+ val = rawReadBuffer[pos];
+ }
+ else
+ {
+ val = is.read();
+ if (val == -1)
+ {
+ encodingError("unfinished multi-byte UTF-8 sequence at EOF",
+ -1, pos);
+ }
+ }
+
+ // Check for the correct bits at the start.
+ if ((val & 0xc0) != 0x80)
+ {
+ encodingError("bad continuation of multi-byte UTF-8 sequence",
+ val, pos + 1);
+ }
+
+ // Return the significant bits.
+ return (val & 0x3f);
+ }
+
+ /**
+ * Convert a buffer of US-ASCII or ISO-8859-1-encoded bytes into
+ * UTF-16 characters.
+ *
+ * When readDataChunk () calls this method, the raw bytes are in
+ * rawReadBuffer, and the final characters will appear in
+ * readBuffer.
+ *
+ * @param count The number of bytes to convert.
+ * @param mask For ASCII conversion, 0x7f; else, 0xff.
+ * @see #readDataChunk
+ * @see #rawReadBuffer
+ * @see #readBuffer
+ */
+ private void copyIso8859_1ReadBuffer(int count, char mask)
+ throws IOException
+ {
+ int i, j;
+ for (i = 0, j = readBufferPos; i < count; i++, j++)
+ {
+ char c = (char) (rawReadBuffer[i] & 0xff);
+ if ((c & mask) != 0)
+ {
+ throw new CharConversionException("non-ASCII character U+"
+ + Integer.toHexString(c));
+ }
+ if (c == 0x0085 && xmlVersion == XML_11)
+ {
+ c = '\r';
+ }
+ readBuffer[j] = c;
+ if (c == '\r')
+ {
+ sawCR = true;
+ }
+ }
+ readBufferLength = j;
+ }
+
+ /**
+ * Convert a buffer of UCS-2-encoded bytes into UTF-16 characters
+ * (as used in Java string manipulation).
+ *
+ * When readDataChunk () calls this method, the raw bytes are in
+ * rawReadBuffer, and the final characters will appear in
+ * readBuffer.
+ * @param count The number of bytes to convert.
+ * @param shift1 The number of bits to shift byte 1.
+ * @param shift2 The number of bits to shift byte 2
+ * @see #readDataChunk
+ * @see #rawReadBuffer
+ * @see #readBuffer
+ */
+ private void copyUcs2ReadBuffer(int count, int shift1, int shift2)
+ throws SAXException
+ {
+ int j = readBufferPos;
+
+ if (count > 0 && (count % 2) != 0)
+ {
+ encodingError("odd number of bytes in UCS-2 encoding", -1, count);
+ }
+ // The loops are faster with less internal brancing; hence two
+ if (shift1 == 0)
+ { // "UTF-16-LE"
+ for (int i = 0; i < count; i += 2)
+ {
+ char c = (char) (rawReadBuffer[i + 1] << 8);
+ c |= 0xff & rawReadBuffer[i];
+ readBuffer[j++] = c;
+ if (c == '\r')
+ {
+ sawCR = true;
+ }
+ }
+ }
+ else
+ { // "UTF-16-BE"
+ for (int i = 0; i < count; i += 2)
+ {
+ char c = (char) (rawReadBuffer[i] << 8);
+ c |= 0xff & rawReadBuffer[i + 1];
+ readBuffer[j++] = c;
+ if (c == '\r')
+ {
+ sawCR = true;
+ }
+ }
+ }
+ readBufferLength = j;
+ }
+
+ /**
+ * Convert a buffer of UCS-4-encoded bytes into UTF-16 characters.
+ *
+ * When readDataChunk () calls this method, the raw bytes are in
+ * rawReadBuffer, and the final characters will appear in
+ * readBuffer.
+ * Java has Unicode chars, and this routine uses surrogate pairs
+ * for ISO-10646 values between 0x00010000 and 0x000fffff. An
+ * exception is thrown if the ISO-10646 character has no Unicode
+ * representation.
+ *
+ * @param count The number of bytes to convert.
+ * @param shift1 The number of bits to shift byte 1.
+ * @param shift2 The number of bits to shift byte 2
+ * @param shift3 The number of bits to shift byte 2
+ * @param shift4 The number of bits to shift byte 2
+ * @see #readDataChunk
+ * @see #rawReadBuffer
+ * @see #readBuffer
+ */
+ private void copyUcs4ReadBuffer(int count, int shift1, int shift2,
+ int shift3, int shift4)
+ throws SAXException
+ {
+ int j = readBufferPos;
+
+ if (count > 0 && (count % 4) != 0)
+ {
+ encodingError("number of bytes in UCS-4 encoding " +
+ "not divisible by 4",
+ -1, count);
+ }
+ for (int i = 0; i < count; i += 4)
+ {
+ int value = (((rawReadBuffer [i] & 0xff) << shift1) |
+ ((rawReadBuffer [i + 1] & 0xff) << shift2) |
+ ((rawReadBuffer [i + 2] & 0xff) << shift3) |
+ ((rawReadBuffer [i + 3] & 0xff) << shift4));
+ if (value < 0x0000ffff)
+ {
+ readBuffer [j++] = (char) value;
+ if (value == (int) '\r')
+ {
+ sawCR = true;
+ }
+ }
+ else if (value < 0x0010ffff)
+ {
+ value -= 0x010000;
+ readBuffer[j++] = (char) (0xd8 | ((value >> 10) & 0x03ff));
+ readBuffer[j++] = (char) (0xdc | (value & 0x03ff));
+ }
+ else
+ {
+ encodingError("UCS-4 value out of range for Unicode",
+ value, i);
+ }
+ }
+ readBufferLength = j;
+ }
+
+ /**
+ * Report a character encoding error.
+ */
+ private void encodingError(String message, int value, int offset)
+ throws SAXException
+ {
+ if (value != -1)
+ {
+ message = message + " (character code: 0x" +
+ Integer.toHexString(value) + ')';
+ error(message);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // Local Variables.
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Re-initialize the variables for each parse.
+ */
+ private void initializeVariables()
+ {
+ // First line
+ line = 1;
+ column = 0;
+
+ // Set up the buffers for data and names
+ dataBufferPos = 0;
+ dataBuffer = new char[DATA_BUFFER_INITIAL];
+ nameBufferPos = 0;
+ nameBuffer = new char[NAME_BUFFER_INITIAL];
+
+ // Set up the DTD hash tables
+ elementInfo = new HashMap();
+ entityInfo = new HashMap();
+ notationInfo = new HashMap();
+ skippedPE = false;
+
+ // Set up the variables for the current
+ // element context.
+ currentElement = null;
+ currentElementContent = CONTENT_UNDECLARED;
+
+ // Set up the input variables
+ sourceType = INPUT_NONE;
+ inputStack = new LinkedList();
+ entityStack = new LinkedList();
+ externalEntity = null;
+ tagAttributePos = 0;
+ tagAttributes = new String[100];
+ rawReadBuffer = new byte[READ_BUFFER_MAX];
+ readBufferOverflow = -1;
+
+ scratch = new InputSource();
+
+ inLiteral = false;
+ expandPE = false;
+ peIsError = false;
+
+ doReport = false;
+
+ inCDATA = false;
+
+ symbolTable = new Object[SYMBOL_TABLE_LENGTH][];
+ }
+
+ static class ExternalIdentifiers
+ {
+
+ String publicId;
+ String systemId;
+ String baseUri;
+
+ ExternalIdentifiers()
+ {
+ }
+
+ ExternalIdentifiers(String publicId, String systemId, String baseUri)
+ {
+ this.publicId = publicId;
+ this.systemId = systemId;
+ this.baseUri = baseUri;
+ }
+
+ }
+
+ static class EntityInfo
+ {
+
+ int type;
+ ExternalIdentifiers ids;
+ String value;
+ String notationName;
+
+ }
+
+ static class AttributeDecl
+ {
+
+ String type;
+ String value;
+ int valueType;
+ String enumeration;
+ String defaultValue;
+
+ }
+
+ static class ElementDecl
+ {
+
+ int contentType;
+ String contentModel;
+ HashMap attributes;
+
+ }
+
+ static class Input
+ {
+
+ int sourceType;
+ URLConnection externalEntity;
+ char[] readBuffer;
+ int readBufferPos;
+ int readBufferLength;
+ int line;
+ int encoding;
+ int readBufferOverflow;
+ InputStream is;
+ int currentByteCount;
+ int column;
+ Reader reader;
+
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/aelfred2/XmlReader.java b/libjava/classpath/gnu/xml/aelfred2/XmlReader.java
new file mode 100644
index 0000000..a3bd03a
--- /dev/null
+++ b/libjava/classpath/gnu/xml/aelfred2/XmlReader.java
@@ -0,0 +1,374 @@
+/* XmlReader.java --
+ Copyright (C) 1999,2000,2001 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 gnu.xml.aelfred2;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import org.xml.sax.*;
+import org.xml.sax.ext.*;
+
+import gnu.xml.pipeline.EventFilter;
+import gnu.xml.pipeline.ValidationConsumer;
+
+
+/**
+ * This SAX2 parser optionally layers a validator over the Ælfred2
+ * SAX2 parser. While this will not evaluate every XML validity constraint,
+ * it does support all the validity constraints that are of any real utility
+ * outside the strict SGML-compatible world. See the documentation for the
+ * SAXDriver class for information about the SAX2 features and properties
+ * that are supported, and documentation for the ValidationConsumer for
+ * information about what validity constraints may not be supported.
+ * (Ælfred2 tests some of those, even in non-validating mode, to
+ * achieve better conformance.)
+ *
+ * Note that due to its internal construction, you can't change most
+ * handlers until parse() returns. This diverges slightly from SAX, which
+ * expects later binding to be supported. Early binding involves less
+ * runtime overhead, which is an issue for event pipelines as used inside
+ * this parser. Rather than relying on the parser to handle late binding
+ * to your own handlers, do it yourself.
+ *
+ * @see SAXDriver
+ * @see gnu.xml.pipeline.ValidationConsumer
+ *
+ * @author David Brownell
+ */
+public final class XmlReader
+ implements XMLReader
+{
+
+ static class FatalErrorHandler
+ extends DefaultHandler2
+ {
+
+ public void error(SAXParseException e)
+ throws SAXException
+ {
+ throw e;
+ }
+
+ }
+
+ private SAXDriver aelfred2 = new SAXDriver();
+ private EventFilter filter = new EventFilter();
+ private boolean isValidating;
+ private boolean active;
+
+ /**
+ * Constructs a SAX Parser.
+ */
+ public XmlReader()
+ {
+ }
+
+ /**
+ * Constructs a SAX Parser, optionally treating validity errors
+ * as if they were fatal errors.
+ */
+ public XmlReader(boolean invalidIsFatal)
+ {
+ if (invalidIsFatal)
+ {
+ setErrorHandler(new FatalErrorHandler());
+ }
+ }
+
+ /**
+ * SAX2: Returns the object used to report the logical
+ * content of an XML document.
+ */
+ public ContentHandler getContentHandler()
+ {
+ return filter.getContentHandler();
+ }
+
+ /**
+ * SAX2: Assigns the object used to report the logical
+ * content of an XML document.
+ * @exception IllegalStateException if called mid-parse
+ */
+ public void setContentHandler(ContentHandler handler)
+ {
+ if (active)
+ {
+ throw new IllegalStateException("already parsing");
+ }
+ filter.setContentHandler(handler);
+ }
+
+ /**
+ * SAX2: Returns the object used to process declarations related
+ * to notations and unparsed entities.
+ */
+ public DTDHandler getDTDHandler()
+ {
+ return filter.getDTDHandler();
+ }
+
+ /**
+ * SAX1 Assigns DTD handler
+ * @exception IllegalStateException if called mid-parse
+ */
+ public void setDTDHandler(DTDHandler handler)
+ {
+ if (active)
+ {
+ throw new IllegalStateException("already parsing");
+ }
+ filter.setDTDHandler(handler);
+ }
+
+ /**
+ * SAX2: Returns the object used when resolving external
+ * entities during parsing (both general and parameter entities).
+ */
+ public EntityResolver getEntityResolver()
+ {
+ return aelfred2.getEntityResolver();
+ }
+
+ /**
+ * SAX1 Assigns parser's entity resolver
+ */
+ public void setEntityResolver(EntityResolver handler)
+ {
+ aelfred2.setEntityResolver(handler);
+ }
+
+ /**
+ * SAX2: Returns the object used to receive callbacks for XML
+ * errors of all levels (fatal, nonfatal, warning); this is never null;
+ */
+ public ErrorHandler getErrorHandler()
+ {
+ return aelfred2.getErrorHandler();
+ }
+
+ /**
+ * SAX1 Assigns error handler
+ * @exception IllegalStateException if called mid-parse
+ */
+ public void setErrorHandler(ErrorHandler handler)
+ {
+ if (active)
+ {
+ throw new IllegalStateException("already parsing");
+ }
+ aelfred2.setErrorHandler(handler);
+ }
+
+ /**
+ * SAX2: Assigns the specified property.
+ * @exception IllegalStateException if called mid-parse
+ */
+ public void setProperty(String propertyId, Object value)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ if (active)
+ {
+ throw new IllegalStateException("already parsing");
+ }
+ if (getProperty(propertyId) != value)
+ {
+ filter.setProperty(propertyId, value);
+ }
+ }
+
+ /**
+ * SAX2: Returns the specified property.
+ */
+ public Object getProperty(String propertyId)
+ throws SAXNotRecognizedException
+ {
+ if ((SAXDriver.PROPERTY + "declaration-handler").equals(propertyId)
+ || (SAXDriver.PROPERTY + "lexical-handler").equals(propertyId))
+ {
+ return filter.getProperty(propertyId);
+ }
+ throw new SAXNotRecognizedException(propertyId);
+ }
+
+ private void forceValidating()
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ aelfred2.setFeature(SAXDriver.FEATURE + "namespace-prefixes",
+ true);
+ aelfred2.setFeature(SAXDriver.FEATURE + "external-general-entities",
+ true);
+ aelfred2.setFeature(SAXDriver.FEATURE + "external-parameter-entities",
+ true);
+ }
+
+ /**
+ * SAX2: Sets the state of features supported in this parser.
+ * Note that this parser requires reporting of namespace prefixes when
+ * validating.
+ */
+ public void setFeature(String featureId, boolean state)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ boolean value = getFeature(featureId);
+
+ if (state == value)
+ {
+ return;
+ }
+
+ if ((SAXDriver.FEATURE + "validation").equals(featureId))
+ {
+ if (active)
+ {
+ throw new SAXNotSupportedException("already parsing");
+ }
+ if (state)
+ {
+ forceValidating();
+ }
+ isValidating = state;
+ }
+ else
+ {
+ aelfred2.setFeature(featureId, state);
+ }
+ }
+
+ /**
+ * SAX2: Tells whether this parser supports the specified feature.
+ * At this time, this directly parallels the underlying SAXDriver,
+ * except that validation is optionally supported.
+ *
+ * @see SAXDriver
+ */
+ public boolean getFeature(String featureId)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ if ((SAXDriver.FEATURE + "validation").equals(featureId))
+ {
+ return isValidating;
+ }
+
+ return aelfred2.getFeature(featureId);
+ }
+
+ /**
+ * SAX1: Sets the locale used for diagnostics; currently,
+ * only locales using the English language are supported.
+ * @param locale The locale for which diagnostics will be generated
+ */
+ public void setLocale(Locale locale)
+ throws SAXException
+ {
+ aelfred2.setLocale(locale);
+ }
+
+ /**
+ * SAX1: Preferred API to parse an XML document, using a
+ * system identifier (URI).
+ */
+ public void parse(String systemId)
+ throws SAXException, IOException
+ {
+ parse(new InputSource(systemId));
+ }
+
+ /**
+ * SAX1: Underlying API to parse an XML document, used
+ * directly when no URI is available. When this is invoked,
+ * and the parser is set to validate, some features will be
+ * automatically reset to appropriate values: for reporting
+ * namespace prefixes, and incorporating external entities.
+ *
+ * @param source The XML input source.
+ *
+ * @exception IllegalStateException if called mid-parse
+ * @exception SAXException The handlers may throw any SAXException,
+ * and the parser normally throws SAXParseException objects.
+ * @exception IOException IOExceptions are normally through through
+ * the parser if there are problems reading the source document.
+ */
+ public void parse(InputSource source)
+ throws SAXException, IOException
+ {
+ EventFilter next;
+ boolean nsdecls;
+
+ synchronized (aelfred2)
+ {
+ if (active)
+ {
+ throw new IllegalStateException("already parsing");
+ }
+ active = true;
+ }
+
+ // set up the output pipeline
+ if (isValidating)
+ {
+ forceValidating();
+ next = new ValidationConsumer(filter);
+ }
+ else
+ {
+ next = filter;
+ }
+
+ // connect pipeline and error handler
+ // don't let _this_ call to bind() affect xmlns* attributes
+ nsdecls = aelfred2.getFeature(SAXDriver.FEATURE + "namespace-prefixes");
+ EventFilter.bind(aelfred2, next);
+ if (!nsdecls)
+ {
+ aelfred2.setFeature(SAXDriver.FEATURE + "namespace-prefixes",
+ false);
+ }
+
+ // parse, clean up
+ try
+ {
+ aelfred2.parse(source);
+ }
+ finally
+ {
+ active = false;
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/aelfred2/package.html b/libjava/classpath/gnu/xml/aelfred2/package.html
new file mode 100644
index 0000000..e204258
--- /dev/null
+++ b/libjava/classpath/gnu/xml/aelfred2/package.html
@@ -0,0 +1,506 @@
+
+
+ This package contains Ælfred2, which includes an
+enhanced SAX2-compatible version of the Ælfred
+non-validating XML parser, a modular (and hence optional)
+DTD validating parser, and modular (and hence optional)
+JAXP glue to those.
+Use these like any other SAX2 parsers. Ælfred is a XML parser written in the java programming language.
+
+ In most Java applets and applications, XML should not be the central
+feature; instead, XML is the means to another end, such as loading
+configuration information, reading meta-data, or parsing transactions. When an XML parser is only a single component of a much larger
+program, it cannot be large, slow, or resource-intensive. With Java
+applets, in particular, code size is a significant issue. The standard
+modem is still not operating at 56 Kbaud, or sometimes even with data
+compression. Assuming an uncompressed 28.8 Kbaud modem, only about
+3 KBytes can be downloaded in one second; compression often doubles
+that speed, but a V.90 modem may not provide another doubling. When
+used with embedded processors, similar size concerns apply. Ælfred is designed for easy and efficient use over the Internet,
+based on the following principles: As you can see from this list, Ælfred is designed for production
+use, but neither validation nor perfect conformance was a requirement.
+Good validating parsers exist, including one in this package,
+and you should use them as appropriate. (See conformance reviews
+available at http://www.xml.com)
+ One of the main goals of Ælfred2 was to significantly improve
+conformance, while not significantly affecting the other goals stated above.
+Since the only use of this parser is with SAX, some classes could be
+removed, and so the overall size of Ælfred was actually reduced.
+Subsequent performance work produced a notable speedup (over twenty
+percent on larger files). That is, the tradeoffs between speed, size, and
+conformance were re-targeted towards conformance and support of newer APIs
+(SAX2), with a a positive performance impact. The role anticipated for this version of Ælfred is as a
+lightweight Free Software SAX parser that can be used in essentially every
+Java program where the handful of conformance violations (noted below)
+are acceptable.
+That certainly includes applets, and
+nowadays one must also mention embedded systems as being even more
+size-critical.
+At this writing, all parsers that are more conformant are
+significantly larger, even when counting the optional
+validation support in this version of Ælfred. Ælfred the Great (AElfred in ASCII) was King of Wessex, and
+some say of King of England, at the time of his death in 899 AD.
+Ælfred introduced a wide-spread literacy program in the hope that
+his people would learn to read English, at least, if Latin was too
+difficult for them. This Ælfred hopes to bring another sort of
+literacy to Java, using XML, at least, if full SGML is too difficult. The initial Æ ligature ("AE)" is also a reminder that XML is
+not limited to ASCII. The Ælfred parser currently builds in support for a handful
+of input encodings. Of course these include UTF-8 and UTF-16, which
+all XML parsers are required to support: If you use any encoding other than UTF-8 or UTF-16 you should
+make sure to label your data appropriately: Encodings accessed through Note that if you are using the Euro symbol with an fixed length
+eight bit encoding, you should probably be using the encoding label
+iso-8859-15 or, with a Microsoft OS, cp-1252.
+Of course, UTF-8 and UTF-16 handle the Euro symbol directly.
+ Known conformance issues should be of negligible importance for
+most applications, and include: When tested against the July 12, 1999 version of the OASIS
+XML Conformance test suite, an earlier version passed 1057 of 1067 tests.
+That contrasts with the original version, which passed 867. The
+current parser is top-ranked in terms of conformance, as is its
+validating sibling (which has some additional conformance violations
+imposed on it by SAX2 API deficiencies as well as some of the more
+curious SGML layering artifacts found in the XML specification). The XML 1.0 specification itself was not without problems,
+and after some delays the W3C has come out with a revised
+"second edition" specification. While that doesn't resolve all
+the problems identified the XML specification, many of the most
+egregious problems have been resolved. (You still need to drink
+magic Kool-Aid before some DTD-related issues make sense.)
+To the extent possible, this parser conforms to that second
+edition specification, and does well against corrected versions
+of the OASIS/NIST XML conformance test cases. See http://xmlconf.sourceforge.net
+for more information about SAX2/XML conformance testing.
+The software in this package is distributed under the GNU General Public
+License (with a special exception described below).
+
+A copy of GNU General Public License (GPL) is included in this distribution,
+in the file COPYING. If you do not have the source code, it is available at:
+
+ http://www.gnu.org/software/classpath/
+ Some of this documentation was modified from the original
+Ælfred README.txt file. All of it has been updated. getMatch()
(see the
+ * description of that method for an explanation of why). Enumeration
+ * also saves a lot of overhead required when calling
+ * getMatch()
multiple times.
+ *
+ * @author Wes Biggs
+ */
+public class REMatchEnumeration implements Enumeration, Serializable {
+ private static final int YES = 1;
+ private static final int MAYBE = 0;
+ private static final int NO = -1;
+
+ private int more;
+ private REMatch match;
+ private RE expr;
+ private CharIndexed input;
+ private int eflags;
+ private int index;
+
+ // Package scope constructor is used by RE.getMatchEnumeration()
+ REMatchEnumeration(RE expr, CharIndexed input, int index, int eflags) {
+ more = MAYBE;
+ this.expr = expr;
+ this.input = input;
+ this.index = index;
+ this.eflags = eflags;
+ }
+
+ /** Returns true if there are more matches in the input text. */
+ public boolean hasMoreElements() {
+ return hasMoreMatches(null);
+ }
+
+ /** Returns true if there are more matches in the input text. */
+ public boolean hasMoreMatches() {
+ return hasMoreMatches(null);
+ }
+
+ /** Returns true if there are more matches in the input text.
+ * Saves the text leading up to the match (or to the end of the input)
+ * in the specified buffer.
+ */
+ public boolean hasMoreMatches(StringBuffer buffer) {
+ if (more == MAYBE) {
+ match = expr.getMatchImpl(input,index,eflags,buffer);
+ if (match != null) {
+ input.move((match.end[0] > 0) ? match.end[0] : 1);
+
+ index = (match.end[0] > 0) ? match.end[0] + match.offset : index + 1;
+ more = YES;
+ } else more = NO;
+ }
+ return (more == YES);
+ }
+
+ /** Returns the next match in the input text. */
+ public Object nextElement() throws NoSuchElementException {
+ return nextMatch();
+ }
+
+ /**
+ * Returns the next match in the input text. This method is provided
+ * for convenience to avoid having to explicitly cast the return value
+ * to class REMatch.
+ */
+ public REMatch nextMatch() throws NoSuchElementException {
+ if (hasMoreElements()) {
+ more = (input.isValid()) ? MAYBE : NO;
+ return match;
+ }
+ throw new NoSuchElementException();
+ }
+}
+
diff --git a/libjava/classpath/gnu/regexp/RESyntax.java b/libjava/classpath/gnu/regexp/RESyntax.java
new file mode 100644
index 0000000..7272b03
--- /dev/null
+++ b/libjava/classpath/gnu/regexp/RESyntax.java
@@ -0,0 +1,527 @@
+/* gnu/regexp/RESyntax.java
+ Copyright (C) 1998-2002, 2004 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 gnu.regexp;
+import java.io.Serializable;
+import java.util.BitSet;
+
+/**
+ * An RESyntax specifies the way a regular expression will be compiled.
+ * This class provides a number of predefined useful constants for
+ * emulating popular regular expression syntaxes. Additionally the
+ * user may construct his or her own syntax, using any combination of the
+ * syntax bit constants. The syntax is an optional argument to any of the
+ * matching methods on class RE.
+ *
+ * @author Wes Biggs
+ */
+
+public final class RESyntax implements Serializable {
+ static final String DEFAULT_LINE_SEPARATOR = System.getProperty("line.separator");
+
+ private static final String SYNTAX_IS_FINAL = RE.getLocalizedMessage("syntax.final");
+
+ private BitSet bits;
+
+ // true for the constant defined syntaxes
+ private boolean isFinal = false;
+
+ private String lineSeparator = DEFAULT_LINE_SEPARATOR;
+
+ // Values for constants are bit indexes
+
+ /**
+ * Syntax bit. Backslash is an escape character in lists.
+ */
+ public static final int RE_BACKSLASH_ESCAPE_IN_LISTS = 0;
+
+ /**
+ * Syntax bit. Use \? instead of ? and \+ instead of +.
+ */
+ public static final int RE_BK_PLUS_QM = 1;
+
+ /**
+ * Syntax bit. POSIX character classes ([:...:]) in lists are allowed.
+ */
+ public static final int RE_CHAR_CLASSES = 2;
+
+ /**
+ * Syntax bit. ^ and $ are special everywhere.
+ * Not implemented.
+ */
+ public static final int RE_CONTEXT_INDEP_ANCHORS = 3;
+
+ /**
+ * Syntax bit. Repetition operators are only special in valid positions.
+ * Not implemented.
+ */
+ public static final int RE_CONTEXT_INDEP_OPS = 4;
+
+ /**
+ * Syntax bit. Repetition and alternation operators are invalid
+ * at start and end of pattern and other places.
+ * Not implemented.
+ */
+ public static final int RE_CONTEXT_INVALID_OPS = 5;
+
+ /**
+ * Syntax bit. Match-any-character operator (.) matches a newline.
+ */
+ public static final int RE_DOT_NEWLINE = 6;
+
+ /**
+ * Syntax bit. Match-any-character operator (.) does not match a null.
+ */
+ public static final int RE_DOT_NOT_NULL = 7;
+
+ /**
+ * Syntax bit. Intervals ({x}, {x,}, {x,y}) are allowed.
+ */
+ public static final int RE_INTERVALS = 8;
+
+ /**
+ * Syntax bit. No alternation (|), match one-or-more (+), or
+ * match zero-or-one (?) operators.
+ */
+ public static final int RE_LIMITED_OPS = 9;
+
+ /**
+ * Syntax bit. Newline is an alternation operator.
+ */
+ public static final int RE_NEWLINE_ALT = 10; // impl.
+
+ /**
+ * Syntax bit. Intervals use { } instead of \{ \}
+ */
+ public static final int RE_NO_BK_BRACES = 11;
+
+ /**
+ * Syntax bit. Grouping uses ( ) instead of \( \).
+ */
+ public static final int RE_NO_BK_PARENS = 12;
+
+ /**
+ * Syntax bit. Backreferences not allowed.
+ */
+ public static final int RE_NO_BK_REFS = 13;
+
+ /**
+ * Syntax bit. Alternation uses | instead of \|
+ */
+ public static final int RE_NO_BK_VBAR = 14;
+
+ /**
+ * Syntax bit. Not implemented.
+ */
+ public static final int RE_NO_EMPTY_RANGES = 15;
+
+ /**
+ * Syntax bit. An unmatched right parenthesis (')' or '\)', depending
+ * on RE_NO_BK_PARENS) will throw an exception when compiling.
+ */
+ public static final int RE_UNMATCHED_RIGHT_PAREN_ORD = 16;
+
+ /**
+ * Syntax bit. Not implemented.
+ */
+ public static final int RE_HAT_LISTS_NOT_NEWLINE = 17;
+
+ /**
+ * Syntax bit. Stingy matching is allowed (+?, *?, ??, {x,y}?).
+ */
+ public static final int RE_STINGY_OPS = 18;
+
+ /**
+ * Syntax bit. Allow character class escapes (\d, \D, \s, \S, \w, \W).
+ */
+ public static final int RE_CHAR_CLASS_ESCAPES = 19;
+
+ /**
+ * Syntax bit. Allow use of (?:xxx) grouping (subexpression is not saved).
+ */
+ public static final int RE_PURE_GROUPING = 20;
+
+ /**
+ * Syntax bit. Allow use of (?=xxx) and (?!xxx) apply the subexpression
+ * to the text following the current position without consuming that text.
+ */
+ public static final int RE_LOOKAHEAD = 21;
+
+ /**
+ * Syntax bit. Allow beginning- and end-of-string anchors (\A, \Z).
+ */
+ public static final int RE_STRING_ANCHORS = 22;
+
+ /**
+ * Syntax bit. Allow embedded comments, (?#comment), as in Perl5.
+ */
+ public static final int RE_COMMENTS = 23;
+
+ /**
+ * Syntax bit. Allow character class escapes within lists, as in Perl5.
+ */
+ public static final int RE_CHAR_CLASS_ESC_IN_LISTS = 24;
+
+ /**
+ * Syntax bit. Possessive matching is allowed (++, *+, ?+, {x,y}+).
+ */
+ public static final int RE_POSSESSIVE_OPS = 25;
+
+ private static final int BIT_TOTAL = 26;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in the awk utility.
+ */
+ public static final RESyntax RE_SYNTAX_AWK;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in the ed utility.
+ */
+ public static final RESyntax RE_SYNTAX_ED;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in the egrep utility.
+ */
+ public static final RESyntax RE_SYNTAX_EGREP;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in the GNU Emacs editor.
+ */
+ public static final RESyntax RE_SYNTAX_EMACS;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in the grep utility.
+ */
+ public static final RESyntax RE_SYNTAX_GREP;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in the POSIX awk specification.
+ */
+ public static final RESyntax RE_SYNTAX_POSIX_AWK;
+
+ /**
+ * Predefined syntax.
+ * Emulates POSIX basic regular expression support.
+ */
+ public static final RESyntax RE_SYNTAX_POSIX_BASIC;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in the POSIX egrep specification.
+ */
+ public static final RESyntax RE_SYNTAX_POSIX_EGREP;
+
+ /**
+ * Predefined syntax.
+ * Emulates POSIX extended regular expression support.
+ */
+ public static final RESyntax RE_SYNTAX_POSIX_EXTENDED;
+
+ /**
+ * Predefined syntax.
+ * Emulates POSIX basic minimal regular expressions.
+ */
+ public static final RESyntax RE_SYNTAX_POSIX_MINIMAL_BASIC;
+
+ /**
+ * Predefined syntax.
+ * Emulates POSIX extended minimal regular expressions.
+ */
+ public static final RESyntax RE_SYNTAX_POSIX_MINIMAL_EXTENDED;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in the sed utility.
+ */
+ public static final RESyntax RE_SYNTAX_SED;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in Larry Wall's perl, version 4,
+ */
+ public static final RESyntax RE_SYNTAX_PERL4;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in Larry Wall's perl, version 4,
+ * using single line mode (/s modifier).
+ */
+ public static final RESyntax RE_SYNTAX_PERL4_S; // single line mode (/s)
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in Larry Wall's perl, version 5.
+ */
+ public static final RESyntax RE_SYNTAX_PERL5;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in Larry Wall's perl, version 5,
+ * using single line mode (/s modifier).
+ */
+ public static final RESyntax RE_SYNTAX_PERL5_S;
+
+ /**
+ * Predefined syntax.
+ * Emulates regular expression support in Java 1.4's java.util.regex
+ * package.
+ */
+ public static final RESyntax RE_SYNTAX_JAVA_1_4;
+
+ static {
+ // Define syntaxes
+
+ RE_SYNTAX_EMACS = new RESyntax().makeFinal();
+
+ RESyntax RE_SYNTAX_POSIX_COMMON = new RESyntax()
+ .set(RE_CHAR_CLASSES)
+ .set(RE_DOT_NEWLINE)
+ .set(RE_DOT_NOT_NULL)
+ .set(RE_INTERVALS)
+ .set(RE_NO_EMPTY_RANGES)
+ .makeFinal();
+
+ RE_SYNTAX_POSIX_BASIC = new RESyntax(RE_SYNTAX_POSIX_COMMON)
+ .set(RE_BK_PLUS_QM)
+ .makeFinal();
+
+ RE_SYNTAX_POSIX_EXTENDED = new RESyntax(RE_SYNTAX_POSIX_COMMON)
+ .set(RE_CONTEXT_INDEP_ANCHORS)
+ .set(RE_CONTEXT_INDEP_OPS)
+ .set(RE_NO_BK_BRACES)
+ .set(RE_NO_BK_PARENS)
+ .set(RE_NO_BK_VBAR)
+ .set(RE_UNMATCHED_RIGHT_PAREN_ORD)
+ .makeFinal();
+
+ RE_SYNTAX_AWK = new RESyntax()
+ .set(RE_BACKSLASH_ESCAPE_IN_LISTS)
+ .set(RE_DOT_NOT_NULL)
+ .set(RE_NO_BK_PARENS)
+ .set(RE_NO_BK_REFS)
+ .set(RE_NO_BK_VBAR)
+ .set(RE_NO_EMPTY_RANGES)
+ .set(RE_UNMATCHED_RIGHT_PAREN_ORD)
+ .makeFinal();
+
+ RE_SYNTAX_POSIX_AWK = new RESyntax(RE_SYNTAX_POSIX_EXTENDED)
+ .set(RE_BACKSLASH_ESCAPE_IN_LISTS)
+ .makeFinal();
+
+ RE_SYNTAX_GREP = new RESyntax()
+ .set(RE_BK_PLUS_QM)
+ .set(RE_CHAR_CLASSES)
+ .set(RE_HAT_LISTS_NOT_NEWLINE)
+ .set(RE_INTERVALS)
+ .set(RE_NEWLINE_ALT)
+ .makeFinal();
+
+ RE_SYNTAX_EGREP = new RESyntax()
+ .set(RE_CHAR_CLASSES)
+ .set(RE_CONTEXT_INDEP_ANCHORS)
+ .set(RE_CONTEXT_INDEP_OPS)
+ .set(RE_HAT_LISTS_NOT_NEWLINE)
+ .set(RE_NEWLINE_ALT)
+ .set(RE_NO_BK_PARENS)
+ .set(RE_NO_BK_VBAR)
+ .makeFinal();
+
+ RE_SYNTAX_POSIX_EGREP = new RESyntax(RE_SYNTAX_EGREP)
+ .set(RE_INTERVALS)
+ .set(RE_NO_BK_BRACES)
+ .makeFinal();
+
+ /* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+
+ RE_SYNTAX_ED = new RESyntax(RE_SYNTAX_POSIX_BASIC)
+ .makeFinal();
+
+ RE_SYNTAX_SED = new RESyntax(RE_SYNTAX_POSIX_BASIC)
+ .makeFinal();
+
+ RE_SYNTAX_POSIX_MINIMAL_BASIC = new RESyntax(RE_SYNTAX_POSIX_COMMON)
+ .set(RE_LIMITED_OPS)
+ .makeFinal();
+
+ /* Differs from RE_SYNTAX_POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+ replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
+
+ RE_SYNTAX_POSIX_MINIMAL_EXTENDED = new RESyntax(RE_SYNTAX_POSIX_COMMON)
+ .set(RE_CONTEXT_INDEP_ANCHORS)
+ .set(RE_CONTEXT_INVALID_OPS)
+ .set(RE_NO_BK_BRACES)
+ .set(RE_NO_BK_PARENS)
+ .set(RE_NO_BK_REFS)
+ .set(RE_NO_BK_VBAR)
+ .set(RE_UNMATCHED_RIGHT_PAREN_ORD)
+ .makeFinal();
+
+ /* There is no official Perl spec, but here's a "best guess" */
+
+ RE_SYNTAX_PERL4 = new RESyntax()
+ .set(RE_BACKSLASH_ESCAPE_IN_LISTS)
+ .set(RE_CONTEXT_INDEP_ANCHORS)
+ .set(RE_CONTEXT_INDEP_OPS) // except for '{', apparently
+ .set(RE_INTERVALS)
+ .set(RE_NO_BK_BRACES)
+ .set(RE_NO_BK_PARENS)
+ .set(RE_NO_BK_VBAR)
+ .set(RE_NO_EMPTY_RANGES)
+ .set(RE_CHAR_CLASS_ESCAPES) // \d,\D,\w,\W,\s,\S
+ .makeFinal();
+
+ RE_SYNTAX_PERL4_S = new RESyntax(RE_SYNTAX_PERL4)
+ .set(RE_DOT_NEWLINE)
+ .makeFinal();
+
+ RE_SYNTAX_PERL5 = new RESyntax(RE_SYNTAX_PERL4)
+ .set(RE_PURE_GROUPING) // (?:)
+ .set(RE_STINGY_OPS) // *?,??,+?,{}?
+ .set(RE_LOOKAHEAD) // (?=)(?!)
+ .set(RE_STRING_ANCHORS) // \A,\Z
+ .set(RE_CHAR_CLASS_ESC_IN_LISTS)// \d,\D,\w,\W,\s,\S within []
+ .set(RE_COMMENTS) // (?#)
+ .makeFinal();
+
+ RE_SYNTAX_PERL5_S = new RESyntax(RE_SYNTAX_PERL5)
+ .set(RE_DOT_NEWLINE)
+ .makeFinal();
+
+ RE_SYNTAX_JAVA_1_4 = new RESyntax(RE_SYNTAX_PERL5)
+ // XXX
+ .set(RE_POSSESSIVE_OPS) // *+,?+,++,{}+
+ .makeFinal();
+ }
+
+ /**
+ * Construct a new syntax object with all bits turned off.
+ * This is equivalent to RE_SYNTAX_EMACS.
+ */
+ public RESyntax() {
+ bits = new BitSet(BIT_TOTAL);
+ }
+
+ /**
+ * Called internally when constructing predefined syntaxes
+ * so their interpretation cannot vary. Conceivably useful
+ * for your syntaxes as well. Causes IllegalAccessError to
+ * be thrown if any attempt to modify the syntax is made.
+ *
+ * @return this object for convenient chaining
+ */
+ public RESyntax makeFinal() {
+ isFinal = true;
+ return this;
+ }
+
+ /**
+ * Construct a new syntax object with all bits set the same
+ * as the other syntax.
+ */
+ public RESyntax(RESyntax other) {
+ bits = (BitSet) other.bits.clone();
+ }
+
+ /**
+ * Check if a given bit is set in this syntax.
+ */
+ public boolean get(int index) {
+ return bits.get(index);
+ }
+
+ /**
+ * Set a given bit in this syntax.
+ *
+ * @param index the constant (RESyntax.RE_xxx) bit to set.
+ * @return a reference to this object for easy chaining.
+ */
+ public RESyntax set(int index) {
+ if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL);
+ bits.set(index);
+ return this;
+ }
+
+ /**
+ * Clear a given bit in this syntax.
+ *
+ * @param index the constant (RESyntax.RE_xxx) bit to clear.
+ * @return a reference to this object for easy chaining.
+ */
+ public RESyntax clear(int index) {
+ if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL);
+ bits.clear(index);
+ return this;
+ }
+
+ /**
+ * Changes the line separator string for regular expressions
+ * created using this RESyntax. The default separator is the
+ * value returned by the system property "line.separator", which
+ * should be correct when reading platform-specific files from a
+ * filesystem. However, many programs may collect input from
+ * sources where the line separator is differently specified (for
+ * example, in the applet environment, the text box widget
+ * interprets line breaks as single-character newlines,
+ * regardless of the host platform.
+ *
+ * Note that setting the line separator to a character or
+ * characters that have specific meaning within the current syntax
+ * can cause unexpected chronosynclastic infundibula.
+ *
+ * @return this object for convenient chaining
+ */
+ public RESyntax setLineSeparator(String aSeparator) {
+ if (isFinal) throw new IllegalAccessError(SYNTAX_IS_FINAL);
+ lineSeparator = aSeparator;
+ return this;
+ }
+
+ /**
+ * Returns the currently active line separator string. The default
+ * is the platform-dependent system property "line.separator".
+ */
+ public String getLineSeparator() {
+ return lineSeparator;
+ }
+}
diff --git a/libjava/classpath/gnu/regexp/REToken.java b/libjava/classpath/gnu/regexp/REToken.java
new file mode 100644
index 0000000..4eae9ec
--- /dev/null
+++ b/libjava/classpath/gnu/regexp/REToken.java
@@ -0,0 +1,86 @@
+/* gnu/regexp/REToken.java
+ Copyright (C) 1998-2001, 2004 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 gnu.regexp;
+import java.io.Serializable;
+
+abstract class REToken implements Serializable {
+
+ protected REToken next = null;
+ protected REToken uncle = null;
+ protected int subIndex;
+
+ protected REToken(int subIndex) {
+ this.subIndex = subIndex;
+ }
+
+ int getMinimumLength() {
+ return 0;
+ }
+
+ void setUncle(REToken anUncle) {
+ uncle = anUncle;
+ }
+
+ /** Returns true if the match succeeded, false if it failed. */
+ abstract boolean match(CharIndexed input, REMatch mymatch);
+
+ /** Returns true if the rest of the tokens match, false if they fail. */
+ protected boolean next(CharIndexed input, REMatch mymatch) {
+ if (next == null) {
+ if (uncle == null) {
+ return true;
+ } else {
+ return uncle.match(input, mymatch);
+ }
+ } else {
+ return next.match(input, mymatch);
+ }
+ }
+
+ boolean chain(REToken token) {
+ next = token;
+ return true; // Token was accepted
+ }
+
+ abstract void dump(StringBuffer os);
+
+ void dumpAll(StringBuffer os) {
+ dump(os);
+ if (next != null) next.dumpAll(os);
+ }
+}
diff --git a/libjava/classpath/gnu/regexp/RETokenAny.java b/libjava/classpath/gnu/regexp/RETokenAny.java
new file mode 100644
index 0000000..ac032dc
--- /dev/null
+++ b/libjava/classpath/gnu/regexp/RETokenAny.java
@@ -0,0 +1,73 @@
+/* gnu/regexp/RETokenAny.java
+ Copyright (C) 1998-2001, 2004 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 gnu.regexp;
+
+final class RETokenAny extends REToken {
+ /** True if '.' can match a newline (RE_DOT_NEWLINE) */
+ private boolean newline;
+
+ /** True if '.' can't match a null (RE_DOT_NOT_NULL) */
+ private boolean matchNull;
+
+ RETokenAny(int subIndex, boolean newline, boolean matchNull) {
+ super(subIndex);
+ this.newline = newline;
+ this.matchNull = matchNull;
+ }
+
+ int getMinimumLength() {
+ return 1;
+ }
+
+ boolean match(CharIndexed input, REMatch mymatch) {
+ char ch = input.charAt(mymatch.index);
+ if ((ch == CharIndexed.OUT_OF_BOUNDS)
+ || (!newline && (ch == '\n'))
+ || (matchNull && (ch == 0))) {
+ return false;
+ }
+ ++mymatch.index;
+ return next(input, mymatch);
+ }
+
+ void dump(StringBuffer os) {
+ os.append('.');
+ }
+}
+
diff --git a/libjava/classpath/gnu/regexp/RETokenBackRef.java b/libjava/classpath/gnu/regexp/RETokenBackRef.java
new file mode 100644
index 0000000..674822a
--- /dev/null
+++ b/libjava/classpath/gnu/regexp/RETokenBackRef.java
@@ -0,0 +1,72 @@
+/* gnu/regexp/RETokenBackRef.java
+ Copyright (C) 1998-2001, 2004 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 gnu.regexp;
+
+final class RETokenBackRef extends REToken {
+ private int num;
+ private boolean insens;
+
+ RETokenBackRef(int subIndex, int num, boolean insens) {
+ super(subIndex);
+ this.num = num;
+ this.insens = insens;
+ }
+
+ // should implement getMinimumLength() -- any ideas?
+
+ boolean match(CharIndexed input, REMatch mymatch) {
+ int b,e;
+ b = mymatch.start[num];
+ e = mymatch.end[num];
+ if ((b==-1)||(e==-1)) return false; // this shouldn't happen, but...
+ for (int i=b; itest
is invoked once for each test.
+ */
+public interface Test
+{
+ /**
+ * Returns the name of the test.
+ */
+ public String getName();
+
+ /**
+ * Performs a test.
+ *
+ * @return result from running the test
+ */
+ public Result test();
+}
diff --git a/libjava/classpath/gnu/test/Unresolved.java b/libjava/classpath/gnu/test/Unresolved.java
new file mode 100644
index 0000000..280d8b6
--- /dev/null
+++ b/libjava/classpath/gnu/test/Unresolved.java
@@ -0,0 +1,57 @@
+/* Unresolved.java - Result code returned when test gives indeterminate results.
+ Copyright (c) 1998 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 gnu.test;
+
+/**
+ * Test produced indeterminate results.
+ */
+public class Unresolved extends Result
+{
+ /**
+ * Constructs an Unresolved result code with additional information.
+ */
+ public Unresolved(String msg) {
+ super("UNRESOLVED", msg);
+ }
+ /**
+ * Constructs an Unresolved result code.
+ */
+ public Unresolved() {
+ this("");
+ }
+}
diff --git a/libjava/classpath/gnu/test/Unsupported.java b/libjava/classpath/gnu/test/Unsupported.java
new file mode 100644
index 0000000..c6dabb0
--- /dev/null
+++ b/libjava/classpath/gnu/test/Unsupported.java
@@ -0,0 +1,59 @@
+/* Unsupported.java -- Result code returned when test does not have the
+ Copyright (c) 1998 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 gnu.test;
+
+/**
+ * Test does not have the required support to run. For example,
+ * Unsupported could be returned when a needed resource
+ * (ie. multicasting) is not available.
+ */
+public class Unsupported extends Result
+{
+ /**
+ * Constructs an Unsupported result code with additional information.
+ */
+ public Unsupported(String msg) {
+ super("UNSUPPORTED", msg);
+ }
+ /**
+ * Constructs an Unsupported result code.
+ */
+ public Unsupported() {
+ this("");
+ }
+}
diff --git a/libjava/classpath/gnu/test/Untested.java b/libjava/classpath/gnu/test/Untested.java
new file mode 100644
index 0000000..5627fa8
--- /dev/null
+++ b/libjava/classpath/gnu/test/Untested.java
@@ -0,0 +1,57 @@
+/* Untested.java -- Result code returned when test was not run -- placeholder.
+ Copyright (c) 1998 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 gnu.test;
+
+/**
+ * Test was not run -- a placeholder.
+ */
+public class Untested extends Result
+{
+ /**
+ * Constructs an Untested result code with additional information.
+ */
+ public Untested(String msg) {
+ super("UNTESTED", msg);
+ }
+ /**
+ * Constructs an Untested result code.
+ */
+ public Untested() {
+ this("");
+ }
+}
diff --git a/libjava/classpath/gnu/test/XFail.java b/libjava/classpath/gnu/test/XFail.java
new file mode 100644
index 0000000..793ff11
--- /dev/null
+++ b/libjava/classpath/gnu/test/XFail.java
@@ -0,0 +1,57 @@
+/* XFail.java - Result code returned when test failed and was expected to fail.
+ Copyright (c) 1998 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 gnu.test;
+
+/**
+ * Test failed and was expected to fail.
+ */
+public class XFail extends Result
+{
+ /**
+ * Constructs an XFail result code with additional information.
+ */
+ public XFail(String msg) {
+ super("XFAIL", msg);
+ }
+ /**
+ * Constructs an XFail result code.
+ */
+ public XFail() {
+ this("");
+ }
+}
diff --git a/libjava/classpath/gnu/test/XPass.java b/libjava/classpath/gnu/test/XPass.java
new file mode 100644
index 0000000..b41dd1c
--- /dev/null
+++ b/libjava/classpath/gnu/test/XPass.java
@@ -0,0 +1,56 @@
+/* XPass.java - Result code returned when test passed but was expected to fail.
+ Copyright (c) 1998 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 gnu.test;
+
+/**
+ * Test passed but was expected to fail.
+ */
+public class XPass extends Result
+{
+ /**
+ * Constructs an XPass result code with additional information.
+ */
+ public XPass(String msg) {
+ super("XPASS", msg);
+ }
+ /**
+ * Constructs an XPass result code.
+ */
+ public XPass() {
+ this("");
+ }
+}
diff --git a/libjava/classpath/gnu/xml/aelfred2/ContentHandler2.java b/libjava/classpath/gnu/xml/aelfred2/ContentHandler2.java
new file mode 100644
index 0000000..1516138
--- /dev/null
+++ b/libjava/classpath/gnu/xml/aelfred2/ContentHandler2.java
@@ -0,0 +1,65 @@
+/* ContentHandler2.java --
+ Copyright (C) 2004 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 gnu.xml.aelfred2;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * Extension to the SAX ContentHandler interface to report parsing events
+ * and parameters required by DOM Level 3 but not supported by SAX.
+ *
+ * @author Chris Burdess
+ */
+public interface ContentHandler2
+ extends ContentHandler
+{
+
+ /**
+ * Reports the XML declaration.
+ * @param version the value of the version attribute in the XML
+ * declaration
+ * @param encoding the encoding specified in the XML declaration, if any
+ * @param standalone the standalone attribute from the XML declaration
+ * @param inputEncoding the encoding of the XML input
+ */
+ void xmlDecl(String version, String encoding, boolean standalone,
+ String inputEncoding)
+ throws SAXException;
+
+}
diff --git a/libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java b/libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java
new file mode 100644
index 0000000..37e8cc9
--- /dev/null
+++ b/libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java
@@ -0,0 +1,231 @@
+/* JAXPFactory.java --
+ Copyright (C) 2001 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 gnu.xml.aelfred2;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.xml.sax.Parser;
+import org.xml.sax.XMLReader;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.helpers.XMLReaderAdapter;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+
+/**
+ * Configurable factory to create an Ælfred2 JAXP parser; required
+ * to bootstrap using JAXP. You should use SAX2 directly where possible,
+ * rather than through JAXP, since that gives you better control.
+ * This class would normally be configured as a platform default factory.
+ *
+ * @author David Brownell
+ */
+public final class JAXPFactory
+ extends SAXParserFactory
+{
+
+ private Hashtable flags = new Hashtable();
+
+ /**
+ * Constructs a factory which normally returns a non-validating
+ * parser.
+ */
+ public JAXPFactory()
+ {
+ }
+
+ public SAXParser newSAXParser()
+ throws ParserConfigurationException, SAXException
+ {
+ JaxpParser jaxp = new JaxpParser();
+ Enumeration e = flags.keys();
+ XMLReader parser = jaxp.getXMLReader();
+
+ parser.setFeature(SAXDriver.FEATURE + "namespaces",
+ isNamespaceAware());
+ parser.setFeature(SAXDriver.FEATURE + "validation",
+ isValidating());
+ // that makes SAX2 feature flags trump JAXP
+
+ while (e.hasMoreElements())
+ {
+ String uri = (String) e.nextElement();
+ Boolean value = (Boolean) flags.get(uri);
+ parser.setFeature(uri, value.booleanValue());
+ }
+
+ return jaxp;
+ }
+
+ // yes, this "feature transfer" mechanism doesn't play well
+
+ public void setFeature(String name, boolean value)
+ throws ParserConfigurationException, SAXNotRecognizedException,
+ SAXNotSupportedException
+ {
+ try
+ {
+ // force "early" detection of errors where possible
+ // (flags can't necessarily be set before parsing)
+ new JaxpParser().getXMLReader().setFeature(name, value);
+
+ flags.put(name, new Boolean(value));
+ }
+ catch (SAXNotRecognizedException e)
+ {
+ throw new SAXNotRecognizedException(name);
+ }
+ catch (SAXNotSupportedException e)
+ {
+ throw new SAXNotSupportedException(name);
+ }
+ catch (Exception e)
+ {
+ throw new ParserConfigurationException(e.getClass().getName()
+ + ": "
+ + e.getMessage());
+ }
+ }
+
+ public boolean getFeature(String name)
+ throws ParserConfigurationException, SAXNotRecognizedException,
+ SAXNotSupportedException
+ {
+ Boolean value = (Boolean) flags.get(name);
+
+ if (value != null)
+ {
+ return value.booleanValue();
+ }
+ else
+ {
+ try
+ {
+ return new JaxpParser().getXMLReader().getFeature(name);
+ }
+ catch (SAXNotRecognizedException e)
+ {
+ throw new SAXNotRecognizedException(name);
+ }
+ catch (SAXNotSupportedException e)
+ {
+ throw new SAXNotSupportedException(name);
+ }
+ catch (SAXException e)
+ {
+ throw new ParserConfigurationException(e.getClass().getName()
+ + ": "
+ + e.getMessage());
+ }
+ }
+ }
+
+ private static class JaxpParser
+ extends SAXParser
+ {
+
+ private XmlReader ae2 = new XmlReader();
+ private XMLReaderAdapter parser = null;
+
+ JaxpParser()
+ {
+ }
+
+ public void setProperty(String id, Object value)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ ae2.setProperty(id, value);
+ }
+
+ public Object getProperty(String id)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ return ae2.getProperty(id);
+ }
+
+ public Parser getParser()
+ throws SAXException
+ {
+ if (parser == null)
+ {
+ parser = new XMLReaderAdapter(ae2);
+ }
+ return parser;
+ }
+
+ public XMLReader getXMLReader ()
+ throws SAXException
+ {
+ return ae2;
+ }
+
+ public boolean isNamespaceAware()
+ {
+ try
+ {
+ return ae2.getFeature(SAXDriver.FEATURE + "namespaces");
+ }
+ catch (Exception e)
+ {
+ throw new Error();
+ }
+ }
+
+ public boolean isValidating()
+ {
+ try
+ {
+ return ae2.getFeature(SAXDriver.FEATURE + "validation");
+ }
+ catch (Exception e)
+ {
+ throw new Error();
+ }
+ }
+
+ // TODO isXIncludeAware()
+
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java b/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java
new file mode 100644
index 0000000..7e950ce
--- /dev/null
+++ b/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java
@@ -0,0 +1,1622 @@
+/* SAXDriver.java --
+ Copyright (C) 1999,2000,2001,2004 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.
+
+Portions derived from code which carried the following notice:
+
+ Copyright (c) 1997, 1998 by Microstar Software Ltd.
+
+ AElfred is free for both commercial and non-commercial use and
+ redistribution, provided that Microstar's copyright and disclaimer are
+ retained intact. You are free to modify AElfred for your own use and
+ to redistribute AElfred with your modifications, provided that the
+ modifications are clearly documented.
+
+ This program 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. Please use it AT
+ YOUR OWN RISK.
+*/
+
+package gnu.xml.aelfred2;
+
+import java.io.*;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Locale;
+import java.util.Stack;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+
+import org.xml.sax.*;
+import org.xml.sax.ext.*;
+import org.xml.sax.helpers.NamespaceSupport;
+
+
+/**
+ * An enhanced SAX2 version of Microstar's Ælfred XML parser.
+ * The enhancements primarily relate to significant improvements in
+ * conformance to the XML specification, and SAX2 support. Performance
+ * has been improved. See the package level documentation for more
+ * information.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * Name
+ * Notes
+ *
+ *
+ * (URL)/external-general-entities
+ * Value defaults to true
+ * (URL)/external-parameter-entities
+ * Value defaults to true
+ * (URL)/is-standalone
+ * (PRELIMINARY) Returns true iff the document's parsing
+ * has started (some non-error event after startDocument()
+ * was reported) and the document's standalone flag is set.
+ * (URL)/namespace-prefixes
+ * Value defaults to false (but XML 1.0 names are
+ * always reported)
+ * (URL)/lexical-handler/parameter-entities
+ * Value is fixed at true
+ * (URL)/namespaces
+ * Value defaults to true
+ * (URL)/resolve-dtd-uris
+ * (PRELIMINARY) Value defaults to true
+ * (URL)/string-interning
+ * Value is fixed at true
+ * (URL)/use-attributes2
+ * (PRELIMINARY) Value is fixed at true
+ * (URL)/use-entity-resolver2
+ * (PRELIMINARY) Value defaults to true
+ *
+ * (URL)/validation
+ * Value is fixed at false
+ *
+ *
+ * (URL)/declaration-handler
+ * A declaration handler may be provided.
+ * (URL)/lexical-handler
+ * A lexical handler may be provided. SAXDriver
class as your entry point, as all
+ * internal parser interfaces are subject to change.
+ *
+ * @author Written by David Megginson <dmeggins@microstar.com>
+ * (version 1.2a with bugfixes)
+ * @author Updated by David Brownell <dbrownell@users.sourceforge.net>
+ * @see SAXDriver
+ */
+final class XmlParser
+{
+
+ // avoid slow per-character readCh()
+ private final static boolean USE_CHEATS = true;
+
+ ////////////////////////////////////////////////////////////////////////
+ // Constants.
+ ////////////////////////////////////////////////////////////////////////
+
+ //
+ // Constants for element content type.
+ //
+
+ /**
+ * Constant: an element has not been declared.
+ * @see #getElementContentType
+ */
+ public final static int CONTENT_UNDECLARED = 0;
+
+ /**
+ * Constant: the element has a content model of ANY.
+ * @see #getElementContentType
+ */
+ public final static int CONTENT_ANY = 1;
+
+ /**
+ * Constant: the element has declared content of EMPTY.
+ * @see #getElementContentType
+ */
+ public final static int CONTENT_EMPTY = 2;
+
+ /**
+ * Constant: the element has mixed content.
+ * @see #getElementContentType
+ */
+ public final static int CONTENT_MIXED = 3;
+
+ /**
+ * Constant: the element has element content.
+ * @see #getElementContentType
+ */
+ public final static int CONTENT_ELEMENTS = 4;
+
+
+ //
+ // Constants for the entity type.
+ //
+
+ /**
+ * Constant: the entity has not been declared.
+ * @see #getEntityType
+ */
+ public final static int ENTITY_UNDECLARED = 0;
+
+ /**
+ * Constant: the entity is internal.
+ * @see #getEntityType
+ */
+ public final static int ENTITY_INTERNAL = 1;
+
+ /**
+ * Constant: the entity is external, non-parsable data.
+ * @see #getEntityType
+ */
+ public final static int ENTITY_NDATA = 2;
+
+ /**
+ * Constant: the entity is external XML data.
+ * @see #getEntityType
+ */
+ public final static int ENTITY_TEXT = 3;
+
+ //
+ // Attribute type constants are interned literal strings.
+ //
+
+ //
+ // Constants for supported encodings. "external" is just a flag.
+ //
+ private final static int ENCODING_EXTERNAL = 0;
+ private final static int ENCODING_UTF_8 = 1;
+ private final static int ENCODING_ISO_8859_1 = 2;
+ private final static int ENCODING_UCS_2_12 = 3;
+ private final static int ENCODING_UCS_2_21 = 4;
+ private final static int ENCODING_UCS_4_1234 = 5;
+ private final static int ENCODING_UCS_4_4321 = 6;
+ private final static int ENCODING_UCS_4_2143 = 7;
+ private final static int ENCODING_UCS_4_3412 = 8;
+ private final static int ENCODING_ASCII = 9;
+
+ //
+ // Constants for attribute default value.
+ //
+
+ /**
+ * Constant: the attribute is not declared.
+ * @see #getAttributeDefaultValueType
+ */
+ public final static int ATTRIBUTE_DEFAULT_UNDECLARED = 30;
+
+ /**
+ * Constant: the attribute has a literal default value specified.
+ * @see #getAttributeDefaultValueType
+ * @see #getAttributeDefaultValue
+ */
+ public final static int ATTRIBUTE_DEFAULT_SPECIFIED = 31;
+
+ /**
+ * Constant: the attribute was declared #IMPLIED.
+ * @see #getAttributeDefaultValueType
+ */
+ public final static int ATTRIBUTE_DEFAULT_IMPLIED = 32;
+
+ /**
+ * Constant: the attribute was declared #REQUIRED.
+ * @see #getAttributeDefaultValueType
+ */
+ public final static int ATTRIBUTE_DEFAULT_REQUIRED = 33;
+
+ /**
+ * Constant: the attribute was declared #FIXED.
+ * @see #getAttributeDefaultValueType
+ * @see #getAttributeDefaultValue
+ */
+ public final static int ATTRIBUTE_DEFAULT_FIXED = 34;
+
+ //
+ // Constants for input.
+ //
+ private final static int INPUT_NONE = 0;
+ private final static int INPUT_INTERNAL = 1;
+ private final static int INPUT_STREAM = 3;
+ private final static int INPUT_READER = 5;
+
+ //
+ // Flags for reading literals.
+ //
+ // expand general entity refs (attribute values in dtd and content)
+ private final static int LIT_ENTITY_REF = 2;
+ // normalize this value (space chars) (attributes, public ids)
+ private final static int LIT_NORMALIZE = 4;
+ // literal is an attribute value
+ private final static int LIT_ATTRIBUTE = 8;
+ // don't expand parameter entities
+ private final static int LIT_DISABLE_PE = 16;
+ // don't expand [or parse] character refs
+ private final static int LIT_DISABLE_CREF = 32;
+ // don't parse general entity refs
+ private final static int LIT_DISABLE_EREF = 64;
+ // literal is a public ID value
+ private final static int LIT_PUBID = 256;
+
+ //
+ // Flags affecting PE handling in DTDs (if expandPE is true).
+ // PEs expand with space padding, except inside literals.
+ //
+ private final static int CONTEXT_NORMAL = 0;
+ private final static int CONTEXT_LITERAL = 1;
+
+ // Emit warnings for relative URIs with no base URI.
+ static boolean uriWarnings;
+ static
+ {
+ String key = "gnu.xml.aelfred2.XmlParser.uriWarnings";
+ GetPropertyAction a = new GetPropertyAction(key);
+ uriWarnings = "true".equals(AccessController.doPrivileged(a));
+ }
+
+ //
+ // The current XML handler interface.
+ //
+ private SAXDriver handler;
+
+ //
+ // I/O information.
+ //
+ private Reader reader; // current reader
+ private InputStream is; // current input stream
+ private int line; // current line number
+ private int column; // current column number
+ private int sourceType; // type of input source
+ private LinkedList inputStack; // stack of input soruces
+ private URLConnection externalEntity; // current external entity
+ private int encoding; // current character encoding
+ private int currentByteCount; // bytes read from current source
+ private InputSource scratch; // temporary
+
+ //
+ // Buffers for decoded but unparsed character input.
+ //
+ private char[] readBuffer;
+ private int readBufferPos;
+ private int readBufferLength;
+ private int readBufferOverflow; // overflow from last data chunk.
+
+ //
+ // Buffer for undecoded raw byte input.
+ //
+ private final static int READ_BUFFER_MAX = 16384;
+ private byte[] rawReadBuffer;
+
+
+ //
+ // Buffer for attribute values, char refs, DTD stuff.
+ //
+ private static int DATA_BUFFER_INITIAL = 4096;
+ private char[] dataBuffer;
+ private int dataBufferPos;
+
+ //
+ // Buffer for parsed names.
+ //
+ private static int NAME_BUFFER_INITIAL = 1024;
+ private char[] nameBuffer;
+ private int nameBufferPos;
+
+ //
+ // Save any standalone flag
+ //
+ private boolean docIsStandalone;
+
+ //
+ // Hashtables for DTD information on elements, entities, and notations.
+ // Populated until we start ignoring decls (because of skipping a PE)
+ //
+ private HashMap elementInfo;
+ private HashMap entityInfo;
+ private HashMap notationInfo;
+ private boolean skippedPE;
+
+ //
+ // Element type currently in force.
+ //
+ private String currentElement;
+ private int currentElementContent;
+
+ //
+ // Stack of entity names, to detect recursion.
+ //
+ private LinkedList entityStack;
+
+ //
+ // PE expansion is enabled in most chunks of the DTD, not all.
+ // When it's enabled, literals are treated differently.
+ //
+ private boolean inLiteral;
+ private boolean expandPE;
+ private boolean peIsError;
+
+ //
+ // can't report entity expansion inside two constructs:
+ // - attribute expansions (internal entities only)
+ // - markup declarations (parameter entities only)
+ //
+ private boolean doReport;
+
+ //
+ // Symbol table, for caching interned names.
+ //
+ // These show up wherever XML names or nmtokens are used: naming elements,
+ // attributes, PIs, notations, entities, and enumerated attribute values.
+ //
+ // NOTE: This hashtable doesn't grow. The default size is intended to be
+ // rather large for most documents. Example: one snapshot of the DocBook
+ // XML 4.1 DTD used only about 350 such names. As a rule, only pathological
+ // documents (ones that don't reuse names) should ever see much collision.
+ //
+ // Be sure that SYMBOL_TABLE_LENGTH always stays prime, for best hashing.
+ // "2039" keeps the hash table size at about two memory pages on typical
+ // 32 bit hardware.
+ //
+ private final static int SYMBOL_TABLE_LENGTH = 2039;
+
+ private Object[][] symbolTable;
+
+ //
+ // Hash table of attributes found in current start tag.
+ //
+ private String[] tagAttributes;
+ private int tagAttributePos;
+
+ //
+ // Utility flag: have we noticed a CR while reading the last
+ // data chunk? If so, we will have to go back and normalise
+ // CR or CR/LF line ends.
+ //
+ private boolean sawCR;
+
+ //
+ // Utility flag: are we in CDATA? If so, whitespace isn't ignorable.
+ //
+ private boolean inCDATA;
+
+ //
+ // Xml version.
+ //
+ private static final int XML_10 = 0;
+ private static final int XML_11 = 1;
+ private int xmlVersion = XML_10;
+
+ //////////////////////////////////////////////////////////////////////
+ // Constructors.
+ ////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Construct a new parser with no associated handler.
+ * @see #setHandler
+ * @see #parse
+ */
+ // package private
+ XmlParser()
+ {
+ }
+
+ /**
+ * Set the handler that will receive parsing events.
+ * @param handler The handler to receive callback events.
+ * @see #parse
+ */
+ // package private
+ void setHandler(SAXDriver handler)
+ {
+ this.handler = handler;
+ }
+
+ /**
+ * Parse an XML document from the character stream, byte stream, or URI
+ * that you provide (in that order of preference). Any URI that you
+ * supply will become the base URI for resolving relative URI, and may
+ * be used to acquire a reader or byte stream.
+ *
+ *
+ * [1] document ::= prolog element Misc*
+ *
+ *
+ * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* "-->"
+ *
+ * <!--
has already been read.)
+ */
+ private void parseComment()
+ throws Exception
+ {
+ char c;
+ boolean saved = expandPE;
+
+ expandPE = false;
+ parseUntil(endDelimComment);
+ require('>');
+ expandPE = saved;
+ handler.comment(dataBuffer, 0, dataBufferPos);
+ dataBufferPos = 0;
+ }
+
+ static final char[] startDelimPI = { '<', '?' };
+ static final char[] endDelimPI = { '?', '>' };
+
+ /**
+ * Parse a processing instruction and do a call-back.
+ *
+ * [16] PI ::= '<?' PITarget
+ * (S (Char* - (Char* '?>' Char*)))?
+ * '?>'
+ * [17] PITarget ::= Name - ( ('X'|'x') ('M'|m') ('L'|l') )
+ *
+ * <?
has already been read.)
+ */
+ private void parsePI()
+ throws SAXException, IOException
+ {
+ String name;
+ boolean saved = expandPE;
+
+ expandPE = false;
+ name = readNmtoken(true);
+ //NE08
+ if (name.indexOf(':') >= 0)
+ {
+ error("Illegal character(':') in processing instruction name ",
+ name, null);
+ }
+ if ("xml".equalsIgnoreCase(name))
+ {
+ error("Illegal processing instruction target", name, null);
+ }
+ if (!tryRead(endDelimPI))
+ {
+ requireWhitespace();
+ parseUntil(endDelimPI);
+ }
+ expandPE = saved;
+ handler.processingInstruction(name, dataBufferToString());
+ }
+
+ static final char[] endDelimCDATA = { ']', ']', '>' };
+
+ private boolean isDirtyCurrentElement;
+
+ /**
+ * Parse a CDATA section.
+ *
+ * [18] CDSect ::= CDStart CData CDEnd
+ * [19] CDStart ::= '<![CDATA['
+ * [20] CData ::= (Char* - (Char* ']]>' Char*))
+ * [21] CDEnd ::= ']]>'
+ *
+ *
+ * [22] prolog ::= XMLDecl? Misc* (Doctypedecl Misc*)?
+ *
+ * <?xml
and whitespace have already been read.)
+ * @return the encoding in the declaration, uppercased; or null
+ * @see #parseTextDecl
+ * @see #setupDecoding
+ */
+ private String parseXMLDecl(boolean ignoreEncoding)
+ throws SAXException, IOException
+ {
+ String version;
+ String encodingName = null;
+ String standalone = null;
+ int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
+ String inputEncoding = null;
+
+ switch (this.encoding)
+ {
+ case ENCODING_EXTERNAL:
+ case ENCODING_UTF_8:
+ inputEncoding = "UTF-8";
+ break;
+ case ENCODING_ISO_8859_1:
+ inputEncoding = "ISO-8859-1";
+ break;
+ case ENCODING_UCS_2_12:
+ inputEncoding = "UTF-16BE";
+ break;
+ case ENCODING_UCS_2_21:
+ inputEncoding = "UTF-16LE";
+ break;
+ }
+
+ // Read the version.
+ require("version");
+ parseEq();
+ checkLegalVersion(version = readLiteral(flags));
+ if (!version.equals("1.0"))
+ {
+ if (version.equals("1.1"))
+ {
+ handler.warn("expected XML version 1.0, not: " + version);
+ xmlVersion = XML_11;
+ }
+ else
+ {
+ error("illegal XML version", version, "1.0 or 1.1");
+ }
+ }
+ else
+ {
+ xmlVersion = XML_10;
+ }
+ // Try reading an encoding declaration.
+ boolean white = tryWhitespace();
+
+ if (tryRead("encoding"))
+ {
+ if (!white)
+ {
+ error("whitespace required before 'encoding='");
+ }
+ parseEq();
+ encodingName = readLiteral(flags);
+ if (!ignoreEncoding)
+ {
+ setupDecoding(encodingName);
+ }
+ }
+
+ // Try reading a standalone declaration
+ if (encodingName != null)
+ {
+ white = tryWhitespace();
+ }
+ if (tryRead("standalone"))
+ {
+ if (!white)
+ {
+ error("whitespace required before 'standalone='");
+ }
+ parseEq();
+ standalone = readLiteral(flags);
+ if ("yes".equals(standalone))
+ {
+ docIsStandalone = true;
+ }
+ else if (!"no".equals(standalone))
+ {
+ error("standalone flag must be 'yes' or 'no'");
+ }
+ }
+
+ skipWhitespace();
+ require("?>");
+
+ if (inputEncoding == null)
+ {
+ inputEncoding = encodingName;
+ }
+ handler.xmlDecl(version, encodingName, docIsStandalone,
+ inputEncoding);
+
+ return encodingName;
+ }
+
+ /**
+ * Parse a text declaration.
+ *
+ * [79] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
+ * [80] EncodingDecl ::= S 'encoding' Eq
+ * ( '"' EncName '"' | "'" EncName "'" )
+ * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
+ *
+ * <?xml
' and whitespace have already been read.)
+ * @return the encoding in the declaration, uppercased; or null
+ * @see #parseXMLDecl
+ * @see #setupDecoding
+ */
+ private String parseTextDecl(boolean ignoreEncoding)
+ throws SAXException, IOException
+ {
+ String encodingName = null;
+ int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
+
+ // Read an optional version.
+ if (tryRead ("version"))
+ {
+ String version;
+ parseEq();
+ checkLegalVersion(version = readLiteral(flags));
+
+ if (version.equals("1.1"))
+ {
+ if (xmlVersion == XML_10)
+ {
+ error("external subset has later version number.", "1.0",
+ version);
+ }
+ handler.warn("expected XML version 1.0, not: " + version);
+ xmlVersion = XML_11;
+ }
+ else if (!version.equals("1.0"))
+ {
+ error("illegal XML version", version, "1.0 or 1.1");
+ }
+ requireWhitespace();
+ }
+
+ // Read the encoding.
+ require("encoding");
+ parseEq();
+ encodingName = readLiteral(flags);
+ if (!ignoreEncoding)
+ {
+ setupDecoding(encodingName);
+ }
+ skipWhitespace();
+ require("?>");
+
+ return encodingName;
+ }
+
+ /**
+ * Sets up internal state so that we can decode an entity using the
+ * specified encoding. This is used when we start to read an entity
+ * and we have been given knowledge of its encoding before we start to
+ * read any data (e.g. from a SAX input source or from a MIME type).
+ *
+ *
+ * [27] Misc ::= Comment | PI | S
+ *
+ */
+ private void parseMisc()
+ throws Exception
+ {
+ while (true)
+ {
+ skipWhitespace();
+ if (tryRead(startDelimPI))
+ {
+ parsePI();
+ }
+ else if (tryRead(startDelimComment))
+ {
+ parseComment();
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Parse a document type declaration.
+ *
+ * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
+ * ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
+ *
+ * <!DOCTYPE
has already been read.)
+ */
+ private void parseDoctypedecl()
+ throws Exception
+ {
+ String rootName;
+ ExternalIdentifiers ids;
+
+ // Read the document type name.
+ requireWhitespace();
+ rootName = readNmtoken(true);
+
+ // Read the External subset's IDs
+ skipWhitespace();
+ ids = readExternalIds(false, true);
+
+ // report (a) declaration of name, (b) lexical info (ids)
+ handler.doctypeDecl(rootName, ids.publicId, ids.systemId);
+
+ // Internal subset is parsed first, if present
+ skipWhitespace();
+ if (tryRead('['))
+ {
+
+ // loop until the subset ends
+ while (true)
+ {
+ doReport = expandPE = true;
+ skipWhitespace();
+ doReport = expandPE = false;
+ if (tryRead(']'))
+ {
+ break; // end of subset
+ }
+ else
+ {
+ // WFC, PEs in internal subset (only between decls)
+ peIsError = expandPE = true;
+ parseMarkupdecl();
+ peIsError = expandPE = false;
+ }
+ }
+ }
+ skipWhitespace();
+ require('>');
+
+ // Read the external subset, if any
+ InputSource subset;
+
+ if (ids.systemId == null)
+ {
+ subset = handler.getExternalSubset(rootName,
+ handler.getSystemId());
+ }
+ else
+ {
+ subset = null;
+ }
+ if (ids.systemId != null || subset != null)
+ {
+ pushString(null, ">");
+
+ // NOTE: [dtd] is so we say what SAX2 expects,
+ // though it's misleading (subset, not entire dtd)
+ if (ids.systemId != null)
+ {
+ pushURL(true, "[dtd]", ids, null, null, null, true);
+ }
+ else
+ {
+ handler.warn("modifying document by adding external subset");
+ pushURL(true, "[dtd]",
+ new ExternalIdentifiers(subset.getPublicId(),
+ subset.getSystemId(),
+ null),
+ subset.getCharacterStream(),
+ subset.getByteStream(),
+ subset.getEncoding(),
+ false);
+ }
+
+ // Loop until we end up back at '>'
+ while (true)
+ {
+ doReport = expandPE = true;
+ skipWhitespace();
+ doReport = expandPE = false;
+ if (tryRead('>'))
+ {
+ break;
+ }
+ else
+ {
+ expandPE = true;
+ parseMarkupdecl();
+ expandPE = false;
+ }
+ }
+
+ // the ">" string isn't popped yet
+ if (inputStack.size() != 1)
+ {
+ error("external subset has unmatched '>'");
+ }
+ }
+
+ // done dtd
+ handler.endDoctype();
+ expandPE = false;
+ doReport = true;
+ }
+
+ /**
+ * Parse a markup declaration in the internal or external DTD subset.
+ *
+ * [29] markupdecl ::= elementdecl | Attlistdecl | EntityDecl
+ * | NotationDecl | PI | Comment
+ * [30] extSubsetDecl ::= (markupdecl | conditionalSect
+ * | PEReference | S) *
+ *
+ *
+ * [39] element ::= EmptyElementTag | STag content ETag
+ * [40] STag ::= '<' Name (S Attribute)* S? '>'
+ * [44] EmptyElementTag ::= '<' Name (S Attribute)* S? '/>'
+ *
+ *
+ * [41] Attribute ::= Name Eq AttValue
+ *
+ * @param name The name of the attribute's element.
+ * @see SAXDriver#attribute
+ */
+ private void parseAttribute(String name)
+ throws Exception
+ {
+ String aname;
+ String type;
+ String value;
+ int flags = LIT_ATTRIBUTE | LIT_ENTITY_REF;
+
+ // Read the attribute name.
+ aname = readNmtoken(true);
+ type = getAttributeType(name, aname);
+
+ // Parse '='
+ parseEq();
+
+ // Read the value, normalizing whitespace
+ // unless it is CDATA.
+ if (handler.stringInterning)
+ {
+ if (type == "CDATA" || type == null)
+ {
+ value = readLiteral(flags);
+ }
+ else
+ {
+ value = readLiteral(flags | LIT_NORMALIZE);
+ }
+ }
+ else
+ {
+ if (type == null || type.equals("CDATA"))
+ {
+ value = readLiteral(flags);
+ }
+ else
+ {
+ value = readLiteral(flags | LIT_NORMALIZE);
+ }
+ }
+
+ // WFC: no duplicate attributes
+ for (int i = 0; i < tagAttributePos; i++)
+ {
+ if (aname.equals(tagAttributes [i]))
+ {
+ error("duplicate attribute", aname, null);
+ }
+ }
+
+ // Inform the handler about the
+ // attribute.
+ handler.attribute(aname, value, true);
+ dataBufferPos = 0;
+
+ // Note that the attribute has been
+ // specified.
+ if (tagAttributePos == tagAttributes.length)
+ {
+ String newAttrib[] = new String[tagAttributes.length * 2];
+ System.arraycopy(tagAttributes, 0, newAttrib, 0, tagAttributePos);
+ tagAttributes = newAttrib;
+ }
+ tagAttributes[tagAttributePos++] = aname;
+ }
+
+ /**
+ * Parse an equals sign surrounded by optional whitespace.
+ *
+ * [25] Eq ::= S? '=' S?
+ *
+ */
+ private void parseEq()
+ throws SAXException, IOException
+ {
+ skipWhitespace();
+ require('=');
+ skipWhitespace();
+ }
+
+ /**
+ * Parse an end tag.
+ *
+ * [42] ETag ::= '' Name S? '>'
+ *
+ *
+ * [43] content ::= (element | CharData | Reference
+ * | CDSect | PI | Comment)*
+ * [67] Reference ::= EntityRef | CharRef
+ *
+ *
+ * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | elements
+ *
+ */
+ private void parseContentspec(String name)
+ throws Exception
+ {
+ // FIXME: move elementDecl() into setElement(), pass EMTPY/ANY ...
+ if (tryRead("EMPTY"))
+ {
+ setElement(name, CONTENT_EMPTY, null, null);
+ if (!skippedPE)
+ {
+ handler.getDeclHandler().elementDecl(name, "EMPTY");
+ }
+ return;
+ }
+ else if (tryRead("ANY"))
+ {
+ setElement(name, CONTENT_ANY, null, null);
+ if (!skippedPE)
+ {
+ handler.getDeclHandler().elementDecl(name, "ANY");
+ }
+ return;
+ }
+ else
+ {
+ String model;
+ char[] saved;
+
+ require('(');
+ saved = readBuffer;
+ dataBufferAppend('(');
+ skipWhitespace();
+ if (tryRead("#PCDATA"))
+ {
+ dataBufferAppend("#PCDATA");
+ parseMixed(saved);
+ model = dataBufferToString();
+ setElement(name, CONTENT_MIXED, model, null);
+ }
+ else
+ {
+ parseElements(saved);
+ model = dataBufferToString();
+ setElement(name, CONTENT_ELEMENTS, model, null);
+ }
+ if (!skippedPE)
+ {
+ handler.getDeclHandler().elementDecl(name, model);
+ }
+ }
+ }
+
+ /**
+ * Parse an element-content model.
+ *
+ * [47] elements ::= (choice | seq) ('?' | '*' | '+')?
+ * [49] choice ::= '(' S? cp (S? '|' S? cp)+ S? ')'
+ * [50] seq ::= '(' S? cp (S? ',' S? cp)* S? ')'
+ *
+ *
+ *
+ * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
+ *
+ */
+ private void parseCp()
+ throws Exception
+ {
+ if (tryRead('('))
+ {
+ dataBufferAppend('(');
+ parseElements(readBuffer);
+ }
+ else
+ {
+ dataBufferAppend(readNmtoken(true));
+ char c = readCh();
+ switch (c)
+ {
+ case '?':
+ case '*':
+ case '+':
+ dataBufferAppend(c);
+ break;
+ default:
+ unread(c);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Parse mixed content.
+ *
+ * [51] Mixed ::= '(' S? ( '#PCDATA' (S? '|' S? Name)*) S? ')*'
+ * | '(' S? ('#PCDATA') S? ')'
+ *
+ *
+ * @param saved Buffer for entity that should have the terminal ')'
+ */
+ private void parseMixed(char[] saved)
+ throws Exception
+ {
+ // Check for PCDATA alone.
+ skipWhitespace();
+ if (tryRead(')'))
+ {
+ // VC: Proper Group/PE Nesting
+ if (readBuffer != saved)
+ {
+ handler.verror("Illegal Group/PE nesting");
+ }
+
+ dataBufferAppend(")*");
+ tryRead('*');
+ return;
+ }
+
+ // Parse mixed content.
+ skipWhitespace();
+ while (!tryRead(")"))
+ {
+ require('|');
+ dataBufferAppend('|');
+ skipWhitespace();
+ dataBufferAppend(readNmtoken(true));
+ skipWhitespace();
+ }
+
+ // VC: Proper Group/PE Nesting
+ if (readBuffer != saved)
+ {
+ handler.verror("Illegal Group/PE nesting");
+ }
+
+ require('*');
+ dataBufferAppend(")*");
+ }
+
+ /**
+ * Parse an attribute list declaration.
+ *
+ * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
+ *
+ *
+ * [53] AttDef ::= S Name S AttType S DefaultDecl
+ *
+ */
+ private void parseAttDef(String elementName)
+ throws Exception
+ {
+ String name;
+ String type;
+ String enumer = null;
+
+ // Read the attribute name.
+ name = readNmtoken(true);
+
+ // Read the attribute type.
+ requireWhitespace();
+ type = readAttType();
+
+ // Get the string of enumerated values if necessary.
+ if (handler.stringInterning)
+ {
+ if ("ENUMERATION" == type || "NOTATION" == type)
+ {
+ enumer = dataBufferToString();
+ }
+ }
+ else
+ {
+ if ("ENUMERATION".equals(type) || "NOTATION".equals(type))
+ {
+ enumer = dataBufferToString();
+ }
+ }
+
+ // Read the default value.
+ requireWhitespace();
+ parseDefault(elementName, name, type, enumer);
+ }
+
+ /**
+ * Parse the attribute type.
+ *
+ * [54] AttType ::= StringType | TokenizedType | EnumeratedType
+ * [55] StringType ::= 'CDATA'
+ * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY'
+ * | 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
+ * [57] EnumeratedType ::= NotationType | Enumeration
+ *
+ */
+ private String readAttType()
+ throws Exception
+ {
+ if (tryRead('('))
+ {
+ parseEnumeration(false);
+ return "ENUMERATION";
+ }
+ else
+ {
+ String typeString = readNmtoken(true);
+ if (handler.stringInterning)
+ {
+ if ("NOTATION" == typeString)
+ {
+ parseNotationType();
+ return typeString;
+ }
+ else if ("CDATA" == typeString
+ || "ID" == typeString
+ || "IDREF" == typeString
+ || "IDREFS" == typeString
+ || "ENTITY" == typeString
+ || "ENTITIES" == typeString
+ || "NMTOKEN" == typeString
+ || "NMTOKENS" == typeString)
+ {
+ return typeString;
+ }
+ }
+ else
+ {
+ if ("NOTATION".equals(typeString))
+ {
+ parseNotationType();
+ return typeString;
+ }
+ else if ("CDATA".equals(typeString)
+ || "ID".equals(typeString)
+ || "IDREF".equals(typeString)
+ || "IDREFS".equals(typeString)
+ || "ENTITY".equals(typeString)
+ || "ENTITIES".equals(typeString)
+ || "NMTOKEN".equals(typeString)
+ || "NMTOKENS".equals(typeString))
+ {
+ return typeString;
+ }
+ }
+ error("illegal attribute type", typeString, null);
+ return null;
+ }
+ }
+
+ /**
+ * Parse an enumeration.
+ *
+ * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
+ *
+ *
+ * [58] NotationType ::= 'NOTATION' S '(' S? NameNtoks
+ * (S? '|' S? name)* S? ')'
+ *
+ *
+ * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED'
+ * | (('#FIXED' S)? AttValue)
+ *
+ */
+ private void parseDefault(String elementName, String name,
+ String type, String enumer)
+ throws Exception
+ {
+ int valueType = ATTRIBUTE_DEFAULT_SPECIFIED;
+ String value = null;
+ int flags = LIT_ATTRIBUTE;
+ boolean saved = expandPE;
+ String defaultType = null;
+
+ // LIT_ATTRIBUTE forces '<' checks now (ASAP) and turns whitespace
+ // chars to spaces (doesn't matter when that's done if it doesn't
+ // interfere with char refs expanding to whitespace).
+
+ if (!skippedPE)
+ {
+ flags |= LIT_ENTITY_REF;
+ if (handler.stringInterning)
+ {
+ if ("CDATA" != type)
+ {
+ flags |= LIT_NORMALIZE;
+ }
+ }
+ else
+ {
+ if (!"CDATA".equals(type))
+ {
+ flags |= LIT_NORMALIZE;
+ }
+ }
+ }
+
+ expandPE = false;
+ if (tryRead('#'))
+ {
+ if (tryRead("FIXED"))
+ {
+ defaultType = "#FIXED";
+ valueType = ATTRIBUTE_DEFAULT_FIXED;
+ requireWhitespace();
+ value = readLiteral(flags);
+ }
+ else if (tryRead("REQUIRED"))
+ {
+ defaultType = "#REQUIRED";
+ valueType = ATTRIBUTE_DEFAULT_REQUIRED;
+ }
+ else if (tryRead("IMPLIED"))
+ {
+ defaultType = "#IMPLIED";
+ valueType = ATTRIBUTE_DEFAULT_IMPLIED;
+ }
+ else
+ {
+ error("illegal keyword for attribute default value");
+ }
+ }
+ else
+ {
+ value = readLiteral(flags);
+ }
+ expandPE = saved;
+ setAttribute(elementName, name, type, enumer, value, valueType);
+ if (handler.stringInterning)
+ {
+ if ("ENUMERATION" == type)
+ {
+ type = enumer;
+ }
+ else if ("NOTATION" == type)
+ {
+ type = "NOTATION " + enumer;
+ }
+ }
+ else
+ {
+ if ("ENUMERATION".equals(type))
+ {
+ type = enumer;
+ }
+ else if ("NOTATION".equals(type))
+ {
+ type = "NOTATION " + enumer;
+ }
+ }
+ if (!skippedPE)
+ {
+ handler.getDeclHandler().attributeDecl(elementName, name, type,
+ defaultType, value);
+ }
+ }
+
+ /**
+ * Parse a conditional section.
+ *
+ * [61] conditionalSect ::= includeSect || ignoreSect
+ * [62] includeSect ::= '<![' S? 'INCLUDE' S? '['
+ * extSubsetDecl ']]>'
+ * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '['
+ * ignoreSectContents* ']]>'
+ * [64] ignoreSectContents ::= Ignore
+ * ('<![' ignoreSectContents* ']]>' Ignore )*
+ * [65] Ignore ::= Char* - (Char* ( '<![' | ']]>') Char* )
+ *
+ *
+ * [66] CharRef ::= '' [0-9]+ ';' | '' [0-9a-fA-F]+ ';'
+ *
+ *
+ * [66] CharRef ::= '' [0-9]+ ';' | '' [0-9a-fA-F]+ ';'
+ *
+ *
+ * [68] EntityRef ::= '&' Name ';'
+ *
+ *
+ * [69] PEReference ::= '%' Name ';'
+ *
+ *
+ * [70] EntityDecl ::= GEDecl | PEDecl
+ * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
+ * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
+ * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
+ * [74] PEDef ::= EntityValue | ExternalID
+ * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
+ * | 'PUBLIC' S PubidLiteral S SystemLiteral
+ * [76] NDataDecl ::= S 'NDATA' S Name
+ *
+ *
+ * [82] NotationDecl ::= '<!NOTATION' S Name S
+ * (ExternalID | PublicID) S? '>'
+ * [83] PublicID ::= 'PUBLIC' S PubidLiteral
+ *
+ *
+ * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
+ *
+ */
+ private void parseCharData()
+ throws Exception
+ {
+ char c;
+ int state = 0;
+ boolean pureWhite = false;
+
+ // assert (dataBufferPos == 0);
+
+ // are we expecting pure whitespace? it might be dirty...
+ if ((currentElementContent == CONTENT_ELEMENTS) && !isDirtyCurrentElement)
+ {
+ pureWhite = true;
+ }
+
+ // always report right out of readBuffer
+ // to minimize (pointless) buffer copies
+ while (true)
+ {
+ int lineAugment = 0;
+ int columnAugment = 0;
+ int i;
+
+loop:
+ for (i = readBufferPos; i < readBufferLength; i++)
+ {
+ switch (c = readBuffer[i])
+ {
+ case '\n':
+ lineAugment++;
+ columnAugment = 0;
+ // pureWhite unmodified
+ break;
+ case '\r': // should not happen!!
+ case '\t':
+ case ' ':
+ // pureWhite unmodified
+ columnAugment++;
+ break;
+ case '&':
+ case '<':
+ columnAugment++;
+ // pureWhite unmodified
+ // CLEAN end of text sequence
+ state = 1;
+ break loop;
+ case ']':
+ // that's not a whitespace char, and
+ // can not terminate pure whitespace either
+ pureWhite = false;
+ if ((i + 2) < readBufferLength)
+ {
+ if (readBuffer [i + 1] == ']'
+ && readBuffer [i + 2] == '>')
+ {
+ // ERROR end of text sequence
+ state = 2;
+ break loop;
+ }
+ }
+ else
+ {
+ // FIXME missing two end-of-buffer cases
+ }
+ columnAugment++;
+ break;
+ default:
+ if ((c < 0x0020 || c > 0xFFFD)
+ || ((c >= 0x007f) && (c <= 0x009f) && (c != 0x0085)
+ && xmlVersion == XML_11))
+ {
+ error("illegal XML character U+"
+ + Integer.toHexString(c));
+ }
+ // that's not a whitespace char
+ pureWhite = false;
+ columnAugment++;
+ }
+ }
+
+ // report text thus far
+ if (lineAugment > 0)
+ {
+ line += lineAugment;
+ column = columnAugment;
+ }
+ else
+ {
+ column += columnAugment;
+ }
+
+ // report characters/whitspace
+ int length = i - readBufferPos;
+
+ if (length != 0)
+ {
+ if (pureWhite)
+ {
+ handler.ignorableWhitespace(readBuffer,
+ readBufferPos, length);
+ }
+ else
+ {
+ handler.charData(readBuffer, readBufferPos, length);
+ }
+ readBufferPos = i;
+ }
+
+ if (state != 0)
+ {
+ break;
+ }
+
+ // fill next buffer from this entity, or
+ // pop stack and continue with previous entity
+ unread(readCh());
+ }
+ if (!pureWhite)
+ {
+ isDirtyCurrentElement = true;
+ }
+ // finish, maybe with error
+ if (state != 1) // finish, no error
+ {
+ error("character data may not contain ']]>'");
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // High-level reading and scanning methods.
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Require whitespace characters.
+ */
+ private void requireWhitespace()
+ throws SAXException, IOException
+ {
+ char c = readCh();
+ if (isWhitespace(c))
+ {
+ skipWhitespace();
+ }
+ else
+ {
+ error("whitespace required", c, null);
+ }
+ }
+
+ /**
+ * Skip whitespace characters.
+ *
+ * [3] S ::= (#x20 | #x9 | #xd | #xa)+
+ *
+ */
+ private void skipWhitespace()
+ throws SAXException, IOException
+ {
+ // Start with a little cheat. Most of
+ // the time, the white space will fall
+ // within the current read buffer; if
+ // not, then fall through.
+ if (USE_CHEATS)
+ {
+ int lineAugment = 0;
+ int columnAugment = 0;
+
+loop:
+ for (int i = readBufferPos; i < readBufferLength; i++)
+ {
+ switch (readBuffer[i])
+ {
+ case ' ':
+ case '\t':
+ case '\r':
+ columnAugment++;
+ break;
+ case '\n':
+ lineAugment++;
+ columnAugment = 0;
+ break;
+ case '%':
+ if (expandPE)
+ {
+ break loop;
+ }
+ // else fall through...
+ default:
+ readBufferPos = i;
+ if (lineAugment > 0)
+ {
+ line += lineAugment;
+ column = columnAugment;
+ }
+ else
+ {
+ column += columnAugment;
+ }
+ return;
+ }
+ }
+ }
+
+ // OK, do it the slow way.
+ char c = readCh ();
+ while (isWhitespace(c))
+ {
+ c = readCh();
+ }
+ unread(c);
+ }
+
+ /**
+ * Read a name or (when parsing an enumeration) name token.
+ *
+ * [5] Name ::= (Letter | '_' | ':') (NameChar)*
+ * [7] Nmtoken ::= (NameChar)+
+ *
+ */
+ private String readNmtoken(boolean isName)
+ throws SAXException, IOException
+ {
+ char c;
+
+ if (USE_CHEATS)
+ {
+loop:
+ for (int i = readBufferPos; i < readBufferLength; i++)
+ {
+ c = readBuffer[i];
+ switch (c)
+ {
+ case '%':
+ if (expandPE)
+ {
+ break loop;
+ }
+ // else fall through...
+
+ // What may legitimately come AFTER a name/nmtoken?
+ case '<': case '>': case '&':
+ case ',': case '|': case '*': case '+': case '?':
+ case ')':
+ case '=':
+ case '\'': case '"':
+ case '[':
+ case ' ': case '\t': case '\r': case '\n':
+ case ';':
+ case '/':
+ int start = readBufferPos;
+ if (i == start)
+ {
+ error("name expected", readBuffer[i], null);
+ }
+ readBufferPos = i;
+ return intern(readBuffer, start, i - start);
+
+ default:
+ // FIXME ... per IBM's OASIS test submission, these:
+ // ? U+06dd
+ // Combining U+309B
+ //these switches are kind of ugly but at least we won't
+ //have to go over the whole lits for each char
+ if (isName && i == readBufferPos)
+ {
+ char c2 = (char) (c & 0x00f0);
+ switch (c & 0xff00)
+ {
+ //starting with 01
+ case 0x0100:
+ switch (c2)
+ {
+ case 0x0030:
+ if (c == 0x0132 || c == 0x0133 || c == 0x013f)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ break;
+ case 0x0040:
+ if (c == 0x0140 || c == 0x0149)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ break;
+ case 0x00c0:
+ if (c == 0x01c4 || c == 0x01cc)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ break;
+ case 0x00f0:
+ if (c == 0x01f1 || c == 0x01f3)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ break;
+ case 0x00b0:
+ if (c == 0x01f1 || c == 0x01f3)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ break;
+ default:
+ if (c == 0x017f)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ }
+
+ break;
+ //starting with 11
+ case 0x1100:
+ switch (c2)
+ {
+ case 0x0000:
+ if (c == 0x1104 || c == 0x1108 ||
+ c == 0x110a || c == 0x110d)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ break;
+ case 0x0030:
+ if (c == 0x113b || c == 0x113f)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ break;
+ case 0x0040:
+ if (c == 0x1141 || c == 0x114d
+ || c == 0x114f )
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ break;
+ case 0x0050:
+ if (c == 0x1151 || c == 0x1156)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ break;
+ case 0x0060:
+ if (c == 0x1162 || c == 0x1164
+ || c == 0x1166 || c == 0x116b
+ || c == 0x116f)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ break;
+ case 0x00b0:
+ if (c == 0x11b6 || c == 0x11b9
+ || c == 0x11bb || c == 0x116f)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ break;
+ default:
+ if (c == 0x1174 || c == 0x119f
+ || c == 0x11ac || c == 0x11c3
+ || c == 0x11f1)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ }
+ break;
+ default:
+ if (c == 0x0e46 || c == 0x1011
+ || c == 0x212f || c == 0x0587
+ || c == 0x0230 )
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ }
+ }
+ // punt on exact tests from Appendix A; approximate
+ // them using the Unicode ID start/part rules
+ if (i == readBufferPos && isName)
+ {
+ if (!Character.isUnicodeIdentifierStart(c)
+ && c != ':' && c != '_')
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(c));
+ }
+ }
+ else if (!Character.isUnicodeIdentifierPart(c)
+ && c != '-' && c != ':' && c != '_' && c != '.'
+ && !isExtender(c))
+ {
+ error("Not a name character, U+"
+ + Integer.toHexString(c));
+ }
+ }
+ }
+ }
+
+ nameBufferPos = 0;
+
+ // Read the first character.
+loop:
+ while (true)
+ {
+ c = readCh();
+ switch (c)
+ {
+ case '%':
+ case '<': case '>': case '&':
+ case ',': case '|': case '*': case '+': case '?':
+ case ')':
+ case '=':
+ case '\'': case '"':
+ case '[':
+ case ' ': case '\t': case '\n': case '\r':
+ case ';':
+ case '/':
+ unread(c);
+ if (nameBufferPos == 0)
+ {
+ error ("name expected");
+ }
+ // punt on exact tests from Appendix A, but approximate them
+ if (isName
+ && !Character.isUnicodeIdentifierStart(nameBuffer[0])
+ && ":_".indexOf(nameBuffer[0]) == -1)
+ {
+ error("Not a name start character, U+"
+ + Integer.toHexString(nameBuffer[0]));
+ }
+ String s = intern(nameBuffer, 0, nameBufferPos);
+ nameBufferPos = 0;
+ return s;
+ default:
+ // punt on exact tests from Appendix A, but approximate them
+
+ if ((nameBufferPos != 0 || !isName)
+ && !Character.isUnicodeIdentifierPart(c)
+ && ":-_.".indexOf(c) == -1
+ && !isExtender(c))
+ {
+ error("Not a name character, U+"
+ + Integer.toHexString(c));
+ }
+ if (nameBufferPos >= nameBuffer.length)
+ {
+ nameBuffer =
+ (char[]) extendArray(nameBuffer,
+ nameBuffer.length, nameBufferPos);
+ }
+ nameBuffer[nameBufferPos++] = c;
+ }
+ }
+ }
+
+ private static boolean isExtender(char c)
+ {
+ // [88] Extender ::= ...
+ return c == 0x00b7 || c == 0x02d0 || c == 0x02d1 || c == 0x0387
+ || c == 0x0640 || c == 0x0e46 || c == 0x0ec6 || c == 0x3005
+ || (c >= 0x3031 && c <= 0x3035)
+ || (c >= 0x309d && c <= 0x309e)
+ || (c >= 0x30fc && c <= 0x30fe);
+ }
+
+ /**
+ * Read a literal. With matching single or double quotes as
+ * delimiters (and not embedded!) this is used to parse:
+ *
+ * [9] EntityValue ::= ... ([^%&] | PEReference | Reference)* ...
+ * [10] AttValue ::= ... ([^<&] | Reference)* ...
+ * [11] SystemLiteral ::= ... (URLchar - "'")* ...
+ * [12] PubidLiteral ::= ... (PubidChar - "'")* ...
+ *
+ * as well as the quoted strings in XML and text declarations
+ * (for version, encoding, and standalone) which have their
+ * own constraints.
+ */
+ private String readLiteral(int flags)
+ throws SAXException, IOException
+ {
+ char delim, c;
+ int startLine = line;
+ boolean saved = expandPE;
+ boolean savedReport = doReport;
+
+ // Find the first delimiter.
+ delim = readCh();
+ if (delim != '"' && delim != '\'')
+ {
+ error("expected '\"' or \"'\"", delim, null);
+ return null;
+ }
+ inLiteral = true;
+ if ((flags & LIT_DISABLE_PE) != 0)
+ {
+ expandPE = false;
+ }
+ doReport = false;
+
+ // Each level of input source has its own buffer; remember
+ // ours, so we won't read the ending delimiter from any
+ // other input source, regardless of entity processing.
+ char[] ourBuf = readBuffer;
+
+ // Read the literal.
+ try
+ {
+ c = readCh();
+ boolean ampRead = false;
+loop:
+ while (! (c == delim && readBuffer == ourBuf))
+ {
+ switch (c)
+ {
+ // attributes and public ids are normalized
+ // in almost the same ways
+ case '\n':
+ case '\r':
+ if ((flags & (LIT_ATTRIBUTE | LIT_PUBID)) != 0)
+ {
+ c = ' ';
+ }
+ break;
+ case '\t':
+ if ((flags & LIT_ATTRIBUTE) != 0)
+ {
+ c = ' ';
+ }
+ break;
+ case '&':
+ c = readCh();
+ // Char refs are expanded immediately, except for
+ // all the cases where it's deferred.
+ if (c == '#')
+ {
+ if ((flags & LIT_DISABLE_CREF) != 0)
+ {
+ dataBufferAppend('&');
+ break;
+ }
+ parseCharRef(false /* Do not do flushDataBuffer */);
+
+ // exotic WFness risk: this is an entity literal,
+ // dataBuffer [dataBufferPos - 1] == '&', and
+ // following chars are a _partial_ entity/char ref
+
+ // It looks like an entity ref ...
+ }
+ else
+ {
+ unread(c);
+ // Expand it?
+ if ((flags & LIT_ENTITY_REF) > 0)
+ {
+ parseEntityRef(false);
+ if (String.valueOf(readBuffer).equals("&"))
+ {
+ ampRead = true;
+ }
+ //Is it just data?
+ }
+ else if ((flags & LIT_DISABLE_EREF) != 0)
+ {
+ dataBufferAppend('&');
+
+ // OK, it will be an entity ref -- expanded later.
+ }
+ else
+ {
+ String name = readNmtoken(true);
+ require(';');
+ dataBufferAppend('&');
+ dataBufferAppend(name);
+ dataBufferAppend(';');
+ }
+ }
+ c = readCh();
+ continue loop;
+
+ case '<':
+ // and why? Perhaps so "&foo;" expands the same
+ // inside and outside an attribute?
+ if ((flags & LIT_ATTRIBUTE) != 0)
+ {
+ error("attribute values may not contain '<'");
+ }
+ break;
+
+ // We don't worry about case '%' and PE refs, readCh does.
+
+ default:
+ break;
+ }
+ dataBufferAppend(c);
+ c = readCh();
+ }
+ }
+ catch (EOFException e)
+ {
+ error("end of input while looking for delimiter (started on line "
+ + startLine + ')', null, new Character(delim).toString());
+ }
+ inLiteral = false;
+ expandPE = saved;
+ doReport = savedReport;
+
+ // Normalise whitespace if necessary.
+ if ((flags & LIT_NORMALIZE) > 0)
+ {
+ dataBufferNormalize();
+ }
+
+ // Return the value.
+ return dataBufferToString();
+ }
+
+ /**
+ * Try reading external identifiers.
+ * A system identifier is not required for notations.
+ * @param inNotation Are we parsing a notation decl?
+ * @param isSubset Parsing external subset decl (may be omitted)?
+ * @return A three-member String array containing the identifiers,
+ * or nulls. Order: public, system, baseURI.
+ */
+ private ExternalIdentifiers readExternalIds(boolean inNotation,
+ boolean isSubset)
+ throws Exception
+ {
+ char c;
+ ExternalIdentifiers ids = new ExternalIdentifiers();
+ int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
+
+ if (tryRead("PUBLIC"))
+ {
+ requireWhitespace();
+ ids.publicId = readLiteral(LIT_NORMALIZE | LIT_PUBID | flags);
+ if (inNotation)
+ {
+ skipWhitespace();
+ c = readCh();
+ unread(c);
+ if (c == '"' || c == '\'')
+ {
+ ids.systemId = readLiteral(flags);
+ }
+ }
+ else
+ {
+ requireWhitespace();
+ ids.systemId = readLiteral(flags);
+ }
+
+ for (int i = 0; i < ids.publicId.length(); i++)
+ {
+ c = ids.publicId.charAt(i);
+ if (c >= 'a' && c <= 'z')
+ {
+ continue;
+ }
+ if (c >= 'A' && c <= 'Z')
+ {
+ continue;
+ }
+ if (" \r\n0123456789-' ()+,./:=?;!*#@$_%".indexOf(c) != -1)
+ {
+ continue;
+ }
+ error("illegal PUBLIC id character U+"
+ + Integer.toHexString(c));
+ }
+ }
+ else if (tryRead("SYSTEM"))
+ {
+ requireWhitespace();
+ ids.systemId = readLiteral(flags);
+ }
+ else if (!isSubset)
+ {
+ error("missing SYSTEM or PUBLIC keyword");
+ }
+
+ if (ids.systemId != null)
+ {
+ if (ids.systemId.indexOf('#') != -1)
+ {
+ handler.verror("SYSTEM id has a URI fragment: " + ids.systemId);
+ }
+ ids.baseUri = handler.getSystemId();
+ if (ids.baseUri == null && uriWarnings)
+ {
+ handler.warn("No base URI; hope URI is absolute: "
+ + ids.systemId);
+ }
+ }
+
+ return ids;
+ }
+
+ /**
+ * Test if a character is whitespace.
+ *
+ * [3] S ::= (#x20 | #x9 | #xd | #xa)+
+ *
+ * @param c The character to test.
+ * @return true if the character is whitespace.
+ */
+ private final boolean isWhitespace(char c)
+ {
+ if (c > 0x20)
+ {
+ return false;
+ }
+ if (c == 0x20 || c == 0x0a || c == 0x09 || c == 0x0d)
+ {
+ return true;
+ }
+ return false; // illegal ...
+ }
+
+ //////////////////////////////////////////////////////////////////////
+ // Utility routines.
+ //////////////////////////////////////////////////////////////////////
+
+ /**
+ * Add a character to the data buffer.
+ */
+ private void dataBufferAppend(char c)
+ {
+ // Expand buffer if necessary.
+ if (dataBufferPos >= dataBuffer.length)
+ {
+ dataBuffer = (char[]) extendArray(dataBuffer,
+ dataBuffer.length, dataBufferPos);
+ }
+ dataBuffer[dataBufferPos++] = c;
+ }
+
+ /**
+ * Add a string to the data buffer.
+ */
+ private void dataBufferAppend(String s)
+ {
+ dataBufferAppend(s.toCharArray(), 0, s.length());
+ }
+
+ /**
+ * Append (part of) a character array to the data buffer.
+ */
+ private void dataBufferAppend(char[] ch, int start, int length)
+ {
+ dataBuffer = (char[]) extendArray(dataBuffer, dataBuffer.length,
+ dataBufferPos + length);
+
+ System.arraycopy(ch, start, dataBuffer, dataBufferPos, length);
+ dataBufferPos += length;
+ }
+
+ /**
+ * Normalise space characters in the data buffer.
+ */
+ private void dataBufferNormalize()
+ {
+ int i = 0;
+ int j = 0;
+ int end = dataBufferPos;
+
+ // Skip spaces at the start.
+ while (j < end && dataBuffer[j] == ' ')
+ {
+ j++;
+ }
+
+ // Skip whitespace at the end.
+ while (end > j && dataBuffer[end - 1] == ' ')
+ {
+ end --;
+ }
+
+ // Start copying to the left.
+ while (j < end)
+ {
+
+ char c = dataBuffer[j++];
+
+ // Normalise all other spaces to
+ // a single space.
+ if (c == ' ')
+ {
+ while (j < end && dataBuffer[j++] == ' ')
+ {
+ continue;
+ }
+ dataBuffer[i++] = ' ';
+ dataBuffer[i++] = dataBuffer[j - 1];
+ }
+ else
+ {
+ dataBuffer[i++] = c;
+ }
+ }
+
+ // The new length is <= the old one.
+ dataBufferPos = i;
+ }
+
+ /**
+ * Convert the data buffer to a string.
+ */
+ private String dataBufferToString()
+ {
+ String s = new String(dataBuffer, 0, dataBufferPos);
+ dataBufferPos = 0;
+ return s;
+ }
+
+ /**
+ * Flush the contents of the data buffer to the handler, as
+ * appropriate, and reset the buffer for new input.
+ */
+ private void dataBufferFlush()
+ throws SAXException
+ {
+ if (currentElementContent == CONTENT_ELEMENTS
+ && dataBufferPos > 0
+ && !inCDATA)
+ {
+ // We can't just trust the buffer to be whitespace, there
+ // are (error) cases when it isn't
+ for (int i = 0; i < dataBufferPos; i++)
+ {
+ if (!isWhitespace(dataBuffer[i]))
+ {
+ handler.charData(dataBuffer, 0, dataBufferPos);
+ dataBufferPos = 0;
+ }
+ }
+ if (dataBufferPos > 0)
+ {
+ handler.ignorableWhitespace(dataBuffer, 0, dataBufferPos);
+ dataBufferPos = 0;
+ }
+ }
+ else if (dataBufferPos > 0)
+ {
+ handler.charData(dataBuffer, 0, dataBufferPos);
+ dataBufferPos = 0;
+ }
+ }
+
+ /**
+ * Require a string to appear, or throw an exception.
+ * ==
instead of String.equals ()
.
+ *
+ *
+ *
+ * @param ename The name of the entity (if any) causing the new input.
+ * @see #popInput
+ * @see #sourceType
+ * @see #externalEntity
+ * @see #readBuffer
+ * @see #readBufferPos
+ * @see #readBufferLength
+ * @see #line
+ * @see #encoding
+ */
+ private void pushInput(String ename)
+ throws SAXException
+ {
+ // Check for entity recursion.
+ if (ename != null)
+ {
+ Iterator entities = entityStack.iterator();
+ while (entities.hasNext())
+ {
+ String e = (String) entities.next();
+ if (e != null && e == ename)
+ {
+ error("recursive reference to entity", ename, null);
+ }
+ }
+ }
+ entityStack.addLast(ename);
+
+ // Don't bother if there is no current input.
+ if (sourceType == INPUT_NONE)
+ {
+ return;
+ }
+
+ // Set up a snapshot of the current
+ // input source.
+ Input input = new Input();
+
+ input.sourceType = sourceType;
+ input.externalEntity = externalEntity;
+ input.readBuffer = readBuffer;
+ input.readBufferPos = readBufferPos;
+ input.readBufferLength = readBufferLength;
+ input.line = line;
+ input.encoding = encoding;
+ input.readBufferOverflow = readBufferOverflow;
+ input.is = is;
+ input.currentByteCount = currentByteCount;
+ input.column = column;
+ input.reader = reader;
+
+ // Push it onto the stack.
+ inputStack.addLast(input);
+ }
+
+ /**
+ * Restore a previous input source.
+ *
+
+
+
+
About Ælfred
+
+Design Principles
+
+
+
+
+
+About the Name Ælfred
+
+Character Encodings
+
+
+
+
+
+
+<?xml version="1.0" encoding="ISO-8859-15"?>
+
+
+java.io.InputStreamReader
+are now fully supported for both external labels (such as MIME types)
+and internal types (as shown above).
+There is one limitation in the support for internal labels:
+the encodings must be derived from the US-ASCII encoding,
+the EBCDIC family of encodings is not recognized.
+Note that Java defines its
+own encoding names, which don't always correspond to the standard
+Internet encoding names defined by the IETF/IANA, and that Java
+may even require use of nonstandard encoding names.
+Please report
+such problems; some of them can be worked around in this parser,
+and many can be worked around by using external labels.
+Known Conformance Violations
+
+
+
+
+
+Copyright and distribution terms
+
+
+ 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.
+
+ Parts derived from code which carried the following notice:
+
+ Copyright (c) 1997, 1998 by Microstar Software Ltd.
+
+ AElfred is free for both commercial and non-commercial use and
+ redistribution, provided that Microstar's copyright and disclaimer are
+ retained intact. You are free to modify AElfred for your own use and
+ to redistribute AElfred with your modifications, provided that the
+ modifications are clearly documented.
+
+ This program 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. Please use it AT
+ YOUR OWN RISK.
+
+
+
As noted above, Microstar has not updated this parser since +the summer of 1998, when it released version 1.2a on its web site. +This release is intended to benefit the developer community by +refocusing the API on SAX2, and improving conformance to the extent +that most developers should not need to use another XML parser.
+ +The code has been cleaned up (referring to the XML 1.0 spec in +all the production numbers in +comments, rather than some preliminary draft, for one example) and +has been sped up a bit as well. +JAXP support has been added, although developers are still +strongly encouraged to use the SAX2 APIs directly.
+ + +The original version of Ælfred did not support the +SAX2 APIs.
+ +This version supports the SAX2 APIs, exposing the standard +boolean feature descriptors. It supports the "DeclHandler" property +to provide access to all DTD declarations not already exposed +through the SAX1 API. The "LexicalHandler" property is supported, +exposing entity boundaries (including the unnamed external subset) and +things like comments and CDATA boundaries. SAX1 compatibility is +currently provided.
+ + +In the 'pipeline' package in this same software distribution is an +XML Validation component +using any full SAX2 event stream (including all document type declarations) +to validate. There is now a XmlReader class +which combines that class and this enhanced Ælfred parser, creating +an optionally validating SAX2 parser.
+ +As noted in the documentation for that validating component, certain +validity constraints can't reliably be tested by a layered validator. +These include all constraints relying on +layering violations (exposing XML at the level of tokens or below, +required since XML isn't a context-free grammar), some that +SAX2 doesn't support, and a few others. The resulting validating +parser is conformant enough for most applications that aren't doing +strange SGML tricks with DTDs. +Moreover, that validating filter can be used without +a parser ... any application component that emits SAX event streams +can DTD-validate its output on demand.
+ +You'll have noticed that the original version of Ælfred +had small size as a top goal. Ælfred2 normally includes a +DTD validation layer, but you can package without that. +Similarly, JAXP factory support is available but optional. +Then the main added cost due to this revision are for +supporting the SAX2 API itself; DTD validation is as +cleanly layered as allowed by SAX2.
+ +Bugs fixed in Ælfred2 include:
+ +Other bugs may also have been fixed.
+ +For better overall validation support, some of the validity +constraints that can't be verified using the SAX2 event stream +are now reported directly by Ælfred2.
+ + + diff --git a/libjava/classpath/gnu/xml/dom/Consumer.java b/libjava/classpath/gnu/xml/dom/Consumer.java new file mode 100644 index 0000000..f99e221 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/Consumer.java @@ -0,0 +1,368 @@ +/* Consumer.java -- + Copyright (C) 2001,2004 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 gnu.xml.dom; + +import org.w3c.dom.DocumentType; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.ext.Attributes2; + +import gnu.xml.pipeline.DomConsumer; +import gnu.xml.pipeline.EventConsumer; + + +/** + * Event consumer which constructs DOM documents using the implementation + * in this package, using SAX2 events. This packages various backdoors + * into this DOM implementation, as needed to address DOM requirements + * that can't be met by strictly conforming implementations of DOM. + * + *These requirements all relate to {@link DocumentType} nodes and + * features of that node type. These features are normally not used, + * because that interface only exposes a subset of the information found + * in DTDs. More, that subset does not include the most important typing + * information. For example, it excludes element content models and + * attribute typing. It does expose some entity management issues, + * although entity management doesn't relate to document typing. + * + *
Note that SAX2 does not expose the literal text of the DTD's + * internal subset, so it will not be present in DOM trees constructed + * using this API. (Though with a good SAX2 implementation, it could + * be partially recreated...) + * + * @author David Brownell + */ +public class Consumer extends DomConsumer +{ + /** + * Constructs an unconfigured event consumer, + * as a terminus in a SAX event pipeline. + */ + // used by PipelineFactory [terminus] + public Consumer () + throws SAXException + { + super (DomDocument.class); + setHandler (new Backdoor (this)); + } + + /** + * Constructs an unconfigured event consumer, + * as a stage in a SAX event pipeline. + */ + // used by PipelineFactory [filter] + public Consumer (EventConsumer next) + throws SAXException + { + super (DomDocument.class, next); + setHandler (new Backdoor (this)); + } + + /** + * Implements the backdoors needed by DOM. + * All methods in this class use implementation-specific APIs that are + * implied by the DOM specification (needed to implement testable + * behavior) but which are excluded from the DOM specification. + */ + public static class Backdoor extends DomConsumer.Handler + { + /** + * Constructor. + * @param consumer must have been initialized to use the + * {@link DomDocument} class (or a subclass) for + * constructing DOM trees + */ + protected Backdoor (DomConsumer consumer) + throws SAXException + { super (consumer); } + + // helper routine + private DomDoctype getDoctype () + throws SAXException + { + DomDocument doc = (DomDocument) getDocument (); + DocumentType dt = doc.getDoctype (); + + if (dt == null) + throw new SAXException ("doctype missing!"); + return (DomDoctype) dt; + } + + // SAX2 "lexical" event + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + DomDocument doc = (DomDocument) getDocument (); + + super.startDTD (name, publicId, systemId); + // DOM L2 doctype creation model is bizarre + DomDoctype dt = new DomDoctype (doc, name, publicId, systemId); + doc.appendChild (dt); + } + + // SAX2 "lexical" event + public void endDTD () + throws SAXException + { + super.endDTD (); + // DOM L2 has no way to make things readonly + getDoctype ().makeReadonly (); + } + + // SAX1 DTD event + public void notationDecl ( + String name, + String publicId, String systemId + ) throws SAXException + { + // DOM L2 can't create/save notation nodes + getDoctype ().declareNotation (name, publicId, systemId); + } + + // SAX1 DTD event + public void unparsedEntityDecl ( + String name, + String publicId, String systemId, + String notationName + ) throws SAXException + { + // DOM L2 can't create/save entity nodes + getDoctype ().declareEntity (name, publicId, systemId, + notationName); + } + + // SAX2 declaration event + public void internalEntityDecl (String name, String value) + throws SAXException + { + // DOM L2 can't create/save entity nodes + // NOTE: this doesn't save the value as a child of this + // node, though it could realistically do so. + getDoctype ().declareEntity (name, null, null, null); + } + + // SAX2 declaration event + public void externalEntityDecl ( + String name, + String publicId, + String systemId + ) throws SAXException + { + // DOM L2 can't create/save entity nodes + // NOTE: DOM allows for these to have children, if + // they don't have unbound namespace references. + getDoctype ().declareEntity (name, publicId, systemId, null); + } + + // SAX2 element + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + Node top; + + super.startElement (uri, localName, qName, atts); + + // might there be more work? + top = getTop (); + if (!top.hasAttributes () || !(atts instanceof Attributes2)) + return; + + // remember any attributes that got defaulted + DomNamedNodeMap map = (DomNamedNodeMap) top.getAttributes (); + Attributes2 attrs = (Attributes2) atts; + int length = atts.getLength (); + + //map.compact (); + for (int i = 0; i < length; i++) { + if (attrs.isSpecified (i)) + continue; + + // value was defaulted. + String temp = attrs.getQName (i); + DomAttr attr; + + if ("".equals (temp)) + attr = (DomAttr) map.getNamedItemNS (attrs.getURI (i), + atts.getLocalName (i)); + else + attr = (DomAttr) map.getNamedItem (temp); + + // DOM L2 can't write this flag, only read it + attr.setSpecified (false); + } + } + + public void endElement ( + String uri, + String localName, + String qName + ) throws SAXException + { + DomNode top = (DomNode) getTop (); + top.compact (); + super.endElement (uri, localName, qName); + } + + protected Text createText ( + boolean isCDATA, + char buf [], + int off, + int len + ) { + DomDocument doc = (DomDocument) getDocument (); + + if (isCDATA) + return doc.createCDATASection (buf, off, len); + else + return doc.createTextNode (buf, off, len); + } + + public void elementDecl(String name, String model) + throws SAXException + { + getDoctype().elementDecl(name, model); + } + + public void attributeDecl ( + String ename, + String aname, + String type, + String mode, + String value + ) throws SAXException + { + getDoctype().attributeDecl(ename, aname, type, mode, value); + /* + if (value == null && !"ID".equals (type)) + return; + + DomDoctype.ElementInfo info; + + info = getDoctype ().getElementInfo (ename); + if (value != null) + info.setAttrDefault (aname, value); + if ("ID".equals (type)) + info.setIdAttr (aname); + */ + + } + + // force duplicate name checking off while we're + // using parser output (don't duplicate the work) + public void startDocument () throws SAXException + { + super.startDocument (); + + DomDocument doc = (DomDocument) getDocument (); + doc.setStrictErrorChecking(false); + doc.setBuilding(true); + } + + /** + * Required by DOM Level 3 to report document parameters + */ + public void xmlDecl(String version, + String encoding, + boolean standalone, + String inputEncoding) + throws SAXException + { + super.xmlDecl(version, encoding, standalone, inputEncoding); + + DomDocument doc = (DomDocument) getDocument(); + doc.setXmlEncoding(encoding); + doc.setInputEncoding(inputEncoding); + } + + public void endDocument () + throws SAXException + { + DomDocument doc = (DomDocument) getDocument (); + doc.setStrictErrorChecking(true); + doc.setBuilding(false); + doc.compact (); + DomDoctype doctype = (DomDoctype) doc.getDoctype(); + if (doctype != null) + { + doctype.makeReadonly(); + } + super.endDocument (); + } + + // these three methods collaborate to populate entity + // refs, marking contents readonly on end-of-entity + + public boolean canPopulateEntityRefs () + { return true; } + + public void startEntity (String name) + throws SAXException + { + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + super.startEntity (name); + + DomNode top = (DomNode) getTop (); + + if (top.getNodeType () == Node.ENTITY_REFERENCE_NODE) + top.readonly = false; + } + + public void endEntity (String name) + throws SAXException + { + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + DomNode top = (DomNode) getTop (); + + if (top.getNodeType () == Node.ENTITY_REFERENCE_NODE) { + top.compact (); + top.makeReadonly (); + } + super.endEntity (name); + } + } +} diff --git a/libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java b/libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java new file mode 100644 index 0000000..e3c69c4 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java @@ -0,0 +1,84 @@ +/* DTDAttributeTypeInfo.java -- + Copyright (C) 2004 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 gnu.xml.dom; + +import org.w3c.dom.TypeInfo; + +/** + * Attribute type information supplied by a DTD attribute declaration. + * + * @author Chris Burdess + */ +class DTDAttributeTypeInfo + implements TypeInfo +{ + + final String elementName; + final String name; + final String type; + final String mode; + final String value; + + DTDAttributeTypeInfo(String elementName, String name, String type, + String mode, String value) + { + this.elementName = elementName; + this.name = name; + this.type = type; + this.mode = mode; + this.value = value; + } + + public final String getTypeName() + { + return type; + } + + public final String getTypeNamespace() + { + return "http://www.w3.org/TR/REC-xml"; + } + + public final boolean isDerivedFrom(String typeNamespace, String typeName, + int derivationMethod) + { + return false; + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java b/libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java new file mode 100644 index 0000000..c5553e2 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java @@ -0,0 +1,112 @@ +/* DTDElementTypeInfo.java -- + Copyright (C) 2004 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 gnu.xml.dom; + +import java.util.HashMap; +import java.util.Iterator; +import org.w3c.dom.TypeInfo; + +/** + * Element type information provided by a DTD element declaration. + * + * @author Chris Burdess + */ +class DTDElementTypeInfo + implements TypeInfo +{ + + final String name; + String model; + HashMap attributes; + String idAttrName; + + DTDElementTypeInfo(String name, String model) + { + this.name = name; + this.model = model; + } + + public final String getTypeName() + { + return null; + } + + public final String getTypeNamespace() + { + return "http://www.w3.org/TR/REC-xml"; + } + + public final boolean isDerivedFrom(String typeNamespace, String typeName, + int derivationMethod) + { + return false; + } + + DTDAttributeTypeInfo getAttributeTypeInfo(String name) + { + if (attributes == null) + { + return null; + } + return (DTDAttributeTypeInfo) attributes.get(name); + } + + void setAttributeTypeInfo(String name, DTDAttributeTypeInfo info) + { + if (attributes == null) + { + attributes = new HashMap(); + } + attributes.put(name, info); + if ("ID".equals(info.type)) + { + idAttrName = name; + } + } + + Iterator attributes() + { + if (attributes == null) + { + return null; + } + return attributes.values().iterator(); + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomAttr.java b/libjava/classpath/gnu/xml/dom/DomAttr.java new file mode 100644 index 0000000..8673a79 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomAttr.java @@ -0,0 +1,380 @@ +/* DomAttr.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.TypeInfo; +import org.w3c.dom.events.MutationEvent; + + +/** + *
"Attr" implementation. In DOM, attributes cost quite a lot of + * memory because their values are complex structures rather than just + * simple strings. To reduce your costs, avoid having more than one + * child of an attribute; stick to a single Text node child, and ignore + * even that by using the attribute's "nodeValue" property.
+ * + *As a bit of general advice, only look at attribute modification + * events through the DOMAttrModified event (sent to the associated + * element). Implementations are not guaranteed to report other events + * in the same order, so you're very likely to write nonportable code if + * you monitor events at the "children of Attr" level.
+ * + *At this writing, not all attribute modifications will cause the + * DOMAttrModified event to be triggered ... only the ones using the string + * methods (setNodeValue, setValue, and Element.setAttribute) to modify + * those values. That is, if you manipulate those children directly, + * elements won't get notified that attribute values have changed. + * The natural fix for that will report other modifications, but won't + * be able to expose "previous" attribute value; it'll need to be cached + * or something (at which point why bother using child nodes).
+ * + *You are strongly advised not to use "children" of any attribute + * nodes you work with.
+ * + * @author David Brownell + * @author Chris Burdess + */ +public class DomAttr + extends DomNsNode + implements Attr +{ + + private boolean specified; + private String value; // string value cache + + /** + * Constructs an Attr node associated with the specified document. + * The "specified" flag is initialized to true, since this DOM has + * no current "back door" mechanisms to manage default values so + * that every value must effectively be "specified". + * + *This constructor should only be invoked by a Document as part of
+ * its createAttribute functionality, or through a subclass which is
+ * similarly used in a "Sub-DOM" style layer.
+ *
+ * @param owner The document with which this node is associated
+ * @param namespaceURI Combined with the local part of the name,
+ * this is used to uniquely identify a type of attribute
+ * @param name Name of this attribute, which may include a prefix
+ */
+ protected DomAttr(DomDocument owner, String namespaceURI, String name)
+ {
+ super(ATTRIBUTE_NODE, owner, namespaceURI, name);
+ specified = true;
+ length = 1;
+
+ // XXX register self to get insertion/removal events
+ // and character data change events and when they happen,
+ // report self-mutation
+ }
+
+ /**
+ * DOM L1
+ * Returns the attribute name (same as getNodeName)
+ */
+ public final String getName()
+ {
+ return getNodeName();
+ }
+
+ /**
+ * DOM L1
+ * Returns true if a parser reported this was in the source text.
+ */
+ public final boolean getSpecified()
+ {
+ return specified;
+ }
+
+ /**
+ * Records whether this attribute was in the source text.
+ */
+ public final void setSpecified(boolean value)
+ {
+ specified = value;
+ }
+
+ /**
+ * DOM L1
+ * Returns the attribute value, with character and entity
+ * references substituted.
+ * NOTE: entity refs as children aren't currently handled.
+ */
+ public String getNodeValue()
+ {
+ // If we have a simple node-value, use that
+ if (first == null)
+ {
+ return (value == null) ? "" : value;
+ }
+ // Otherwise collect child node-values
+ StringBuffer buf = new StringBuffer();
+ for (DomNode ctx = first; ctx != null; ctx = ctx.next)
+ {
+ switch (ctx.nodeType)
+ {
+ case Node.TEXT_NODE:
+ buf.append(ctx.getNodeValue());
+ break;
+ case Node.ENTITY_REFERENCE_NODE:
+ // TODO
+ break;
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * DOM L1
+ * Assigns the value of the attribute; it will have one child,
+ * which is a text node with the specified value (same as
+ * setNodeValue).
+ */
+ public final void setValue(String value)
+ {
+ setNodeValue(value);
+ }
+
+ /**
+ * DOM L1
+ * Returns the value of the attribute as a non-null string; same
+ * as getNodeValue.
+ * NOTE: entity refs as children aren't currently handled.
+ */
+ public final String getValue()
+ {
+ return getNodeValue();
+ }
+
+ /**
+ * DOM L1
+ * Assigns the attribute value; using this API, no entity or
+ * character references will exist.
+ * Causes a DOMAttrModified mutation event to be sent.
+ */
+ public void setNodeValue(String value)
+ {
+ if (readonly)
+ {
+ throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR);
+ }
+ if (value == null)
+ {
+ value = "";
+ }
+ String oldValue = getNodeValue();
+ while (last != null)
+ {
+ removeChild(last);
+ }
+ // don't create a new node just for this...
+ /*
+ Node text = owner.createTextNode(value);
+ appendChild(text);
+ */
+ this.value = value;
+ length = 1;
+ specified = true;
+
+ mutating(oldValue, value, MutationEvent.MODIFICATION);
+ }
+
+ public final Node getFirstChild()
+ {
+ // Create a child text node if necessary
+ if (first == null)
+ {
+ length = 0;
+ Node text = owner.createTextNode((value == null) ? "" : value);
+ appendChild(text);
+ }
+ return first;
+ }
+
+ public final Node getLastChild()
+ {
+ // Create a child text node if necessary
+ if (last == null)
+ {
+ length = 0;
+ Node text = owner.createTextNode((value == null) ? "" : value);
+ appendChild(text);
+ }
+ return last;
+ }
+
+ public Node item(int index)
+ {
+ // Create a child text node if necessary
+ if (first == null)
+ {
+ length = 0;
+ Node text = owner.createTextNode((value == null) ? "" : value);
+ appendChild(text);
+ }
+ return super.item(index);
+ }
+
+ /**
+ * DOM L2
+ * Returns the element with which this attribute is associated.
+ */
+ public final Element getOwnerElement()
+ {
+ return (Element) parent;
+ }
+
+ public final Node getNextSibling()
+ {
+ return null;
+ }
+
+ public final Node getPreviousSibling()
+ {
+ return null;
+ }
+
+ public Node getParentNode()
+ {
+ return null;
+ }
+
+ /**
+ * Records the element with which this attribute is associated.
+ */
+ public final void setOwnerElement(Element e)
+ {
+ if (parent != null)
+ {
+ throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR);
+ }
+ if (!(e instanceof DomElement))
+ {
+ throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR);
+ }
+ parent = (DomElement) e;
+ depth = parent.depth + 1;
+ }
+
+ /**
+ * The base URI of an Attr is always null
.
+ */
+ public final String getBaseURI()
+ {
+ return null;
+ }
+
+ /**
+ * Shallow clone of the attribute, breaking all ties with any
+ * elements.
+ */
+ public Object clone()
+ {
+ DomAttr retval = (DomAttr) super.clone();
+ retval.specified = true;
+ return retval;
+ }
+
+ private void mutating(String oldValue, String newValue, short why)
+ {
+ if (!reportMutations || parent == null)
+ {
+ return;
+ }
+
+ // EVENT: DOMAttrModified, target = parent,
+ // prev/new values provided, also attr name
+ MutationEvent event;
+
+ event = (MutationEvent) createEvent ("MutationEvents");
+ event.initMutationEvent ("DOMAttrModified",
+ true /* bubbles */, false /* nocancel */,
+ null, oldValue, newValue, getNodeName (), why);
+ parent.dispatchEvent (event);
+ }
+
+ // DOM Level 3 methods
+
+ public TypeInfo getSchemaTypeInfo()
+ {
+ if (parent != null)
+ {
+ // DTD implementation
+ DomDoctype doctype = (DomDoctype) parent.owner.getDoctype();
+ if (doctype != null)
+ {
+ return doctype.getAttributeTypeInfo(parent.getNodeName(),
+ getNodeName());
+ }
+ // TODO XML Schema implementation
+ }
+ return null;
+ }
+
+ public boolean isId()
+ {
+ if (parent != null)
+ {
+ DomDoctype doctype = (DomDoctype) parent.owner.getDoctype();
+ if (doctype != null)
+ {
+ DTDAttributeTypeInfo info =
+ doctype.getAttributeTypeInfo(parent.getNodeName(),
+ getNodeName());
+ if (info != null && "ID".equals(info.type))
+ {
+ return true;
+ }
+ }
+ DomElement element = (DomElement) parent;
+ if (element.userIdAttrs != null &&
+ element.userIdAttrs.contains(this))
+ {
+ return true;
+ }
+ // TODO XML Schema implementation
+ }
+ return false;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/DomCDATASection.java b/libjava/classpath/gnu/xml/dom/DomCDATASection.java
new file mode 100644
index 0000000..e34359e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/DomCDATASection.java
@@ -0,0 +1,91 @@
+/* DomCDATASection.java --
+ Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom;
+
+import org.w3c.dom.CDATASection;
+
+/**
+ *
"CDATASection" implementation. + * This is a non-core DOM class, supporting the "XML" feature. + * CDATA sections are just ways to represent text using different + * delimeters.
+ * + *You are strongly advised not to use CDATASection nodes. + * The advantage of having slightly prettier ways to print text that may + * have lots of embedded XML delimiters, such as "&" and "<", + * can be dwarfed by the cost of dealing with multiple kinds of text + * nodes in all your algorithms.
+ * + * @author David Brownell + * @author Chris Burdess + */ +public class DomCDATASection + extends DomText + implements CDATASection +{ + + /** + * Constructs a CDATA section node associated with the specified + * document and holding the specified data. + * + *This constructor should only be invoked by a Document as part of + * its createCDATASection functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + * + */ + protected DomCDATASection(DomDocument owner, String value) + { + super(CDATA_SECTION_NODE, owner, value); + } + + protected DomCDATASection(DomDocument owner, char buf [], int off, int len) + { + super(CDATA_SECTION_NODE, owner, buf, off, len); + } + + /** + * DOM L1 + * Returns the string "#cdata-section". + */ + final public String getNodeName() + { + return "#cdata-section"; + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomCharacterData.java b/libjava/classpath/gnu/xml/dom/DomCharacterData.java new file mode 100644 index 0000000..e94dcc4 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomCharacterData.java @@ -0,0 +1,310 @@ +/* DomCharacterData.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import org.w3c.dom.CharacterData; +import org.w3c.dom.DOMException; +import org.w3c.dom.events.MutationEvent; + + +/** + *
Abstract "CharacterData" implementation. This + * facilitates reusing code in classes implementing subtypes of that DOM + * interface (Text, Comment, CDATASection).
+ * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomCharacterData + extends DomNode + implements CharacterData +{ + + private String text; + + // package private + DomCharacterData(short nodeType, DomDocument doc, String value) + { + super(nodeType, doc); + text = (value == null) ? "" : value; + } + + // package private + DomCharacterData(short nodeType, DomDocument doc, + char[] buf, int offset, int length) + { + super(nodeType, doc); + text = (buf == null) ? "" : new String(buf, offset, length); + } + + /** + * DOM L1 + * Appends the specified data to the value of this node. + * Causes a DOMCharacterDataModified mutation event to be reported. + */ + public void appendData(String arg) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + String value = text + arg; + mutating(value); + text = value; + } + + /** + * DOM L1 + * Modifies the value of this node. + * Causes a DOMCharacterDataModified mutation event to be reported. + */ + public void deleteData(int offset, int count) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + char[] raw = text.toCharArray(); + if (offset < 0 || count < 0 || offset > raw.length) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + if ((offset + count) > raw.length) + { + count = raw.length - offset; + } + if (count == 0) + { + return; + } + try + { + char[] buf = new char[raw.length - count]; + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(raw, offset + count, buf, offset, + raw.length - (offset + count)); + String value = new String(buf); + mutating(value); + text = value; + } + catch (IndexOutOfBoundsException x) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * DOM L1 + * Returns the value of this node. + */ + public String getNodeValue() + { + return text; + } + + /** + * DOM L1 + * Returns the value of this node; same as getNodeValue. + */ + public final String getData() + { + return text; + } + + /** + * DOM L1 + * Returns the length of the data. + */ + public int getLength() + { + return text.length(); + } + + /** + * DOM L1 + * Modifies the value of this node. + */ + public void insertData(int offset, String arg) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + char[] raw = text.toCharArray(); + char[] tmp = arg.toCharArray (); + char[] buf = new char[raw.length + tmp.length]; + + try + { + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(tmp, 0, buf, offset, tmp.length); + System.arraycopy(raw, offset, buf, offset + tmp.length, + raw.length - offset); + String value = new String(buf); + mutating(value); + text = value; + } + catch (IndexOutOfBoundsException x) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * DOM L1 + * Modifies the value of this node. Causes DOMCharacterDataModified + * mutation events to be reported (at least one). + */ + public void replaceData(int offset, int count, String arg) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + char[] raw = text.toCharArray(); + + // deleteData + if (offset < 0 || count < 0 || offset > raw.length) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + if ((offset + count) > raw.length) + { + count = raw.length - offset; + } + try + { + char[] buf = new char[raw.length - count]; + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(raw, offset + count, buf, offset, + raw.length - (offset + count)); + + // insertData + char[] tmp = arg.toCharArray (); + char[] buf2 = new char[buf.length + tmp.length]; + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(tmp, 0, buf, offset, tmp.length); + System.arraycopy(raw, offset, buf, offset + tmp.length, + raw.length - offset); + String value = new String(buf); + mutating(value); + text = value; + } + catch (IndexOutOfBoundsException x) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * DOM L1 + * Assigns the value of this node. + * Causes a DOMCharacterDataModified mutation event to be reported. + */ + public void setNodeValue(String value) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + if (value == null) + { + value = ""; + } + mutating(value); + text = value; + } + + /** + * DOM L1 + * Assigns the value of this node; same as setNodeValue. + */ + final public void setData(String data) + { + setNodeValue(data); + } + + /** + * DOM L1 + * Returns the specified substring. + */ + public String substringData(int offset, int count) + { + try + { + return text.substring(offset, count); + } + catch (StringIndexOutOfBoundsException e) + { + if (offset >= 0 && count >= 0 && offset < text.length()) + { + return text.substring(offset); + } + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * The base URI for character data isnull
.
+ * @since DOM Level 3 Core
+ */
+ public final String getBaseURI()
+ {
+ return null;
+ }
+
+ private void mutating(String newValue)
+ {
+ if (!reportMutations)
+ {
+ return;
+ }
+
+ // EVENT: DOMCharacterDataModified, target = this,
+ // prev/new values provided
+ MutationEvent event;
+
+ event = (MutationEvent) createEvent("MutationEvents");
+ event.initMutationEvent("DOMCharacterDataModified",
+ true /* bubbles */, false /* nocancel */,
+ null, text, newValue, null, (short) 0);
+ dispatchEvent(event);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/DomComment.java b/libjava/classpath/gnu/xml/dom/DomComment.java
new file mode 100644
index 0000000..71c8160
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/DomComment.java
@@ -0,0 +1,81 @@
+/* DomComment.java --
+ Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom;
+
+import org.w3c.dom.Comment;
+
+/**
+ * "Comment" implementation. + * Comments hold data intended for direct consumption by people; + * programs should only use ProcessingInstruction nodes. Note that + * since SAX makes comment reporting optional, XML systems that + * rely on comments (such as by using this class) will often lose + * those comments at some point in the processing pipeline.
+ * + * @author David Brownell + * @author Chris Burdess + */ +public class DomComment + extends DomCharacterData + implements Comment +{ + + /** + * Constructs a comment node associated with the specified + * document and holding the specified data. + * + *This constructor should only be invoked by a Document as part of + * its createComment functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + */ + protected DomComment(DomDocument owner, String value) + { + super(COMMENT_NODE, owner, value); + } + + /** + * DOM L1 + * Returns the string "#comment". + */ + final public String getNodeName() + { + return "#comment"; + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomDOMException.java b/libjava/classpath/gnu/xml/dom/DomDOMException.java new file mode 100644 index 0000000..cf93fcf --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDOMException.java @@ -0,0 +1,175 @@ +/* DomDOMException.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +/** + *
DOMException implementation. The version that + * is provided by the W3C is abstract, so it can't be instantiated. + * + *
This also provides a bit more information about the error + * that is being reported, in terms of the relevant DOM structures + * and data. + * + * @author David Brownell + */ +public class DomDOMException + extends DOMException +{ + + /** @serial Data that caused an error to be reported */ + private String data; + + /** @serial Node associated with the error. */ + private Node node; + + /** @serial Data associated with the error. */ + private int value; + + /** + * Constructs an exception, with the diagnostic message + * corresponding to the specified code. + */ + public DomDOMException(short code) + { + super(code, diagnostic(code)); + } + + /** + * Constructs an exception, with the diagnostic message + * corresponding to the specified code and additional + * information as provided. + */ + public DomDOMException(short code, String data, Node node, int value) + { + super(code, diagnostic(code)); + this.data = data; + this.node = node; + this.value = value; + } + + /** Returns the node to which the diagnotic applies, or null. */ + final public Node getNode() + { + return node; + } + + /** Returns data to which the diagnotic applies, or null. */ + final public String getData() + { + return data; + } + + /** Returns data to which the diagnotic applies, or null. */ + final public int getValue() + { + return value; + } + + /** + * Returns a diagnostic message that may be slightly more useful + * than the generic one, where possible. + */ + public String getMessage() + { + String retval = super.getMessage(); + + if (data != null) + { + retval += "\nMore Information: " + data; + } + if (value != 0) + { + retval += "\nNumber: " + value; + } + if (node != null) + { + retval += "\nNode Name: " + node.getNodeName(); + } + return retval; + } + + // these strings should be localizable. + + private static String diagnostic(short code) + { + switch (code) + { + // DOM L1: + case INDEX_SIZE_ERR: + return "An index or size is out of range."; + case DOMSTRING_SIZE_ERR: + return "A string is too big."; + case HIERARCHY_REQUEST_ERR: + return "The node doesn't belong here."; + case WRONG_DOCUMENT_ERR: + return "The node belongs in another document."; + case INVALID_CHARACTER_ERR: + return "That character is not permitted."; + case NO_DATA_ALLOWED_ERR: + return "This node does not permit data."; + case NO_MODIFICATION_ALLOWED_ERR: + return "No changes are allowed."; + case NOT_FOUND_ERR: + return "The node was not found in that context."; + case NOT_SUPPORTED_ERR: + return "That object is not supported."; + case INUSE_ATTRIBUTE_ERR: + return "The attribute belongs to a different element."; + + // DOM L2: + case INVALID_STATE_ERR: + return "The object is not usable."; + case SYNTAX_ERR: + return "An illegal string was provided."; + case INVALID_MODIFICATION_ERR: + return "An object's type may not be changed."; + case NAMESPACE_ERR: + return "The operation violates XML Namespaces."; + case INVALID_ACCESS_ERR: + return "Parameter or operation isn't supported by this node."; + case TYPE_MISMATCH_ERR: + return "The type of the argument is incompatible with the expected type."; + } + return "Reserved exception number: " + code; + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomDoctype.java b/libjava/classpath/gnu/xml/dom/DomDoctype.java new file mode 100644 index 0000000..d35eedc --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDoctype.java @@ -0,0 +1,455 @@ +/* DomDoctype.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import java.util.HashMap; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Entity; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Notation; + +/** + *
"DocumentType" implementation (with no extensions for supporting + * any document typing information). This is a non-core DOM class, + * supporting the "XML" feature.
+ * + *Few XML applications will actually care about this partial + * DTD support, since it doesn't expose any (!) of the data typing + * facilities which can motivate applications to use DTDs. It does not + * expose element content models, or information about attribute typing + * rules. Plus the information it exposes isn't very useful; as one example, + * DOM exposes information about unparsed ENTITY objects, which is only used + * with certain element attributes, but does not expose the information about + * those attributes which is needed to apply that data!
+ * + *Also, note that there are no nonportable ways to associate even the + * notation and entity information exposed by DOM with a DocumentType. While + * there is a DOM L2 method to construct a DocumentType, it only gives access + * to the textual content of the <!DOCTYPE ...> declaration.
+ * + *In short, you are strongly advised not to rely on this incomplete + * DTD functionality in your application code.
+ * + * @see DomEntity + * @see DomEntityReference + * @see DomNotation + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomDoctype + extends DomExtern + implements DocumentType +{ + + private DomNamedNodeMap notations; + private DomNamedNodeMap entities; + private final DOMImplementation implementation; + private String subset; + + private HashMap elements = new HashMap(); + private boolean ids; + + /** + * Constructs a DocumentType node associated with the specified + * implementation, with the specified name. + * + *This constructor should only be invoked by a DOMImplementation as + * part of its createDocumentType functionality, or through a subclass + * which is similarly used in a "Sub-DOM" style layer. + * + *
Note that at this time there is no standard SAX API granting + * access to the internal subset text, so that relying on that value + * is not currently portable. + * + * @param impl The implementation with which this object is associated + * @param name Name of this root element + * @param publicId If non-null, provides the external subset's + * PUBLIC identifier + * @param systemId If non-null, provides the external subset's + * SYSTEM identifier + * @param internalSubset Provides the literal value (unparsed, no + * entities expanded) of the DTD's internal subset. + */ + protected DomDoctype(DOMImplementation impl, + String name, + String publicId, + String systemId, + String internalSubset) + { + super(DOCUMENT_TYPE_NODE, null, name, publicId, systemId); + implementation = impl; + subset = internalSubset; + } + + /** + * JAXP builder constructor. + * @param doc the document + * @param name the name of the document element + * @param publicId the public ID of the document type declaration + * @param systemId the system ID of the document type declaration + */ + public DomDoctype(DomDocument doc, + String name, + String publicId, + String systemId) + { + super(DOCUMENT_TYPE_NODE, doc, name, publicId, systemId); + implementation = doc.getImplementation(); + } + + /** + * DOM L1 + * Returns the root element's name (just like getNodeName). + */ + final public String getName() + { + return getNodeName(); + } + + /** + * DOM L1 + * Returns information about any general entities declared + * in the DTD. + * + *
Note: DOM L1 doesn't throw a DOMException here, but + * then it doesn't have the strange construction rules of L2. + * + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public NamedNodeMap getEntities() + { + if (entities == null) + { + entities = new DomNamedNodeMap(this, Node.ENTITY_NODE); + } + return entities; + } + + /** + * Records the declaration of a general entity in this DocumentType. + * + * @param name Name of the entity + * @param publicId If non-null, provides the entity's PUBLIC identifier + * @param systemId Provides the entity's SYSTEM identifier + * @param notation If non-null, provides the entity's notation + * (indicating an unparsed entity) + * @return The Entity that was declared, or null if the entity wasn't + * recorded (because it's a parameter entity or because an entity with + * this name was already declared). + * + * @exception DOMException NO_MODIFICATION_ALLOWED_ERR if the + * DocumentType is no longer writable. + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public Entity declareEntity(String name, + String publicId, + String systemId, + String notation) + { + DomEntity entity; + + if (name.charAt(0) == '%' || "[dtd]".equals(name)) + { + return null; + } + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + getEntities(); + + DomDocument.checkName(name, (owner != null) ? + "1.1".equals(owner.getXmlVersion()) : false); + if (entities.getNamedItem(name) != null) + { + return null; + } + + entity = new DomEntity(owner, name, publicId, systemId, notation); + entities.setNamedItem(entity); + return entity; + } + + /** + * DOM L1 + * Returns information about any notations declared in the DTD. + * + *
Note: DOM L1 doesn't throw a DOMException here, but + * then it doesn't have the strange construction rules of L2. + * + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public NamedNodeMap getNotations() + { + if (notations == null) + { + notations = new DomNamedNodeMap(this, Node.NOTATION_NODE); + } + return notations; + } + + /** + * Records the declaration of a notation in this DocumentType. + * + * @param name Name of the notation + * @param publicId If non-null, provides the notation's PUBLIC identifier + * @param systemId If non-null, provides the notation's SYSTEM identifier + * @return The notation that was declared. + * + * @exception DOMException NO_MODIFICATION_ALLOWED_ERR if the + * DocumentType is no longer writable. + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public Notation declareNotation(String name, + String publicId, + String systemId) + { + DomNotation notation; + + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + getNotations(); + + DomDocument.checkName(name, (owner != null) ? + "1.1".equals(owner.getXmlVersion()) : false); + + notation = new DomNotation(owner, name, publicId, systemId); + notations.setNamedItem(notation); + return notation; + } + + /** + * DOM L2 + * Returns the internal subset of the document, as a string of unparsed + * XML declarations (and comments, PIs, whitespace); or returns null if + * there is no such subset. There is no vendor-independent expectation + * that this attribute be set, or that declarations found in it be + * reflected in the entities or notations attributes + * of this Document "Type" object. + * + *
Some application-specific XML profiles require that documents
+ * only use specific PUBLIC identifiers, without an internal subset
+ * to modify the interperetation of the declarations associated with
+ * that PUBLIC identifier through some standard.
+ */
+ public String getInternalSubset()
+ {
+ return subset;
+ }
+
+ /**
+ * The base URI of a DocumentType is always null
.
+ * See the Infoset Mapping, appendix C.
+ */
+ public final String getBaseURI()
+ {
+ return null;
+ }
+
+ /**
+ * Sets the internal "readonly" flag so the node and its associated
+ * data (only lists of entities and notations, no type information
+ * at the moment) can't be changed.
+ */
+ public void makeReadonly()
+ {
+ super.makeReadonly();
+ if (entities != null)
+ {
+ entities.makeReadonly();
+ }
+ if (notations != null)
+ {
+ notations.makeReadonly();
+ }
+ }
+
+ void setOwner(DomDocument doc)
+ {
+ if (entities != null)
+ {
+ for (DomNode ctx = entities.first; ctx != null; ctx = ctx.next)
+ {
+ ctx.setOwner(doc);
+ }
+ }
+ if (notations != null)
+ {
+ for (DomNode ctx = notations.first; ctx != null; ctx = ctx.next)
+ {
+ ctx.setOwner(doc);
+ }
+ }
+ super.setOwner(doc);
+ }
+
+ /**
+ * DOM L2
+ * Consults the DOM implementation to determine if the requested
+ * feature is supported.
+ */
+ final public boolean supports(String feature, String version)
+ {
+ return implementation.hasFeature(feature, version);
+ }
+
+ /**
+ * Returns the implementation associated with this document type.
+ */
+ final public DOMImplementation getImplementation()
+ {
+ return implementation;
+ }
+
+ public void elementDecl(String name, String model)
+ {
+ DTDElementTypeInfo info = getElementTypeInfo(name);
+ if (info == null)
+ {
+ info = new DTDElementTypeInfo(name, model);
+ elements.put(name, info);
+ }
+ else
+ {
+ info.model = model;
+ }
+ }
+
+ DTDElementTypeInfo getElementTypeInfo(String name)
+ {
+ return (DTDElementTypeInfo) elements.get(name);
+ }
+
+ public void attributeDecl(String eName, String aName, String type,
+ String mode, String value)
+ {
+ DTDAttributeTypeInfo info = new DTDAttributeTypeInfo(eName, aName, type,
+ mode, value);
+ DTDElementTypeInfo elementInfo = getElementTypeInfo(eName);
+ if (elementInfo == null)
+ {
+ elementInfo = new DTDElementTypeInfo(eName, null);
+ elements.put(eName, elementInfo);
+ }
+ elementInfo.setAttributeTypeInfo(aName, info);
+ if ("ID".equals(type))
+ {
+ ids = true;
+ }
+ }
+
+ DTDAttributeTypeInfo getAttributeTypeInfo(String elementName, String name)
+ {
+ DTDElementTypeInfo elementInfo =
+ (DTDElementTypeInfo) elements.get(elementName);
+ return (elementInfo == null) ? null :
+ elementInfo.getAttributeTypeInfo(name);
+ }
+
+ boolean hasIds()
+ {
+ return ids;
+ }
+
+ public boolean isSameNode(Node arg)
+ {
+ if (equals(arg))
+ {
+ return true;
+ }
+ if (!(arg instanceof DocumentType))
+ {
+ return false;
+ }
+ DocumentType doctype = (DocumentType) arg;
+ if (!equal(getPublicId(), doctype.getPublicId()))
+ {
+ return false;
+ }
+ if (!equal(getSystemId(), doctype.getSystemId()))
+ {
+ return false;
+ }
+ if (!equal(getInternalSubset(), doctype.getInternalSubset()))
+ {
+ return false;
+ }
+ // TODO entities
+ // TODO notations
+ return true;
+ }
+
+ /**
+ * Shallow clone of the doctype, except that associated
+ * entities and notations are (deep) cloned.
+ */
+ public Object clone()
+ {
+ DomDoctype node = (DomDoctype) super.clone();
+
+ if (entities != null)
+ {
+ node.entities = new DomNamedNodeMap(node, Node.ENTITY_NODE);
+ for (DomNode ctx = entities.first; ctx != null; ctx = ctx.next)
+ {
+ node.entities.setNamedItem(ctx.cloneNode(true));
+ }
+ }
+ if (notations != null)
+ {
+ node.notations = new DomNamedNodeMap(node, Node.NOTATION_NODE);
+ for (DomNode ctx = notations.first; ctx != null; ctx = ctx.next)
+ {
+ node.notations.setNamedItem(ctx.cloneNode(true));
+ }
+ }
+ return node;
+ }
+
+
+}
diff --git a/libjava/classpath/gnu/xml/dom/DomDocument.java b/libjava/classpath/gnu/xml/dom/DomDocument.java
new file mode 100644
index 0000000..dc476b5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/DomDocument.java
@@ -0,0 +1,1496 @@
+/* DomDocument.java --
+ Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom;
+
+import java.util.Iterator;
+import javax.xml.XMLConstants;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.DOMConfiguration;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Element;
+import org.w3c.dom.Entity;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.Notation;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.w3c.dom.UserDataHandler;
+import org.w3c.dom.traversal.DocumentTraversal;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.NodeIterator;
+import org.w3c.dom.traversal.TreeWalker;
+import org.w3c.dom.xpath.XPathEvaluator;
+import org.w3c.dom.xpath.XPathException;
+import org.w3c.dom.xpath.XPathExpression;
+import org.w3c.dom.xpath.XPathNSResolver;
+
+/**
+ *
"Document" and "DocumentTraversal" implementation. + * + *
Note that when this checks names for legality, it uses an + * approximation of the XML rules, not the real ones. Specifically, + * it uses Unicode rules, with sufficient tweaks to pass a majority + * of basic XML conformance tests. (The huge XML character tables are + * hairy to implement.) + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomDocument + extends DomNode + implements Document, DocumentTraversal, XPathEvaluator +{ + + private final DOMImplementation implementation; + private boolean checkingCharacters = true; + boolean checkingWellformedness = true; + + boolean building; // if true, skip mutation events in the tree + + DomDocumentConfiguration config; + + String inputEncoding; + String encoding; + String version = "1.0"; + boolean standalone; + String systemId; + + /** + * Constructs a Document node, associating it with an instance + * of the DomImpl class. + * + *
Note that this constructor disables character checking.
+ * It is normally used when connecting a DOM to an XML parser,
+ * and duplicating such checks is undesirable. When used for
+ * purposes other than connecting to a parser, you should
+ * re-enable that checking.
+ *
+ * @see #setCheckingCharacters
+ */
+ public DomDocument()
+ {
+ this(new DomImpl());
+ }
+
+ /**
+ * Constructs a Document node, associating it with the specified
+ * implementation. This should only be used in conjunction with
+ * a specialized implementation; it will normally be called by
+ * that implementation.
+ *
+ * @see DomImpl
+ * @see #setCheckingCharacters
+ */
+ protected DomDocument(DOMImplementation impl)
+ {
+ super(DOCUMENT_NODE, null);
+ implementation = impl;
+ }
+
+ /**
+ * Sets the building
flag.
+ * Mutation events in the document are not reported.
+ */
+ public void setBuilding(boolean flag)
+ {
+ building = flag;
+ }
+
+ /**
+ * Sets whether to check for document well-formedness.
+ * If true, an exception will be raised if a second doctype or root
+ * element node is added to the document.
+ */
+ public void setCheckWellformedness(boolean flag)
+ {
+ checkingWellformedness = flag;
+ }
+
+ /**
+ * DOM L1
+ * Returns the constant "#document".
+ */
+ final public String getNodeName()
+ {
+ return "#document";
+ }
+
+ /**
+ * DOM L1
+ * Returns the document's root element, or null.
+ */
+ final public Element getDocumentElement()
+ {
+ for (DomNode ctx = first; ctx != null; ctx = ctx.next)
+ {
+ if (ctx.nodeType == ELEMENT_NODE)
+ {
+ return (Element) ctx;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * DOM L1
+ * Returns the document's DocumentType, or null.
+ */
+ final public DocumentType getDoctype()
+ {
+ for (DomNode ctx = first; ctx != null; ctx = ctx.next)
+ {
+ if (ctx.nodeType == DOCUMENT_TYPE_NODE)
+ {
+ return (DocumentType) ctx;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * DOM L1
+ * Returns the document's DOMImplementation.
+ */
+ final public DOMImplementation getImplementation()
+ {
+ return implementation;
+ }
+
+ /**
+ * DOM L1 (relocated in DOM L2)
+ * Returns the element with the specified "ID" attribute, or null.
+ *
+ *
Returns null unless {@link Consumer} was used to populate internal + * DTD declaration information, using package-private APIs. If that + * internal DTD information is available, the document may be searched for + * the element with that ID. + */ + public Element getElementById(String id) + { + DomDoctype doctype = (DomDoctype) getDoctype(); + + if (doctype == null || !doctype.hasIds() + || id == null || id.length() == 0) + { + return null; + } + + // yes, this is linear in size of document. + // it'd be easy enough to maintain a hashtable. + Node current = getDocumentElement(); + Node temp; + + if (current == null) + { + return null; + } + while (current != this) + { + // done? + if (current.getNodeType() == ELEMENT_NODE) + { + DomElement element = (DomElement) current; + DTDElementTypeInfo info = + doctype.getElementTypeInfo(current.getNodeName()); + if (info != null && + id.equals(element.getAttribute(info.idAttrName))) + { + return element; + } + else if (element.userIdAttrs != null) + { + for (Iterator i = element.userIdAttrs.iterator(); + i.hasNext(); ) + { + Node idAttr = (Node) i.next(); + if (id.equals(idAttr.getNodeValue())) + { + return element; + } + } + } + } + + // descend? + if (current.hasChildNodes()) + { + current = current.getFirstChild(); + continue; + } + + // lateral? + temp = current.getNextSibling(); + if (temp != null) + { + current = temp; + continue; + } + + // back up ... + do + { + temp = current.getParentNode(); + if (temp == null) + { + return null; + } + current = temp; + temp = current.getNextSibling(); + } + while (temp == null); + current = temp; + } + return null; + } + + private void checkNewChild(Node newChild) + { + if (newChild.getNodeType() == ELEMENT_NODE + && getDocumentElement() != null) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "document element already present: " + + getDocumentElement(), newChild, 0); + } + if (newChild.getNodeType() == DOCUMENT_TYPE_NODE + && getDoctype() != null) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "document type already present: " + + getDoctype(), newChild, 0); + } + } + + /** + * DOM L1 + * Appends the specified node to this node's list of children, + * enforcing the constraints that there be only one root element + * and one document type child. + */ + public Node appendChild(Node newChild) + { + if (checkingWellformedness) + { + checkNewChild(newChild); + } + return super.appendChild(newChild); + } + + /** + * DOM L1 + * Inserts the specified node in this node's list of children, + * enforcing the constraints that there be only one root element + * and one document type child. + */ + public Node insertBefore(Node newChild, Node refChild) + { + if (checkingWellformedness) + { + checkNewChild(newChild); + } + return super.insertBefore(newChild, refChild); + } + + /** + * DOM L1 + * Replaces the specified node in this node's list of children, + * enforcing the constraints that there be only one root element + * and one document type child. + */ + public Node replaceChild(Node newChild, Node refChild) + { + if (checkingWellformedness && + ((newChild.getNodeType() == ELEMENT_NODE && + refChild.getNodeType() != ELEMENT_NODE) || + (newChild.getNodeType() == DOCUMENT_TYPE_NODE && + refChild.getNodeType() != DOCUMENT_TYPE_NODE))) + { + checkNewChild(newChild); + } + return super.replaceChild(newChild, refChild); + } + + // NOTE: DOM can't really tell when the name of an entity, + // notation, or PI must follow the namespace rules (excluding + // colons) instead of the XML rules (which allow them without + // much restriction). That's an API issue. verifyXmlName + // aims to enforce the XML rules, not the namespace rules. + + /** + * Throws a DOM exception if the specified name is not a legal XML 1.0 + * Name. + * @deprecated This method is deprecated and may be removed in future + * versions of GNU JAXP + */ + public static void verifyXmlName(String name) + { + // XXX why is this public? + checkName(name, false); + } + + static void checkName(String name, boolean xml11) + { + if (name == null) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0); + } + int len = name.length(); + if (len == 0) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0); + } + + // dog: rewritten to use the rules for XML 1.0 and 1.1 + + // Name start character + char c = name.charAt(0); + if (xml11) + { + // XML 1.1 + if ((c < 0x0041 || c > 0x005a) && + (c < 0x0061 || c > 0x007a) && + c != ':' && c != '_' && + (c < 0x00c0 || c > 0x00d6) && + (c < 0x00d8 || c > 0x00f6) && + (c < 0x00f8 || c > 0x02ff) && + (c < 0x0370 || c > 0x037d) && + (c < 0x037f || c > 0x1fff) && + (c < 0x200c || c > 0x200d) && + (c < 0x2070 || c > 0x218f) && + (c < 0x2c00 || c > 0x2fef) && + (c < 0x3001 || c > 0xd7ff) && + (c < 0xf900 || c > 0xfdcf) && + (c < 0xfdf0 || c > 0xfffd) && + (c < 0x10000 || c > 0xeffff)) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + } + else + { + // XML 1.0 + int type = Character.getType(c); + switch (type) + { + case Character.LOWERCASE_LETTER: // Ll + case Character.UPPERCASE_LETTER: // Lu + case Character.OTHER_LETTER: // Lo + case Character.TITLECASE_LETTER: // Lt + case Character.LETTER_NUMBER: // Nl + if ((c > 0xf900 && c < 0xfffe) || + (c >= 0x20dd && c <= 0x20e0)) + { + // Compatibility area and Unicode 2.0 exclusions + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + break; + default: + if (c != ':' && c != '_' && (c < 0x02bb || c > 0x02c1) && + c != 0x0559 && c != 0x06e5 && c != 0x06e6) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + } + } + + // Subsequent characters + for (int i = 1; i < len; i++) + { + c = name.charAt(i); + if (xml11) + { + // XML 1.1 + if ((c < 0x0041 || c > 0x005a) && + (c < 0x0061 || c > 0x007a) && + (c < 0x0030 || c > 0x0039) && + c != ':' && c != '_' && c != '-' && c != '.' && + (c < 0x00c0 || c > 0x00d6) && + (c < 0x00d8 || c > 0x00f6) && + (c < 0x00f8 || c > 0x02ff) && + (c < 0x0370 || c > 0x037d) && + (c < 0x037f || c > 0x1fff) && + (c < 0x200c || c > 0x200d) && + (c < 0x2070 || c > 0x218f) && + (c < 0x2c00 || c > 0x2fef) && + (c < 0x3001 || c > 0xd7ff) && + (c < 0xf900 || c > 0xfdcf) && + (c < 0xfdf0 || c > 0xfffd) && + (c < 0x10000 || c > 0xeffff) && + c != 0x00b7 && + (c < 0x0300 || c > 0x036f) && + (c < 0x203f || c > 0x2040)) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, name, + null, c); + } + } + else + { + // XML 1.0 + int type = Character.getType(c); + switch (type) + { + case Character.LOWERCASE_LETTER: // Ll + case Character.UPPERCASE_LETTER: // Lu + case Character.DECIMAL_DIGIT_NUMBER: // Nd + case Character.OTHER_LETTER: // Lo + case Character.TITLECASE_LETTER: // Lt + case Character.LETTER_NUMBER: // Nl + case Character.COMBINING_SPACING_MARK: // Mc + case Character.ENCLOSING_MARK: // Me + case Character.NON_SPACING_MARK: // Mn + case Character.MODIFIER_LETTER: // Lm + if ((c > 0xf900 && c < 0xfffe) || + (c >= 0x20dd && c <= 0x20e0)) + { + // Compatibility area and Unicode 2.0 exclusions + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + break; + default: + if (c != '-' && c != '.' && c != ':' && c != '_' && + c != 0x0387 && (c < 0x02bb || c > 0x02c1) && + c != 0x0559 && c != 0x06e5 && c != 0x06e6 && c != 0x00b7) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + } + } + } + + // FIXME characters with a font or compatibility decomposition (i.e. + // those with a "compatibility formatting tag" in field 5 of the + // database -- marked by field 5 beginning with a "<") are not allowed. + } + + // package private + static void checkNCName(String name, boolean xml11) + { + checkName(name, xml11); + int len = name.length(); + int index = name.indexOf(':'); + if (index != -1) + { + if (index == 0 || index == (len - 1) || + name.lastIndexOf(':') != index) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + name, null, 0); + } + } + } + + // package private + static void checkChar(String value, boolean xml11) + { + char[] chars = value.toCharArray(); + checkChar(chars, 0, chars.length, xml11); + } + + static void checkChar(char[] buf, int off, int len, boolean xml11) + { + for (int i = 0; i < len; i++) + { + char c = buf[i]; + + // assume surrogate pairing checks out OK, for simplicity + if ((c >= 0x0020 && c <= 0xd7ff) || + (c == 0x000a || c == 0x000d || c == 0x0009) || + (c >= 0xe000 && c <= 0xfffd) || + (c >= 0x10000 && c <= 0x10ffff)) + { + continue; + } + if (xml11) + { + if ((c >= 0x0001 && c <= 0x001f) || + (c >= 0x007f && c <= 0x0084) || + (c >= 0x0086 && c <= 0x009f)) + { + continue; + } + } + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + new String(buf, off, len), null, c); + } + } + + /** + * DOM L1 + * Returns a newly created element with the specified name. + */ + public Element createElement(String name) + { + Element element; + + if (checkingCharacters) + { + checkName(name, "1.1".equals(version)); + } + if (name.startsWith("xml:")) + { + element = createElementNS(null, name); + } + else + { + DomElement domElement = new DomElement(this, null, name); + domElement.localName = null; + element = domElement; + } + defaultAttributes(element, name); + return element; + } + + /** + * DOM L2 + * Returns a newly created element with the specified name + * and namespace information. + */ + public Element createElementNS(String namespaceURI, String name) + { + if (checkingCharacters) + { + checkNCName(name, "1.1".equals(version)); + } + + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + if (name.startsWith("xml:")) + { + if (namespaceURI != null + && !XMLConstants.XML_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace is always " + + XMLConstants.XML_NS_URI, this, 0); + } + namespaceURI = XMLConstants.XML_NS_URI; + } + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:")) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns is reserved", this, 0); + } + else if (namespaceURI == null && name.indexOf(':') != -1) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "prefixed name '" + name + + "' needs a URI", this, 0); + } + + Element element = new DomElement(this, namespaceURI, name); + defaultAttributes(element, name); + return element; + } + + private void defaultAttributes(Element element, String name) + { + DomDoctype doctype = (DomDoctype) getDoctype(); + if (doctype == null) + { + return; + } + + // default any attributes that need it + DTDElementTypeInfo info = doctype.getElementTypeInfo(name); + if (info != null) + { + for (Iterator i = info.attributes(); i != null && i.hasNext(); ) + { + DTDAttributeTypeInfo attr = (DTDAttributeTypeInfo) i.next(); + DomAttr node = (DomAttr) createAttribute(attr.name); + + String value = attr.value; + if (value == null) + { + value = ""; + } + node.setValue(value); + node.setSpecified(false); + element.setAttributeNode(node); + } + } + } + + /** + * DOM L1 + * Returns a newly created document fragment. + */ + public DocumentFragment createDocumentFragment() + { + return new DomDocumentFragment(this); + } + + /** + * DOM L1 + * Returns a newly created text node with the specified value. + */ + public Text createTextNode(String value) + { + if (checkingCharacters) + { + checkChar(value, "1.1".equals(version)); + } + return new DomText(this, value); + } + + /** + * Returns a newly created text node with the specified value. + */ + public Text createTextNode(char[] buf, int off, int len) + { + if (checkingCharacters) + { + checkChar(buf, off, len, "1.1".equals(version)); + } + return new DomText(this, buf, off, len); + } + + /** + * DOM L1 + * Returns a newly created comment node with the specified value. + */ + public Comment createComment(String value) + { + if (checkingCharacters) + { + checkChar(value, "1.1".equals(version)); + } + return new DomComment(this, value); + } + + /** + * DOM L1 + * Returns a newly created CDATA section node with the specified value. + */ + public CDATASection createCDATASection(String value) + { + if (checkingCharacters) + { + checkChar(value, "1.1".equals(version)); + } + return new DomCDATASection(this, value); + } + + /** + * Returns a newly created CDATA section node with the specified value. + */ + public CDATASection createCDATASection(char[] buf, int off, int len) + { + if (checkingCharacters) + { + checkChar(buf, off, len, "1.1".equals(version)); + } + return new DomCDATASection(this, buf, off, len); + } + + /** + * DOM L1 + * Returns a newly created processing instruction. + */ + public ProcessingInstruction createProcessingInstruction(String target, + String data) + { + if (checkingCharacters) + { + boolean xml11 = "1.1".equals(version); + checkName(target, xml11); + if ("xml".equalsIgnoreCase(target)) + { + throw new DomDOMException(DOMException.SYNTAX_ERR, + "illegal PI target name", + this, 0); + } + checkChar(data, xml11); + } + return new DomProcessingInstruction(this, target, data); + } + + /** + * DOM L1 + * Returns a newly created attribute with the specified name. + */ + public Attr createAttribute(String name) + { + if (checkingCharacters) + { + checkName(name, "1.1".equals(version)); + } + if (name.startsWith("xml:")) + { + return createAttributeNS(XMLConstants.XML_NS_URI, name); + } + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:")) + { + return createAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, name); + } + else + { + DomAttr ret = new DomAttr(this, null, name); + ret.localName = null; + return ret; + } + } + + /** + * DOM L2 + * Returns a newly created attribute with the specified name + * and namespace information. + */ + public Attr createAttributeNS(String namespaceURI, String name) + { + if (checkingCharacters) + { + checkNCName(name, "1.1".equals(version)); + } + + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + if (name.startsWith ("xml:")) + { + if (namespaceURI == null) + { + namespaceURI = XMLConstants.XML_NS_URI; + } + else if (!XMLConstants.XML_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace is always " + + XMLConstants.XML_NS_URI, + this, 0); + } + } + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:")) + { + if (namespaceURI == null) + { + namespaceURI = XMLConstants.XMLNS_ATTRIBUTE_NS_URI; + } + else if (!XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns namespace must be " + + XMLConstants.XMLNS_ATTRIBUTE_NS_URI, + this, 0); + } + } + else if (namespaceURI == null && name.indexOf(':') != -1) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "prefixed name needs a URI: " + name, this, 0); + } + return new DomAttr(this, namespaceURI, name); + } + + /** + * DOM L1 + * Returns a newly created reference to the specified entity. + * The caller should populate this with the appropriate children + * and then mark it as readonly. + * + * @see DomNode#makeReadonly + */ + public EntityReference createEntityReference(String name) + { + DomEntityReference ret = new DomEntityReference(this, name); + DocumentType doctype = getDoctype(); + if (doctype != null) + { + DomEntity ent = (DomEntity) doctype.getEntities().getNamedItem(name); + if (ent != null) + { + for (DomNode ctx = ent.first; ctx != null; ctx = ctx.next) + { + ret.appendChild(ctx.cloneNode(true)); + } + } + } + ret.makeReadonly(); + return ret; + } + + /** + * DOM L2 + * Makes a copy of the specified node, with all nodes "owned" by + * this document and with children optionally copied. This type + * of standard utility has become, well, a standard utility. + * + *
Note that EntityReference nodes created through this method (either + * directly, or recursively) never have children, and that there is no + * portable way to associate them with such children. + * + *
Note also that there is no requirement that the specified node + * be associated with a different document. This differs from the + * cloneNode operation in that the node itself is not given + * an opportunity to participate, so that any information managed + * by node subclasses will be lost. + */ + public Node importNode(Node src, boolean deep) + { + Node dst = null; + switch (src.getNodeType()) + { + case TEXT_NODE: + dst = createTextNode(src.getNodeValue()); + break; + case CDATA_SECTION_NODE: + dst = createCDATASection(src.getNodeValue()); + break; + case COMMENT_NODE: + dst = createComment(src.getNodeValue()); + break; + case PROCESSING_INSTRUCTION_NODE: + dst = createProcessingInstruction(src.getNodeName(), + src.getNodeValue()); + break; + case NOTATION_NODE: + // NOTE: There's no standard way to create + // these, or add them to a doctype. Useless. + Notation notation = (Notation) src; + dst = new DomNotation(this, notation.getNodeName(), + notation.getPublicId(), + notation.getSystemId()); + break; + case ENTITY_NODE: + // NOTE: There's no standard way to create + // these, or add them to a doctype. Useless. + Entity entity = (Entity) src; + dst = new DomEntity(this, entity.getNodeName(), + entity.getPublicId(), + entity.getSystemId(), + entity.getNotationName()); + if (deep) + { + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, deep)); + } + } + break; + case ENTITY_REFERENCE_NODE: + dst = createEntityReference(src.getNodeName()); + break; + case DOCUMENT_FRAGMENT_NODE: + dst = new DomDocumentFragment(this); + if (deep) + { + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, deep)); + } + } + break; + case ATTRIBUTE_NODE: + String attr_nsuri = src.getNamespaceURI(); + if (attr_nsuri != null) + { + dst = createAttributeNS(attr_nsuri, src.getNodeName()); + } + else + { + dst = createAttribute(src.getNodeName()); + } + // this is _always_ done regardless of "deep" setting + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, false)); + } + break; + case ELEMENT_NODE: + String elem_nsuri = src.getNamespaceURI(); + if (elem_nsuri != null) + { + dst = createElementNS(elem_nsuri, src.getNodeName()); + } + else + { + dst = createElement(src.getNodeName()); + } + NamedNodeMap srcAttrs = src.getAttributes(); + NamedNodeMap dstAttrs = dst.getAttributes(); + int len = srcAttrs.getLength(); + for (int i = 0; i < len; i++) + { + Attr a = (Attr) srcAttrs.item(i); + Attr dflt; + + // maybe update defaulted attributes + dflt = (Attr) dstAttrs.getNamedItem(a.getNodeName()); + if (dflt != null) + { + String newval = a.getNodeValue(); + if (!dflt.getNodeValue().equals(newval) + || a.getSpecified () == true) + { + dflt.setNodeValue (newval); + } + continue; + } + + dstAttrs.setNamedItem((Attr) importNode(a, false)); + } + if (deep) + { + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, true)); + } + } + break; + // can't import document or doctype nodes + case DOCUMENT_NODE: + case DOCUMENT_TYPE_NODE: + // FALLTHROUGH + // can't import unrecognized or nonstandard nodes + default: + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, null, src, 0); + } + + // FIXME cleanup a bit -- for deep copies, copy those + // children in one place, here (code sharing is healthy) + + if (src instanceof DomNode) + { + ((DomNode) src).notifyUserDataHandlers(UserDataHandler.NODE_IMPORTED, + src, dst); + } + return dst; + } + + /** + * DOM L2 (Traversal) + * Returns a newly created node iterator. Don't forget to detach + * this iterator when you're done using it! + * + * @see DomIterator + */ + public NodeIterator createNodeIterator(Node root, + int whatToShow, + NodeFilter filter, + boolean expandEntities) + { + return new DomNodeIterator(root, whatToShow, filter, expandEntities, + false); + } + + public TreeWalker createTreeWalker(Node root, + int whatToShow, + NodeFilter filter, + boolean expandEntities) + { + return new DomNodeIterator(root, whatToShow, filter, expandEntities, + true); + } + + // DOM Level 3 methods + + /** + * DOM L3 + */ + public String getInputEncoding() + { + return inputEncoding; + } + + public void setInputEncoding(String inputEncoding) + { + this.inputEncoding = inputEncoding; + } + + /** + * DOM L3 + */ + public String getXmlEncoding() + { + return encoding; + } + + public void setXmlEncoding(String encoding) + { + this.encoding = encoding; + } + + public boolean getXmlStandalone() + { + return standalone; + } + + public void setXmlStandalone(boolean xmlStandalone) + { + standalone = xmlStandalone; + } + + public String getXmlVersion() + { + return version; + } + + public void setXmlVersion(String xmlVersion) + { + if (xmlVersion == null) + { + xmlVersion = "1.0"; + } + if ("1.0".equals(xmlVersion) || + "1.1".equals(xmlVersion)) + { + version = xmlVersion; + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + } + + public boolean getStrictErrorChecking() + { + return checkingCharacters; + } + + public void setStrictErrorChecking(boolean strictErrorChecking) + { + checkingCharacters = strictErrorChecking; + } + + public String lookupPrefix(String namespaceURI) + { + Node root = getDocumentElement(); + return (root == null) ? null : root.lookupPrefix(namespaceURI); + } + + public boolean isDefaultNamespace(String namespaceURI) + { + Node root = getDocumentElement(); + return (root == null) ? false : root.isDefaultNamespace(namespaceURI); + } + + public String lookupNamespaceURI(String prefix) + { + Node root = getDocumentElement(); + return (root == null) ? null : root.lookupNamespaceURI(prefix); + } + + public String getBaseURI() + { + return getDocumentURI(); + /* + Node root = getDocumentElement(); + if (root != null) + { + NamedNodeMap attrs = root.getAttributes(); + Node xmlBase = attrs.getNamedItemNS(XMLConstants.XML_NS_URI, "base"); + if (xmlBase != null) + { + return xmlBase.getNodeValue(); + } + } + return systemId; + */ + } + + public String getDocumentURI() + { + return systemId; + } + + public void setDocumentURI(String documentURI) + { + systemId = documentURI; + } + + public Node adoptNode(Node source) + { + int sourceNodeType = source.getNodeType(); + switch (sourceNodeType) + { + case DOCUMENT_NODE: + case DOCUMENT_TYPE_NODE: + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + case ENTITY_NODE: + case NOTATION_NODE: + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + if (source instanceof DomNode) + { + // GNU native + DomNode src = (DomNode) source; + DomNode dst = src; + if (dst.parent != null) + { + dst = (DomNode) dst.cloneNode(true); + } + dst.setOwner(this); + src.notifyUserDataHandlers(UserDataHandler.NODE_ADOPTED, src, dst); + return dst; + } + else + { + // Some other implementation + Node dst = null; + switch (sourceNodeType) + { + case Node.ATTRIBUTE_NODE: + { + Attr src = (Attr) source; + String nodeName = src.getNodeName(); + String localName = src.getLocalName(); + String namespaceUri = src.getNamespaceURI(); + dst = (localName == null) ? + createAttribute(nodeName) : + createAttributeNS(namespaceUri, nodeName); + adoptChildren(src, dst); + break; + } + case Node.CDATA_SECTION_NODE: + { + CDATASection src = (CDATASection) source; + dst = createCDATASection(src.getData()); + break; + } + case Node.COMMENT_NODE: + { + Comment src = (Comment) source; + dst = createComment(src.getData()); + break; + } + case Node.DOCUMENT_FRAGMENT_NODE: + { + DocumentFragment src = (DocumentFragment) source; + dst = createDocumentFragment(); + adoptChildren(src, dst); + break; + } + case Node.ELEMENT_NODE: + { + Element src = (Element) source; + String nodeName = src.getNodeName(); + String localName = src.getLocalName(); + String namespaceUri = src.getNamespaceURI(); + dst = (localName == null) ? + createElement(nodeName) : + createElementNS(namespaceUri, nodeName); + adoptAttributes(src, dst); + adoptChildren(src, dst); + break; + } + case Node.ENTITY_REFERENCE_NODE: + { + EntityReference src = (EntityReference) source; + dst = createEntityReference(src.getNodeName()); + adoptChildren(src, dst); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE: + { + ProcessingInstruction src = (ProcessingInstruction) source; + dst = createProcessingInstruction(src.getTarget(), + src.getData()); + break; + } + case Node.TEXT_NODE: + { + Text src = (Text) source; + dst = createTextNode(src.getData()); + break; + } + } + return dst; + } + } + + void adoptChildren(Node src, Node dst) + { + Node node = src.getFirstChild(); + while (node != null) + { + Node next = node.getNextSibling(); + dst.appendChild(adoptNode(node)); + node = next; + } + } + + void adoptAttributes(Node src, Node dst) + { + NamedNodeMap srcAttrs = src.getAttributes(); + NamedNodeMap dstAttrs = dst.getAttributes(); + int len = srcAttrs.getLength(); + for (int i = 0; i < len; i++) + { + Node node = srcAttrs.item(i); + String localName = node.getLocalName(); + if (localName == null) + { + dstAttrs.setNamedItem(adoptNode(node)); + } + else + { + dstAttrs.setNamedItemNS(adoptNode(node)); + } + } + } + + public DOMConfiguration getDomConfig() + { + if (config == null) + { + config = new DomDocumentConfiguration(); + } + return config; + } + + public void normalizeDocument() + { + boolean save = building; + building = true; + normalizeNode(this); + building = save; + } + + void normalizeNode(DomNode node) + { + node.normalize(); + if (config != null) + { + switch (node.nodeType) + { + case CDATA_SECTION_NODE: + if (!config.cdataSections) + { + // replace CDATA section with text node + Text text = createTextNode(node.getNodeValue()); + node.parent.insertBefore(text, node); + node.parent.removeChild(node); + // merge adjacent text nodes + String data = text.getWholeText(); + node = (DomNode) text.replaceWholeText(data); + } + else if (config.splitCdataSections) + { + String value = node.getNodeValue(); + int i = value.indexOf("]]>"); + while (i != -1) + { + Node node2 = createCDATASection(value.substring(0, i)); + node.parent.insertBefore(node2, node); + value = value.substring(i + 3); + node.setNodeValue(value); + i = value.indexOf("]]>"); + } + } + break; + case COMMENT_NODE: + if (!config.comments) + { + node.parent.removeChild(node); + } + break; + case TEXT_NODE: + if (!config.elementContentWhitespace && + ((Text) node).isElementContentWhitespace()) + { + node.parent.removeChild(node); + } + break; + case ENTITY_REFERENCE_NODE: + if (!config.entities) + { + for (DomNode ctx = node.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + node.parent.insertBefore(ctx, node); + ctx = ctxNext; + } + node.parent.removeChild(node); + } + break; + case ELEMENT_NODE: + if (!config.namespaceDeclarations) + { + DomNamedNodeMap attrs = + (DomNamedNodeMap) node.getAttributes(); + boolean aro = attrs.readonly; + attrs.readonly = false; // Ensure we can delete if necessary + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String namespace = attr.getNamespaceURI(); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespace)) + { + attrs.removeNamedItemNS(namespace, + attr.getLocalName()); + i--; + len--; + } + } + attrs.readonly = aro; + } + break; + } + } + for (DomNode ctx = node.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + normalizeNode(ctx); + ctx = ctxNext; + } + } + + public Node renameNode(Node n, String namespaceURI, String qualifiedName) + throws DOMException + { + if (n instanceof DomNsNode) + { + DomNsNode src = (DomNsNode) n; + if (src == null) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + if (src.owner != this) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, src, 0); + } + boolean xml11 = "1.1".equals(version); + checkName(qualifiedName, xml11); + int ci = qualifiedName.indexOf(':'); + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + if (namespaceURI != null) + { + checkNCName(qualifiedName, xml11); + String prefix = (ci == -1) ? "" : + qualifiedName.substring(0, ci); + if (XMLConstants.XML_NS_PREFIX.equals(prefix) && + !XMLConstants.XML_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace must be " + + XMLConstants.XML_NS_URI, src, 0); + } + else if (src.nodeType == ATTRIBUTE_NODE && + (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) || + XMLConstants.XMLNS_ATTRIBUTE.equals(qualifiedName)) && + !XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns namespace must be " + + XMLConstants.XMLNS_ATTRIBUTE_NS_URI, src, 0); + } + if (XMLConstants.XML_NS_URI.equals(namespaceURI) && + !XMLConstants.XML_NS_PREFIX.equals(prefix)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace must be " + + XMLConstants.XML_NS_URI, src, 0); + } + else if (src.nodeType == ATTRIBUTE_NODE && + XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI) && + !(XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) || + XMLConstants.XMLNS_ATTRIBUTE.equals(qualifiedName))) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns namespace must be " + + XMLConstants.XMLNS_ATTRIBUTE_NS_URI, src, 0); + } + + } + src.setNodeName(qualifiedName); + src.setNamespaceURI(namespaceURI); + src.notifyUserDataHandlers(UserDataHandler.NODE_RENAMED, src, src); + // TODO MutationNameEvents + // DOMElementNameChanged or DOMAttributeNameChanged + return src; + } + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, null, n, 0); + } + + // -- XPathEvaluator -- + + public XPathExpression createExpression(String expression, + XPathNSResolver resolver) + throws XPathException, DOMException + { + return new DomXPathExpression(this, expression, resolver); + } + + public XPathNSResolver createNSResolver(Node nodeResolver) + { + return new DomXPathNSResolver(nodeResolver); + } + + public Object evaluate(String expression, + Node contextNode, + XPathNSResolver resolver, + short type, + Object result) + throws XPathException, DOMException + { + XPathExpression xpe = + new DomXPathExpression(this, expression, resolver); + return xpe.evaluate(contextNode, type, result); + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java b/libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java new file mode 100644 index 0000000..42444e8 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java @@ -0,0 +1,171 @@ +/* DomDocumentBuilder.java -- + Copyright (C) 2004 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 gnu.xml.dom; + +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; +import java.net.URL; +import javax.xml.parsers.DocumentBuilder; +import org.w3c.dom.Document; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSParser; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Document builder using the GNU DOM Load & Save implementation. + * + * @author Chris Burdess + */ +class DomDocumentBuilder + extends DocumentBuilder +{ + + final DOMImplementation impl; + final DOMImplementationLS ls; + final LSParser parser; + + DomDocumentBuilder(DOMImplementation impl, + DOMImplementationLS ls, + LSParser parser) + { + this.impl = impl; + this.ls = ls; + this.parser = parser; + } + + public boolean isNamespaceAware() + { + DOMConfiguration config = parser.getDomConfig(); + return ((Boolean) config.getParameter("namespaces")).booleanValue(); + } + + public boolean isValidating() + { + DOMConfiguration config = parser.getDomConfig(); + return ((Boolean) config.getParameter("validating")).booleanValue(); + } + + public boolean isXIncludeAware() + { + DOMConfiguration config = parser.getDomConfig(); + return ((Boolean) config.getParameter("xinclude-aware")).booleanValue(); + } + + public void setEntityResolver(EntityResolver resolver) + { + DOMConfiguration config = parser.getDomConfig(); + config.setParameter("entity-resolver", resolver); + } + + public void setErrorHandler(ErrorHandler handler) + { + DOMConfiguration config = parser.getDomConfig(); + config.setParameter("error-handler", handler); + } + + public DOMImplementation getDOMImplementation() + { + return impl; + } + + public Document newDocument() + { + return impl.createDocument(null, null, null); + } + + public Document parse(InputStream in) + throws SAXException, IOException + { + LSInput input = ls.createLSInput(); + input.setByteStream(in); + return parser.parse(input); + } + + public Document parse(InputStream in, String systemId) + throws SAXException, IOException + { + LSInput input = ls.createLSInput(); + input.setByteStream(in); + input.setSystemId(systemId); + return parser.parse(input); + } + + public Document parse(String systemId) + throws SAXException, IOException + { + return parser.parseURI(systemId); + } + + public Document parse(InputSource is) + throws SAXException, IOException + { + LSInput input = ls.createLSInput(); + String systemId = is.getSystemId(); + InputStream in = is.getByteStream(); + if (in != null) + { + input.setByteStream(in); + } + else + { + Reader reader = is.getCharacterStream(); + if (reader != null) + { + input.setCharacterStream(reader); + } + else + { + URL url = new URL(systemId); + input.setByteStream(url.openStream()); + } + } + input.setPublicId(is.getPublicId()); + input.setSystemId(systemId); + input.setEncoding(is.getEncoding()); + return parser.parse(input); + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java b/libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java new file mode 100644 index 0000000..814141c --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java @@ -0,0 +1,128 @@ +/* DomDocumentBuilderFactory.java -- + Copyright (C) 2004 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 gnu.xml.dom; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSParser; + +/** + * Document builder factory that uses a DOM Level 3 Load & Save + * implementation. + * + * @author Chris Burdess + */ +public class DomDocumentBuilderFactory + extends DocumentBuilderFactory +{ + + final DOMImplementation impl; + final DOMImplementationLS ls; + + public DomDocumentBuilderFactory() + { + try + { + DOMImplementationRegistry reg = + DOMImplementationRegistry.newInstance(); + impl = reg.getDOMImplementation("LS 3.0"); + if (impl == null) + { + throw new FactoryConfigurationError("no LS implementations found"); + } + ls = (DOMImplementationLS) impl; + } + catch (Exception e) + { + throw new FactoryConfigurationError(e); + } + } + + public DocumentBuilder newDocumentBuilder() + throws ParserConfigurationException + { + LSParser parser = ls.createLSParser(DOMImplementationLS.MODE_ASYNCHRONOUS, + "http://www.w3.org/TR/REC-xml"); + DOMConfiguration config = parser.getDomConfig(); + setParameter(config, "namespaces", + isNamespaceAware() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "element-content-whitespace", + isIgnoringElementContentWhitespace() ? Boolean.FALSE : + Boolean.TRUE); + setParameter(config, "comments", + isIgnoringComments() ? Boolean.FALSE : Boolean.TRUE); + setParameter(config, "expand-entity-references", + isExpandEntityReferences() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "coalescing", + isCoalescing() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "validating", + isValidating() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "xinclude-aware", + isXIncludeAware() ? Boolean.TRUE : Boolean.FALSE); + return new DomDocumentBuilder(impl, ls, parser); + } + + void setParameter(DOMConfiguration config, String name, Object value) + throws ParserConfigurationException + { + if (!config.canSetParameter(name, value)) + { + throw new ParserConfigurationException(name); + } + config.setParameter(name, value); + } + + public Object getAttribute(String name) + { + // TODO + return null; + } + + public void setAttribute(String name, Object value) + { + // TODO + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java b/libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java new file mode 100644 index 0000000..5c589f8 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java @@ -0,0 +1,260 @@ +/* DomDocumentConfiguration.java -- + Copyright (C) 2004 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 gnu.xml.dom; + +import java.util.Arrays; +import java.util.List; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; + +/** + * Document configuration, used to store normalization and other parameters. + * + * @author Chris Burdess + */ +class DomDocumentConfiguration + implements DOMConfiguration, DOMStringList +{ + + private static final List SUPPORTED_PARAMETERS = + Arrays.asList(new String[] { "cdata-sections", + "comments", + "element-content-whitespace", + "entities", + "error-handler", + "namespace-declarations", + "split-cdata-sections", + "infoset"}); + + boolean cdataSections = true; + boolean comments = true; + boolean elementContentWhitespace = true; + boolean entities = true; + DOMErrorHandler errorHandler; + boolean namespaceDeclarations = true; + boolean splitCdataSections = true; + + public void setParameter(String name, Object value) + throws DOMException + { + name = name.toLowerCase(); + if ("cdata-sections".equals(name)) + { + cdataSections = "true".equals(value.toString()); + } + else if ("comments".equals(name)) + { + comments = "true".equals(value.toString()); + } + else if ("element-content-whitespace".equals(name)) + { + elementContentWhitespace = "true".equals(value.toString()); + } + else if ("entities".equals(name)) + { + entities = "true".equals(value.toString()); + } + else if ("error-handler".equals(name)) + { + try + { + errorHandler = (DOMErrorHandler) value; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.TYPE_MISMATCH_ERR, + value.getClass().getName(), null, 0); + } + } + else if ("namespace-declarations".equals(name)) + { + namespaceDeclarations = "true".equals(value.toString()); + } + else if ("split-cdata-sections".equals(name)) + { + comments = "true".equals(value.toString()); + } + else if ("infoset".equals(name)) + { + if ("true".equals(value.toString())) + { + entities = false; + cdataSections = false; + namespaceDeclarations = true; + elementContentWhitespace = true; + comments = true; + } + } + else if (("canonical-form".equals(name) || + "check-character-normalization".equals(name) || + "datatype-normalization".equals(name) || + "normalize-characters".equals(name) || + "validate".equals(name) || + "validate-if-schema".equals(name)) && + "false".equals(value.toString())) + { + // NOOP + } + else if (("namespaces".equals(name) || + "well-formed".equals(name)) && + "true".equals(value.toString())) + { + // NOOP + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, + name, null, 0); + } + } + + public Object getParameter(String name) + throws DOMException + { + name = name.toLowerCase(); + if ("cdata-sections".equals(name)) + { + return cdataSections ? Boolean.TRUE : Boolean.FALSE; + } + else if ("comments".equals(name)) + { + return comments ? Boolean.TRUE : Boolean.FALSE; + } + else if ("element-content-whitespace".equals(name)) + { + return elementContentWhitespace ? Boolean.TRUE : Boolean.FALSE; + } + else if ("entities".equals(name)) + { + return entities ? Boolean.TRUE : Boolean.FALSE; + } + else if ("error-handler".equals(name)) + { + return errorHandler; + } + else if ("namespace-declarations".equals(name)) + { + return namespaceDeclarations ? Boolean.TRUE : Boolean.FALSE; + } + else if ("split-cdata-sections".equals(name)) + { + return comments ? Boolean.TRUE : Boolean.FALSE; + } + else if ("canonical-form".equals(name) || + "check-character-normalization".equals(name) || + "datatype-normalization".equals(name) || + "normalize-characters".equals(name) || + "validate".equals(name) || + "validate-if-schema".equals(name)) + { + return Boolean.FALSE; + } + else if ("namespaces".equals(name) || + "well-formed".equals(name)) + { + return Boolean.TRUE; + } + else if ("infoset".equals(name)) + { + return (entities == false && + cdataSections == false && + namespaceDeclarations == true && + comments == true) ? Boolean.TRUE : Boolean.FALSE; + } + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, name, null, 0); + } + + public boolean canSetParameter(String name, Object value) + { + name = name.toLowerCase(); + if ("error-handler".equals(name)) + { + return (value == null || value instanceof DOMErrorHandler); + } + else if (contains(name)) + { + return true; + } + else if ("canonical-form".equals(name) || + "check-character-normalization".equals(name) || + "datatype-normalization".equals(name) || + "normalize-characters".equals(name) || + "validate".equals(name) || + "validate-if-schema".equals(name)) + { + return "false".equals(value.toString()); + } + else if ("namespaces".equals(name) || + "well-formed".equals(name)) + { + return "true".equals(value.toString()); + } + return false; + } + + public DOMStringList getParameterNames() + { + return this; + } + + public String item(int i) + { + try + { + return (String) SUPPORTED_PARAMETERS.get(i); + } + catch (IndexOutOfBoundsException e) + { + return null; + } + } + + public int getLength() + { + return SUPPORTED_PARAMETERS.size(); + } + + public boolean contains(String str) + { + str = str.toLowerCase(); + return SUPPORTED_PARAMETERS.contains(str); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDocumentFragment.java b/libjava/classpath/gnu/xml/dom/DomDocumentFragment.java new file mode 100644 index 0000000..8d26037 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentFragment.java @@ -0,0 +1,76 @@ +/* DomDocumentFragment.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import org.w3c.dom.DocumentFragment; + +/** + *
"DocumentFragment" implementation.
+ * + * @author David Brownell + * @author Chris Burdess + */ +public class DomDocumentFragment + extends DomNode + implements DocumentFragment +{ + + /** + * Constructs a DocumentFragment node associated with the + * specified document. + * + *This constructor should only be invoked by a Document as part of + * its createDocumentFragment functionality, or through a subclass which + * is similarly used in a "Sub-DOM" style layer. + */ + protected DomDocumentFragment(DomDocument owner) + { + super(DOCUMENT_FRAGMENT_NODE, owner); + } + + /** + * DOM L1 + * Returns the string "#document-fragment". + */ + final public String getNodeName() + { + return "#document-fragment"; + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomElement.java b/libjava/classpath/gnu/xml/dom/DomElement.java new file mode 100644 index 0000000..34509f6 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomElement.java @@ -0,0 +1,523 @@ +/* DomElement.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import java.util.HashSet; +import java.util.Set; +import javax.xml.XMLConstants; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.TypeInfo; + +/** + *
"Element" implementation. + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomElement + extends DomNsNode + implements Element +{ + + /** + * User-defined ID attributes. + * Used by DomAttr.isId and DomDocument.getElementById + */ + Set userIdAttrs; + + // Attributes are VERY expensive in DOM, and not just for + // this implementation. Avoid creating them. + private DomNamedNodeMap attributes; + + // xml:space cache + String xmlSpace = ""; + + /** + * Constructs an Element node associated with the specified document. + * + *
This constructor should only be invoked by a Document as part + * of its createElement functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + * + * @param owner The document with which this node is associated + * @param namespaceURI Combined with the local part of the name, + * this is used to uniquely identify a type of element + * @param name Name of this element, which may include a prefix + */ + protected DomElement(DomDocument owner, String namespaceURI, String name) + { + super(ELEMENT_NODE, owner, namespaceURI, name); + } + + /** + * DOM L1 + * Returns the element's attributes + */ + public NamedNodeMap getAttributes() + { + if (attributes == null) + { + attributes = new DomNamedNodeMap(this, Node.ATTRIBUTE_NODE); + } + return attributes; + } + + /** + * DOM L2> + * Returns true iff this is an element node with attributes. + */ + public boolean hasAttributes() + { + return attributes != null && attributes.length != 0; + } + + /** + * Shallow clone of the element, except that associated + * attributes are (deep) cloned. + */ + public Object clone() + { + DomElement node = (DomElement) super.clone(); + + if (attributes != null) + { + node.attributes = new DomNamedNodeMap(node, Node.ATTRIBUTE_NODE); + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + node.attributes.setNamedItemNS(ctx.cloneNode(true)); + } + } + return node; + } + + void setOwner(DomDocument doc) + { + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + ctx.setOwner(doc); + } + } + super.setOwner(doc); + } + + /** + * Marks this element, its children, and its associated attributes as + * readonly. + */ + public void makeReadonly() + { + super.makeReadonly(); + if (attributes != null) + { + attributes.makeReadonly(); + } + } + + /** + * DOM L1 + * Returns the element name (same as getNodeName). + */ + final public String getTagName() + { + return getNodeName(); + } + + /** + * DOM L1 + * Returns the value of the specified attribute, or an + * empty string. + */ + public String getAttribute(String name) + { + if ("xml:space" == name) // NB only works on interned string + { + // Use cached value + return xmlSpace; + } + Attr attr = getAttributeNode(name); + return (attr == null) ? "" : attr.getValue(); + } + + /** + * DOM L2 + * Returns true if the element has an attribute with the + * specified name (specified or DTD defaulted). + */ + public boolean hasAttribute(String name) + { + return getAttributeNode(name) != null; + } + + /** + * DOM L2 + * Returns true if the element has an attribute with the + * specified name (specified or DTD defaulted). + */ + public boolean hasAttributeNS(String namespaceURI, String local) + { + return getAttributeNodeNS(namespaceURI, local) != null; + } + + /** + * DOM L2 + * Returns the value of the specified attribute, or an + * empty string. + */ + public String getAttributeNS(String namespaceURI, String local) + { + Attr attr = getAttributeNodeNS(namespaceURI, local); + return (attr == null) ? "" : attr.getValue(); + } + + /** + * DOM L1 + * Returns the appropriate attribute node; the name is the + * nodeName property of the attribute. + */ + public Attr getAttributeNode(String name) + { + return (attributes == null) ? null : + (Attr) attributes.getNamedItem(name); + } + + /** + * DOM L2 + * Returns the appropriate attribute node; the name combines + * the namespace name and the local part. + */ + public Attr getAttributeNodeNS(String namespace, String localPart) + { + return (attributes == null) ? null : + (Attr) attributes.getNamedItemNS(namespace, localPart); + } + + /** + * DOM L1 + * Modifies an existing attribute to have the specified value, + * or creates a new one with that value. The name used is the + * nodeName value. + */ + public void setAttribute(String name, String value) + { + Attr attr = getAttributeNode(name); + if (attr != null) + { + attr.setNodeValue(value); + ((DomAttr) attr).setSpecified(true); + return; + } + attr = owner.createAttribute(name); + attr.setNodeValue(value); + setAttributeNode(attr); + } + + /** + * DOM L2 + * Modifies an existing attribute to have the specified value, + * or creates a new one with that value. + */ + public void setAttributeNS(String uri, String aname, String value) + { + if (("xmlns".equals (aname) || aname.startsWith ("xmlns:")) + && !XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals (uri)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "setting xmlns attribute to illegal value", this, 0); + } + + Attr attr = getAttributeNodeNS(uri, aname); + if (attr != null) + { + attr.setNodeValue(value); + return; + } + attr = owner.createAttributeNS(uri, aname); + attr.setNodeValue(value); + setAttributeNodeNS(attr); + } + + /** + * DOM L1 + * Stores the specified attribute, optionally overwriting any + * existing one with that name. + */ + public Attr setAttributeNode(Attr attr) + { + return (Attr) getAttributes().setNamedItem(attr); + } + + /** + * DOM L2 + * Stores the specified attribute, optionally overwriting any + * existing one with that name. + */ + public Attr setAttributeNodeNS(Attr attr) + { + return (Attr) getAttributes().setNamedItemNS(attr); + } + + /** + * DOM L1 + * Removes the appropriate attribute node. + * If there is no such node, this is (bizarrely enough) a NOP so you + * won't see exceptions if your code deletes non-existent attributes. + * + *
Note that since there is no portable way for DOM to record + * DTD information, default values for attributes will never be + * provided automatically. + */ + public void removeAttribute(String name) + { + if (attributes == null) + { + return; + } + + try + { + attributes.removeNamedItem(name); + } + catch (DomDOMException e) + { + if (e.code != DOMException.NOT_FOUND_ERR) + { + throw e; + } + } + } + + /** + * DOM L1 + * Removes the appropriate attribute node; the name is the + * nodeName property of the attribute. + * + *
Note that since there is no portable way for DOM to record + * DTD information, default values for attributes will never be + * provided automatically. + */ + public Attr removeAttributeNode(Attr node) + { + if (attributes == null) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, null, node, 0); + } + return (Attr) attributes.removeNamedItem(node.getNodeName()); + } + + /** + * DOM L2 + * Removes the appropriate attribute node; the name combines + * the namespace name and the local part. + * + *
Note that since there is no portable way for DOM to record + * DTD information, default values for attributes will never be + * provided automatically. + */ + public void removeAttributeNS(String namespace, String localPart) + { + if (attributes == null) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, localPart, null, 0); + } + attributes.removeNamedItemNS (namespace, localPart); + } + + // DOM Level 3 methods + + public String lookupPrefix(String namespaceURI) + { + if (namespaceURI == null) + { + return null; + } + String namespace = getNamespaceURI(); + if (namespace != null && namespace.equals(namespaceURI)) + { + return getPrefix(); + } + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(ctx.getNamespaceURI())) + { + String value = ctx.getNodeValue(); + if (value.equals(namespaceURI)) + { + return ctx.getLocalName(); + } + } + } + } + return super.lookupPrefix(namespaceURI); + } + + public boolean isDefaultNamespace(String namespaceURI) + { + String namespace = getNamespaceURI(); + if (namespace != null && namespace.equals(namespaceURI)) + { + return getPrefix() == null; + } + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(ctx.getNamespaceURI())) + { + String qName = ctx.getNodeName(); + return (XMLConstants.XMLNS_ATTRIBUTE.equals(qName)); + } + } + } + return super.isDefaultNamespace(namespaceURI); + } + + public String lookupNamespaceURI(String prefix) + { + String namespace = getNamespaceURI(); + if (namespace != null && equal(prefix, getPrefix())) + { + return namespace; + } + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(ctx.getNamespaceURI())) + { + if (prefix == null) + { + if (XMLConstants.XMLNS_ATTRIBUTE.equals(ctx.getNodeName())) + { + return ctx.getNodeValue(); + } + } + else + { + if (prefix.equals(ctx.getLocalName())) + { + return ctx.getNodeValue(); + } + } + } + } + } + return super.lookupNamespaceURI(prefix); + } + + public String getBaseURI() + { + if (attributes != null) + { + Node xmlBase = + attributes.getNamedItemNS(XMLConstants.XML_NS_URI, "base"); + if (xmlBase != null) + { + return xmlBase.getNodeValue(); + } + } + return super.getBaseURI(); + } + + public TypeInfo getSchemaTypeInfo() + { + // DTD implementation + DomDoctype doctype = (DomDoctype) owner.getDoctype(); + if (doctype != null) + { + return doctype.getElementTypeInfo(getNodeName()); + } + // TODO XML Schema implementation + return null; + } + + public void setIdAttribute(String name, boolean isId) + { + NamedNodeMap attrs = getAttributes(); + Attr attr = (Attr) attrs.getNamedItem(name); + setIdAttributeNode(attr, isId); + } + + public void setIdAttributeNode(Attr attr, boolean isId) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + if (attr == null || attr.getOwnerElement() != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + if (isId) + { + if (userIdAttrs == null) + { + userIdAttrs = new HashSet(); + } + userIdAttrs.add(attr); + } + else if (userIdAttrs != null) + { + userIdAttrs.remove(attr); + if (userIdAttrs.isEmpty()) + { + userIdAttrs = null; + } + } + } + + public void setIdAttributeNS(String namespaceURI, String localName, + boolean isId) + { + NamedNodeMap attrs = getAttributes(); + Attr attr = (Attr) attrs.getNamedItemNS(namespaceURI, localName); + setIdAttributeNode(attr, isId); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomEntity.java b/libjava/classpath/gnu/xml/dom/DomEntity.java new file mode 100644 index 0000000..3a76479 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomEntity.java @@ -0,0 +1,147 @@ +/* DomEntity.java -- + Copyright (C) 1999,2000,2004 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 gnu.xml.dom; + +import org.w3c.dom.Entity; + +/** + *
"Entity" implementation. This is a non-core DOM class, supporting the + * "XML" feature. There are two types of entities, neither of which works + * particularly well in this API:
In short, avoid using this DOM functionality. + * + * @see DomDoctype + * @see DomEntityReference + * @see DomNotation + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomEntity + extends DomExtern + implements Entity +{ + + private String notation; + + /** + * Constructs an Entity node associated with the specified document, + * with the specified descriptive data. + * + *
This constructor should only be invoked by a DomDoctype as part + * of its declareEntity functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + * + * @param owner The document with which this entity is associated + * @param name Name of this entity + * @param publicId If non-null, provides the entity's PUBLIC identifier + * @param systemId Provides the entity's SYSTEM identifier (URI) + * @param notation If non-null, provides the unparsed entity's notation. + */ + protected DomEntity(DomDocument owner, + String name, + String publicId, + String systemId, + String notation) + { + super(ENTITY_NODE, owner, name, publicId, systemId); + this.notation = notation; + + // NOTE: if notation == null, this is a parsed entity + // which could reasonably be given child nodes ... + makeReadonly(); + } + + /** + * DOM L1 + * Returns the NOTATION identifier associated with this entity, if any. + */ + final public String getNotationName() + { + return notation; + } + + // DOM Level 3 methods + + public String getInputEncoding() + { + // TODO + return null; + } + + public String getXmlEncoding() + { + // TODO + return null; + } + + public String getXmlVersion() + { + // TODO + return null; + } + + /** + * The base URI of an external entity is its system ID. + * The base URI of an internal entity is the parent document's base URI. + * @since DOM Level 3 Core + */ + public String getBaseURI() + { + String systemId = getSystemId(); + return (systemId == null) ? owner.getBaseURI() : systemId; + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomEntityReference.java b/libjava/classpath/gnu/xml/dom/DomEntityReference.java new file mode 100644 index 0000000..d4596b4 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomEntityReference.java @@ -0,0 +1,130 @@ +/* DomEntityReference.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import org.w3c.dom.DocumentType; +import org.w3c.dom.Entity; +import org.w3c.dom.EntityReference; + +/** + *
"EntityReference" implementation (reference to parsed entity). + * This is a non-core DOM class, supporting the "XML" feature. + * It does not represent builtin entities (such as "&") + * or character references, which are always directly expanded in + * DOM trees.
+ * + *Note that while the DOM specification permits these nodes to have + * a readonly set of children, this is not required. Similarly, it does + * not require a DOM to couple EntityReference nodes with any Entity nodes + * that have the same entity name (and equivalent children). It also + * effectively guarantees that references created directly or indirectly + * through the Document.ImportNode method will not have children. + * The level of functionality you may get is extremely variable. + * + *
Also significant is that even at their most functional level, the fact + * that EntityReference children must be readonly has caused significant + * problems when modifying work products held in DOM trees. Other problems + * include issues related to undeclared namespace prefixes (and references + * to the current default namespace) that may be found in the text of such + * parsed entities nodes. These must be contextually bound as part of DOM + * tree construction. When such nodes are moved, the namespace associated + * with a given prefix (or default) may change to be in conflict with the + * namespace bound to the node at creation time. + * + *
In short, avoid using this DOM functionality. + * + * @see DomDoctype + * @see DomEntity + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomEntityReference + extends DomNode + implements EntityReference +{ + + private String name; + + /** + * Constructs an EntityReference node associated with the specified + * document. The creator should populate this with whatever contents + * are appropriate, and then mark it as readonly. + * + *
This constructor should only be invoked by a Document as part of + * its createEntityReference functionality, or through a subclass which + * is similarly used in a "Sub-DOM" style layer. + * + * @see DomNode#makeReadonly + */ + protected DomEntityReference(DomDocument owner, String name) + { + super(ENTITY_REFERENCE_NODE, owner); + this.name = name; + } + + /** + * Returns the name of the referenced entity. + * @since DOM Level 1 Core + */ + public final String getNodeName() + { + return name; + } + + /** + * The base URI of an entity reference is the base URI where the entity + * declaration occurs. + * @since DOM Level 3 Core + */ + public final String getBaseURI() + { + DocumentType doctype = owner.getDoctype(); + if (doctype == null) + { + return null; + } + Entity entity = (Entity) doctype.getEntities().getNamedItem(name); + if (entity == null) + { + return null; + } + return entity.getBaseURI(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomEvent.java b/libjava/classpath/gnu/xml/dom/DomEvent.java new file mode 100644 index 0000000..d57eac0 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomEvent.java @@ -0,0 +1,345 @@ +/* DomEvent.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.dom; + +import org.w3c.dom.*; +import org.w3c.dom.events.*; +import org.w3c.dom.views.AbstractView; // used by UIEvent + +/** + * "Event" implementation. Events are + * created (through DocumentEvent interface methods on the document object), + * and are sent to any target node in the document. + * + *
Applications may define application specific event subclasses, but + * should otherwise use the DocumentTraversal interface to acquire + * event objects. + * + * @author David Brownell + */ +public class DomEvent + implements Event +{ + + String type; // init + EventTarget target; + EventTarget currentNode; + short eventPhase; + boolean bubbles; // init + boolean cancelable; // init + long timeStamp; // ? + + /** Returns the event's type (name) as initialized */ + public final String getType() + { + return type; + } + + /** + * Returns event's target; delivery of an event is initiated + * by a target.dispatchEvent(event) invocation. + */ + public final EventTarget getTarget() + { + return target; + } + + /** + * Returns the target to which events are currently being + * delivered. When capturing or bubbling, this will not + * be what getTarget returns. + */ + public final EventTarget getCurrentTarget() + { + return currentNode; + } + + /** + * Returns CAPTURING_PHASE, AT_TARGET, or BUBBLING; + * only meaningful within EventListener.handleEvent + */ + public final short getEventPhase() + { + return eventPhase; + } + + /** + * Returns true if the news of the event bubbles to tree tops + * (as specified during initialization). + */ + public final boolean getBubbles() + { + return bubbles; + } + + /** + * Returns true if the default handling may be canceled + * (as specified during initialization). + */ + public final boolean getCancelable() + { + return cancelable; + } + + /** + * Returns the event's timestamp. + */ + public final long getTimeStamp() + { + return timeStamp; + } + + boolean stop; + boolean doDefault; + + /** + * Requests the event no longer be captured or bubbled; only + * listeners on the event target will see the event, if they + * haven't yet been notified. + * + *
Avoid using this except for application-specific + * events, for which you the protocol explicitly "blesses" the use + * of this with some event types. Otherwise, you are likely to break + * algorithms which depend on event notification either directly or + * through bubbling or capturing.
+ * + *Note that this method is not final, specifically to enable + * enforcing of policies about events always propagating.
+ */ + public void stopPropagation() + { + stop = true; + } + + /** + * Requests that whoever dispatched the event not perform their + * default processing when event delivery completes. Initializes + * event timestamp. + */ + public final void preventDefault() + { + doDefault = false; + } + + /** Initializes basic event state. */ + public void initEvent(String typeArg, + boolean canBubbleArg, + boolean cancelableArg) + { + eventPhase = 0; + type = typeArg; + bubbles = canBubbleArg; + cancelable = cancelableArg; + timeStamp = System.currentTimeMillis(); + } + + /** Constructs, but does not initialize, an event. */ + public DomEvent(String type) + { + this.type = type; + } + + /** + * Returns a basic printable description of the event's type, + * state, and delivery conditions + */ + public String toString() + { + StringBuffer buf = new StringBuffer("[Event "); + buf.append(type); + switch (eventPhase) + { + case CAPTURING_PHASE: + buf.append(", CAPTURING"); + break; + case AT_TARGET: + buf.append(", AT TARGET"); + break; + case BUBBLING_PHASE: + buf.append(", BUBBLING"); + break; + default: + buf.append(", (inactive)"); + break; + } + if (bubbles && eventPhase != BUBBLING_PHASE) + { + buf.append(", bubbles"); + } + if (cancelable) + { + buf.append(", can cancel"); + } + // were we to provide subclass info, this's where it'd live + buf.append("]"); + return buf.toString(); + } + + /** + * "MutationEvent" implementation. + */ + public static final class DomMutationEvent + extends DomEvent + implements MutationEvent + { + + // package private + Node relatedNode; // init + + private String prevValue; // init + private String newValue; // init + + private String attrName; // init + private short attrChange; // init + + /** Returns any "related" node provided by this type of event */ + public final Node getRelatedNode() + { + return relatedNode; + } + + /** Returns any "previous value" provided by this type of event */ + public final String getPrevValue() + { + return prevValue; + } + + /** Returns any "new value" provided by this type of event */ + public final String getNewValue() + { + return newValue; + } + + /** For attribute change events, returns the attribute's name */ + public final String getAttrName() + { + return attrName; + } + + /** For attribute change events, returns how the attribuet changed */ + public final short getAttrChange() + { + return attrChange; + } + + /** Initializes a mutation event */ + public final void initMutationEvent(String typeArg, + boolean canBubbleArg, + boolean cancelableArg, + Node relatedNodeArg, + String prevValueArg, + String newValueArg, + String attrNameArg, + short attrChangeArg) + { + // super.initEvent is inlined here for speed + // (mutation events are issued on all DOM changes) + eventPhase = 0; + type = typeArg; + bubbles = canBubbleArg; + cancelable = cancelableArg; + timeStamp = System.currentTimeMillis(); + + relatedNode = relatedNodeArg; + prevValue = prevValueArg; + newValue = newValueArg; + attrName = attrNameArg; + attrChange = attrChangeArg; + } + + // clear everything that should be GC-able + void clear() + { + type = null; + target = null; + relatedNode = null; + currentNode = null; + prevValue = newValue = attrName = null; + } + + /** Constructs an uninitialized mutation event. */ + public DomMutationEvent(String type) + { + super(type); + } + + } + + /** + * "UIEvent" implementation. + */ + public static class DomUIEvent + extends DomEvent + implements UIEvent + { + + private AbstractView view; // init + private int detail; // init + + /** Constructs an uninitialized User Interface (UI) event */ + public DomUIEvent (String type) { super (type); } + + public final AbstractView getView () { return view; } + public final int getDetail () { return detail; } + + /** Initializes a UI event */ + public final void initUIEvent(String typeArg, + boolean canBubbleArg, + boolean cancelableArg, + AbstractView viewArg, + int detailArg) + { + super.initEvent(typeArg, canBubbleArg, cancelableArg); + view = viewArg; + detail = detailArg; + } + + } + + /* + + static final class DomMouseEvent extends DomUIEvent + implements MouseEvent + { + // another half dozen state variables/accessors + } + + */ + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomExtern.java b/libjava/classpath/gnu/xml/dom/DomExtern.java new file mode 100644 index 0000000..87a6909 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomExtern.java @@ -0,0 +1,117 @@ +/* DomExtern.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +/** + *Abstract implemention of nodes describing external DTD-related + * objects. This facilitates reusing code for Entity, Notation, and + * DocumentType (really, external subset) nodes. Such support is not + * part of the core DOM; it's for the "XML" feature.
+ * + *Note that you are strongly advised to avoid using the DOM + * features that take advantage of this class, since (as of L2) none + * of them is defined fully enough to permit full use of the + * XML feature they partially expose.
+ * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomExtern + extends DomNode +{ + + private final String name; + private final String publicId; + private final String systemId; + + /** + * Constructs a node associated with the specified document, + * with the specified descriptive data. + * + * @param owner The document with which this object is associated + * @param name Name of this object + * @param publicId If non-null, provides the entity's PUBLIC identifier + * @param systemId If non-null, provides the entity's SYSTEM identifier + */ + // package private + DomExtern(short nodeType, + DomDocument owner, + String name, + String publicId, + String systemId) + { + super(nodeType, owner); + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + } + + /** + * DOM L1 + * Returns the SYSTEM identifier associated with this object, if any. + */ + public final String getSystemId() + { + return systemId; + } + + /** + * DOM L1 + * Returns the PUBLIC identifier associated with this object, if any. + */ + public final String getPublicId() + { + return publicId; + } + + /** + * DOM L1 + * Returns the object's name. + */ + public final String getNodeName() + { + return name; + } + + public final String getLocalName() + { + return name; + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomImpl.java b/libjava/classpath/gnu/xml/dom/DomImpl.java new file mode 100644 index 0000000..cabe741 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomImpl.java @@ -0,0 +1,278 @@ +/* DomImpl.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Element; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSParser; +import org.w3c.dom.ls.LSSerializer; +import gnu.xml.dom.html2.DomHTMLImpl; +import gnu.xml.dom.ls.DomLSInput; +import gnu.xml.dom.ls.DomLSOutput; +import gnu.xml.dom.ls.DomLSParser; +import gnu.xml.dom.ls.DomLSSerializer; + +/** + *"DOMImplementation" implementation.
+ * + *At this writing, the following features are supported: + * "XML" (L1, L2, L3), + * "Events" (L2), "MutationEvents" (L2), "USER-Events" (a conformant extension), + * "HTMLEvents" (L2), "UIEvents" (L2), "Traversal" (L2), "XPath" (L3), + * "LS" (L3) "LS-Async" (L3). + * It is possible to compile the package so it doesn't support some of these + * features (notably, Traversal). + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomImpl + implements DOMImplementation, DOMImplementationLS +{ + + /** + * Constructs a DOMImplementation object which supports + * "XML" and other DOM Level 2 features. + */ + public DomImpl() + { + } + + /** + * DOM L1 + * Returns true if the specified feature and version are + * supported. Note that the case of the feature name is ignored. + */ + public boolean hasFeature(String name, String version) + { + if (name.length() == 0) + { + return false; + } + name = name.toLowerCase(); + if (name.charAt(0) == '+') + { + name = name.substring(1); + } + + if ("xml".equals(name) || "core".equals(name)) + { + return (version == null || + "".equals(version) || + "1.0".equals(version) || + "2.0".equals(version) || + "3.0".equals(version)); + + } + else if ("ls".equals(name) || "ls-async".equals(name)) + { + return (version == null || + "".equals(version) || + "3.0".equals(version)); + } + else if ("events".equals(name) + || "mutationevents".equals(name) + || "uievents".equals(name) + // || "mouseevents".equals(name) + || "htmlevents".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + + // Extension: "USER-" prefix event types can + // be created and passed through the DOM. + + } + else if ("user-events".equals(name)) + { + return (version == null || + "".equals(version) || + "0.1".equals(version)); + + // NOTE: "hasFeature" for events is here interpreted to + // mean the DOM can manufacture those sorts of events, + // since actually choosing to report the events is more + // often part of the environment or application. It's + // only really an issue for mutation events. + + } + else if (DomNode.reportMutations + && "traversal".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + } + else if ("xpath".equals(name)) + { + return (version == null || + "".equals(version) || + "3.0".equals(version)); + } + else if ("html".equals(name) || "xhtml".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + } + + // views + // stylesheets + // css, css2 + // range + + return false; + } + + /** + * DOM L2 + * Creates and returns a DocumentType, associated with this + * implementation. This DocumentType can have no associated + * objects(notations, entities) until the DocumentType is + * first associated with a document. + * + *
Note that there is no implication that this DTD will + * be parsed by the DOM, or ever have contents. Moreover, the + * DocumentType created here can only be added to a document by + * the createDocument method(below). That means that the only + * portable way to create a Document object is to start parsing, + * queue comment and processing instruction (PI) nodes, and then only + * create a DOM Document after (a) it's known if a DocumentType + * object is needed, and (b) the name and namespace of the root + * element is known. Queued comment and PI nodes would then be + * inserted appropriately in the document prologue, both before and + * after the DTD node, and additional attributes assigned to the + * root element. + *(One hopes that the final DOM REC fixes this serious botch.) + */ + public DocumentType createDocumentType(String rootName, + String publicId, + String systemId) + // CR2 deleted internal subset, ensuring DocumentType + // is 100% useless instead of just 90% so. + { + DomDocument.checkNCName(rootName, false); + return new DomDoctype(this, rootName, publicId, systemId, null); + } + + /** + * DOM L2 + * Creates and returns a Document, populated only with a root element and + * optionally a document type(if that was provided). + */ + public Document createDocument(String namespaceURI, + String rootName, + DocumentType doctype) + { + Document doc = createDocument(); + Element root = null; + + if (rootName != null) + { + root = doc.createElementNS(namespaceURI, rootName); + if (rootName.startsWith("xmlns:")) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns is reserved", null, 0); + } + } + // Bleech -- L2 seemingly _requires_ omission of xmlns attributes. + if (doctype != null) + { + doc.appendChild(doctype); // handles WRONG_DOCUMENT error + } + if (root != null) + { + doc.appendChild(root); + } + return doc; + } + + protected Document createDocument() + { + return new DomDocument(this); + } + + // DOM Level 3 + + public Object getFeature(String feature, String version) + { + if (hasFeature(feature, version)) + { + if ("html".equalsIgnoreCase(feature) || + "xhtml".equalsIgnoreCase(feature)) + { + return new DomHTMLImpl(); + } + return this; + } + return null; + } + + // -- DOMImplementationLS -- + + public LSParser createLSParser(short mode, String schemaType) + throws DOMException + { + return new DomLSParser(mode, schemaType); + } + + public LSSerializer createLSSerializer() + { + return new DomLSSerializer(); + } + + public LSInput createLSInput() + { + return new DomLSInput(); + } + + public LSOutput createLSOutput() + { + return new DomLSOutput(); + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomIterator.java b/libjava/classpath/gnu/xml/dom/DomIterator.java new file mode 100644 index 0000000..472c6e8 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomIterator.java @@ -0,0 +1,373 @@ +/* DomIterator.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.MutationEvent; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +/** + *
"NodeIterator" implementation, usable with any L2 DOM which + * supports MutationEvents.
+ * + * @author David Brownell + */ +public final class DomIterator + implements NodeIterator, EventListener +{ + + private Node reference; + private boolean right; + private boolean done; + + private final Node root; + private final int whatToShow; + private final NodeFilter filter; + private final boolean expandEntityReferences; + + /** + * Constructs and initializes an iterator. + */ + protected DomIterator(Node root, + int whatToShow, + NodeFilter filter, + boolean entityReferenceExpansion) + { + if (!root.isSupported("MutationEvents", "2.0")) + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, + "Iterator needs mutation events", root, 0); + } + + this.root = root; + this.whatToShow = whatToShow; + this.filter = filter; + this.expandEntityReferences = entityReferenceExpansion; + + // start condition: going right, seen nothing yet. + reference = null; + right = true; + + EventTarget target = (EventTarget) root; + target.addEventListener("DOMNodeRemoved", this, false); + } + + /** + * DOM L2 + * Flags the iterator as done, unregistering its event listener so + * that the iterator can be garbage collected without relying on weak + * references (a "Java 2" feature) in the event subsystem. + */ + public void detach() + { + EventTarget target = (EventTarget) root; + target.removeEventListener("DOMNodeRemoved", this, false); + done = true; + } + + /** + * DOM L2 + * Returns the flag controlling whether iteration descends + * through entity references. + */ + public boolean getExpandEntityReferences() + { + return expandEntityReferences; + } + + /** + * DOM L2 + * Returns the filter provided during construction. + */ + public NodeFilter getFilter() + { + return filter; + } + + /** + * DOM L2 + * Returns the root of the tree this is iterating through. + */ + public Node getRoot() + { + return root; + } + + /** + * DOM L2 + * Returns the mask of flags provided during construction. + */ + public int getWhatToShow() + { + return whatToShow; + } + + /** + * DOM L2 + * Returns the next node in a forward iteration, masked and filtered. + * Note that the node may be read-only due to entity expansions. + * A null return indicates the iteration is complete, but may still + * be processed backwards. + */ + public Node nextNode() + { + if (done) + { + throw new DomDOMException(DOMException.INVALID_STATE_ERR); + } + right = true; + return walk(true); + } + + /** + * DOM L2 + * Returns the next node in a backward iteration, masked and filtered. + * Note that the node may be read-only due to entity expansions. + * A null return indicates the iteration is complete, but may still + * be processed forwards. + */ + public Node previousNode() + { + if (done) + { + throw new DomDOMException(DOMException.INVALID_STATE_ERR); + } + Node previous = reference; + right = false; + walk(false); + return previous; + } + + private boolean shouldShow(Node node) + // raises Runtime exceptions indirectly, via acceptNode() + { + if ((whatToShow & (1 << (node.getNodeType() - 1))) == 0) + { + return false; + } + if (filter == null) + { + return true; + } + return filter.acceptNode(node) == NodeFilter.FILTER_ACCEPT; + } + + // + // scenario: root = 1, sequence = 1 2 ... 3 4 + // forward walk: 1 2 ... 3 4 null + // then backward: 4 3 ... 2 1 null + // + // At the leftmost end, "previous" == null + // At the rightmost end, "previous" == 4 + // + // The current draft spec really seem to make no sense re the + // role of the reference node, so what it says is ignored here. + // + private Node walk(boolean forward) + { + Node here = reference; + + while ((here = successor(here, forward)) != null + && !shouldShow(here)) + { + continue; + } + if (here != null || !forward) + { + reference = here; + } + return here; + } + + private boolean isLeaf(Node here) + { + boolean leaf = !here.hasChildNodes(); + if (!leaf && !expandEntityReferences) + { + leaf = (here.getNodeType() == Node.ENTITY_REFERENCE_NODE); + } + return leaf; + } + + // + // Returns the immediate successor in a forward (or backward) + // document order walk, sans filtering ... except that it knows + // how to stop, returning null when done. This is a depth first + // preorder traversal when run in the forward direction. + // + private Node successor(Node here, boolean forward) + { + Node next; + + // the "leftmost" end is funky + if (here == null) + { + return forward ? root : null; + } + + // + // Forward, this is preorder: children before siblings. + // Backward, it's postorder: we saw the children already. + // + if (forward && !isLeaf(here)) + { + return here.getFirstChild(); + } + + // + // Siblings ... if forward, we visit them, if backwards + // we visit their children first. + // + if (forward) + { + if ((next = here.getNextSibling()) != null) + { + return next; + } + } + else if ((next = here.getPreviousSibling()) != null) + { + if (isLeaf(next)) + { + return next; + } + next = next.getLastChild(); + while (!isLeaf(next)) + { + next = next.getLastChild(); + } + return next; + } + + // + // We can't go down or lateral -- it's up, then. The logic is + // the converse of what's above: backwards is easy (the parent + // is next), forwards isn't. + // + next = here.getParentNode(); + if (!forward) + { + return next; + } + + Node temp = null; + while (next != null + && next != root + && (temp = next.getNextSibling()) == null) + { + next = next.getParentNode(); + } + if (next == root) + { + return null; + } + return temp; + } + + /** + * Not for public use. This lets the iterator know when its + * reference node will be removed from the tree, so that a new + * one may be selected. + * + *This version works by watching removal events as they + * bubble up. So, don't prevent them from bubbling. + */ + public void handleEvent(Event e) + { + MutationEvent event; + Node ancestor, removed; + + if (reference == null + || !"DOMNodeRemoved".equals(e.getType()) + || e.getEventPhase() != Event.BUBBLING_PHASE) + { + return; + } + + event = (MutationEvent) e; + removed = (Node) event.getTarget(); + + // See if the removal will cause trouble for this iterator + // by being the reference node or an ancestor of it. + for (ancestor = reference; + ancestor != null && ancestor != root; + ancestor = ancestor.getParentNode()) + { + if (ancestor == removed) + { + break; + } + } + if (ancestor != removed) + { + return; + } + + // OK, it'll cause trouble. We want to make the "next" + // node in our current traversal direction seem right. + // So we pick the nearest node that's not getting removed, + // but go in the _opposite_ direction from our current + // traversal ... so the "next" doesn't skip anything. + Node candidate; + +search: + while ((candidate = walk(!right)) != null) + { + for (ancestor = candidate; + ancestor != null && ancestor != root; + ancestor = ancestor.getParentNode()) + { + if (ancestor == removed) + { + continue search; + } + } + return; + } + + // The current DOM WD talks about a special case here; + // I've not yet seen it. + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomNSResolverContext.java b/libjava/classpath/gnu/xml/dom/DomNSResolverContext.java new file mode 100644 index 0000000..4cf5777 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNSResolverContext.java @@ -0,0 +1,90 @@ +/* DomNSResolverContext.java -- + Copyright (C) 2004 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 gnu.xml.dom; + +import java.util.Iterator; +import javax.xml.namespace.NamespaceContext; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * Namespace content wrapper for an XPathNSResolver. + * + * @author Chris Burdess + */ +class DomNSResolverContext + implements NamespaceContext, Iterator +{ + + final XPathNSResolver resolver; + + DomNSResolverContext(XPathNSResolver resolver) + { + this.resolver = resolver; + } + + public String getNamespaceURI(String prefix) + { + return resolver.lookupNamespaceURI(prefix); + } + + public String getPrefix(String namespaceURI) + { + return null; + } + + public Iterator getPrefixes(String namespaceURI) + { + return this; + } + + public boolean hasNext() + { + return false; + } + + public Object next() + { + return null; + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java b/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java new file mode 100644 index 0000000..6f22402 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java @@ -0,0 +1,421 @@ +/* DomNamedNodeMap.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + *
"NamedNodeMap" implementation.
+ * Used mostly to hold element attributes, but sometimes also + * to list notations or entities. + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomNamedNodeMap + implements NamedNodeMap +{ + + final DomNode owner; + final short type; + + DomNode first; + int length; + boolean readonly; + + // package private + DomNamedNodeMap(DomNode owner, short type) + { + this.owner = owner; + this.type = type; + } + + /** + * Exposes the internal "readonly" flag. In DOM, all NamedNodeMap + * objects found in a DocumentType object are read-only (after + * they are fully constructed), and those holding attributes of + * a readonly element will also be readonly. + */ + public final boolean isReadonly() + { + return readonly; + } + + /** + * Sets the internal "readonly" flag so the node and its + * children can't be changed. + */ + public void makeReadonly() + { + readonly = true; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.makeReadonly(); + } + } + + /** + * DOM L1 + * Returns the named item from the map, or null; names are just + * the nodeName property. + */ + public Node getNamedItem(String name) + { + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + if (ctx.getNodeName().equals(name)) + { + return ctx; + } + } + return null; + } + + /** + * DOM L2 + * Returns the named item from the map, or null; names are the + * localName and namespaceURI properties, ignoring any prefix. + */ + public Node getNamedItemNS(String namespaceURI, String localName) + { + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + String name = ctx.getLocalName(); + if ((localName == null && name == null) || + (localName != null && localName.equals(name))) + { + String uri = ctx.getNamespaceURI(); + if ("".equals(uri)) + { + uri = null; + } + if ((namespaceURI == null && uri == null) || + (namespaceURI != null && namespaceURI.equals(uri))) + { + return ctx; + } + } + } + return null; + } + + /** + * DOM L1 + * Stores the named item into the map, optionally overwriting + * any existing node with that name. The name used is just + * the nodeName attribute. + */ + public Node setNamedItem(Node arg) + { + return setNamedItem(arg, false); + } + + /** + * DOM L2 + * Stores the named item into the map, optionally overwriting + * any existing node with that fully qualified name. The name + * used incorporates the localName and namespaceURI properties, + * and ignores any prefix. + */ + public Node setNamedItemNS(Node arg) + { + return setNamedItem(arg, true); + } + + Node setNamedItem(Node arg, boolean ns) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + + DomNode node = (DomNode) arg; + if (node.owner != owner.owner) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR); + } + if (node.nodeType != type) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR); + } + if (node.nodeType == Node.ATTRIBUTE_NODE) + { + DomNode element = node.parent; + if (element != null && element != owner) + { + throw new DomDOMException(DOMException.INUSE_ATTRIBUTE_ERR); + } + node.parent = owner; + node.depth = owner.depth + 1; + } + + String nodeName = node.getNodeName(); + String localName = ns ? node.getLocalName() : null; + String namespaceURI = ns ? node.getNamespaceURI() : null; + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + + // maybe attribute ADDITION events (?) + DomNode last = null; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + boolean test = false; + if (ns) + { + String tln = ctx.getLocalName(); + if (tln == null) + { + tln = ctx.getNodeName(); + } + if (tln.equals(localName)) + { + String tu = ctx.getNamespaceURI(); + if ((tu == null && namespaceURI == null) || + (tu != null && tu.equals(namespaceURI))) + { + test = true; + } + } + } + else + { + test = ctx.getNodeName().equals(nodeName); + } + if (test) + { + // replace + node.previous = ctx.previous; + node.next = ctx.next; + if (ctx.previous != null) + { + ctx.previous.next = node; + } + if (ctx.next != null) + { + ctx.next.previous = node; + } + if (first == ctx) + { + first = node; + } + reparent(node, nodeName, ctx.index); + ctx.parent = null; + ctx.next = null; + ctx.previous = null; + ctx.setDepth(0); + ctx.index = 0; + return ctx; + } + last = ctx; + } + // append + if (last != null) + { + last.next = node; + node.previous = last; + } + else + { + first = node; + } + length++; + reparent(node, nodeName, 0); + return null; + } + + void reparent(DomNode node, String nodeName, int i) + { + node.parent = owner; + node.setDepth(owner.depth + 1); + // index renumbering + for (DomNode ctx = node; ctx != null; ctx = ctx.next) + { + ctx.index = i++; + } + // cache xml:space + boolean xmlSpace = "xml:space".equals(nodeName); + if (xmlSpace && owner instanceof DomElement) + { + ((DomElement) owner).xmlSpace = node.getNodeValue(); + } + } + + /** + * DOM L1 + * Removes the named item from the map, or reports an exception; + * names are just the nodeName property. + */ + public Node removeNamedItem(String name) + { + return removeNamedItem(null, name, false); + } + + /** + * DOM L2 + * Removes the named item from the map, or reports an exception; + * names are the localName and namespaceURI properties. + */ + public Node removeNamedItemNS(String namespaceURI, String localName) + { + return removeNamedItem(namespaceURI, localName, true); + } + + Node removeNamedItem(String uri, String name, boolean ns) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + + // report attribute REMOVAL event? + + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + boolean test = false; + String nodeName = ctx.getNodeName(); + if (ns) + { + String tln = ctx.getLocalName(); + if (tln.equals(name)) + { + String tu = ctx.getNamespaceURI(); + if ((tu == null && uri == null) || + (tu != null && tu.equals(uri))) + { + test = true; + } + } + } + else + { + test = nodeName.equals(name); + } + if (test) + { + // uncache xml:space + boolean xmlSpace = "xml:space".equals(nodeName); + if (xmlSpace && owner instanceof DomElement) + { + ((DomElement) owner).xmlSpace = ""; + } + // is this a default attribute? + if (ctx.nodeType == Node.ATTRIBUTE_NODE) + { + String def = getDefaultValue(ctx.getNodeName()); + if (def != null) + { + ctx.setNodeValue(def); + ((DomAttr) ctx).setSpecified(false); + return null; + } + } + // remove + if (ctx == first) + { + first = ctx.next; + } + if (ctx.previous != null) + { + ctx.previous.next = ctx.next; + } + if (ctx.next != null) + { + ctx.next.previous = ctx.previous; + } + length--; + ctx.previous = null; + ctx.next = null; + ctx.parent = null; + ctx.setDepth(0); + ctx.index = 0; + return ctx; + } + } + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + + String getDefaultValue(String name) + { + DomDoctype doctype = (DomDoctype) owner.owner.getDoctype(); + if (doctype == null) + { + return null; + } + DTDAttributeTypeInfo info = + doctype.getAttributeTypeInfo(owner.getNodeName(), name); + if (info == null) + { + return null; + } + return info.value; + } + + /** + * DOM L1 + * Returns the indexed item from the map, or null. + */ + public Node item(int index) + { + DomNode ctx = first; + int count = 0; + while (ctx != null && count < index) + { + ctx = ctx.next; + count++; + } + return ctx; + } + + /** + * DOM L1 + * Returns the length of the map. + */ + public int getLength() + { + return length; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNode.java b/libjava/classpath/gnu/xml/dom/DomNode.java new file mode 100644 index 0000000..3f29fb1 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNode.java @@ -0,0 +1,2189 @@ +/* DomNode.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.events.DocumentEvent; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventException; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.MutationEvent; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +/** + *"Node", "EventTarget", and "DocumentEvent" implementation. + * This provides most of the core DOM functionality; only more + * specialized features are provided by subclasses. Those subclasses may + * have some particular constraints they must implement, by overriding + * methods defined here. Such constraints are noted here in the method + * documentation.
+ * + *Note that you can create events with type names prefixed with "USER-", + * and pass them through this DOM. This lets you use the DOM event scheme + * for application specific purposes, although you must use a predefined event + * structure (such as MutationEvent) to pass data along with those events. + * Test for existence of this feature with the "USER-Events" DOM feature + * name.
+ * + *Other kinds of events you can send include the "html" events, + * like "load", "unload", "abort", "error", and "blur"; and the mutation + * events. If this DOM has been compiled with mutation event support + * enabled, it will send mutation events when you change parts of the + * tree; otherwise you may create and send such events yourself, but + * they won't be generated by the DOM itself.
+ * + *Note that there is a namespace-aware name comparison method, + * nameAndTypeEquals, which compares the names (and types) of + * two nodes in conformance with the "Namespaces in XML" specification. + * While mostly intended for use with elements and attributes, this should + * also be helpful for ProcessingInstruction nodes and some others which + * do not have namespace URIs. + * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomNode + implements Node, NodeList, EventTarget, DocumentEvent, Cloneable, Comparable +{ + + // package private + //final static String xmlNamespace = "http://www.w3.org/XML/1998/namespace"; + //final static String xmlnsURI = "http://www.w3.org/2000/xmlns/"; + + // tunable + // NKIDS_* affects arrays of children (which grow) + // (currently) fixed size: + // ANCESTORS_* is for event capture/bubbling, # ancestors + // NOTIFICATIONS_* is for per-node event delivery, # events + private static final int NKIDS_DELTA = 8; + private static final int ANCESTORS_INIT = 20; + private static final int NOTIFICATIONS_INIT = 10; + + // tunable: enable mutation events or not? Enabling it costs about + // 10-15% in DOM construction time, last time it was measured. + + // package private !!! + static final boolean reportMutations = true; + + // locking protocol changeable only within this class + private static final Object lockNode = new Object(); + + // NON-FINAL class data + + // Optimize event dispatch by not allocating memory each time + private static boolean dispatchDataLock; + private static DomNode[] ancestors = new DomNode[ANCESTORS_INIT]; + private static ListenerRecord[] notificationSet + = new ListenerRecord[NOTIFICATIONS_INIT]; + + // Ditto for the (most common) event object itself! + private static boolean eventDataLock; + private static DomEvent.DomMutationEvent mutationEvent + = new DomEvent.DomMutationEvent(null); + + // + // PER-INSTANCE DATA + // + + DomDocument owner; + DomNode parent; // parent node; + DomNode previous; // previous sibling node + DomNode next; // next sibling node + DomNode first; // first child node + DomNode last; // last child node + int index; // index of this node in its parent's children + int depth; // depth of the node in the document + int length; // number of children + final short nodeType; + + // Bleech ... "package private" so a builder can populate entity refs. + // writable during construction. DOM spec is nasty. + boolean readonly; + + // event registrations + private ListenerRecord[] listeners; + private int nListeners; + + // DOM Level 3 userData dictionary. + private HashMap userData; + private HashMap userDataHandlers; + + // + // Some of the methods here are declared 'final' because + // knowledge about their implementation is built into this + // class -- for both integrity and performance. + // + + /** + * Reduces space utilization for this node. + */ + public void compact() + { + if (listeners != null && listeners.length != nListeners) + { + if (nListeners == 0) + { + listeners = null; + } + else + { + ListenerRecord[] l = new ListenerRecord[nListeners]; + System.arraycopy(listeners, 0, l, 0, nListeners); + listeners = l; + } + } + } + + /** + * Constructs a node and associates it with its owner. Only + * Document and DocumentType nodes may be created with no owner, + * and DocumentType nodes get an owner as soon as they are + * associated with a document. + */ + protected DomNode(short nodeType, DomDocument owner) + { + this.nodeType = nodeType; + + if (owner == null) + { + // DOM calls never go down this path + if (nodeType != DOCUMENT_NODE && nodeType != DOCUMENT_TYPE_NODE) + { + throw new IllegalArgumentException ("no owner!"); + } + } + this.owner = owner; + } + + + /** + * DOM L1 + * Returns null; Element subclasses must override this method. + */ + public NamedNodeMap getAttributes() + { + return null; + } + + /** + * DOM L2> + * Returns true iff this is an element node with attributes. + */ + public boolean hasAttributes() + { + return false; + } + + /** + * DOM L1 + * Returns a list, possibly empty, of the children of this node. + * In this implementation, to conserve memory, nodes are the same + * as their list of children. This can have ramifications for + * subclasses, which may need to provide their own getLength method + * for reasons unrelated to the NodeList method of the same name. + */ + public NodeList getChildNodes() + { + return this; + } + + /** + * DOM L1 + * Returns the first child of this node, or null if there are none. + */ + public Node getFirstChild() + { + return first; + } + + /** + * DOM L1 + * Returns the last child of this node, or null if there are none. + */ + public Node getLastChild() + { + return last; + } + + /** + * DOM L1 + * Returns true if this node has children. + */ + public boolean hasChildNodes() + { + return length != 0; + } + + + /** + * Exposes the internal "readonly" flag. In DOM, children of + * entities and entity references are readonly, as are the + * objects associated with DocumentType objets. + */ + public final boolean isReadonly() + { + return readonly; + } + + /** + * Sets the internal "readonly" flag so this subtree can't be changed. + * Subclasses need to override this method for any associated content + * that's not a child node, such as an element's attributes or the + * (few) declarations associated with a DocumentType. + */ + public void makeReadonly() + { + readonly = true; + for (DomNode child = first; child != null; child = child.next) + { + child.makeReadonly(); + } + } + + /** + * Used to adopt a node to a new document. + */ + void setOwner(DomDocument doc) + { + this.owner = doc; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.setOwner(doc); + } + } + + // just checks the node for inclusion -- may be called many + // times (docfrag) before anything is allowed to change + private void checkMisc(DomNode child) + { + if (readonly && !owner.building) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + null, this, 0); + } + for (DomNode ctx = this; ctx != null; ctx = ctx.parent) + { + if (child == ctx) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "can't make ancestor into a child", + this, 0); + } + } + + DomDocument owner = (nodeType == DOCUMENT_NODE) ? (DomDocument) this : + this.owner; + DomDocument childOwner = child.owner; + short childNodeType = child.nodeType; + + if (childOwner != owner) + { + // new in DOM L2, this case -- patch it up later, in reparent() + if (!(childNodeType == DOCUMENT_TYPE_NODE && childOwner == null)) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, child, 0); + } + } + + // enforce various structural constraints + switch (nodeType) + { + case DOCUMENT_NODE: + switch (childNodeType) + { + case ELEMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + case COMMENT_NODE: + case DOCUMENT_TYPE_NODE: + return; + } + break; + + case ATTRIBUTE_NODE: + switch (childNodeType) + { + case TEXT_NODE: + case ENTITY_REFERENCE_NODE: + return; + } + break; + + case DOCUMENT_FRAGMENT_NODE: + case ENTITY_REFERENCE_NODE: + case ELEMENT_NODE: + case ENTITY_NODE: + switch (childNodeType) + { + case ELEMENT_NODE: + case TEXT_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + case CDATA_SECTION_NODE: + case ENTITY_REFERENCE_NODE: + return; + } + break; + } + if (owner.checkingWellformedness) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "can't append " + + nodeTypeToString(childNodeType) + + " to node of type " + + nodeTypeToString(nodeType), + this, 0); + } + } + + // Here's hoping a good optimizer will detect the case when the + // next several methods are never called, and won't allocate + // object code space of any kind. (Case: not reporting any + // mutation events. We can also remove some static variables + // listed above.) + + private void insertionEvent(DomEvent.DomMutationEvent event, + DomNode target) + { + if (owner == null || owner.building) + { + return; + } + boolean doFree = false; + + if (event == null) + { + event = getMutationEvent(); + } + if (event != null) + { + doFree = true; + } + else + { + event = new DomEvent.DomMutationEvent(null); + } + event.initMutationEvent("DOMNodeInserted", + true /* bubbles */, false /* nocancel */, + this /* related */, null, null, null, (short) 0); + target.dispatchEvent(event); + + // XXX should really visit every descendant of 'target' + // and sent a DOMNodeInsertedIntoDocument event to it... + // bleech, there's no way to keep that acceptably fast. + + if (doFree) + { + event.target = null; + event.relatedNode = null; + event.currentNode = null; + eventDataLock = false; + } // else we created work for the GC + } + + private void removalEvent(DomEvent.DomMutationEvent event, + DomNode target) + { + if (owner == null || owner.building) + { + return; + } + boolean doFree = false; + + if (event == null) + { + event = getMutationEvent(); + } + if (event != null) + { + doFree = true; + } + else + { + event = new DomEvent.DomMutationEvent(null); + } + event.initMutationEvent("DOMNodeRemoved", + true /* bubbles */, false /* nocancel */, + this /* related */, null, null, null, (short) 0); + target.dispatchEvent(event); + + // XXX should really visit every descendant of 'target' + // and sent a DOMNodeRemovedFromDocument event to it... + // bleech, there's no way to keep that acceptably fast. + + event.target = null; + event.relatedNode = null; + event.currentNode = null; + if (doFree) + { + eventDataLock = false; + } + // else we created more work for the GC + } + + // + // Avoid creating lots of memory management work, by using a simple + // allocation strategy for the mutation event objects that get used + // at least once per tree modification. We can't use stack allocation, + // so we do the next simplest thing -- more or less, static allocation. + // Concurrent notifications should be rare, anyway. + // + // Returns the preallocated object, which needs to be carefully freed, + // or null to indicate the caller needs to allocate their own. + // + static private DomEvent.DomMutationEvent getMutationEvent() + { + synchronized (lockNode) + { + if (eventDataLock) + { + return null; + } + eventDataLock = true; + return mutationEvent; + } + } + + // NOTE: this is manually inlined in the insertion + // and removal event methods above; change in sync. + static private void freeMutationEvent() + { + // clear fields to enable GC + mutationEvent.clear(); + eventDataLock = false; + } + + void setDepth(int depth) + { + this.depth = depth; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.setDepth(depth + 1); + } + } + + /** + * DOM L1 + * Appends the specified node to this node's list of children. + * Document subclasses must override this to enforce the restrictions + * that there be only one element and document type child. + * + *
Causes a DOMNodeInserted mutation event to be reported. + * Will first cause a DOMNodeRemoved event to be reported if the + * parameter already has a parent. If the new child is a document + * fragment node, both events will be reported for each child of + * the fragment; the order in which children are removed and + * inserted is implementation-specific. + * + *
If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node appendChild(Node newChild) + { + try + { + DomNode child = (DomNode) newChild; + + if (child.nodeType == DOCUMENT_FRAGMENT_NODE) + { + // Append all nodes in the fragment to this node + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + checkMisc(ctx); + } + for (DomNode ctx = child.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + appendChild(ctx); + ctx = ctxNext; + } + } + else + { + checkMisc(child); + if (child.parent != null) + { + child.parent.removeChild(child); + } + child.parent = this; + child.index = length++; + child.setDepth(depth + 1); + child.next = null; + if (last == null) + { + first = child; + child.previous = null; + } + else + { + last.next = child; + child.previous = last; + } + last = child; + + if (reportMutations) + { + insertionEvent(null, child); + } + } + + return child; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, newChild, 0); + } + } + + /** + * DOM L1 + * Inserts the specified node in this node's list of children. + * Document subclasses must override this to enforce the restrictions + * that there be only one element and document type child. + * + *
Causes a DOMNodeInserted mutation event to be reported. Will + * first cause a DOMNodeRemoved event to be reported if the newChild + * parameter already has a parent. If the new child is a document + * fragment node, both events will be reported for each child of + * the fragment; the order in which children are removed and inserted + * is implementation-specific. + * + *
If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node insertBefore(Node newChild, Node refChild) + { + if (refChild == null) + { + return appendChild(newChild); + } + + try + { + DomNode child = (DomNode) newChild; + DomNode ref = (DomNode) refChild; + + if (child.nodeType == DOCUMENT_FRAGMENT_NODE) + { + // Append all nodes in the fragment to this node + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + checkMisc(ctx); + } + for (DomNode ctx = child.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + insertBefore(ctx, ref); + ctx = ctxNext; + } + } + else + { + checkMisc(child); + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + if (ref == child) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "can't insert node before itself", + ref, 0); + } + + if (child.parent != null) + { + child.parent.removeChild(child); + } + child.parent = this; + int i = ref.index; + child.setDepth(depth + 1); + child.next = ref; + if (ref.previous != null) + { + ref.previous.next = child; + } + child.previous = ref.previous; + ref.previous = child; + if (first == ref) + { + first = child; + } + // index renumbering + for (DomNode ctx = child; ctx != null; ctx = ctx.next) + { + ctx.index = i++; + } + + if (reportMutations) + { + insertionEvent(null, child); + } + } + + return child; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, newChild, 0); + } + } + + /** + * DOM L1 + * Replaces the specified node in this node's list of children. + * Document subclasses must override this to test the restrictions + * that there be only one element and document type child. + * + *
Causes DOMNodeRemoved and DOMNodeInserted mutation event to be + * reported. Will cause another DOMNodeRemoved event to be reported if + * the newChild parameter already has a parent. These events may be + * delivered in any order, except that the event reporting removal + * from such an existing parent will always be delivered before the + * event reporting its re-insertion as a child of some other node. + * The order in which children are removed and inserted is implementation + * specific. + * + *
If your application needs to depend on the in which those removal + * and insertion events are delivered, don't use this API. Instead, + * invoke the removeChild and insertBefore methods directly, to guarantee + * a specific delivery order. Similarly, don't use document fragments, + * Otherwise your application code may not work on a DOM which implements + * this method differently. + * + *
If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node replaceChild(Node newChild, Node refChild) + { + try + { + DomNode child = (DomNode) newChild; + DomNode ref = (DomNode) refChild; + + DomEvent.DomMutationEvent event = getMutationEvent(); + boolean doFree = (event != null); + + if (child.nodeType == DOCUMENT_FRAGMENT_NODE) + { + // Append all nodes in the fragment to this node + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + checkMisc(ctx); + } + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + + if (reportMutations) + { + removalEvent(event, ref); + } + length--; + length += child.length; + + if (child.length == 0) + { + // Removal + if (ref.previous != null) + { + ref.previous.next = ref.next; + } + if (ref.next != null) + { + ref.next.previous = ref.previous; + } + if (first == ref) + { + first = ref.next; + } + if (last == ref) + { + last = ref.previous; + } + } + else + { + int i = ref.index; + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + // Insertion + ctx.parent = this; + ctx.index = i++; + ctx.setDepth(ref.depth); + if (ctx == child.first) + { + ctx.previous = ref.previous; + } + if (ctx == child.last) + { + ctx.next = ref.next; + } + } + if (first == ref) + { + first = child.first; + } + if (last == ref) + { + last = child.last; + } + } + } + else + { + checkMisc(child); + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + + if (reportMutations) + { + removalEvent(event, ref); + } + + if (child.parent != null) + { + child.parent.removeChild(child); + } + child.parent = this; + child.index = ref.index; + child.setDepth(ref.depth); + if (ref.previous != null) + { + ref.previous.next = child; + } + child.previous = ref.previous; + if (ref.next != null) + { + ref.next.previous = child; + } + child.next = ref.next; + if (first == ref) + { + first = child; + } + if (last == ref) + { + last = child; + } + + if (reportMutations) + { + insertionEvent(event, child); + } + if (doFree) + { + freeMutationEvent(); + } + } + ref.parent = null; + ref.index = 0; + ref.setDepth(0); + ref.previous = null; + ref.next = null; + + return ref; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, newChild, 0); + } + } + + /** + * DOM L1 + * Removes the specified child from this node's list of children, + * or else reports an exception. + * + *
Causes a DOMNodeRemoved mutation event to be reported. + * + *
If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node removeChild(Node refChild) + { + try + { + DomNode ref = (DomNode) refChild; + + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + if (readonly && !owner.building) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + null, this, 0); + } + + for (DomNode child = first; child != null; child = child.next) + { + if (child == ref) + { + if (reportMutations) + { + removalEvent(null, child); + } + + length--; + if (ref.previous != null) + { + ref.previous.next = ref.next; + } + if (ref.next != null) + { + ref.next.previous = ref.previous; + } + if (first == ref) + { + first = ref.next; + } + if (last == ref) + { + last = ref.previous; + } + // renumber indices + int i = 0; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.index = i++; + } + ref.parent = null; + ref.setDepth(0); + ref.index = 0; + ref.previous = null; + ref.next = null; + + return ref; + } + } + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + "that's no child of mine", refChild, 0); + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, refChild, 0); + } + } + + /** + * DOM L1 (NodeList) + * Returns the item with the specified index in this NodeList, + * else null. + */ + public Node item(int index) + { + DomNode child = first; + int count = 0; + while (child != null && count < index) + { + child = child.next; + count++; + } + return child; + } + + /** + * DOM L1 (NodeList) + * Returns the number of elements in this NodeList. + * (Note that many interfaces have a "Length" property, not just + * NodeList, and if a node subtype must implement one of those, + * it will also need to override getChildNodes.) + */ + public int getLength() + { + return length; + } + + /** + * Minimize extra space consumed by this node to hold children and event + * listeners. + */ + public void trimToSize() + { + if (listeners != null && listeners.length != nListeners) + { + ListenerRecord[] newKids = new ListenerRecord[length]; + System.arraycopy(listeners, 0, newKids, 0, nListeners); + listeners = newKids; + } + } + + /** + * DOM L1 + * Returns the previous sibling, if one is known. + */ + public Node getNextSibling() + { + return next; + } + + /** + * DOM L1 + * Returns the previous sibling, if one is known. + */ + public Node getPreviousSibling() + { + return previous; + } + + /** + * DOM L1 + * Returns the parent node, if one is known. + */ + public Node getParentNode() + { + return parent; + } + + /** + * DOM L2 + * Consults the DOM implementation to determine if the requested + * feature is supported. DocumentType subclasses must override + * this method, and associate themselves directly with the + * DOMImplementation node used. (This method relies on being able + * to access the DOMImplementation from the owner document, but + * DocumentType nodes can be created without an owner.) + */ + public boolean isSupported(String feature, String version) + { + Document doc = owner; + DOMImplementation impl = null; + + if (doc == null && nodeType == DOCUMENT_NODE) + { + doc = (Document) this; + } + + if (doc == null) + { + // possible for DocumentType + throw new IllegalStateException ("unbound ownerDocument"); + } + + impl = doc.getImplementation(); + return impl.hasFeature(feature, version); + } + + /** + * DOM L1 (modified in L2) + * Returns the owner document. This is only null for Document nodes, + * and (new in L2) for DocumentType nodes which have not yet been + * associated with the rest of their document. + */ + final public Document getOwnerDocument() + { + return owner; + } + + /** + * DOM L1 + * Does nothing; this must be overridden (along with the + * getNodeValue method) for nodes with a non-null defined value. + */ + public void setNodeValue(String value) + { + } + + /** + * DOM L1 + * Returns null; this must be overridden for nodes types with + * a defined value, along with the setNodeValue method. + */ + public String getNodeValue() + { + return null; + } + + /** This forces GCJ compatibility. + * Without this method GCJ is unable to compile to byte code. + */ + public final short getNodeType() + { + return nodeType; + } + + /** This forces GCJ compatibility. + * Without this method GCJ seems unable to natively compile GNUJAXP. + */ + public abstract String getNodeName(); + + /** + * DOM L2 + * Does nothing; this must be overridden (along with the + * getPrefix method) for element and attribute nodes. + */ + public void setPrefix(String prefix) + { + } + + /** + * DOM L2 + * Returns null; this must be overridden for element and + * attribute nodes. + */ + public String getPrefix() + { + return null; + } + + /** + * DOM L2 + * Returns null; this must be overridden for element and + * attribute nodes. + */ + public String getNamespaceURI() + { + return null; + } + + /** + * DOM L2 + * Returns the node name; this must be overridden for element and + * attribute nodes. + */ + public String getLocalName() + { + return null; + } + + /** + * DOM L1 + * Returns a clone of this node which optionally includes cloned + * versions of child nodes. Clones are always mutable, except for + * entity reference nodes. + */ + public Node cloneNode(boolean deep) + { + DomNode node = (DomNode) clone(); + + if (deep) + { + DomDocument doc = (nodeType == DOCUMENT_NODE) ? + (DomDocument) node : node.owner; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + DomNode newChild = (DomNode) ctx.cloneNode(deep); + newChild.setOwner(doc); + node.appendChild(newChild); + } + } + + if (nodeType == ENTITY_REFERENCE_NODE) + { + node.makeReadonly(); + } + notifyUserDataHandlers(UserDataHandler.NODE_CLONED, this, node); + return node; + } + + void notifyUserDataHandlers(short op, Node src, Node dst) + { + if (userDataHandlers != null) + { + for (Iterator i = userDataHandlers.entrySet().iterator(); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String key = (String) entry.getKey(); + UserDataHandler handler = (UserDataHandler) entry.getValue(); + Object data = userData.get(key); + handler.handle(op, key, data, src, dst); + } + } + } + + /** + * Clones this node; roughly equivalent to cloneNode(false). + * Element subclasses must provide a new implementation which + * invokes this method to handle the basics, and then arranges + * to clone any element attributes directly. Attribute subclasses + * must make similar arrangements, ensuring that existing ties to + * elements are broken by cloning. + */ + public Object clone() + { + try + { + DomNode node = (DomNode) super.clone(); + + node.parent = null; + node.depth = 0; + node.index = 0; + node.length = 0; + node.first = null; + node.last = null; + node.previous = null; + node.next = null; + + node.readonly = false; + node.listeners = null; + node.nListeners = 0; + return node; + + } + catch (CloneNotSupportedException x) + { + throw new Error("clone didn't work"); + } + } + + // the elements-by-tagname stuff is needed for both + // elements and documents ... this is in lieu of a + // common base class between Node and NodeNS. + + /** + * DOM L1 + * Creates a NodeList giving array-style access to elements with + * the specified name. Access is fastest if indices change by + * small values, and the DOM is not modified. + */ + public NodeList getElementsByTagName(String tag) + { + return new ShadowList(null, tag); + } + + /** + * DOM L2 + * Creates a NodeList giving array-style access to elements with + * the specified namespace and local name. Access is fastest if + * indices change by small values, and the DOM is not modified. + */ + public NodeList getElementsByTagNameNS(String namespace, String local) + { + return new ShadowList(namespace, local); + } + + + // + // This shadow class is GC-able even when the live list it shadows + // can't be, because of event registration hookups. Its finalizer + // makes that live list become GC-able. + // + final class ShadowList + implements NodeList + { + + private LiveNodeList liveList; + + ShadowList(String ns, String local) + { + liveList = new LiveNodeList(ns, local); + } + + public void finalize() + { + liveList.detach(); + liveList = null; + } + + public Node item(int index) + { + return liveList.item(index); + } + + public int getLength() + { + return liveList.getLength(); + } + } + + final class LiveNodeList + implements NodeList, EventListener, NodeFilter + { + + private final boolean matchAnyURI; + private final boolean matchAnyName; + private final String elementURI; + private final String elementName; + + private DomIterator current; + private int lastIndex; + + LiveNodeList(String uri, String name) + { + elementURI = uri; + elementName = name; + matchAnyURI = "*".equals(uri); + matchAnyName = "*".equals(name); + + DomNode.this.addEventListener("DOMNodeInserted", this, true); + DomNode.this.addEventListener("DOMNodeRemoved", this, true); + } + + void detach() + { + current.detach(); + current = null; + + DomNode.this.removeEventListener("DOMNodeInserted", this, true); + DomNode.this.removeEventListener("DOMNodeRemoved", this, true); + } + + public short acceptNode(Node element) + { + if (element == DomNode.this) + { + return FILTER_SKIP; + } + + // use namespace-aware matching ... + if (elementURI != null) + { + if (!(matchAnyURI + || elementURI.equals(element.getNamespaceURI()))) + { + return FILTER_SKIP; + } + if (!(matchAnyName + || elementName.equals(element.getLocalName()))) + { + return FILTER_SKIP; + } + + // ... or qName-based kind. + } + else + { + if (!(matchAnyName + || elementName.equals(element.getNodeName()))) + { + return FILTER_SKIP; + } + } + return FILTER_ACCEPT; + } + + private DomIterator createIterator() + { + return new DomIterator(DomNode.this, + NodeFilter.SHOW_ELEMENT, + this, /* filter */ + true /* expand entity refs */ + ); + } + + public void handleEvent(Event e) + { + MutationEvent mutation = (MutationEvent) e; + Node related = mutation.getRelatedNode(); + + // XXX if it's got children ... check all kids too, they + // will invalidate our saved index + + if (related.getNodeType() != Node.ELEMENT_NODE || + related.getNodeName() != elementName || + related.getNamespaceURI() != elementURI) + { + return; + } + + current = null; + } + + public Node item(int index) + { + if (current == null) + { + current = createIterator(); + lastIndex = -1; + } + + // last node or before? go backwards + if (index <= lastIndex) { + while (index != lastIndex) { + current.previousNode (); + lastIndex--; + } + Node ret = current.previousNode (); + current = null; + return ret; + } + + // somewhere after last node + while (++lastIndex != index) + current.nextNode (); + Node ret = current.nextNode (); + current = null; + return ret; + } + + public int getLength() + { + int retval = 0; + NodeIterator iter = createIterator(); + + while (iter.nextNode() != null) + { + retval++; + } + current = null; + return retval; + } + + } + + // + // EventTarget support + // + static final class ListenerRecord + { + + String type; + EventListener listener; + boolean useCapture; + + // XXX use JDK 1.2 java.lang.ref.WeakReference to listener, + // and we can both get rid of "shadow" classes and remove + // the need for applications to apply similar trix ... but + // JDK 1.2 support isn't generally available yet + + ListenerRecord(String type, EventListener listener, boolean useCapture) + { + this.type = type.intern(); + this.listener = listener; + this.useCapture = useCapture; + } + + boolean equals(ListenerRecord rec) + { + return listener == rec.listener + && useCapture == rec.useCapture + && type == rec.type; + } + + } + + /** + * DOM L2 (Events) + * Returns an instance of the specified type of event object. + * Understands about DOM Mutation, HTML, and UI events. + * + *
If the name of the event type begins with "USER-", then an object + * implementing the "Event" class will be returned; this provides a + * limited facility for application-defined events to use the DOM event + * infrastructure. Alternatively, use one of the standard DOM event + * classes and initialize it using use such a "USER-" event type name; + * or defin, instantiate, and initialize an application-specific subclass + * of DomEvent and pass that to dispatchEvent(). + * + * @param eventType Identifies the particular DOM feature module + * defining the type of event, such as "MutationEvents". + * The event "name" is a different kind of "type". + */ + public Event createEvent(String eventType) + { + eventType = eventType.toLowerCase(); + + if ("mutationevents".equals(eventType)) + { + return new DomEvent.DomMutationEvent(null); + } + + if ("htmlevents".equals(eventType) + || "events".equals(eventType) + || "user-events".equals(eventType)) + { + return new DomEvent(null); + } + + if ("uievents".equals(eventType)) + { + return new DomEvent.DomUIEvent(null); + } + + // mouse events + + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, + eventType, null, 0); + } + + /** + * DOM L2 (Events) + * Registers an event listener's interest in a class of events. + */ + public final void addEventListener(String type, + EventListener listener, + boolean useCapture) + { + if (listeners == null) + { + listeners = new ListenerRecord[1]; + } + else if (nListeners == listeners.length) + { + ListenerRecord[] newListeners = + new ListenerRecord[listeners.length + NKIDS_DELTA]; + System.arraycopy(listeners, 0, newListeners, 0, nListeners); + listeners = newListeners; + } + + // prune duplicates + ListenerRecord record; + + record = new ListenerRecord(type, listener, useCapture); + for (int i = 0; i < nListeners; i++) + { + if (record.equals(listeners[i])) + { + return; + } + } + listeners [nListeners++] = record; + } + + // XXX this exception should be discarded from DOM + + // this class can be instantiated, unlike the one in the spec + static final class DomEventException + extends EventException + { + + DomEventException() + { + super(UNSPECIFIED_EVENT_TYPE_ERR, "unspecified event type"); + } + + } + + /** + * DOM L2 (Events) + * Delivers an event to all relevant listeners, returning true if the + * caller should perform their default action. Note that the event + * must have been provided by the createEvent() method on this + * class, else it can't be dispatched. + * + * @see #createEvent + * + * @exception NullPointerException When a null event is passed. + * @exception ClassCastException When the event wasn't provided by + * the createEvent method, or otherwise isn't a DomEvent. + * @exception EventException If the event type wasn't specified + */ + public final boolean dispatchEvent(Event event) + throws EventException + { + DomEvent e = (DomEvent) event; + DomNode[] ancestors = null; + int ancestorMax = 0; + boolean haveDispatchDataLock = false; + + if (e.type == null) + { + throw new DomEventException(); + } + + e.doDefault = true; + e.target = this; + + // + // Typical case: one nonrecursive dispatchEvent call at a time + // for this class. If that's our case, we can avoid allocating + // garbage, which is overall a big win. Even with advanced GCs + // that deal well with short-lived garbage, and wayfast allocators, + // it still helps. + // + // Remember -- EVERY mutation goes though here at least once. + // + // When populating a DOM tree, trying to send mutation events is + // the primary cost; this dominates the critical path. + // + try + { + DomNode current; + int index; + boolean haveAncestorRegistrations = false; + ListenerRecord[] notificationSet; + int ancestorLen; + + synchronized (lockNode) + { + if (!dispatchDataLock) + { + haveDispatchDataLock = dispatchDataLock = true; + notificationSet = DomNode.notificationSet; + ancestors = DomNode.ancestors; + } + else + { + notificationSet = new ListenerRecord[NOTIFICATIONS_INIT]; + ancestors = new DomNode[ANCESTORS_INIT]; + } + ancestorLen = ancestors.length; + } + + // XXX autogrow ancestors ... based on statistics + + // Climb to the top of this subtree and handle capture, letting + // each node (from the top down) capture until one stops it or + // until we get to this one. + + for (index = 0, current = parent; + current != null && index < ancestorLen; + index++, current = current.parent) + { + if (current.nListeners != 0) + { + haveAncestorRegistrations = true; + } + ancestors [index] = current; + } + if (current != null) + { + throw new RuntimeException("dispatchEvent capture stack size"); + } + + ancestorMax = index; + e.stop = false; + + if (haveAncestorRegistrations) + { + e.eventPhase = Event.CAPTURING_PHASE; + while (!e.stop && index-- > 0) + { + current = ancestors [index]; + if (current.nListeners != 0) + { + notifyNode(e, current, true, notificationSet); + } + } + } + + // Always deliver events to the target node (this) + // unless stopPropagation was called. If we saw + // no registrations yet (typical!), we never will. + if (!e.stop && nListeners != 0) + { + e.eventPhase = Event.AT_TARGET; + notifyNode (e, this, false, notificationSet); + } + else if (!haveAncestorRegistrations) + { + e.stop = true; + } + + // If the event bubbles and propagation wasn't halted, + // walk back up the ancestor list. Stop bubbling when + // any bubbled event handler stops it. + + if (!e.stop && e.bubbles) + { + e.eventPhase = Event.BUBBLING_PHASE; + for (index = 0; + !e.stop + && index < ancestorMax + && (current = ancestors[index]) != null; + index++) + { + if (current.nListeners != 0) + { + notifyNode(e, current, false, notificationSet); + } + } + } + e.eventPhase = 0; + + // Caller chooses whether to perform the default + // action based on return from this method. + return e.doDefault; + + } + finally + { + if (haveDispatchDataLock) + { + // synchronize to force write ordering + synchronized (lockNode) + { + // null out refs to ensure they'll be GC'd + for (int i = 0; i < ancestorMax; i++) + { + ancestors [i] = null; + } + // notificationSet handled by notifyNode + + dispatchDataLock = false; + } + } + } + } + + private void notifyNode(DomEvent e, + DomNode current, + boolean capture, + ListenerRecord[] notificationSet) + { + int count = 0; + + // do any of this set of listeners get notified? + for (int i = 0; i < current.nListeners; i++) + { + ListenerRecord rec = current.listeners[i]; + + if (rec.useCapture != capture) + { + continue; + } + if (!e.type.equals (rec.type)) + { + continue; + } + if (count >= notificationSet.length) + { + // very simple growth algorithm + int len = Math.max(notificationSet.length, 1); + ListenerRecord[] tmp = new ListenerRecord[len * 2]; + System.arraycopy(notificationSet, 0, tmp, 0, + notificationSet.length); + notificationSet = tmp; + } + notificationSet[count++] = rec; + } + + // Notify just those listeners + e.currentNode = current; + for (int i = 0; i < count; i++) + { + try + { + // Late in the DOM CR process (3rd or 4th CR?) the + // removeEventListener spec became asymmetric with respect + // to addEventListener ... effect is now immediate. + for (int j = 0; j < current.nListeners; j++) + { + if (current.listeners[j].equals(notificationSet[i])) + { + notificationSet[i].listener.handleEvent(e); + break; + } + } + + } + catch (Exception x) + { + // ignore all exceptions + } + notificationSet[i] = null; // free for GC + } + } + + /** + * DOM L2 (Events) + * Unregisters an event listener. + */ + public final void removeEventListener(String type, + EventListener listener, + boolean useCapture) + { + for (int i = 0; i < nListeners; i++) + { + if (listeners[i].listener != listener) + { + continue; + } + if (listeners[i].useCapture != useCapture) + { + continue; + } + if (!listeners[i].type.equals(type)) + { + continue; + } + + if (nListeners == 1) + { + listeners = null; + nListeners = 0; + } + else + { + for (int j = i + 1; j < nListeners; j++) + { + listeners[i++] = listeners[j++]; + } + listeners[--nListeners] = null; + } + break; + } + // no exceptions reported + } + + /** + * DOM L1 (relocated in DOM L2) + * In this node and all contained nodes (including attributes if + * relevant) merge adjacent text nodes. This is done while ignoring + * text which happens to use CDATA delimiters). + */ + public final void normalize() + { + // Suspend readonly status + boolean saved = readonly; + readonly = false; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + switch (ctx.nodeType) + { + case TEXT_NODE: + while (ctx.next != null && ctx.next.nodeType == TEXT_NODE) + { + Text text = (Text) ctx; + text.appendData(ctx.next.getNodeValue()); + removeChild(ctx.next); + } + break; + case ELEMENT_NODE: + NamedNodeMap attrs = ctx.getAttributes(); + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + attrs.item(i).normalize(); + } + // Fall through + case DOCUMENT_NODE: + case DOCUMENT_FRAGMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_REFERENCE_NODE: + ctx.normalize(); + break; + } + } + readonly = saved; + } + + /** + * Returns true iff node types match, and either (a) both nodes have no + * namespace and their getNodeName() values are the same, or (b) both + * nodes have the same getNamespaceURI() and same getLocalName() values. + * + *
Note that notion of a "Per-Element-Type" attribute name scope, as + * found in a non-normative appendix of the XML Namespaces specification, + * is not supported here. Your application must implement that notion, + * typically by not bothering to check nameAndTypeEquals for attributes + * without namespace URIs unless you already know their elements are + * nameAndTypeEquals. + */ + public boolean nameAndTypeEquals(Node other) + { + if (other == this) + { + return true; + } + // node types must match + if (nodeType != other.getNodeType()) + { + return false; + } + + // if both have namespaces, do a "full" comparision + // this is a "global" partition + String ns1 = this.getNamespaceURI(); + String ns2 = other.getNamespaceURI(); + + if (ns1 != null && ns2 != null) + { + return ns1.equals(ns2) && + equal(getLocalName(), other.getLocalName()); + } + + // if neither has a namespace, this is a "no-namespace" name. + if (ns1 == null && ns2 == null) + { + if (!getNodeName().equals(other.getNodeName())) + { + return false; + } + // can test the non-normative "per-element-type" scope here. + // if this is an attribute node and both nodes have been bound + // to elements (!!), then return the nameAndTypeEquals() + // comparison of those elements. + return true; + } + + // otherwise they're unequal: one scoped, one not. + return false; + } + + // DOM Level 3 methods + + public String getBaseURI() + { + return (parent != null) ? parent.getBaseURI() : null; + } + + public short compareDocumentPosition(Node other) + throws DOMException + { + return (short) compareTo(other); + } + + /** + * DOM nodes have a natural ordering: document order. + */ + public final int compareTo(Object other) + { + if (other instanceof DomNode) + { + DomNode n1 = this; + DomNode n2 = (DomNode) other; + if (n1.owner != n2.owner) + { + return 0; + } + int d1 = n1.depth, d2 = n2.depth; + int delta = d1 - d2; + while (d1 > d2) + { + n1 = n1.parent; + d1--; + } + while (d2 > d1) + { + n2 = n2.parent; + d2--; + } + int c = compareTo2(n1, n2); + return (c != 0) ? c : delta; + } + return 0; + } + + /** + * Compare two nodes at the same depth. + */ + final int compareTo2(DomNode n1, DomNode n2) + { + if (n1 == n2 || n1.depth == 0 || n2.depth == 0) + { + return 0; + } + int c = compareTo2(n1.parent, n2.parent); + return (c != 0) ? c : n1.index - n2.index; + } + + public final String getTextContent() + throws DOMException + { + return getTextContent(true); + } + + final String getTextContent(boolean topLevel) + throws DOMException + { + switch (nodeType) + { + case ELEMENT_NODE: + case ENTITY_NODE: + case ENTITY_REFERENCE_NODE: + case DOCUMENT_FRAGMENT_NODE: + StringBuffer buffer = new StringBuffer(); + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + String textContent = ctx.getTextContent(false); + if (textContent != null) + { + buffer.append(textContent); + } + } + return buffer.toString(); + case TEXT_NODE: + case CDATA_SECTION_NODE: + if (((Text) this).isElementContentWhitespace()) + { + return ""; + } + return getNodeValue(); + case ATTRIBUTE_NODE: + return getNodeValue(); + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + return topLevel ? getNodeValue() : ""; + default: + return null; + } + } + + public void setTextContent(String textContent) + throws DOMException + { + switch (nodeType) + { + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_NODE: + case ENTITY_REFERENCE_NODE: + case DOCUMENT_FRAGMENT_NODE: + for (DomNode ctx = first; ctx != null; ) + { + DomNode n = ctx.next; + removeChild(ctx); + ctx = n; + } + if (textContent != null) + { + Text text = owner.createTextNode(textContent); + appendChild(text); + } + break; + case TEXT_NODE: + case CDATA_SECTION_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + setNodeValue(textContent); + break; + } + } + + public boolean isSameNode(Node other) + { + return this == other; + } + + public String lookupPrefix(String namespaceURI) + { + return (parent == null || parent == owner) ? null : + parent.lookupPrefix(namespaceURI); + } + + public boolean isDefaultNamespace(String namespaceURI) + { + return (parent == null || parent == owner) ? false : + parent.isDefaultNamespace(namespaceURI); + } + + public String lookupNamespaceURI(String prefix) + { + return (parent == null || parent == owner) ? null : + parent.lookupNamespaceURI(prefix); + } + + public boolean isEqualNode(Node arg) + { + if (this == arg) + { + return true; + } + if (arg == null) + { + return false; + } + if (nodeType != arg.getNodeType() || + !equal(getNodeName(), arg.getNodeName()) || + !equal(getLocalName(), arg.getLocalName()) || + !equal(getNamespaceURI(), arg.getNamespaceURI()) || + !equal(getPrefix(), arg.getPrefix()) || + !equal(getNodeValue(), arg.getNodeValue())) + { + return false; + } + // Children + Node argCtx = arg.getFirstChild(); + getFirstChild(); // because of DomAttr lazy children + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + if (!ctx.isEqualNode(argCtx)) + { + return false; + } + argCtx = argCtx.getNextSibling(); + } + if (argCtx != null) + { + return false; + } + + // TODO Attr NamedNodeMap + // TODO DocumentType + return true; + } + + boolean equal(String arg1, String arg2) + { + return ((arg1 == null && arg2 == null) || + (arg1 != null && arg1.equals(arg2))); + } + + public Object getFeature(String feature, String version) + { + DOMImplementation impl = (nodeType == DOCUMENT_NODE) ? + ((Document) this).getImplementation() : owner.getImplementation(); + if (impl.hasFeature(feature, version)) + { + return this; + } + return null; + } + + public Object setUserData(String key, Object data, UserDataHandler handler) + { + if (userData == null) + { + userData = new HashMap(); + } + if (handler != null) + { + if (userDataHandlers == null) + { + userDataHandlers = new HashMap(); + } + userDataHandlers.put(key, handler); + } + return userData.put(key, data); + } + + public Object getUserData(String key) + { + if (userData == null) + { + return null; + } + return userData.get(key); + } + + public String toString() + { + String nodeName = getNodeName(); + String nodeValue = getNodeValue(); + StringBuffer buf = new StringBuffer(getClass().getName()); + buf.append('['); + if (nodeName != null) + { + buf.append(nodeName); + } + if (nodeValue != null) + { + if (nodeName != null) + { + buf.append('='); + } + buf.append('\''); + buf.append(encode(nodeValue)); + buf.append('\''); + } + buf.append(']'); + return buf.toString(); + } + + String encode(String value) + { + StringBuffer buf = null; + int len = value.length(); + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '\n') + { + if (buf == null) + { + buf = new StringBuffer(value.substring(0, i)); + } + buf.append("\\n"); + } + else if (c == '\r') + { + if (buf == null) + { + buf = new StringBuffer(value.substring(0, i)); + } + buf.append("\\r"); + } + else if (buf != null) + { + buf.append(c); + } + } + return (buf != null) ? buf.toString() : value; + } + + String nodeTypeToString(short nodeType) + { + switch (nodeType) + { + case ELEMENT_NODE: + return "ELEMENT_NODE"; + case ATTRIBUTE_NODE: + return "ATTRIBUTE_NODE"; + case TEXT_NODE: + return "TEXT_NODE"; + case CDATA_SECTION_NODE: + return "CDATA_SECTION_NODE"; + case DOCUMENT_NODE: + return "DOCUMENT_NODE"; + case DOCUMENT_TYPE_NODE: + return "DOCUMENT_TYPE_NODE"; + case COMMENT_NODE: + return "COMMENT_NODE"; + case PROCESSING_INSTRUCTION_NODE: + return "PROCESSING_INSTRUCTION_NODE"; + case DOCUMENT_FRAGMENT_NODE: + return "DOCUMENT_FRAGMENT_NODE"; + case ENTITY_NODE: + return "ENTITY_NODE"; + case ENTITY_REFERENCE_NODE: + return "ENTITY_REFERENCE_NODE"; + case NOTATION_NODE: + return "NOTATION_NODE"; + default: + return "UNKNOWN"; + } + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomNodeIterator.java b/libjava/classpath/gnu/xml/dom/DomNodeIterator.java new file mode 100644 index 0000000..6079f7a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNodeIterator.java @@ -0,0 +1,327 @@ +/* DomNodeIterator.java -- + Copyright (C) 2004 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 gnu.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; +import org.w3c.dom.traversal.TreeWalker; + +/** + * Node iterator and tree walker. + * + * @author Chris Burdess + */ +public class DomNodeIterator + implements NodeIterator, TreeWalker +{ + + Node root; + final int whatToShow; + final NodeFilter filter; + final boolean entityReferenceExpansion; + final boolean walk; + Node current; + + public DomNodeIterator(Node root, int whatToShow, NodeFilter filter, + boolean entityReferenceExpansion, boolean walk) + { + if (root == null) + { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "null root"); + } + this.root = root; + this.whatToShow = whatToShow; + this.filter = filter; + this.entityReferenceExpansion = entityReferenceExpansion; + this.walk = walk; + current = root; + } + + public Node getRoot() + { + return root; + } + + public int getWhatToShow() + { + return whatToShow; + } + + public NodeFilter getFilter() + { + return filter; + } + + public boolean getExpandEntityReferences() + { + return entityReferenceExpansion; + } + + public Node nextNode() + throws DOMException + { + if (root == null) + { + throw new DOMException(DOMException.INVALID_STATE_ERR, "null root"); + } + Node ret; + do + { + if (current.equals(root)) + { + ret = root.getFirstChild(); + } + else if (walk) + { + ret = current.getFirstChild(); + if (ret == null) + { + ret = current.getNextSibling(); + } + if (ret == null) + { + Node tmp = current; + ret = tmp.getParentNode(); + while (!ret.equals(root) && tmp.equals(ret.getLastChild())) + { + tmp = ret; + ret = tmp.getParentNode(); + } + if (ret.equals(root)) + { + ret = null; + } + else + { + ret = ret.getNextSibling(); + } + } + } + else + { + ret = current.getNextSibling(); + } + } + while (!accept(ret)); + current = (ret == null) ? current : ret; + return ret; + } + + public Node previousNode() + throws DOMException + { + if (root == null) + { + throw new DOMException(DOMException.INVALID_STATE_ERR, "null root"); + } + Node ret; + do + { + if (current.equals(root)) + { + ret = current.getLastChild(); + } + else if (walk) + { + ret = current.getLastChild(); + if (ret == null) + { + ret = current.getPreviousSibling(); + } + if (ret == null) + { + Node tmp = current; + ret = tmp.getParentNode(); + while (!ret.equals(root) && tmp.equals(ret.getFirstChild())) + { + tmp = ret; + ret = tmp.getParentNode(); + } + if (ret.equals(root)) + { + ret = null; + } + else + { + ret = ret.getPreviousSibling(); + } + } + } + else + { + ret = current.getPreviousSibling(); + } + } + while (!accept(ret)); + current = (ret == null) ? current : ret; + return ret; + } + + public Node getCurrentNode() + { + return current; + } + + public void setCurrentNode(Node current) + throws DOMException + { + if (current == null) + { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "null root"); + } + this.current = current; + } + + public Node parentNode() + { + Node ret = current.getParentNode(); + if (!accept (ret)) + { + ret = null; + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node firstChild () + { + Node ret = current.getFirstChild(); + while (!accept(ret)) + { + ret = ret.getNextSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node lastChild() + { + Node ret = current.getLastChild(); + while (!accept(ret)) + { + ret = ret.getPreviousSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node previousSibling() + { + Node ret = current.getPreviousSibling(); + while (!accept(ret)) + { + ret = ret.getPreviousSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node nextSibling() + { + Node ret = current.getNextSibling(); + while (!accept(ret)) + { + ret = ret.getNextSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public void detach() + { + root = null; + } + + boolean accept(Node node) + { + if (node == null) + { + return true; + } + boolean ret; + switch (node.getNodeType()) + { + case Node.ATTRIBUTE_NODE: + ret = (whatToShow & NodeFilter.SHOW_ATTRIBUTE) != 0; + break; + case Node.CDATA_SECTION_NODE: + ret = (whatToShow & NodeFilter.SHOW_CDATA_SECTION) != 0; + break; + case Node.COMMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_COMMENT) != 0; + break; + case Node.DOCUMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_DOCUMENT) != 0; + break; + case Node.DOCUMENT_FRAGMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_DOCUMENT_FRAGMENT) != 0; + break; + case Node.DOCUMENT_TYPE_NODE: + ret = (whatToShow & NodeFilter.SHOW_DOCUMENT_TYPE) != 0; + break; + case Node.ELEMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_ELEMENT) != 0; + break; + case Node.ENTITY_NODE: + ret = (whatToShow & NodeFilter.SHOW_ENTITY) != 0; + break; + case Node.ENTITY_REFERENCE_NODE: + ret = (whatToShow & NodeFilter.SHOW_ENTITY_REFERENCE) != 0; + ret = ret && entityReferenceExpansion; + break; + case Node.NOTATION_NODE: + ret = (whatToShow & NodeFilter.SHOW_NOTATION) != 0; + break; + case Node.PROCESSING_INSTRUCTION_NODE: + ret = (whatToShow & NodeFilter.SHOW_PROCESSING_INSTRUCTION) != 0; + break; + case Node.TEXT_NODE: + ret = (whatToShow & NodeFilter.SHOW_TEXT) != 0; + break; + default: + ret = true; + } + if (ret && filter != null) + { + ret = (filter.acceptNode(node) == NodeFilter.FILTER_ACCEPT); + } + return ret; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNotation.java b/libjava/classpath/gnu/xml/dom/DomNotation.java new file mode 100644 index 0000000..26e7872 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNotation.java @@ -0,0 +1,103 @@ +/* DomNotation.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import org.w3c.dom.Notation; + +/** + *
"Notation" implementation. This is a non-core DOM class, supporting + * the "XML" feature.
+ * + *Although unparsed entities using this notation can be detected using + * DOM, neither NOTATIONS nor ENTITY/ENTITIES attributes can be so detected. + * More, there is no portable way to construct a Notation node, so there's + * no way that vendor-neutral DOM construction APIs could even report a + * NOTATION used to identify the intended meaning of a ProcessingInstruction. + *
+ * + *In short, avoid using this DOM functionality. + * + * @see DomDoctype + * @see DomEntity + * @see DomPI + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomNotation + extends DomExtern + implements Notation +{ + + /** + * Constructs a Notation node associated with the specified document, + * with the specified descriptive data. Note that at least one of + * the PUBLIC and SYSTEM identifiers must be provided; unlike other + * external objects in XML, notations may have only a PUBLIC identifier. + * + *
This constructor should only be invoked by a DomDoctype object + * as part of its declareNotation functionality, or through a subclass + * which is similarly used in a "Sub-DOM" style layer. + * + * @param owner The document with which this notation is associated + * @param name Name of this notation + * @param publicId If non-null, provides the notation's PUBLIC identifier + * @param systemId If non-null, rovides the notation's SYSTEM identifier + */ + protected DomNotation(DomDocument owner, + String name, + String publicId, + String systemId) + { + super(NOTATION_NODE, owner, name, publicId, systemId); + makeReadonly(); + } + + /** + * The base URI of an external entity is its system ID. + * The base URI of an internal entity is the parent document's base URI. + * @since DOM Level 3 Core + */ + public String getBaseURI() + { + String systemId = getSystemId(); + return (systemId == null) ? owner.getBaseURI() : systemId; + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomNsNode.java b/libjava/classpath/gnu/xml/dom/DomNsNode.java new file mode 100644 index 0000000..b27514e --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNsNode.java @@ -0,0 +1,200 @@ +/* DomNsNode.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import javax.xml.XMLConstants; +import org.w3c.dom.DOMException; + +/** + *
Abstract implemention of namespace support. This facilitates + * sharing code for attribute and element nodes. + * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomNsNode + extends DomNode +{ + + private String name; + private String namespace; + private String prefix; + String localName; + + /** + * Constructs a node associated with the specified document, and + * with the specified namespace information. + * + * @param owner The document with which this entity is associated + * @param namespaceURI Combined with the local part of the name, + * this identifies a type of element or attribute; may be null. + * If this is the empty string, it is reassigned as null so that + * applications only need to test that case. + * @param name Name of this node, which may include a prefix + */ + // package private + DomNsNode(short nodeType, DomDocument owner, String namespaceURI, String name) + { + super(nodeType, owner); + setNodeName(name); + setNamespaceURI(namespaceURI); + } + + /** + * DOM L1 + * Returns the node's name, including any namespace prefix. + */ + public final String getNodeName() + { + return name; + } + + final void setNodeName(String name) + { + this.name = name.intern(); + int index = name.indexOf(':'); + if (index == -1) + { + prefix = null; + localName = this.name; + } + else + { + prefix = name.substring(0, index).intern(); + localName = name.substring(index + 1).intern(); + } + } + + /** + * DOM L2 + * Returns the node's namespace URI + * or null if the node name is not namespace scoped. + */ + public final String getNamespaceURI() + { + return namespace; + } + + final void setNamespaceURI(String namespaceURI) + { + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + namespace = (namespaceURI == null) ? null : namespaceURI.intern(); + } + + /** + * DOM L2 + * Returns any prefix part of the node's name (before any colon). + */ + public final String getPrefix() + { + return prefix; + } + + /** + * DOM L2 + * Assigns the prefix part of the node's name (before any colon). + */ + public final void setPrefix(String prefix) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + + if (prefix == null) + { + name = localName; + return; + } + else if (namespace == null) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "can't set prefix, node has no namespace URI", + this, 0); + } + + DomDocument.checkName(prefix, "1.1".equals(owner.getXmlVersion())); + if (prefix.indexOf (':') != -1) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "illegal prefix " + prefix, this, 0); + } + + if (XMLConstants.XML_NS_PREFIX.equals(prefix) + && !XMLConstants.XML_NS_URI.equals(namespace)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace is always " + + XMLConstants.XML_NS_URI, this, 0); + } + + if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) + { + if (namespace != null || getNodeType() != ATTRIBUTE_NODE) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns attribute prefix is reserved", + this, 0); + } + } + else if (getNodeType () == ATTRIBUTE_NODE + && (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:"))) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "namespace declarations can't change names", + this, 0); + } + + this.prefix = prefix.intern(); + } + + /** + * DOM L2 + * Returns the local part of the node's name (after any colon). + */ + public final String getLocalName() + { + return localName; + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java b/libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java new file mode 100644 index 0000000..2c90967 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java @@ -0,0 +1,147 @@ +/* DomProcessingInstruction.java -- + Copyright (C) 1999,2000,2001,2004 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 gnu.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.ProcessingInstruction; + +/** + *
"ProcessingInstruction" (PI) implementation. + * This is a non-core DOM class, supporting the "XML" feature.
+ * + *Unlike other DOM APIs in the "XML" feature, this one fully + * exposes the functionality it describes. So there is no reason + * inherent in DOM to avoid using this API, unless you want to rely + * on NOTATION declarations to associate meaning with your PIs; + * there is no vendor-neutal way to record those notations in DOM.
+ * + *Also of note is that PI support is part of SAX, so that XML + * systems using PIs can choose among multiple APIs.
+ * + * @see DomNotation + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomProcessingInstruction + extends DomNode + implements ProcessingInstruction +{ + + private String target; + private String data; + + /** + * Constructs a ProcessingInstruction node associated with the + * specified document, with the specified data. + * + *This constructor should only be invoked by a Document object as + * part of its createProcessingInstruction functionality, or through + * a subclass which is similarly used in a "Sub-DOM" style layer. + */ + protected DomProcessingInstruction(DomDocument owner, + String target, String data) + { + super(PROCESSING_INSTRUCTION_NODE, owner); + this.target = target; + this.data = data; + } + + /** + * DOM L1 + * Returns the target of the processing instruction. + */ + public final String getTarget() + { + return target; + } + + /** + * DOM L1 + * Returns the target of the processing instruction + * (same as getTarget). + */ + public final String getNodeName() + { + return target; + } + + /** + * DOM L1 + * Returns the data associated with the processing instruction. + */ + public final String getData() + { + return data; + } + + /** + * DOM L1 + * Returns the data associated with the processing instruction + * (same as getData). + */ + public final String getNodeValue() + { + return data; + } + + /** + * DOM L1 + * Assigns the data associated with the processing instruction; + * same as setNodeValue. + */ + public final void setData(String data) + { + setNodeValue(data); + } + + /** + * DOM L1 + * Assigns the data associated with the processing instruction. + */ + public final void setNodeValue(String data) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + this.data = data; + } + +} + diff --git a/libjava/classpath/gnu/xml/dom/DomText.java b/libjava/classpath/gnu/xml/dom/DomText.java new file mode 100644 index 0000000..3ca17dc --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomText.java @@ -0,0 +1,220 @@ +/* DomText.java -- + Copyright (C) 1999, 2000, 2001, 2004 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 gnu.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Text; + +/** + *
"Text" implementation.
+ * + * @author David Brownell + * @author Chris Burdess + */ +public class DomText + extends DomCharacterData + implements Text +{ + + // NOTE: deleted unused per-instance "isIgnorable" + // support to reclaim its space. + + /** + * Constructs a text node associated with the specified + * document and holding the specified data. + * + *This constructor should only be invoked by a Document object
+ * as part of its createTextNode functionality, or through a subclass
+ * which is similarly used in a "Sub-DOM" style layer.
+ */
+ protected DomText(DomDocument owner, String value)
+ {
+ super(TEXT_NODE, owner, value);
+ }
+
+ protected DomText(DomDocument owner, char[] buf, int off, int len)
+ {
+ super(TEXT_NODE, owner, buf, off, len);
+ }
+
+ // Used by DomCDATA
+ DomText(short nodeType, DomDocument owner, String value)
+ {
+ super(nodeType, owner, value);
+ }
+
+ DomText(short nodeType, DomDocument owner, char[] buf, int off, int len)
+ {
+ super(nodeType, owner, buf, off, len);
+ }
+
+ /**
+ * DOM L1
+ * Returns the string "#text".
+ */
+ // can't be 'final' with CDATA subclassing
+ public String getNodeName()
+ {
+ return "#text";
+ }
+
+ /**
+ * DOM L1
+ * Splits this text node in two parts at the offset, returning
+ * the new text node (the sibling with the second part).
+ */
+ public Text splitText(int offset)
+ {
+ if (isReadonly())
+ {
+ throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR);
+ }
+ try
+ {
+ String text = getNodeValue();
+ String before = text.substring(0, offset);
+ String after = text.substring(offset);
+ Text next;
+
+ if (getNodeType() == TEXT_NODE)
+ {
+ next = owner.createTextNode(after);
+ }
+ else // CDATA_SECTION_NODE
+ {
+ next = owner.createCDATASection(after);
+ }
+
+ if (this.next != null)
+ {
+ parent.insertBefore(next, this.next);
+ }
+ else
+ {
+ parent.appendChild(next);
+ }
+ setNodeValue(before);
+ return next;
+
+ }
+ catch (IndexOutOfBoundsException x)
+ {
+ throw new DomDOMException(DOMException.INDEX_SIZE_ERR);
+ }
+ }
+
+ // DOM Level 3
+
+ public boolean isElementContentWhitespace()
+ {
+ if (parent != null)
+ {
+ DomDoctype doctype = (DomDoctype) owner.getDoctype();
+ if (doctype != null)
+ {
+ DTDElementTypeInfo info =
+ doctype.getElementTypeInfo(parent.getNodeName());
+ if (info != null)
+ {
+ if (info.model == null && info.model.indexOf("#PCDATA") != -1)
+ {
+ return false;
+ }
+ return getNodeValue().trim().length() == 0;
+ }
+ }
+ }
+ return false;
+ }
+
+ public String getWholeText()
+ {
+ DomNode ref = this;
+ DomNode ctx;
+ for (ctx = previous; ctx != null &&
+ (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE);
+ ctx = ctx.previous)
+ {
+ ref = ctx;
+ }
+ StringBuffer buf = new StringBuffer(ref.getNodeValue());
+ for (ctx = ref.next; ctx != null &&
+ (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE);
+ ctx = ctx.next)
+ {
+ buf.append(ctx.getNodeValue());
+ }
+ return buf.toString ();
+ }
+
+ public Text replaceWholeText(String content)
+ throws DOMException
+ {
+ boolean isEmpty = (content == null || content.length () == 0);
+ if (!isEmpty)
+ {
+ setNodeValue(content);
+ }
+
+ DomNode ref = this;
+ DomNode ctx;
+ for (ctx = previous; ctx != null &&
+ (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE);
+ ctx = ctx.previous)
+ {
+ ref = ctx;
+ }
+ ctx = ref.next;
+ if ((isEmpty || ref != this) && parent != null)
+ {
+ parent.removeChild(ref);
+ }
+ for (; ctx != null &&
+ (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE);
+ ctx = ref)
+ {
+ ref = ctx.next;
+ if ((isEmpty || ctx != this) && parent != null)
+ {
+ parent.removeChild(ctx);
+ }
+ }
+ return (isEmpty) ? null : this;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/dom/DomXPathExpression.java b/libjava/classpath/gnu/xml/dom/DomXPathExpression.java
new file mode 100644
index 0000000..2518752
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/DomXPathExpression.java
@@ -0,0 +1,147 @@
+/* DomXPathExpression.java --
+ Copyright (C) 2004 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 gnu.xml.dom;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+import org.w3c.dom.xpath.XPathException;
+import org.w3c.dom.xpath.XPathNSResolver;
+import org.w3c.dom.xpath.XPathResult;
+import gnu.xml.xpath.DocumentOrderComparator;
+
+/**
+ * An XPath expression.
+ *
+ * @author Chris Burdess
+ */
+class DomXPathExpression
+implements org.w3c.dom.xpath.XPathExpression
+{
+
+ final DomDocument doc;
+ final XPathExpression expression;
+ final XPathNSResolver resolver;
+
+ DomXPathExpression(DomDocument doc, String expression,
+ XPathNSResolver resolver)
+ throws XPathException
+ {
+ this.doc = doc;
+ this.resolver = resolver;
+
+ XPathFactory factory = XPathFactory.newInstance();
+ XPath xpath = factory.newXPath();
+ if (resolver != null)
+ {
+ xpath.setNamespaceContext(new DomNSResolverContext(resolver));
+ }
+ try
+ {
+ this.expression = xpath.compile(expression);
+ }
+ catch (XPathExpressionException e)
+ {
+ throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+ e.getMessage ());
+ }
+ }
+
+ public Object evaluate(Node contextNode, short type, Object result)
+ throws XPathException, DOMException
+ {
+ try
+ {
+ QName typeName = null;
+ switch (type)
+ {
+ case XPathResult.BOOLEAN_TYPE:
+ typeName = XPathConstants.BOOLEAN;
+ break;
+ case XPathResult.NUMBER_TYPE:
+ typeName = XPathConstants.NUMBER;
+ break;
+ case XPathResult.STRING_TYPE:
+ typeName = XPathConstants.STRING;
+ break;
+ case XPathResult.ANY_UNORDERED_NODE_TYPE:
+ case XPathResult.FIRST_ORDERED_NODE_TYPE:
+ typeName = XPathConstants.NODE;
+ break;
+ case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
+ case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
+ typeName = XPathConstants.NODESET;
+ break;
+ default:
+ throw new XPathException(XPathException.TYPE_ERR, null);
+ }
+ Object val = expression.evaluate(contextNode, typeName);
+ switch (type)
+ {
+ case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
+ // Sort the nodes
+ List ns = new ArrayList((Collection) val);
+ Collections.sort(ns, new DocumentOrderComparator());
+ val = ns;
+ }
+ return new DomXPathResult(val, type);
+ }
+ catch (javax.xml.xpath.XPathException e)
+ {
+ throw new XPathException(XPathException.TYPE_ERR, e.getMessage());
+ }
+ }
+
+ public String toString ()
+ {
+ return getClass ().getName () + "[expression=" + expression + "]";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java b/libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java
new file mode 100644
index 0000000..96dfd97
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java
@@ -0,0 +1,64 @@
+/* DomXPathNSResolver.java --
+ Copyright (C) 2004 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 gnu.xml.dom;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.xpath.XPathNSResolver;
+
+/**
+ * Generic XPath namespace resolver using a DOM Node.
+ *
+ * @author Chris Burdess
+ */
+class DomXPathNSResolver
+implements XPathNSResolver
+{
+
+ Node node;
+
+ DomXPathNSResolver (Node node)
+ {
+ this.node = node;
+ }
+
+ public String lookupNamespaceURI (String prefix)
+ {
+ return node.lookupNamespaceURI (prefix);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/dom/DomXPathResult.java b/libjava/classpath/gnu/xml/dom/DomXPathResult.java
new file mode 100644
index 0000000..bed2496
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/DomXPathResult.java
@@ -0,0 +1,233 @@
+/* DomXPathResult.java --
+ Copyright (C) 2004 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 gnu.xml.dom;
+
+import java.util.Collection;
+import java.util.Iterator;
+import org.w3c.dom.Node;
+import org.w3c.dom.xpath.XPathException;
+import org.w3c.dom.xpath.XPathResult;
+
+/**
+ * An XPath result object.
+ *
+ * @author Chris Burdess
+ */
+class DomXPathResult
+implements XPathResult
+{
+
+ final Object value;
+ final short type;
+ Iterator iterator;
+
+ DomXPathResult (Object value, short requestedType)
+ {
+ this.value = value;
+ if (value instanceof Boolean)
+ {
+ type = XPathResult.BOOLEAN_TYPE;
+ }
+ else if (value instanceof Double)
+ {
+ type = XPathResult.NUMBER_TYPE;
+ }
+ else if (value instanceof String)
+ {
+ type = XPathResult.STRING_TYPE;
+ }
+ else if (value instanceof Collection)
+ {
+ Collection ns = (Collection) value;
+ switch (requestedType)
+ {
+ case XPathResult.ANY_TYPE:
+ case XPathResult.ANY_UNORDERED_NODE_TYPE:
+ type = (ns.size () == 1) ? XPathResult.FIRST_ORDERED_NODE_TYPE :
+ XPathResult.ORDERED_NODE_ITERATOR_TYPE;
+ break;
+ default:
+ type = requestedType;
+ }
+ iterator = ns.iterator ();
+ }
+ else
+ {
+ throw new IllegalArgumentException ();
+ }
+ }
+
+ public boolean getBooleanValue()
+ {
+ if (type == XPathResult.BOOLEAN_TYPE)
+ {
+ return ((Boolean) value).booleanValue ();
+ }
+ throw new XPathException (XPathException.TYPE_ERR, value.toString ());
+ }
+
+ public boolean getInvalidIteratorState()
+ {
+ return iterator == null;
+ }
+
+ public double getNumberValue()
+ {
+ if (type == XPathResult.NUMBER_TYPE)
+ {
+ return ((Double) value).doubleValue ();
+ }
+ throw new XPathException (XPathException.TYPE_ERR, value.toString ());
+ }
+
+ public short getResultType()
+ {
+ return type;
+ }
+
+ public Node getSingleNodeValue()
+ {
+ switch (type)
+ {
+ case XPathResult.FIRST_ORDERED_NODE_TYPE:
+ case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
+ case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
+ Collection ns = (Collection) value;
+ if (ns.isEmpty ())
+ {
+ return null;
+ }
+ else
+ {
+ return (Node) ns.iterator ().next ();
+ }
+ }
+ throw new XPathException (XPathException.TYPE_ERR, value.toString ());
+ }
+
+ public int getSnapshotLength()
+ {
+ switch (type)
+ {
+ case XPathResult.FIRST_ORDERED_NODE_TYPE:
+ case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
+ case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
+ return ((Collection) value).size ();
+ }
+ throw new XPathException (XPathException.TYPE_ERR, value.toString ());
+ }
+
+ public String getStringValue()
+ {
+ if (type == XPathResult.STRING_TYPE)
+ {
+ return (String) value;
+ }
+ throw new XPathException (XPathException.TYPE_ERR, value.toString ());
+ }
+
+ public Node iterateNext()
+ {
+ if (iterator != null)
+ {
+ if (iterator.hasNext ())
+ {
+ return (Node) iterator.next ();
+ }
+ else
+ {
+ iterator = null;
+ return null;
+ }
+ }
+ throw new XPathException (XPathException.TYPE_ERR, value.toString ());
+ }
+
+ public Node snapshotItem(int index)
+ {
+ switch (type)
+ {
+ case XPathResult.FIRST_ORDERED_NODE_TYPE:
+ case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
+ case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
+ case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
+ Collection ns = (Collection) value;
+ Node[] nodes = new Node[ns.size ()];
+ ns.toArray (nodes);
+ return nodes[index];
+ }
+ throw new XPathException (XPathException.TYPE_ERR, value.toString ());
+ }
+
+ public String toString ()
+ {
+ return getClass ().getName () + "[type=" + typeName (type) + ",value=" +
+ value + ']';
+ }
+
+ private String typeName (short type)
+ {
+ switch (type)
+ {
+ case XPathResult.BOOLEAN_TYPE:
+ return "BOOLEAN_TYPE";
+ case XPathResult.NUMBER_TYPE:
+ return "NUMBER_TYPE";
+ case XPathResult.STRING_TYPE:
+ return "STRING_TYPE";
+ case XPathResult.FIRST_ORDERED_NODE_TYPE:
+ return "FIRST_ORDERED_NODE_TYPE";
+ case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
+ return "ORDERED_NODE_ITERATOR_TYPE";
+ case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
+ return "ORDERED_NODE_SNAPSHOT_TYPE";
+ case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
+ return "UNORDERED_NODE_ITERATOR_TYPE";
+ case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
+ return "UNORDERED_NODE_SNAPSHOT_TYPE";
+ default:
+ return "(unknown)";
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/dom/ImplementationList.java b/libjava/classpath/gnu/xml/dom/ImplementationList.java
new file mode 100644
index 0000000..8c0f449
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/ImplementationList.java
@@ -0,0 +1,70 @@
+/* ImplementationList.java --
+ Copyright (C) 2004 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 gnu.xml.dom;
+
+import java.util.List;
+
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.DOMImplementationList;
+
+/**
+ * Implementation list for GNU JAXP.
+ *
+ * @author Chris Burdess
+ */
+public class ImplementationList
+ implements DOMImplementationList
+{
+
+ private List list;
+
+ ImplementationList(List list)
+ {
+ this.list = list;
+ }
+
+ public int getLength()
+ {
+ return list.size();
+ }
+
+ public DOMImplementation item(int index)
+ {
+ return (DOMImplementation) list.get(index);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/dom/ImplementationSource.java b/libjava/classpath/gnu/xml/dom/ImplementationSource.java
new file mode 100644
index 0000000..913079c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/ImplementationSource.java
@@ -0,0 +1,167 @@
+/* ImplementationSource.java --
+ Copyright (C) 2004 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 gnu.xml.dom;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.DOMImplementationList;
+import org.w3c.dom.DOMImplementationSource;
+
+/**
+ * Implementation source for GNU JAXP.
+ *
+ * @author Chris Burdess
+ */
+public class ImplementationSource
+ implements DOMImplementationSource
+{
+
+ private static final String DIGITS = "1234567890";
+
+ /*
+ * GNU DOM implementations.
+ */
+ private static final DOMImplementation[] implementations;
+
+ static
+ {
+ List acc = new ArrayList();
+ acc.add(new gnu.xml.dom.DomImpl());
+ try
+ {
+ Class t = Class.forName("gnu.xml.libxmlj.dom.GnomeDocumentBuilder");
+ acc.add(t.newInstance());
+ }
+ catch (Exception e)
+ {
+ // libxmlj not available
+ }
+ catch (UnsatisfiedLinkError e)
+ {
+ // libxmlj not available
+ }
+ implementations = new DOMImplementation[acc.size()];
+ acc.toArray(implementations);
+ }
+
+ public DOMImplementation getDOMImplementation(String features)
+ {
+ List available = getImplementations(features);
+ if (available.isEmpty())
+ {
+ return null;
+ }
+ return (DOMImplementation) available.get(0);
+ }
+
+ public DOMImplementationList getDOMImplementationList(String features)
+ {
+ List available = getImplementations(features);
+ return new ImplementationList(available);
+ }
+
+ /**
+ * Returns a list of the implementations that support the specified
+ * features.
+ */
+ private final List getImplementations(String features)
+ {
+ List available = new ArrayList(Arrays.asList(implementations));
+ for (Iterator i = parseFeatures(features).iterator(); i.hasNext(); )
+ {
+ String feature = (String) i.next();
+ String version = null;
+ int si = feature.indexOf(' ');
+ if (si != -1)
+ {
+ version = feature.substring(si + 1);
+ feature = feature.substring(0, si);
+ }
+ for (Iterator j = available.iterator(); j.hasNext(); )
+ {
+ DOMImplementation impl = (DOMImplementation) j.next();
+ if (!impl.hasFeature(feature, version))
+ {
+ j.remove();
+ }
+ }
+ }
+ return available;
+ }
+
+ /**
+ * Parses the feature list into feature tokens.
+ */
+ final List parseFeatures(String features)
+ {
+ List list = new ArrayList();
+ int pos = 0, start = 0;
+ int len = features.length();
+ for (; pos < len; pos++)
+ {
+ char c = features.charAt(pos);
+ if (c == ' ')
+ {
+ if (pos + 1 < len &&
+ DIGITS.indexOf(features.charAt(pos + 1)) == -1)
+ {
+ list.add(getFeature(features, start, pos));
+ start = pos + 1;
+ }
+ }
+ }
+ if (pos > start)
+ {
+ list.add(getFeature(features, start, len));
+ }
+ return list;
+ }
+
+ final String getFeature(String features, int start, int end)
+ {
+ if (features.length() > 0 && features.charAt(start) == '+')
+ {
+ return features.substring(start + 1, end);
+ }
+ return features.substring(start, end);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/dom/JAXPFactory.java b/libjava/classpath/gnu/xml/dom/JAXPFactory.java
new file mode 100644
index 0000000..8f481fad
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/JAXPFactory.java
@@ -0,0 +1,286 @@
+/* JAXPFactory.java --
+ Copyright (C) 2001 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 gnu.xml.dom;
+
+import java.io.IOException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMImplementation;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+
+
+/**
+ * DOM bootstrapping API, for use with JAXP.
+ *
+ * @see Consumer
+ *
+ * @author David Brownell
+ */
+public final class JAXPFactory
+ extends DocumentBuilderFactory
+{
+
+ private static final String PROPERTY = "http://xml.org/sax/properties/";
+ private static final String FEATURE = "http://xml.org/sax/features/";
+
+ private SAXParserFactory pf;
+
+ /**
+ * Default constructor.
+ */
+ public JAXPFactory()
+ {
+ }
+
+ /**
+ * Constructs a JAXP document builder which uses the default
+ * JAXP SAX2 parser and the DOM implementation in this package.
+ */
+ public DocumentBuilder newDocumentBuilder()
+ throws ParserConfigurationException
+ {
+ if (pf == null)
+ {
+ // Force use of AElfred2 since not all JAXP parsers
+ // conform very well to the SAX2 API spec ...
+ pf = new gnu.xml.aelfred2.JAXPFactory();
+ // pf = SAXParserFactory.newInstance ();
+ }
+
+ // JAXP default: false
+ pf.setValidating(isValidating());
+
+ // FIXME: this namespace setup may cause errors in some
+ // conformant SAX2 parsers, which we CAN patch up by
+ // splicing a "NSFilter" stage up front ...
+
+ // JAXP default: false
+ pf.setNamespaceAware(isNamespaceAware());
+
+ try
+ {
+ // undo rude "namespace-prefixes=false" default
+ pf.setFeature(FEATURE + "namespace-prefixes", true);
+
+ return new JAXPBuilder(pf.newSAXParser().getXMLReader(), this);
+ }
+ catch (SAXException e)
+ {
+ String msg = "can't create JAXP DocumentBuilder: " + e.getMessage();
+ throw new ParserConfigurationException(msg);
+ }
+ }
+
+ /** There seems to be no useful specification for attribute names */
+ public void setAttribute(String name, Object value)
+ throws IllegalArgumentException
+ {
+ if ("http://java.sun.com/xml/jaxp/properties/schemaLanguage".equals(name))
+ {
+ // TODO
+ }
+ else
+ {
+ throw new IllegalArgumentException(name);
+ }
+ }
+
+ /** There seems to be no useful specification for attribute names */
+ public Object getAttribute(String name)
+ throws IllegalArgumentException
+ {
+ throw new IllegalArgumentException(name);
+ }
+
+ static final class JAXPBuilder
+ extends DocumentBuilder
+ implements ErrorHandler
+ {
+
+ private Consumer consumer;
+ private XMLReader producer;
+ private DomImpl impl;
+
+ JAXPBuilder(XMLReader parser, JAXPFactory factory)
+ throws ParserConfigurationException
+ {
+ impl = new DomImpl();
+
+ // set up consumer side
+ try
+ {
+ consumer = new Consumer();
+ }
+ catch (SAXException e)
+ {
+ throw new ParserConfigurationException(e.getMessage());
+ }
+
+ // JAXP defaults: true, noise nodes are good (bleech)
+ consumer.setHidingReferences(factory.isExpandEntityReferences());
+ consumer.setHidingComments(factory.isIgnoringComments());
+ consumer.setHidingWhitespace(factory.isIgnoringElementContentWhitespace());
+ consumer.setHidingCDATA(factory.isCoalescing());
+
+ // set up producer side
+ producer = parser;
+ producer.setContentHandler(consumer.getContentHandler());
+ producer.setDTDHandler(consumer.getDTDHandler());
+
+ try
+ {
+ String id;
+
+ // if validating, report validity errors, and default
+ // to treating them as fatal
+ if (factory.isValidating ())
+ {
+ producer.setFeature(FEATURE + "validation", true);
+ producer.setErrorHandler(this);
+ }
+
+ // always save prefix info, maybe do namespace processing
+ producer.setFeature(FEATURE + "namespace-prefixes", true);
+ producer.setFeature(FEATURE + "namespaces",
+ factory.isNamespaceAware());
+
+ // set important handlers
+ id = PROPERTY + "lexical-handler";
+ producer.setProperty(id, consumer.getProperty(id));
+
+ id = PROPERTY + "declaration-handler";
+ producer.setProperty(id, consumer.getProperty(id));
+
+ }
+ catch (SAXException e)
+ {
+ throw new ParserConfigurationException(e.getMessage());
+ }
+ }
+
+ public Document parse(InputSource source)
+ throws SAXException, IOException
+ {
+ producer.parse(source);
+ Document doc = consumer.getDocument();
+ // TODO inputEncoding
+ doc.setDocumentURI(source.getSystemId());
+ return doc;
+ }
+
+ public boolean isNamespaceAware()
+ {
+ try
+ {
+ return producer.getFeature(FEATURE + "namespaces");
+ }
+ catch (SAXException e)
+ {
+ // "can't happen"
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ public boolean isValidating()
+ {
+ try
+ {
+ return producer.getFeature(FEATURE + "validation");
+ }
+ catch (SAXException e)
+ {
+ // "can't happen"
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ public void setEntityResolver(EntityResolver resolver)
+ {
+ producer.setEntityResolver(resolver);
+ }
+
+ public void setErrorHandler(ErrorHandler handler)
+ {
+ producer.setErrorHandler(handler);
+ consumer.setErrorHandler(handler);
+ }
+
+ public DOMImplementation getDOMImplementation()
+ {
+ return impl;
+ }
+
+ public Document newDocument()
+ {
+ return new DomDocument();
+ }
+
+ // implementation of error handler that's used when validating
+ public void fatalError(SAXParseException e)
+ throws SAXException
+ {
+ throw e;
+ }
+
+ public void error(SAXParseException e)
+ throws SAXException
+ {
+ throw e;
+ }
+
+ public void warning(SAXParseException e)
+ throws SAXException
+ {
+ /* ignore */
+ }
+
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java
new file mode 100644
index 0000000..5da9133
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java
@@ -0,0 +1,189 @@
+/* DomHTMLAnchorElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLAnchorElement;
+
+/**
+ * An HTML 'A' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLAnchorElement
+ extends DomHTMLElement
+ implements HTMLAnchorElement
+{
+
+ protected DomHTMLAnchorElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getAccessKey()
+ {
+ return getHTMLAttribute("accesskey");
+ }
+
+ public void setAccessKey(String accessKey)
+ {
+ setHTMLAttribute("accesskey", accessKey);
+ }
+
+ public String getCharset()
+ {
+ return getHTMLAttribute("charset");
+ }
+
+ public void setCharset(String charset)
+ {
+ setHTMLAttribute("charset", charset);
+ }
+
+ public String getCoords()
+ {
+ return getHTMLAttribute("coords");
+ }
+
+ public void setCoords(String coords)
+ {
+ setHTMLAttribute("coords", coords);
+ }
+
+ public String getHref()
+ {
+ return getHTMLAttribute("href");
+ }
+
+ public void setHref(String href)
+ {
+ setHTMLAttribute("href", href);
+ }
+
+ public String getHreflang()
+ {
+ return getHTMLAttribute("hreflang");
+ }
+
+ public void setHreflang(String hreflang)
+ {
+ setHTMLAttribute("hreflang", hreflang);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public String getRel()
+ {
+ return getHTMLAttribute("rel");
+ }
+
+ public void setRel(String rel)
+ {
+ setHTMLAttribute("rel", rel);
+ }
+
+ public String getRev()
+ {
+ return getHTMLAttribute("rev");
+ }
+
+ public void setRev(String rev)
+ {
+ setHTMLAttribute("rev", rev);
+ }
+
+ public String getShape()
+ {
+ return getHTMLAttribute("shape");
+ }
+
+ public void setShape(String shape)
+ {
+ setHTMLAttribute("shape", shape);
+ }
+
+ public int getTabIndex()
+ {
+ return getIntHTMLAttribute("tabindex");
+ }
+
+ public void setTabIndex(int tabIndex)
+ {
+ setIntHTMLAttribute("tabindex", tabIndex);
+ }
+
+ public String getTarget()
+ {
+ return getHTMLAttribute("target");
+ }
+
+ public void setTarget(String target)
+ {
+ setHTMLAttribute("target", target);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public void setType(String type)
+ {
+ setHTMLAttribute("type", type);
+ }
+
+ public void blur()
+ {
+ dispatchUIEvent("blur");
+ }
+
+ public void focus()
+ {
+ dispatchUIEvent("focus");
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java
new file mode 100644
index 0000000..8ec4d3c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java
@@ -0,0 +1,169 @@
+/* DomHTMLAppletElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLAppletElement;
+
+/**
+ * An HTML 'APPLET' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLAppletElement
+ extends DomHTMLElement
+ implements HTMLAppletElement
+{
+
+ protected DomHTMLAppletElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+ public String getAlt()
+ {
+ return getHTMLAttribute("alt");
+ }
+
+ public void setAlt(String alt)
+ {
+ setHTMLAttribute("alt", alt);
+ }
+
+ public String getArchive()
+ {
+ return getHTMLAttribute("archive");
+ }
+
+ public void setArchive(String archive)
+ {
+ setHTMLAttribute("archive", archive);
+ }
+
+ public String getCode()
+ {
+ return getHTMLAttribute("code");
+ }
+
+ public void setCode(String code)
+ {
+ setHTMLAttribute("code", code);
+ }
+
+ public String getCodeBase()
+ {
+ return getHTMLAttribute("codebase");
+ }
+
+ public void setCodeBase(String codeBase)
+ {
+ setHTMLAttribute("codebase", codeBase);
+ }
+
+ public String getHeight()
+ {
+ return getHTMLAttribute("height");
+ }
+
+ public void setHeight(String height)
+ {
+ setHTMLAttribute("height", height);
+ }
+
+ public int getHspace()
+ {
+ return getIntHTMLAttribute("hspace");
+ }
+
+ public void setHspace(int hspace)
+ {
+ setIntHTMLAttribute("hspace", hspace);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public String getObject()
+ {
+ return getHTMLAttribute("object");
+ }
+
+ public void setObject(String object)
+ {
+ setHTMLAttribute("object", object);
+ }
+
+ public int getVspace()
+ {
+ return getIntHTMLAttribute("vspace");
+ }
+
+ public void setVspace(int vspace)
+ {
+ setIntHTMLAttribute("vspace", vspace);
+ }
+
+ public String getWidth()
+ {
+ return getHTMLAttribute("width");
+ }
+
+ public void setWidth(String width)
+ {
+ setHTMLAttribute("width", width);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java
new file mode 100644
index 0000000..d7eed07
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java
@@ -0,0 +1,139 @@
+/* DomHTMLAreaElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLAreaElement;
+
+/**
+ * An HTML 'AREA' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLAreaElement
+ extends DomHTMLElement
+ implements HTMLAreaElement
+{
+
+ protected DomHTMLAreaElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getAccessKey()
+ {
+ return getHTMLAttribute("accesskey");
+ }
+
+ public void setAccessKey(String accessKey)
+ {
+ setHTMLAttribute("accesskey", accessKey);
+ }
+
+ public String getAlt()
+ {
+ return getHTMLAttribute("alt");
+ }
+
+ public void setAlt(String alt)
+ {
+ setHTMLAttribute("alt", alt);
+ }
+
+ public String getCoords()
+ {
+ return getHTMLAttribute("coords");
+ }
+
+ public void setCoords(String coords)
+ {
+ setHTMLAttribute("coords", coords);
+ }
+
+ public String getHref()
+ {
+ return getHTMLAttribute("href");
+ }
+
+ public void setHref(String href)
+ {
+ setHTMLAttribute("href", href);
+ }
+
+ public boolean getNoHref()
+ {
+ return getBooleanHTMLAttribute("nohref");
+ }
+
+ public void setNoHref(boolean nohref)
+ {
+ setBooleanHTMLAttribute("nohref", nohref);
+ }
+
+ public String getShape()
+ {
+ return getHTMLAttribute("shape");
+ }
+
+ public void setShape(String shape)
+ {
+ setHTMLAttribute("shape", shape);
+ }
+
+ public int getTabIndex()
+ {
+ return getIntHTMLAttribute("tabindex");
+ }
+
+ public void setTabIndex(int tabIndex)
+ {
+ setIntHTMLAttribute("tabindex", tabIndex);
+ }
+
+ public String getTarget()
+ {
+ return getHTMLAttribute("target");
+ }
+
+ public void setTarget(String target)
+ {
+ setHTMLAttribute("target", target);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java
new file mode 100644
index 0000000..673699d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLBRElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLBRElement;
+
+/**
+ * An HTML 'BR' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLBRElement
+ extends DomHTMLElement
+ implements HTMLBRElement
+{
+
+ protected DomHTMLBRElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getClear()
+ {
+ return getHTMLAttribute("clear");
+ }
+
+ public void setClear(String clear)
+ {
+ setHTMLAttribute("clear", clear);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java
new file mode 100644
index 0000000..ddc8053
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java
@@ -0,0 +1,79 @@
+/* DomHTMLBaseElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLBaseElement;
+
+/**
+ * An HTML 'BASE' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLBaseElement
+ extends DomHTMLElement
+ implements HTMLBaseElement
+{
+
+ protected DomHTMLBaseElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getHref()
+ {
+ return getHTMLAttribute("href");
+ }
+
+ public void setHref(String href)
+ {
+ setHTMLAttribute("href", href);
+ }
+
+ public String getTarget()
+ {
+ return getHTMLAttribute("target");
+ }
+
+ public void setTarget(String target)
+ {
+ setHTMLAttribute("target", target);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java
new file mode 100644
index 0000000..73172d3
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java
@@ -0,0 +1,89 @@
+/* DomHTMLBaseFontElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLBaseFontElement;
+
+/**
+ * An HTML 'BASEFONT' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLBaseFontElement
+ extends DomHTMLElement
+ implements HTMLBaseFontElement
+{
+
+ protected DomHTMLBaseFontElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getColor()
+ {
+ return getHTMLAttribute("color");
+ }
+
+ public void setColor(String color)
+ {
+ setHTMLAttribute("color", color);
+ }
+
+ public String getFace()
+ {
+ return getHTMLAttribute("face");
+ }
+
+ public void setFace(String face)
+ {
+ setHTMLAttribute("face", face);
+ }
+
+ public int getSize()
+ {
+ return getIntHTMLAttribute("size");
+ }
+
+ public void setSize(int size)
+ {
+ setIntHTMLAttribute("size", size);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java
new file mode 100644
index 0000000..44fbcf2
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java
@@ -0,0 +1,119 @@
+/* DomHTMLBodyElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLBodyElement;
+
+/**
+ * An HTML 'BODY' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLBodyElement
+ extends DomHTMLElement
+ implements HTMLBodyElement
+{
+
+ protected DomHTMLBodyElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getALink()
+ {
+ return getHTMLAttribute("alink");
+ }
+
+ public void setALink(String alink)
+ {
+ setHTMLAttribute("alink", alink);
+ }
+
+ public String getBackground()
+ {
+ return getHTMLAttribute("background");
+ }
+
+ public void setBackground(String background)
+ {
+ setHTMLAttribute("background", background);
+ }
+
+ public String getBgColor()
+ {
+ return getHTMLAttribute("bgcolor");
+ }
+
+ public void setBgColor(String bgcolor)
+ {
+ setHTMLAttribute("bgcolor", bgcolor);
+ }
+
+ public String getLink()
+ {
+ return getHTMLAttribute("link");
+ }
+
+ public void setLink(String link)
+ {
+ setHTMLAttribute("link", link);
+ }
+
+ public String getText()
+ {
+ return getHTMLAttribute("text");
+ }
+
+ public void setText(String text)
+ {
+ setHTMLAttribute("text", text);
+ }
+
+ public String getVLink()
+ {
+ return getHTMLAttribute("vlink");
+ }
+
+ public void setVLink(String vlink)
+ {
+ setHTMLAttribute("vlink", vlink);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java
new file mode 100644
index 0000000..5aff5f8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java
@@ -0,0 +1,121 @@
+/* DomHTMLButtonElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.html2.HTMLButtonElement;
+import org.w3c.dom.html2.HTMLFormElement;
+
+/**
+ * An HTML 'BUTTON' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLButtonElement
+ extends DomHTMLElement
+ implements HTMLButtonElement
+{
+
+ protected DomHTMLButtonElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public HTMLFormElement getForm()
+ {
+ return (HTMLFormElement) getParentElement("form");
+ }
+
+ public String getAccessKey()
+ {
+ return getHTMLAttribute("accesskey");
+ }
+
+ public void setAccessKey(String accessKey)
+ {
+ setHTMLAttribute("accesskey", accessKey);
+ }
+
+ public boolean getDisabled()
+ {
+ return getBooleanHTMLAttribute("disabled");
+ }
+
+ public void setDisabled(boolean disabled)
+ {
+ setBooleanHTMLAttribute("disabled", disabled);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public int getTabIndex()
+ {
+ return getIntHTMLAttribute("tabindex");
+ }
+
+ public void setTabIndex(int tabIndex)
+ {
+ setIntHTMLAttribute("tabindex", tabIndex);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public String getValue()
+ {
+ return getHTMLAttribute("value");
+ }
+
+ public void setValue(String value)
+ {
+ setHTMLAttribute("value", value);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java
new file mode 100644
index 0000000..577337a
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java
@@ -0,0 +1,227 @@
+/* DomHTMLCollection.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import gnu.xml.dom.DomDOMException;
+import gnu.xml.dom.DomElement;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.html2.HTMLCollection;
+import org.w3c.dom.html2.HTMLOptionsCollection;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.NodeIterator;
+
+/**
+ * An HTML element collection.
+ *
+ * @author Chris Burdess
+ */
+class DomHTMLCollection
+ implements HTMLCollection, HTMLOptionsCollection, NodeList, NodeFilter
+{
+
+ final DomHTMLDocument doc;
+ final Node root;
+ List nodeNames;
+ List attributeNames;
+ List results;
+
+ DomHTMLCollection(DomHTMLDocument doc, Node root)
+ {
+ this.doc = doc;
+ this.root = root;
+ }
+
+ // -- Node name and attribute filtering --
+
+ void addNodeName(String name)
+ {
+ if (nodeNames == null)
+ {
+ nodeNames = new LinkedList();
+ }
+ nodeNames.add(name);
+ }
+
+ void addAttributeName(String name)
+ {
+ if (attributeNames == null)
+ {
+ attributeNames = new LinkedList();
+ }
+ attributeNames.add(name);
+ }
+
+ public short acceptNode(Node n)
+ {
+ if (n.getNodeType() != Node.ELEMENT_NODE)
+ {
+ return NodeFilter.FILTER_SKIP;
+ }
+ String localName = n.getLocalName();
+ if (localName == null)
+ {
+ localName = n.getNodeName();
+ }
+ if (nodeNames != null && !acceptName(localName))
+ {
+ return NodeFilter.FILTER_SKIP;
+ }
+ if (attributeNames != null && !acceptAttributes(n.getAttributes()))
+ {
+ return NodeFilter.FILTER_SKIP;
+ }
+ return NodeFilter.FILTER_ACCEPT;
+ }
+
+ private boolean acceptName(String name)
+ {
+ for (Iterator i = nodeNames.iterator(); i.hasNext(); )
+ {
+ String nodeName = (String) i.next();
+ if (nodeName.equalsIgnoreCase(name))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean acceptAttributes(NamedNodeMap attrs)
+ {
+ for (Iterator i = attributeNames.iterator(); i.hasNext(); )
+ {
+ String attributeName = (String) i.next();
+ Node attr = getNamedItem(attrs, attributeName);
+ if (attr != null)
+ {
+ // Check that attribute has a non-null value
+ String nodeValue = attr.getNodeValue();
+ if (nodeValue != null && nodeValue.length() > 0)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Case-insensitive version of getNamedItem.
+ */
+ private Node getNamedItem(NamedNodeMap attrs, String name)
+ {
+ int len = attrs.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ Node attr = attrs.item(i);
+ String attrName = attr.getLocalName();
+ if (attrName == null)
+ {
+ attrName = attr.getNodeName();
+ }
+ if (name.equalsIgnoreCase(attrName))
+ {
+ return attr;
+ }
+ }
+ return null;
+ }
+
+ // -- Perform query --
+
+ void evaluate()
+ {
+ NodeIterator i = doc.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
+ this, true);
+ results = new ArrayList();
+ for (Node node = i.nextNode(); node != null; node = i.nextNode())
+ {
+ results.add(node);
+ }
+ }
+
+ // -- HTMLCollection/NodeList interface --
+
+ public int getLength()
+ {
+ return results.size();
+ }
+
+ public void setLength(int length)
+ {
+ throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
+ }
+
+ public Node item(int index)
+ {
+ return (Node) results.get(index);
+ }
+
+ public Node namedItem(String name)
+ {
+ boolean xhtml = false; // FIXME detect XHTML document
+ for (Iterator i = results.iterator(); i.hasNext(); )
+ {
+ Node node = (Node) i.next();
+ NamedNodeMap attrs = node.getAttributes();
+ Node attr = getNamedItem(attrs, "id");
+ if (name.equals(attr.getTextContent()))
+ {
+ return node;
+ }
+ if (!xhtml)
+ {
+ attr = getNamedItem(attrs, "name");
+ if (name.equals(attr.getTextContent()))
+ {
+ return node;
+ }
+ }
+ }
+ return null;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java
new file mode 100644
index 0000000..2b9dbf2
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLDListElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLDListElement;
+
+/**
+ * An HTML 'DL' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLDListElement
+ extends DomHTMLElement
+ implements HTMLDListElement
+{
+
+ protected DomHTMLDListElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public boolean getCompact()
+ {
+ return getBooleanHTMLAttribute("compact");
+ }
+
+ public void setCompact(boolean compact)
+ {
+ setBooleanHTMLAttribute("compact", compact);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java
new file mode 100644
index 0000000..26af97e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLDirectoryElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLDirectoryElement;
+
+/**
+ * An HTML 'DIR' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLDirectoryElement
+ extends DomHTMLElement
+ implements HTMLDirectoryElement
+{
+
+ protected DomHTMLDirectoryElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public boolean getCompact()
+ {
+ return getBooleanHTMLAttribute("compact");
+ }
+
+ public void setCompact(boolean compact)
+ {
+ setBooleanHTMLAttribute("compact", compact);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java
new file mode 100644
index 0000000..462069d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLDivElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLDivElement;
+
+/**
+ * An HTML 'DIV' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLDivElement
+ extends DomHTMLElement
+ implements HTMLDivElement
+{
+
+ protected DomHTMLDivElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java
new file mode 100644
index 0000000..10ee9e7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java
@@ -0,0 +1,425 @@
+/* DomHTMLDocument.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import gnu.xml.dom.DomDocument;
+import gnu.xml.dom.DomDOMException;
+import java.lang.reflect.Constructor;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.html2.HTMLCollection;
+import org.w3c.dom.html2.HTMLDocument;
+import org.w3c.dom.html2.HTMLElement;
+
+/**
+ * An HTML document.
+ * This is the factory object used to create HTML elements.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLDocument
+ extends DomDocument
+ implements HTMLDocument
+{
+
+ private static final Class[] ELEMENT_PT = new Class[] {
+ DomHTMLDocument.class,
+ String.class,
+ String.class
+ };
+
+ private static Map ELEMENT_CLASSES;
+ static
+ {
+ Map map = new HashMap();
+ map.put("a", DomHTMLAnchorElement.class);
+ map.put("applet", DomHTMLAppletElement.class);
+ map.put("area", DomHTMLAreaElement.class);
+ map.put("base", DomHTMLBaseElement.class);
+ map.put("basefont", DomHTMLBaseFontElement.class);
+ map.put("body", DomHTMLBodyElement.class);
+ map.put("br", DomHTMLBRElement.class);
+ map.put("button", DomHTMLButtonElement.class);
+ map.put("dir", DomHTMLDirectoryElement.class);
+ map.put("div", DomHTMLDivElement.class);
+ map.put("dlist", DomHTMLDListElement.class);
+ map.put("fieldset", DomHTMLFieldSetElement.class);
+ map.put("font", DomHTMLFontElement.class);
+ map.put("form", DomHTMLFormElement.class);
+ map.put("frame", DomHTMLFrameElement.class);
+ map.put("frameset", DomHTMLFrameSetElement.class);
+ map.put("head", DomHTMLHeadElement.class);
+ map.put("h1", DomHTMLHeadingElement.class);
+ map.put("h2", DomHTMLHeadingElement.class);
+ map.put("h3", DomHTMLHeadingElement.class);
+ map.put("h4", DomHTMLHeadingElement.class);
+ map.put("h5", DomHTMLHeadingElement.class);
+ map.put("h6", DomHTMLHeadingElement.class);
+ map.put("html", DomHTMLHtmlElement.class);
+ map.put("iframe", DomHTMLIFrameElement.class);
+ map.put("img", DomHTMLImageElement.class);
+ map.put("input", DomHTMLInputElement.class);
+ map.put("isindex", DomHTMLIsIndexElement.class);
+ map.put("label", DomHTMLLabelElement.class);
+ map.put("legend", DomHTMLLegendElement.class);
+ map.put("li", DomHTMLLIElement.class);
+ map.put("link", DomHTMLLinkElement.class);
+ map.put("map", DomHTMLMapElement.class);
+ map.put("menu", DomHTMLMenuElement.class);
+ map.put("meta", DomHTMLMetaElement.class);
+ map.put("ins", DomHTMLModElement.class);
+ map.put("del", DomHTMLModElement.class);
+ map.put("object", DomHTMLObjectElement.class);
+ map.put("ol", DomHTMLOListElement.class);
+ map.put("optgroup", DomHTMLOptGroupElement.class);
+ map.put("option", DomHTMLOptionElement.class);
+ map.put("p", DomHTMLParagraphElement.class);
+ map.put("param", DomHTMLParamElement.class);
+ map.put("pre", DomHTMLPreElement.class);
+ map.put("q", DomHTMLQuoteElement.class);
+ map.put("blockquote", DomHTMLQuoteElement.class);
+ map.put("script", DomHTMLScriptElement.class);
+ map.put("select", DomHTMLSelectElement.class);
+ map.put("style", DomHTMLStyleElement.class);
+ map.put("caption", DomHTMLTableCaptionElement.class);
+ map.put("th", DomHTMLTableCellElement.class);
+ map.put("td", DomHTMLTableCellElement.class);
+ map.put("col", DomHTMLTableColElement.class);
+ map.put("colgroup", DomHTMLTableColElement.class);
+ map.put("table", DomHTMLTableElement.class);
+ map.put("tr", DomHTMLTableRowElement.class);
+ map.put("thead", DomHTMLTableSectionElement.class);
+ map.put("tfoot", DomHTMLTableSectionElement.class);
+ map.put("tbody", DomHTMLTableSectionElement.class);
+ map.put("textarea", DomHTMLTextAreaElement.class);
+ map.put("title", DomHTMLTitleElement.class);
+ map.put("ul", DomHTMLUListElement.class);
+ ELEMENT_CLASSES = Collections.unmodifiableMap(map);
+ }
+
+ private static Set HTML_NS_URIS;
+ static
+ {
+ Set set = new HashSet();
+ set.add("http://www.w3.org/TR/html4/strict");
+ set.add("http://www.w3.org/TR/html4/loose");
+ set.add("http://www.w3.org/TR/html4/frameset");
+ set.add("http://www.w3.org/1999/xhtml");
+ set.add("http://www.w3.org/TR/xhtml1/strict");
+ set.add("http://www.w3.org/TR/xhtml1/loose");
+ set.add("http://www.w3.org/TR/xhtml1/frameset");
+ HTML_NS_URIS = Collections.unmodifiableSet(set);
+ }
+
+ /**
+ * Convenience constructor.
+ */
+ public DomHTMLDocument()
+ {
+ this(new DomHTMLImpl());
+ }
+
+ /**
+ * Constructor.
+ * This is called by the DOMImplementation.
+ */
+ public DomHTMLDocument(DomHTMLImpl impl)
+ {
+ super(impl);
+ }
+
+ private Node getChildNodeByName(Node parent, String name)
+ {
+ for (Node ctx = parent.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ if (name.equalsIgnoreCase(ctx.getNodeName()))
+ {
+ return ctx;
+ }
+ }
+ return null;
+ }
+
+ public String getTitle()
+ {
+ Node html = getDocumentElement();
+ if (html != null)
+ {
+ Node head = getChildNodeByName(html, "head");
+ if (head != null)
+ {
+ Node title = getChildNodeByName(head, "title");
+ if (title != null)
+ {
+ return title.getTextContent();
+ }
+ }
+ }
+ return null;
+ }
+
+ public void setTitle(String title)
+ {
+ Node html = getDocumentElement();
+ if (html == null)
+ {
+ html = createElement("html");
+ appendChild(html);
+ }
+ Node head = getChildNodeByName(html, "head");
+ if (head == null)
+ {
+ head = createElement("head");
+ Node first = html.getFirstChild();
+ if (first != null)
+ {
+ html.insertBefore(first, head);
+ }
+ else
+ {
+ html.appendChild(head);
+ }
+ }
+ Node titleNode = getChildNodeByName(head, "title");
+ if (titleNode == null)
+ {
+ titleNode = createElement("title");
+ Node first = head.getFirstChild();
+ if (first != null)
+ {
+ head.insertBefore(first, titleNode);
+ }
+ else
+ {
+ head.appendChild(titleNode);
+ }
+ }
+ titleNode.setTextContent(title);
+ }
+
+ public String getReferrer()
+ {
+ // TODO getReferrer
+ return null;
+ }
+
+ public String getDomain()
+ {
+ try
+ {
+ URL url = new URL(getDocumentURI());
+ return url.getHost();
+ }
+ catch (MalformedURLException e)
+ {
+ return null;
+ }
+ }
+
+ public String getURL()
+ {
+ return getDocumentURI();
+ }
+
+ public HTMLElement getBody()
+ {
+ Node html = getDocumentElement();
+ if (html != null)
+ {
+ Node body = getChildNodeByName(html, "body");
+ if (body == null)
+ {
+ body = getChildNodeByName(html, "frameset");
+ }
+ return (HTMLElement) body;
+ }
+ return null;
+ }
+
+ public void setBody(HTMLElement body)
+ {
+ Node html = getDocumentElement();
+ if (html == null)
+ {
+ html = createElement("html");
+ appendChild(html);
+ }
+ Node ref = getBody();
+ if (ref == null)
+ {
+ html.appendChild(body);
+ }
+ else
+ {
+ html.replaceChild(body, ref);
+ }
+ }
+
+ public HTMLCollection getImages()
+ {
+ DomHTMLCollection ret = new DomHTMLCollection(this, this);
+ ret.addNodeName("img");
+ ret.evaluate();
+ return ret;
+ }
+
+ public HTMLCollection getApplets()
+ {
+ DomHTMLCollection ret = new DomHTMLCollection(this, this);
+ ret.addNodeName("object");
+ ret.addNodeName("applet");
+ ret.evaluate();
+ return ret;
+ }
+
+ public HTMLCollection getLinks()
+ {
+ DomHTMLCollection ret = new DomHTMLCollection(this, this);
+ ret.addNodeName("area");
+ ret.addNodeName("a");
+ ret.evaluate();
+ return ret;
+ }
+
+ public HTMLCollection getForms()
+ {
+ DomHTMLCollection ret = new DomHTMLCollection(this, this);
+ ret.addNodeName("form");
+ ret.evaluate();
+ return ret;
+ }
+
+ public HTMLCollection getAnchors()
+ {
+ DomHTMLCollection ret = new DomHTMLCollection(this, this);
+ ret.addNodeName("a");
+ ret.addAttributeName("name");
+ ret.evaluate();
+ return ret;
+ }
+
+ public String getCookie()
+ {
+ // TODO getCookie
+ return null;
+ }
+
+ public void setCookie(String cookie)
+ {
+ // TODO setCookie
+ }
+
+ public void open()
+ {
+ // TODO open
+ }
+
+ public void close()
+ {
+ // TODO close
+ }
+
+ public void write(String text)
+ {
+ // TODO write
+ }
+
+ public void writeln(String text)
+ {
+ // TODO write
+ }
+
+ public NodeList getElementsByName(String name)
+ {
+ DomHTMLCollection ret = new DomHTMLCollection(this, this);
+ ret.addNodeName(name);
+ ret.evaluate();
+ return ret;
+ // TODO xhtml: return only form controls (?)
+ }
+
+ public Element createElement(String tagName)
+ {
+ return createElementNS(null, tagName);
+ }
+
+ public Element createElementNS(String uri, String qName)
+ {
+ /* If a non-HTML element, use the default implementation. */
+ if (uri != null && !HTML_NS_URIS.contains(uri))
+ {
+ return super.createElementNS(uri, qName);
+ }
+ String localName = qName.toLowerCase();
+ int ci = qName.indexOf(':');
+ if (ci != -1)
+ {
+ localName = qName.substring(ci + 1);
+ }
+ Class t = (Class) ELEMENT_CLASSES.get(localName);
+ /* If a non-HTML element, use the default implementation. */
+ if (t == null)
+ {
+ return super.createElementNS(uri, qName);
+ }
+ try
+ {
+ Constructor c = t.getDeclaredConstructor(ELEMENT_PT);
+ Object[] args = new Object[] { this, uri, qName };
+ return (Element) c.newInstance(args);
+ }
+ catch (Exception e)
+ {
+ DOMException e2 = new DomDOMException(DOMException.TYPE_MISMATCH_ERR);
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java
new file mode 100644
index 0000000..b957083
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java
@@ -0,0 +1,287 @@
+/* DomHTMLElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import gnu.xml.dom.DomDOMException;
+import gnu.xml.dom.DomElement;
+import gnu.xml.dom.DomEvent;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.events.UIEvent;
+import org.w3c.dom.html2.HTMLElement;
+
+/**
+ * Abstract implementation of an HTML element node.
+ *
+ * @author Chris Burdess
+ */
+public abstract class DomHTMLElement
+ extends DomElement
+ implements HTMLElement
+{
+
+ protected DomHTMLElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ /**
+ * Returns the value of the specified attribute.
+ * The attribute name is case insensitive.
+ */
+ protected String getHTMLAttribute(String name)
+ {
+ if (hasAttributes())
+ {
+ NamedNodeMap attrs = getAttributes();
+ int len = attrs.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ Node attr = attrs.item(i);
+ String attrName = attr.getLocalName();
+ if (attrName == null)
+ {
+ attrName = attr.getNodeName();
+ }
+ if (attrName.equalsIgnoreCase(name))
+ {
+ return attr.getNodeValue();
+ }
+ }
+ }
+ return "";
+ }
+
+ protected int getIntHTMLAttribute(String name)
+ {
+ String value = getHTMLAttribute(name);
+ if (value == null)
+ {
+ return -1;
+ }
+ try
+ {
+ return Integer.parseInt(value);
+ }
+ catch (NumberFormatException e)
+ {
+ return -1;
+ }
+ }
+
+ protected boolean getBooleanHTMLAttribute(String name)
+ {
+ String value = getHTMLAttribute(name);
+ return value != null;
+ }
+
+ /**
+ * Sets the value of the specified attribute.
+ * The attribute name is case insensitive.
+ */
+ protected void setHTMLAttribute(String name, String value)
+ {
+ Node attr;
+ NamedNodeMap attrs = getAttributes();
+ int len = attrs.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ attr = attrs.item(i);
+ String attrName = attr.getLocalName();
+ if (attrName == null)
+ {
+ attrName = attr.getNodeName();
+ }
+ if (attrName.equalsIgnoreCase(name))
+ {
+ if (value != null)
+ {
+ attr.setNodeValue(value);
+ }
+ else
+ {
+ attrs.removeNamedItem(attr.getNodeName());
+ }
+ return;
+ }
+ }
+ if (value != null)
+ {
+ // Create a new attribute
+ DomHTMLDocument doc = (DomHTMLDocument) getOwnerDocument();
+ // XXX namespace URI for attribute?
+ attr = doc.createAttribute(name);
+ attr.setNodeValue(value);
+ }
+ }
+
+ protected void setIntHTMLAttribute(String name, int value)
+ {
+ setHTMLAttribute(name, Integer.toString(value));
+ }
+
+ protected void setBooleanHTMLAttribute(String name, boolean value)
+ {
+ setHTMLAttribute(name, value ? name : null);
+ }
+
+ /**
+ * Returns the first parent element with the specified name.
+ */
+ protected Node getParentElement(String name)
+ {
+ for (Node parent = getParentNode(); parent != null;
+ parent = parent.getParentNode())
+ {
+ String parentName = parent.getLocalName();
+ if (parentName == null)
+ {
+ parentName = parent.getNodeName();
+ }
+ if (name.equalsIgnoreCase(parentName))
+ {
+ return parent;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the first child element with the specified name.
+ */
+ protected Node getChildElement(String name)
+ {
+ for (Node child = getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ String childName = child.getLocalName();
+ if (childName == null)
+ {
+ childName = child.getLocalName();
+ }
+ if (name.equalsIgnoreCase(childName))
+ {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the index of this element among elements of the same name,
+ * relative to its parent.
+ */
+ protected int getIndex()
+ {
+ int index = 0;
+ Node parent = getParentNode();
+ if (parent != null)
+ {
+ for (Node ctx = parent.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ if (ctx == this)
+ {
+ return index;
+ }
+ index++;
+ }
+ }
+ throw new DomDOMException(DOMException.NOT_FOUND_ERR);
+ }
+
+ protected void dispatchUIEvent(String name)
+ {
+ UIEvent event = new DomEvent.DomUIEvent(name);
+ dispatchEvent(event);
+ }
+
+ public String getId()
+ {
+ return getHTMLAttribute("id");
+ }
+
+ public void setId(String id)
+ {
+ setHTMLAttribute("id", id);
+ }
+
+ public String getTitle()
+ {
+ return getHTMLAttribute("title");
+ }
+
+ public void setTitle(String title)
+ {
+ setHTMLAttribute("title", title);
+ }
+
+ public String getLang()
+ {
+ return getHTMLAttribute("lang");
+ }
+
+ public void setLang(String lang)
+ {
+ setHTMLAttribute("lang", lang);
+ }
+
+ public String getDir()
+ {
+ return getHTMLAttribute("dir");
+ }
+
+ public void setDir(String dir)
+ {
+ setHTMLAttribute("dir", dir);
+ }
+
+ public String getClassName()
+ {
+ return getHTMLAttribute("class");
+ }
+
+ public void setClassName(String className)
+ {
+ setHTMLAttribute("class", className);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java
new file mode 100644
index 0000000..2c85772
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java
@@ -0,0 +1,65 @@
+/* DomHTMLFieldSetElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLFieldSetElement;
+import org.w3c.dom.html2.HTMLFormElement;
+
+/**
+ * An HTML 'FIELDSET' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLFieldSetElement
+ extends DomHTMLElement
+ implements HTMLFieldSetElement
+{
+
+ protected DomHTMLFieldSetElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public HTMLFormElement getForm()
+ {
+ return (HTMLFormElement) getParentElement("form");
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java
new file mode 100644
index 0000000..08bd349
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java
@@ -0,0 +1,89 @@
+/* DomHTMLFontElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLFontElement;
+
+/**
+ * An HTML 'FONT' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLFontElement
+ extends DomHTMLElement
+ implements HTMLFontElement
+{
+
+ protected DomHTMLFontElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getColor()
+ {
+ return getHTMLAttribute("color");
+ }
+
+ public void setColor(String color)
+ {
+ setHTMLAttribute("color", color);
+ }
+
+ public String getFace()
+ {
+ return getHTMLAttribute("face");
+ }
+
+ public void setFace(String face)
+ {
+ setHTMLAttribute("face", face);
+ }
+
+ public String getSize()
+ {
+ return getHTMLAttribute("size");
+ }
+
+ public void setSize(String size)
+ {
+ setHTMLAttribute("size", size);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java
new file mode 100644
index 0000000..119d97e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java
@@ -0,0 +1,150 @@
+/* DomHTMLFormElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLCollection;
+import org.w3c.dom.html2.HTMLFormElement;
+
+/**
+ * An HTML 'FORM' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLFormElement
+ extends DomHTMLElement
+ implements HTMLFormElement
+{
+
+ protected DomHTMLFormElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public HTMLCollection getElements()
+ {
+ DomHTMLCollection ret =
+ new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this);
+ ret.addNodeName("input");
+ ret.addNodeName("button");
+ ret.addNodeName("select");
+ ret.addNodeName("textarea");
+ ret.addNodeName("isindex");
+ ret.addNodeName("label");
+ ret.addNodeName("option");
+ ret.evaluate();
+ return ret;
+ }
+
+ public int getLength()
+ {
+ return getElements().getLength();
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public String getAcceptCharset()
+ {
+ return getHTMLAttribute("accept-charset");
+ }
+
+ public void setAcceptCharset(String acceptCharset)
+ {
+ setHTMLAttribute("accept-charset", acceptCharset);
+ }
+
+ public String getAction()
+ {
+ return getHTMLAttribute("action");
+ }
+
+ public void setAction(String action)
+ {
+ setHTMLAttribute("action", action);
+ }
+
+ public String getEnctype()
+ {
+ return getHTMLAttribute("enctype");
+ }
+
+ public void setEnctype(String enctype)
+ {
+ setHTMLAttribute("enctype", enctype);
+ }
+
+ public String getMethod()
+ {
+ return getHTMLAttribute("method");
+ }
+
+ public void setMethod(String method)
+ {
+ setHTMLAttribute("method", method);
+ }
+
+ public String getTarget()
+ {
+ return getHTMLAttribute("target");
+ }
+
+ public void setTarget(String target)
+ {
+ setHTMLAttribute("target", target);
+ }
+
+ public void submit()
+ {
+ dispatchUIEvent("submit");
+ }
+
+ public void reset()
+ {
+ dispatchUIEvent("reset");
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java
new file mode 100644
index 0000000..124f352
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java
@@ -0,0 +1,146 @@
+/* DomHTMLFrameElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.html2.HTMLFrameElement;
+
+/**
+ * An HTML 'FRAME' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLFrameElement
+ extends DomHTMLElement
+ implements HTMLFrameElement
+{
+
+ protected DomHTMLFrameElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getFrameBorder()
+ {
+ return getHTMLAttribute("frameborder");
+ }
+
+ public void setFrameBorder(String frameBorder)
+ {
+ setHTMLAttribute("frameborder", frameBorder);
+ }
+
+ public String getLongDesc()
+ {
+ return getHTMLAttribute("longdesc");
+ }
+
+ public void setLongDesc(String longDesc)
+ {
+ setHTMLAttribute("longdesc", longDesc);
+ }
+
+ public String getMarginHeight()
+ {
+ return getHTMLAttribute("marginheight");
+ }
+
+ public void setMarginHeight(String marginHeight)
+ {
+ setHTMLAttribute("marginheight", marginHeight);
+ }
+
+ public String getMarginWidth()
+ {
+ return getHTMLAttribute("marginwidth");
+ }
+
+ public void setMarginWidth(String marginWidth)
+ {
+ setHTMLAttribute("marginwidth", marginWidth);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public boolean getNoResize()
+ {
+ return getBooleanHTMLAttribute("noresize");
+ }
+
+ public void setNoResize(boolean noResize)
+ {
+ setBooleanHTMLAttribute("noresize", noResize);
+ }
+
+ public String getScrolling()
+ {
+ return getHTMLAttribute("scrolling");
+ }
+
+ public void setScrolling(String scrolling)
+ {
+ setHTMLAttribute("scrolling", scrolling);
+ }
+
+ public String getSrc()
+ {
+ return getHTMLAttribute("src");
+ }
+
+ public void setSrc(String src)
+ {
+ setHTMLAttribute("src", src);
+ }
+
+ public Document getContentDocument()
+ {
+ // TODO getContentDocument
+ return null;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java
new file mode 100644
index 0000000..44d317f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java
@@ -0,0 +1,79 @@
+/* DomHTMLFrameSetElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLFrameSetElement;
+
+/**
+ * An HTML 'FRAMESET' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLFrameSetElement
+ extends DomHTMLElement
+ implements HTMLFrameSetElement
+{
+
+ protected DomHTMLFrameSetElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getCols()
+ {
+ return getHTMLAttribute("cols");
+ }
+
+ public void setCols(String cols)
+ {
+ setHTMLAttribute("cols", cols);
+ }
+
+ public String getRows()
+ {
+ return getHTMLAttribute("rows");
+ }
+
+ public void setRows(String rows)
+ {
+ setHTMLAttribute("rows", rows);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java
new file mode 100644
index 0000000..d1b4801
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java
@@ -0,0 +1,99 @@
+/* DomHTMLHRElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLHRElement;
+
+/**
+ * An HTML 'HR' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLHRElement
+ extends DomHTMLElement
+ implements HTMLHRElement
+{
+
+ protected DomHTMLHRElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+ public boolean getNoShade()
+ {
+ return getBooleanHTMLAttribute("noshade");
+ }
+
+ public void setNoShade(boolean noShade)
+ {
+ setBooleanHTMLAttribute("noshade", noShade);
+ }
+
+ public String getSize()
+ {
+ return getHTMLAttribute("size");
+ }
+
+ public void setSize(String size)
+ {
+ setHTMLAttribute("size", size);
+ }
+
+ public String getWidth()
+ {
+ return getHTMLAttribute("width");
+ }
+
+ public void setWidth(String width)
+ {
+ setHTMLAttribute("width", width);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java
new file mode 100644
index 0000000..f68e8c7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLHeadElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLHeadElement;
+
+/**
+ * An HTML 'HEAD' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLHeadElement
+ extends DomHTMLElement
+ implements HTMLHeadElement
+{
+
+ protected DomHTMLHeadElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getProfile()
+ {
+ return getHTMLAttribute("profile");
+ }
+
+ public void setProfile(String profile)
+ {
+ setHTMLAttribute("profile", profile);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java
new file mode 100644
index 0000000..f1427ad
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLHeadingElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLHeadingElement;
+
+/**
+ * An HTML 'H1', 'H2', 'H3', 'H4', 'H5', or 'H6' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLHeadingElement
+ extends DomHTMLElement
+ implements HTMLHeadingElement
+{
+
+ protected DomHTMLHeadingElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java
new file mode 100644
index 0000000..95d4526
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLHtmlElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLHtmlElement;
+
+/**
+ * An HTML 'HTML' top-level element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLHtmlElement
+ extends DomHTMLElement
+ implements HTMLHtmlElement
+{
+
+ protected DomHTMLHtmlElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getVersion()
+ {
+ return getHTMLAttribute("version");
+ }
+
+ public void setVersion(String version)
+ {
+ setHTMLAttribute("version", version);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java
new file mode 100644
index 0000000..c5ca75d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java
@@ -0,0 +1,166 @@
+/* DomHTMLIFrameElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.html2.HTMLIFrameElement;
+
+/**
+ * An HTML 'IFRAME' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLIFrameElement
+ extends DomHTMLElement
+ implements HTMLIFrameElement
+{
+
+ protected DomHTMLIFrameElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+ public String getFrameBorder()
+ {
+ return getHTMLAttribute("frameborder");
+ }
+
+ public void setFrameBorder(String frameBorder)
+ {
+ setHTMLAttribute("frameborder", frameBorder);
+ }
+
+ public String getHeight()
+ {
+ return getHTMLAttribute("height");
+ }
+
+ public void setHeight(String height)
+ {
+ setHTMLAttribute("height", height);
+ }
+
+ public String getLongDesc()
+ {
+ return getHTMLAttribute("longdesc");
+ }
+
+ public void setLongDesc(String longDesc)
+ {
+ setHTMLAttribute("longdesc", longDesc);
+ }
+
+ public String getMarginHeight()
+ {
+ return getHTMLAttribute("marginheight");
+ }
+
+ public void setMarginHeight(String marginHeight)
+ {
+ setHTMLAttribute("marginheight", marginHeight);
+ }
+
+ public String getMarginWidth()
+ {
+ return getHTMLAttribute("marginwidth");
+ }
+
+ public void setMarginWidth(String marginWidth)
+ {
+ setHTMLAttribute("marginwidth", marginWidth);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public String getScrolling()
+ {
+ return getHTMLAttribute("scrolling");
+ }
+
+ public void setScrolling(String scrolling)
+ {
+ setHTMLAttribute("scrolling", scrolling);
+ }
+
+ public String getSrc()
+ {
+ return getHTMLAttribute("src");
+ }
+
+ public void setSrc(String src)
+ {
+ setHTMLAttribute("src", src);
+ }
+
+ public String getWidth()
+ {
+ return getHTMLAttribute("width");
+ }
+
+ public void setWidth(String width)
+ {
+ setHTMLAttribute("width", width);
+ }
+
+ public Document getContentDocument()
+ {
+ // TODO getContentDocument
+ return null;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java
new file mode 100644
index 0000000..c96e5fe
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java
@@ -0,0 +1,179 @@
+/* DomHTMLImageElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLImageElement;
+
+/**
+ * An HTML 'IMG' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLImageElement
+ extends DomHTMLElement
+ implements HTMLImageElement
+{
+
+ protected DomHTMLImageElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+ public String getAlt()
+ {
+ return getHTMLAttribute("alt");
+ }
+
+ public void setAlt(String alt)
+ {
+ setHTMLAttribute("alt", alt);
+ }
+
+ public String getBorder()
+ {
+ return getHTMLAttribute("border");
+ }
+
+ public void setBorder(String border)
+ {
+ setHTMLAttribute("border", border);
+ }
+
+ public int getHeight()
+ {
+ return getIntHTMLAttribute("height");
+ }
+
+ public void setHeight(int height)
+ {
+ setIntHTMLAttribute("height", height);
+ }
+
+ public int getHspace()
+ {
+ return getIntHTMLAttribute("hspace");
+ }
+
+ public void setHspace(int hspace)
+ {
+ setIntHTMLAttribute("hspace", hspace);
+ }
+
+ public boolean getIsMap()
+ {
+ return getBooleanHTMLAttribute("ismap");
+ }
+
+ public void setIsMap(boolean isMap)
+ {
+ setBooleanHTMLAttribute("ismap", isMap);
+ }
+
+ public String getLongDesc()
+ {
+ return getHTMLAttribute("longdesc");
+ }
+
+ public void setLongDesc(String longDesc)
+ {
+ setHTMLAttribute("longdesc", longDesc);
+ }
+
+ public String getSrc()
+ {
+ return getHTMLAttribute("src");
+ }
+
+ public void setSrc(String src)
+ {
+ setHTMLAttribute("src", src);
+ }
+
+ public String getUseMap()
+ {
+ return getHTMLAttribute("usemap");
+ }
+
+ public void setUseMap(String useMap)
+ {
+ setHTMLAttribute("usemap", useMap);
+ }
+
+ public int getVspace()
+ {
+ return getIntHTMLAttribute("vspace");
+ }
+
+ public void setVspace(int vspace)
+ {
+ setIntHTMLAttribute("vspace", vspace);
+ }
+
+ public int getWidth()
+ {
+ return getIntHTMLAttribute("width");
+ }
+
+ public void setWidth(int width)
+ {
+ setIntHTMLAttribute("width", width);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java
new file mode 100644
index 0000000..9f0db08
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java
@@ -0,0 +1,67 @@
+/* DomHTMLImpl.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import gnu.xml.dom.DomImpl;
+import org.w3c.dom.Document;
+
+/**
+ * Specialised DOMImplementation for creating HTML documents.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLImpl
+ extends DomImpl
+{
+
+ protected Document createDocument()
+ {
+ return new DomHTMLDocument(this);
+ }
+
+ public Object getFeature(String feature, String version)
+ {
+ if (hasFeature(feature, version))
+ {
+ return this;
+ }
+ return null;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java
new file mode 100644
index 0000000..1dbc9c2
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java
@@ -0,0 +1,266 @@
+/* DomHTMLInputElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLFormElement;
+import org.w3c.dom.html2.HTMLInputElement;
+
+/**
+ * An HTML 'INPUT' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLInputElement
+ extends DomHTMLElement
+ implements HTMLInputElement
+{
+
+ protected String value;
+ protected Boolean checked;
+
+ protected DomHTMLInputElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getDefaultValue()
+ {
+ return getHTMLAttribute("value");
+ }
+
+ public void setDefaultValue(String defaultValue)
+ {
+ setHTMLAttribute("value", defaultValue);
+ }
+
+ public boolean getDefaultChecked()
+ {
+ return getBooleanHTMLAttribute("checked");
+ }
+
+ public void setDefaultChecked(boolean defaultChecked)
+ {
+ setBooleanHTMLAttribute("checked", defaultChecked);
+ }
+
+ public HTMLFormElement getForm()
+ {
+ return (HTMLFormElement) getParentElement("form");
+ }
+
+ public String getAccept()
+ {
+ return getHTMLAttribute("accept");
+ }
+
+ public void setAccept(String accept)
+ {
+ setHTMLAttribute("accept", accept);
+ }
+
+ public String getAccessKey()
+ {
+ return getHTMLAttribute("accesskey");
+ }
+
+ public void setAccessKey(String accessKey)
+ {
+ setHTMLAttribute("accesskey", accessKey);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+ public String getAlt()
+ {
+ return getHTMLAttribute("alt");
+ }
+
+ public void setAlt(String alt)
+ {
+ setHTMLAttribute("alt", alt);
+ }
+
+ public boolean getChecked()
+ {
+ if (checked == null)
+ {
+ checked = Boolean.valueOf(getDefaultChecked());
+ }
+ return checked.booleanValue();
+ }
+
+ public void setChecked(boolean checked)
+ {
+ this.checked = Boolean.valueOf(checked);
+ }
+
+ public boolean getDisabled()
+ {
+ return getBooleanHTMLAttribute("disabled");
+ }
+
+ public void setDisabled(boolean disabled)
+ {
+ setBooleanHTMLAttribute("disabled", disabled);
+ }
+
+ public int getMaxLength()
+ {
+ return getIntHTMLAttribute("maxLength");
+ }
+
+ public void setMaxLength(int maxLength)
+ {
+ setIntHTMLAttribute("maxLength", maxLength);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public boolean getReadOnly()
+ {
+ return getBooleanHTMLAttribute("readonly");
+ }
+
+ public void setReadOnly(boolean readOnly)
+ {
+ setBooleanHTMLAttribute("readonly", readOnly);
+ }
+
+ public int getSize()
+ {
+ return getIntHTMLAttribute("size");
+ }
+
+ public void setSize(int size)
+ {
+ setIntHTMLAttribute("size", size);
+ }
+
+ public String getSrc()
+ {
+ return getHTMLAttribute("src");
+ }
+
+ public void setSrc(String src)
+ {
+ setHTMLAttribute("src", src);
+ }
+
+ public int getTabIndex()
+ {
+ return getIntHTMLAttribute("tabindex");
+ }
+
+ public void setTabIndex(int tabIndex)
+ {
+ setIntHTMLAttribute("tabindex", tabIndex);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public void setType(String type)
+ {
+ setHTMLAttribute("type", type);
+ }
+
+ public String getUseMap()
+ {
+ return getHTMLAttribute("usemap");
+ }
+
+ public void setUseMap(String useMap)
+ {
+ setHTMLAttribute("usemap", useMap);
+ }
+
+ public String getValue()
+ {
+ if (value == null)
+ {
+ value = getDefaultValue();
+ }
+ return value;
+ }
+
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+ public void blur()
+ {
+ dispatchUIEvent("blur");
+ }
+
+ public void focus()
+ {
+ dispatchUIEvent("focus");
+ }
+
+ public void select()
+ {
+ dispatchUIEvent("select");
+ }
+
+ public void click()
+ {
+ dispatchUIEvent("click");
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java
new file mode 100644
index 0000000..087f4a0
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java
@@ -0,0 +1,75 @@
+/* DomHTMLIsIndexElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLFormElement;
+import org.w3c.dom.html2.HTMLIsIndexElement;
+
+/**
+ * An HTML 'ISINDEX' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLIsIndexElement
+ extends DomHTMLElement
+ implements HTMLIsIndexElement
+{
+
+ protected DomHTMLIsIndexElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public HTMLFormElement getForm()
+ {
+ return (HTMLFormElement) getParentElement("form");
+ }
+
+ public String getPrompt()
+ {
+ return getHTMLAttribute("prompt");
+ }
+
+ public void setPrompt(String prompt)
+ {
+ setHTMLAttribute("prompt", prompt);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java
new file mode 100644
index 0000000..11eccdf
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java
@@ -0,0 +1,79 @@
+/* DomHTMLLIElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLLIElement;
+
+/**
+ * An HTML 'LI' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLLIElement
+ extends DomHTMLElement
+ implements HTMLLIElement
+{
+
+ protected DomHTMLLIElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public void setType(String type)
+ {
+ setHTMLAttribute("type", type);
+ }
+
+ public int getValue()
+ {
+ return getIntHTMLAttribute("value");
+ }
+
+ public void setValue(int value)
+ {
+ setIntHTMLAttribute("value", value);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java
new file mode 100644
index 0000000..c0cc39f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java
@@ -0,0 +1,85 @@
+/* DomHTMLLabelElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLFormElement;
+import org.w3c.dom.html2.HTMLLabelElement;
+
+/**
+ * An HTML 'LABEL' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLLabelElement
+ extends DomHTMLElement
+ implements HTMLLabelElement
+{
+
+ protected DomHTMLLabelElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public HTMLFormElement getForm()
+ {
+ return (HTMLFormElement) getParentElement("form");
+ }
+
+ public String getAccessKey()
+ {
+ return getHTMLAttribute("accesskey");
+ }
+
+ public void setAccessKey(String accessKey)
+ {
+ setHTMLAttribute("accesskey", accessKey);
+ }
+
+ public String getHtmlFor()
+ {
+ return getHTMLAttribute("for");
+ }
+
+ public void setHtmlFor(String htmlFor)
+ {
+ setHTMLAttribute("for", htmlFor);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java
new file mode 100644
index 0000000..a500f8f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java
@@ -0,0 +1,85 @@
+/* DomHTMLLegendElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLFormElement;
+import org.w3c.dom.html2.HTMLLegendElement;
+
+/**
+ * An HTML 'LEGEND' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLLegendElement
+ extends DomHTMLElement
+ implements HTMLLegendElement
+{
+
+ protected DomHTMLLegendElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public HTMLFormElement getForm()
+ {
+ return (HTMLFormElement) getParentElement("form");
+ }
+
+ public String getAccessKey()
+ {
+ return getHTMLAttribute("accesskey");
+ }
+
+ public void setAccessKey(String accessKey)
+ {
+ setHTMLAttribute("accesskey", accessKey);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java
new file mode 100644
index 0000000..127726e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java
@@ -0,0 +1,149 @@
+/* DomHTMLLinkElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLLinkElement;
+
+/**
+ * An HTML 'LINK' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLLinkElement
+ extends DomHTMLElement
+ implements HTMLLinkElement
+{
+
+ protected DomHTMLLinkElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public boolean getDisabled()
+ {
+ return getBooleanHTMLAttribute("disabled");
+ }
+
+ public void setDisabled(boolean disabled)
+ {
+ setBooleanHTMLAttribute("disabled", disabled);
+ }
+
+ public String getCharset()
+ {
+ return getHTMLAttribute("charset");
+ }
+
+ public void setCharset(String charset)
+ {
+ setHTMLAttribute("charset", charset);
+ }
+
+ public String getHref()
+ {
+ return getHTMLAttribute("href");
+ }
+
+ public void setHref(String href)
+ {
+ setHTMLAttribute("href", href);
+ }
+
+ public String getHreflang()
+ {
+ return getHTMLAttribute("hreflang");
+ }
+
+ public void setHreflang(String hreflang)
+ {
+ setHTMLAttribute("hreflang", hreflang);
+ }
+
+ public String getMedia()
+ {
+ return getHTMLAttribute("media");
+ }
+
+ public void setMedia(String media)
+ {
+ setHTMLAttribute("media", media);
+ }
+
+ public String getRel()
+ {
+ return getHTMLAttribute("rel");
+ }
+
+ public void setRel(String rel)
+ {
+ setHTMLAttribute("rel", rel);
+ }
+
+ public String getRev()
+ {
+ return getHTMLAttribute("rev");
+ }
+
+ public void setRev(String rev)
+ {
+ setHTMLAttribute("rev", rev);
+ }
+
+ public String getTarget()
+ {
+ return getHTMLAttribute("target");
+ }
+
+ public void setTarget(String target)
+ {
+ setHTMLAttribute("target", target);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public void setType(String type)
+ {
+ setHTMLAttribute("type", type);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java
new file mode 100644
index 0000000..1f7182f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java
@@ -0,0 +1,79 @@
+/* DomHTMLMapElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLCollection;
+import org.w3c.dom.html2.HTMLMapElement;
+
+/**
+ * An HTML 'MAP' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLMapElement
+ extends DomHTMLElement
+ implements HTMLMapElement
+{
+
+ protected DomHTMLMapElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public HTMLCollection getAreas()
+ {
+ DomHTMLCollection ret =
+ new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this);
+ ret.addNodeName("area");
+ ret.evaluate();
+ return ret;
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java
new file mode 100644
index 0000000..17f6f58
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLMenuElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLMenuElement;
+
+/**
+ * An HTML 'MENU' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLMenuElement
+ extends DomHTMLElement
+ implements HTMLMenuElement
+{
+
+ protected DomHTMLMenuElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public boolean getCompact()
+ {
+ return getBooleanHTMLAttribute("compact");
+ }
+
+ public void setCompact(boolean compact)
+ {
+ setBooleanHTMLAttribute("compact", compact);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java
new file mode 100644
index 0000000..1a04405
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java
@@ -0,0 +1,99 @@
+/* DomHTMLMetaElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLMetaElement;
+
+/**
+ * An HTML 'META' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLMetaElement
+ extends DomHTMLElement
+ implements HTMLMetaElement
+{
+
+ protected DomHTMLMetaElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getContent()
+ {
+ return getHTMLAttribute("content");
+ }
+
+ public void setContent(String content)
+ {
+ setHTMLAttribute("content", content);
+ }
+
+ public String getHttpEquiv()
+ {
+ return getHTMLAttribute("http-equiv");
+ }
+
+ public void setHttpEquiv(String httpEquiv)
+ {
+ setHTMLAttribute("http-equiv", httpEquiv);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public String getScheme()
+ {
+ return getHTMLAttribute("scheme");
+ }
+
+ public void setScheme(String scheme)
+ {
+ setHTMLAttribute("scheme", scheme);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java
new file mode 100644
index 0000000..493f724
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java
@@ -0,0 +1,79 @@
+/* DomHTMLModElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLModElement;
+
+/**
+ * An HTML 'INS' or 'DEL' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLModElement
+ extends DomHTMLElement
+ implements HTMLModElement
+{
+
+ protected DomHTMLModElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getCite()
+ {
+ return getHTMLAttribute("cite");
+ }
+
+ public void setCite(String cite)
+ {
+ setHTMLAttribute("cite", cite);
+ }
+
+ public String getDateTime()
+ {
+ return getHTMLAttribute("datetime");
+ }
+
+ public void setDateTime(String dateTime)
+ {
+ setHTMLAttribute("datetime", dateTime);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java
new file mode 100644
index 0000000..fb98cf4
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java
@@ -0,0 +1,89 @@
+/* DomHTMLOListElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLOListElement;
+
+/**
+ * An HTML 'OL' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLOListElement
+ extends DomHTMLElement
+ implements HTMLOListElement
+{
+
+ protected DomHTMLOListElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public boolean getCompact()
+ {
+ return getBooleanHTMLAttribute("compact");
+ }
+
+ public void setCompact(boolean compact)
+ {
+ setBooleanHTMLAttribute("compact", compact);
+ }
+
+ public int getStart()
+ {
+ return getIntHTMLAttribute("start");
+ }
+
+ public void setStart(int start)
+ {
+ setIntHTMLAttribute("start", start);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public void setType(String type)
+ {
+ setHTMLAttribute("type", type);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java
new file mode 100644
index 0000000..fdea9b1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java
@@ -0,0 +1,242 @@
+/* DomHTMLObjectElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.html2.HTMLFormElement;
+import org.w3c.dom.html2.HTMLObjectElement;
+
+/**
+ * An HTML 'OBJECT' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLObjectElement
+ extends DomHTMLElement
+ implements HTMLObjectElement
+{
+
+ protected DomHTMLObjectElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public HTMLFormElement getForm()
+ {
+ return (HTMLFormElement) getParentElement("form");
+ }
+
+ public String getCode()
+ {
+ return getHTMLAttribute("code");
+ }
+
+ public void setCode(String code)
+ {
+ setHTMLAttribute("code", code);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+ public String getArchive()
+ {
+ return getHTMLAttribute("archive");
+ }
+
+ public void setArchive(String archive)
+ {
+ setHTMLAttribute("archive", archive);
+ }
+
+ public String getBorder()
+ {
+ return getHTMLAttribute("border");
+ }
+
+ public void setBorder(String border)
+ {
+ setHTMLAttribute("border", border);
+ }
+
+ public String getCodeBase()
+ {
+ return getHTMLAttribute("codebase");
+ }
+
+ public void setCodeBase(String codeBase)
+ {
+ setHTMLAttribute("codebase", codeBase);
+ }
+
+ public String getCodeType()
+ {
+ return getHTMLAttribute("codetype");
+ }
+
+ public void setCodeType(String codeType)
+ {
+ setHTMLAttribute("codetype", codeType);
+ }
+
+ public String getData()
+ {
+ return getHTMLAttribute("data");
+ }
+
+ public void setData(String data)
+ {
+ setHTMLAttribute("data", data);
+ }
+
+ public boolean getDeclare()
+ {
+ return getBooleanHTMLAttribute("declare");
+ }
+
+ public void setDeclare(boolean declare)
+ {
+ setBooleanHTMLAttribute("declare", declare);
+ }
+
+ public String getHeight()
+ {
+ return getHTMLAttribute("height");
+ }
+
+ public void setHeight(String height)
+ {
+ setHTMLAttribute("height", height);
+ }
+
+ public int getHspace()
+ {
+ return getIntHTMLAttribute("hspace");
+ }
+
+ public void setHspace(int hspace)
+ {
+ setIntHTMLAttribute("hspace", hspace);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public String getStandby()
+ {
+ return getHTMLAttribute("standby");
+ }
+
+ public void setStandby(String standby)
+ {
+ setHTMLAttribute("standby", standby);
+ }
+
+ public int getTabIndex()
+ {
+ return getIntHTMLAttribute("tabindex");
+ }
+
+ public void setTabIndex(int tabIndex)
+ {
+ setIntHTMLAttribute("tabindex", tabIndex);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public void setType(String type)
+ {
+ setHTMLAttribute("type", type);
+ }
+
+ public String getUseMap()
+ {
+ return getHTMLAttribute("usemap");
+ }
+
+ public void setUseMap(String useMap)
+ {
+ setHTMLAttribute("usemap", useMap);
+ }
+
+ public int getVspace()
+ {
+ return getIntHTMLAttribute("vspace");
+ }
+
+ public void setVspace(int vspace)
+ {
+ setIntHTMLAttribute("vspace", vspace);
+ }
+
+ public String getWidth()
+ {
+ return getHTMLAttribute("width");
+ }
+
+ public void setWidth(String width)
+ {
+ setHTMLAttribute("width", width);
+ }
+
+ public Document getContentDocument()
+ {
+ // TODO getContentDocument
+ return null;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java
new file mode 100644
index 0000000..76545e1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java
@@ -0,0 +1,79 @@
+/* DomHTMLOptGroupElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLOptGroupElement;
+
+/**
+ * An HTML 'OPTGROUP' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLOptGroupElement
+ extends DomHTMLElement
+ implements HTMLOptGroupElement
+{
+
+ protected DomHTMLOptGroupElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public boolean getDisabled()
+ {
+ return getBooleanHTMLAttribute("disabled");
+ }
+
+ public void setDisabled(boolean disabled)
+ {
+ setBooleanHTMLAttribute("disabled", disabled);
+ }
+
+ public String getLabel()
+ {
+ return getHTMLAttribute("label");
+ }
+
+ public void setLabel(String label)
+ {
+ setHTMLAttribute("label", label);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java
new file mode 100644
index 0000000..69c059d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java
@@ -0,0 +1,131 @@
+/* DomHTMLOptionElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLFormElement;
+import org.w3c.dom.html2.HTMLOptionElement;
+
+/**
+ * An HTML 'OPTION' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLOptionElement
+ extends DomHTMLElement
+ implements HTMLOptionElement
+{
+
+ protected Boolean selected;
+
+ protected DomHTMLOptionElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public HTMLFormElement getForm()
+ {
+ return (HTMLFormElement) getParentElement("form");
+ }
+
+ public boolean getDefaultSelected()
+ {
+ return getBooleanHTMLAttribute("selected");
+ }
+
+ public void setDefaultSelected(boolean defaultSelected)
+ {
+ setBooleanHTMLAttribute("selected", defaultSelected);
+ }
+
+ public String getText()
+ {
+ return getTextContent();
+ }
+
+ public int getIndex()
+ {
+ return super.getIndex();
+ }
+
+ public boolean getDisabled()
+ {
+ return getBooleanHTMLAttribute("disabled");
+ }
+
+ public void setDisabled(boolean disabled)
+ {
+ setBooleanHTMLAttribute("disabled", disabled);
+ }
+
+ public String getLabel()
+ {
+ return getHTMLAttribute("label");
+ }
+
+ public void setLabel(String label)
+ {
+ setHTMLAttribute("label", label);
+ }
+
+ public boolean getSelected()
+ {
+ if (selected == null)
+ {
+ selected = Boolean.valueOf(getDefaultSelected());
+ }
+ return selected.booleanValue();
+ }
+
+ public void setSelected(boolean selected)
+ {
+ this.selected = Boolean.valueOf(selected);
+ }
+
+ public String getValue()
+ {
+ return getHTMLAttribute("value");
+ }
+
+ public void setValue(String value)
+ {
+ setHTMLAttribute("value", value);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java
new file mode 100644
index 0000000..2a8c4f6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLParagraphElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLParagraphElement;
+
+/**
+ * An HTML 'P' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLParagraphElement
+ extends DomHTMLElement
+ implements HTMLParagraphElement
+{
+
+ protected DomHTMLParagraphElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java
new file mode 100644
index 0000000..81c6559
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java
@@ -0,0 +1,99 @@
+/* DomHTMLParamElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLParamElement;
+
+/**
+ * An HTML 'PARAM' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLParamElement
+ extends DomHTMLElement
+ implements HTMLParamElement
+{
+
+ protected DomHTMLParamElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public void setType(String type)
+ {
+ setHTMLAttribute("type", type);
+ }
+
+ public String getValue()
+ {
+ return getHTMLAttribute("value");
+ }
+
+ public void setValue(String value)
+ {
+ setHTMLAttribute("value", value);
+ }
+
+ public String getValueType()
+ {
+ return getHTMLAttribute("valuetype");
+ }
+
+ public void setValueType(String valueType)
+ {
+ setHTMLAttribute("valuetype", valueType);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java
new file mode 100644
index 0000000..7b44562
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java
@@ -0,0 +1,266 @@
+/* DomHTMLParser.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import gnu.javax.swing.text.html.parser.support.Parser;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.parser.DTD;
+import javax.swing.text.html.parser.TagElement;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.html2.HTMLDocument;
+
+/**
+ * This parser reads HTML from the given stream and stores into
+ * {@link HTMLDocument}. The HTML tag becomes the {@link Node}.
+ * The tag attributes become the node attributes. The text inside
+ * HTML tag is inserted as one or several text nodes. The nested
+ * HTML tags are inserted as child nodes.
+ *
+ * If the strict tree structure, closing the tag means closing all
+ * nested tags. To work around this, this parser closes the nested
+ * tags and immediately reopens them after the closed tag.
+ * In this way, <b><i>c</b>d
+ * is parsed as <b><i>c</i></b><i>d
.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class DomHTMLParser
+ extends gnu.javax.swing.text.html.parser.support.Parser
+{
+ /**
+ * The target where HTML document will be inserted.
+ */
+ protected DomHTMLDocument document;
+
+ /**
+ * The subsequently created new nodes will be inserted as the
+ * childs of this cursor.
+ */
+ protected Node cursor;
+
+ /**
+ * Create parser using the given DTD.
+ *
+ * @param dtd the DTD (for example,
+ * {@link gnu.javax.swing.text.html.parser.HTML_401F}).
+ */
+ public DomHTMLParser(DTD dtd)
+ {
+ super(dtd);
+ }
+
+ /**
+ * Parse SGML insertion ( <! ... > ).
+ * Currently just treats it as comment.
+ */
+ public boolean parseMarkupDeclarations(StringBuffer strBuff)
+ throws java.io.IOException
+ {
+ Node c = document.createComment(strBuff.toString());
+ cursor.appendChild(c);
+ return false;
+ }
+
+ /**
+ * Read the document, present in the given stream, and
+ * return the corresponding {@link HTMLDocument}.
+ *
+ * @param input a stream to read from.
+ * @return a document, reflecting the structure of the provided HTML
+ * text.
+ *
+ * @throws IOException if the reader throws one.
+ */
+ public HTMLDocument parseDocument(Reader input)
+ throws IOException
+ {
+ try
+ {
+ document = new DomHTMLDocument();
+
+ cursor = document;
+
+ parse(input);
+
+ DomHTMLDocument h = document;
+ document = null;
+ return h;
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ throw new IOException("Exception: " + ex.getMessage());
+ }
+ }
+
+ /**
+ * Create a new node.
+ * @param name the name of node, case insensitive.
+ * @return the created node.
+ */
+ protected Node createNode(String name)
+ {
+ Node new_node = document.createElement(name.toLowerCase());
+ AttributeSet hatts = getAttributes();
+ NamedNodeMap natts = new_node.getAttributes();
+
+ Enumeration enumeration = hatts.getAttributeNames();
+ Object key;
+ Node attribute;
+
+ while (hatts != null)
+ {
+ while (enumeration.hasMoreElements())
+ {
+ key = enumeration.nextElement();
+ attribute = document.createAttribute(key.toString());
+ attribute.setNodeValue(hatts.getAttribute(key).toString());
+ natts.setNamedItem(attribute);
+ }
+
+ // The default values are stored in a parent node.
+ hatts = hatts.getResolveParent();
+ }
+
+ return new_node;
+ }
+
+ /**
+ * Handle comment by inserting the comment node.
+ * @param text the comment text.
+ */
+ protected void handleComment(char[] text)
+ {
+ Node c = document.createComment(new String(text));
+ cursor.appendChild(c);
+ }
+
+ /**
+ * Handle the tag with no content.
+ * @param tag the tag to handle.
+ */
+ protected void handleEmptyTag(TagElement tag)
+ {
+ String name = tag.getHTMLTag().toString();
+
+ if (name.equalsIgnoreCase("#pcdata"))
+ return;
+
+ Node c = createNode(name);
+ cursor.appendChild(c);
+ }
+
+ /**
+ * Close the given tag. Close and reopen all nested tags.
+ * @param tag the tag to close.
+ */
+ protected void handleEndTag(TagElement tag)
+ {
+ String name = tag.getHTMLTag().toString();
+ String nname = cursor.getNodeName();
+
+ // Closing the current tag.
+ if (nname != null && nname.equalsIgnoreCase(name))
+ {
+ cursor = cursor.getParentNode();
+ }
+ else
+ {
+ Node nCursor = cursor.getParentNode();
+
+ // Remember the opened nodes.
+ LinkedList open = new LinkedList();
+ Node close = cursor;
+ while (close != null && !close.getNodeName().equalsIgnoreCase(name))
+ {
+ if (close != document)
+ open.addFirst(close);
+ close = close.getParentNode();
+ }
+
+ if (close == null)
+ cursor = document;
+ else
+ cursor = close.getParentNode();
+
+ // Insert the copies of the opened nodes.
+ Iterator iter = open.iterator();
+ while (iter.hasNext())
+ {
+ Node item = (Node) iter.next();
+ Node copy = item.cloneNode(true);
+ cursor.appendChild(copy);
+ cursor = copy;
+ }
+ }
+ }
+
+ /**
+ * Handle the start tag by inserting the HTML element.
+ * @param tag the tag to handle.
+ */
+ protected void handleStartTag(TagElement tag)
+ {
+ HTML.Tag h = tag.getHTMLTag();
+ Node c = createNode(h.toString());
+ cursor.appendChild(c);
+ cursor = c;
+ }
+
+ /**
+ * Handle text by inserting the text node.
+ * @param text the text to insert.
+ */
+ protected void handleText(char[] text)
+ {
+ Node c = document.createTextNode(text, 0, text.length);
+ cursor.appendChild(c);
+ }
+}
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java
new file mode 100644
index 0000000..9b36a28
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLPreElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLPreElement;
+
+/**
+ * An HTML 'PRE' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLPreElement
+ extends DomHTMLElement
+ implements HTMLPreElement
+{
+
+ protected DomHTMLPreElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public int getWidth()
+ {
+ return getIntHTMLAttribute("width");
+ }
+
+ public void setWidth(int width)
+ {
+ setIntHTMLAttribute("width", width);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java
new file mode 100644
index 0000000..678a5ad
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLQuoteElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLQuoteElement;
+
+/**
+ * An HTML 'Q' or 'BLOCKQUOTE' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLQuoteElement
+ extends DomHTMLElement
+ implements HTMLQuoteElement
+{
+
+ protected DomHTMLQuoteElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getCite()
+ {
+ return getHTMLAttribute("cite");
+ }
+
+ public void setCite(String cite)
+ {
+ setHTMLAttribute("cite", cite);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java
new file mode 100644
index 0000000..8f8fff5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java
@@ -0,0 +1,129 @@
+/* DomHTMLScriptElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLScriptElement;
+
+/**
+ * An HTML 'SCRIPT' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLScriptElement
+ extends DomHTMLElement
+ implements HTMLScriptElement
+{
+
+ protected DomHTMLScriptElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getText()
+ {
+ return getTextContent();
+ }
+
+ public void setText(String text)
+ {
+ setTextContent(text);
+ }
+
+ public String getHtmlFor()
+ {
+ return getHTMLAttribute("for");
+ }
+
+ public void setHtmlFor(String htmlFor)
+ {
+ setHTMLAttribute("for", htmlFor);
+ }
+
+ public String getEvent()
+ {
+ return getHTMLAttribute("event");
+ }
+
+ public void setEvent(String event)
+ {
+ setHTMLAttribute("event", event);
+ }
+
+ public String getCharset()
+ {
+ return getHTMLAttribute("charset");
+ }
+
+ public void setCharset(String charset)
+ {
+ setHTMLAttribute("charset", charset);
+ }
+
+ public boolean getDefer()
+ {
+ return getBooleanHTMLAttribute("defer");
+ }
+
+ public void setDefer(boolean defer)
+ {
+ setBooleanHTMLAttribute("defer", defer);
+ }
+
+ public String getSrc()
+ {
+ return getHTMLAttribute("src");
+ }
+
+ public void setSrc(String src)
+ {
+ setHTMLAttribute("src", src);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public void setType(String type)
+ {
+ setHTMLAttribute("type", type);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java
new file mode 100644
index 0000000..09752e1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java
@@ -0,0 +1,211 @@
+/* DomHTMLSelectElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import gnu.xml.dom.DomDOMException;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.html2.HTMLElement;
+import org.w3c.dom.html2.HTMLFormElement;
+import org.w3c.dom.html2.HTMLOptionElement;
+import org.w3c.dom.html2.HTMLOptionsCollection;
+import org.w3c.dom.html2.HTMLSelectElement;
+
+/**
+ * An HTML 'SELECT' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLSelectElement
+ extends DomHTMLElement
+ implements HTMLSelectElement
+{
+
+ protected DomHTMLSelectElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public int getSelectedIndex()
+ {
+ HTMLOptionsCollection options = getOptions();
+ int len = options.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ HTMLOptionElement option = (HTMLOptionElement) options.item(i);
+ if (option.getSelected())
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public void setSelectedIndex(int selectedIndex)
+ {
+ HTMLOptionsCollection options = getOptions();
+ int len = options.getLength();
+ if (selectedIndex < 0 || selectedIndex >= len)
+ {
+ throw new DomDOMException(DOMException.INDEX_SIZE_ERR);
+ }
+ for (int i = 0; i < len; i++)
+ {
+ HTMLOptionElement option = (HTMLOptionElement) options.item(i);
+ option.setSelected(i == selectedIndex);
+ }
+ }
+
+ public String getValue()
+ {
+ return getHTMLAttribute("value");
+ }
+
+ public void setValue(String value)
+ {
+ setHTMLAttribute("value", value);
+ }
+
+ public int getLength()
+ {
+ return getIntHTMLAttribute("length");
+ }
+
+ public void setLength(int length)
+ {
+ setIntHTMLAttribute("length", length);
+ }
+
+ public HTMLFormElement getForm()
+ {
+ return (HTMLFormElement) getParentElement("form");
+ }
+
+ public HTMLOptionsCollection getOptions()
+ {
+ DomHTMLCollection ret =
+ new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this);
+ ret.addNodeName("option");
+ ret.evaluate();
+ return ret;
+ }
+
+ public boolean getDisabled()
+ {
+ return getBooleanHTMLAttribute("disabled");
+ }
+
+ public void setDisabled(boolean disabled)
+ {
+ setBooleanHTMLAttribute("disabled", disabled);
+ }
+
+ public boolean getMultiple()
+ {
+ return getBooleanHTMLAttribute("multiple");
+ }
+
+ public void setMultiple(boolean multiple)
+ {
+ setBooleanHTMLAttribute("multiple", multiple);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public int getSize()
+ {
+ return getIntHTMLAttribute("size");
+ }
+
+ public void setSize(int size)
+ {
+ setIntHTMLAttribute("size", size);
+ }
+
+ public int getTabIndex()
+ {
+ return getIntHTMLAttribute("tabindex");
+ }
+
+ public void setTabIndex(int tabIndex)
+ {
+ setIntHTMLAttribute("tabindex", tabIndex);
+ }
+
+ public void add(HTMLElement element, HTMLElement before)
+ {
+ insertBefore(before, element);
+ }
+
+ public void remove(int index)
+ {
+ HTMLOptionsCollection options = getOptions();
+ int len = options.getLength();
+ if (index < 0 || index >= len)
+ {
+ throw new DomDOMException(DOMException.INDEX_SIZE_ERR);
+ }
+ HTMLOptionElement option = (HTMLOptionElement) options.item(index);
+ option.getParentNode().removeChild(option);
+ }
+
+ public void blur()
+ {
+ dispatchUIEvent("blur");
+ }
+
+ public void focus()
+ {
+ dispatchUIEvent("focus");
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java
new file mode 100644
index 0000000..f6f1fcc
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java
@@ -0,0 +1,89 @@
+/* DomHTMLStyleElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLStyleElement;
+
+/**
+ * An HTML 'STYLE' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLStyleElement
+ extends DomHTMLElement
+ implements HTMLStyleElement
+{
+
+ protected DomHTMLStyleElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public boolean getDisabled()
+ {
+ return getBooleanHTMLAttribute("disabled");
+ }
+
+ public void setDisabled(boolean disabled)
+ {
+ setBooleanHTMLAttribute("disabled", disabled);
+ }
+
+ public String getMedia()
+ {
+ return getHTMLAttribute("media");
+ }
+
+ public void setMedia(String media)
+ {
+ setHTMLAttribute("media", media);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public void setType(String type)
+ {
+ setHTMLAttribute("type", type);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java
new file mode 100644
index 0000000..28ea341
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java
@@ -0,0 +1,70 @@
+/* DomHTMLTableCaptionElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLTableCaptionElement;
+
+/**
+ * An HTML 'CAPTION' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLTableCaptionElement
+ extends DomHTMLElement
+ implements HTMLTableCaptionElement
+{
+
+ protected DomHTMLTableCaptionElement(DomHTMLDocument owner,
+ String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java
new file mode 100644
index 0000000..41d33af
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java
@@ -0,0 +1,205 @@
+/* DomHTMLTableCellElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLTableCellElement;
+
+/**
+ * An HTML 'TH' or 'TD' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLTableCellElement
+ extends DomHTMLElement
+ implements HTMLTableCellElement
+{
+
+ protected DomHTMLTableCellElement(DomHTMLDocument owner,
+ String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public int getCellIndex()
+ {
+ return getIndex();
+ }
+
+ public String getAbbr()
+ {
+ return getHTMLAttribute("abbr");
+ }
+
+ public void setAbbr(String abbr)
+ {
+ setHTMLAttribute("abbr", abbr);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+ public String getAxis()
+ {
+ return getHTMLAttribute("axis");
+ }
+
+ public void setAxis(String axis)
+ {
+ setHTMLAttribute("axis", axis);
+ }
+
+ public String getBgColor()
+ {
+ return getHTMLAttribute("bgcolor");
+ }
+
+ public void setBgColor(String bgColor)
+ {
+ setHTMLAttribute("bgcolor", bgColor);
+ }
+
+ public String getCh()
+ {
+ return getHTMLAttribute("char");
+ }
+
+ public void setCh(String ch)
+ {
+ setHTMLAttribute("char", ch);
+ }
+
+ public String getChOff()
+ {
+ return getHTMLAttribute("charoff");
+ }
+
+ public void setChOff(String chOff)
+ {
+ setHTMLAttribute("charoff", chOff);
+ }
+
+ public int getColSpan()
+ {
+ return getIntHTMLAttribute("colspan");
+ }
+
+ public void setColSpan(int colSpan)
+ {
+ setIntHTMLAttribute("colspan", colSpan);
+ }
+
+ public String getHeaders()
+ {
+ return getHTMLAttribute("headers");
+ }
+
+ public void setHeaders(String headers)
+ {
+ setHTMLAttribute("headers", headers);
+ }
+
+ public String getHeight()
+ {
+ return getHTMLAttribute("height");
+ }
+
+ public void setHeight(String height)
+ {
+ setHTMLAttribute("height", height);
+ }
+
+ public boolean getNoWrap()
+ {
+ return getBooleanHTMLAttribute("nowrap");
+ }
+
+ public void setNoWrap(boolean noWrap)
+ {
+ setBooleanHTMLAttribute("nowrap", noWrap);
+ }
+
+ public int getRowSpan()
+ {
+ return getIntHTMLAttribute("rowspan");
+ }
+
+ public void setRowSpan(int rowSpan)
+ {
+ setIntHTMLAttribute("rowspan", rowSpan);
+ }
+
+ public String getScope()
+ {
+ return getHTMLAttribute("scope");
+ }
+
+ public void setScope(String scope)
+ {
+ setHTMLAttribute("scope", scope);
+ }
+
+ public String getVAlign()
+ {
+ return getHTMLAttribute("valign");
+ }
+
+ public void setVAlign(String vAlign)
+ {
+ setHTMLAttribute("valign", vAlign);
+ }
+
+ public String getWidth()
+ {
+ return getHTMLAttribute("width");
+ }
+
+ public void setWidth(String width)
+ {
+ setHTMLAttribute("width", width);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java
new file mode 100644
index 0000000..799447d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java
@@ -0,0 +1,120 @@
+/* DomHTMLTableColElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLTableColElement;
+
+/**
+ * An HTML 'COL' or 'COLGROUP' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLTableColElement
+ extends DomHTMLElement
+ implements HTMLTableColElement
+{
+
+ protected DomHTMLTableColElement(DomHTMLDocument owner,
+ String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+ public String getCh()
+ {
+ return getHTMLAttribute("char");
+ }
+
+ public void setCh(String ch)
+ {
+ setHTMLAttribute("char", ch);
+ }
+
+ public String getChOff()
+ {
+ return getHTMLAttribute("charoff");
+ }
+
+ public void setChOff(String chOff)
+ {
+ setHTMLAttribute("charoff", chOff);
+ }
+
+ public int getSpan()
+ {
+ return getIntHTMLAttribute("span");
+ }
+
+ public void setSpan(int span)
+ {
+ setIntHTMLAttribute("span", span);
+ }
+
+ public String getVAlign()
+ {
+ return getHTMLAttribute("valign");
+ }
+
+ public void setVAlign(String vAlign)
+ {
+ setHTMLAttribute("valign", vAlign);
+ }
+
+ public String getWidth()
+ {
+ return getHTMLAttribute("width");
+ }
+
+ public void setWidth(String width)
+ {
+ setHTMLAttribute("width", width);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java
new file mode 100644
index 0000000..ea92540
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java
@@ -0,0 +1,398 @@
+/* DomHTMLTableElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import gnu.xml.dom.DomDOMException;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+import org.w3c.dom.html2.HTMLCollection;
+import org.w3c.dom.html2.HTMLElement;
+import org.w3c.dom.html2.HTMLTableCaptionElement;
+import org.w3c.dom.html2.HTMLTableElement;
+import org.w3c.dom.html2.HTMLTableSectionElement;
+
+/**
+ * An HTML 'TABLE' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLTableElement
+ extends DomHTMLElement
+ implements HTMLTableElement
+{
+
+ protected DomHTMLTableElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public HTMLTableCaptionElement getCaption()
+ {
+ return (HTMLTableCaptionElement) getChildElement("caption");
+ }
+
+ public void setCaption(HTMLTableCaptionElement caption)
+ {
+ HTMLTableCaptionElement ref = getCaption();
+ if (ref == null)
+ {
+ appendChild(caption);
+ }
+ else
+ {
+ replaceChild(caption, ref);
+ }
+ }
+
+ public HTMLTableSectionElement getTHead()
+ {
+ return (HTMLTableSectionElement) getChildElement("thead");
+ }
+
+ public void setTHead(HTMLTableSectionElement tHead)
+ {
+ HTMLTableSectionElement ref = getTHead();
+ if (ref == null)
+ {
+ appendChild(tHead);
+ }
+ else
+ {
+ replaceChild(tHead, ref);
+ }
+ }
+
+ public HTMLTableSectionElement getTFoot()
+ {
+ return (HTMLTableSectionElement) getChildElement("tfoot");
+ }
+
+ public void setTFoot(HTMLTableSectionElement tFoot)
+ {
+ HTMLTableSectionElement ref = getTFoot();
+ if (ref == null)
+ {
+ appendChild(tFoot);
+ }
+ else
+ {
+ replaceChild(tFoot, ref);
+ }
+ }
+
+ public HTMLCollection getRows()
+ {
+ DomHTMLCollection ret =
+ new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this);
+ ret.addNodeName("tr");
+ ret.evaluate();
+ return ret;
+ }
+
+ public HTMLCollection getTBodies()
+ {
+ DomHTMLCollection ret =
+ new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this);
+ ret.addNodeName("tbody");
+ ret.evaluate();
+ return ret;
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+ public String getBgColor()
+ {
+ return getHTMLAttribute("bgcolor");
+ }
+
+ public void setBgColor(String bgColor)
+ {
+ setHTMLAttribute("bgcolor", bgColor);
+ }
+
+ public String getBorder()
+ {
+ return getHTMLAttribute("border");
+ }
+
+ public void setBorder(String border)
+ {
+ setHTMLAttribute("border", border);
+ }
+
+ public String getCellPadding()
+ {
+ return getHTMLAttribute("cellpadding");
+ }
+
+ public void setCellPadding(String cellPadding)
+ {
+ setHTMLAttribute("cellpadding", cellPadding);
+ }
+
+ public String getCellSpacing()
+ {
+ return getHTMLAttribute("cellspacing");
+ }
+
+ public void setCellSpacing(String cellSpacing)
+ {
+ setHTMLAttribute("cellspacing", cellSpacing);
+ }
+
+ public String getFrame()
+ {
+ return getHTMLAttribute("frame");
+ }
+
+ public void setFrame(String frame)
+ {
+ setHTMLAttribute("frame", frame);
+ }
+
+ public String getRules()
+ {
+ return getHTMLAttribute("rules");
+ }
+
+ public void setRules(String rules)
+ {
+ setHTMLAttribute("rules", rules);
+ }
+
+ public String getSummary()
+ {
+ return getHTMLAttribute("summary");
+ }
+
+ public void setSummary(String summary)
+ {
+ setHTMLAttribute("summary", summary);
+ }
+
+ public String getWidth()
+ {
+ return getHTMLAttribute("width");
+ }
+
+ public void setWidth(String width)
+ {
+ setHTMLAttribute("width", width);
+ }
+
+ public HTMLElement createTHead()
+ {
+ HTMLTableSectionElement ref = getTHead();
+ if (ref == null)
+ {
+ return (HTMLElement) getOwnerDocument().createElement("thead");
+ }
+ else
+ {
+ return ref;
+ }
+ }
+
+ public void deleteTHead()
+ {
+ HTMLTableSectionElement ref = getTHead();
+ if (ref != null)
+ {
+ removeChild(ref);
+ }
+ }
+
+ public HTMLElement createTFoot()
+ {
+ HTMLTableSectionElement ref = getTFoot();
+ if (ref == null)
+ {
+ return (HTMLElement) getOwnerDocument().createElement("tfoot");
+ }
+ else
+ {
+ return ref;
+ }
+ }
+
+ public void deleteTFoot()
+ {
+ HTMLTableSectionElement ref = getTFoot();
+ if (ref != null)
+ {
+ removeChild(ref);
+ }
+ }
+
+ public HTMLElement createCaption()
+ {
+ HTMLTableCaptionElement ref = getCaption();
+ if (ref == null)
+ {
+ return (HTMLElement) getOwnerDocument().createElement("caption");
+ }
+ else
+ {
+ return ref;
+ }
+ }
+
+ public void deleteCaption()
+ {
+ HTMLTableCaptionElement ref = getCaption();
+ if (ref != null)
+ {
+ removeChild(ref);
+ }
+ }
+
+ public HTMLElement insertRow(int index)
+ {
+ Node ref = getRow(index);
+ Node row = getOwnerDocument().createElement("tr");
+ if (ref == null)
+ {
+ Node tbody = getChildElement("tbody");
+ if (tbody == null)
+ {
+ tbody = getOwnerDocument().createElement("tfoot");
+ appendChild(tbody);
+ }
+ tbody.appendChild(row);
+ }
+ else
+ {
+ ref.getParentNode().insertBefore(row, ref);
+ }
+ return (HTMLElement) row;
+ }
+
+ public void deleteRow(int index)
+ {
+ Node ref = getRow(index);
+ if (ref == null)
+ {
+ throw new DomDOMException(DOMException.INDEX_SIZE_ERR);
+ }
+ ref.getParentNode().removeChild(ref);
+ }
+
+ Node getRow(final int index)
+ {
+ int i = 0;
+ Node thead = getChildElement("thead");
+ if (thead != null)
+ {
+ for (Node ctx = thead.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ String ctxName = ctx.getLocalName();
+ if (ctxName == null)
+ {
+ ctxName = ctx.getNodeName();
+ }
+ if (!"tr".equalsIgnoreCase(ctxName))
+ {
+ continue;
+ }
+ if (index == i)
+ {
+ return ctx;
+ }
+ i++;
+ }
+ }
+ Node tbody = getChildElement("tbody");
+ if (tbody == null)
+ {
+ tbody = this;
+ }
+ for (Node ctx = tbody.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ String ctxName = ctx.getLocalName();
+ if (ctxName == null)
+ {
+ ctxName = ctx.getNodeName();
+ }
+ if (!"tr".equalsIgnoreCase(ctxName))
+ {
+ continue;
+ }
+ if (index == i)
+ {
+ return ctx;
+ }
+ i++;
+ }
+ Node tfoot = getChildElement("tfoot");
+ if (tfoot != null)
+ {
+ for (Node ctx = tfoot.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ String ctxName = ctx.getLocalName();
+ if (ctxName == null)
+ {
+ ctxName = ctx.getNodeName();
+ }
+ if (!"tr".equalsIgnoreCase(ctxName))
+ {
+ continue;
+ }
+ if (index == i)
+ {
+ return ctx;
+ }
+ i++;
+ }
+ }
+ return null;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java
new file mode 100644
index 0000000..ecd07a7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java
@@ -0,0 +1,229 @@
+/* DomHTMLTableRowElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import gnu.xml.dom.DomDOMException;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+import org.w3c.dom.html2.HTMLCollection;
+import org.w3c.dom.html2.HTMLElement;
+import org.w3c.dom.html2.HTMLTableRowElement;
+
+/**
+ * An HTML 'TR' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLTableRowElement
+ extends DomHTMLElement
+ implements HTMLTableRowElement
+{
+
+ protected DomHTMLTableRowElement(DomHTMLDocument owner,
+ String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public int getRowIndex()
+ {
+ return getIndex();
+ }
+
+ public int getSectionRowIndex()
+ {
+ int index = 0;
+ DomHTMLElement parent = (DomHTMLElement) getParentElement("table");
+ if (parent != null)
+ {
+ Node thead = parent.getChildElement("thead");
+ if (thead != null)
+ {
+ for (Node ctx = thead.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ if (ctx == this)
+ {
+ return index;
+ }
+ index++;
+ }
+ }
+ Node tbody = parent.getChildElement("tbody");
+ if (tbody != null)
+ {
+ for (Node ctx = tbody.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ if (ctx == this)
+ {
+ return index;
+ }
+ index++;
+ }
+ }
+ Node tfoot = parent.getChildElement("tfoot");
+ if (tfoot != null)
+ {
+ for (Node ctx = tfoot.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ if (ctx == this)
+ {
+ return index;
+ }
+ index++;
+ }
+ }
+ }
+ throw new DomDOMException(DOMException.NOT_FOUND_ERR);
+ }
+
+ public HTMLCollection getCells()
+ {
+ DomHTMLCollection ret =
+ new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this);
+ ret.addNodeName("th");
+ ret.addNodeName("td");
+ ret.evaluate();
+ return ret;
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+ public String getBgColor()
+ {
+ return getHTMLAttribute("bgcolor");
+ }
+
+ public void setBgColor(String bgColor)
+ {
+ setHTMLAttribute("bgcolor", bgColor);
+ }
+
+ public String getCh()
+ {
+ return getHTMLAttribute("char");
+ }
+
+ public void setCh(String ch)
+ {
+ setHTMLAttribute("char", ch);
+ }
+
+ public String getChOff()
+ {
+ return getHTMLAttribute("charoff");
+ }
+
+ public void setChOff(String chOff)
+ {
+ setHTMLAttribute("charoff", chOff);
+ }
+
+ public String getVAlign()
+ {
+ return getHTMLAttribute("valign");
+ }
+
+ public void setVAlign(String vAlign)
+ {
+ setHTMLAttribute("valign", vAlign);
+ }
+
+ public HTMLElement insertCell(int index)
+ {
+ Node ref = getCell(index);
+ Node cell = getOwnerDocument().createElement("td");
+ if (ref == null)
+ {
+ appendChild(cell);
+ }
+ else
+ {
+ insertBefore(cell, ref);
+ }
+ return (HTMLElement) cell;
+ }
+
+ public void deleteCell(int index)
+ {
+ Node ref = getCell(index);
+ if (ref == null)
+ {
+ throw new DomDOMException(DOMException.INDEX_SIZE_ERR);
+ }
+ removeChild(ref);
+ }
+
+ Node getCell(final int index)
+ {
+ int i = 0;
+ for (Node ctx = getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ String name = ctx.getLocalName();
+ if (name == null)
+ {
+ name = ctx.getNodeName();
+ }
+ if (!"td".equalsIgnoreCase(name) &&
+ !"th".equalsIgnoreCase(name))
+ {
+ continue;
+ }
+ if (index == i)
+ {
+ return ctx;
+ }
+ i++;
+ }
+ return null;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java
new file mode 100644
index 0000000..da015f1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java
@@ -0,0 +1,163 @@
+/* DomHTMLTableSectionElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import gnu.xml.dom.DomDOMException;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+import org.w3c.dom.html2.HTMLCollection;
+import org.w3c.dom.html2.HTMLElement;
+import org.w3c.dom.html2.HTMLTableSectionElement;
+
+/**
+ * An HTML 'THEAD', 'TFOOT', or 'TBODY' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLTableSectionElement
+ extends DomHTMLElement
+ implements HTMLTableSectionElement
+{
+
+ protected DomHTMLTableSectionElement(DomHTMLDocument owner,
+ String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getAlign()
+ {
+ return getHTMLAttribute("align");
+ }
+
+ public void setAlign(String align)
+ {
+ setHTMLAttribute("align", align);
+ }
+
+ public String getCh()
+ {
+ return getHTMLAttribute("char");
+ }
+
+ public void setCh(String ch)
+ {
+ setHTMLAttribute("char", ch);
+ }
+
+ public String getChOff()
+ {
+ return getHTMLAttribute("charoff");
+ }
+
+ public void setChOff(String chOff)
+ {
+ setHTMLAttribute("charoff", chOff);
+ }
+
+ public String getVAlign()
+ {
+ return getHTMLAttribute("valign");
+ }
+
+ public void setVAlign(String vAlign)
+ {
+ setHTMLAttribute("valign", vAlign);
+ }
+
+ public HTMLCollection getRows()
+ {
+ DomHTMLCollection ret =
+ new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this);
+ ret.addNodeName("tr");
+ ret.evaluate();
+ return ret;
+ }
+
+ public HTMLElement insertRow(int index)
+ {
+ Node ref = getRow(index);
+ Node row = getOwnerDocument().createElement("tr");
+ if (ref == null)
+ {
+ appendChild(row);
+ }
+ else
+ {
+ insertBefore(row, ref);
+ }
+ return (HTMLElement) row;
+ }
+
+ public void deleteRow(int index)
+ {
+ Node ref = getRow(index);
+ if (ref == null)
+ {
+ throw new DomDOMException(DOMException.INDEX_SIZE_ERR);
+ }
+ removeChild(ref);
+ }
+
+ Node getRow(final int index)
+ {
+ int i = 0;
+ for (Node ctx = getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ String name = ctx.getLocalName();
+ if (name == null)
+ {
+ name = ctx.getNodeName();
+ }
+ if (!"tr".equalsIgnoreCase(name))
+ {
+ continue;
+ }
+ if (index == i)
+ {
+ return ctx;
+ }
+ i++;
+ }
+ return null;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java
new file mode 100644
index 0000000..22d6105
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java
@@ -0,0 +1,182 @@
+/* DomHTMLTextAreaElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLFormElement;
+import org.w3c.dom.html2.HTMLTextAreaElement;
+
+/**
+ * An HTML 'TEXTAREA' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLTextAreaElement
+ extends DomHTMLElement
+ implements HTMLTextAreaElement
+{
+
+ protected String value;
+
+ protected DomHTMLTextAreaElement(DomHTMLDocument owner,
+ String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getDefaultValue()
+ {
+ return getHTMLAttribute("value");
+ }
+
+ public void setDefaultValue(String defaultValue)
+ {
+ setHTMLAttribute("value", defaultValue);
+ }
+
+ public HTMLFormElement getForm()
+ {
+ return (HTMLFormElement) getParentElement("form");
+ }
+
+ public String getAccessKey()
+ {
+ return getHTMLAttribute("accesskey");
+ }
+
+ public void setAccessKey(String accessKey)
+ {
+ setHTMLAttribute("accesskey", accessKey);
+ }
+
+ public int getCols()
+ {
+ return getIntHTMLAttribute("cols");
+ }
+
+ public void setCols(int cols)
+ {
+ setIntHTMLAttribute("cols", cols);
+ }
+
+ public boolean getDisabled()
+ {
+ return getBooleanHTMLAttribute("disabled");
+ }
+
+ public void setDisabled(boolean disabled)
+ {
+ setBooleanHTMLAttribute("disabled", disabled);
+ }
+
+ public String getName()
+ {
+ return getHTMLAttribute("name");
+ }
+
+ public void setName(String name)
+ {
+ setHTMLAttribute("name", name);
+ }
+
+ public boolean getReadOnly()
+ {
+ return getBooleanHTMLAttribute("readOnly");
+ }
+
+ public void setReadOnly(boolean readOnly)
+ {
+ setBooleanHTMLAttribute("readonly", readOnly);
+ }
+
+ public int getRows()
+ {
+ return getIntHTMLAttribute("rows");
+ }
+
+ public void setRows(int rows)
+ {
+ setIntHTMLAttribute("rows", rows);
+ }
+
+ public int getTabIndex()
+ {
+ return getIntHTMLAttribute("tabindex");
+ }
+
+ public void setTabIndex(int tabIndex)
+ {
+ setIntHTMLAttribute("tabindex", tabIndex);
+ }
+
+ public String getType()
+ {
+ return "textarea";
+ }
+
+ public String getValue()
+ {
+ if (value == null)
+ {
+ value = getDefaultValue();
+ }
+ return value;
+ }
+
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+ public void blur()
+ {
+ dispatchUIEvent("blur");
+ }
+
+ public void focus()
+ {
+ dispatchUIEvent("focus");
+ }
+
+ public void select()
+ {
+ dispatchUIEvent("select");
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java
new file mode 100644
index 0000000..f62342d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java
@@ -0,0 +1,69 @@
+/* DomHTMLTitleElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLTitleElement;
+
+/**
+ * An HTML 'TITLE' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLTitleElement
+ extends DomHTMLElement
+ implements HTMLTitleElement
+{
+
+ protected DomHTMLTitleElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public String getText()
+ {
+ return getTextContent();
+ }
+
+ public void setText(String text)
+ {
+ setTextContent(text);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java
new file mode 100644
index 0000000..c07adea
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java
@@ -0,0 +1,79 @@
+/* DomHTMLUListElement.java --
+ Copyright (C) 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 gnu.xml.dom.html2;
+
+import org.w3c.dom.html2.HTMLUListElement;
+
+/**
+ * An HTML 'UL' element node.
+ *
+ * @author Chris Burdess
+ */
+public class DomHTMLUListElement
+ extends DomHTMLElement
+ implements HTMLUListElement
+{
+
+ protected DomHTMLUListElement(DomHTMLDocument owner, String namespaceURI,
+ String name)
+ {
+ super(owner, namespaceURI, name);
+ }
+
+ public boolean getCompact()
+ {
+ return getBooleanHTMLAttribute("compact");
+ }
+
+ public void setCompact(boolean compact)
+ {
+ setBooleanHTMLAttribute("compact", compact);
+ }
+
+ public String getType()
+ {
+ return getHTMLAttribute("type");
+ }
+
+ public void setType(String type)
+ {
+ setHTMLAttribute("type", type);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSException.java b/libjava/classpath/gnu/xml/dom/ls/DomLSException.java
new file mode 100644
index 0000000..6ac49e6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/ls/DomLSException.java
@@ -0,0 +1,57 @@
+/* DomLSException.java --
+ Copyright (C) 2004 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 gnu.xml.dom.ls;
+
+import org.w3c.dom.ls.LSException;
+
+/**
+ * A DOM LS exception incorporating a cause.
+ *
+ * @author Chris Burdess
+ */
+public class DomLSException
+ extends LSException
+{
+
+ public DomLSException(short type, Exception cause)
+ {
+ super(type, (cause == null) ? null : cause.getMessage());
+ initCause(cause);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSInput.java b/libjava/classpath/gnu/xml/dom/ls/DomLSInput.java
new file mode 100644
index 0000000..44274ec
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/ls/DomLSInput.java
@@ -0,0 +1,158 @@
+/* DomLSInput.java --
+ Copyright (C) 1999,2000,2001 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 gnu.xml.dom.ls;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import org.w3c.dom.ls.LSInput;
+
+/**
+ * Specification of XML input to parse.
+ *
+ * @author Chris Burdess
+ */
+public class DomLSInput
+ implements LSInput
+{
+
+ private InputStream in;
+ private String systemId;
+ private String publicId;
+ private String baseURI;
+ private String encoding;
+ private boolean certifiedText;
+
+ public Reader getCharacterStream()
+ {
+ return new InputStreamReader(in);
+ }
+
+ public void setCharacterStream(Reader characterStream)
+ {
+ in = new ReaderInputStream(characterStream);
+ }
+
+ public InputStream getByteStream()
+ {
+ return in;
+ }
+
+ public void setByteStream(InputStream byteStream)
+ {
+ in = byteStream;
+ }
+
+ public String getStringData()
+ {
+ StringBuffer acc = new StringBuffer();
+ Reader reader = getCharacterStream();
+ try
+ {
+ char[] buf = new char[4096];
+ for (int len = reader.read(buf); len != -1; len = reader.read(buf))
+ {
+ acc.append(buf, 0, len);
+ }
+ }
+ catch (IOException e)
+ {
+ return null; // ?
+ }
+ return acc.toString();
+ }
+
+ public void setStringData(String stringData)
+ {
+ in = new ReaderInputStream(new StringReader(stringData));
+ }
+
+ public String getSystemId()
+ {
+ return systemId;
+ }
+
+ public void setSystemId(String systemId)
+ {
+ this.systemId = systemId;
+ }
+
+ public String getPublicId()
+ {
+ return publicId;
+ }
+
+ public void setPublicId(String publicId)
+ {
+ this.publicId = publicId;
+ }
+
+ public String getBaseURI()
+ {
+ return baseURI;
+ }
+
+ public void setBaseURI(String baseURI)
+ {
+ this.baseURI = baseURI;
+ }
+
+ public String getEncoding()
+ {
+ return encoding;
+ }
+
+ public void setEncoding(String encoding)
+ {
+ this.encoding = encoding;
+ }
+
+ public boolean getCertifiedText()
+ {
+ return certifiedText;
+ }
+
+ public void setCertifiedText(boolean certifiedText)
+ {
+ this.certifiedText = certifiedText;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java b/libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java
new file mode 100644
index 0000000..c2f4d41
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java
@@ -0,0 +1,98 @@
+/* DomLSOutput.java --
+ Copyright (C) 1999,2000,2001 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 gnu.xml.dom.ls;
+
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import org.w3c.dom.ls.LSOutput;
+
+/**
+ * Specification of XML output to produce.
+ *
+ * @author Chris Burdess
+ */
+public class DomLSOutput
+ implements LSOutput
+{
+
+ private OutputStream out;
+ private String systemId;
+ private String encoding;
+
+ public Writer getCharacterStream()
+ {
+ return new OutputStreamWriter(out);
+ }
+
+ public void setCharacterStream(Writer characterStream)
+ {
+ out = new WriterOutputStream(characterStream);
+ }
+
+ public OutputStream getByteStream()
+ {
+ return out;
+ }
+
+ public void setByteStream(OutputStream out)
+ {
+ this.out = out;
+ }
+
+ public String getSystemId()
+ {
+ return systemId;
+ }
+
+ public void setSystemId(String systemId)
+ {
+ this.systemId = systemId;
+ }
+
+ public String getEncoding()
+ {
+ return encoding;
+ }
+
+ public void setEncoding(String encoding)
+ {
+ this.encoding = encoding;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java b/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java
new file mode 100644
index 0000000..eb7c1c4
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java
@@ -0,0 +1,574 @@
+/* DomLSParser.java --
+ Copyright (C) 1999,2000,2001 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 gnu.xml.dom.ls;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMConfiguration;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMStringList;
+import org.w3c.dom.Node;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSException;
+import org.w3c.dom.ls.LSInput;
+import org.w3c.dom.ls.LSParser;
+import org.w3c.dom.ls.LSParserFilter;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import gnu.xml.dom.DomDocument;
+import gnu.xml.dom.DomDOMException;
+
+/**
+ * Parser implementation for GNU DOM.
+ *
+ * @author Chris Burdess
+ */
+public class DomLSParser
+ implements LSParser, DOMConfiguration, DOMStringList, ErrorHandler
+{
+
+ private static final List SUPPORTED_PARAMETERS
+ = Arrays.asList(new String[] { "cdata-sections",
+ "comments",
+ "element-content-whitespace",
+ "namespaces",
+ "expand-entity-references",
+ "coalescing",
+ "validating",
+ "xinclude-aware",
+ "entity-resolver",
+ "error-handler" });
+
+ private LSParserFilter filter;
+ private final boolean async;
+ private String schemaType;
+ private SAXEventSink eventSink;
+ private SAXParserFactory factory;
+ private XMLReader reader;
+
+ private boolean namespaceAware = true;
+ private boolean ignoreWhitespace;
+ private boolean expandEntityReferences;
+ private boolean ignoreComments;
+ private boolean coalescing;
+ private boolean validating;
+ private boolean xIncludeAware;
+ private EntityResolver entityResolver;
+ private ErrorHandler errorHandler;
+
+ public DomLSParser(short mode, String schemaType)
+ throws DOMException
+ {
+ switch (mode)
+ {
+ case DOMImplementationLS.MODE_ASYNCHRONOUS:
+ async = true;
+ break;
+ case DOMImplementationLS.MODE_SYNCHRONOUS:
+ async = false;
+ break;
+ default:
+ throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
+ }
+ // TODO schemaType
+ this.schemaType = schemaType;
+ factory = SAXParserFactory.newInstance();
+ }
+
+ // -- LSParser --
+
+ public DOMConfiguration getDomConfig()
+ {
+ return this;
+ }
+
+ public LSParserFilter getFilter()
+ {
+ return filter;
+ }
+
+ public void setFilter(LSParserFilter filter)
+ {
+ this.filter = filter;
+ }
+
+ public boolean getAsync()
+ {
+ return async;
+ }
+
+ public boolean getBusy()
+ {
+ return eventSink != null;
+ }
+
+ public Document parse(LSInput input)
+ throws DOMException, LSException
+ {
+ if (async)
+ {
+ return doParse(input);
+ }
+ else
+ {
+ synchronized (this)
+ {
+ return doParse(input);
+ }
+ }
+ }
+
+ public Document parseURI(String uri)
+ throws DOMException, LSException
+ {
+ LSInput input = new DomLSInput();
+ input.setSystemId(uri);
+ return parse(input);
+ }
+
+ public Node parseWithContext(LSInput input, Node context, short action)
+ throws DOMException, LSException
+ {
+ Document doc = (context.getNodeType() == Node.DOCUMENT_NODE) ?
+ (Document) context : context.getOwnerDocument();
+ input.setBaseURI(doc.getDocumentURI());
+ // TODO use namespaces defined on context node
+ Document ret = parse(input);
+ Node root = ret.getDocumentElement();
+ root = doc.adoptNode(root);
+ switch (action)
+ {
+ case ACTION_APPEND_AS_CHILDREN:
+ context.appendChild(root);
+ break;
+ case ACTION_REPLACE_CHILDREN:
+ Node c1 = context.getFirstChild();
+ while (c1 != null)
+ {
+ Node next = c1.getNextSibling();
+ context.removeChild(c1);
+ c1 = next;
+ }
+ context.appendChild(root);
+ break;
+ case ACTION_INSERT_BEFORE:
+ Node p1 = context.getParentNode();
+ p1.insertBefore(root, context);
+ break;
+ case ACTION_INSERT_AFTER:
+ Node p2 = context.getParentNode();
+ Node r1 = context.getNextSibling();
+ if (r1 == null)
+ {
+ p2.appendChild(root);
+ }
+ else
+ {
+ p2.insertBefore(root, r1);
+ }
+ break;
+ case ACTION_REPLACE:
+ Node p3 = context.getParentNode();
+ Node r2 = context.getNextSibling();
+ p3.removeChild(context);
+ if (r2 == null)
+ {
+ p3.appendChild(root);
+ }
+ else
+ {
+ p3.insertBefore(root, r2);
+ }
+ break;
+ }
+ return root;
+ }
+
+ public void abort()
+ {
+ if (eventSink != null)
+ {
+ eventSink.interrupt();
+ }
+ }
+
+ private Document doParse(LSInput input)
+ throws DOMException, LSException
+ {
+ // create event sink
+ if (eventSink != null)
+ {
+ throw new LSException(LSException.PARSE_ERR, "parse in progress");
+ }
+ InputSource source = getInputSource(input);
+ eventSink = (filter == null) ? new SAXEventSink() :
+ new FilteredSAXEventSink(filter);
+ // configure sink
+ eventSink.namespaceAware = namespaceAware;
+ eventSink.ignoreWhitespace = ignoreWhitespace;
+ eventSink.expandEntityReferences = expandEntityReferences;
+ eventSink.ignoreComments = ignoreComments;
+ eventSink.coalescing = coalescing;
+ // get and configure reader
+ XMLReader reader = getXMLReader();
+ try
+ {
+ reader.setContentHandler(eventSink);
+ reader.setDTDHandler(eventSink);
+ reader.setProperty("http://xml.org/sax/properties/lexical-handler",
+ eventSink);
+ reader.setProperty("http://xml.org/sax/properties/declaration-handler",
+ eventSink);
+ reader.setFeature("http://xml.org/sax/features/namespaces",
+ namespaceAware);
+ reader.setFeature("http://xml.org/sax/features/namespace-prefixes",
+ true);
+ reader.setFeature("http://xml.org/sax/features/validation",
+ validating);
+ try
+ {
+ reader.setFeature("http://xml.org/sax/features/use-attributes2",
+ true);
+ }
+ catch (SAXNotRecognizedException e)
+ {
+ // ignore
+ }
+ try
+ {
+ reader.setFeature("http://xml.org/sax/features/external-general-entities",
+ true);
+ }
+ catch (SAXNotRecognizedException e)
+ {
+ // ignore
+ }
+ reader.setEntityResolver(entityResolver);
+ reader.setErrorHandler(errorHandler);
+ // parse
+ reader.parse(source);
+ }
+ catch (DOMException e)
+ {
+ reader = null;
+ eventSink = null;
+ throw e;
+ }
+ catch (SAXException e)
+ {
+ reader = null;
+ eventSink = null;
+ throw new DomLSException(LSException.PARSE_ERR, e);
+ }
+ catch (IOException e)
+ {
+ reader = null;
+ eventSink = null;
+ throw new DomLSException(LSException.PARSE_ERR, e);
+ }
+ // return document
+ Document ret = eventSink.doc;
+ String systemId = input.getSystemId();
+ if (systemId != null && ret instanceof DomDocument)
+ {
+ ((DomDocument) ret).setDocumentURI(systemId);
+ }
+ eventSink = null;
+ return ret;
+ }
+
+ private XMLReader getXMLReader()
+ throws LSException
+ {
+ if (reader == null)
+ {
+ factory.setNamespaceAware(namespaceAware);
+ factory.setValidating(validating);
+ factory.setXIncludeAware(xIncludeAware);
+ try
+ {
+ SAXParser parser = factory.newSAXParser();
+ reader = parser.getXMLReader();
+ }
+ catch (ParserConfigurationException e)
+ {
+ throw new DomLSException(LSException.PARSE_ERR, e);
+ }
+ catch (SAXException e)
+ {
+ throw new DomLSException(LSException.PARSE_ERR, e);
+ }
+ }
+ return reader;
+ }
+
+ private InputSource getInputSource(LSInput input)
+ throws LSException
+ {
+ InputSource source = null;
+ String systemId = input.getSystemId();
+ InputStream in = input.getByteStream();
+ if (in != null)
+ {
+ source = new InputSource(in);
+ source.setSystemId(systemId);
+ }
+ if (source == null && entityResolver != null)
+ {
+ String publicId = input.getPublicId();
+ try
+ {
+ source = entityResolver.resolveEntity(publicId, systemId);
+ }
+ catch (SAXException e)
+ {
+ throw new DomLSException(LSException.PARSE_ERR, e);
+ }
+ catch (IOException e)
+ {
+ throw new DomLSException(LSException.PARSE_ERR, e);
+ }
+ }
+ if (source == null)
+ {
+ URL url = null;
+ String base = input.getBaseURI();
+ try
+ {
+ try
+ {
+ URL baseURL = (base == null) ? null : new URL(base);
+ url = (baseURL == null) ? new URL(systemId) :
+ new URL(baseURL, systemId);
+ }
+ catch (MalformedURLException e)
+ {
+ File baseFile = (base == null) ? null : new File(base);
+ url = (baseFile == null) ? new File(systemId).toURL() :
+ new File(baseFile, systemId).toURL();
+ }
+ in = url.openStream();
+ systemId = url.toString();
+ source = new InputSource(in);
+ source.setSystemId(systemId);
+ }
+ catch (IOException e)
+ {
+ throw new DomLSException(LSException.PARSE_ERR, e);
+ }
+ }
+ return source;
+ }
+
+ // -- DOMConfiguration --
+
+ public void setParameter(String name, Object value)
+ throws DOMException
+ {
+ name = name.toLowerCase();
+ if ("cdata-sections".equals(name))
+ {
+ coalescing = !((Boolean) value).booleanValue();
+ }
+ else if ("comments".equals(name))
+ {
+ ignoreComments = !((Boolean) value).booleanValue();
+ }
+ else if ("element-content-whitespace".equals(name))
+ {
+ ignoreWhitespace = !((Boolean) value).booleanValue();
+ }
+ else if ("namespaces".equals(name))
+ {
+ namespaceAware = ((Boolean) value).booleanValue();
+ }
+ else if ("expand-entity-references".equals(name))
+ {
+ expandEntityReferences = ((Boolean) value).booleanValue();
+ }
+ else if ("coalescing".equals(name))
+ {
+ coalescing = ((Boolean) value).booleanValue();
+ }
+ else if ("validating".equals(name))
+ {
+ validating = ((Boolean) value).booleanValue();
+ }
+ else if ("xinclude-aware".equals(name))
+ {
+ xIncludeAware = ((Boolean) value).booleanValue();
+ }
+ else if ("entity-resolver".equals(name))
+ {
+ entityResolver = (EntityResolver) value;
+ }
+ else if ("error-handler".equals(name))
+ {
+ errorHandler = (ErrorHandler) value;
+ }
+ else
+ {
+ throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
+ }
+ // invalidate reader, a new one will be created
+ reader = null;
+ }
+
+ public Object getParameter(String name)
+ throws DOMException
+ {
+ name = name.toLowerCase();
+ if ("cdata-sections".equals(name))
+ {
+ return coalescing ? Boolean.FALSE : Boolean.TRUE;
+ }
+ else if ("comments".equals(name))
+ {
+ return ignoreComments ? Boolean.FALSE : Boolean.TRUE;
+ }
+ else if ("element-content-whitespace".equals(name))
+ {
+ return ignoreWhitespace ? Boolean.FALSE : Boolean.TRUE;
+ }
+ else if ("namespaces".equals(name))
+ {
+ return namespaceAware ? Boolean.TRUE : Boolean.FALSE;
+ }
+ else if ("expand-entity-references".equals(name))
+ {
+ return expandEntityReferences ? Boolean.TRUE : Boolean.FALSE;
+ }
+ else if ("coalescing".equals(name))
+ {
+ return coalescing ? Boolean.TRUE : Boolean.FALSE;
+ }
+ else if ("validating".equals(name))
+ {
+ return validating ? Boolean.TRUE : Boolean.FALSE;
+ }
+ else if ("xinclude-aware".equals(name))
+ {
+ return xIncludeAware ? Boolean.TRUE : Boolean.FALSE;
+ }
+ else if ("entity-resolver".equals(name))
+ {
+ return entityResolver;
+ }
+ else if ("error-handler".equals(name))
+ {
+ return errorHandler;
+ }
+ else
+ {
+ throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
+ }
+ }
+
+ public boolean canSetParameter(String name, Object value)
+ {
+ return contains(name);
+ }
+
+ public DOMStringList getParameterNames()
+ {
+ return this;
+ }
+
+ // -- DOMStringList --
+
+ public String item(int i)
+ {
+ return (String) SUPPORTED_PARAMETERS.get(i);
+ }
+
+ public int getLength()
+ {
+ return SUPPORTED_PARAMETERS.size();
+ }
+
+ public boolean contains(String str)
+ {
+ return SUPPORTED_PARAMETERS.contains(str);
+ }
+
+ // -- ErrorHandler --
+
+ public void warning(SAXParseException e)
+ throws SAXException
+ {
+ if (errorHandler != null)
+ {
+ errorHandler.warning(e);
+ }
+ }
+
+ public void error(SAXParseException e)
+ throws SAXException
+ {
+ if (errorHandler != null)
+ {
+ errorHandler.error(e);
+ }
+ }
+
+ public void fatalError(SAXParseException e)
+ throws SAXException
+ {
+ if (errorHandler != null)
+ {
+ errorHandler.fatalError(e);
+ }
+ abort();
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java b/libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java
new file mode 100644
index 0000000..cedaf15
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java
@@ -0,0 +1,354 @@
+/* DomLSSerializer.java --
+ Copyright (C) 1999,2000,2001 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 gnu.xml.dom.ls;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Arrays;
+import java.util.List;
+import org.w3c.dom.DOMConfiguration;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMStringList;
+import org.w3c.dom.Node;
+import org.w3c.dom.ls.LSException;
+import org.w3c.dom.ls.LSOutput;
+import org.w3c.dom.ls.LSSerializer;
+import org.w3c.dom.ls.LSSerializerFilter;
+import org.w3c.dom.traversal.NodeFilter;
+import gnu.xml.dom.DomDOMException;
+import gnu.xml.transform.StreamSerializer;
+
+/**
+ * Serialize a DOM node to a stream.
+ *
+ * @author Chris Burdess
+ */
+public class DomLSSerializer
+ extends StreamSerializer
+ implements LSSerializer, DOMConfiguration, DOMStringList
+{
+
+ private static final List SUPPORTED_PARAMETERS =
+ Arrays.asList(new String[] {"discard-default-content",
+ "xml-declaration"});
+
+ private LSSerializerFilter filter;
+ private StreamSerializer serializer;
+
+ public DomLSSerializer()
+ {
+ super();
+ discardDefaultContent = true;
+ }
+
+ // -- LSSerializer --
+
+ public DOMConfiguration getDomConfig()
+ {
+ return this;
+ }
+
+ public String getNewLine()
+ {
+ return eol;
+ }
+
+ public void setNewLine(String newLine)
+ {
+ if (newLine == null)
+ {
+ newLine = System.getProperty("line.separator");
+ }
+ eol = newLine;
+ }
+
+ public LSSerializerFilter getFilter()
+ {
+ return filter;
+ }
+
+ public void setFilter(LSSerializerFilter filter)
+ {
+ this.filter = filter;
+ }
+
+ public boolean write(Node node, LSOutput output)
+ throws LSException
+ {
+ OutputStream out = output.getByteStream();
+ try
+ {
+ if (out == null)
+ {
+ String systemId = output.getSystemId();
+ try
+ {
+ URL url = new URL(systemId);
+ URLConnection connection = url.openConnection();
+ connection.setDoOutput(true);
+ if (connection instanceof HttpURLConnection)
+ {
+ ((HttpURLConnection) connection).setRequestMethod("PUT");
+ }
+ out = connection.getOutputStream();
+ }
+ catch (MalformedURLException e)
+ {
+ File file = new File(systemId);
+ out = new FileOutputStream(file);
+ }
+ }
+ serialize(node, out);
+ out.flush();
+ return true;
+ }
+ catch (IOException e)
+ {
+ throw new DomLSException(LSException.SERIALIZE_ERR, e);
+ }
+ }
+
+ public boolean writeToURI(Node node, String uri)
+ throws LSException
+ {
+ LSOutput output = new DomLSOutput();
+ output.setSystemId(uri);
+ return write(node, output);
+ }
+
+ public String writeToString(Node node)
+ throws DOMException, LSException
+ {
+ Writer writer = new StringWriter();
+ LSOutput output = new DomLSOutput();
+ output.setCharacterStream(writer);
+ write(node, output);
+ return writer.toString();
+ }
+
+ public void serialize(Node node, OutputStream out)
+ throws IOException
+ {
+ if (filter == null)
+ {
+ super.serialize(node, out);
+ }
+ else
+ {
+ int wts = filter.getWhatToShow();
+ if (wts != NodeFilter.SHOW_ALL)
+ {
+ switch (node.getNodeType())
+ {
+ case Node.ATTRIBUTE_NODE:
+ if ((wts & NodeFilter.SHOW_ATTRIBUTE) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ case Node.TEXT_NODE:
+ if ((wts & NodeFilter.SHOW_TEXT) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ case Node.ELEMENT_NODE:
+ if ((wts & NodeFilter.SHOW_ELEMENT) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ case Node.CDATA_SECTION_NODE:
+ if ((wts & NodeFilter.SHOW_CDATA_SECTION) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ case Node.COMMENT_NODE:
+ if ((wts & NodeFilter.SHOW_COMMENT) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ case Node.DOCUMENT_NODE:
+ if ((wts & NodeFilter.SHOW_DOCUMENT) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ case Node.DOCUMENT_TYPE_NODE:
+ if ((wts & NodeFilter.SHOW_DOCUMENT_TYPE) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ if ((wts & NodeFilter.SHOW_PROCESSING_INSTRUCTION) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ if ((wts & NodeFilter.SHOW_DOCUMENT_FRAGMENT) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ case Node.ENTITY_NODE:
+ if ((wts & NodeFilter.SHOW_ENTITY) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ case Node.ENTITY_REFERENCE_NODE:
+ if ((wts & NodeFilter.SHOW_ENTITY_REFERENCE) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ case Node.NOTATION_NODE:
+ if ((wts & NodeFilter.SHOW_NOTATION) == 0)
+ {
+ super.serialize(node, out);
+ return;
+ }
+ break;
+ }
+ }
+ switch (filter.acceptNode(node))
+ {
+ case NodeFilter.FILTER_ACCEPT:
+ super.serialize(node, out);
+ break;
+ case NodeFilter.FILTER_REJECT:
+ break;
+ case NodeFilter.FILTER_SKIP:
+ Node first = node.getFirstChild();
+ if (first != null)
+ {
+ serialize(first, out);
+ }
+ break;
+ }
+ }
+ }
+
+ // -- DOMConfiguration --
+
+ public void setParameter(String name, Object value)
+ throws DOMException
+ {
+ if ("discard-default-content".equals(name))
+ {
+ discardDefaultContent = "true".equals(value.toString());
+ }
+ else if ("xml-declaration".equals(name))
+ {
+ xmlDeclaration = "false".equals(value.toString());
+ }
+ else
+ {
+ throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
+ }
+ }
+
+ public Object getParameter(String name)
+ throws DOMException
+ {
+ if ("discard-default-content".equals(name))
+ {
+ return discardDefaultContent ? "true" : "false";
+ }
+ else if ("xml-declaration".equals(name))
+ {
+ return xmlDeclaration ? "true" : "false";
+ }
+ else
+ {
+ throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
+ }
+ }
+
+ public boolean canSetParameter(String name, Object value)
+ {
+ return contains(name);
+ }
+
+ public DOMStringList getParameterNames()
+ {
+ return this;
+ }
+
+ // -- DOMStringList --
+
+ public String item(int i)
+ {
+ return (String) SUPPORTED_PARAMETERS.get(i);
+ }
+
+ public int getLength()
+ {
+ return SUPPORTED_PARAMETERS.size();
+ }
+
+ public boolean contains(String str)
+ {
+ return SUPPORTED_PARAMETERS.contains(str);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java b/libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java
new file mode 100644
index 0000000..1c99ee5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java
@@ -0,0 +1,354 @@
+/* FilteredSAXEventSink.java --
+ Copyright (C) 1999,2000,2001 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 gnu.xml.dom.ls;
+
+import java.util.LinkedList;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import org.w3c.dom.ls.LSParserFilter;
+import org.w3c.dom.traversal.NodeFilter;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * A SAX event sink that calls out to a parser filter in order to decide
+ * whether to insert nodes into the tree.
+ *
+ * @author Chris Burdess
+ */
+class FilteredSAXEventSink
+ extends SAXEventSink
+{
+
+ final LSParserFilter filter;
+ final int whatToShow;
+
+ /**
+ * Stack of elements to insert.
+ */
+ LinkedList nodes;
+
+ /**
+ * Corresponding stack of filter decisions about the nodes.
+ */
+ LinkedList decisions;
+
+ /**
+ * True when rejecting child nodes.
+ */
+ boolean rejecting;
+
+ FilteredSAXEventSink(LSParserFilter filter)
+ {
+ this.filter = filter;
+ whatToShow = filter.getWhatToShow();
+ }
+
+ public void startDocument()
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ nodes = new LinkedList();
+ decisions = new LinkedList();
+
+ super.startDocument();
+ }
+
+ public void endDocument()
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ super.endDocument();
+
+ switch (getDecision(ctx, false))
+ {
+ case LSParserFilter.FILTER_REJECT:
+ ctx = null;
+ doc = null;
+ break;
+ }
+
+ nodes = null;
+ decisions = null;
+ }
+
+ public void startElement(String uri, String localName, String qName,
+ Attributes atts)
+ throws SAXException
+ {
+ if (rejecting || interrupted)
+ {
+ return;
+ }
+ Element element = createElement(uri, localName, qName, atts);
+ ctx = element;
+
+ short decision = getDecision(element, true);
+ nodes.addLast(element);
+ decisions.addLast(new Short(decision));
+
+ switch (decision)
+ {
+ case LSParserFilter.FILTER_REJECT:
+ rejecting = true;
+ break;
+ case LSParserFilter.FILTER_INTERRUPT:
+ interrupted = true;
+ break;
+ }
+ }
+
+ protected Attr createAttr(Attributes atts, int index)
+ {
+ Attr attr = super.createAttr(atts, index);
+ short decision = getDecision(attr, false);
+ switch (decision)
+ {
+ case LSParserFilter.FILTER_REJECT:
+ return null;
+ case LSParserFilter.FILTER_INTERRUPT:
+ interrupted = true;
+ return null;
+ }
+ return attr;
+ }
+
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException
+ {
+ if (rejecting || interrupted)
+ {
+ return;
+ }
+ super.endElement(uri, localName, qName);
+
+ Element element = (Element) nodes.removeLast();
+ Node parent = nodes.isEmpty() ? doc : (Node) nodes.getLast();
+ ctx = parent;
+ short decision = ((Short) decisions.removeLast()).shortValue();
+ switch (decision)
+ {
+ case LSParserFilter.FILTER_SKIP:
+ // Add all children of element to parent
+ for (Node child = element.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ parent.insertBefore(child, element);
+ }
+ return;
+ case LSParserFilter.FILTER_REJECT:
+ rejecting = false;
+ break;
+ }
+ decision = getDecision(element, false);
+ switch (decision)
+ {
+ case LSParserFilter.FILTER_ACCEPT:
+ parent.appendChild(element);
+ break;
+ case LSParserFilter.FILTER_INTERRUPT:
+ interrupted = true;
+ break;
+ }
+ }
+
+ public void characters(char[] c, int off, int len)
+ throws SAXException
+ {
+ if (rejecting || interrupted)
+ {
+ return;
+ }
+ Text text = createText(c, off, len);
+ short decision = getDecision(text, false);
+ switch (decision)
+ {
+ case LSParserFilter.FILTER_ACCEPT:
+ ctx.appendChild(text);
+ break;
+ case LSParserFilter.FILTER_INTERRUPT:
+ interrupted = true;
+ break;
+ }
+ }
+
+ public void processingInstruction(String target, String data)
+ throws SAXException
+ {
+ if (rejecting || interrupted || inDTD)
+ {
+ return;
+ }
+ Node pi = createProcessingInstruction(target, data);
+ short decision = getDecision(pi, false);
+ switch (decision)
+ {
+ case LSParserFilter.FILTER_ACCEPT:
+ ctx.appendChild(pi);
+ break;
+ case LSParserFilter.FILTER_INTERRUPT:
+ interrupted = true;
+ break;
+ }
+ }
+
+ public void startDTD(String name, String publicId, String systemId)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ Node doctype = createDocumentType(name, publicId, systemId);
+ ctx = doctype;
+ inDTD = true;
+ nodes.addLast(doctype);
+ decisions.addLast(new Short(LSParserFilter.FILTER_ACCEPT));
+ }
+
+ public void endDTD()
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ Node doctype = (Node) nodes.removeLast();
+ decisions.removeLast();
+ inDTD = false;
+ ctx = doc;
+ short decision = getDecision(doctype, false);
+ switch (decision)
+ {
+ case LSParserFilter.FILTER_ACCEPT:
+ ctx.appendChild(doctype);
+ break;
+ case LSParserFilter.FILTER_INTERRUPT:
+ interrupted = true;
+ break;
+ }
+ }
+
+ public void comment(char[] c, int off, int len)
+ throws SAXException
+ {
+ if (rejecting || interrupted || inDTD)
+ {
+ return;
+ }
+ Node comment = createComment(c, off, len);
+ short decision = getDecision(comment, false);
+ switch (decision)
+ {
+ case LSParserFilter.FILTER_ACCEPT:
+ ctx.appendChild(comment);
+ break;
+ case LSParserFilter.FILTER_INTERRUPT:
+ interrupted = true;
+ break;
+ }
+ }
+
+ // TODO declarations
+
+ short getDecision(Node node, boolean start)
+ {
+ boolean show = (whatToShow == NodeFilter.SHOW_ALL);
+ if (!show)
+ {
+ switch (node.getNodeType())
+ {
+ case Node.ATTRIBUTE_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_ATTRIBUTE) != 0);
+ break;
+ case Node.TEXT_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_TEXT) != 0);
+ break;
+ case Node.CDATA_SECTION_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_CDATA_SECTION) != 0);
+ break;
+ case Node.ELEMENT_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_ELEMENT) != 0);
+ break;
+ case Node.COMMENT_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_COMMENT) != 0);
+ break;
+ case Node.DOCUMENT_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_DOCUMENT) != 0);
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_PROCESSING_INSTRUCTION) != 0);
+ break;
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_DOCUMENT_FRAGMENT) != 0);
+ break;
+ case Node.DOCUMENT_TYPE_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_DOCUMENT_TYPE) != 0);
+ break;
+ case Node.ENTITY_REFERENCE_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_ENTITY_REFERENCE) != 0);
+ break;
+ case Node.ENTITY_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_ENTITY) != 0);
+ break;
+ case Node.NOTATION_NODE:
+ show = ((whatToShow & NodeFilter.SHOW_NOTATION) != 0);
+ break;
+ }
+ }
+ if (!show)
+ {
+ return LSParserFilter.FILTER_ACCEPT;
+ }
+ if (start)
+ {
+ return filter.startElement((Element) node);
+ }
+ return filter.acceptNode(node);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java b/libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java
new file mode 100644
index 0000000..5b41abd
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java
@@ -0,0 +1,237 @@
+/* ReaderInputStream.java --
+ Copyright (C) 1999, 2000, 2001, 2004 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 gnu.xml.dom.ls;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * Character stream wrapper.
+ *
+ * @author Chris Burdess
+ * @author Mark Wielaard
+ */
+public class ReaderInputStream
+ extends InputStream
+{
+
+ private Reader reader;
+ private String encoding;
+
+ // Holds extra spillover data if necessary
+ private byte extra[];
+ private int pos;
+
+ private byte extra_marked[];
+ private int pos_marked;
+
+ public ReaderInputStream(Reader reader)
+ {
+ this.reader = reader;
+ this.encoding = "UTF-8";
+ }
+
+ void setEncoding(String encoding)
+ {
+ this.encoding = encoding;
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (extra != null)
+ {
+ int result = extra[pos];
+ pos++;
+ if (pos >= extra.length)
+ {
+ extra = null;
+ }
+ return result;
+ }
+ return reader.read();
+ }
+
+ public int read(byte[] b)
+ throws IOException
+ {
+ return read(b, 0, b.length);
+ }
+
+ public int read(byte[] b, int off, int len)
+ throws IOException
+ {
+ if (len == 0)
+ {
+ return 0;
+ }
+
+ if (extra != null)
+ {
+ int available = extra.length - pos;
+ int l = available < len ? available : len;
+ System.arraycopy(extra, 0, b, off, l);
+ pos += l;
+ if (pos >= extra.length)
+ {
+ extra = null;
+ }
+ return l;
+ }
+
+ char[] c = new char[len];
+ int l = reader.read(c, 0, len);
+ if (l == -1)
+ {
+ return -1;
+ }
+
+ String s = new String(c, 0, l);
+ byte[] d = s.getBytes(encoding);
+
+ int available = d.length;
+ int more = d.length - len;
+ if (more > 0)
+ {
+ extra = new byte[more];
+ pos = 0;
+ System.arraycopy(d, len, extra, 0, more);
+ available -= more;
+ }
+
+ System.arraycopy(d, 0, b, off, available);
+ return available;
+ }
+
+ public void close()
+ throws IOException
+ {
+ reader.close();
+ }
+
+ public boolean markSupported()
+ {
+ return reader.markSupported();
+ }
+
+ public void mark(int limit)
+ {
+ if (extra != null)
+ {
+ extra_marked = new byte[extra.length];
+ System.arraycopy(extra, 0, extra_marked, 0, extra.length);
+ pos_marked = pos;
+ }
+ else
+ {
+ extra_marked = null;
+ }
+
+ try
+ {
+ // Note that this might be a bit more than asked for.
+ // Because we might also have the extra_marked bytes.
+ // That is fine (and necessary for reset() to work).
+ reader.mark(limit);
+ }
+ catch (IOException ioe)
+ {
+ throw new RuntimeException(ioe);
+ }
+ }
+
+ public void reset()
+ throws IOException
+ {
+ extra = extra_marked;
+ pos = pos_marked;
+ extra_marked = null;
+
+ reader.reset();
+ }
+
+ public long skip(long n)
+ throws IOException
+ {
+ long done = 0;
+ if (extra != null)
+ {
+ int available = extra.length - pos;
+ done = available < n ? available : n;
+ pos += done;
+ if (pos >= extra.length)
+ {
+ extra = null;
+ }
+ }
+
+ n -= done;
+ if (n > 0)
+ {
+ return reader.skip(n) + done;
+ }
+ else
+ {
+ return done;
+ }
+ }
+
+ /**
+ * Returns conservative number of bytes available without blocking.
+ * Actual number of bytes that can be read without blocking might
+ * be (much) bigger.
+ */
+ public int available()
+ throws IOException
+ {
+ if (extra != null)
+ {
+ return pos - extra.length;
+ }
+
+ return reader.ready() ? 1 : 0;
+ }
+
+ public String toString()
+ {
+ return getClass().getName() + "[" + reader + ", " + encoding + "]";
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java b/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java
new file mode 100644
index 0000000..a850460
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java
@@ -0,0 +1,557 @@
+/* SAXEventSink.java --
+ Copyright (C) 1999,2000,2001 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 gnu.xml.dom.ls;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import javax.xml.XMLConstants;
+import org.w3c.dom.Attr;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Entity;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import org.xml.sax.Attributes;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.Attributes2;
+import org.xml.sax.ext.DeclHandler;
+import org.xml.sax.ext.LexicalHandler;
+import gnu.xml.aelfred2.ContentHandler2;
+import gnu.xml.dom.DomAttr;
+import gnu.xml.dom.DomDocument;
+import gnu.xml.dom.DomDoctype;
+
+/**
+ * A SAX content and lexical handler used to construct a DOM document.
+ *
+ * @author Chris Burdess
+ */
+class SAXEventSink
+ implements ContentHandler2, LexicalHandler, DTDHandler, DeclHandler
+{
+
+ private static final String XMLNS_URI = XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
+ private static final String XMLNS_PREFIX = XMLConstants.XMLNS_ATTRIBUTE;
+
+ boolean namespaceAware;
+ boolean ignoreWhitespace;
+ boolean expandEntityReferences;
+ boolean ignoreComments;
+ boolean coalescing;
+
+ DomDocument doc; // document being constructed
+ Node ctx; // current context (parent node)
+ LinkedList entityCtx; // entity context
+ List pending; // namespace nodes waiting for a declaring element
+ Locator locator;
+ boolean inCDATA;
+ boolean inDTD;
+ boolean interrupted;
+
+ void interrupt()
+ {
+ interrupted = true;
+ }
+
+ // -- ContentHandler2 --
+
+ public void setDocumentLocator(Locator locator)
+ {
+ this.locator = locator;
+ }
+
+ public void startDocument()
+ throws SAXException
+ {
+ if (namespaceAware)
+ {
+ pending = new LinkedList();
+ }
+ doc = new DomDocument();
+ doc.setStrictErrorChecking(false);
+ doc.setBuilding(true);
+ ctx = doc;
+ }
+
+ public void xmlDecl(String version, String encoding, boolean standalone,
+ String inputEncoding)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ doc.setXmlVersion(version);
+ doc.setXmlEncoding(encoding);
+ doc.setXmlStandalone(standalone);
+ doc.setInputEncoding(inputEncoding);
+ }
+
+ public void endDocument()
+ throws SAXException
+ {
+ doc.setStrictErrorChecking(true);
+ doc.setBuilding(false);
+ DomDoctype doctype = (DomDoctype) doc.getDoctype();
+ if (doctype != null)
+ {
+ doctype.makeReadonly();
+ }
+ ctx = null;
+ locator = null;
+ }
+
+ public void startPrefixMapping(String prefix, String uri)
+ throws SAXException
+ {
+ if (namespaceAware)
+ {
+ String nsName = (prefix != null && prefix.length() > 0) ?
+ XMLNS_PREFIX + ":" + prefix : XMLNS_PREFIX;
+ DomAttr ns = (DomAttr) doc.createAttributeNS(XMLNS_URI, nsName);
+ ns.setNodeValue(uri);
+ if (ctx.getNodeType() == Node.ATTRIBUTE_NODE)
+ {
+ // Add to owner element
+ Node target = ((Attr) ctx).getOwnerElement();
+ target.getAttributes().setNamedItemNS(ns);
+ }
+ else
+ {
+ // Add to pending list; namespace node will be inserted when
+ // element is seen
+ pending.add(ns);
+ }
+ }
+ }
+
+ public void endPrefixMapping(String prefix)
+ throws SAXException
+ {
+ }
+
+ public void startElement(String uri, String localName, String qName,
+ Attributes atts)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ Element element = createElement(uri, localName, qName, atts);
+ // add element to context
+ ctx.appendChild(element);
+ ctx = element;
+ }
+
+ protected Element createElement(String uri, String localName, String qName,
+ Attributes atts)
+ throws SAXException
+ {
+ // create element node
+ Element element = namespaceAware ?
+ doc.createElementNS(uri, qName) :
+ doc.createElement(qName);
+ NamedNodeMap attrs = element.getAttributes();
+ if (namespaceAware && !pending.isEmpty())
+ {
+ // add pending namespace nodes
+ for (Iterator i = pending.iterator(); i.hasNext(); )
+ {
+ Node ns = (Node) i.next();
+ attrs.setNamedItemNS(ns);
+ }
+ pending.clear();
+ }
+ // add attributes
+ int len = atts.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ // create attribute
+ Attr attr = createAttr(atts, i);
+ if (attr != null)
+ {
+ // add attribute to element
+ if (namespaceAware)
+ {
+ attrs.setNamedItemNS(attr);
+ }
+ else
+ {
+ attrs.setNamedItem(attr);
+ }
+ }
+ }
+ return element;
+ }
+
+ protected Attr createAttr(Attributes atts, int index)
+ {
+ DomAttr attr;
+ if (namespaceAware)
+ {
+ String a_uri = atts.getURI(index);
+ String a_qName = atts.getQName(index);
+ attr = (DomAttr) doc.createAttributeNS(a_uri, a_qName);
+ }
+ else
+ {
+ String a_qName = atts.getQName(index);
+ attr = (DomAttr) doc.createAttribute(a_qName);
+ }
+ attr.setNodeValue(atts.getValue(index));
+ if (atts instanceof Attributes2)
+ {
+ Attributes2 atts2 = (Attributes2) atts;
+ // TODO attr.setDeclared(atts2.isDeclared(index));
+ attr.setSpecified(atts2.isSpecified(index));
+ }
+ return attr;
+ }
+
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ if (namespaceAware)
+ {
+ pending.clear();
+ }
+ ctx = ctx.getParentNode();
+ }
+
+ public void characters(char[] c, int off, int len)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ ctx.appendChild(createText(c, off, len));
+ }
+
+ protected Text createText(char[] c, int off, int len)
+ throws SAXException
+ {
+ Text text = (inCDATA && !coalescing) ?
+ doc.createCDATASection(new String(c, off, len)) :
+ doc.createTextNode(new String(c, off, len));
+ return text;
+ }
+
+ public void ignorableWhitespace(char[] c, int off, int len)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ if (!ignoreWhitespace)
+ {
+ characters(c, off, len);
+ }
+ }
+
+ public void processingInstruction(String target, String data)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ if (!inDTD)
+ {
+ Node pi = createProcessingInstruction(target, data);
+ ctx.appendChild(pi);
+ }
+ }
+
+ protected Node createProcessingInstruction(String target, String data)
+ {
+ return doc.createProcessingInstruction(target, data);
+ }
+
+ public void skippedEntity(String name)
+ throws SAXException
+ {
+ // This callback is totally pointless
+ }
+
+ // -- LexicalHandler --
+
+ public void startDTD(String name, String publicId, String systemId)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ Node doctype = createDocumentType(name, publicId, systemId);
+ doc.appendChild(doctype);
+ ctx = doctype;
+ inDTD = true;
+ }
+
+ protected Node createDocumentType(String name, String publicId,
+ String systemId)
+ {
+ return new DomDoctype(doc, name, publicId, systemId);
+ }
+
+ public void endDTD()
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ inDTD = false;
+ ctx = ctx.getParentNode();
+ }
+
+ public void startEntity(String name)
+ throws SAXException
+ {
+ DocumentType doctype = doc.getDoctype();
+ if (doctype == null)
+ {
+ throw new SAXException("SAX parser error: " +
+ "reference to entity in undeclared doctype");
+ }
+ if ("[dtd]".equals(name) || name.charAt(0) == '%')
+ {
+ // Ignore DTD and parameter entities
+ ctx = doctype;
+ return;
+ }
+ if ("lt".equals(name) ||
+ "gt".equals(name) ||
+ "amp".equals(name) ||
+ "apos".equals(name) ||
+ "quot".equals(name))
+ {
+ return;
+ }
+ // Get entity
+ NamedNodeMap entities = doctype.getEntities();
+ Entity entity = (Entity) entities.getNamedItem(name);
+ if (entity == null)
+ {
+ throw new SAXException("SAX parser error: " +
+ "reference to undeclared entity: " + name);
+ }
+ pushEntity(entity);
+ }
+
+ public void endEntity(String name)
+ throws SAXException
+ {
+ if ("[dtd]".equals(name) || name.charAt(0) == '%')
+ {
+ // Ignore DTD and parameter entities
+ return;
+ }
+ if ("lt".equals(name) ||
+ "gt".equals(name) ||
+ "amp".equals(name) ||
+ "apos".equals(name) ||
+ "quot".equals(name))
+ {
+ return;
+ }
+ // Get entity
+ Entity entity = popEntity();
+ // TODO resolve external entities to ensure that entity has content
+ if (expandEntityReferences)
+ {
+ // Get entity content
+ for (Node child = entity.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ ctx.appendChild(child);
+ }
+ }
+ else
+ {
+ Node entityReference = doc.createEntityReference(name);
+ ctx.appendChild(entityReference);
+ }
+ }
+
+ void pushEntity(Node entity)
+ {
+ if (entityCtx == null)
+ {
+ entityCtx = new LinkedList();
+ }
+ entityCtx.addLast(ctx);
+ ctx = entity;
+ }
+
+ Entity popEntity()
+ {
+ Entity ret = (Entity) ctx;
+ ctx = (Node) entityCtx.removeLast();
+ return ret;
+ }
+
+ public void startCDATA()
+ throws SAXException
+ {
+ inCDATA = true;
+ }
+
+ public void endCDATA()
+ throws SAXException
+ {
+ inCDATA = false;
+ }
+
+ public void comment(char[] c, int off, int len)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ if (!inDTD)
+ {
+ Node comment = createComment(c, off, len);
+ ctx.appendChild(comment);
+ }
+ }
+
+ protected Node createComment(char[] c, int off, int len)
+ {
+ return doc.createComment(new String(c, off, len));
+ }
+
+ // -- DTDHandler --
+
+ public void notationDecl(String name, String publicId, String systemId)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ DomDoctype doctype = (DomDoctype) ctx;
+ doctype.declareNotation(name, publicId, systemId);
+ }
+
+ public void unparsedEntityDecl(String name, String publicId, String systemId,
+ String notationName)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ DomDoctype doctype = (DomDoctype) ctx;
+ Entity entity = doctype.declareEntity(name, publicId, systemId,
+ notationName);
+ }
+
+ // -- DeclHandler --
+
+ public void elementDecl(String name, String model)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ // Ignore fake element declarations generated by ValidationConsumer.
+ // If an element is not really declared in the DTD it will not be
+ // declared in the document model.
+ if (!(ctx instanceof DomDoctype))
+ {
+ return;
+ }
+ DomDoctype doctype = (DomDoctype) ctx;
+ doctype.elementDecl(name, model);
+ }
+
+ public void attributeDecl(String eName, String aName, String type,
+ String mode, String value)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ DomDoctype doctype = (DomDoctype) ctx;
+ doctype.attributeDecl(eName, aName, type, mode, value);
+ }
+
+ public void internalEntityDecl(String name, String value)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ DomDoctype doctype = (DomDoctype) ctx;
+ Entity entity = doctype.declareEntity(name, null, null, null);
+ if (entity != null)
+ {
+ Node text = doc.createTextNode(value);
+ entity.appendChild(text);
+ }
+ }
+
+ public void externalEntityDecl(String name, String publicId, String systemId)
+ throws SAXException
+ {
+ if (interrupted)
+ {
+ return;
+ }
+ DomDoctype doctype = (DomDoctype) ctx;
+ Entity entity = doctype.declareEntity(name, publicId, systemId, null);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java b/libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java
new file mode 100644
index 0000000..2fb2061
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java
@@ -0,0 +1,98 @@
+/* WriterOutputStream.java --
+ Copyright (C) 1999,2000,2001 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 gnu.xml.dom.ls;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+/**
+ * Character stream wrapper.
+ *
+ * @author Chris Burdess
+ */
+public class WriterOutputStream
+ extends OutputStream
+{
+
+ private Writer writer;
+ private String encoding;
+
+ public WriterOutputStream(Writer writer)
+ {
+ this.writer = writer;
+ this.encoding = "UTF-8";
+ }
+
+ void setEncoding(String encoding)
+ {
+ this.encoding = encoding;
+ }
+
+ public void write(int c)
+ throws IOException
+ {
+ writer.write(c);
+ }
+
+ public void write(byte[] b)
+ throws IOException
+ {
+ write(b, 0, b.length);
+ }
+
+ public void write(byte[] b, int off, int len)
+ throws IOException
+ {
+ writer.write(new String(b, off, len, encoding));
+ }
+
+ public void close()
+ throws IOException
+ {
+ writer.close();
+ }
+
+ public void flush()
+ throws IOException
+ {
+ writer.flush();
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/dom/package.html b/libjava/classpath/gnu/xml/dom/package.html
new file mode 100644
index 0000000..fbc864a
--- /dev/null
+++ b/libjava/classpath/gnu/xml/dom/package.html
@@ -0,0 +1,273 @@
+
+
+This is a Free Software DOM Level 3 implementation, supporting these features: +
+Note that while DOM does not specify its behavior in the +face of concurrent access, this implementation does. +Specifically: +
+A number of DOM implementations are available in Java, including +commercial ones from Sun, IBM, Oracle, and DataChannel as well as +noncommercial ones from Docuverse, OpenXML, and Silfide. Why have +another? Some of the goals of this version: +
+ ++This also works with the GNU Compiler for Java (GCJ). GCJ promises +to be quite the environment for programming Java, both directly and from +C++ using the new CNI interfaces (which really use C++, unlike JNI).
+ + +At this writing:
++I ran a profiler a few times and remove some of the performance hotspots, +but it's not tuned. Reporting mutation events, in particular, is +rather costly -- it started at about a 40% penalty for appendNode calls, +I've got it down around 12%, but it'll be hard to shrink it much further. +The overall code size is relatively small, though you may want to be rid of +many of the unused DOM interface classes (HTML, CSS, and so on). +
+ + +Starting with DOM Level 2, you can really see that DOM is constructed +as a bunch of optional modules around a core of either XML or HTML +functionality. Different implementations will support different optional +modules. This implementation provides a set of features that should be +useful if you're not depending on the HTML functionality (lots of convenience +functions that mostly don't buy much except API surface area) and user +interface support. That is, browsers will want more -- but what they +need should be cleanly layered over what's already here.
+ +This DOM implementation supports the "XML" feature set, which basically +gets you four things over the bare core (which you're officially not supposed +to implement except in conjunction with the "XML" or "HTML" feature). In +order of decreasing utility, those four things are:
Events may be one of the more interesting new features in Level 2. +This package provides the core feature set and exposes mutation events. +No gooey events though; if you want that, write a layered implementation!
+ +Three mutation events aren't currently generated:
In addition, certain kinds of attribute modification aren't reported. +A fix is known, but it couldn't report the previous value of the attribute. +More work could fix all of this (as well as reduce the generally high cost +of childful attributes), but that's not been done yet.
+ +Also, note that it is a Bad Thing to have the listener +for a mutation event change the ancestry for the target of that event. +Or to prevent mutation events from bubbling to where they're needed. +Just don't do those, OK?
+ +As an experimental feature (named "USER-Events"), you can provide +your own "user" events. Just name them anything starting with "USER-" +and you're set. Dispatch them through, bubbling, capturing, or what +ever takes your fancy. One important thing you can't currently do is +pass any data (like an object) with those events. Maybe later there +will be a "UserEvent" interface letting you get some substantial use +out of this mechanism even if you're not "inside" of a DOM package.
+ +You can create and send HTML events. Ditto UIEvents. Since DOM +doesn't require a UI, it's the UI's job to send them; perhaps that's +part of your application.
+ +This package may be built without the ability to report mutation +events, gaining a significant speedup in DOM construction time. However, +if that is done then certain other features -- notably node iterators +and getElementsByTagname -- will not be available. + + +
Each DOM node has all you need to walk to everything connected +to that node. Lightweight, efficient utilities are easily layered on +top of just the core APIs.
+ +Traversal APIs are an optional part of DOM Level 2, providing +a not-so-lightweight way to walk over DOM trees, if your application +didn't already have such utilities for use with data represented via +DOM. Implementing this helped debug the (optional) event and mutation +event subsystems, so it's provided here.
+ +At this writing, the "TreeWalker" interface isn't implemented.
+ + + +For what appear to be a combination of historical and "committee +logic" reasons, DOM has a number of features which I strongly advise +you to avoid using in your library and application code. These +include the following types of DOM nodes; see the documentation for the +implementation class for more information:
If you really need to use unparsed entities or notations, use SAX; +it offers better support for all DTD-related functionality. +It also exposes actual +document typing information (such as element content models).
+ +Also, when accessing attribute values, use methods that provide their +values as single strings, rather than those which expose value substructure +(Text and EntityReference nodes). (See the DomAttr +documentation for more information.)
+ +Note that many of these features were provided as partial support for +editor functionality (including the incomplete DTD access). Full editor +functionality requires access to potentially malformed lexical structure, +at the level of unparsed tokens and below. Access at such levels is so +complex that using it in non-editor applications sacrifices all the +benefits of XML; editor aplications need extremely specialized APIs.
+ +(This isn't a slam against DTDs, note; only against the broken support +for them in DOM. Even despite inclusion of some dubious SGML legacy features +such as notations and unparsed entities, +and the ongoing proliferation of alternative schema and validation tools, +DTDs are still the most widely adopted tool +to constrain XML document structure. +Alternative schemes generally focus on data transfer style +applications; open document architectures comparable to +DocBook 4.0 don't yet exist in the schema world. +Feel free to use DTDs; just don't expect DOM to help you.)
+ + + + diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java new file mode 100644 index 0000000..24088fb --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java @@ -0,0 +1,116 @@ +/* GnomeAttr.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.TypeInfo; + +/** + * A DOM attribute node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeAttr + extends GnomeNode + implements Attr +{ + + GnomeAttr(Object id) + { + super(id); + } + + public String getName() + { + return getNodeName(); + } + + public native boolean getSpecified(); + + public native String getValue(); + + public native void setValue(String value) + throws DOMException; + + public Node getParentNode() + { + return null; + } + + public Element getOwnerElement() + { + return (Element) super.getParentNode(); + } + + // DOM Level 3 methods + + public TypeInfo getSchemaTypeInfo() + { + return new GnomeTypeInfo(id); + } + + public boolean isId() + { + if (xmljIsId()) + { + return true; + } + GnomeElement element = (GnomeElement) getOwnerElement(); + return (element != null && + element.userIdAttrs != null && + element.userIdAttrs.contains(this)); + } + + private native boolean xmljIsId(); + + public String toString() + { + StringBuffer buffer = new StringBuffer(getClass().getName()); + buffer.append("[name="); + buffer.append(getName()); + buffer.append(",value="); + buffer.append(getValue()); + buffer.append("]"); + return buffer.toString(); + } + +} + diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java new file mode 100644 index 0000000..8fb89ff --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java @@ -0,0 +1,57 @@ +/* GnomeCDATASection.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.CDATASection; + +/** + * A DOM CDATA section node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeCDATASection + extends GnomeText + implements CDATASection +{ + + GnomeCDATASection(Object id) + { + super(id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java new file mode 100644 index 0000000..a320092 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java @@ -0,0 +1,117 @@ +/* GnomeCharacterData.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.CharacterData; +import org.w3c.dom.DOMException; + +/** + * A DOM character data node implemented in libxml2. + * + * @author Chris Burdess + */ +abstract class GnomeCharacterData + extends GnomeNode + implements CharacterData +{ + + GnomeCharacterData(Object id) + { + super(id); + } + + public String getData() + throws DOMException + { + return getNodeValue(); + } + + public void setData(String data) + throws DOMException + { + setNodeValue(data); + } + + public int getLength() + { + return getData().length(); + } + + public String substringData(int offset, int count) + throws DOMException + { + return getData().substring(offset, offset + count); + } + + public void appendData(String arg) + throws DOMException + { + setData(getData() + arg); + } + + public void insertData(int offset, String arg) + throws DOMException + { + String data = getData(); + setData(data.substring(0, offset) + arg + data.substring(offset)); + } + + public void deleteData(int offset, int count) + throws DOMException + { + String data = getData(); + setData(data.substring(0, offset) + data.substring(offset + count)); + } + + public void replaceData(int offset, int count, String arg) + { + String data = getData(); + setData(data.substring(0, offset) + arg + + data.substring(offset + count)); + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(getClass().getName()); + buffer.append("[data="); + buffer.append(getData()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java new file mode 100644 index 0000000..a0cad5b --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java @@ -0,0 +1,57 @@ +/* GnomeComment.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.Comment; + +/** + * A DOM comment node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeComment + extends GnomeCharacterData + implements Comment +{ + + GnomeComment(Object id) + { + super(id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java new file mode 100644 index 0000000..eae0787 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java @@ -0,0 +1,98 @@ +/* GnomeDOMException.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; + +class GnomeDOMException + extends DOMException +{ + + GnomeDOMException(short code, String message) + { + super(code, createMessage(code, message)); + } + + private static String createMessage(int code, String message) + { + if (message != null) + { + return message; + } + switch (code) + { + case INDEX_SIZE_ERR: + return "INDEX_SIZE_ERR"; + case DOMSTRING_SIZE_ERR: + return "DOMSTRING_SIZE_ERR"; + case HIERARCHY_REQUEST_ERR: + return "HIERARCHY_REQUEST_ERR"; + case WRONG_DOCUMENT_ERR: + return "WRONG_DOCUMENT_ERR"; + case INVALID_CHARACTER_ERR: + return "INVALID_CHARACTER_ERR"; + case NO_DATA_ALLOWED_ERR: + return "NO_DATA_ALLOWED_ERR"; + case NO_MODIFICATION_ALLOWED_ERR: + return "NO_MODIFICATION_ALLOWED_ERR"; + case NOT_FOUND_ERR: + return "NOT_FOUND_ERR"; + case NOT_SUPPORTED_ERR: + return "NOT_SUPPORTED_ERR"; + case INUSE_ATTRIBUTE_ERR: + return "INUSE_ATTRIBUTE_ERR"; + case INVALID_STATE_ERR: + return "INVALID_STATE_ERR"; + case SYNTAX_ERR: + return "SYNTAX_ERR"; + case INVALID_MODIFICATION_ERR: + return "INVALID_MODIFICATION_ERR"; + case NAMESPACE_ERR: + return "NAMESPACE_ERR"; + case INVALID_ACCESS_ERR: + return "INVALID_ACCESS_ERR"; + case VALIDATION_ERR: + return "VALIDATION_ERR"; + case TYPE_MISMATCH_ERR: + return "TYPE_MISMATCH_ERR"; + default: + return null; + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java new file mode 100644 index 0000000..3456acd --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java @@ -0,0 +1,84 @@ +/* GnomeDOMStringList.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.DOMStringList; + +/** + * Implementation of a string list using an array of strings. + * + * @author Chris Burdess + */ +class GnomeDOMStringList + implements DOMStringList +{ + + final String[] values; + + GnomeDOMStringList(String[] values) + { + this.values = values; + } + + public int getLength() + { + return values.length; + } + + public String item(int index) + { + if (index < 0 || index >= values.length) + { + return null; + } + return values[index]; + } + + public boolean contains(String value) + { + for (int i = 0; i < values.length; i++) + { + if (values[i].equalsIgnoreCase(value)) + { + return true; + } + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java new file mode 100644 index 0000000..3706fba --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java @@ -0,0 +1,561 @@ +/* GnomeDocument.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import java.util.Iterator; + +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMStringList; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.traversal.DocumentTraversal; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; +import org.w3c.dom.traversal.TreeWalker; +import org.w3c.dom.xpath.XPathEvaluator; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathExpression; +import org.w3c.dom.xpath.XPathNSResolver; + +import gnu.xml.dom.DomNodeIterator; + +/** + * A DOM document node implemented in libxml2. + * + * @author Chris Burdess + */ +public class GnomeDocument + extends GnomeNode + implements Document, DOMConfiguration, XPathEvaluator, DocumentTraversal +{ + + DOMImplementation dom; + + /** + * Not currently used. + */ + boolean strictErrorChecking; + + /* DOMConfiguration */ + boolean canonicalForm = false; + boolean cdataSections = true; + boolean checkCharacterNormalization = false; + boolean comments = true; + boolean datatypeNormalization = false; + boolean elementContentWhitespace = true; + boolean entities = true; + DOMErrorHandler errorHandler; + boolean namespaces = true; + boolean namespaceDeclarations = true; + boolean normalizeCharacters = false; + boolean splitCdataSections = true; + boolean validate = false; + boolean validateIfSchema = false; + boolean wellFormed = true; + + GnomeDocument(Object id) + { + super(id); + strictErrorChecking = true; + } + + protected void finalize() + { + free(id); + } + + private native void free(Object id); + + public native DocumentType getDoctype(); + + public DOMImplementation getImplementation() + { + return dom; + } + + public native Element getDocumentElement(); + + public Element createElement(String tagName) + throws DOMException + { + return createElementNS(null, tagName); + } + + public native DocumentType createDocumentType(String name, String publicId, + String systemId); + + public native DocumentFragment createDocumentFragment(); + + public native Text createTextNode(String data); + + public native Comment createComment(String data); + + public native CDATASection createCDATASection(String data) + throws DOMException; + + public native ProcessingInstruction createProcessingInstruction(String target, + String data) + throws DOMException; + + public Attr createAttribute(String name) + throws DOMException + { + return createAttributeNS(null, name); + } + + public native EntityReference createEntityReference(String name) + throws DOMException; + + public native NodeList getElementsByTagName(String tagName); + + public Node importNode(Node importedNode, boolean deep) + throws DOMException + { + Node ret = xmljImportNode(importedNode, deep); + if (importedNode instanceof GnomeNode) + { + ((GnomeNode) importedNode) + .notifyUserDataHandlers(UserDataHandler.NODE_IMPORTED, + importedNode, ret); + } + return ret; + } + + private native Node xmljImportNode(Node importedNode, boolean deep) + throws DOMException; + + public native Element createElementNS(String namespaceURI, String + qualifiedName) + throws DOMException; + + public native Attr createAttributeNS(String namespaceURI, String + qualifiedName) + throws DOMException; + + public native NodeList getElementsByTagNameNS(String namespaceURI, + String localName); + + public Element getElementById(String elementId) + { + Element element = xmljGetElementById(elementId); + if (element == null) + { + TreeWalker walker = createTreeWalker(this, NodeFilter.SHOW_ELEMENT, + null, false); + for (Node node = walker.nextNode(); node != null; + node = walker.nextNode()) + { + GnomeElement e = (GnomeElement) node; + if (e.userIdAttrs != null) + { + for (Iterator i = e.userIdAttrs.iterator(); i.hasNext(); ) + { + Attr attr = (Attr) i.next(); + if (attr.getNodeValue().equals(elementId)) + { + return e; + } + } + } + } + } + return element; + } + + private native Element xmljGetElementById(String elementId); + + // DOM Level 3 methods + + public native String getInputEncoding(); + + public native String getXmlEncoding(); + + public native boolean getXmlStandalone(); + + public native void setXmlStandalone(boolean xmlStandalone); + + public native String getXmlVersion(); + + public native void setXmlVersion(String xmlVersion); + + public boolean getStrictErrorChecking() + { + return strictErrorChecking; + } + + public void setStrictErrorChecking(boolean strictErrorChecking) + { + this.strictErrorChecking = strictErrorChecking; + } + + public native String getDocumentURI(); + + public native void setDocumentURI(String documentURI); + + public Node adoptNode(Node source) + throws DOMException + { + if (source == null || !(source instanceof GnomeNode)) + { + return null; + } + Node ret = xmljAdoptNode(source); + if (source instanceof GnomeNode) + { + ((GnomeNode) source). + notifyUserDataHandlers(UserDataHandler.NODE_ADOPTED, + source, ret); + } + return ret; + } + + private native Node xmljAdoptNode(Node source) + throws DOMException; + + public DOMConfiguration getDomConfig() + { + return this; + } + + public void normalizeDocument() + { + normalize(); + } + + public native Node renameNode(Node n, String namespaceURI, + String qualifiedName); + + // -- DOMConfiguration methods -- + + public void setParameter(String name, Object value) + throws DOMException + { + name = name.toLowerCase(); + if ("canonical-form".equals(name)) + { + /* optional + canonicalForm = getBooleanValue(value);*/ + } + else if ("cdata-sections".equals(name)) + { + cdataSections = getBooleanValue(value); + } + else if ("check-character-normalization".equals(name)) + { + /* optional + checkCharacterNormalization = getBooleanValue(value);*/ + } + else if ("comments".equals(name)) + { + comments = getBooleanValue(value); + } + else if ("datatype-normalization".equals(name)) + { + /* optional + datatypeNormalization = getBooleanValue(value);*/ + } + else if ("element-content-whitespace".equals(name)) + { + /* optional + elementContentWhitespace = getBooleanValue(value);*/ + } + else if ("entities".equals(name)) + { + entities = getBooleanValue(value); + } + else if ("error-handler".equals(name)) + { + errorHandler = (DOMErrorHandler) value; + } + else if ("infoset".equals(name)) + { + if (getBooleanValue(value)) + { + validateIfSchema = false; + entities = false; + datatypeNormalization = false; + cdataSections = false; + namespaceDeclarations = true; + wellFormed = true; + elementContentWhitespace = true; + comments = true; + namespaces = true; + } + } + else if ("namespaces".equals(name)) + { + /* optional + namespaces = getBooleanValue(value);*/ + } + else if ("namespace-declarations".equals(name)) + { + namespaceDeclarations = getBooleanValue(value); + } + else if ("normalize-characters".equals(name)) + { + /* optional + normalizeCharacters = getBooleanValue(value);*/ + } + else if ("split-cdata-sections".equals(name)) + { + splitCdataSections = getBooleanValue(value); + } + else if ("validate".equals(name)) + { + /* optional + validate = getBooleanValue(value);*/ + } + else if ("validate-if-schema".equals(name)) + { + /* optional + validateIfSchema = getBooleanValue(value);*/ + } + else if ("well-formed".equals(name)) + { + /* optional + wellFormed = getBooleanValue(value);*/ + } + else + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, name); + } + } + + public Object getParameter(String name) + throws DOMException + { + name = name.toLowerCase(); + if ("canonical-form".equals(name)) + { + return new Boolean(canonicalForm); + } + else if ("cdata-sections".equals(name)) + { + return new Boolean(cdataSections); + } + else if ("check-character-normalization".equals(name)) + { + return new Boolean(checkCharacterNormalization); + } + else if ("comments".equals(name)) + { + return new Boolean(comments); + } + else if ("datatype-normalization".equals(name)) + { + return new Boolean(datatypeNormalization); + } + else if ("element-content-whitespace".equals(name)) + { + return new Boolean(elementContentWhitespace); + } + else if ("entities".equals(name)) + { + return new Boolean(entities); + } + else if ("error-handler".equals(name)) + { + return errorHandler; + } + else if ("infoset".equals(name)) + { + return new Boolean(!validateIfSchema && + !entities && + !datatypeNormalization && + !cdataSections && + namespaceDeclarations && + wellFormed && + elementContentWhitespace && + comments && + namespaces); + } + else if ("namespaces".equals(name)) + { + return new Boolean(namespaces); + } + else if ("namespace-declarations".equals(name)) + { + return new Boolean(namespaceDeclarations); + } + else if ("normalize-characters".equals(name)) + { + return new Boolean(normalizeCharacters); + } + else if ("split-cdata-sections".equals(name)) + { + return new Boolean(splitCdataSections); + } + else if ("validate".equals(name)) + { + return new Boolean(validate); + } + else if ("validate-if-schema".equals(name)) + { + return new Boolean(validateIfSchema); + } + else if ("well-formed".equals(name)) + { + return new Boolean(wellFormed); + } + else + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, name); + } + } + + public boolean canSetParameter(String name, Object value) + { + name = name.toLowerCase(); + if ("error-handler".equals(name)) + { + return (value == null || value instanceof DOMErrorHandler); + } + return ("cdata-sections".equals(name) || + "comments".equals(name) || + "entities".equals(name) || + "namespace-declarations".equals(name) || + "split-cdata-sections".equals(name)); + } + + public DOMStringList getParameterNames() + { + String[] names = new String[] { + "canonical-form", + "cdata-sections", + "check-character-normalization", + "comments", + "datatype-normalization", + "element-content-whitespace", + "entities", + "error-handler", + "infoset", + "namespaces", + "namespace-declarations", + "normalize-characters", + "split-cdata-sections", + "validate", + "validate-if-schema", + "well-formed" + }; + return new GnomeDOMStringList(names); + } + + private boolean getBooleanValue(Object value) + { + if (value instanceof Boolean) + { + return ((Boolean) value).booleanValue(); + } + else if (value instanceof String) + { + return new Boolean ((String) value).booleanValue(); + } + return false; + } + + // -- XPathEvaluator methods -- + + public XPathExpression createExpression(String expression, + XPathNSResolver resolver) + throws XPathException, DOMException + { + return new GnomeXPathExpression(this, expression, resolver); + } + + public XPathNSResolver createNSResolver(Node nodeResolver) + { + return new GnomeXPathNSResolver(nodeResolver); + } + + public native Object evaluate(String expression, + Node contextNode, + XPathNSResolver resolver, + short type, + Object result) + throws XPathException, DOMException; + + // -- DocumentTraversal methods -- + + public NodeIterator createNodeIterator(Node root, + int whatToShow, + NodeFilter filter, + boolean entityReferenceExpansion) + throws DOMException + { + return new DomNodeIterator(root, whatToShow, filter, + entityReferenceExpansion, false); + } + + public TreeWalker createTreeWalker(Node root, + int whatToShow, + NodeFilter filter, + boolean entityReferenceExpansion) + throws DOMException + { + return new DomNodeIterator(root, whatToShow, filter, + entityReferenceExpansion, true); + } + + // -- Debugging -- + + public String toString() + { + StringBuffer buffer = new StringBuffer(getClass().getName()); + buffer.append("[version="); + buffer.append(getXmlVersion()); + buffer.append(",standalone="); + buffer.append(getXmlStandalone()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java new file mode 100644 index 0000000..4decee0 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java @@ -0,0 +1,326 @@ +/* GnomeDocumentBuilder.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import java.io.InputStream; +import java.io.IOException; +import java.net.URL; +import javax.xml.parsers.DocumentBuilder; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMImplementation; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import gnu.xml.libxmlj.util.NamedInputStream; +import gnu.xml.libxmlj.util.StandaloneDocumentType; +import gnu.xml.libxmlj.util.StandaloneLocator; +import gnu.xml.libxmlj.util.XMLJ; + +/** + * A JAXP DOM implementation that uses Gnome libxml2 as the underlying + * parser and node representation. + * + * @author Chris Burdess + */ +public class GnomeDocumentBuilder + extends DocumentBuilder + implements DOMImplementation +{ + + static + { + XMLJ.init(); + } + + // -- DocumentBuilder -- + + private boolean validate; + private boolean coalesce; + private boolean expandEntities; + private EntityResolver entityResolver; + private ErrorHandler errorHandler; + private boolean seenFatalError; + + /** + * Constructs a new validating document builder. + */ + public GnomeDocumentBuilder() + { + this(true, false, false); + } + + /** + * Constructs a new document builder. + * @param validate whether to validate during parsing + * @param coalesce whether to merge CDATA as text nodes + * @param expandEntities whether to expand entity references + */ + public GnomeDocumentBuilder(boolean validate, + boolean coalesce, + boolean expandEntities) + { + this.validate = validate; + this.coalesce = coalesce; + this.expandEntities = expandEntities; + } + + public DOMImplementation getDOMImplementation() + { + return this; + } + + public boolean isNamespaceAware() + { + return true; + } + + public boolean isValidating() + { + return validate; + } + + public Document newDocument() + { + return createDocument(null, null, null); + } + + public Document parse(InputSource input) + throws SAXException, IOException + { + NamedInputStream in = XMLJ.getInputStream(input); + byte[] detectBuffer = in.getDetectBuffer(); + String publicId = input.getPublicId(); + String systemId = input.getSystemId(); + String base = XMLJ.getBaseURI(systemId); + // Handle zero-length document + if (detectBuffer == null) + { + throw new SAXParseException("No document element", publicId, + systemId, 0, 0); + } + seenFatalError = false; + return parseStream(in, + detectBuffer, + publicId, + systemId, + base, + validate, + coalesce, + expandEntities, + true, //entityResolver != null, + errorHandler != null); + } + + private native Document parseStream(InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean validate, + boolean coalesce, + boolean expandEntities, + boolean entityResolver, + boolean errorHandler); + + public void setEntityResolver(EntityResolver resolver) + { + entityResolver = resolver; + } + + public void setErrorHandler(ErrorHandler handler) + { + errorHandler = handler; + } + + // -- DOMImplementation -- + + public boolean hasFeature(String name, String version) + { + if (name.length() == 0) + { + return false; + } + name = name.toLowerCase(); + if (name.charAt(0) == '+') + { + name = name.substring(1); + } + + if ("xml".equals(name) || "core".equals(name)) + { + return (version == null || + "".equals(version) || + "1.0".equals(version) || + "2.0".equals(version) || + "3.0".equals(version)); + + } + else if ("ls".equals(name) || "ls-async".equals(name)) + { + // TODO + /* + return (version == null || + "".equals(version) || + "3.0".equals(version)); + */ + return false; + } + else if ("traversal".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + } + else if ("xpath".equals(name)) + { + return (version == null || + "".equals(version) || + "3.0".equals(version)); + } + return false; + } + + // DOM Level 3 + + public Object getFeature(String feature, String version) + { + if (hasFeature(feature, version)) + { + return this; + } + return null; + } + + public native Document createDocument(String namespaceURI, + String qualifiedName, + DocumentType doctype); + + public DocumentType createDocumentType(String qualifiedName, + String publicId, + String systemId) + { + return new StandaloneDocumentType(qualifiedName, publicId, systemId); + } + + // Callback hooks from JNI + + private void setDocumentLocator(Object ctx, Object loc) + { + // ignore + } + + private InputStream resolveEntity(String publicId, String systemId, + String base) + throws SAXException, IOException + { + String url = XMLJ.getAbsoluteURI(base, systemId); + InputStream in = null; + if (entityResolver != null) + { + InputSource source = entityResolver.resolveEntity(publicId, url); + if (source != null) + { + in = XMLJ.getInputStream(source); + } + } + if (in == null) + { + in = XMLJ.getInputStream(new URL(url)); + } + return in; + } + + private void warning(String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws SAXException + { + if (!seenFatalError && errorHandler != null) + { + Locator l = new StandaloneLocator(lineNumber, + columnNumber, + publicId, + systemId); + errorHandler.warning(new SAXParseException(message, l)); + } + } + + private void error(String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws SAXException + { + if (!seenFatalError && errorHandler != null) + { + Locator l = new StandaloneLocator(lineNumber, + columnNumber, + publicId, + systemId); + errorHandler.error(new SAXParseException(message, l)); + } + } + + private void fatalError(String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws SAXException + { + if (!seenFatalError && errorHandler != null) + { + seenFatalError = true; + Locator l = new StandaloneLocator(lineNumber, + columnNumber, + publicId, + systemId); + errorHandler.fatalError(new SAXParseException(message, l)); + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java new file mode 100644 index 0000000..c4f0ce2 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java @@ -0,0 +1,94 @@ +/* GnomeDocumentBuilderFactory.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +/** + * Factory for JAXP document builders using the libxml2 implementation. + * + * @author Chris Burdess + */ +public class GnomeDocumentBuilderFactory +extends DocumentBuilderFactory +{ + + public GnomeDocumentBuilderFactory () + { + setNamespaceAware (true); + } + + public Object getAttribute (String name) + { + // TODO + return null; + } + + public DocumentBuilder newDocumentBuilder () + throws ParserConfigurationException + { + /* + if (!isNamespaceAware ()) + { + String msg = "Parser must be namespace-aware"; + throw new ParserConfigurationException (msg); + } + if (isIgnoringComments ()) + { + String msg = "Ignoring comments not supported"; + throw new ParserConfigurationException (msg); + } + if (isIgnoringElementContentWhitespace ()) + { + String msg = "Ignoring element content whitespace not supported"; + throw new ParserConfigurationException (msg); + } + */ + return new GnomeDocumentBuilder (isValidating (), + isCoalescing (), + isExpandEntityReferences ()); + } + + public void setAttribute (String name, Object value) + { + // TODO + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java new file mode 100644 index 0000000..e5b355e --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java @@ -0,0 +1,57 @@ +/* GnomeDocumentFragment.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.DocumentFragment; + +/** + * A DOM document fragment node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeDocumentFragment +extends GnomeNode +implements DocumentFragment +{ + + GnomeDocumentFragment (Object id) + { + super (id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java new file mode 100644 index 0000000..257fbbc --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java @@ -0,0 +1,96 @@ +/* GnomeDocumentType.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.DocumentType; +import org.w3c.dom.NamedNodeMap; + +/** + * A DOM document type node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeDocumentType +extends GnomeNode +implements DocumentType +{ + + GnomeDocumentType (Object id) + { + super (id); + } + + public String getName () + { + return getNodeName (); + } + + public NamedNodeMap getEntities () + { + return new GnomeNamedNodeMap (id, 1); + } + + public NamedNodeMap getNotations () + { + return new GnomeNamedNodeMap (id, 2); + } + + public native String getPublicId (); + + public native String getSystemId (); + + public native String getInternalSubset (); + + public String toString () + { + String publicId = getPublicId (); + StringBuffer buffer = new StringBuffer (getClass ().getName ()); + buffer.append ("["); + if (publicId != null) + { + buffer.append ("publicId="); + buffer.append (publicId); + buffer.append (","); + } + buffer.append ("systemId="); + buffer.append (getSystemId ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java new file mode 100644 index 0000000..2770cbb --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java @@ -0,0 +1,182 @@ +/* GnomeElement.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import java.util.HashSet; +import java.util.Set; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.w3c.dom.TypeInfo; + +/** + * A DOM element node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeElement + extends GnomeNode + implements Element +{ + + /** + * User-defined ID attributes. + */ + Set userIdAttrs; + + GnomeElement(Object id) + { + super(id); + } + + public String getTagName() + { + return getNodeName(); + } + + public native String getAttribute(String name); + + public native void setAttribute(String name, String value) + throws DOMException; + + public void removeAttribute(String name) + throws DOMException + { + Attr attr = getAttributeNode(name); + if (attr != null) + { + removeAttributeNode(attr); + } + } + + public native Attr getAttributeNode(String name); + + public native Attr setAttributeNode(Attr newAttr) + throws DOMException; + + public native Attr removeAttributeNode(Attr oldAttr) + throws DOMException; + + public native NodeList getElementsByTagName(String name); + + public native String getAttributeNS(String namespaceURI, String localName); + + public native void setAttributeNS(String namespaceURI, String + qualifiedName, String value) + throws DOMException; + + public void removeAttributeNS(String namespaceURI, String localName) + throws DOMException + { + Attr attr = getAttributeNodeNS(namespaceURI, localName); + if (attr != null) + { + removeAttributeNode(attr); + } + } + + public native Attr getAttributeNodeNS(String namespaceURI, + String localName); + + public native Attr setAttributeNodeNS(Attr newAttr) + throws DOMException; + + public native NodeList getElementsByTagNameNS(String namespaceURI, + String localName); + + public native boolean hasAttribute(String name); + + public native boolean hasAttributeNS(String namespaceURI, + String localName); + + // DOM Level 3 methods + + public TypeInfo getSchemaTypeInfo() + { + return new GnomeTypeInfo(id); + } + + public void setIdAttribute(String name, boolean isId) + { + Attr attr = getAttributeNode(name); + setIdAttributeNode(attr, isId); + } + + public void setIdAttributeNode(Attr attr, boolean isId) + { + if (attr == null)// FIXME || !attr.getOwnerElement().equals(this)) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + if (isId) + { + if (userIdAttrs == null) + { + userIdAttrs = new HashSet(); + } + userIdAttrs.add(attr); + } + else if (userIdAttrs != null) + { + userIdAttrs.remove(attr); + if (userIdAttrs.isEmpty()) + { + userIdAttrs = null; + } + } + } + + public void setIdAttributeNS(String namespaceURI, String localName, + boolean isId) + { + Attr attr = getAttributeNodeNS(namespaceURI, localName); + setIdAttributeNode(attr, isId); + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(getClass().getName()); + buffer.append("[tagName="); + buffer.append(getTagName()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java new file mode 100644 index 0000000..76367f8 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java @@ -0,0 +1,102 @@ +/* GnomeEntity.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.Entity; + +/** + * A DOM entity node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeEntity +extends GnomeNode +implements Entity +{ + + GnomeEntity (Object id) + { + super (id); + } + + public native String getPublicId (); + + public native String getSystemId (); + + public native String getNotationName (); + + // DOM Level 3 methods + + public String getInputEncoding () + { + // TODO + return null; + } + + public String getXmlEncoding () + { + // TODO + return null; + } + + public String getXmlVersion () + { + // TODO + return null; + } + + public String toString () + { + String publicId = getPublicId (); + StringBuffer buffer = new StringBuffer (getClass ().getName ()); + buffer.append ("["); + if (publicId != null) + { + buffer.append ("publicId="); + buffer.append (publicId); + buffer.append (","); + } + buffer.append ("systemId="); + buffer.append (getSystemId ()); + buffer.append (",notationName="); + buffer.append (getNotationName ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java new file mode 100644 index 0000000..136b3a6 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java @@ -0,0 +1,57 @@ +/* GnomeEntityReference.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.EntityReference; + +/** + * A DOM entity reference node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeEntityReference +extends GnomeNode +implements EntityReference +{ + + GnomeEntityReference (Object id) + { + super (id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java new file mode 100644 index 0000000..8ca8921 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java @@ -0,0 +1,92 @@ +/* GnomeNamedNodeMap.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * A DOM named node map implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNamedNodeMap +implements NamedNodeMap +{ + + /** + * The node id. + */ + private final Object id; + + /** + * The map type. + * 0=attributes + * 1=entities + * 2=notations + */ + private final int type; + + GnomeNamedNodeMap (Object id, int type) + { + this.id = id; + this.type = type; + } + + public native Node getNamedItem (String name); + + public native Node setNamedItem (Node arg) + throws DOMException; + + public native Node removeNamedItem (String name) + throws DOMException; + + public native Node item (int index); + + public native int getLength (); + + public native Node getNamedItemNS (String namespaceURI, String localName); + + public native Node setNamedItemNS (Node arg) + throws DOMException; + + public native Node removeNamedItemNS (String namespaceURI, + String localName); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java new file mode 100644 index 0000000..4a2e9ff --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java @@ -0,0 +1,499 @@ +/* GnomeNode.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; + +import gnu.xml.libxmlj.util.StandaloneDocumentType; + +/** + * A DOM node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNode + implements Node, Comparable +{ + + /** + * Maps document pointers to a map of node pointers to node instances. + */ + static Map instances; + + /** + * Retrieves the node instance for the specified node pointer. + * This creates a new instance and adds it to the cache if required. + * @param doc the document pointer + * @param node the node pointer + * @param type the node type + */ + static GnomeNode newInstance(final Object doc, final Object node, + final int type) + { + if (doc == null) + { + throw new NullPointerException("doc"); + } + if (node == null) + { + throw new NullPointerException("node"); + } + if (instances == null) + { + instances = new HashMap(); + } + Map docNodes = (Map) instances.get(doc); + if (docNodes == null) + { + docNodes = new HashMap(1024); // TODO review optimal initial capacity + instances.put(doc, docNodes); + } + GnomeNode nodeInstance = (GnomeNode) docNodes.get(node); + if (nodeInstance != null) + { + return nodeInstance; // Return cached version + } + switch (type) + { + case ELEMENT_NODE: + nodeInstance = new GnomeElement(node); + break; + case ATTRIBUTE_NODE: + nodeInstance = new GnomeAttr(node); + break; + case TEXT_NODE: + nodeInstance = new GnomeText(node); + break; + case CDATA_SECTION_NODE: + nodeInstance = new GnomeCDATASection(node); + break; + case ENTITY_REFERENCE_NODE: + nodeInstance = new GnomeEntityReference(node); + break; + case ENTITY_NODE: + nodeInstance = new GnomeEntity(node); + break; + case PROCESSING_INSTRUCTION_NODE: + nodeInstance = new GnomeProcessingInstruction(node); + break; + case COMMENT_NODE: + nodeInstance = new GnomeComment(node); + break; + case DOCUMENT_NODE: + nodeInstance = new GnomeDocument(node); + break; + case DOCUMENT_TYPE_NODE: + nodeInstance = new GnomeDocumentType(node); + break; + case DOCUMENT_FRAGMENT_NODE: + nodeInstance = new GnomeDocumentFragment(node); + break; + case NOTATION_NODE: + nodeInstance = new GnomeNotation(node); + break; + default: + throw new IllegalArgumentException("Unknown node type: " + type); + } + docNodes.put(node, nodeInstance); + return nodeInstance; + } + + /** + * Frees the specified document. + * This removes all its nodes from the cache. + */ + static void freeDocument(final Object doc) + { + if (instances == null || doc == null) + { + return; + } + instances.remove(doc); + //System.out.println("Freed "+instances.remove(doc)); + } + + /** + * xmlNodePtr + */ + final Object id; + + Map userData; + Map userDataHandlers; + + GnomeNode(final Object id) + { + this.id = id; + } + + public native String getNodeName(); + + public native String getNodeValue() + throws DOMException; + + public native void setNodeValue(String nodeValue) + throws DOMException; + + public native short getNodeType(); + + public native Node getParentNode(); + + public NodeList getChildNodes() + { + return new GnomeNodeList(id); + } + + public native Node getFirstChild(); + + public native Node getLastChild(); + + public native Node getPreviousSibling(); + + public native Node getNextSibling(); + + public NamedNodeMap getAttributes() + { + return new GnomeNamedNodeMap(id, 0); + } + + public native Document getOwnerDocument(); + + public Node insertBefore(Node newChild, Node refChild) + throws DOMException + { + if (newChild instanceof StandaloneDocumentType) + { + DocumentType dt = (DocumentType) newChild; + newChild = ((GnomeDocument) getOwnerDocument()) + .createDocumentType(dt.getName(), dt.getPublicId(), + dt.getSystemId()); + } + if (newChild == null) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + if (!(newChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null); + } + if (refChild == null || !(refChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + return xmljInsertBefore(newChild, refChild); + } + + private native Node xmljInsertBefore(Node newChild, Node refChild) + throws DOMException; + + public Node replaceChild(Node newChild, Node oldChild) + throws DOMException + { + if (newChild instanceof StandaloneDocumentType) + { + DocumentType dt = (DocumentType) newChild; + newChild = ((GnomeDocument) getOwnerDocument()) + .createDocumentType(dt.getName(), dt.getPublicId(), + dt.getSystemId()); + } + if (newChild == null) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + if (!(newChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, newChild.toString()); + } + if (oldChild == null || !(oldChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + return xmljReplaceChild(newChild, oldChild); + } + + private native Node xmljReplaceChild(Node newChild, Node oldChild) + throws DOMException; + + public Node removeChild(Node oldChild) + throws DOMException + { + if (!(oldChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null); + } + return xmljRemoveChild(oldChild); + } + + private native Node xmljRemoveChild(Node oldChild) + throws DOMException; + + public Node appendChild(Node newChild) + throws DOMException + { + if (newChild instanceof StandaloneDocumentType) + { + DocumentType dt = (DocumentType) newChild; + newChild = ((GnomeDocument) getOwnerDocument()) + .createDocumentType(dt.getName(), dt.getPublicId(), + dt.getSystemId()); + } + if (!(newChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null); + } + return xmljAppendChild(newChild); + } + + private native Node xmljAppendChild(Node newChild) + throws DOMException; + + public native boolean hasChildNodes(); + + public Node cloneNode(boolean deep) + { + Node ret = xmljCloneNode(deep); + notifyUserDataHandlers(UserDataHandler.NODE_CLONED, this, ret); + return ret; + } + + private native Node xmljCloneNode(boolean deep); + + public native void normalize(); + + public boolean isSupported(String feature, String version) + { + return getOwnerDocument().getImplementation() + .hasFeature(feature, version); + } + + public native String getNamespaceURI(); + + public native String getPrefix(); + + public native void setPrefix(String prefix) + throws DOMException; + + public native String getLocalName(); + + public native boolean hasAttributes(); + + public int hashCode() + { + return id.hashCode(); + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + return (other instanceof GnomeNode && + ((GnomeNode) other).id == id); + } + + // DOM Level 3 methods + + public native String getBaseURI(); + + public short compareDocumentPosition(Node other) + throws DOMException + { + return (short) compareTo(other); + } + + public final int compareTo(Object other) + { + if (other instanceof GnomeNode) + { + return xmljCompareTo(other); + } + return 0; + } + + private native int xmljCompareTo(Object other); + + public String getTextContent() + throws DOMException + { + switch (getNodeType()) + { + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_NODE: + case ENTITY_REFERENCE_NODE: + case DOCUMENT_FRAGMENT_NODE: + StringBuffer buffer = new StringBuffer(); + NodeList children = getChildNodes(); + int len = children.getLength(); + for (int i = 0; i < len; i++) + { + Node child = children.item(i); + String textContent = child.getTextContent(); + if (textContent != null) + { + buffer.append(textContent); + } + } + return buffer.toString(); + case TEXT_NODE: + case CDATA_SECTION_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + return getNodeValue(); + default: + return null; + } + } + + public void setTextContent(String textContent) + throws DOMException + { + switch (getNodeType()) + { + case ENTITY_REFERENCE_NODE: + // entity references are read only + throw new GnomeDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + null); + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_NODE: + case DOCUMENT_FRAGMENT_NODE: + NodeList children = getChildNodes(); + int len = children.getLength(); + for (int i = 0; i < len; i++) + { + Node child = children.item(i); + removeChild(child); + } + if (textContent != null) + { + Text text = getOwnerDocument().createTextNode(textContent); + appendChild(text); + } + break; + case TEXT_NODE: + case CDATA_SECTION_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + setNodeValue(textContent); + break; + } + } + + public boolean isSameNode(Node other) + { + return equals(other); + } + + public native String lookupPrefix(String namespaceURI); + + public native boolean isDefaultNamespace(String namespaceURI); + + public native String lookupNamespaceURI(String prefix); + + public native boolean isEqualNode(Node arg); + + public Object getFeature(String feature, String version) + { + return getOwnerDocument().getImplementation() + .getFeature(feature, version); + } + + public Object setUserData(String key, Object data, UserDataHandler handler) + { + // TODO handler + if (userData == null) + { + userData = new HashMap(); + } + if (handler != null) + { + if (userDataHandlers == null) + { + userDataHandlers = new HashMap(); + } + userDataHandlers.put(key, handler); + } + return userData.put(key, data); + } + + public Object getUserData(String key) + { + if (userData == null) + { + return null; + } + return userData.get(key); + } + + void notifyUserDataHandlers(short op, Node src, Node dst) + { + if (userDataHandlers != null) + { + for (Iterator i = userDataHandlers.entrySet().iterator(); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String key = (String) entry.getKey(); + UserDataHandler handler = (UserDataHandler) entry.getValue(); + Object data = userData.get(key); + handler.handle(op, key, data, src, dst); + } + } + } + + public String toString() + { + StringBuffer buffer = new StringBuffer(getClass().getName()); + buffer.append("[nodeName="); + buffer.append(getNodeName()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java new file mode 100644 index 0000000..efd07ac --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java @@ -0,0 +1,66 @@ +/* GnomeNodeList.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A DOM node list implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNodeList +implements NodeList +{ + + /** + * The node id. + */ + private final Object id; + + GnomeNodeList (Object id) + { + this.id = id; + } + + public native Node item (int index); + + public native int getLength (); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java new file mode 100644 index 0000000..ca1560e --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java @@ -0,0 +1,78 @@ +/* GnomeNotation.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.Notation; + +/** + * A DOM notation node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNotation +extends GnomeNode +implements Notation +{ + + GnomeNotation (Object id) + { + super (id); + } + + public native String getPublicId (); + + public native String getSystemId (); + + public String toString () + { + String publicId = getPublicId (); + StringBuffer buffer = new StringBuffer (getClass ().getName ()); + buffer.append ("["); + if (publicId != null) + { + buffer.append ("publicId="); + buffer.append (publicId); + buffer.append (","); + } + buffer.append ("systemId="); + buffer.append (getSystemId ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java new file mode 100644 index 0000000..a6c47b2 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java @@ -0,0 +1,77 @@ +/* GnomeProcessingInstruction.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.ProcessingInstruction; + +/** + * A DOM processing instruction node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeProcessingInstruction +extends GnomeNode +implements ProcessingInstruction +{ + + GnomeProcessingInstruction (Object id) + { + super (id); + } + + public String getTarget () + { + return getNodeName (); + } + + public native String getData (); + + public native void setData (String data) + throws DOMException; + + public String toString () + { + StringBuffer buffer = new StringBuffer (getClass ().getName ()); + buffer.append ("[data="); + buffer.append (getData ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java new file mode 100644 index 0000000..77677a5 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java @@ -0,0 +1,130 @@ +/* GnomeText.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +/** + * A DOM text node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeText +extends GnomeCharacterData +implements Text +{ + + GnomeText (Object id) + { + super (id); + } + + public Text splitText (int offset) + throws DOMException + { + String value = getNodeValue (); + String part1 = value.substring (0, offset); + String part2 = value.substring (offset); + Text text = getOwnerDocument ().createTextNode (part1); + getParentNode ().insertBefore (text, this); + setNodeValue (part2); + return text; + } + + // DOM Level 3 + + public boolean isElementContentWhitespace () + { + return getTextContent ().trim ().length () == 0; + } + + public String getWholeText () + { + Node first = this; + Node node = getPreviousSibling (); + while (node != null && node instanceof Text) + { + first = node; + node = node.getPreviousSibling (); + } + StringBuffer buf = new StringBuffer (first.getNodeValue ()); + node = first.getNextSibling (); + while (node != null && node instanceof Text) + { + buf.append (node.getNodeValue ()); + node = node.getNextSibling (); + } + return buf.toString (); + } + + public Text replaceWholeText (String content) throws DOMException + { + boolean isEmpty = (content == null || content.length () == 0); + if (!isEmpty) + { + setNodeValue (content); + } + + Node first = this; + Node node = getPreviousSibling (); + while (node != null && node instanceof Text) + { + first = node; + node = node.getPreviousSibling (); + } + node = first.getNextSibling (); + Node parent = getParentNode (); + if (first != this || isEmpty) + { + parent.removeChild (first); + } + while (node != null && node instanceof Text) + { + Node tmp = node; + node = node.getNextSibling (); + if (tmp != this || isEmpty) + { + parent.removeChild (tmp); + } + } + return (isEmpty) ? null : this; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java new file mode 100644 index 0000000..d365f0d --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java @@ -0,0 +1,65 @@ +/* GnomeTypeInfo.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.TypeInfo; + +/** + * Provides XML Schema information about an element or attribute. + * + * @author Chris Burdess + */ +class GnomeTypeInfo implements TypeInfo +{ + + final Object id; + + GnomeTypeInfo(Object id) + { + this.id = id; + } + + public native String getTypeName (); + + public native String getTypeNamespace (); + + public native boolean isDerivedFrom (String typeNamespaceArg, + String typeNameArg, + int derivationMethod); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java new file mode 100644 index 0000000..8158047 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java @@ -0,0 +1,86 @@ +/* GnomeXPathExpression.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathExpression; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * A compiled XPath expression implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeXPathExpression +implements XPathExpression +{ + + /** + * xmlXPathCompExprPtr + */ + final Object expr; + + GnomeXPathExpression (GnomeDocument doc, String expression, + XPathNSResolver resolver) + { + expr = init (expression); + // TODO resolver + } + + protected void finalize () + { + free (expr); + } + + private native Object init (String expression); + + private native void free (Object expr); + + public Object evaluate (Node contextNode, short type, Object result) + throws XPathException, DOMException + { + return doEvaluate (expr, contextNode, type, result); + } + + private native Object doEvaluate (Object expr, Node contextNode, + short type, Object result) + throws XPathException, DOMException; + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java new file mode 100644 index 0000000..a9ba855 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java @@ -0,0 +1,65 @@ +/* GnomeXPathNSResolver.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * XPath namespace URI resolver implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeXPathNSResolver + implements XPathNSResolver +{ + + Node node; + + GnomeXPathNSResolver(Node node) + { + this.node = node; + } + + public String lookupNamespaceURI(String prefix) + { + return node.lookupNamespaceURI(prefix); + } + +} + diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java new file mode 100644 index 0000000..dde3be2 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java @@ -0,0 +1,73 @@ +/* GnomeXPathNodeList.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A node list that uses an XPath result object. + * + * @author Chris Burdess + */ +class GnomeXPathNodeList +implements NodeList +{ + + /** + * xmlXPathObjectPtr + */ + final Object obj; + + GnomeXPathNodeList (Object obj) + { + this.obj = obj; + } + + protected void finalize () + { + free(obj); + } + + private native void free (Object obj); + + public native int getLength (); + + public native Node item (int index); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java new file mode 100644 index 0000000..b384e4a --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java @@ -0,0 +1,132 @@ +/* GnomeXPathResult.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathResult; + +/** + * An XPath result object implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeXPathResult +implements XPathResult +{ + + /** + * xmlXPathObjectPtr + */ + final Object obj; + + GnomeXPathResult (Object obj) + { + this.obj = obj; + } + + protected void finalize () + { + free (obj); + } + + private native void free (Object obj); + + public native short getResultType (); + + public native double getNumberValue () + throws XPathException; + + public native String getStringValue () + throws XPathException; + + public native boolean getBooleanValue () + throws XPathException; + + public native Node getSingleNodeValue () + throws XPathException; + + public native boolean getInvalidIteratorState(); + + public native int getSnapshotLength () + throws XPathException; + + public native Node iterateNext () + throws XPathException, DOMException; + + public native Node snapshotItem (int index) + throws XPathException; + + public String toString () + { + short type = getResultType (); + switch (type) + { + case STRING_TYPE: + return getStringValue (); + case NUMBER_TYPE: + return new Double (getNumberValue ()).toString (); + case BOOLEAN_TYPE: + return Boolean.valueOf (getBooleanValue ()).toString (); + case UNORDERED_NODE_SNAPSHOT_TYPE: + int len = getSnapshotLength (); + switch (len) { + case 0: + return "[no matches]"; + case 1: + return getSingleNodeValue ().toString (); + default: + StringBuffer buffer = new StringBuffer (); + for (int i = 0; i < len; i++) + { + if (i > 0) + { + buffer.append (','); + } + buffer.append (snapshotItem (i)); + } + return buffer.toString (); + } + default: + return getClass ().getName () + "[type=" + type + ",length=" + + getSnapshotLength () + ']'; + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java new file mode 100644 index 0000000..0c812f6 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java @@ -0,0 +1,99 @@ +/* GnomeLocator.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.sax; + +import org.xml.sax.Locator; + +/** + * SAX Locator implementation that uses libxml2. + * + * @author Chris Burdess + */ +class GnomeLocator +implements Locator +{ + + // An xmlParserCtxtPtr + private final Object ctx; + + // An xmlSAXLocatorPtr + private final Object loc; + + GnomeLocator (Object ctx, Object loc) + { + this.ctx = ctx; + this.loc = loc; + if (ctx == null) + { + throw new NullPointerException ("ctx"); + } + if (loc == null) + { + throw new NullPointerException ("loc"); + } + } + + public String getPublicId () + { + return publicId (ctx, loc); + } + + private native String publicId (Object ctx, Object loc); + + public String getSystemId () + { + return systemId (ctx, loc); + } + + private native String systemId (Object ctx, Object loc); + + public int getLineNumber () + { + return lineNumber (ctx, loc); + } + + private native int lineNumber (Object ctx, Object loc); + + public int getColumnNumber () + { + return columnNumber (ctx, loc); + } + + private native int columnNumber (Object ctx, Object loc); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java new file mode 100644 index 0000000..a5cdc42 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java @@ -0,0 +1,105 @@ +/* GnomeSAXParser.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.sax; + +import javax.xml.parsers.SAXParser; + +import org.xml.sax.Parser; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; + +/** + * JAXP SAX parser implementation that uses libxml2. + * + * @author Chris Burdess + */ +class GnomeSAXParser +extends SAXParser +{ + + private boolean namespaceAware; + private boolean validating; + + /** + * Creates a new SAX parser. + */ + GnomeSAXParser (boolean namespaceAware, boolean validating) + { + this.namespaceAware = namespaceAware; + this.validating = validating; + } + + public Parser getParser () + throws SAXException + { + throw new SAXNotSupportedException ("SAX version 1 not supported"); + } + + public XMLReader getXMLReader () + throws SAXException + { + return new GnomeXMLReader (namespaceAware, validating); + } + + public Object getProperty (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkPropertyName (name); + throw new SAXNotSupportedException (name); + } + + public void setProperty (String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkPropertyName (name); + throw new SAXNotSupportedException (name); + } + + public boolean isNamespaceAware () + { + return namespaceAware; + } + + public boolean isValidating () + { + return validating; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java new file mode 100644 index 0000000..5152d54 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java @@ -0,0 +1,92 @@ +/* GnomeSAXParserFactory.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.sax; + +import java.util.Map; +import java.util.HashMap; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + * JAXP SAX parser factory implementation that uses libxml2. + * + * @author Chris Burdess + */ +public class GnomeSAXParserFactory +extends SAXParserFactory +{ + + private Map features; + + /** + * Creates a new SAX parser factory. + */ + public GnomeSAXParserFactory () + { + features = new HashMap (); + } + + public SAXParser newSAXParser () + throws ParserConfigurationException, SAXException + { + // TODO features + return new GnomeSAXParser (isNamespaceAware (), isValidating ()); + } + + public boolean getFeature (String name) + throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkFeatureName (name); + Boolean val = (Boolean) features.get (name); + return (val == null) ? false : val.booleanValue (); + } + + public void setFeature (String name, boolean flag) + throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkFeatureName (name); + features.put (name, flag ? Boolean.TRUE : Boolean.FALSE); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java new file mode 100644 index 0000000..846015a --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java @@ -0,0 +1,1065 @@ +/* GnomeXMLReader.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.sax; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; + +import gnu.xml.libxmlj.util.NamedInputStream; +import gnu.xml.libxmlj.util.StandaloneLocator; +import gnu.xml.libxmlj.util.XMLJ; + +/** + * A SAX2 parser that uses libxml2. + * + * @author Chris Burdess + */ +public class GnomeXMLReader +implements XMLReader +{ + + static + { + XMLJ.init (); + } + + private static final String FEATURES_PREFIX = + "http://xml.org/sax/features/"; + + private static final List RECOGNIZED_FEATURES = + Arrays.asList (new String[] + { + "external-general-entities", + "external-parameter-entities", + "is-standalone", + "lexical-handler/parameter-entities", + "namespaces", + "namespace-prefixes", + "resolve-dtd-uris", + "string-interning", + "use-attributes2", + "use-locator2", + "use-entity-resolver2", + "validation" + }); + + private static final String PROPERTIES_PREFIX = + "http://xml.org/sax/properties/"; + + private static final List RECOGNIZED_PROPERTIES = + Arrays.asList (new String[] + { + "declaration-handler", + "dom-node", + "lexical-handler", + "xml-string" + }); + + // Features + + private transient boolean standalone; + private boolean namespaces; + private boolean namespacePrefixes; + private boolean validation; + + // Callback handlers + + private ContentHandler contentHandler; + + private DTDHandler dtdHandler; + + private EntityResolver entityResolver; + + private ErrorHandler errorHandler; + + private DeclHandler declarationHandler; + + private LexicalHandler lexicalHandler; + + private GnomeLocator locator; + + // Namespace helper for handling callbacks + private transient Namespaces ns; + + // If true, do not invoke callback methods except endDocument + private transient boolean seenFatalError; + + private transient boolean seenStartDocument; + + private transient String base; + + public GnomeXMLReader () + { + this (true, true); + } + + public GnomeXMLReader (boolean namespaces, boolean validation) + { + this.namespaces = namespaces; + this.validation = validation; + ns = new Namespaces (); + } + + public ContentHandler getContentHandler () + { + return contentHandler; + } + + public void setContentHandler (ContentHandler handler) + { + contentHandler = handler; + } + + public DTDHandler getDTDHandler () + { + return dtdHandler; + } + + public void setDTDHandler (DTDHandler handler) + { + dtdHandler = handler; + } + + public EntityResolver getEntityResolver () + { + return entityResolver; + } + + public void setEntityResolver (EntityResolver resolver) + { + entityResolver = resolver; + } + + public ErrorHandler getErrorHandler () + { + return errorHandler; + } + + public void setErrorHandler (ErrorHandler handler) + { + errorHandler = handler; + } + + // Features + + public boolean getFeature (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkFeatureName (name); + String key = name.substring (FEATURES_PREFIX.length ()); + if ("external-general-entities".equals (key)) + { + return validation; // TODO check this + } + else if ("external-parameter-entities".equals (key)) + { + return validation; // TODO check this + } + else if ("is-standalone".equals (key)) + { + return standalone; + } + else if ("namespaces".equals (key)) + { + return namespaces; + } + else if ("namespace-prefixes".equals (key)) + { + return namespacePrefixes; + } + else if ("resolve-dtd-uris".equals (key)) + { + return true; + } + else if ("validation".equals (key)) + { + return validation; + } + else + { + return false; + } + } + + public void setFeature (String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkFeatureName (name); + String key = name.substring (FEATURES_PREFIX.length ()); + if ("namespaces".equals (key)) + { + namespaces = value; + } + else if ("namespace-prefixes".equals (key)) + { + namespacePrefixes = value; + } + else if ("validation".equals (key)) + { + validation = value; + } + } + + /** + * Check that the specified feature name is recognized. + */ + static void checkFeatureName (String name) + throws SAXNotRecognizedException + { + if (name == null || !name.startsWith (FEATURES_PREFIX)) + { + throw new SAXNotRecognizedException (name); + } + String key = name.substring (FEATURES_PREFIX.length ()); + if (!RECOGNIZED_FEATURES.contains (key)) + { + throw new SAXNotRecognizedException (name); + } + } + + // Properties + + public Object getProperty (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkPropertyName (name); + String key = name.substring (PROPERTIES_PREFIX.length ()); + if ("declaration-handler".equals (key)) + { + return getDeclarationHandler (); + } + else if ("lexical-handler".equals (key)) + { + return getLexicalHandler (); + } + else + { + throw new SAXNotSupportedException (name); + } + } + + public void setProperty (String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkPropertyName (name); + String key = name.substring (PROPERTIES_PREFIX.length ()); + if ("declaration-handler".equals (key)) + { + setDeclarationHandler ((DeclHandler) value); + } + else if ("lexical-handler".equals (key)) + { + setLexicalHandler ((LexicalHandler) value); + } + } + + public DeclHandler getDeclarationHandler () + { + return declarationHandler; + } + + public void setDeclarationHandler (DeclHandler declarationHandler) + { + this.declarationHandler = declarationHandler; + } + + public LexicalHandler getLexicalHandler () + { + return lexicalHandler; + } + + public void setLexicalHandler (LexicalHandler lexicalHandler) + { + this.lexicalHandler = lexicalHandler; + } + + /** + * Check that the specified property name is recognized. + */ + static void checkPropertyName (String name) + throws SAXNotRecognizedException + { + if (!name.startsWith (PROPERTIES_PREFIX)) + { + throw new SAXNotRecognizedException (name); + } + String key = name.substring (PROPERTIES_PREFIX.length ()); + if (!RECOGNIZED_PROPERTIES.contains (key)) + { + throw new SAXNotRecognizedException (name); + } + } + + // Parse + + public void parse (String systemId) + throws IOException, SAXException + { + URL url = null; + try + { + url = new URL (systemId); + } + catch (MalformedURLException e) + { + File file = new File(systemId); + if (!file.exists ()) + { + throw new FileNotFoundException (systemId); + } + String path = file.getAbsolutePath(); + if (File.separatorChar != '/') + { + path = path.replace (File.separatorChar, '/'); + } + if (!path.startsWith ("/")) + { + path = "/" + path; + } + if (!path.endsWith ("/") && file.isDirectory ()) + { + path = path + "/"; + } + url = new URL ("file:" + path); + } + InputSource source = new InputSource(url.toString ()); + source.setByteStream (url.openStream ()); + parse (source); + } + + public synchronized void parse (InputSource input) + throws IOException, SAXException + { + NamedInputStream in = XMLJ.getInputStream (input); + byte[] detectBuffer = in.getDetectBuffer (); + String publicId = input.getPublicId (); + String systemId = input.getSystemId (); + base = XMLJ.getBaseURI (systemId); + // Reset state + standalone = false; + seenFatalError = false; + seenStartDocument = false; + if (systemId != null) + { + int lsi = systemId.lastIndexOf ('/'); + if (lsi != -1) + { + base = systemId.substring (0, lsi + 1); + } + } + // Handle zero-length document + if (detectBuffer == null) + { + startDocument (true); + fatalError ("No document element", 0, 0, publicId, systemId); + endDocument (); + return; + } + // Parse + parseStream(in, + detectBuffer, + publicId, + systemId, + base, + validation, + contentHandler != null, + dtdHandler != null, + entityResolver != null, + errorHandler != null, + declarationHandler != null, + lexicalHandler != null); + in.close (); + } + + native void parseStream (InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean validate, + boolean contentHandler, + boolean dtdHandler, + boolean entityResolver, + boolean errorHandler, + boolean declarationHandler, + boolean lexicalHandler) + throws IOException, SAXException; + + String getURI (String prefix) + { + if (!namespaces) + { + return null; + } + return ns.getURI (prefix); + } + + // Callbacks from libxmlj + + private void startDTD (String name, String publicId, String systemId) + throws SAXException + { + if (seenFatalError || lexicalHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + lexicalHandler.startDTD (name, publicId, systemId); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void externalEntityDecl (String name, String publicId, + String systemId) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + declarationHandler.externalEntityDecl (name, publicId, systemId); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void internalEntityDecl (String name, String value) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + declarationHandler.internalEntityDecl (name, value); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private InputStream resolveEntity (String publicId, String systemId) + throws SAXException, IOException + { + if (entityResolver == null) + { + return null; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + InputSource source = entityResolver.resolveEntity (publicId, systemId); + return (source == null) ? null : XMLJ.getInputStream (source); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + if (seenFatalError || dtdHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + dtdHandler.notationDecl (name, publicId, systemId); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void attributeDecl (String eName, String aName, String type, + String mode, String value) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + declarationHandler.attributeDecl (eName, aName, type, mode, value); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void elementDecl (String name, String model) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + declarationHandler.elementDecl (name, model); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void unparsedEntityDecl (String name, String publicId, + String systemId, String notationName) + throws SAXException + { + if (seenFatalError || dtdHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + dtdHandler.unparsedEntityDecl (name, publicId, systemId, + notationName); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void setDocumentLocator (Object ctx, Object loc) + { + locator = new GnomeLocator (ctx, loc); + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + contentHandler.setDocumentLocator (locator); + } + catch (Exception e) + { + } + } + + private void startDocument (boolean standalone) + throws SAXException + { + this.standalone = standalone; + seenStartDocument = true; + if (contentHandler == null) + { + return; + } + try + { + contentHandler.startDocument (); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void endDocument () + throws SAXException + { + if (contentHandler == null) + { + return; + } + try + { + contentHandler.endDocument(); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void startElement(String name, String[] attrs) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + XMLName xName = new XMLName (this, name); + if (namespaces) + { + // Handle defined namespaces + ns.push (); + int len = (attrs == null) ? 0 : attrs.length; + if (len > 0) + { + ArrayList filtered = new ArrayList (len); + for (int i = 0; i < len; i += 2) + { + String attName = attrs[i]; + String attValue = attrs[i + 1]; + if (attName.equals ("xmlns")) + { + startPrefixMapping ("", attValue); + } + else if (attName.startsWith ("xmlns:")) + { + startPrefixMapping (attName.substring (6), attValue); + } + else + { + filtered.add (attName); + filtered.add (attValue); + } + } + // Remove xmlns attributes + attrs = new String[filtered.size ()]; + filtered.toArray (attrs); + } + } + // Construct attributes + Attributes atts = new StringArrayAttributes (this, attrs); + contentHandler.startElement (xName.uri, xName.localName, xName.qName, + atts); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void endElement (String name) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + XMLName xName = new XMLName (this, name); + String uri = (xName.uri == null) ? "" : xName.uri; + contentHandler.endElement (uri, xName.localName, xName.qName); + // Handle undefining namespaces + if (namespaces) + { + for (Iterator i = ns.currentPrefixes (); i.hasNext (); ) + { + endPrefixMapping ((String) i.next ()); + } + ns.pop (); // releases current depth + } + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + ns.define (prefix, uri); + contentHandler.startPrefixMapping (prefix, uri); + } + + private void endPrefixMapping (String prefix) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + contentHandler.endPrefixMapping (prefix); + } + + private void characters (String text) + throws SAXException + { + if (seenFatalError || contentHandler == null || text == null) + { + return; + } + try + { + char[] ch = text.toCharArray (); + contentHandler.characters (ch, 0, ch.length); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void ignorableWhitespace (String text) + throws SAXException + { + if (seenFatalError || contentHandler == null || text == null) + { + return; + } + try + { + char[] ch = text.toCharArray (); + contentHandler.ignorableWhitespace (ch, 0, ch.length); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void processingInstruction (String target, String data) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + if (data == null) + { + data = ""; + } + contentHandler.processingInstruction (target, data); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void comment (String text) + throws SAXException + { + if (seenFatalError || lexicalHandler == null || text == null) + { + return; + } + try + { + char[] ch = text.toCharArray (); + lexicalHandler.comment (ch, 0, ch.length); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void cdataBlock (String text) + throws SAXException + { + if (seenFatalError || text == null) + { + return; + } + try + { + if (lexicalHandler == null) + { + characters(text); + } + else + { + lexicalHandler.startCDATA(); + characters(text); + lexicalHandler.endCDATA(); + } + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void warning (String message, + int lineNumber, int columnNumber, + String publicId, String systemId) + throws SAXException + { + if (seenFatalError || errorHandler == null) + { + return; + } + try + { + Locator l = new StandaloneLocator (lineNumber, columnNumber, + publicId, systemId); + errorHandler.warning (new SAXParseException (message, l)); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void error (String message, + int lineNumber, int columnNumber, + String publicId, String systemId) + throws SAXException + { + if (seenFatalError || errorHandler == null) + { + return; + } + try + { + Locator l = new StandaloneLocator (lineNumber, columnNumber, + publicId, systemId); + errorHandler.error (new SAXParseException (message, l)); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void fatalError (String message, + int lineNumber, int columnNumber, + String publicId, String systemId) + throws SAXException + { + if (seenFatalError || errorHandler == null) + { + return; + } + try + { + if (!seenStartDocument) + { + startDocument (false); + } + seenFatalError = true; + Locator l = new StandaloneLocator (lineNumber, columnNumber, + publicId, systemId); + errorHandler.fatalError (new SAXParseException (message, l)); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java b/libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java new file mode 100644 index 0000000..646d7b4 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java @@ -0,0 +1,122 @@ +/* Namespaces.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.sax; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; + +/** + * Helper class for managing namespaces. + * + * @author Chris Burdess + */ +class Namespaces +{ + + ArrayList stack = new ArrayList (); + + /** + * Increments the tree depth. + * This allocates a new potential namespace entry. + */ + void push () + { + stack.add (null); + } + + /** + * Decrements the tree depth. + * This removes namespaces defined at the extremity. + */ + void pop () + { + stack.remove (stack.size() - 1); + } + + /** + * Searches for the namespace URI corresponding to the specified prefix. + */ + String getURI (String prefix) + { + for (int i = stack.size () - 1; i >= 0; i--) + { + HashMap ns = (HashMap) stack.get (i); + if (ns != null && ns.containsKey (prefix)) + { + String ret = (String) ns.get (prefix); + return (ret == null) ? "" : ret; + } + } + return ""; + } + + /** + * Defines the specified prefix-URI mapping at the current depth in the + * tree. + */ + void define (String prefix, String uri) + { + int index = stack.size () - 1; + HashMap ns = (HashMap) stack.get (index); + if (ns == null) + { + ns = new HashMap (); + stack.set (index, ns); + } + ns.put (prefix, uri); + } + + /** + * Returns an iterator over the prefixes defined at the current depth. + */ + Iterator currentPrefixes () + { + HashMap ns = (HashMap) stack.get (stack.size () - 1); + if (ns == null) + { + return Collections.EMPTY_LIST.iterator (); + } + else + { + return ns.keySet ().iterator (); + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java b/libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java new file mode 100644 index 0000000..f534efb --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java @@ -0,0 +1,171 @@ +/* StringArrayAttributes.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.sax; + +import org.xml.sax.Attributes; + +/** + * An implementation of Attributes that reads values from an array of + * strings, supplied by libxml2. + * Each pair of elements in the array represents a key followed by a value. + * + * @author Chris Burdess + */ +class StringArrayAttributes +implements Attributes +{ + + private int len; + private XMLName[] keys; + private String[] values; + + StringArrayAttributes (GnomeXMLReader parser, String[] pairs) + { + len = (pairs == null) ? 0 : pairs.length / 2; + keys = new XMLName[len]; + values = new String[len]; + for (int i = 0; i < len; i++) + { + int pairIndex = i * 2; + keys[i] = new XMLName (parser, pairs[pairIndex]); + values[i] = pairs[pairIndex + 1]; + } + } + + public int getLength () + { + return len; + } + + public String getURI (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return keys[index].uri; + } + + public String getLocalName (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return keys[index].localName; + } + + public String getQName (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return keys[index].qName; + } + + public String getType (int index) + { + if (index < 0 || index >= len) + { + return null; + } + // TODO can we get this information from libxml2? + return "CDATA"; + } + + public String getValue (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return values[index]; + } + + public int getIndex (String uri, String localName) + { + for (int i = 0; i < len; i++) + { + XMLName key = keys[i]; + if (key.localName.equals (localName)) + { + if ((key.uri == null && uri == null) || + (key.uri != null && key.uri.equals(uri))) + { + return i; + } + } + } + return -1; + } + + public int getIndex (String qName) + { + for (int i = 0; i < len; i++) + { + if (keys[i].qName.equals (qName)) + { + return i; + } + } + return -1; + } + + public String getType (String uri, String localName) + { + return getType (getIndex (uri, localName)); + } + + public String getType (String qName) + { + return getType (getIndex (qName)); + } + + public String getValue (String uri, String localName) + { + return getValue (getIndex (uri, localName)); + } + + public String getValue (String qName) + { + return getValue (getIndex (qName)); + } + +} + diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java b/libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java new file mode 100644 index 0000000..5950a79 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java @@ -0,0 +1,92 @@ +/* XMLName.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.sax; + +/** + * Structure containing the components of an XML element/attribute name. + * + * @author Chris Burdess + */ +class XMLName +{ + + private static final String XML_URI = "http://www.w3.org/XML/1998/namespace"; + + final String uri; + final String localName; + final String qName; + final String prefix; + + XMLName (GnomeXMLReader parser, String qName) + { + this.qName = qName; + int ci = qName.lastIndexOf (':'); + if (ci < 1) + { + localName = qName; + prefix = null; + uri = ""; + } + else + { + localName = qName.substring (ci + 1); + prefix = qName.substring (0, ci); + if ("xml".equals (prefix)) + { + if ("lang".equals (localName) || "space".equals (localName)) + { + uri = XML_URI; + } + else + { + uri = parser.getURI (prefix); + } + } + else + { + uri = parser.getURI (prefix); + } + } + } + + public String toString () + { + return qName; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java b/libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java new file mode 100644 index 0000000..0601e5e --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java @@ -0,0 +1,111 @@ +/* ErrorListenerErrorHandler.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.transform; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.TransformerException; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * Provides a SAX ErrorHandler interface to an ErrorListener. + * + * @author Chris Burdess + */ +class ErrorListenerErrorHandler +implements ErrorHandler +{ + + private ErrorListener listener; + + ErrorListenerErrorHandler (ErrorListener listener) + { + this.listener = listener; + } + + public void warning (SAXParseException e) + throws SAXException + { + try + { + listener.warning (new TransformerException (e)); + } + catch (TransformerException te) + { + throw getSAXException (te); + } + } + + public void error (SAXParseException e) + throws SAXException + { + try + { + listener.error (new TransformerException (e)); + } + catch (TransformerException te) + { + throw getSAXException (te); + } + } + + public void fatalError (SAXParseException e) + throws SAXException + { + try + { + listener.fatalError (new TransformerException (e)); + } + catch (TransformerException te) + { + throw getSAXException (te); + } + } + + private SAXException getSAXException (TransformerException e) + { + Throwable cause = e.getCause (); + if (cause instanceof SAXException) + { + return (SAXException) cause; + } + return new SAXException (e); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java new file mode 100755 index 0000000..37aa05b --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java @@ -0,0 +1,572 @@ +/* GnomeTransformer.java - + Copyright (C) 2004 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 gnu.xml.libxmlj.transform; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.net.URL; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.Source; +import javax.xml.transform.SourceLocator; +import javax.xml.transform.Result; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; + +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Node; + +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; + +import gnu.xml.libxmlj.dom.GnomeDocument; +import gnu.xml.libxmlj.sax.GnomeXMLReader; +import gnu.xml.libxmlj.util.NamedInputStream; +import gnu.xml.libxmlj.util.StandaloneLocator; +import gnu.xml.libxmlj.util.XMLJ; + +/** + * An implementation of {@link javax.xml.transform.Transformer} which + * performs XSLT transformation usinglibxslt
.
+ *
+ * @author Julian Scheid
+ * @author Chris Burdess
+ */
+public class GnomeTransformer
+ extends Transformer
+ implements Templates
+{
+
+ /**
+ * The parameters added by the user via {@link setParameter()}.
+ */
+ private Map parameters;
+
+ /**
+ * The output properties set by the user.
+ */
+ private Properties outputProperties;
+
+ /**
+ * The URI resolver to use during transformation.
+ */
+ private URIResolver resolver;
+
+ /**
+ * The error listener for transformation errors.
+ */
+ private ErrorListener errorListener;
+
+ /**
+ * Handle to the source stylesheet.
+ * This is a native pointer of type xsltStylesheetPtr.
+ */
+ private Object stylesheet;
+
+ /**
+ * Constructor.
+ * @param source the XSLT stylesheet document source
+ * @param resolver the resolver to use during transformation
+ * @param errorListener the error listener for transformation errors
+ */
+ GnomeTransformer (Source source,
+ URIResolver resolver,
+ ErrorListener errorListener)
+ throws TransformerConfigurationException
+ {
+ this.resolver = resolver;
+ this.errorListener = errorListener;
+ parameters = new HashMap ();
+ outputProperties = new Properties ();
+
+ if (source == null)
+ {
+ stylesheet = newStylesheet ();
+ }
+ else if (source instanceof StreamSource)
+ {
+ try
+ {
+ StreamSource ss = (StreamSource) source;
+ NamedInputStream in = XMLJ.getInputStream (ss);
+ String systemId = ss.getSystemId ();
+ String publicId = ss.getPublicId ();
+ String base = XMLJ.getBaseURI (systemId);
+ byte[] detectBuffer = in.getDetectBuffer ();
+ if (detectBuffer == null)
+ {
+ String msg = "No document element";
+ throw new TransformerConfigurationException (msg);
+ }
+ stylesheet = newStylesheetFromStream (in, detectBuffer, publicId,
+ systemId, base,
+ (resolver != null),
+ (errorListener != null));
+ }
+ catch (IOException e)
+ {
+ throw new TransformerConfigurationException (e);
+ }
+ }
+ else if (source instanceof DOMSource)
+ {
+ DOMSource ds = (DOMSource) source;
+ Node node = ds.getNode ();
+ if (!(node instanceof GnomeDocument))
+ {
+ String msg = "Node is not a GnomeDocument";
+ throw new TransformerConfigurationException (msg);
+ }
+ GnomeDocument doc = (GnomeDocument) node;
+ stylesheet = newStylesheetFromDoc (doc);
+ }
+ else
+ {
+ String msg = "Source type not supported (" + source + ")";
+ throw new TransformerConfigurationException (msg);
+ }
+ }
+
+ /**
+ * Copy constructor.
+ */
+ private GnomeTransformer (Object stylesheet,
+ URIResolver resolver,
+ ErrorListener errorListener,
+ Map parameters,
+ Properties outputProperties)
+ {
+ this.stylesheet = stylesheet;
+ this.resolver = resolver;
+ this.errorListener = errorListener;
+ this.parameters = parameters;
+ this.outputProperties = outputProperties;
+ }
+
+ private native Object newStylesheet ()
+ throws TransformerConfigurationException;
+
+ private native Object newStylesheetFromStream (InputStream in,
+ byte[] detectBuffer,
+ String publicId,
+ String systemId,
+ String base,
+ boolean entityResolver,
+ boolean errorHandler)
+ throws TransformerConfigurationException;
+
+ private native Object newStylesheetFromDoc (GnomeDocument doc)
+ throws TransformerConfigurationException;
+
+ //--- Implementation of javax.xml.transform.Transformer follows.
+
+ // Set, get and clear the parameters to use on transformation
+
+ public synchronized void setParameter (String parameter, Object value)
+ {
+ parameters.put (parameter, value);
+ }
+
+ public synchronized Object getParameter (String name)
+ {
+ return parameters.get (name);
+ }
+
+ public synchronized void clearParameters ()
+ {
+ parameters.clear ();
+ }
+
+ // Set and get the ErrorListener to use on transformation
+
+ public void setErrorListener (ErrorListener listener)
+ {
+ this.errorListener = listener;
+ }
+
+ public ErrorListener getErrorListener ()
+ {
+ return errorListener;
+ }
+
+ // Set and get the URIResolver to use on transformation
+
+ public void setURIResolver (URIResolver resolver)
+ {
+ this.resolver = resolver;
+ }
+
+ public URIResolver getURIResolver ()
+ {
+ return resolver;
+ }
+
+ // Set the output properties to use on transformation; get default
+ // output properties and output properties specified in the
+ // stylesheet or by the user.
+
+ public void setOutputProperties (Properties outputProperties)
+ {
+ // Note: defensive copying
+ this.outputProperties = new Properties (outputProperties);
+ }
+
+ public void setOutputProperty (String name, String value)
+ {
+ outputProperties.setProperty (name, value);
+ }
+
+ public Properties getOutputProperties ()
+ {
+ // Note: defensive copying
+ return new Properties (this.outputProperties);
+ }
+
+ public String getOutputProperty (String name)
+ {
+ return outputProperties.getProperty (name);
+ }
+
+ // -- Templates --
+
+ public Transformer newTransformer ()
+ {
+ return new GnomeTransformer (stylesheet, resolver, errorListener,
+ new HashMap (parameters),
+ new Properties (outputProperties));
+ }
+
+ // -- transform --
+
+ /**
+ * Transforms the given source and writes the result to the
+ * given target.
+ */
+ public void transform (Source source, Result result)
+ throws TransformerException
+ {
+ if (source instanceof StreamSource)
+ {
+ try
+ {
+ StreamSource ss = (StreamSource) source;
+ NamedInputStream in = XMLJ.getInputStream (ss);
+ String publicId = ss.getPublicId ();
+ String systemId = ss.getSystemId ();
+ String base = XMLJ.getBaseURI (systemId);
+ byte[] detectBuffer = in.getDetectBuffer ();
+ if (detectBuffer == null)
+ {
+ throw new TransformerException ("No document element");
+ }
+ if (result instanceof StreamResult)
+ {
+ OutputStream out = XMLJ.getOutputStream ((StreamResult) result);
+ transformStreamToStream (in, detectBuffer, publicId, systemId,
+ base, (resolver != null),
+ (errorListener != null), out);
+ }
+ else if (result instanceof DOMResult)
+ {
+ DOMResult dr = (DOMResult) result;
+ GnomeDocument ret =
+ transformStreamToDoc (in, detectBuffer, publicId, systemId,
+ base, (resolver != null),
+ (errorListener != null));
+ dr.setNode (ret);
+ dr.setSystemId (null);
+ }
+ else if (result instanceof SAXResult)
+ {
+ SAXResult sr = (SAXResult) result;
+ transformStreamToSAX (in, detectBuffer, publicId, systemId,
+ base, (resolver != null),
+ (errorListener != null),
+ getSAXContext (sr));
+ }
+ else
+ {
+ String msg = "Result type not supported (" + result + ")";
+ throw new TransformerConfigurationException (msg);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new TransformerException (e);
+ }
+ }
+ else if (source instanceof DOMSource)
+ {
+ DOMSource ds = (DOMSource) source;
+ Node node = ds.getNode ();
+ if (!(node instanceof GnomeDocument))
+ {
+ String msg = "Node is not a GnomeDocument (" + node + ")";
+ throw new TransformerException (msg);
+ }
+ GnomeDocument doc = (GnomeDocument) node;
+ if (result instanceof StreamResult)
+ {
+ try
+ {
+ OutputStream out = XMLJ.getOutputStream ((StreamResult) result);
+ transformDocToStream (doc, out);
+ }
+ catch (IOException e)
+ {
+ throw new TransformerException (e);
+ }
+ }
+ else if (result instanceof DOMResult)
+ {
+ DOMResult dr = (DOMResult) result;
+ GnomeDocument ret = transformDocToDoc (doc);
+ dr.setNode (ret);
+ dr.setSystemId (null);
+ }
+ else if (result instanceof SAXResult)
+ {
+ SAXResult sr = (SAXResult) result;
+ transformDocToSAX (doc, getSAXContext (sr));
+ }
+ else
+ {
+ String msg = "Result type not supported";
+ throw new TransformerConfigurationException (msg);
+ }
+ }
+ else
+ {
+ String msg = "Source type not supported";
+ throw new TransformerConfigurationException (msg);
+ }
+ }
+
+ private GnomeXMLReader getSAXContext (SAXResult result)
+ {
+ GnomeXMLReader ctx = new GnomeXMLReader ();
+ ctx.setContentHandler (result.getHandler ());
+ ctx.setLexicalHandler (result.getLexicalHandler ());
+ if (errorListener != null)
+ {
+ ErrorHandler errorHandler =
+ new ErrorListenerErrorHandler (errorListener);
+ ctx.setErrorHandler (errorHandler);
+ }
+ if (resolver != null)
+ {
+ EntityResolver entityResolver =
+ new URIResolverEntityResolver (resolver);
+ ctx.setEntityResolver (entityResolver);
+ }
+ return ctx;
+ }
+
+ private native void transformStreamToStream (InputStream in,
+ byte[] detectBuffer,
+ String publicId,
+ String systemId,
+ String base,
+ boolean entityResolver,
+ boolean errorHandler,
+ OutputStream out)
+ throws TransformerException;
+
+ private native GnomeDocument transformStreamToDoc (InputStream in,
+ byte[] detectBuffer,
+ String publicId,
+ String systemId,
+ String base,
+ boolean entityResolver,
+ boolean errorHandler)
+ throws TransformerException;
+
+ private native void transformStreamToSAX (InputStream in,
+ byte[] detectBuffer,
+ String publicId,
+ String systemId,
+ String base,
+ boolean entityResolver,
+ boolean errorHandler,
+ GnomeXMLReader out)
+ throws TransformerException;
+
+ private native void transformDocToStream (GnomeDocument in,
+ OutputStream out)
+ throws TransformerException;
+
+ private native GnomeDocument transformDocToDoc (GnomeDocument in)
+ throws TransformerException;
+
+ private native void transformDocToSAX (GnomeDocument in,
+ GnomeXMLReader out)
+ throws TransformerException;
+
+ /*
+ * Retrieve parameters as a string array.
+ * This is a convenience method called from native code.
+ */
+ private String[] getParameterArray ()
+ {
+ String[] parameterArray = new String[parameters.size () * 2];
+ int index = 0;
+ for (Iterator it = parameters.keySet ().iterator ();
+ it.hasNext ();
+ ++index)
+ {
+ String parameterKey = (String) it.next ();
+ String parameterValue = (String) parameters.get (parameterKey);
+ parameterArray[index * 2 + 0] = parameterKey;
+ parameterArray[index * 2 + 1] =
+ "'" + ((parameterValue != null) ? parameterValue : "") + "'";
+ // FIXME encode parameter value correctly for XPath
+ }
+ return parameterArray;
+ }
+
+ // -- Free xsltStylesheet handle --
+
+ public void finalize ()
+ {
+ if (stylesheet != null)
+ {
+ free ();
+ stylesheet = null;
+ }
+ }
+
+ private native void free ();
+
+ // -- Callbacks --
+
+ private InputStream resolveEntity (String publicId, String systemId)
+ throws TransformerException
+ {
+ if (resolver != null)
+ {
+ systemId = resolver.resolve (null, systemId).getSystemId ();
+ }
+ if (systemId == null)
+ {
+ return null;
+ }
+ try
+ {
+ URL url = new URL (systemId);
+ return XMLJ.getInputStream (url);
+ }
+ catch (IOException e)
+ {
+ throw new TransformerException (e);
+ }
+ }
+
+ private void setDocumentLocator (Object ctx, Object loc)
+ {
+ }
+
+ private void warning (String message,
+ int lineNumber,
+ int columnNumber,
+ String publicId,
+ String systemId)
+ throws TransformerException
+ {
+ if (errorListener == null)
+ {
+ return;
+ }
+ SourceLocator l = new StandaloneLocator (lineNumber,
+ columnNumber,
+ publicId,
+ systemId);
+ errorListener.warning (new TransformerException (message, l));
+ }
+
+ private void error (String message,
+ int lineNumber,
+ int columnNumber,
+ String publicId,
+ String systemId)
+ throws TransformerException
+ {
+ if (errorListener == null)
+ {
+ return;
+ }
+ SourceLocator l = new StandaloneLocator (lineNumber,
+ columnNumber,
+ publicId,
+ systemId);
+ errorListener.error (new TransformerException (message, l));
+ }
+
+ private void fatalError (String message,
+ int lineNumber,
+ int columnNumber,
+ String publicId,
+ String systemId)
+ throws TransformerException
+ {
+ if (errorListener == null)
+ {
+ return;
+ }
+ SourceLocator l = new StandaloneLocator (lineNumber,
+ columnNumber,
+ publicId,
+ systemId);
+ errorListener.fatalError (new TransformerException (message, l));
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java
new file mode 100755
index 0000000..78dfe21
--- /dev/null
+++ b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java
@@ -0,0 +1,349 @@
+/* GnomeTransformerFactory.java -
+ Copyright (C) 2004 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 gnu.xml.libxmlj.transform;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.URIResolver;
+
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+import gnu.xml.libxmlj.util.XMLJ;
+
+/**
+ * An implementation of TransformerFactory
producing
+ * Transformer
objects which use libxslt
+ * for transformation.
+ *
+ * @author Julian Scheid
+ * @author Chris Burdess
+ */
+public class GnomeTransformerFactory
+ extends TransformerFactory
+{
+
+ static
+ {
+ XMLJ.init ();
+ }
+
+ /**
+ * URIResolver set by user, or default implementation.
+ */
+ private URIResolver uriResolver;
+
+ /**
+ * ErrorListener set by user, or default implementation.
+ */
+ private ErrorListener errorListener;
+
+ /**
+ * Attributes set by user.
+ */
+ private Map attributes = new HashMap ();
+
+ //--- Implementation of javax.xml.transform.TransformerFactory
+ //--- follows.
+
+ // -- begin getAssociatedStylesheet implementation --
+
+ /**
+ * Returns the stylesheet associated with the specified XML source, or
+ * null
if no associated stylesheet could be found.
+ */
+ public Source getAssociatedStylesheet(Source source, String media,
+ String title, String charset)
+ throws TransformerConfigurationException
+ {
+ String href= null;
+ String base = source.getSystemId();
+ if (source instanceof DOMSource)
+ {
+ Node node = ((DOMSource) source).getNode();
+ Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) ?
+ (Document) node : node.getOwnerDocument();
+ if (base == null)
+ {
+ base = doc.getDocumentURI();
+ }
+ for (node = doc.getFirstChild(); node != null;
+ node = node.getNextSibling())
+ {
+ if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE &&
+ "xml-stylesheet".equals(node.getNodeName()))
+ {
+ String data = node.getNodeValue();
+ if (media != null &&
+ !media.equals(parseParameter(data, "type")))
+ {
+ continue;
+ }
+ if (title != null &&
+ !title.equals(parseParameter(data, "title")))
+ {
+ continue;
+ }
+ href = parseParameter(data, "href");
+ }
+ }
+ }
+ else
+ {
+ InputSource input;
+ XMLReader parser = null;
+ try
+ {
+ if (source instanceof SAXSource)
+ {
+ SAXSource sax = (SAXSource) source;
+ input = sax.getInputSource();
+ parser = sax.getXMLReader();
+ }
+ else
+ {
+ StreamSource stream = (StreamSource) source;
+ InputStream in = stream.getInputStream();
+ input = new InputSource(in);
+ }
+ input.setSystemId(base);
+ if (parser == null)
+ {
+ parser = createXMLReader();
+ }
+ AssociatedStylesheetHandler ash =
+ new AssociatedStylesheetHandler();
+ ash.media = media;
+ ash.title = title;
+ parser.setContentHandler(ash);
+ parser.parse(input);
+ href = ash.href;
+ }
+ catch (SAXException e)
+ {
+ throw new TransformerConfigurationException(e);
+ }
+ catch (IOException e)
+ {
+ throw new TransformerConfigurationException(e);
+ }
+ }
+ if (href == null)
+ {
+ return null;
+ }
+ if (base != null)
+ {
+ base = XMLJ.getBaseURI(base);
+ }
+ href = XMLJ.getAbsoluteURI(base, href);
+ return new StreamSource(href);
+ }
+
+ private XMLReader createXMLReader()
+ throws TransformerConfigurationException
+ {
+ try
+ {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser parser = factory.newSAXParser();
+ return parser.getXMLReader();
+ }
+ catch (FactoryConfigurationError e)
+ {
+ throw new TransformerConfigurationException(e);
+ }
+ catch (ParserConfigurationException e)
+ {
+ throw new TransformerConfigurationException(e);
+ }
+ catch (SAXException e)
+ {
+ throw new TransformerConfigurationException(e);
+ }
+ }
+
+ class AssociatedStylesheetHandler
+ extends DefaultHandler
+ {
+
+ String media;
+ String title;
+ String href;
+
+ public void processingInstruction(String target, String data)
+ throws SAXException
+ {
+ if ("xml-stylesheet".equals(target))
+ {
+ if (media != null && !media.equals(parseParameter(data, "type")))
+ {
+ return;
+ }
+ if (title != null && !title.equals(parseParameter(data, "title")))
+ {
+ return;
+ }
+ href = parseParameter(data, "href");
+ }
+ }
+
+ }
+
+ String parseParameter(String data, String name)
+ {
+ int start = data.indexOf(name + "=");
+ if (start != -1)
+ {
+ start += name.length() + 2;
+ char delim = data.charAt(start - 1);
+ int end = data.indexOf(delim, start);
+ if (end != -1)
+ {
+ return data.substring(start, end);
+ }
+ }
+ return null;
+ }
+
+ // -- end getAssociatedStylesheet implementation --
+
+ public synchronized void setAttribute (String name, Object value)
+ {
+ this.attributes.put (name, value);
+ }
+
+ public synchronized Object getAttribute (String name)
+ {
+ return attributes.get (name);
+ }
+
+ public void setErrorListener (ErrorListener errorListener)
+ {
+ this.errorListener = errorListener;
+ }
+
+ public ErrorListener getErrorListener ()
+ {
+ return errorListener;
+ }
+
+ public void setURIResolver (URIResolver uriResolver)
+ {
+ this.uriResolver = uriResolver;
+ }
+
+ public URIResolver getURIResolver ()
+ {
+ return uriResolver;
+ }
+
+ public boolean getFeature (String name)
+ {
+ return (StreamSource.FEATURE.equals (name) ||
+ StreamResult.FEATURE.equals (name) ||
+ DOMSource.FEATURE.equals (name) ||
+ DOMResult.FEATURE.equals (name));
+ }
+
+ public void setFeature(String name, boolean value)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException(name);
+ }
+
+ /**
+ * Returns a new instance of class {@link Transformer} for a
+ * null souce.
+ */
+ public Transformer newTransformer ()
+ throws TransformerConfigurationException
+ {
+ return newTransformer (null);
+ }
+
+ /**
+ * Returns a new instance of class {@link Transformer} for
+ * the given souce.
+ */
+ public Transformer newTransformer (Source source)
+ throws TransformerConfigurationException
+ {
+ return new GnomeTransformer (source, uriResolver, errorListener);
+ }
+
+ /**
+ * Returns a new instance of class {@link Templates} for
+ * the given souce.
+ */
+ public Templates newTemplates (Source source)
+ throws TransformerConfigurationException
+ {
+ return new GnomeTransformer (source, uriResolver, errorListener);
+ }
+
+ /**
+ * Perform native cleanup.
+ */
+ public static native void freeLibxsltGlobal ();
+
+}
diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java b/libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java
new file mode 100644
index 0000000..88a58e1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java
@@ -0,0 +1,87 @@
+/* URIResolverEntityResolver.java -
+ Copyright (C) 2004 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 gnu.xml.libxmlj.transform;
+
+import java.io.IOException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.sax.SAXSource;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Provides an EntityResolver interface to a URIResolver.
+ *
+ * @author Chris Burdess
+ */
+class URIResolverEntityResolver
+implements EntityResolver
+{
+
+ private URIResolver resolver;
+
+ URIResolverEntityResolver (URIResolver resolver)
+ {
+ this.resolver = resolver;
+ }
+
+ public InputSource resolveEntity (String publicId, String systemId)
+ throws SAXException, IOException
+ {
+ try
+ {
+ return SAXSource.sourceToInputSource (resolver.resolve (systemId,
+ null));
+ }
+ catch (TransformerException e)
+ {
+ Throwable cause = e.getCause ();
+ if (cause instanceof SAXException)
+ {
+ throw (SAXException) cause;
+ }
+ else if (cause instanceof IOException)
+ {
+ throw (IOException) cause;
+ }
+ throw new SAXException (e);
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/package.html b/libjava/classpath/gnu/xml/libxmlj/transform/package.html
new file mode 100755
index 0000000..dac1027
--- /dev/null
+++ b/libjava/classpath/gnu/xml/libxmlj/transform/package.html
@@ -0,0 +1,14 @@
+
++ A JAXP-compliant wrapper for the XSLT C library for Gnome, also + known as libxslt. Allows to use libxslt via the Java API for XML + processing. +
+ ++ Usage: +
javax.xml.transform.TransformerFactory
+ to gnu.xml.libxmlj.GnomeTransformerFactory
.In effect, this makes a remote procedure call to the URI, with the + * request and response document syntax as chosen by the application. + * Note that all the input events must be seen, and sent to the URI, + * before the first output event can be seen. Clients are delayed + * at least by waiting for the server to respond, constraining concurrency. + * Services can thus be used to synchronize concurrent activities, and + * even to prioritize service among different clients. + * + *
You are advised to avoid restricting yourself to an "RPC" model + * for distributed computation. With a World Wide Web, network latencies + * and failures (e.g. non-availability) + * are significant; adopting a "procedure" model, rather than a workflow + * model where bulk requests are sent and worked on asynchronously, is not + * generally an optimal system-wide architecture. When the messages may + * need authentication, such as with an OpenPGP signature, or when server + * loads don't argue in favor of immediate responses, non-RPC models can + * be advantageous. (So-called "peer to peer" computing models are one + * additional type of model, though too often that term is applied to + * systems that still have a centralized control structure.) + * + *
Be strict in what you send, liberal in what you accept, as + * the Internet tradition goes. Strictly conformant data should never cause + * problems to its receiver; make your request pipeline be very strict, and + * don't compromise on that. Make your response pipeline strict as well, + * but be ready to tolerate specific mild, temporary, and well-documented + * variations from specific communications peers. + * + * @see XmlServlet + * + * @author David Brownell + */ +final public class CallFilter implements EventConsumer +{ + private Requestor req; + private EventConsumer next; + private URL target; + private URLConnection conn; + private ErrorHandler errHandler; + + + /** + * Initializes a call filter so that its inputs are sent to the + * specified URI, and its outputs are sent to the next consumer + * provided. + * + * @exception IOException if the URI isn't accepted as a URL + */ + // constructor used by PipelineFactory + public CallFilter (String uri, EventConsumer next) + throws IOException + { + this.next = next; + req = new Requestor (); + setCallTarget (uri); + } + + /** + * Assigns the URI of the call target to be used. + * Does not affect calls currently being made. + */ + final public void setCallTarget (String uri) + throws IOException + { + target = new URL (uri); + } + + /** + * Assigns the error handler to be used to present most fatal + * errors. + */ + public void setErrorHandler (ErrorHandler handler) + { + req.setErrorHandler (handler); + } + + + /** + * Returns the call target's URI. + */ + final public String getCallTarget () + { + return target.toString (); + } + + /** Returns the content handler currently in use. */ + final public org.xml.sax.ContentHandler getContentHandler () + { + return req; + } + + /** Returns the DTD handler currently in use. */ + final public DTDHandler getDTDHandler () + { + return req; + } + + + /** + * Returns the declaration or lexical handler currently in + * use, or throws an exception for other properties. + */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + if (EventFilter.DECL_HANDLER.equals (id)) + return req; + if (EventFilter.LEXICAL_HANDLER.equals (id)) + return req; + throw new SAXNotRecognizedException (id); + } + + + // JDK 1.1 seems to need it to be done this way, sigh + ErrorHandler getErrorHandler () { return errHandler; } + + // + // Takes input and echoes to server as POST input. + // Then sends the POST reply to the next pipeline element. + // + final class Requestor extends XMLWriter + { + Requestor () + { + super ((Writer)null); + } + + public synchronized void startDocument () throws SAXException + { + // Connect to remote object and set up to send it XML text + try { + if (conn != null) + throw new IllegalStateException ("call is being made"); + + conn = target.openConnection (); + conn.setDoOutput (true); + conn.setRequestProperty ("Content-Type", + "application/xml;charset=UTF-8"); + + setWriter (new OutputStreamWriter ( + conn.getOutputStream (), + "UTF8"), "UTF-8"); + + } catch (IOException e) { + fatal ("can't write (POST) to URI: " + target, e); + } + + // NOW base class can safely write that text! + super.startDocument (); + } + + public void endDocument () throws SAXException + { + // + // Finish writing the request (for HTTP, a POST); + // this closes the output stream. + // + super.endDocument (); + + // + // Receive the response. + // Produce events for the next stage. + // + InputSource source; + XMLReader producer; + String encoding; + + try { + + source = new InputSource (conn.getInputStream ()); + +// FIXME if status is anything but success, report it!! It'd be good to +// save the request data just in case we need to deal with a forward. + + encoding = Resolver.getEncoding (conn.getContentType ()); + if (encoding != null) + source.setEncoding (encoding); + + producer = XMLReaderFactory.createXMLReader (); + producer.setErrorHandler (getErrorHandler ()); + EventFilter.bind (producer, next); + producer.parse (source); + conn = null; + + } catch (IOException e) { + fatal ("I/O Exception reading response, " + e.getMessage (), e); + } + } + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/DomConsumer.java b/libjava/classpath/gnu/xml/pipeline/DomConsumer.java new file mode 100644 index 0000000..389e02b --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/DomConsumer.java @@ -0,0 +1,982 @@ +/* DomConsumer.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.pipeline; + +import gnu.xml.aelfred2.ContentHandler2; +import gnu.xml.util.DomParser; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.helpers.AttributesImpl; +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.CharacterData; +import org.w3c.dom.Document; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + +/** + * This consumer builds a DOM Document from its input, acting either as a + * pipeline terminus or as an intermediate buffer. When a document's worth + * of events has been delivered to this consumer, that document is read with + * a {@link DomParser} and sent to the next consumer. It is also available + * as a read-once property. + * + *
The DOM tree is constructed as faithfully as possible. There are some + * complications since a DOM should expose behaviors that can't be implemented + * without API backdoors into that DOM, and because some SAX parsers don't + * report all the information that DOM permits to be exposed. The general + * problem areas involve information from the Document Type Declaration (DTD). + * DOM only represents a limited subset, but has some behaviors that depend + * on much deeper knowledge of a document's DTD. You shouldn't have much to + * worry about unless you change handling of "noise" nodes from its default + * setting (which ignores them all); note if you use JAXP to populate your + * DOM trees, it wants to save "noise" nodes by default. (Such nodes include + * ignorable whitespace, comments, entity references and CDATA boundaries.) + * Otherwise, your + * main worry will be if you use a SAX parser that doesn't flag ignorable + * whitespace unless it's validating (few don't). + * + *
The SAX2 events used as input must contain XML Names for elements + * and attributes, with original prefixes. In SAX2, + * this is optional unless the "namespace-prefixes" parser feature is set. + * Moreover, many application components won't provide completely correct + * structures anyway. Before you convert a DOM to an output document, + * you should plan to postprocess it to create or repair such namespace + * information. The {@link NSFilter} pipeline stage does such work. + * + *
Note: changes late in DOM L2 process made it impractical to + * attempt to create the DocumentType node in any implementation-neutral way, + * much less to populate it (L1 didn't support even creating such nodes). + * To create and populate such a node, subclass the inner + * {@link DomConsumer.Handler} class and teach it about the backdoors into + * whatever DOM implementation you want. It's possible that some revised + * DOM API (L3?) will make this problem solvable again. + * + * @see DomParser + * + * @author David Brownell + */ +public class DomConsumer implements EventConsumer +{ + private Class domImpl; + + private boolean hidingCDATA = true; + private boolean hidingComments = true; + private boolean hidingWhitespace = true; + private boolean hidingReferences = true; + + private Handler handler; + private ErrorHandler errHandler; + + private EventConsumer next; + + // FIXME: this can't be a generic pipeline stage just now, + // since its input became a Class not a String (to be turned + // into a class, using the right class loader) + + + /** + * Configures this pipeline terminus to use the specified implementation + * of DOM when constructing its result value. + * + * @param impl class implementing {@link org.w3c.dom.Document Document} + * which publicly exposes a default constructor + * + * @exception SAXException when there is a problem creating an + * empty DOM document using the specified implementation + */ + public DomConsumer (Class impl) + throws SAXException + { + domImpl = impl; + handler = new Handler (this); + } + + /** + * This is the hook through which a subclass provides a handler + * which knows how to access DOM extensions, specific to some + * implementation, to record additional data in a DOM. + * Treat this as part of construction; don't call it except + * before (or between) parses. + */ + protected void setHandler (Handler h) + { + handler = h; + } + + + private Document emptyDocument () + throws SAXException + { + try { + return (Document) domImpl.newInstance (); + } catch (IllegalAccessException e) { + throw new SAXException ("can't access constructor: " + + e.getMessage ()); + } catch (InstantiationException e) { + throw new SAXException ("can't instantiate Document: " + + e.getMessage ()); + } + } + + + /** + * Configures this consumer as a buffer/filter, using the specified + * DOM implementation when constructing its result value. + * + *
This event consumer acts as a buffer and filter, in that it + * builds a DOM tree and then writes it out when endDocument + * is invoked. Because of the limitations of DOM, much information + * will as a rule not be seen in that replay. To get a full fidelity + * copy of the input event stream, use a {@link TeeConsumer}. + * + * @param impl class implementing {@link org.w3c.dom.Document Document} + * which publicly exposes a default constructor + * @param next receives a "replayed" sequence of parse events when + * the endDocument method is invoked. + * + * @exception SAXException when there is a problem creating an + * empty DOM document using the specified DOM implementation + */ + public DomConsumer (Class impl, EventConsumer n) + throws SAXException + { + this (impl); + next = n; + } + + + /** + * Returns the document constructed from the preceding + * sequence of events. This method should not be + * used again until another sequence of events has been + * given to this EventConsumer. + */ + final public Document getDocument () + { + return handler.clearDocument (); + } + + public void setErrorHandler (ErrorHandler handler) + { + errHandler = handler; + } + + + /** + * Returns true if the consumer is hiding entity references nodes + * (the default), and false if EntityReference nodes should + * instead be created. Such EntityReference nodes will normally be + * empty, unless an implementation arranges to populate them and then + * turn them back into readonly objects. + * + * @see #setHidingReferences + */ + final public boolean isHidingReferences () + { return hidingReferences; } + + /** + * Controls whether the consumer will hide entity expansions, + * or will instead mark them with entity reference nodes. + * + * @see #isHidingReferences + * @param flag False if entity reference nodes will appear + */ + final public void setHidingReferences (boolean flag) + { hidingReferences = flag; } + + + /** + * Returns true if the consumer is hiding comments (the default), + * and false if they should be placed into the output document. + * + * @see #setHidingComments + */ + public final boolean isHidingComments () + { return hidingComments; } + + /** + * Controls whether the consumer is hiding comments. + * + * @see #isHidingComments + */ + public final void setHidingComments (boolean flag) + { hidingComments = flag; } + + + /** + * Returns true if the consumer is hiding ignorable whitespace + * (the default), and false if such whitespace should be placed + * into the output document as children of element nodes. + * + * @see #setHidingWhitespace + */ + public final boolean isHidingWhitespace () + { return hidingWhitespace; } + + /** + * Controls whether the consumer hides ignorable whitespace + * + * @see #isHidingComments + */ + public final void setHidingWhitespace (boolean flag) + { hidingWhitespace = flag; } + + + /** + * Returns true if the consumer is saving CDATA boundaries, or + * false (the default) otherwise. + * + * @see #setHidingCDATA + */ + final public boolean isHidingCDATA () + { return hidingCDATA; } + + /** + * Controls whether the consumer will save CDATA boundaries. + * + * @see #isHidingCDATA + * @param flag True to treat CDATA text differently from other + * text nodes + */ + final public void setHidingCDATA (boolean flag) + { hidingCDATA = flag; } + + + + /** Returns the document handler being used. */ + final public ContentHandler getContentHandler () + { return handler; } + + /** Returns the DTD handler being used. */ + final public DTDHandler getDTDHandler () + { return handler; } + + /** + * Returns the lexical handler being used. + * (DOM construction can't really use declaration handlers.) + */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + if ("http://xml.org/sax/properties/lexical-handler".equals (id)) + return handler; + if ("http://xml.org/sax/properties/declaration-handler".equals (id)) + return handler; + throw new SAXNotRecognizedException (id); + } + + EventConsumer getNext () { return next; } + + ErrorHandler getErrorHandler () { return errHandler; } + + /** + * Class used to intercept various parsing events and use them to + * populate a DOM document. Subclasses would typically know and use + * backdoors into specific DOM implementations, used to implement + * DTD-related functionality. + * + *
Note that if this ever throws a DOMException (runtime exception) + * that will indicate a bug in the DOM (e.g. doesn't support something + * per specification) or the parser (e.g. emitted an illegal name, or + * accepted illegal input data).
+ */ + public static class Handler + implements ContentHandler2, LexicalHandler, + DTDHandler, DeclHandler + { + protected DomConsumer consumer; + + private DOMImplementation impl; + private Document document; + private boolean isL2; + + private Locator locator; + private Node top; + private boolean inCDATA; + private boolean mergeCDATA; + private boolean inDTD; + private String currentEntity; + + private boolean recreatedAttrs; + private AttributesImpl attributes = new AttributesImpl (); + + /** + * Subclasses may use SAX2 events to provide additional + * behaviors in the resulting DOM. + */ + protected Handler (DomConsumer consumer) + throws SAXException + { + this.consumer = consumer; + document = consumer.emptyDocument (); + impl = document.getImplementation (); + isL2 = impl.hasFeature ("XML", "2.0"); + } + + private void fatal (String message, Exception x) + throws SAXException + { + SAXParseException e; + ErrorHandler errHandler = consumer.getErrorHandler ();; + + if (locator == null) + e = new SAXParseException (message, null, null, -1, -1, x); + else + e = new SAXParseException (message, locator, x); + if (errHandler != null) + errHandler.fatalError (e); + throw e; + } + + /** + * Returns and forgets the document produced. If the handler is + * reused, a new document may be created. + */ + Document clearDocument () + { + Document retval = document; + document = null; + locator = null; + return retval; + } + + /** + * Returns the document under construction. + */ + protected Document getDocument () + { return document; } + + /** + * Returns the current node being populated. This is usually + * an Element or Document, but it might be an EntityReference + * node if some implementation-specific code knows how to put + * those into the result tree and later mark them as readonly. + */ + protected Node getTop () + { return top; } + + + // SAX1 + public void setDocumentLocator (Locator locator) + { + this.locator = locator; + } + + // SAX1 + public void startDocument () + throws SAXException + { + if (document == null) + try { + if (isL2) { + // couple to original implementation + document = impl.createDocument (null, "foo", null); + document.removeChild (document.getFirstChild ()); + } else { + document = consumer.emptyDocument (); + } + } catch (Exception e) { + fatal ("DOM create document", e); + } + top = document; + } + + // ContentHandler2 + public void xmlDecl(String version, + String encoding, + boolean standalone, + String inputEncoding) + throws SAXException + { + if (document != null) + { + document.setXmlVersion(version); + document.setXmlStandalone(standalone); + } + } + + // SAX1 + public void endDocument () + throws SAXException + { + try { + if (consumer.getNext () != null && document != null) { + DomParser parser = new DomParser (document); + + EventFilter.bind (parser, consumer.getNext ()); + parser.parse ("ignored"); + } + } finally { + top = null; + } + } + + // SAX1 + public void processingInstruction (String target, String data) + throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (currentEntity != null) + return; + + ProcessingInstruction pi; + + if (isL2 + // && consumer.isUsingNamespaces () + && target.indexOf (':') != -1) + namespaceError ( + "PI target name is namespace nonconformant: " + + target); + if (inDTD) + return; + pi = document.createProcessingInstruction (target, data); + top.appendChild (pi); + } + + /** + * Subclasses may overrride this method to provide a more efficient + * way to construct text nodes. + * Typically, copying the text into a single character array will + * be more efficient than doing that as well as allocating other + * needed for a String, including an internal StringBuffer. + * Those additional memory and CPU costs can be incurred later, + * if ever needed. + * Unfortunately the standard DOM factory APIs encourage those costs + * to be incurred early. + */ + protected Text createText ( + boolean isCDATA, + char ch [], + int start, + int length + ) { + String value = new String (ch, start, length); + + if (isCDATA) + return document.createCDATASection (value); + else + return document.createTextNode (value); + } + + // SAX1 + public void characters (char ch [], int start, int length) + throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly + // at creation time) + if (currentEntity != null) + return; + + Node lastChild = top.getLastChild (); + + // merge consecutive text or CDATA nodes if appropriate. + if (lastChild instanceof Text) { + if (consumer.isHidingCDATA () + // consecutive Text content ... always merge + || (!inCDATA + && !(lastChild instanceof CDATASection)) + // consecutive CDATASection content ... don't + // merge between sections, only within them + || (inCDATA && mergeCDATA + && lastChild instanceof CDATASection) + ) { + CharacterData last = (CharacterData) lastChild; + String value = new String (ch, start, length); + + last.appendData (value); + return; + } + } + if (inCDATA && !consumer.isHidingCDATA ()) { + top.appendChild (createText (true, ch, start, length)); + mergeCDATA = true; + } else + top.appendChild (createText (false, ch, start, length)); + } + + // SAX2 + public void skippedEntity (String name) + throws SAXException + { + // this callback is useless except to report errors, since + // we can't know if the ref was in content, within an + // attribute, within a declaration ... only one of those + // cases supports more intelligent action than a panic. + fatal ("skipped entity: " + name, null); + } + + // SAX2 + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + // reconstruct "xmlns" attributes deleted by all + // SAX2 parsers without "namespace-prefixes" = true + if ("".equals (prefix)) + attributes.addAttribute ("", "", "xmlns", + "CDATA", uri); + else + attributes.addAttribute ("", "", "xmlns:" + prefix, + "CDATA", uri); + recreatedAttrs = true; + } + + // SAX2 + public void endPrefixMapping (String prefix) + throws SAXException + { } + + // SAX2 + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (currentEntity != null) + return; + + // parser discarded basic information; DOM tree isn't writable + // without massaging to assign prefixes to all nodes. + // the "NSFilter" class does that massaging. + if (qName.length () == 0) + qName = localName; + + + Element element; + int length = atts.getLength (); + + if (!isL2) { + element = document.createElement (qName); + + // first the explicit attributes ... + length = atts.getLength (); + for (int i = 0; i < length; i++) + element.setAttribute (atts.getQName (i), + atts.getValue (i)); + // ... then any recreated ones (DOM deletes duplicates) + if (recreatedAttrs) { + recreatedAttrs = false; + length = attributes.getLength (); + for (int i = 0; i < length; i++) + element.setAttribute (attributes.getQName (i), + attributes.getValue (i)); + attributes.clear (); + } + + top.appendChild (element); + top = element; + return; + } + + // For an L2 DOM when namespace use is enabled, use + // createElementNS/createAttributeNS except when + // (a) it's an element in the default namespace, or + // (b) it's an attribute with no prefix + String namespace; + + if (localName.length () != 0) + namespace = (uri.length () == 0) ? null : uri; + else + namespace = getNamespace (getPrefix (qName), atts); + + if (namespace == null) + element = document.createElement (qName); + else + element = document.createElementNS (namespace, qName); + + populateAttributes (element, atts); + if (recreatedAttrs) { + recreatedAttrs = false; + // ... DOM deletes any duplicates + populateAttributes (element, attributes); + attributes.clear (); + } + + top.appendChild (element); + top = element; + } + + final static String xmlnsURI = "http://www.w3.org/2000/xmlns/"; + + private void populateAttributes (Element element, Attributes attrs) + throws SAXParseException + { + int length = attrs.getLength (); + + for (int i = 0; i < length; i++) { + String type = attrs.getType (i); + String value = attrs.getValue (i); + String name = attrs.getQName (i); + String local = attrs.getLocalName (i); + String uri = attrs.getURI (i); + + // parser discarded basic information, DOM tree isn't writable + if (name.length () == 0) + name = local; + + // all attribute types other than these three may not + // contain scoped names... enumerated attributes get + // reported as NMTOKEN, except for NOTATION values + if (!("CDATA".equals (type) + || "NMTOKEN".equals (type) + || "NMTOKENS".equals (type))) { + if (value.indexOf (':') != -1) { + namespaceError ( + "namespace nonconformant attribute value: " + + "<" + element.getNodeName () + + " " + name + "='" + value + "' ...>"); + } + } + + // xmlns="" is legal (undoes default NS) + // xmlns:foo="" is illegal + String prefix = getPrefix (name); + String namespace; + + if ("xmlns".equals (prefix)) { + if ("".equals (value)) + namespaceError ("illegal null namespace decl, " + name); + namespace = xmlnsURI; + } else if ("xmlns".equals (name)) + namespace = xmlnsURI; + + else if (prefix == null) + namespace = null; + else if (!"".equals(uri) && uri.length () != 0) + namespace = uri; + else + namespace = getNamespace (prefix, attrs); + + if (namespace == null) + element.setAttribute (name, value); + else + element.setAttributeNS (namespace, name, value); + } + } + + private String getPrefix (String name) + { + int temp; + + if ((temp = name.indexOf (':')) > 0) + return name.substring (0, temp); + return null; + } + + // used with SAX1-level parser output + private String getNamespace (String prefix, Attributes attrs) + throws SAXParseException + { + String namespace; + String decl; + + // defaulting + if (prefix == null) { + decl = "xmlns"; + namespace = attrs.getValue (decl); + if ("".equals (namespace)) + return null; + else if (namespace != null) + return namespace; + + // "xmlns" is like a keyword + // ... according to the Namespace REC, but DOM L2 CR2+ + // and Infoset violate that by assigning a namespace. + // that conflict is resolved elsewhere. + } else if ("xmlns".equals (prefix)) + return null; + + // "xml" prefix is fixed + else if ("xml".equals (prefix)) + return "http://www.w3.org/XML/1998/namespace"; + + // otherwise, expect a declaration + else { + decl = "xmlns:" + prefix; + namespace = attrs.getValue (decl); + } + + // if we found a local declaration, great + if (namespace != null) + return namespace; + + + // ELSE ... search up the tree we've been building + for (Node n = top; + n != null && n.getNodeType () != Node.DOCUMENT_NODE; + n = (Node) n.getParentNode ()) { + if (n.getNodeType () == Node.ENTITY_REFERENCE_NODE) + continue; + Element e = (Element) n; + Attr attr = e.getAttributeNode (decl); + if (attr != null) + return attr.getNodeValue (); + } + // see above re "xmlns" as keyword + if ("xmlns".equals (decl)) + return null; + + namespaceError ("Undeclared namespace prefix: " + prefix); + return null; + } + + // SAX2 + public void endElement (String uri, String localName, String qName) + throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (currentEntity != null) + return; + + top = top.getParentNode (); + } + + // SAX1 (mandatory reporting if validating) + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + if (consumer.isHidingWhitespace ()) + return; + characters (ch, start, length); + } + + // SAX2 lexical event + public void startCDATA () + throws SAXException + { + inCDATA = true; + // true except for the first fragment of a cdata section + mergeCDATA = false; + } + + // SAX2 lexical event + public void endCDATA () + throws SAXException + { + inCDATA = false; + } + + // SAX2 lexical event + // + // this SAX2 callback merges two unrelated things: + // - Declaration of the root element type ... belongs with + // the other DTD declaration methods, NOT HERE. + // - IDs for the optional external subset ... belongs here + // with other lexical information. + // + // ...and it doesn't include the internal DTD subset, desired + // both to support DOM L2 and to enable "pass through" processing + // + public void startDTD (String name, String publicId, String SystemId) + throws SAXException + { + // need to filter out comments and PIs within the DTD + inDTD = true; + } + + // SAX2 lexical event + public void endDTD () + throws SAXException + { + inDTD = false; + } + + // SAX2 lexical event + public void comment (char ch [], int start, int length) + throws SAXException + { + Node comment; + + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (consumer.isHidingComments () + || inDTD + || currentEntity != null) + return; + comment = document.createComment (new String (ch, start, length)); + top.appendChild (comment); + } + + /** + * May be overridden by subclasses to return true, indicating + * that entity reference nodes can be populated and then made + * read-only. + */ + public boolean canPopulateEntityRefs () + { return false; } + + // SAX2 lexical event + public void startEntity (String name) + throws SAXException + { + // are we ignoring what would be contents of an + // entity ref, since we can't populate it? + if (currentEntity != null) + return; + + // Are we hiding all entity boundaries? + if (consumer.isHidingReferences ()) + return; + + // SAX2 shows parameter entities; DOM hides them + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + + // Since we can't create a populated entity ref node in any + // standard way, we create an unpopulated one. + EntityReference ref = document.createEntityReference (name); + top.appendChild (ref); + top = ref; + + // ... allowing subclasses to populate them + if (!canPopulateEntityRefs ()) + currentEntity = name; + } + + // SAX2 lexical event + public void endEntity (String name) + throws SAXException + { + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + if (name.equals (currentEntity)) + currentEntity = null; + if (!consumer.isHidingReferences ()) + top = top.getParentNode (); + } + + + // SAX1 DTD event + public void notationDecl ( + String name, + String publicId, String SystemId + ) throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // SAX1 DTD event + public void unparsedEntityDecl ( + String name, + String publicId, String SystemId, + String notationName + ) throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // SAX2 declaration event + public void elementDecl (String name, String model) + throws SAXException + { + /* IGNORE -- no content model support in DOM L2 */ + } + + // SAX2 declaration event + public void attributeDecl ( + String eName, + String aName, + String type, + String mode, + String value + ) throws SAXException + { + /* IGNORE -- no attribute model support in DOM L2 */ + } + + // SAX2 declaration event + public void internalEntityDecl (String name, String value) + throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // SAX2 declaration event + public void externalEntityDecl ( + String name, + String publicId, + String SystemId + ) throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // + // These really should offer the option of nonfatal handling, + // like other validity errors, though that would cause major + // chaos in the DOM data structures. DOM is already spec'd + // to treat many of these as fatal, so this is consistent. + // + private void namespaceError (String description) + throws SAXParseException + { + SAXParseException err; + + err = new SAXParseException (description, locator); + throw err; + } + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/EventConsumer.java b/libjava/classpath/gnu/xml/pipeline/EventConsumer.java new file mode 100644 index 0000000..017bc7f --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/EventConsumer.java @@ -0,0 +1,95 @@ +/* EventConsumer.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.pipeline; + +import org.xml.sax.*; + + +/** + * Collects the event consumption apparatus of a SAX pipeline stage. + * Consumers which permit some handlers or other characteristics to be + * configured will provide methods to support that configuration. + * + *Two important categories of consumers include filters, which + * process events and pass them on to other consumers, and terminus + * (or terminal) stages, which don't pass events on. Filters are not + * necessarily derived from the {@link EventFilter} class, although that + * class can substantially simplify their construction by automating the + * most common activities. + * + *
Event consumers which follow certain conventions for the signatures + * of their constructors can be automatically assembled into pipelines + * by the {@link PipelineFactory} class. + * + * @author David Brownell + */ +public interface EventConsumer +{ + /** Most stages process these core SAX callbacks. */ + public ContentHandler getContentHandler (); + + /** Few stages will use unparsed entities. */ + public DTDHandler getDTDHandler (); + + /** + * This method works like the SAX2 XMLReader method of the same name, + * and is used to retrieve the optional lexical and declaration handlers + * in a pipeline. + * + * @param id This is a URI identifying the type of property desired. + * @return The value of that property, if it is defined. + * + * @exception SAXNotRecognizedException Thrown if the particular + * pipeline stage does not understand the specified identifier. + */ + public Object getProperty (String id) + throws SAXNotRecognizedException; + + /** + * This method provides a filter stage with a handler that abstracts + * presentation of warnings and both recoverable and fatal errors. + * Most pipeline stages should share a single policy and mechanism + * for such reports, since application components require consistency + * in such activities. Accordingly, typical responses to this method + * invocation involve saving the handler for use; filters will pass + * it on to any other consumers they use. + * + * @param handler encapsulates error handling policy for this stage + */ + public void setErrorHandler (ErrorHandler handler); +} diff --git a/libjava/classpath/gnu/xml/pipeline/EventFilter.java b/libjava/classpath/gnu/xml/pipeline/EventFilter.java new file mode 100644 index 0000000..6600271 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/EventFilter.java @@ -0,0 +1,809 @@ +/* EventFilter.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.pipeline; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.xml.sax.*; +import org.xml.sax.ext.*; +import org.xml.sax.helpers.XMLFilterImpl; + +import gnu.xml.aelfred2.ContentHandler2; + +/** + * A customizable event consumer, used to assemble various kinds of filters + * using SAX handlers and an optional second consumer. It can be constructed + * in two ways:
Additionally, SAX handlers may be assigned, which completely replace + * the "upstream" view (through {@link EventConsumer}) of handlers, initially + * null or the "next" consumer provided to the constructor. To make + * it easier to build specialized filter classes, this class implements + * all the standard SAX consumer handlers, and those implementations + * delegate "downstream" to the consumer accessed by {@link #getNext}. + * + *
The simplest way to create a custom a filter class is to create a + * subclass which overrides one or more handler interface methods. The + * constructor for that subclass then registers itself as a handler for + * those interfaces using a call such as setContentHandler(this), + * so the "upstream" view of event delivery is modified from the state + * established in the base class constructor. That way, + * the overridden methods intercept those event callbacks + * as they go "downstream", and + * all other event callbacks will pass events to any next consumer. + * Overridden methods may invoke superclass methods (perhaps after modifying + * parameters) if they wish to delegate such calls. Such subclasses + * should use {@link #getErrorHandler} to report errors using the + * common error reporting mechanism. + * + *
Another important technique is to construct a filter consisting + * of only a few specific types of handler. For example, one could easily + * prune out lexical events or various declarations by providing handlers + * which don't pass those events downstream, or by providing null handlers. + * + *
This may be viewed as the consumer oriented analogue of the SAX2 + * {@link org.xml.sax.helpers.XMLFilterImpl XMLFilterImpl} class. + * Key differences include:
The {@link #chainTo chainTo()} convenience routine supports chaining to + * an XMLFilterImpl, in its role as a limited functionality event + * consumer. Its event producer role ({@link XMLFilter}) is ignored. + * + *
The {@link #bind bind()} routine may be used associate event pipelines + * with any kind of {@link XMLReader} that will produce the events. + * Such pipelines don't necessarily need to have any members which are + * implemented using this class. That routine has some intelligence + * which supports automatic changes to parser feature flags, letting + * event piplines become largely independent of the particular feature + * sets of parsers. + * + * @author David Brownell + */ +public class EventFilter + implements EventConsumer, ContentHandler2, DTDHandler, + LexicalHandler, DeclHandler +{ + // SAX handlers + private ContentHandler docHandler, docNext; + private DTDHandler dtdHandler, dtdNext; + private LexicalHandler lexHandler, lexNext; + private DeclHandler declHandler, declNext; + // and ideally, one more for the stuff SAX2 doesn't show + + private Locator locator; + private EventConsumer next; + private ErrorHandler errHandler; + + + /** SAX2 URI prefix for standard feature flags. */ + public static final String FEATURE_URI + = "http://xml.org/sax/features/"; + /** SAX2 URI prefix for standard properties (mostly for handlers). */ + public static final String PROPERTY_URI + = "http://xml.org/sax/properties/"; + + /** SAX2 property identifier for {@link DeclHandler} events */ + public static final String DECL_HANDLER + = PROPERTY_URI + "declaration-handler"; + /** SAX2 property identifier for {@link LexicalHandler} events */ + public static final String LEXICAL_HANDLER + = PROPERTY_URI + "lexical-handler"; + + // + // These class objects will be null if the relevant class isn't linked. + // Small configurations (pJava and some kinds of embedded systems) need + // to facilitate smaller executables. So "instanceof" is undesirable + // when bind() sees if it can remove some stages. + // + // SECURITY NOTE: assuming all these classes are part of the same sealed + // package, there's no problem saving these in the instance of this class + // that's associated with "this" class loader. But that wouldn't be true + // for classes in another package. + // + private static boolean loaded; + private static Class nsClass; + private static Class validClass; + private static Class wfClass; + private static Class xincClass; + + static ClassLoader getClassLoader () + { + Method m = null; + + try { + m = Thread.class.getMethod("getContextClassLoader", null); + } catch (NoSuchMethodException e) { + // Assume that we are running JDK 1.1, use the current ClassLoader + return EventFilter.class.getClassLoader(); + } + + try { + return (ClassLoader) m.invoke(Thread.currentThread(), null); + } catch (IllegalAccessException e) { + // assert(false) + throw new UnknownError(e.getMessage()); + } catch (InvocationTargetException e) { + // assert(e.getTargetException() instanceof SecurityException) + throw new UnknownError(e.getMessage()); + } + } + + static Class loadClass (ClassLoader classLoader, String className) + { + try { + if (classLoader == null) + return Class.forName(className); + else + return classLoader.loadClass(className); + } catch (Exception e) { + return null; + } + } + + static private void loadClasses () + { + ClassLoader loader = getClassLoader (); + + nsClass = loadClass (loader, "gnu.xml.pipeline.NSFilter"); + validClass = loadClass (loader, "gnu.xml.pipeline.ValidationConsumer"); + wfClass = loadClass (loader, "gnu.xml.pipeline.WellFormednessFilter"); + xincClass = loadClass (loader, "gnu.xml.pipeline.XIncludeFilter"); + loaded = true; + } + + + /** + * Binds the standard SAX2 handlers from the specified consumer + * pipeline to the specified producer. These handlers include the core + * {@link ContentHandler} and {@link DTDHandler}, plus the extension + * {@link DeclHandler} and {@link LexicalHandler}. Any additional + * application-specific handlers need to be bound separately. + * The {@link ErrorHandler} is handled differently: the producer's + * error handler is passed through to the consumer pipeline. + * The producer is told to include namespace prefix information if it + * can, since many pipeline stages need that Infoset information to + * work well. + * + *
At the head of the pipeline, certain standard event filters are + * recognized and handled specially. This facilitates construction + * of processing pipelines that work regardless of the capabilities + * of the XMLReader implementation in use; for example, it permits + * validating output of a {@link gnu.xml.util.DomParser}.
Other than that, this method works with any kind of event consumer, + * not just event filters. Note that in all cases, the standard handlers + * are assigned; any previous handler assignments for the handler will + * be overridden. + * + * @param producer will deliver events to the specified consumer + * @param consumer pipeline supplying event handlers to be associated + * with the producer (may not be null) + */ + public static void bind (XMLReader producer, EventConsumer consumer) + { + Class klass = null; + boolean prefixes; + + if (!loaded) + loadClasses (); + + // DOM building, printing, layered validation, and other + // things don't work well when prefix info is discarded. + // Include it by default, whenever possible. + try { + producer.setFeature (FEATURE_URI + "namespace-prefixes", + true); + prefixes = true; + } catch (SAXException e) { + prefixes = false; + } + + // NOTE: This loop doesn't use "instanceof", since that + // would prevent compiling/linking without those classes + // being present. + while (consumer != null) { + klass = consumer.getClass (); + + // we might have already changed this problematic SAX2 default. + if (nsClass != null && nsClass.isAssignableFrom (klass)) { + if (!prefixes) + break; + consumer = ((EventFilter)consumer).getNext (); + + // the parser _might_ do DTD validation by default ... + // if not, maybe we can change this setting. + } else if (validClass != null + && validClass.isAssignableFrom (klass)) { + try { + producer.setFeature (FEATURE_URI + "validation", + true); + consumer = ((ValidationConsumer)consumer).getNext (); + } catch (SAXException e) { + break; + } + + // parsers are required not to have such bugs + } else if (wfClass != null && wfClass.isAssignableFrom (klass)) { + consumer = ((WellFormednessFilter)consumer).getNext (); + + // stop on the first pipeline stage we can't remove + } else + break; + + if (consumer == null) + klass = null; + } + + // the actual setting here doesn't matter as much + // as that producer and consumer agree + if (xincClass != null && klass != null + && xincClass.isAssignableFrom (klass)) + ((XIncludeFilter)consumer).setSavingPrefixes (prefixes); + + // Some SAX parsers can't handle null handlers -- bleech + DefaultHandler2 h = new DefaultHandler2 (); + + if (consumer != null && consumer.getContentHandler () != null) + producer.setContentHandler (consumer.getContentHandler ()); + else + producer.setContentHandler (h); + if (consumer != null && consumer.getDTDHandler () != null) + producer.setDTDHandler (consumer.getDTDHandler ()); + else + producer.setDTDHandler (h); + + try { + Object dh; + + if (consumer != null) + dh = consumer.getProperty (DECL_HANDLER); + else + dh = null; + if (dh == null) + dh = h; + producer.setProperty (DECL_HANDLER, dh); + } catch (Exception e) { /* ignore */ } + try { + Object lh; + + if (consumer != null) + lh = consumer.getProperty (LEXICAL_HANDLER); + else + lh = null; + if (lh == null) + lh = h; + producer.setProperty (LEXICAL_HANDLER, lh); + } catch (Exception e) { /* ignore */ } + + // this binding goes the other way around + if (producer.getErrorHandler () == null) + producer.setErrorHandler (h); + if (consumer != null) + consumer.setErrorHandler (producer.getErrorHandler ()); + } + + /** + * Initializes all handlers to null. + */ + // constructor used by PipelineFactory + public EventFilter () { } + + + /** + * Handlers that are not otherwise set will default to those from + * the specified consumer, making it easy to pass events through. + * If the consumer is null, all handlers are initialzed to null. + */ + // constructor used by PipelineFactory + public EventFilter (EventConsumer consumer) + { + if (consumer == null) + return; + + next = consumer; + + // We delegate through the "xxNext" handlers, and + // report the "xxHandler" ones on our input side. + + // Normally a subclass would both override handler + // methods and register itself as the "xxHandler". + + docHandler = docNext = consumer.getContentHandler (); + dtdHandler = dtdNext = consumer.getDTDHandler (); + try { + declHandler = declNext = (DeclHandler) + consumer.getProperty (DECL_HANDLER); + } catch (SAXException e) { /* leave value null */ } + try { + lexHandler = lexNext = (LexicalHandler) + consumer.getProperty (LEXICAL_HANDLER); + } catch (SAXException e) { /* leave value null */ } + } + + /** + * Treats the XMLFilterImpl as a limited functionality event consumer, + * by arranging to deliver events to it; this lets such classes be + * "wrapped" as pipeline stages. + * + *
Upstream Event Setup: + * If no handlers have been assigned to this EventFilter, then the + * handlers from specified XMLFilterImpl are returned from this + * {@link EventConsumer}: the XMLFilterImpl is just "wrapped". + * Otherwise the specified handlers will be returned. + * + *
Downstream Event Setup: + * Subclasses may chain event delivery to the specified XMLFilterImpl + * by invoking the appropiate superclass methods, + * as if their constructor passed a "next" EventConsumer to the + * constructor for this class. + * If this EventFilter has an ErrorHandler, it is assigned as + * the error handler for the XMLFilterImpl, just as would be + * done for a next stage implementing {@link EventConsumer}. + * + * @param next the next downstream component of the pipeline. + * @exception IllegalStateException if the "next" consumer has + * already been set through the constructor. + */ + public void chainTo (XMLFilterImpl next) + { + if (this.next != null) + throw new IllegalStateException (); + + docNext = next.getContentHandler (); + if (docHandler == null) + docHandler = docNext; + dtdNext = next.getDTDHandler (); + if (dtdHandler == null) + dtdHandler = dtdNext; + + try { + declNext = (DeclHandler) next.getProperty (DECL_HANDLER); + if (declHandler == null) + declHandler = declNext; + } catch (SAXException e) { /* leave value null */ } + try { + lexNext = (LexicalHandler) next.getProperty (LEXICAL_HANDLER); + if (lexHandler == null) + lexHandler = lexNext; + } catch (SAXException e) { /* leave value null */ } + + if (errHandler != null) + next.setErrorHandler (errHandler); + } + + /** + * Records the error handler that should be used by this stage, and + * passes it "downstream" to any subsequent stage. + */ + final public void setErrorHandler (ErrorHandler handler) + { + errHandler = handler; + if (next != null) + next.setErrorHandler (handler); + } + + /** + * Returns the error handler assigned this filter stage, or null + * if no such assigment has been made. + */ + final public ErrorHandler getErrorHandler () + { + return errHandler; + } + + + /** + * Returns the next event consumer in sequence; or null if there + * is no such handler. + */ + final public EventConsumer getNext () + { return next; } + + + /** + * Assigns the content handler to use; a null handler indicates + * that these events will not be forwarded. + * This overrides the previous settting for this handler, which was + * probably pointed to the next consumer by the base class constructor. + */ + final public void setContentHandler (ContentHandler h) + { + docHandler = h; + } + + /** Returns the content handler being used. */ + final public ContentHandler getContentHandler () + { + return docHandler; + } + + /** + * Assigns the DTD handler to use; a null handler indicates + * that these events will not be forwarded. + * This overrides the previous settting for this handler, which was + * probably pointed to the next consumer by the base class constructor. + */ + final public void setDTDHandler (DTDHandler h) + { dtdHandler = h; } + + /** Returns the dtd handler being used. */ + final public DTDHandler getDTDHandler () + { + return dtdHandler; + } + + /** + * Stores the property, normally a handler; a null handler indicates + * that these events will not be forwarded. + * This overrides the previous handler settting, which was probably + * pointed to the next consumer by the base class constructor. + */ + final public void setProperty (String id, Object o) + throws SAXNotRecognizedException, SAXNotSupportedException + { + try { + Object value = getProperty (id); + + if (value == o) + return; + if (DECL_HANDLER.equals (id)) { + declHandler = (DeclHandler) o; + return; + } + if (LEXICAL_HANDLER.equals (id)) { + lexHandler = (LexicalHandler) o; + return; + } + throw new SAXNotSupportedException (id); + + } catch (ClassCastException e) { + throw new SAXNotSupportedException (id); + } + } + + /** Retrieves a property of unknown intent (usually a handler) */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + if (DECL_HANDLER.equals (id)) + return declHandler; + if (LEXICAL_HANDLER.equals (id)) + return lexHandler; + + throw new SAXNotRecognizedException (id); + } + + /** + * Returns any locator provided to the next consumer, if this class + * (or a subclass) is handling {@link ContentHandler } events. + */ + public Locator getDocumentLocator () + { return locator; } + + + // CONTENT HANDLER DELEGATIONS + + /** SAX2: passes this callback to the next consumer, if any */ + public void setDocumentLocator (Locator locator) + { + this.locator = locator; + if (docNext != null) + docNext.setDocumentLocator (locator); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startDocument () throws SAXException + { + if (docNext != null) + docNext.startDocument (); + } + + public void xmlDecl(String version, String encoding, boolean standalone, + String inputEncoding) + throws SAXException + { + if (docNext != null && docNext instanceof ContentHandler2) + { + ((ContentHandler2) docNext).xmlDecl(version, encoding, standalone, + inputEncoding); + } + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void skippedEntity (String name) throws SAXException + { + if (docNext != null) + docNext.skippedEntity (name); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void processingInstruction (String target, String data) + throws SAXException + { + if (docNext != null) + docNext.processingInstruction (target, data); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void characters (char ch [], int start, int length) + throws SAXException + { + if (docNext != null) + docNext.characters (ch, start, length); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + if (docNext != null) + docNext.ignorableWhitespace (ch, start, length); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (docNext != null) + docNext.startPrefixMapping (prefix, uri); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startElement ( + String uri, String localName, + String qName, Attributes atts + ) throws SAXException + { + if (docNext != null) + docNext.startElement (uri, localName, qName, atts); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endElement (String uri, String localName, String qName) + throws SAXException + { + if (docNext != null) + docNext.endElement (uri, localName, qName); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endPrefixMapping (String prefix) throws SAXException + { + if (docNext != null) + docNext.endPrefixMapping (prefix); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endDocument () throws SAXException + { + if (docNext != null) + docNext.endDocument (); + locator = null; + } + + + // DTD HANDLER DELEGATIONS + + /** SAX1: passes this callback to the next consumer, if any */ + public void unparsedEntityDecl ( + String name, + String publicId, + String systemId, + String notationName + ) throws SAXException + { + if (dtdNext != null) + dtdNext.unparsedEntityDecl (name, publicId, systemId, notationName); + } + + /** SAX1: passes this callback to the next consumer, if any */ + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + if (dtdNext != null) + dtdNext.notationDecl (name, publicId, systemId); + } + + + // LEXICAL HANDLER DELEGATIONS + + /** SAX2: passes this callback to the next consumer, if any */ + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + if (lexNext != null) + lexNext.startDTD (name, publicId, systemId); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endDTD () + throws SAXException + { + if (lexNext != null) + lexNext.endDTD (); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void comment (char ch [], int start, int length) + throws SAXException + { + if (lexNext != null) + lexNext.comment (ch, start, length); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startCDATA () + throws SAXException + { + if (lexNext != null) + lexNext.startCDATA (); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endCDATA () + throws SAXException + { + if (lexNext != null) + lexNext.endCDATA (); + } + + /** + * SAX2: passes this callback to the next consumer, if any. + */ + public void startEntity (String name) + throws SAXException + { + if (lexNext != null) + lexNext.startEntity (name); + } + + /** + * SAX2: passes this callback to the next consumer, if any. + */ + public void endEntity (String name) + throws SAXException + { + if (lexNext != null) + lexNext.endEntity (name); + } + + + // DECLARATION HANDLER DELEGATIONS + + + /** SAX2: passes this callback to the next consumer, if any */ + public void elementDecl (String name, String model) + throws SAXException + { + if (declNext != null) + declNext.elementDecl (name, model); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void attributeDecl (String eName, String aName, + String type, String mode, String value) + throws SAXException + { + if (declNext != null) + declNext.attributeDecl (eName, aName, type, mode, value); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + { + if (declNext != null) + declNext.externalEntityDecl (name, publicId, systemId); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void internalEntityDecl (String name, String value) + throws SAXException + { + if (declNext != null) + declNext.internalEntityDecl (name, value); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/LinkFilter.java b/libjava/classpath/gnu/xml/pipeline/LinkFilter.java new file mode 100644 index 0000000..ddb9fda --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/LinkFilter.java @@ -0,0 +1,242 @@ +/* LinkFilter.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.pipeline; + +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Vector; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + + +/** + * Pipeline filter to remember XHTML links found in a document, + * so they can later be crawled. Fragments are not counted, and duplicates + * are ignored. Callers are responsible for filtering out URLs they aren't + * interested in. Events are passed through unmodified. + * + *
Input MUST include a setDocumentLocator() call, as it's used to + * resolve relative links in the absence of a "base" element. Input MUST + * also include namespace identifiers, since it is the XHTML namespace + * identifier which is used to identify the relevant elements. + * + *
FIXME: handle xml:base attribute ... in association with + * a stack of base URIs. Similarly, recognize/support XLink data. + * + * @author David Brownell + */ +public class LinkFilter extends EventFilter +{ + // for storing URIs + private Vector vector = new Vector (); + + // struct for "full" link record (tbd) + // these for troubleshooting original source: + // original uri + // uri as resolved (base, relative, etc) + // URI of originating doc + // line # + // original element + attrs (img src, desc, etc) + + // XLink model of the link ... for inter-site pairups ? + + private String baseURI; + + private boolean siteRestricted = false; + + // + // XXX leverage blacklist info (like robots.txt) + // + // XXX constructor w/param ... pipeline for sending link data + // probably XHTML --> XLink, providing info as sketched above + // + + + /** + * Constructs a new event filter, which collects links in private data + * structure for later enumeration. + */ + // constructor used by PipelineFactory + public LinkFilter () + { + super.setContentHandler (this); + } + + + /** + * Constructs a new event filter, which collects links in private data + * structure for later enumeration and passes all events, unmodified, + * to the next consumer. + */ + // constructor used by PipelineFactory + public LinkFilter (EventConsumer next) + { + super (next); + super.setContentHandler (this); + } + + + /** + * Returns an enumeration of the links found since the filter + * was constructed, or since removeAllLinks() was called. + * + * @return enumeration of strings. + */ + public Enumeration getLinks () + { + return vector.elements (); + } + + /** + * Removes records about all links reported to the event + * stream, as if the filter were newly created. + */ + public void removeAllLinks () + { + vector = new Vector (); + } + + + /** + * Collects URIs for (X)HTML content from elements which hold them. + */ + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + String link; + + // Recognize XHTML links. + if ("http://www.w3.org/1999/xhtml".equals (uri)) { + + if ("a".equals (localName) || "base".equals (localName) + || "area".equals (localName)) + link = atts.getValue ("href"); + else if ("iframe".equals (localName) || "frame".equals (localName)) + link = atts.getValue ("src"); + else if ("blockquote".equals (localName) || "q".equals (localName) + || "ins".equals (localName) || "del".equals (localName)) + link = atts.getValue ("cite"); + else + link = null; + link = maybeAddLink (link); + + // "base" modifies designated baseURI + if ("base".equals (localName) && link != null) + baseURI = link; + + if ("iframe".equals (localName) || "img".equals (localName)) + maybeAddLink (atts.getValue ("longdesc")); + } + + super.startElement (uri, localName, qName, atts); + } + + private String maybeAddLink (String link) + { + int index; + + // ignore empty links and fragments inside docs + if (link == null) + return null; + if ((index = link.indexOf ("#")) >= 0) + link = link.substring (0, index); + if (link.equals ("")) + return null; + + try { + // get the real URI + URL base = new URL ((baseURI != null) + ? baseURI + : getDocumentLocator ().getSystemId ()); + URL url = new URL (base, link); + + link = url.toString (); + + // ignore duplicates + if (vector.contains (link)) + return link; + + // other than what "base" does, stick to original site: + if (siteRestricted) { + // don't switch protocols + if (!base.getProtocol ().equals (url.getProtocol ())) + return link; + // don't switch servers + if (base.getHost () != null + && !base.getHost ().equals (url.getHost ())) + return link; + } + + vector.addElement (link); + + return link; + + } catch (IOException e) { + // bad URLs we don't want + } + return null; + } + + /** + * Reports an error if no Locator has been made available. + */ + public void startDocument () + throws SAXException + { + if (getDocumentLocator () == null) + throw new SAXException ("no Locator!"); + } + + /** + * Forgets about any base URI information that may be recorded. + * Applications will often want to call removeAllLinks(), likely + * after examining the links which were reported. + */ + public void endDocument () + throws SAXException + { + baseURI = null; + super.endDocument (); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/NSFilter.java b/libjava/classpath/gnu/xml/pipeline/NSFilter.java new file mode 100644 index 0000000..db875e1 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/NSFilter.java @@ -0,0 +1,341 @@ +/* NSFilter.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.pipeline; + +import java.util.Enumeration; +import java.util.Stack; + +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.NamespaceSupport; + +/** + * This filter ensures that element and attribute names are properly prefixed, + * and that such prefixes are declared. Such data is critical for operations + * like writing XML text, and validating against DTDs: names or their prefixes + * may have been discarded, although they are essential to the exchange of + * information using XML. There are various common ways that such data + * gets discarded:
This filter uses a heuristic to choose the prefix to assign to any + * particular name which wasn't already corectly prefixed. The associated + * namespace will be correct, and the prefix will be declared. Original + * structures facilitating text editing, such as conventions about use of + * mnemonic prefix names or the scoping of prefixes, can't always be + * reconstructed after they are discarded, as strongly encouraged by the + * current SAX2 defaults. + * + *
Note that this can't possibly know whether values inside attribute + * value or document content involve prefixed names. If your application + * requires using prefixed names in such locations you'll need to add some + * appropriate logic (perhaps adding additional heuristics in a subclass). + * + * @author David Brownell + */ +public class NSFilter extends EventFilter +{ + private NamespaceSupport nsStack = new NamespaceSupport (); + private Stack elementStack = new Stack (); + + private boolean pushedContext; + private String nsTemp [] = new String [3]; + private AttributesImpl attributes = new AttributesImpl (); + private boolean usedDefault; + + // gensymmed prefixes use this root name + private static final String prefixRoot = "prefix-"; + + + /** + * Passes events through to the specified consumer, after first + * processing them. + * + * @param next the next event consumer to receive events. + */ + // constructor used by PipelineFactory + public NSFilter (EventConsumer next) + { + super (next); + + setContentHandler (this); + } + + private void fatalError (String message) + throws SAXException + { + SAXParseException e; + ErrorHandler handler = getErrorHandler (); + Locator locator = getDocumentLocator (); + + if (locator == null) + e = new SAXParseException (message, null, null, -1, -1); + else + e = new SAXParseException (message, locator); + if (handler != null) + handler.fatalError (e); + throw e; + } + + + public void startDocument () throws SAXException + { + elementStack.removeAllElements (); + nsStack.reset (); + pushedContext = false; + super.startDocument (); + } + + /** + * This call is not passed to the next consumer in the chain. + * Prefix declarations and scopes are only exposed in the form + * of attributes; this callback just records a declaration that + * will be exposed as an attribute. + */ + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (pushedContext == false) { + nsStack.pushContext (); + pushedContext = true; + } + + // this check is awkward, but the paranoia prevents big trouble + for (Enumeration e = nsStack.getDeclaredPrefixes (); + e.hasMoreElements (); + /* NOP */ ) { + String declared = (String) e.nextElement (); + + if (!declared.equals (prefix)) + continue; + if (uri.equals (nsStack.getURI (prefix))) + return; + fatalError ("inconsistent binding for prefix '" + prefix + + "' ... " + uri + " (was " + nsStack.getURI (prefix) + ")"); + } + + if (!nsStack.declarePrefix (prefix, uri)) + fatalError ("illegal prefix declared: " + prefix); + } + + private String fixName (String ns, String l, String name, boolean isAttr) + throws SAXException + { + if ("".equals (name) || name == null) { + name = l; + if ("".equals (name) || name == null) + fatalError ("empty/null name"); + } + + // can we correctly process the name as-is? + // handles "element scope" attribute names here. + if (nsStack.processName (name, nsTemp, isAttr) != null + && nsTemp [0].equals (ns) + ) { + return nsTemp [2]; + } + + // nope, gotta modify the name or declare a default mapping + int temp; + + // get rid of any current prefix + if ((temp = name.indexOf (':')) >= 0) { + name = name.substring (temp + 1); + + // ... maybe that's enough (use/prefer default namespace) ... + if (!isAttr && nsStack.processName (name, nsTemp, false) != null + && nsTemp [0].equals (ns) + ) { + return nsTemp [2]; + } + } + + // must we define and use the default/undefined prefix? + if ("".equals (ns)) { + if (isAttr) + fatalError ("processName bug"); + if (attributes.getIndex ("xmlns") != -1) + fatalError ("need to undefine default NS, but it's bound: " + + attributes.getValue ("xmlns")); + + nsStack.declarePrefix ("", ""); + attributes.addAttribute ("", "", "xmlns", "CDATA", ""); + return name; + } + + // is there at least one non-null prefix we can use? + for (Enumeration e = nsStack.getDeclaredPrefixes (); + e.hasMoreElements (); + /* NOP */) { + String prefix = (String) e.nextElement (); + String uri = nsStack.getURI (prefix); + + if (uri == null || !uri.equals (ns)) + continue; + return prefix + ":" + name; + } + + // no such luck. create a prefix name, declare it, use it. + for (temp = 0; temp >= 0; temp++) { + String prefix = prefixRoot + temp; + + if (nsStack.getURI (prefix) == null) { + nsStack.declarePrefix (prefix, ns); + attributes.addAttribute ("", "", "xmlns:" + prefix, + "CDATA", ns); + return prefix + ":" + name; + } + } + fatalError ("too many prefixes genned"); + // NOTREACHED + return null; + } + + public void startElement ( + String uri, String localName, + String qName, Attributes atts + ) throws SAXException + { + if (!pushedContext) + nsStack.pushContext (); + pushedContext = false; + + // make sure we have all NS declarations handy before we start + int length = atts.getLength (); + + for (int i = 0; i < length; i++) { + String aName = atts.getQName (i); + + if (!aName.startsWith ("xmlns")) + continue; + + String prefix; + + if ("xmlns".equals (aName)) + prefix = ""; + else if (aName.indexOf (':') == 5) + prefix = aName.substring (6); + else // "xmlnsfoo" etc. + continue; + startPrefixMapping (prefix, atts.getValue (i)); + } + + // put namespace decls at the start of our regenned attlist + attributes.clear (); + for (Enumeration e = nsStack.getDeclaredPrefixes (); + e.hasMoreElements (); + /* NOP */) { + String prefix = (String) e.nextElement (); + + attributes.addAttribute ("", "", + ("".equals (prefix) + ? "xmlns" + : "xmlns:" + prefix), + "CDATA", + nsStack.getURI (prefix)); + } + + // name fixups: element, then attributes. + // fixName may declare a new prefix or, for the element, + // redeclare the default (if element name needs it). + qName = fixName (uri, localName, qName, false); + + for (int i = 0; i < length; i++) { + String aName = atts.getQName (i); + String aNS = atts.getURI (i); + String aLocal = atts.getLocalName (i); + String aType = atts.getType (i); + String aValue = atts.getValue (i); + + if (aName.startsWith ("xmlns")) + continue; + aName = fixName (aNS, aLocal, aName, true); + attributes.addAttribute (aNS, aLocal, aName, aType, aValue); + } + + elementStack.push (qName); + + // pass event along, with cleaned-up names and decls. + super.startElement (uri, localName, qName, attributes); + } + + public void endElement (String uri, String localName, String qName) + throws SAXException + { + nsStack.popContext (); + qName = (String) elementStack.pop (); + super.endElement (uri, localName, qName); + } + + /** + * This call is not passed to the next consumer in the chain. + * Prefix declarations and scopes are only exposed in their + * attribute form. + */ + public void endPrefixMapping (String prefix) + throws SAXException + { } + + public void endDocument () throws SAXException + { + elementStack.removeAllElements (); + nsStack.reset (); + super.endDocument (); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/PipelineFactory.java b/libjava/classpath/gnu/xml/pipeline/PipelineFactory.java new file mode 100644 index 0000000..f88ab16 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/PipelineFactory.java @@ -0,0 +1,723 @@ +/* PipelineFactory.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.pipeline; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.lang.reflect.Constructor; +import java.util.StringTokenizer; + +import org.xml.sax.*; +import org.xml.sax.ext.*; + + +/** + * This provides static factory methods for creating simple event pipelines. + * These pipelines are specified by strings, suitable for passing on + * command lines or embedding in element attributes. For example, one way + * to write a pipeline that restores namespace syntax, validates (stopping + * the pipeline on validity errors) and then writes valid data to standard + * output is this:
+ * nsfix | validate | write ( stdout )+ * + *
In this syntax, the tokens are always separated by whitespace, and each + * stage of the pipeline may optionally have a parameter (which can be a + * pipeline) in parentheses. Interior stages are called filters, and the + * rightmost end of a pipeline is called a terminus. + * + *
Stages are usually implemented by a single class, which may not be + * able to act as both a filter and a terminus; but any terminus can be + * automatically turned into a filter, through use of a {@link TeeConsumer}. + * The stage identifiers are either class names, or are one of the following + * short identifiers built into this class. (Most of these identifiers are + * no more than aliases for classes.) The built-in identifiers include:
+ +Stage | +Parameter | +Terminus | +Description | +
---|---|---|---|
dom | +none | +yes | +Applications code can access a DOM Document built + from the input event stream. When used as a filter, this buffers + data up to an endDocument call, and then uses a DOM parser + to report everything that has been recorded (which can easily be + less than what was reported to it). | +
nsfix | +none | +no | +This stage ensures that the XML element and attribute + names in its output use namespace prefixes and declarations correctly. + That is, so that they match the "Namespace plus LocalName" naming data + with which each XML element and attribute is already associated. | +
null | +none | +yes | +This stage ignores all input event data. | +
server | +required server URL |
+ no | +Sends its input as XML request to a remote server, + normally a web application server using the HTTP or HTTPS protocols. + The output of this stage is the parsed response from that server. | +
tee | +required first pipeline |
+ no | +This sends its events down two paths; its parameter + is a pipeline descriptor for the first path, and the second path + is the output of this stage. | +
validate | +none | +yes | +This checks for validity errors, and reports them + through its error handler. The input must include declaration events + and some lexical events. | +
wf | +none | +yes | +This class provides some basic "well formedness" + tests on the input event stream, and reports a fatal error if any + of them fail. One example: start/end calls for elements must match. + No SAX parser is permitted to produce malformed output, but other + components can easily do so. | +
write | +required "stdout", "stderr", or filename |
+ yes | +Writes its input to the specified output, as pretty + printed XML text encoded using UTF-8. Input events must be well + formed and "namespace fixed", else the output won't be XML (or possibly + namespace) conformant. The symbolic names represent + System.out and System.err respectively; names must + correspond to files which don't yet exist. | +
xhtml | +required "stdout", "stderr", or filename |
+ yes | +Like write (above), except that XHTML rules + are followed. The XHTML 1.0 Transitional document type is declared, + and only ASCII characters are written (for interoperability). Other + characters are written as entity or character references; the text is + pretty printed. | +
xinclude | +none | +no | +This stage handles XInclude processing. + This is like entity inclusion, except that the included content + is declared in-line rather than in the DTD at the beginning of + a document. + | +
xslt | +required XSLT stylesheet URI |
+ no | +This stage handles XSLT transformation + according to a stylesheet. + The implementation of the transformation may not actually + stream data, although if such an XSLT engine is in use + then that can happen. + | +
Note that {@link EventFilter#bind} can automatically eliminate + * some filters by setting SAX2 parser features appropriately. This means + * that you can routinely put filters like "nsfix", "validate", or "wf" at the + * front of a pipeline (for components that need inputs conditioned to match + * that level of correctness), and know that it won't actually be used unless + * it's absolutely necessary. + * + * @author David Brownell + */ +public class PipelineFactory +{ + /** + * Creates a simple pipeline according to the description string passed in. + */ + public static EventConsumer createPipeline (String description) + throws IOException + { + return createPipeline (description, null); + } + + /** + * Extends an existing pipeline by prepending the filter pipeline to the + * specified consumer. Some pipelines need more customization than can + * be done through this simplified syntax. When they are set up with + * direct API calls, use this method to merge more complex pipeline + * segments with easily configured ones. + */ + public static EventConsumer createPipeline ( + String description, + EventConsumer next + ) throws IOException + { + // tokens are (for now) what's separated by whitespace; + // very easy to parse, but IDs never have spaces. + + StringTokenizer tokenizer; + String tokens []; + + tokenizer = new StringTokenizer (description); + tokens = new String [tokenizer.countTokens ()]; + for (int i = 0; i < tokens.length; i++) + tokens [i] = tokenizer.nextToken (); + + PipelineFactory factory = new PipelineFactory (); + Pipeline pipeline = factory.parsePipeline (tokens, next); + + return pipeline.createPipeline (); + } + + + private PipelineFactory () { /* NYET */ } + + + /** + * Extends an existing pipeline by prepending a pre-tokenized filter + * pipeline to the specified consumer. Tokens are class names (or the + * predefined aliases) left and right parenthesis, and the vertical bar. + */ + public static EventConsumer createPipeline ( + String tokens [], + EventConsumer next + ) throws IOException + { + PipelineFactory factory = new PipelineFactory (); + Pipeline pipeline = factory.parsePipeline (tokens, next); + + return pipeline.createPipeline (); + } + + + private String tokens []; + private int index; + + private Pipeline parsePipeline (String toks [], EventConsumer next) + { + tokens = toks; + index = 0; + + Pipeline retval = parsePipeline (next); + + if (index != toks.length) + throw new ArrayIndexOutOfBoundsException ( + "extra token: " + tokens [index]); + return retval; + } + + // pipeline ::= stage | stage '|' pipeline + private Pipeline parsePipeline (EventConsumer next) + { + Pipeline retval = new Pipeline (parseStage ()); + + // minimal pipelines: "stage" and "... | id" + if (index > (tokens.length - 2) + || !"|".equals (tokens [index]) + ) { + retval.next = next; + return retval; + } + index++; + retval.rest = parsePipeline (next); + return retval; + } + + // stage ::= id | id '(' pipeline ')' + private Stage parseStage () + { + Stage retval = new Stage (tokens [index++]); + + // minimal stages: "id" and "id ( id )" + if (index > (tokens.length - 2) + || !"(".equals (tokens [index]) /*)*/ + ) + return retval; + + index++; + retval.param = parsePipeline (null); + if (index >= tokens.length) + throw new ArrayIndexOutOfBoundsException ( + "missing right paren"); + if (/*(*/ !")".equals (tokens [index++])) + throw new ArrayIndexOutOfBoundsException ( + "required right paren, not: " + tokens [index - 1]); + return retval; + } + + + // + // these classes obey the conventions for constructors, so they're + // only built in to this table of shortnames + // + // - filter (one or two types of arglist) + // * last constructor is 'next' element + // * optional (first) string parameter + // + // - terminus (one or types of arglist) + // * optional (only) string parameter + // + // terminus stages are transformed into filters if needed, by + // creating a "tee". filter stages aren't turned to terminus + // stages though; either eliminate such stages, or add some + // terminus explicitly. + // + private static final String builtinStages [][] = { + { "dom", "gnu.xml.dom.Consumer" }, + { "nsfix", "gnu.xml.pipeline.NSFilter" }, + { "null", "gnu.xml.pipeline.EventFilter" }, + { "server", "gnu.xml.pipeline.CallFilter" }, + { "tee", "gnu.xml.pipeline.TeeConsumer" }, + { "validate", "gnu.xml.pipeline.ValidationConsumer" }, + { "wf", "gnu.xml.pipeline.WellFormednessFilter" }, + { "xinclude", "gnu.xml.pipeline.XIncludeFilter" }, + { "xslt", "gnu.xml.pipeline.XsltFilter" }, + +// XXX want: option for validate, to preload external part of a DTD + + // xhtml, write ... nyet generic-ready + }; + + private static class Stage + { + String id; + Pipeline param; + + Stage (String name) + { id = name; } + + public String toString () + { + if (param == null) + return id; + return id + " ( " + param + " )"; + } + + private void fail (String message) + throws IOException + { + throw new IOException ("in '" + id + + "' stage of pipeline, " + message); + } + + EventConsumer createStage (EventConsumer next) + throws IOException + { + String name = id; + + // most builtins are just class aliases + for (int i = 0; i < builtinStages.length; i++) { + if (id.equals (builtinStages [i][0])) { + name = builtinStages [i][1]; + break; + } + } + + // Save output as XML or XHTML text + if ("write".equals (name) || "xhtml".equals (name)) { + String filename; + boolean isXhtml = "xhtml".equals (name); + OutputStream out = null; + TextConsumer consumer; + + if (param == null) + fail ("parameter is required"); + + filename = param.toString (); + if ("stdout".equals (filename)) + out = System.out; + else if ("stderr".equals (filename)) + out = System.err; + else { + File f = new File (filename); + +/* + if (!f.isAbsolute ()) + fail ("require absolute file paths"); + */ + if (f.exists ()) + fail ("file already exists: " + f.getName ()); + +// XXX this races against the existence test + out = new FileOutputStream (f); + } + + if (!isXhtml) + consumer = new TextConsumer (out); + else + consumer = new TextConsumer ( + new OutputStreamWriter (out, "8859_1"), + true); + + consumer.setPrettyPrinting (true); + if (next == null) + return consumer; + return new TeeConsumer (consumer, next); + + } else { + // + // Here go all the builtins that are just aliases for + // classes, and all stage IDs that started out as such + // class names. The following logic relies on several + // documented conventions for constructor invocation. + // + String msg = null; + + try { + Class klass = Class.forName (name); + Class argTypes [] = null; + Constructor constructor = null; + boolean filter = false; + Object params [] = null; + Object obj = null; + + // do we need a filter stage? + if (next != null) { + // "next" consumer is always passed, with + // or without the optional string param + if (param == null) { + argTypes = new Class [1]; + argTypes [0] = EventConsumer.class; + + params = new Object [1]; + params [0] = next; + + msg = "no-param filter"; + } else { + argTypes = new Class [2]; + argTypes [0] = String.class; + argTypes [1] = EventConsumer.class; + + params = new Object [2]; + params [0] = param.toString (); + params [1] = next; + + msg = "one-param filter"; + } + + + try { + constructor = klass.getConstructor (argTypes); + } catch (NoSuchMethodException e) { + // try creating a filter from a + // terminus and a tee + filter = true; + msg += " built from "; + } + } + + // build from a terminus stage, with or + // without the optional string param + if (constructor == null) { + String tmp; + + if (param == null) { + argTypes = new Class [0]; + params = new Object [0]; + + tmp = "no-param terminus"; + } else { + argTypes = new Class [1]; + argTypes [0] = String.class; + + params = new Object [1]; + params [0] = param.toString (); + + tmp = "one-param terminus"; + } + if (msg == null) + msg = tmp; + else + msg += tmp; + constructor = klass.getConstructor (argTypes); + // NOT creating terminus by dead-ending + // filters ... users should think about + // that one, something's likely wrong + } + + obj = constructor.newInstance (params); + + // return EventConsumers directly, perhaps after + // turning them into a filter + if (obj instanceof EventConsumer) { + if (filter) + return new TeeConsumer ((EventConsumer) obj, next); + return (EventConsumer) obj; + } + + // if it's not a handler, it's an error + // we can wrap handlers in a filter + EventFilter retval = new EventFilter (); + boolean updated = false; + + if (obj instanceof ContentHandler) { + retval.setContentHandler ((ContentHandler) obj); + updated = true; + } + if (obj instanceof DTDHandler) { + retval.setDTDHandler ((DTDHandler) obj); + updated = true; + } + if (obj instanceof LexicalHandler) { + retval.setProperty ( + EventFilter.PROPERTY_URI + "lexical-handler", + obj); + updated = true; + } + if (obj instanceof DeclHandler) { + retval.setProperty ( + EventFilter.PROPERTY_URI + "declaration-handler", + obj); + updated = true; + } + + if (!updated) + fail ("class is neither Consumer nor Handler"); + + if (filter) + return new TeeConsumer (retval, next); + return retval; + + } catch (IOException e) { + throw e; + + } catch (NoSuchMethodException e) { + fail (name + " constructor missing -- " + msg); + + } catch (ClassNotFoundException e) { + fail (name + " class not found"); + + } catch (Exception e) { + // e.printStackTrace (); + fail ("stage not available: " + e.getMessage ()); + } + } + // NOTREACHED + return null; + } + } + + private static class Pipeline + { + Stage stage; + + // rest may be null + Pipeline rest; + EventConsumer next; + + Pipeline (Stage s) + { stage = s; } + + public String toString () + { + if (rest == null && next == null) + return stage.toString (); + if (rest != null) + return stage + " | " + rest; + throw new IllegalArgumentException ("next"); + } + + EventConsumer createPipeline () + throws IOException + { + if (next == null) { + if (rest == null) + next = stage.createStage (null); + else + next = stage.createStage (rest.createPipeline ()); + } + return next; + } + } + +/* + public static void main (String argv []) + { + try { + // three basic terminus cases + createPipeline ("null"); + createPipeline ("validate"); + createPipeline ("write ( stdout )"); + + // four basic filters + createPipeline ("nsfix | write ( stderr )"); + createPipeline ("wf | null"); + createPipeline ("null | null"); + createPipeline ( +"call ( http://www.example.com/services/xml-1a ) | xhtml ( stdout )"); + + // tee junctions + createPipeline ("tee ( validate ) | write ( stdout )"); + createPipeline ("tee ( nsfix | write ( stdout ) ) | validate"); + + // longer pipeline + createPipeline ("nsfix | tee ( validate ) | write ( stdout )"); + createPipeline ( + "null | wf | nsfix | tee ( validate ) | write ( stdout )"); + + // try some parsing error cases + try { + createPipeline ("null ("); // extra token '(' + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("nsfix |"); // extra token '|' + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("xhtml ( foo"); // missing right paren + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("xhtml ( foo bar"); // required right paren + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("tee ( nsfix | validate");// missing right paren + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + // try some construction error cases + + try { + createPipeline ("call"); // missing param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("call ( foobar )"); // broken param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("nsfix ( foobar )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("null ( foobar )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("wf ( foobar )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("xhtml ( foobar.html )"); + new File ("foobar.html").delete (); + // now supported + } catch (Exception e) { + System.err.println ("** err: " + e.getMessage ()); } + try { + createPipeline ("xhtml"); // missing param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("write ( stdout ) | null"); // nonterminal + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("validate | null"); + // now supported + } catch (Exception e) { + System.err.println ("** err: " + e.getMessage ()); } + try { + createPipeline ("validate ( foo )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("tee"); // missing param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + // only builtins so far + createPipeline ("com.example.xml.FilterClass"); + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + } catch (Exception e) { + e.printStackTrace (); + } + } +/**/ + +} diff --git a/libjava/classpath/gnu/xml/pipeline/TeeConsumer.java b/libjava/classpath/gnu/xml/pipeline/TeeConsumer.java new file mode 100644 index 0000000..8186de4 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/TeeConsumer.java @@ -0,0 +1,417 @@ +/* TeeConsumer.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.pipeline; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; + +/** + * Fans its events out to two other consumers, a "tee" filter stage in an + * event pipeline. Networks can be assembled with multiple output points. + * + *
Error handling should be simple if you remember that exceptions + * you throw will cancel later stages in that callback's pipeline, and + * generally the producer will stop if it sees such an exception. You + * may want to protect your pipeline against such backflows, making a + * kind of reverse filter (or valve?) so that certain exceptions thrown by + * your pipeline will caught and handled before the producer sees them. + * Just use a "try/catch" block, rememebering that really important + * cleanup tasks should be in "finally" clauses. + * + *
That issue isn't unique to "tee" consumers, but tee consumers have + * the additional twist that exceptions thrown by the first consumer + * will cause the second consumer not to see the callback (except for + * the endDocument callback, which signals state cleanup). + * + * @author David Brownell + */ +final public class TeeConsumer + implements EventConsumer, + ContentHandler, DTDHandler, + LexicalHandler,DeclHandler +{ + private EventConsumer first, rest; + + // cached to minimize time overhead + private ContentHandler docFirst, docRest; + private DeclHandler declFirst, declRest; + private LexicalHandler lexFirst, lexRest; + + + /** + * Constructs a consumer which sends all its events to the first + * consumer, and then the second one. If the first consumer throws + * an exception, the second one will not see the event which + * caused that exception to be reported. + * + * @param car The first consumer to get the events + * @param cdr The second consumer to get the events + */ + public TeeConsumer (EventConsumer car, EventConsumer cdr) + { + if (car == null || cdr == null) + throw new NullPointerException (); + first = car; + rest = cdr; + + // + // Cache the handlers. + // + docFirst = first.getContentHandler (); + docRest = rest.getContentHandler (); + // DTD handler isn't cached (rarely needed) + + try { + declFirst = null; + declFirst = (DeclHandler) first.getProperty ( + EventFilter.DECL_HANDLER); + } catch (SAXException e) {} + try { + declRest = null; + declRest = (DeclHandler) rest.getProperty ( + EventFilter.DECL_HANDLER); + } catch (SAXException e) {} + + try { + lexFirst = null; + lexFirst = (LexicalHandler) first.getProperty ( + EventFilter.LEXICAL_HANDLER); + } catch (SAXException e) {} + try { + lexRest = null; + lexRest = (LexicalHandler) rest.getProperty ( + EventFilter.LEXICAL_HANDLER); + } catch (SAXException e) {} + } + +/* FIXME + /** + * Constructs a pipeline, and is otherwise a shorthand for the + * two-consumer constructor for this class. + * + * @param first Description of the first pipeline to get events, + * which will be passed to {@link PipelineFactory#createPipeline} + * @param rest The second pipeline to get the events + * / + // constructor used by PipelineFactory + public TeeConsumer (String first, EventConsumer rest) + throws IOException + { + this (PipelineFactory.createPipeline (first), rest); + } +*/ + + /** Returns the first pipeline to get event calls. */ + public EventConsumer getFirst () + { return first; } + + /** Returns the second pipeline to get event calls. */ + public EventConsumer getRest () + { return rest; } + + /** Returns the content handler being used. */ + final public ContentHandler getContentHandler () + { + if (docRest == null) + return docFirst; + if (docFirst == null) + return docRest; + return this; + } + + /** Returns the dtd handler being used. */ + final public DTDHandler getDTDHandler () + { + // not cached (hardly used) + if (rest.getDTDHandler () == null) + return first.getDTDHandler (); + if (first.getDTDHandler () == null) + return rest.getDTDHandler (); + return this; + } + + /** Returns the declaration or lexical handler being used. */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + // + // in degenerate cases, we have no work to do. + // + Object firstProp = null, restProp = null; + + try { firstProp = first.getProperty (id); } + catch (SAXNotRecognizedException e) { /* ignore */ } + try { restProp = rest.getProperty (id); } + catch (SAXNotRecognizedException e) { /* ignore */ } + + if (restProp == null) + return firstProp; + if (firstProp == null) + return restProp; + + // + // we've got work to do; handle two builtin cases. + // + if (EventFilter.DECL_HANDLER.equals (id)) + return this; + if (EventFilter.LEXICAL_HANDLER.equals (id)) + return this; + + // + // non-degenerate, handled by both consumers, but we don't know + // how to handle this. + // + throw new SAXNotRecognizedException ("can't tee: " + id); + } + + /** + * Provides the error handler to both subsequent nodes of + * this filter stage. + */ + public void setErrorHandler (ErrorHandler handler) + { + first.setErrorHandler (handler); + rest.setErrorHandler (handler); + } + + + // + // ContentHandler + // + public void setDocumentLocator (Locator locator) + { + // this call is not made by all parsers + docFirst.setDocumentLocator (locator); + docRest.setDocumentLocator (locator); + } + + public void startDocument () + throws SAXException + { + docFirst.startDocument (); + docRest.startDocument (); + } + + public void endDocument () + throws SAXException + { + try { + docFirst.endDocument (); + } finally { + docRest.endDocument (); + } + } + + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + docFirst.startPrefixMapping (prefix, uri); + docRest.startPrefixMapping (prefix, uri); + } + + public void endPrefixMapping (String prefix) + throws SAXException + { + docFirst.endPrefixMapping (prefix); + docRest.endPrefixMapping (prefix); + } + + public void skippedEntity (String name) + throws SAXException + { + docFirst.skippedEntity (name); + docRest.skippedEntity (name); + } + + public void startElement (String uri, String localName, + String qName, Attributes atts) + throws SAXException + { + docFirst.startElement (uri, localName, qName, atts); + docRest.startElement (uri, localName, qName, atts); + } + + public void endElement (String uri, String localName, String qName) + throws SAXException + { + docFirst.endElement (uri, localName, qName); + docRest.endElement (uri, localName, qName); + } + + public void processingInstruction (String target, String data) + throws SAXException + { + docFirst.processingInstruction (target, data); + docRest.processingInstruction (target, data); + } + + public void characters (char ch [], int start, int length) + throws SAXException + { + docFirst.characters (ch, start, length); + docRest.characters (ch, start, length); + } + + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + docFirst.ignorableWhitespace (ch, start, length); + docRest.ignorableWhitespace (ch, start, length); + } + + + // + // DTDHandler + // + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + DTDHandler l1 = first.getDTDHandler (); + DTDHandler l2 = rest.getDTDHandler (); + + l1.notationDecl (name, publicId, systemId); + l2.notationDecl (name, publicId, systemId); + } + + public void unparsedEntityDecl (String name, + String publicId, String systemId, + String notationName + ) throws SAXException + { + DTDHandler l1 = first.getDTDHandler (); + DTDHandler l2 = rest.getDTDHandler (); + + l1.unparsedEntityDecl (name, publicId, systemId, notationName); + l2.unparsedEntityDecl (name, publicId, systemId, notationName); + } + + + // + // DeclHandler + // + public void attributeDecl (String eName, String aName, + String type, + String mode, String value) + throws SAXException + { + declFirst.attributeDecl (eName, aName, type, mode, value); + declRest.attributeDecl (eName, aName, type, mode, value); + } + + public void elementDecl (String name, String model) + throws SAXException + { + declFirst.elementDecl (name, model); + declRest.elementDecl (name, model); + } + + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + { + declFirst.externalEntityDecl (name, publicId, systemId); + declRest.externalEntityDecl (name, publicId, systemId); + } + + public void internalEntityDecl (String name, String value) + throws SAXException + { + declFirst.internalEntityDecl (name, value); + declRest.internalEntityDecl (name, value); + } + + + // + // LexicalHandler + // + public void comment (char ch [], int start, int length) + throws SAXException + { + lexFirst.comment (ch, start, length); + lexRest.comment (ch, start, length); + } + + public void startCDATA () + throws SAXException + { + lexFirst.startCDATA (); + lexRest.startCDATA (); + } + + public void endCDATA () + throws SAXException + { + lexFirst.endCDATA (); + lexRest.endCDATA (); + } + + public void startEntity (String name) + throws SAXException + { + lexFirst.startEntity (name); + lexRest.startEntity (name); + } + + public void endEntity (String name) + throws SAXException + { + lexFirst.endEntity (name); + lexRest.endEntity (name); + } + + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + lexFirst.startDTD (name, publicId, systemId); + lexRest.startDTD (name, publicId, systemId); + } + + public void endDTD () + throws SAXException + { + lexFirst.endDTD (); + lexRest.endDTD (); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/TextConsumer.java b/libjava/classpath/gnu/xml/pipeline/TextConsumer.java new file mode 100644 index 0000000..67bd23b --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/TextConsumer.java @@ -0,0 +1,117 @@ +/* TextConsumer.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.pipeline; + +import java.io.*; + +import org.xml.sax.*; + +import gnu.xml.util.XMLWriter; + + +/** + * Terminates a pipeline, consuming events to print them as well formed + * XML (or XHTML) text. + * + *
Input must be well formed, and must include XML names (e.g. the + * prefixes and prefix declarations must be present), or the output of + * this class is undefined. + * + * @see NSFilter + * @see WellFormednessFilter + * + * @author David Brownell + */ +public class TextConsumer extends XMLWriter implements EventConsumer +{ + /** + * Constructs an event consumer which echoes its input as text, + * optionally adhering to some basic XHTML formatting options + * which increase interoperability with old (v3) browsers. + * + *
For the best interoperability, when writing as XHTML only + * ASCII characters are emitted; other characters are turned to + * entity or character references as needed, and no XML declaration + * is provided in the document. + */ + public TextConsumer (Writer w, boolean isXhtml) + throws IOException + { + super (w, isXhtml ? "US-ASCII" : null); + setXhtml (isXhtml); + } + + /** + * Constructs a consumer that writes its input as XML text. + * XHTML rules are not followed. + */ + public TextConsumer (Writer w) + throws IOException + { + this (w, false); + } + + /** + * Constructs a consumer that writes its input as XML text, + * encoded in UTF-8. XHTML rules are not followed. + */ + public TextConsumer (OutputStream out) + throws IOException + { + this (new OutputStreamWriter (out, "UTF8"), false); + } + + /** EventConsumer Returns the document handler being used. */ + public ContentHandler getContentHandler () + { return this; } + + /** EventConsumer Returns the dtd handler being used. */ + public DTDHandler getDTDHandler () + { return this; } + + /** XMLReaderRetrieves a property (lexical and decl handlers) */ + public Object getProperty (String propertyId) + throws SAXNotRecognizedException + { + if (EventFilter.LEXICAL_HANDLER.equals (propertyId)) + return this; + if (EventFilter.DECL_HANDLER.equals (propertyId)) + return this; + throw new SAXNotRecognizedException (propertyId); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java b/libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java new file mode 100644 index 0000000..0fbfa9264 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java @@ -0,0 +1,1928 @@ +/* ValidationConsumer.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.pipeline; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.EmptyStackException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.xml.sax.Attributes; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +/** + * This class checks SAX2 events to report validity errors; it works as + * both a filter and a terminus on an event pipeline. It relies on the + * producer of SAX events to:
xmlns*
+ * attributes (rather than omitting either or both). At this writing, the major SAX2 parsers (such as Ælfred2, + * Crimson, and Xerces) meet these requirements, and this validation + * module is used by the optional Ælfred2 validation support. + *
+ * + *Note that because this is a layered validator, it has to duplicate some + * work that the parser is doing; there are also other cost to layering. + * However, because of layering it doesn't need a parser in order + * to work! You can use it with anything that generates SAX events, such + * as an application component that wants to detect invalid content in + * a changed area without validating an entire document, or which wants to + * ensure that it doesn't write invalid data to a communications partner.
+ * + *Also, note that because this is a layered validator, the line numbers + * reported for some errors may seem strange. For example, if an element does + * not permit character content, the validator + * will use the locator provided to it. + * That might reflect the last character of a characters event + * callback, rather than the first non-whitespace character.
+ * + *Current limitations of the validation performed are in roughly three + * categories.
+ * + *The first category represents constraints which demand violations + * of software layering: exposing lexical details, one of the first things + * that application programming interfaces (APIs) hide. These + * invariably relate to XML entity handling, and to historical oddities + * of the XML validation semantics. Curiously, + * recent (Autumn 1999) conformance testing showed that these constraints are + * among those handled worst by existing XML validating parsers. Arguments + * have been made that each of these VCs should be turned into WFCs (most + * of them) or discarded (popular for the standalone declaration); in short, + * that these are bugs in the XML specification (not all via SGML):
The second category of limitations on this validation represent + * constraints associated with information that is not guaranteed to be + * available (or in one case, is guaranteed not to be available, + * through the SAX2 API:
A third category relates to ease of implementation. (Think of this + * as "bugs".) The most notable issue here is character handling. Rather + * than attempting to implement the voluminous character tables in the XML + * specification (Appendix B), Unicode rules are used directly from + * the java.lang.Character class. Recent JVMs have begun to diverge from + * the original specification for that class (Unicode 2.0), meaning that + * different JVMs may handle that aspect of conformance differently. + *
+ * + *Note that for some of the validity errors that SAX2 does not + * expose, a nonvalidating parser is permitted (by the XML specification) + * to report validity errors. When used with a parser that does so for + * the validity constraints mentioned above (or any other SAX2 event + * stream producer that does the same thing), overall conformance is + * substantially improved. + * + * @see gnu.xml.aelfred2.SAXDriver + * @see gnu.xml.aelfred2.XmlReader + * + * @author David Brownell + */ +public final class ValidationConsumer extends EventFilter +{ + // report error if we happen to notice a non-deterministic choice? + // we won't report buggy content models; just buggy instances + private static final boolean warnNonDeterministic = false; + + // for tracking active content models + private String rootName; + private Stack contentStack = new Stack (); + + // flags for "saved DTD" processing + private boolean disableDeclarations; + private boolean disableReset; + + // + // most VCs get tested when we see element start tags. the per-element + // info (including attributes) recorded here duplicates that found inside + // many nonvalidating parsers, hence dual lookups etc ... that's why a + // layered validator isn't going to be as fast as a non-layered one. + // + + // key = element name; value = ElementInfo + private Hashtable elements = new Hashtable (); + + // some VCs relate to ID/IDREF/IDREFS attributes + // key = id; value = boolean true (defd) or false (refd) + private Hashtable ids = new Hashtable (); + + // we just record declared notation and unparsed entity names. + // the implementation here is simple/slow; these features + // are seldom used, one hopes they'll wither away soon + private Vector notations = new Vector (5, 5); + private Vector nDeferred = new Vector (5, 5); + private Vector unparsed = new Vector (5, 5); + private Vector uDeferred = new Vector (5, 5); + + // note: DocBk 3.1.7 XML defines over 2 dozen notations, + // used when defining unparsed entities for graphics + // (and maybe in other places) + + + + /** + * Creates a pipeline terminus which consumes all events passed to + * it; this will report validity errors as if they were fatal errors, + * unless an error handler is assigned. + * + * @see #setErrorHandler + */ + // constructor used by PipelineFactory + // ... and want one taking system ID of an external subset + public ValidationConsumer () + { + this (null); + } + + /** + * Creates a pipeline filter which reports validity errors and then + * passes events on to the next consumer if they were not fatal. + * + * @see #setErrorHandler + */ + // constructor used by PipelineFactory + // ... and want one taking system ID of an external subset + // (which won't send declaration events) + public ValidationConsumer (EventConsumer next) + { + super (next); + + setContentHandler (this); + setDTDHandler (this); + try { setProperty (DECL_HANDLER, this); } + catch (Exception e) { /* "can't happen" */ } + try { setProperty (LEXICAL_HANDLER, this); } + catch (Exception e) { /* "can't happen" */ } + } + + + private static final String fakeRootName + = ":Nobody:in:their_Right.Mind_would:use:this-name:1x:"; + + /** + * Creates a validation consumer which is preloaded with the DTD provided. + * It does this by constructing a document with that DTD, then parsing + * that document and recording its DTD declarations. Then it arranges + * not to modify that information. + * + *
The resulting validation consumer will only validate against + * the specified DTD, regardless of whether some other DTD is found + * in a document being parsed. + * + * @param rootName The name of the required root element; if this is + * null, any root element name will be accepted. + * @param publicId If non-null and there is a non-null systemId, this + * identifier provides an alternate access identifier for the DTD's + * external subset. + * @param systemId If non-null, this is a URI (normally URL) that + * may be used to access the DTD's external subset. + * @param internalSubset If non-null, holds literal markup declarations + * comprising the DTD's internal subset. + * @param resolver If non-null, this will be provided to the parser for + * use when resolving parameter entities (including any external subset). + * @param resolver If non-null, this will be provided to the parser for + * use when resolving parameter entities (including any external subset). + * @param minimalElement If non-null, a minimal valid document. + * + * @exception SAXNotSupportedException If the default SAX parser does + * not support the standard lexical or declaration handlers. + * @exception SAXParseException If the specified DTD has either + * well-formedness or validity errors + * @exception IOException If the specified DTD can't be read for + * some reason + */ + public ValidationConsumer ( + String rootName, + String publicId, + String systemId, + String internalSubset, + EntityResolver resolver, + String minimalDocument + ) throws SAXException, IOException + { + this (null); + + disableReset = true; + if (rootName == null) + rootName = fakeRootName; + + // + // Synthesize document with that DTD; is it possible to do + // better for the declaration of the root element? + // + // NOTE: can't use SAX2 to write internal subsets. + // + StringWriter writer = new StringWriter (); + + writer.write (""); + } + if (internalSubset != null) + writer.write (internalSubset); + writer.write ("\n ]>"); + + if (minimalDocument != null) { + writer.write ("\n"); + writer.write (minimalDocument); + writer.write ("\n"); + } else { + writer.write (" <"); + writer.write (rootName); + writer.write ("/>\n"); + } + minimalDocument = writer.toString (); + + // + // OK, load it + // + XMLReader producer; + + producer = XMLReaderFactory.createXMLReader (); + bind (producer, this); + + if (resolver != null) + producer.setEntityResolver (resolver); + + InputSource in; + + in = new InputSource (new StringReader (minimalDocument)); + producer.parse (in); + + disableDeclarations = true; + if (rootName == fakeRootName) + this.rootName = null; + } + + private void resetState () + { + if (!disableReset) { + rootName = null; + contentStack.removeAllElements (); + elements.clear (); + ids.clear (); + + notations.removeAllElements (); + nDeferred.removeAllElements (); + unparsed.removeAllElements (); + uDeferred.removeAllElements (); + } + } + + + private void warning (String description) + throws SAXException + { + ErrorHandler errHandler = getErrorHandler (); + Locator locator = getDocumentLocator (); + SAXParseException err; + + if (errHandler == null) + return; + + if (locator == null) + err = new SAXParseException (description, null, null, -1, -1); + else + err = new SAXParseException (description, locator); + errHandler.warning (err); + } + + // package private (for ChildrenRecognizer) + private void error (String description) + throws SAXException + { + ErrorHandler errHandler = getErrorHandler (); + Locator locator = getDocumentLocator (); + SAXParseException err; + + if (locator == null) + err = new SAXParseException (description, null, null, -1, -1); + else + err = new SAXParseException (description, locator); + if (errHandler != null) + errHandler.error (err); + else // else we always treat it as fatal! + throw err; + } + + private void fatalError (String description) + throws SAXException + { + ErrorHandler errHandler = getErrorHandler (); + Locator locator = getDocumentLocator (); + SAXParseException err; + + if (locator != null) + err = new SAXParseException (description, locator); + else + err = new SAXParseException (description, null, null, -1, -1); + if (errHandler != null) + errHandler.fatalError (err); + // we always treat this as fatal, regardless of the handler + throw err; + } + + + private static boolean isExtender (char c) + { + // [88] Extender ::= ... + return c == 0x00b7 || c == 0x02d0 || c == 0x02d1 || c == 0x0387 + || c == 0x0640 || c == 0x0e46 || c == 0x0ec6 || c == 0x3005 + || (c >= 0x3031 && c <= 0x3035) + || (c >= 0x309d && c <= 0x309e) + || (c >= 0x30fc && c <= 0x30fe); + } + + + // use augmented Unicode rules, not full XML rules + private boolean isName (String name, String context, String id) + throws SAXException + { + char buf [] = name.toCharArray (); + boolean pass = true; + + if (!Character.isUnicodeIdentifierStart (buf [0]) + && ":_".indexOf (buf [0]) == -1) + pass = false; + else { + int max = buf.length; + for (int i = 1; pass && i < max; i++) { + char c = buf [i]; + if (!Character.isUnicodeIdentifierPart (c) + && ":-_.".indexOf (c) == -1 + && !isExtender (c)) + pass = false; + } + } + + if (!pass) + error ("In " + context + " for " + id + + ", '" + name + "' is not a name"); + return pass; // true == OK + } + + // use augmented Unicode rules, not full XML rules + private boolean isNmtoken (String nmtoken, String context, String id) + throws SAXException + { + char buf [] = nmtoken.toCharArray (); + boolean pass = true; + int max = buf.length; + + // XXX make this share code with isName + + for (int i = 0; pass && i < max; i++) { + char c = buf [i]; + if (!Character.isUnicodeIdentifierPart (c) + && ":-_.".indexOf (c) == -1 + && !isExtender (c)) + pass = false; + } + + if (!pass) + error ("In " + context + " for " + id + + ", '" + nmtoken + "' is not a name token"); + return pass; // true == OK + } + + private void checkEnumeration (String value, String type, String name) + throws SAXException + { + if (!hasMatch (value, type)) + // VC: Enumeration + error ("Value '" + value + + "' for attribute '" + name + + "' is not permitted: " + type); + } + + // used to test enumerated attributes and mixed content models + // package private + static boolean hasMatch (String value, String orList) + { + int len = value.length (); + int max = orList.length () - len; + + for (int start = 0; + (start = orList.indexOf (value, start)) != -1; + start++) { + char c; + + if (start > max) + break; + c = orList.charAt (start - 1); + if (c != '|' && c != '('/*)*/) + continue; + c = orList.charAt (start + len); + if (c != '|' && /*(*/ c != ')') + continue; + return true; + } + return false; + } + + /** + * LexicalHandler Records the declaration of the root + * element, so it can be verified later. + * Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + if (disableDeclarations) + return; + + rootName = name; + super.startDTD (name, publicId, systemId); + } + + /** + * LexicalHandler Verifies that all referenced notations + * and unparsed entities have been declared. + * Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void endDTD () + throws SAXException + { + if (disableDeclarations) + return; + + // this is a convenient hook for end-of-dtd checks, but we + // could also trigger it in the first startElement call. + // locator info is more appropriate here though. + + // VC: Notation Declared (NDATA can refer to them before decls, + // as can NOTATION attribute enumerations and defaults) + int length = nDeferred.size (); + for (int i = 0; i < length; i++) { + String notation = (String) nDeferred.elementAt (i); + if (!notations.contains (notation)) { + error ("A declaration referred to notation '" + notation + + "' which was never declared"); + } + } + nDeferred.removeAllElements (); + + // VC: Entity Name (attribute values can refer to them + // before they're declared); VC Attribute Default Legal + length = uDeferred.size (); + for (int i = 0; i < length; i++) { + String entity = (String) uDeferred.elementAt (i); + if (!unparsed.contains (entity)) { + error ("An attribute default referred to entity '" + entity + + "' which was never declared"); + } + } + uDeferred.removeAllElements (); + super.endDTD (); + } + + + // These are interned, so we can rely on "==" to find the type of + // all attributes except enumerations ... + // "(this|or|that|...)" and "NOTATION (this|or|that|...)" + static final String types [] = { + "CDATA", + "ID", "IDREF", "IDREFS", + "NMTOKEN", "NMTOKENS", + "ENTITY", "ENTITIES" + }; + + + /** + * DecllHandler Records attribute declaration for later use + * in validating document content, and checks validity constraints + * that are applicable to attribute declarations. + * Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void attributeDecl ( + String eName, + String aName, + String type, + String mode, + String value + ) throws SAXException + { + if (disableDeclarations) + return; + + ElementInfo info = (ElementInfo) elements.get (eName); + AttributeInfo ainfo = new AttributeInfo (); + boolean checkOne = false; + boolean interned = false; + + // cheap interning of type names and #FIXED, #REQUIRED + // for faster startElement (we can use "==") + for (int i = 0; i < types.length; i++) { + if (types [i].equals (type)) { + type = types [i]; + interned = true; + break; + } + } + if ("#FIXED".equals (mode)) + mode = "#FIXED"; + else if ("#REQUIRED".equals (mode)) + mode = "#REQUIRED"; + + ainfo.type = type; + ainfo.mode = mode; + ainfo.value = value; + + // we might not have seen the content model yet + if (info == null) { + info = new ElementInfo (eName); + elements.put (eName, info); + } + if ("ID" == type) { + checkOne = true; + if (!("#REQUIRED" == mode || "#IMPLIED".equals (mode))) { + // VC: ID Attribute Default + error ("ID attribute '" + aName + + "' must be #IMPLIED or #REQUIRED"); + } + + } else if (!interned && type.startsWith ("NOTATION ")) { + checkOne = true; + + // VC: Notation Attributes (notations must be declared) + StringTokenizer tokens = new StringTokenizer ( + type.substring (10, type.lastIndexOf (')')), + "|"); + while (tokens.hasMoreTokens ()) { + String token = tokens.nextToken (); + if (!notations.contains (token)) + nDeferred.addElement (token); + } + } + if (checkOne) { + for (Enumeration e = info.attributes.keys (); + e.hasMoreElements (); + /* NOP */) { + String name; + AttributeInfo ainfo2; + + name = (String) e.nextElement (); + ainfo2 = (AttributeInfo) info.attributes.get (name); + if (type == ainfo2.type || !interned /* NOTATION */) { + // VC: One ID per Element Type + // VC: One Notation per Element TYpe + error ("Element '" + eName + + "' already has an attribute of type " + + (interned ? "NOTATION" : type) + + " ('" + name + + "') so '" + aName + + "' is a validity error"); + } + } + } + + // VC: Attribute Default Legal + if (value != null) { + + if ("CDATA" == type) { + // event source rejected '<' + + } else if ("NMTOKEN" == type) { + // VC: Name Token (is a nmtoken) + isNmtoken (value, "attribute default", aName); + + } else if ("NMTOKENS" == type) { + // VC: Name Token (is a nmtoken; at least one value) + StringTokenizer tokens = new StringTokenizer (value); + if (!tokens.hasMoreTokens ()) + error ("Default for attribute '" + aName + + "' must have at least one name token."); + else do { + String token = tokens.nextToken (); + isNmtoken (token, "attribute default", aName); + } while (tokens.hasMoreTokens ()); + + } else if ("IDREF" == type || "ENTITY" == type) { + // VC: Entity Name (is a name) + // VC: IDREF (is a name) (is declared) + isName (value, "attribute default", aName); + if ("ENTITY" == type && !unparsed.contains (value)) + uDeferred.addElement (value); + + } else if ("IDREFS" == type || "ENTITIES" == type) { + // VC: Entity Name (is a name; at least one value) + // VC: IDREF (is a name; at least one value) + StringTokenizer names = new StringTokenizer (value); + if (!names.hasMoreTokens ()) + error ("Default for attribute '" + aName + + "' must have at least one name."); + else do { + String name = names.nextToken (); + isName (name, "attribute default", aName); + if ("ENTITIES" == type && !unparsed.contains (name)) + uDeferred.addElement (value); + } while (names.hasMoreTokens ()); + + } else if (type.charAt (0) == '(' /*)*/ ) { + // VC: Enumeration (must match) + checkEnumeration (value, type, aName); + + } else if (!interned && checkOne) { /* NOTATION */ + // VC: Notation attributes (must be names) + isName (value, "attribute default", aName); + + // VC: Notation attributes (must be declared) + if (!notations.contains (value)) + nDeferred.addElement (value); + + // VC: Enumeration (must match) + checkEnumeration (value, type, aName); + + } else if ("ID" != type) + throw new RuntimeException ("illegal attribute type: " + type); + } + + if (info.attributes.get (aName) == null) + info.attributes.put (aName, ainfo); + /* + else + warning ("Element '" + eName + + "' already has an attribute named '" + aName + "'"); + */ + + if ("xml:space".equals (aName)) { + if (!("(default|preserve)".equals (type) + || "(preserve|default)".equals (type) + // these next two are arguable; XHTML's DTD doesn't + // deserve errors. After all, it's not like any + // illegal _value_ could pass ... + || "(preserve)".equals (type) + || "(default)".equals (type) + )) + error ( + "xml:space attribute type must be like '(default|preserve)'" + + " not '" + type + "'" + ); + + } + super.attributeDecl (eName, aName, type, mode, value); + } + + /** + * DecllHandler Records the element declaration for later use + * when checking document content, and checks validity constraints that + * apply to element declarations. Passed to the next consumer, unless + * this one was preloaded with a particular DTD. + */ + public void elementDecl (String name, String model) + throws SAXException + { + if (disableDeclarations) + return; + + ElementInfo info = (ElementInfo) elements.get (name); + + // we might have seen an attribute decl already + if (info == null) { + info = new ElementInfo (name); + elements.put (name, info); + } + if (info.model != null) { + // NOTE: not all parsers can report such duplicates. + // VC: Unique Element Type Declaration + error ("Element type '" + name + + "' was already declared."); + } else { + info.model = model; + + // VC: No Duplicate Types (in mixed content models) + if (model.charAt (1) == '#') // (#PCDATA... + info.getRecognizer (this); + } + super.elementDecl (name, model); + } + + /** + * DecllHandler passed to the next consumer, unless this + * one was preloaded with a particular DTD + */ + public void internalEntityDecl (String name, String value) + throws SAXException + { + if (!disableDeclarations) + super.internalEntityDecl (name, value); + } + + /** + * DecllHandler passed to the next consumer, unless this + * one was preloaded with a particular DTD + */ + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + { + if (!disableDeclarations) + super.externalEntityDecl (name, publicId, systemId); + } + + + /** + * DTDHandler Records the notation name, for checking + * NOTATIONS attribute values and declararations of unparsed + * entities. Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + if (disableDeclarations) + return; + + notations.addElement (name); + super.notationDecl (name, publicId, systemId); + } + + /** + * DTDHandler Records the entity name, for checking + * ENTITY and ENTITIES attribute values; records the notation + * name if it hasn't yet been declared. Passed to the next consumer, + * unless this one was preloaded with a particular DTD. + */ + public void unparsedEntityDecl ( + String name, + String publicId, + String systemId, + String notationName + ) throws SAXException + { + if (disableDeclarations) + return; + + unparsed.addElement (name); + if (!notations.contains (notationName)) + nDeferred.addElement (notationName); + super.unparsedEntityDecl (name, publicId, systemId, notationName); + } + + + /** + * ContentHandler Ensures that state from any previous parse + * has been deleted. + * Passed to the next consumer. + */ + public void startDocument () + throws SAXException + { + resetState (); + super.startDocument (); + } + + + private static boolean isAsciiLetter (char c) + { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + + + /** + * ContentHandler Reports a fatal exception. Validating + * XML processors may not skip any entities. + */ + public void skippedEntity (String name) + throws SAXException + { + fatalError ("may not skip entities"); + } + + /* + * SAX2 doesn't expand non-PE refs in attribute defaults... + */ + private String expandDefaultRefs (String s) + throws SAXException + { + if (s.indexOf ('&') < 0) + return s; + +// FIXME: handle nn; nn; &name; + String message = "Can't expand refs in attribute default: " + s; + warning (message); + + return s; + } + + /** + * ContentHandler Performs validity checks against element + * (and document) content models, and attribute values. + * Passed to the next consumer. + */ + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + // + // First check content model for the enclosing scope. + // + if (contentStack.isEmpty ()) { + // VC: Root Element Type + if (!qName.equals (rootName)) { + if (rootName == null) + warning ("This document has no DTD, can't be valid"); + else + error ("Root element type '" + qName + + "' was declared to be '" + rootName + "'"); + } + } else { + Recognizer state = (Recognizer) contentStack.peek (); + + if (state != null) { + Recognizer newstate = state.acceptElement (qName); + + if (newstate == null) + error ("Element type '" + qName + + "' in element '" + state.type.name + + "' violates content model " + state.type.model + ); + if (newstate != state) { + contentStack.pop (); + contentStack.push (newstate); + } + } + } + + // + // Then check that this element was declared, and push the + // object used to validate its content model onto our stack. + // + // This is where the recognizer gets created, if needed; if + // it's a "children" (elements) content model, an NDFA is + // created. (One recognizer is used per content type, no + // matter how complex that recognizer is.) + // + ElementInfo info; + + info = (ElementInfo) elements.get (qName); + if (info == null || info.model == null) { + // VC: Element Valid (base clause) + error ("Element type '" + qName + "' was not declared"); + contentStack.push (null); + + // for less diagnostic noise, fake a declaration. + elementDecl (qName, "ANY"); + } else + contentStack.push (info.getRecognizer (this)); + + // + // Then check each attribute present + // + int len; + String aname; + AttributeInfo ainfo; + + if (atts != null) + len = atts.getLength (); + else + len = 0; + + for (int i = 0; i < len; i++) { + aname = atts.getQName (i); + + if (info == null + || (ainfo = (AttributeInfo) info.attributes.get (aname)) + == null) { + // VC: Attribute Value Type + error ("Attribute '" + aname + + "' was not declared for element type " + qName); + continue; + } + + String value = atts.getValue (i); + + // note that "==" for type names and "#FIXED" is correct + // (and fast) since we've interned those literals. + + if ("#FIXED" == ainfo.mode) { + String expanded = expandDefaultRefs (ainfo.value); + + // VC: Fixed Attribute Default + if (!value.equals (expanded)) { + error ("Attribute '" + aname + + "' must match " + expanded + ); + continue; + } + } + + if ("CDATA" == ainfo.type) + continue; + + // + // For all other attribute types, there are various + // rules to follow. + // + + if ("ID" == ainfo.type) { + // VC: ID (must be a name) + if (isName (value, "ID attribute", aname)) { + if (Boolean.TRUE == ids.get (value)) + // VC: ID (appears once) + error ("ID attribute " + aname + + " uses an ID value '" + value + + "' which was already declared."); + else + // any forward refs are no longer problems + ids.put (value, Boolean.TRUE); + } + continue; + } + + if ("IDREF" == ainfo.type) { + // VC: IDREF (value must be a name) + if (isName (value, "IDREF attribute", aname)) { + // VC: IDREF (must match some ID attribute) + if (ids.get (value) == null) + // new -- assume it's a forward ref + ids.put (value, Boolean.FALSE); + } + continue; + } + + if ("IDREFS" == ainfo.type) { + StringTokenizer tokens = new StringTokenizer (value, " "); + + if (!tokens.hasMoreTokens ()) { + // VC: IDREF (one or more values) + error ("IDREFS attribute " + aname + + " must have at least one ID ref"); + } else do { + String id = tokens.nextToken (); + + // VC: IDREF (value must be a name) + if (isName (id, "IDREFS attribute", aname)) { + // VC: IDREF (must match some ID attribute) + if (ids.get (id) == null) + // new -- assume it's a forward ref + ids.put (id, Boolean.FALSE); + } + } while (tokens.hasMoreTokens ()); + continue; + } + + if ("NMTOKEN" == ainfo.type) { + // VC: Name Token (is a name token) + isNmtoken (value, "NMTOKEN attribute", aname); + continue; + } + + if ("NMTOKENS" == ainfo.type) { + StringTokenizer tokens = new StringTokenizer (value, " "); + + if (!tokens.hasMoreTokens ()) { + // VC: Name Token (one or more values) + error ("NMTOKENS attribute " + aname + + " must have at least one name token"); + } else do { + String token = tokens.nextToken (); + + // VC: Name Token (is a name token) + isNmtoken (token, "NMTOKENS attribute", aname); + } while (tokens.hasMoreTokens ()); + continue; + } + + if ("ENTITY" == ainfo.type) { + if (!unparsed.contains (value)) + // VC: Entity Name + error ("Value of attribute '" + aname + + "' refers to unparsed entity '" + value + + "' which was not declared."); + continue; + } + + if ("ENTITIES" == ainfo.type) { + StringTokenizer tokens = new StringTokenizer (value, " "); + + if (!tokens.hasMoreTokens ()) { + // VC: Entity Name (one or more values) + error ("ENTITIES attribute " + aname + + " must have at least one name token"); + } else do { + String entity = tokens.nextToken (); + + if (!unparsed.contains (entity)) + // VC: Entity Name + error ("Value of attribute '" + aname + + "' refers to unparsed entity '" + entity + + "' which was not declared."); + } while (tokens.hasMoreTokens ()); + continue; + } + + // + // check for enumerations last; more expensive + // + if (ainfo.type.charAt (0) == '(' /*)*/ + || ainfo.type.startsWith ("NOTATION ") + ) { + // VC: Enumeration (value must be defined) + checkEnumeration (value, ainfo.type, aname); + continue; + } + } + + // + // Last, check that all #REQUIRED attributes were provided + // + if (info != null) { + Hashtable table = info.attributes; + + if (table.size () != 0) { + Enumeration e = table.keys (); + + // XXX table.keys uses the heap, bleech -- slows things + + while (e.hasMoreElements ()) { + aname = (String) e.nextElement (); + ainfo = (AttributeInfo) table.get (aname); + + // "#REQUIRED" mode was interned in attributeDecl + if ("#REQUIRED" == ainfo.mode + && atts.getValue (aname) == null) { + // VC: Required Attribute + error ("Attribute '" + aname + "' must be specified " + + "for element type " + qName); + } + } + } + } + super.startElement (uri, localName, qName, atts); + } + + /** + * ContentHandler Reports a validity error if the element's content + * model does not permit character data. + * Passed to the next consumer. + */ + public void characters (char ch [], int start, int length) + throws SAXException + { + Recognizer state; + + if (contentStack.empty ()) + state = null; + else + state = (Recognizer) contentStack.peek (); + + // NOTE: if this ever supports with SAX parsers that don't + // report ignorable whitespace as such (only XP?), this class + // needs to morph it into ignorableWhitespace() as needed ... + + if (state != null && !state.acceptCharacters ()) + // VC: Element Valid (clauses three, four -- see recognizer) + error ("Character content not allowed in element " + + state.type.name); + + super.characters (ch, start, length); + } + + + /** + * ContentHandler Reports a validity error if the element's content + * model does not permit end-of-element yet, or a well formedness error + * if there was no matching startElement call. + * Passed to the next consumer. + */ + public void endElement (String uri, String localName, String qName) + throws SAXException + { + try { + Recognizer state = (Recognizer) contentStack.pop (); + + if (state != null && !state.completed ()) + // VC: Element valid (clauses two, three, four; see Recognizer) + error ("Premature end for element '" + + state.type.name + + "', content model " + + state.type.model); + + // could insist on match of start element, but that's + // something the input stream must to guarantee. + + } catch (EmptyStackException e) { + fatalError ("endElement without startElement: " + qName + + ((uri == null) + ? "" + : ( " { '" + uri + "', " + localName + " }"))); + } + super.endElement (uri, localName, qName); + } + + /** + * ContentHandler Checks whether all ID values that were + * referenced have been declared, and releases all resources. + * Passed to the next consumer. + * + * @see #setDocumentLocator + */ + public void endDocument () + throws SAXException + { + for (Enumeration idNames = ids.keys (); + idNames.hasMoreElements (); + /* NOP */) { + String id = (String) idNames.nextElement (); + + if (Boolean.FALSE == ids.get (id)) { + // VC: IDREF (must match ID) + error ("Undeclared ID value '" + id + + "' was referred to by an IDREF/IDREFS attribute"); + } + } + + resetState (); + super.endDocument (); + } + + + /** Holds per-element declarations */ + static private final class ElementInfo + { + String name; + String model; + + // key = attribute name; value = AttributeInfo + Hashtable attributes = new Hashtable (11); + + ElementInfo (String n) { name = n; } + + private Recognizer recognizer; + + // for validating content models: one per type, shared, + // and constructed only on demand ... so unused elements do + // not need to consume resources. + Recognizer getRecognizer (ValidationConsumer consumer) + throws SAXException + { + if (recognizer == null) { + if ("ANY".equals (model)) + recognizer = ANY; + else if ("EMPTY".equals (model)) + recognizer = new EmptyRecognizer (this); + else if ('#' == model.charAt (1)) + // n.b. this constructor does a validity check + recognizer = new MixedRecognizer (this, consumer); + else + recognizer = new ChildrenRecognizer (this, consumer); + } + return recognizer; + } + } + + /** Holds per-attribute declarations */ + static private final class AttributeInfo + { + String type; + String mode; // #REQUIRED, etc (or null) + String value; // or null + } + + + // + // Content model validation + // + + static private final Recognizer ANY = new Recognizer (null); + + + // Base class defines the calls used to validate content, + // and supports the "ANY" content model + static private class Recognizer + { + final ElementInfo type; + + Recognizer (ElementInfo t) { type = t; } + + // return true iff character data is legal here + boolean acceptCharacters () + throws SAXException + // VC: Element Valid (third and fourth clauses) + { return true; } + + // null return = failure + // otherwise, next state (like an FSM) + // prerequisite: tested that name was declared + Recognizer acceptElement (String name) + throws SAXException + // VC: Element Valid (fourth clause) + { return this; } + + // return true iff model is completed, can finish + boolean completed () + throws SAXException + // VC: Element Valid (fourth clause) + { return true; } + + public String toString () + // n.b. "children" is the interesting case! + { return (type == null) ? "ANY" : type.model; } + } + + // "EMPTY" content model -- no characters or elements + private static final class EmptyRecognizer extends Recognizer + { + public EmptyRecognizer (ElementInfo type) + { super (type); } + + // VC: Element Valid (first clause) + boolean acceptCharacters () + { return false; } + + // VC: Element Valid (first clause) + Recognizer acceptElement (String name) + { return null; } + } + + // "Mixed" content model -- ANY, but restricts elements + private static final class MixedRecognizer extends Recognizer + { + private String permitted []; + + // N.B. constructor tests for duplicated element names (VC) + public MixedRecognizer (ElementInfo t, ValidationConsumer v) + throws SAXException + { + super (t); + + // (#PCDATA...)* or (#PCDATA) ==> ... or empty + // with the "..." being "|elname|..." + StringTokenizer tokens = new StringTokenizer ( + t.model.substring (8, t.model.lastIndexOf (')')), + "|"); + Vector vec = new Vector (); + + while (tokens.hasMoreTokens ()) { + String token = tokens.nextToken (); + + if (vec.contains (token)) + v.error ("element " + token + + " is repeated in mixed content model: " + + t.model); + else + vec.addElement (token.intern ()); + } + permitted = new String [vec.size ()]; + for (int i = 0; i < permitted.length; i++) + permitted [i] = (String) vec.elementAt (i); + + // in one large machine-derived DTD sample, most of about + // 250 mixed content models were empty, and 25 had ten or + // more entries. 2 had over a hundred elements. Linear + // search isn't obviously wrong. + } + + // VC: Element Valid (third clause) + Recognizer acceptElement (String name) + { + int length = permitted.length; + + // first pass -- optimistic w.r.t. event source interning + // (and document validity) + for (int i = 0; i < length; i++) + if (permitted [i] == name) + return this; + // second pass -- pessimistic w.r.t. event source interning + for (int i = 0; i < length; i++) + if (permitted [i].equals (name)) + return this; + return null; + } + } + + + // recognizer loop flags, see later + private static final int F_LOOPHEAD = 0x01; + private static final int F_LOOPNEXT = 0x02; + + // for debugging -- used to label/count nodes in toString() + private static int nodeCount; + + /** + * "Children" content model -- these are nodes in NDFA state graphs. + * They work in fixed space. Note that these graphs commonly have + * cycles, handling features such as zero-or-more and one-or-more. + * + *
It's readonly, so only one copy is ever needed. The content model + * stack may have any number of pointers into each graph, when a model + * happens to be needed more than once due to element nesting. Since + * traversing the graph just moves to another node, and never changes + * it, traversals never interfere with each other. + * + *
There is an option to report non-deterministic models. These are + * always XML errors, but ones which are not often reported despite the + * fact that they can lead to different validating parsers giving + * different results for the same input. (The XML spec doesn't require + * them to be reported.) + * + *
FIXME There's currently at least one known bug here, in that + * it's not actually detecting the non-determinism it tries to detect. + * (Of the "optional.xml" test, the once-or-twice-2* tests are all non-D; + * maybe some others.) This may relate to the issue flagged below as + * "should not" happen (but it was), which showed up when patching the + * graph to have one exit node (or more EMPTY nodes). + */ + private static final class ChildrenRecognizer extends Recognizer + implements Cloneable + { + // for reporting non-deterministic content models + // ... a waste of space if we're not reporting those! + // ... along with the 'model' member (in base class) + private ValidationConsumer consumer; + + // for CHOICE nodes -- each component is an arc that + // accepts a different NAME (or is EMPTY indicating + // NDFA termination). + private Recognizer components []; + + // for NAME/SEQUENCE nodes -- accepts that NAME and + // then goes to the next node (CHOICE, NAME, EMPTY). + private String name; + private Recognizer next; + + // loops always point back to a CHOICE node. we mark such choice + // nodes (F_LOOPHEAD) for diagnostics and faster deep cloning. + // We also mark nodes before back pointers (F_LOOPNEXT), to ensure + // termination when we patch sequences and loops. + private int flags; + + + // prevent a needless indirection between 'this' and 'node' + private void copyIn (ChildrenRecognizer node) + { + // model & consumer are already set + components = node.components; + name = node.name; + next = node.next; + flags = node.flags; + } + + // used to construct top level "children" content models, + public ChildrenRecognizer (ElementInfo type, ValidationConsumer vc) + { + this (vc, type); + populate (type.model.toCharArray (), 0); + patchNext (new EmptyRecognizer (type), null); + } + + // used internally; populating is separate + private ChildrenRecognizer (ValidationConsumer vc, ElementInfo type) + { + super (type); + consumer = vc; + } + + + // + // When rewriting some graph nodes we need deep clones in one case; + // mostly shallow clones (what the JVM handles for us) are fine. + // + private ChildrenRecognizer shallowClone () + { + try { + return (ChildrenRecognizer) clone (); + } catch (CloneNotSupportedException e) { + throw new Error ("clone"); + } + } + + private ChildrenRecognizer deepClone () + { + return deepClone (new Hashtable (37)); + } + + private ChildrenRecognizer deepClone (Hashtable table) + { + ChildrenRecognizer retval; + + if ((flags & F_LOOPHEAD) != 0) { + retval = (ChildrenRecognizer) table.get (this); + if (retval != null) + return this; + + retval = shallowClone (); + table.put (this, retval); + } else + retval = shallowClone (); + + if (next != null) { + if (next instanceof ChildrenRecognizer) + retval.next = ((ChildrenRecognizer)next) + .deepClone (table); + else if (!(next instanceof EmptyRecognizer)) + throw new RuntimeException ("deepClone"); + } + + if (components != null) { + retval.components = new Recognizer [components.length]; + for (int i = 0; i < components.length; i++) { + Recognizer temp = components [i]; + + if (temp == null) + retval.components [i] = null; + else if (temp instanceof ChildrenRecognizer) + retval.components [i] = ((ChildrenRecognizer)temp) + .deepClone (table); + else if (!(temp instanceof EmptyRecognizer)) + throw new RuntimeException ("deepClone"); + } + } + + return retval; + } + + // connect subgraphs, first to next (sequencing) + private void patchNext (Recognizer theNext, Hashtable table) + { + // backpointers must not be repatched or followed + if ((flags & F_LOOPNEXT) != 0) + return; + + // XXX this table "shouldn't" be needed, right? + // but some choice nodes looped if it isn't there. + if (table != null && table.get (this) != null) + return; + if (table == null) + table = new Hashtable (); + + // NAME/SEQUENCE + if (name != null) { + if (next == null) + next = theNext; + else if (next instanceof ChildrenRecognizer) { + ((ChildrenRecognizer)next).patchNext (theNext, table); + } else if (!(next instanceof EmptyRecognizer)) + throw new RuntimeException ("patchNext"); + return; + } + + // CHOICE + for (int i = 0; i < components.length; i++) { + if (components [i] == null) + components [i] = theNext; + else if (components [i] instanceof ChildrenRecognizer) { + ((ChildrenRecognizer)components [i]) + .patchNext (theNext, table); + } else if (!(components [i] instanceof EmptyRecognizer)) + throw new RuntimeException ("patchNext"); + } + + if (table != null && (flags | F_LOOPHEAD) != 0) + table.put (this, this); + } + + /** + * Parses a 'children' spec (or recursively 'cp') and makes this + * become a regular graph node. + * + * @return index after this particle + */ + private int populate (char parseBuf [], int startPos) + { + int nextPos = startPos + 1; + char c; + + if (nextPos < 0 || nextPos >= parseBuf.length) + throw new IndexOutOfBoundsException (); + + // Grammar of the string is from the XML spec, but + // with whitespace removed by the SAX parser. + + // children ::= (choice | seq) ('?' | '*' | '+')? + // cp ::= (Name | choice | seq) ('?' | '*' | '+')? + // choice ::= '(' cp ('|' choice)* ')' + // seq ::= '(' cp (',' choice)* ')' + + // interior nodes only + // cp ::= name ... + if (parseBuf [startPos] != '('/*)*/) { + boolean done = false; + do { + switch (c = parseBuf [nextPos]) { + case '?': case '*': case '+': + case '|': case ',': + case /*(*/ ')': + done = true; + continue; + default: + nextPos++; + continue; + } + } while (!done); + name = new String (parseBuf, startPos, nextPos - startPos); + + // interior OR toplevel nodes + // cp ::= choice .. + // cp ::= seq .. + } else { + // collect everything as a separate list, and merge it + // into "this" later if we can (SEQUENCE or singleton) + ChildrenRecognizer first; + + first = new ChildrenRecognizer (consumer, type); + nextPos = first.populate (parseBuf, nextPos); + c = parseBuf [nextPos++]; + + if (c == ',' || c == '|') { + ChildrenRecognizer current = first; + char separator = c; + Vector v = null; + + if (separator == '|') { + v = new Vector (); + v.addElement (first); + } + + do { + ChildrenRecognizer link; + + link = new ChildrenRecognizer (consumer, type); + nextPos = link.populate (parseBuf, nextPos); + + if (separator == ',') { + current.patchNext (link, null); + current = link; + } else + v.addElement (link); + + c = parseBuf [nextPos++]; + } while (c == separator); + + // choice ... collect everything into one array. + if (separator == '|') { + // assert v.size() > 1 + components = new Recognizer [v.size ()]; + for (int i = 0; i < components.length; i++) { + components [i] = (Recognizer) + v.elementAt (i); + } + // assert flags == 0 + + // sequence ... merge into "this" to be smaller. + } else + copyIn (first); + + // treat singletons like one-node sequences. + } else + copyIn (first); + + if (c != /*(*/ ')') + throw new RuntimeException ("corrupt content model"); + } + + // + // Arity is optional, and the root of all fun. We keep the + // FSM state graph simple by only having NAME/SEQUENCE and + // CHOICE nodes (or EMPTY to terminate a model), easily + // evaluated. So we rewrite each node that has arity, using + // those primitives. We create loops here, if needed. + // + if (nextPos < parseBuf.length) { + c = parseBuf [nextPos]; + if (c == '?' || c == '*' || c == '+') { + nextPos++; + + // Rewrite 'zero-or-one' "?" arity to a CHOICE: + // - SEQUENCE (clone, what's next) + // - or, what's next + // Size cost: N --> N + 1 + if (c == '?') { + Recognizer once = shallowClone (); + + components = new Recognizer [2]; + components [0] = once; + // components [1] initted to null + name = null; + next = null; + flags = 0; + + + // Rewrite 'zero-or-more' "*" arity to a CHOICE. + // - LOOP (clone, back to this CHOICE) + // - or, what's next + // Size cost: N --> N + 1 + } else if (c == '*') { + ChildrenRecognizer loop = shallowClone (); + + loop.patchNext (this, null); + loop.flags |= F_LOOPNEXT; + flags = F_LOOPHEAD; + + components = new Recognizer [2]; + components [0] = loop; + // components [1] initted to null + name = null; + next = null; + + + // Rewrite 'one-or-more' "+" arity to a SEQUENCE. + // Basically (a)+ --> ((a),(a)*). + // - this + // - CHOICE + // * LOOP (clone, back to the CHOICE) + // * or, whatever's next + // Size cost: N --> 2N + 1 + } else if (c == '+') { + ChildrenRecognizer loop = deepClone (); + ChildrenRecognizer choice; + + choice = new ChildrenRecognizer (consumer, type); + loop.patchNext (choice, null); + loop.flags |= F_LOOPNEXT; + choice.flags = F_LOOPHEAD; + + choice.components = new Recognizer [2]; + choice.components [0] = loop; + // choice.components [1] initted to null + // choice.name, choice.next initted to null + + patchNext (choice, null); + } + } + } + + return nextPos; + } + + // VC: Element Valid (second clause) + boolean acceptCharacters () + { return false; } + + // VC: Element Valid (second clause) + Recognizer acceptElement (String type) + throws SAXException + { + // NAME/SEQUENCE + if (name != null) { + if (name.equals (type)) + return next; + return null; + } + + // CHOICE ... optionally reporting nondeterminism we + // run across. we won't check out every transition + // for nondeterminism; only the ones we follow. + Recognizer retval = null; + + for (int i = 0; i < components.length; i++) { + Recognizer temp = components [i].acceptElement (type); + + if (temp == null) + continue; + else if (!warnNonDeterministic) + return temp; + else if (retval == null) + retval = temp; + else if (retval != temp) + consumer.error ("Content model " + this.type.model + + " is non-deterministic for " + type); + } + return retval; + } + + // VC: Element Valid (second clause) + boolean completed () + throws SAXException + { + // expecting a specific element + if (name != null) + return false; + + // choice, some sequences + for (int i = 0; i < components.length; i++) { + if (components [i].completed ()) + return true; + } + + return false; + } + +/** / + // FOR DEBUGGING ... flattens the graph for printing. + + public String toString () + { + StringBuffer buf = new StringBuffer (); + + // only one set of loop labels can be generated + // at a time... + synchronized (ANY) { + nodeCount = 0; + + toString (buf, new Hashtable ()); + return buf.toString (); + } + } + + private void toString (StringBuffer buf, Hashtable table) + { + // When we visit a node, label and count it. + // Nodes are never visited/counted more than once. + // For small models labels waste space, but if arity + // mappings were used the savings are substantial. + // (Plus, the output can be more readily understood.) + String temp = (String) table.get (this); + + if (temp != null) { + buf.append ('{'); + buf.append (temp); + buf.append ('}'); + return; + } else { + StringBuffer scratch = new StringBuffer (15); + + if ((flags & F_LOOPHEAD) != 0) + scratch.append ("loop"); + else + scratch.append ("node"); + scratch.append ('-'); + scratch.append (++nodeCount); + temp = scratch.toString (); + + table.put (this, temp); + buf.append ('['); + buf.append (temp); + buf.append (']'); + buf.append (':'); + } + + // NAME/SEQUENCE + if (name != null) { + // n.b. some output encodings turn some name chars into '?' + // e.g. with Japanese names and ASCII output + buf.append (name); + if (components != null) // bug! + buf.append ('$'); + if (next == null) + buf.append (",*"); + else if (next instanceof EmptyRecognizer) // patch-to-next + buf.append (",{}"); + else if (next instanceof ChildrenRecognizer) { + buf.append (','); + ((ChildrenRecognizer)next).toString (buf, table); + } else // bug! + buf.append (",+"); + return; + } + + // CHOICE + buf.append ("<"); + for (int i = 0; i < components.length; i++) { + if (i != 0) + buf.append ("|"); + if (components [i] instanceof EmptyRecognizer) { + buf.append ("{}"); + } else if (components [i] == null) { // patch-to-next + buf.append ('*'); + } else { + ChildrenRecognizer r; + + r = (ChildrenRecognizer) components [i]; + r.toString (buf, table); + } + } + buf.append (">"); + } +/**/ + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java b/libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java new file mode 100644 index 0000000..ef430165 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java @@ -0,0 +1,363 @@ +/* WellFormednessFilter.java -- + Copyright (C) 1999,2000,2001 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 gnu.xml.pipeline; + +import java.util.EmptyStackException; +import java.util.Stack; + +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * This filter reports fatal exceptions in the case of event streams that + * are not well formed. The rules currently tested include:
Other checks for event stream correctness may be provided in
+ * the future. For example, insisting that
+ * entity boundaries nest correctly,
+ * namespace scopes nest correctly,
+ * namespace values never contain relative URIs,
+ * attributes don't have "<" characters;
+ * and more.
+ *
+ * @author David Brownell
+ */
+public final class WellFormednessFilter extends EventFilter
+{
+ private boolean startedDoc;
+ private Stack elementStack = new Stack ();
+ private boolean startedCDATA;
+ private String dtdState = "before";
+
+
+ /**
+ * Swallows all events after performing well formedness checks.
+ */
+ // constructor used by PipelineFactory
+ public WellFormednessFilter ()
+ { this (null); }
+
+
+ /**
+ * Passes events through to the specified consumer, after first
+ * processing them.
+ */
+ // constructor used by PipelineFactory
+ public WellFormednessFilter (EventConsumer consumer)
+ {
+ super (consumer);
+
+ setContentHandler (this);
+ setDTDHandler (this);
+
+ try {
+ setProperty (LEXICAL_HANDLER, this);
+ } catch (SAXException e) { /* can't happen */ }
+ }
+
+ /**
+ * Resets state as if any preceding event stream was well formed.
+ * Particularly useful if it ended through some sort of error,
+ * and the endDocument call wasn't made.
+ */
+ public void reset ()
+ {
+ startedDoc = false;
+ startedCDATA = false;
+ elementStack.removeAllElements ();
+ }
+
+
+ private SAXParseException getException (String message)
+ {
+ SAXParseException e;
+ Locator locator = getDocumentLocator ();
+
+ if (locator == null)
+ return new SAXParseException (message, null, null, -1, -1);
+ else
+ return new SAXParseException (message, locator);
+ }
+
+ private void fatalError (String message)
+ throws SAXException
+ {
+ SAXParseException e = getException (message);
+ ErrorHandler handler = getErrorHandler ();
+
+ if (handler != null)
+ handler.fatalError (e);
+ throw e;
+ }
+
+ /**
+ * Throws an exception when called after startDocument.
+ *
+ * @param locator the locator, to be used in error reporting or relative
+ * URI resolution.
+ *
+ * @exception IllegalStateException when called after the document
+ * has already been started
+ */
+ public void setDocumentLocator (Locator locator)
+ {
+ if (startedDoc)
+ throw new IllegalStateException (
+ "setDocumentLocator called after startDocument");
+ super.setDocumentLocator (locator);
+ }
+
+ public void startDocument () throws SAXException
+ {
+ if (startedDoc)
+ fatalError ("startDocument called more than once");
+ startedDoc = true;
+ startedCDATA = false;
+ elementStack.removeAllElements ();
+ super.startDocument ();
+ }
+
+ public void startElement (
+ String uri, String localName,
+ String qName, Attributes atts
+ ) throws SAXException
+ {
+ if (!startedDoc)
+ fatalError ("callback outside of document?");
+ if ("inside".equals (dtdState))
+ fatalError ("element inside DTD?");
+ else
+ dtdState = "after";
+ if (startedCDATA)
+ fatalError ("element inside CDATA section");
+ if (qName == null || "".equals (qName))
+ fatalError ("startElement name missing");
+ elementStack.push (qName);
+ super.startElement (uri, localName, qName, atts);
+ }
+
+ public void endElement (String uri, String localName, String qName)
+ throws SAXException
+ {
+ if (!startedDoc)
+ fatalError ("callback outside of document?");
+ if (startedCDATA)
+ fatalError ("element inside CDATA section");
+ if (qName == null || "".equals (qName))
+ fatalError ("endElement name missing");
+
+ try {
+ String top = (String) elementStack.pop ();
+
+ if (!qName.equals (top))
+ fatalError ("<" + top + " ...>..." + qName + ">");
+ // XXX could record/test namespace info
+ } catch (EmptyStackException e) {
+ fatalError ("endElement without startElement: " + qName + ">");
+ }
+ super.endElement (uri, localName, qName);
+ }
+
+ public void endDocument () throws SAXException
+ {
+ if (!startedDoc)
+ fatalError ("callback outside of document?");
+ dtdState = "before";
+ startedDoc = false;
+ super.endDocument ();
+ }
+
+
+ public void startDTD (String root, String publicId, String systemId)
+ throws SAXException
+ {
+ if (!startedDoc)
+ fatalError ("callback outside of document?");
+ if ("before" != dtdState)
+ fatalError ("two DTDs?");
+ if (!elementStack.empty ())
+ fatalError ("DTD must precede root element");
+ dtdState = "inside";
+ super.startDTD (root, publicId, systemId);
+ }
+
+ public void notationDecl (String name, String publicId, String systemId)
+ throws SAXException
+ {
+// FIXME: not all parsers will report startDTD() ...
+// we'd rather insist we're "inside".
+ if ("after" == dtdState)
+ fatalError ("not inside DTD");
+ super.notationDecl (name, publicId, systemId);
+ }
+
+ public void unparsedEntityDecl (String name,
+ String publicId, String systemId, String notationName)
+ throws SAXException
+ {
+// FIXME: not all parsers will report startDTD() ...
+// we'd rather insist we're "inside".
+ if ("after" == dtdState)
+ fatalError ("not inside DTD");
+ super.unparsedEntityDecl (name, publicId, systemId, notationName);
+ }
+
+ // FIXME: add the four DeclHandler calls too
+
+ public void endDTD ()
+ throws SAXException
+ {
+ if (!startedDoc)
+ fatalError ("callback outside of document?");
+ if ("inside" != dtdState)
+ fatalError ("DTD ends without start?");
+ dtdState = "after";
+ super.endDTD ();
+ }
+
+ public void characters (char ch [], int start, int length)
+ throws SAXException
+ {
+ int here = start, end = start + length;
+ if (elementStack.empty ())
+ fatalError ("characters must be in an element");
+ while (here < end) {
+ if (ch [here++] != ']')
+ continue;
+ if (here == end) // potential problem ...
+ continue;
+ if (ch [here++] != ']')
+ continue;
+ if (here == end) // potential problem ...
+ continue;
+ if (ch [here++] == '>')
+ fatalError ("character data can't contain \"]]>\"");
+ }
+ super.characters (ch, start, length);
+ }
+
+ public void ignorableWhitespace (char ch [], int start, int length)
+ throws SAXException
+ {
+ int here = start, end = start + length;
+ if (elementStack.empty ())
+ fatalError ("characters must be in an element");
+ while (here < end) {
+ if (ch [here++] == '\r')
+ fatalError ("whitespace can't contain CR");
+ }
+ super.ignorableWhitespace (ch, start, length);
+ }
+
+ public void processingInstruction (String target, String data)
+ throws SAXException
+ {
+ if (data.indexOf ('\r') > 0)
+ fatalError ("PIs can't contain CR");
+ if (data.indexOf ("?>") > 0)
+ fatalError ("PIs can't contain \"?>\"");
+ }
+
+ public void comment (char ch [], int start, int length)
+ throws SAXException
+ {
+ if (!startedDoc)
+ fatalError ("callback outside of document?");
+ if (startedCDATA)
+ fatalError ("comments can't nest in CDATA");
+ int here = start, end = start + length;
+ while (here < end) {
+ if (ch [here] == '\r')
+ fatalError ("comments can't contain CR");
+ if (ch [here++] != '-')
+ continue;
+ if (here == end)
+ fatalError ("comments can't end with \"--->\"");
+ if (ch [here++] == '-')
+ fatalError ("comments can't contain \"--\"");
+ }
+ super.comment (ch, start, length);
+ }
+
+ public void startCDATA ()
+ throws SAXException
+ {
+ if (!startedDoc)
+ fatalError ("callback outside of document?");
+ if (startedCDATA)
+ fatalError ("CDATA starts can't nest");
+ startedCDATA = true;
+ super.startCDATA ();
+ }
+
+ public void endCDATA ()
+ throws SAXException
+ {
+ if (!startedDoc)
+ fatalError ("callback outside of document?");
+ if (!startedCDATA)
+ fatalError ("CDATA end without start?");
+ startedCDATA = false;
+ super.endCDATA ();
+ }
+}
diff --git a/libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java b/libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java
new file mode 100644
index 0000000..02607a4
--- /dev/null
+++ b/libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java
@@ -0,0 +1,579 @@
+/* XIncludeFilter.java --
+ Copyright (C) 2001,2002 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 gnu.xml.pipeline;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Hashtable;
+import java.util.Stack;
+import java.util.Vector;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+import gnu.xml.util.Resolver;
+
+
+
+/**
+ * Filter to process an XPointer-free subset of
+ * XInclude, supporting its
+ * use as a kind of replacement for parsed general entities.
+ * XInclude works much like the #include
of C/C++ but
+ * works for XML documents as well as unparsed text files.
+ * Restrictions from the 17-Sept-2002 CR draft of XInclude are as follows:
+ *
+ *
XML documents that are included will normally be processed using + * the default SAX namespace rules, meaning that prefix information may + * be discarded. This may be changed with {@link #setSavingPrefixes + * setSavingPrefixes()}. You are strongly advised to do this. + * + *
Note that XInclude allows highly incompatible implementations, which + * are specialized to handle application-specific infoset extensions. Some + * such implementations can be implemented by subclassing this one, but + * they may only be substituted in applications at "user option". + * + *
TBD: "IURI" handling.
+ *
+ * @author David Brownell
+ */
+public class XIncludeFilter extends EventFilter implements Locator
+{
+ private Hashtable extEntities = new Hashtable (5, 5);
+ private int ignoreCount;
+ private Stack uris = new Stack ();
+ private Locator locator;
+ private Vector inclusions = new Vector (5, 5);
+ private boolean savingPrefixes;
+
+ /**
+ */
+ public XIncludeFilter (EventConsumer next)
+ throws SAXException
+ {
+ super (next);
+ setContentHandler (this);
+ // DTDHandler callbacks pass straight through
+ setProperty (DECL_HANDLER, this);
+ setProperty (LEXICAL_HANDLER, this);
+ }
+
+ private void fatal (SAXParseException e) throws SAXException
+ {
+ ErrorHandler eh;
+
+ eh = getErrorHandler ();
+ if (eh != null)
+ eh.fatalError (e);
+ throw e;
+ }
+
+ /**
+ * Passes "this" down the filter chain as a proxy locator.
+ */
+ public void setDocumentLocator (Locator locator)
+ {
+ this.locator = locator;
+ super.setDocumentLocator (this);
+ }
+
+ /** Used for proxy locator; do not call directly. */
+ public String getSystemId ()
+ { return (locator == null) ? null : locator.getSystemId (); }
+ /** Used for proxy locator; do not call directly. */
+ public String getPublicId ()
+ { return (locator == null) ? null : locator.getPublicId (); }
+ /** Used for proxy locator; do not call directly. */
+ public int getLineNumber ()
+ { return (locator == null) ? -1 : locator.getLineNumber (); }
+ /** Used for proxy locator; do not call directly. */
+ public int getColumnNumber ()
+ { return (locator == null) ? -1 : locator.getColumnNumber (); }
+
+ /**
+ * Assigns the flag controlling the setting of the SAX2
+ * namespace-prefixes flag.
+ */
+ public void setSavingPrefixes (boolean flag)
+ { savingPrefixes = flag; }
+
+ /**
+ * Returns the flag controlling the setting of the SAX2
+ * namespace-prefixes flag when parsing included documents.
+ * The default value is the SAX2 default (false), which discards
+ * information that can be useful.
+ */
+ public boolean isSavingPrefixes ()
+ { return savingPrefixes; }
+
+ //
+ // Two mechanisms are interacting here.
+ //
+ // - XML Base implies a stack of base URIs, updated both by
+ // "real entity" boundaries and element boundaries.
+ //
+ // - Active "Real Entities" (for document and general entities,
+ // and by xincluded files) are tracked to prevent circular
+ // inclusions.
+ //
+ private String addMarker (String uri)
+ throws SAXException
+ {
+ if (locator != null && locator.getSystemId () != null)
+ uri = locator.getSystemId ();
+
+ // guard against InputSource objects without system IDs
+ if (uri == null)
+ fatal (new SAXParseException ("Entity URI is unknown", locator));
+
+ try {
+ URL url = new URL (uri);
+
+ uri = url.toString ();
+ if (inclusions.contains (uri))
+ fatal (new SAXParseException (
+ "XInclude, circular inclusion", locator));
+ inclusions.addElement (uri);
+ uris.push (url);
+ } catch (IOException e) {
+ // guard against illegal relative URIs (Xerces)
+ fatal (new SAXParseException ("parser bug: relative URI",
+ locator, e));
+ }
+ return uri;
+ }
+
+ private void pop (String uri)
+ {
+ inclusions.removeElement (uri);
+ uris.pop ();
+ }
+
+ //
+ // Document entity boundaries get both treatments.
+ //
+ public void startDocument () throws SAXException
+ {
+ ignoreCount = 0;
+ addMarker (null);
+ super.startDocument ();
+ }
+
+ public void endDocument () throws SAXException
+ {
+ inclusions.setSize (0);
+ extEntities.clear ();
+ uris.setSize (0);
+ super.endDocument ();
+ }
+
+ //
+ // External general entity boundaries get both treatments.
+ //
+ public void externalEntityDecl (String name,
+ String publicId, String systemId)
+ throws SAXException
+ {
+ if (name.charAt (0) == '%')
+ return;
+ try {
+ URL url = new URL (locator.getSystemId ());
+ systemId = new URL (url, systemId).toString ();
+ } catch (IOException e) {
+ // what could we do?
+ }
+ extEntities.put (name, systemId);
+ }
+
+ public void startEntity (String name)
+ throws SAXException
+ {
+ if (ignoreCount != 0) {
+ ignoreCount++;
+ return;
+ }
+
+ String uri = (String) extEntities.get (name);
+ if (uri != null)
+ addMarker (uri);
+ super.startEntity (name);
+ }
+
+ public void endEntity (String name)
+ throws SAXException
+ {
+ if (ignoreCount != 0) {
+ if (--ignoreCount != 0)
+ return;
+ }
+
+ String uri = (String) extEntities.get (name);
+
+ if (uri != null)
+ pop (uri);
+ super.endEntity (name);
+ }
+
+ //
+ // element boundaries only affect the base URI stack,
+ // unless they're XInclude elements.
+ //
+ public void
+ startElement (String uri, String localName, String qName, Attributes atts)
+ throws SAXException
+ {
+ if (ignoreCount != 0) {
+ ignoreCount++;
+ return;
+ }
+
+ URL baseURI = (URL) uris.peek ();
+ String base;
+
+ base = atts.getValue ("http://www.w3.org/XML/1998/namespace", "base");
+ if (base == null)
+ uris.push (baseURI);
+ else {
+ URL url;
+
+ if (base.indexOf ('#') != -1)
+ fatal (new SAXParseException (
+ "xml:base with fragment: " + base,
+ locator));
+
+ try {
+ baseURI = new URL (baseURI, base);
+ uris.push (baseURI);
+ } catch (Exception e) {
+ fatal (new SAXParseException (
+ "xml:base with illegal uri: " + base,
+ locator, e));
+ }
+ }
+
+ if (!"http://www.w3.org/2001/XInclude".equals (uri)) {
+ super.startElement (uri, localName, qName, atts);
+ return;
+ }
+
+ if ("include".equals (localName)) {
+ String href = atts.getValue ("href");
+ String parse = atts.getValue ("parse");
+ String encoding = atts.getValue ("encoding");
+ URL url = (URL) uris.peek ();
+ SAXParseException x = null;
+
+ if (href == null)
+ fatal (new SAXParseException (
+ "XInclude missing href",
+ locator));
+ if (href.indexOf ('#') != -1)
+ fatal (new SAXParseException (
+ "XInclude with fragment: " + href,
+ locator));
+
+ if (parse == null || "xml".equals (parse))
+ x = xinclude (url, href);
+ else if ("text".equals (parse))
+ x = readText (url, href, encoding);
+ else
+ fatal (new SAXParseException (
+ "unknown XInclude parsing mode: " + parse,
+ locator));
+ if (x == null) {
+ // strip out all child content
+ ignoreCount++;
+ return;
+ }
+
+ // FIXME the 17-Sept-2002 CR of XInclude says we "must"
+ // use xi:fallback elements to handle resource errors,
+ // if they exist.
+ fatal (x);
+
+ } else if ("fallback".equals (localName)) {
+ fatal (new SAXParseException (
+ "illegal top level XInclude 'fallback' element",
+ locator));
+ } else {
+ ErrorHandler eh = getErrorHandler ();
+
+ // CR doesn't say this is an error
+ if (eh != null)
+ eh.warning (new SAXParseException (
+ "unrecognized toplevel XInclude element: " + localName,
+ locator));
+ super.startElement (uri, localName, qName, atts);
+ }
+ }
+
+ public void endElement (String uri, String localName, String qName)
+ throws SAXException
+ {
+ if (ignoreCount != 0) {
+ if (--ignoreCount != 0)
+ return;
+ }
+
+ uris.pop ();
+ if (!("http://www.w3.org/2001/XInclude".equals (uri)
+ && "include".equals (localName)))
+ super.endElement (uri, localName, qName);
+ }
+
+ //
+ // ignore all content within non-empty xi:include elements
+ //
+ public void characters (char ch [], int start, int length)
+ throws SAXException
+ {
+ if (ignoreCount == 0)
+ super.characters (ch, start, length);
+ }
+
+ public void processingInstruction (String target, String value)
+ throws SAXException
+ {
+ if (ignoreCount == 0)
+ super.processingInstruction (target, value);
+ }
+
+ public void ignorableWhitespace (char ch [], int start, int length)
+ throws SAXException
+ {
+ if (ignoreCount == 0)
+ super.ignorableWhitespace (ch, start, length);
+ }
+
+ public void comment (char ch [], int start, int length)
+ throws SAXException
+ {
+ if (ignoreCount == 0)
+ super.comment (ch, start, length);
+ }
+
+ public void startCDATA () throws SAXException
+ {
+ if (ignoreCount == 0)
+ super.startCDATA ();
+ }
+
+ public void endCDATA () throws SAXException
+ {
+ if (ignoreCount == 0)
+ super.endCDATA ();
+ }
+
+ public void startPrefixMapping (String prefix, String uri)
+ throws SAXException
+ {
+ if (ignoreCount == 0)
+ super.startPrefixMapping (prefix, uri);
+ }
+
+ public void endPrefixMapping (String prefix) throws SAXException
+ {
+ if (ignoreCount == 0)
+ super.endPrefixMapping (prefix);
+ }
+
+ public void skippedEntity (String name) throws SAXException
+ {
+ if (ignoreCount == 0)
+ super.skippedEntity (name);
+ }
+
+ // JDK 1.1 seems to need it to be done this way, sigh
+ void setLocator (Locator l) { locator = l; }
+ Locator getLocator () { return locator; }
+
+
+ //
+ // for XIncluded entities, manage the current locator and
+ // filter out events that would be incorrect to report
+ //
+ private class Scrubber extends EventFilter
+ {
+ Scrubber (EventFilter f)
+ throws SAXException
+ {
+ // delegation passes to next in chain
+ super (f);
+
+ // process all content events
+ super.setContentHandler (this);
+ super.setProperty (LEXICAL_HANDLER, this);
+
+ // drop all DTD events
+ super.setDTDHandler (null);
+ super.setProperty (DECL_HANDLER, null);
+ }
+
+ // maintain proxy locator
+ // only one startDocument()/endDocument() pair per event stream
+ public void setDocumentLocator (Locator l)
+ { setLocator (l); }
+ public void startDocument ()
+ { }
+ public void endDocument ()
+ { }
+
+ private void reject (String message) throws SAXException
+ { fatal (new SAXParseException (message, getLocator ())); }
+
+ // only the DTD from the "base document" gets reported
+ public void startDTD (String root, String publicId, String systemId)
+ throws SAXException
+ { reject ("XIncluded DTD: " + systemId); }
+ public void endDTD ()
+ throws SAXException
+ { reject ("XIncluded DTD"); }
+ // ... so this should never happen
+ public void skippedEntity (String name) throws SAXException
+ { reject ("XInclude skipped entity: " + name); }
+
+ // since we rejected DTDs, only builtin entities can be reported
+ }
+
+ // This package exposes a kind of XML processing pipeline, based on sending
+SAX events, which can be used as components of application architectures.
+Pipelines are used to convey streams of processing events from a producer
+to one or more consumers, and to let each consumer control the data seen by
+later consumers.
+
+ There is a PipelineFactory class which
+accepts a syntax describing how to construct some simple pipelines. Strings
+describing such pipelines can be used in command line tools (see the
+DoParse class)
+and in other places that it is
+useful to let processing be easily reconfigured. Pipelines can of course
+be constructed programmatically, providing access to options that the
+factory won't.
+
+ Web applications are supported by making it easy for servlets (or
+non-Java web application components) to be part of a pipeline. They can
+originate XML (or XHTML) data through an InputSource or in
+response to XML messages sent from clients using CallFilter
+pipeline stages. Such facilities are available using the simple syntax
+for pipeline construction.
+
+
+ Pipelines should be simple to understand.
+
+ Many producers will be SAX2 XMLReader objects, and
+will read (pull) data which is then written (pushed) as events.
+Typically these will parse XML text (acquired from
+ In other cases, you will write producers yourself. For example, some
+data structures might know how to write themselves out using one or
+more XML models, expressed as sequences of SAX2 event callbacks.
+An application module might
+itself be a producer, issuing startDocument and endDocument events
+and then asking those data structures to write themselves out to a
+given EventConsumer, or walking data structures (such as JDBC query
+results) and applying its own conversion rules. WAP format XML
+(WBMXL) can be directly converted to producer output.
+
+ SAX2 introduced an "XMLFilter" interface, which is a kind of XMLReader.
+It is most useful in conjunction with its XMLFilterImpl helper class;
+see the EventFilter javadoc
+for information contrasting that XMLFilterImpl approach with the
+relevant parts of this pipeline framework. Briefly, such XMLFilterImpl
+children can be either producers or consumers, and are more limited in
+configuration flexibility. In this framework, the focus of filters is
+on the EventConsumer side; see the section on
+pipe fitting below.
+
+
+ Many consumers will be used to create standard representations of XML
+data. The TextConsumer takes its events
+and writes them as text for a single XML document,
+using an internal XMLWriter.
+The DomConsumer takes its events and uses
+them to create and populate a DOM Document.
+
+ In other cases, you will write consumers yourself. For example,
+you might use a particular unmarshaling filter to produce objects
+that fit your application's requirements, instead of using DOM.
+Such consumers work at the level of XML data models, rather than with
+specific representations such as XML text or a DOM tree. You could
+convert your output directly to WAP format data (WBXML).
+
+
+ Pipelines are composite event consumers, with each stage having
+the opportunity to transform the data before delivering it to any
+subsequent stages.
+
+ The PipelineFactory class
+provides access to much of this functionality through a simple syntax.
+See the table in that class's javadoc describing a number of standard
+components. Direct API calls are still needed for many of the most
+interesting pipeline configurations, including ones leveraging actual
+or logical concurrency.
+
+ Four basic types of pipe fitting are directly supported. These may
+be used to construct complex pipeline networks. Note that filters can be as complex as
+XSLT transforms
+available) on input data, or as simple as removing simple syntax data
+such as ignorable whitespace, comments, and CDATA delimiters.
+Some simple "built-in" filters are part of this package.
+
+
+ If you follow these coding conventions, your classes may be used
+directly (give the full class name) in pipeline descriptions as understood
+by the PipelineFactory. There are four constructors the factory may
+try to use; in order of decreasing numbers of parameters, these are: Of course, classes may support more than one such usage convention;
+if they do, they can automatically be used in multiple modes. If you
+try to use a terminus class as a filter, and that terminus has a constructor
+with the appropriate number of arguments, it is automatically wrapped in
+a "tee" filter.
+
+
+ It can sometimes be hard to see what's happening, when something
+goes wrong. Easily fixed: just snapshot the data. Then you can find
+out where things start to go wrong.
+
+ If you're using pipeline descriptors so that they're easily
+administered, just stick a write ( filename )
+filter into the pipeline at an appropriate point.
+
+ Inside your programs, you can do the same thing directly: perhaps
+by saving a Writer (perhaps a StringWriter) in a variable, using that
+to create a TextConsumer, and making that the first part of a tee --
+splicing that into your pipeline at a convenient location.
+
+ You can also use a DomConsumer to buffer the data, but remember
+that DOM doesn't save all the information that XML provides, so that DOM
+snapshots are relatively low fidelity. They also are substantially more
+expensive in terms of memory than a StringWriter holding similar data.
+
+ Producers in pipelines don't need to start from XML
+data structures, such as text in XML syntax (likely coming
+from some XMLReader that parses XML) or a
+DOM representation (perhaps with a
+DomParser).
+
+ One common type of event producer will instead make
+direct calls to SAX event handlers returned from an
+EventConsumer.
+For example, making ContentHandler.startElement
+calls and matching ContentHandler.endElement calls.
+
+ Applications making such calls can catch certain
+common "syntax errors" by using a
+WellFormednessFilter.
+That filter will detect (and report) erroneous input data
+such as mismatched document, element, or CDATA start/end calls.
+Use such a filter near the head of the pipeline that your
+producer feeds, at least while debugging, to help ensure that
+you're providing legal XML Infoset data.
+
+ You can also arrange to validate data on the fly.
+For DTD validation, you can configure a
+ValidationConsumer
+to work as a filter, using any DTD you choose.
+Other validation schemes can be handled with other
+validation filters.
+
+
diff --git a/libjava/classpath/gnu/xml/transform/AbstractNumberNode.java b/libjava/classpath/gnu/xml/transform/AbstractNumberNode.java
new file mode 100644
index 0000000..91029d6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/AbstractNumberNode.java
@@ -0,0 +1,328 @@
+/* AbstractNumberNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing the XSL The SAX2 XMLReaderFactory should return a SAX2 XML parser which
+ * supports both of the standardized extension handlers (for declaration
+ * and lexical events). That parser will be used to produce events.
+ *
+ * The first parameter to the command gives the name of the document that
+ * will be given to that processor. If it is a file name, it is converted
+ * to a URL first.
+ *
+ * The second parameter describes a simple processing pipeline, and will
+ * be used as input to {@link gnu.xml.pipeline.PipelineFactory}
+ * methods which identify the processing to be done. Examples of such a
+ * pipeline include Relatively complex pipelines can be described on the command line, but
+ * not all interesting ones will require as little configuration as can be done
+ * in that way. Put filters like "nsfix", perhaps followed by "validate",
+ * at the front of the pipeline so they can be optimized out if a parser
+ * supports those modes natively.
+ *
+ * If the parsing is aborted for any reason, the JVM will exit with a
+ * failure code. If a validating parse was done then both validation and
+ * well formedness errors will cause a failure. A non-validating parse
+ * will report failure on well formedness errors.
+ *
+ * @see gnu.xml.pipeline.PipelineFactory
+ *
+ * @author David Brownell
+ */
+final public class DoParse
+{
+ private DoParse () { /* no instances allowed */ }
+
+ // first reported nonrecoverable error
+ private static SAXParseException fatal;
+
+ // error categories
+ private static int errorCount;
+ private static int fatalCount;
+
+ /**
+ * Command line invoker for this class; pass a filename or URL
+ * as the first argument, and a pipeline description as the second.
+ * Make sure to use filters to condition the input to stages that
+ * require it; an nsfix filter will be a common requirement,
+ * to restore syntax that SAX2 parsers delete by default. Some
+ * conditioning filters may be eliminated by setting parser options.
+ * (For example, "nsfix" can set the "namespace-prefixes" feature to
+ * a non-default value of "true". In the same way, "validate" can set
+ * the "validation" feature to "true".)
+ */
+ public static void main (String argv [])
+ throws IOException
+ {
+ int exitStatus = 1;
+
+ if (argv.length != 2) {
+ System.err.println ("Usage: DoParse [filename|URL] pipeline-spec");
+ System.err.println ("Example pipeline specs:");
+ System.err.println (" 'nsfix | validate'");
+ System.err.println (
+ " ... restore namespace syntax, validate");
+ System.err.println (" 'nsfix | write ( stdout )'");
+ System.err.println (
+ " ... restore namespace syntax, write to stdout as XML"
+ );
+ System.exit (1);
+ }
+
+ try {
+ //
+ // Get input source for specified document (or try ;-)
+ //
+ argv [0] = Resolver.getURL (argv [0]);
+ InputSource input = new InputSource (argv [0]);
+
+ //
+ // Get the producer, using the system default parser (which
+ // can be overridden for this particular invocation).
+ //
+ // And the pipeline, using commandline options.
+ //
+ XMLReader producer;
+ EventConsumer consumer;
+
+ producer = XMLReaderFactory.createXMLReader ();
+
+ //
+ // XXX pipeline factory now has a pre-tokenized input
+ // method, use it ... that way at least some params
+ // can be written using quotes (have spaces, ...)
+ //
+ consumer = PipelineFactory.createPipeline (argv [1]);
+
+ //
+ // XXX want commandline option for tweaking error handler.
+ // Want to be able to present warnings.
+ //
+ producer.setErrorHandler (new MyErrorHandler ());
+
+ // XXX need facility enabling resolving to local DTDs
+
+ //
+ // Parse. The pipeline may get optimized a bit, so we
+ // can't always fail cleanly for validation without taking
+ // a look at the filter stages.
+ //
+ EventFilter.bind (producer, consumer);
+ producer.parse (input);
+
+ try {
+ if (producer.getFeature (
+ "http://org.xml/sax/features/validation"))
+ exitStatus = ((errorCount + fatalCount) > 0) ? 1 : 0;
+ else if (fatalCount == 0)
+ exitStatus = 0;
+ } catch (SAXException e) {
+ if (hasValidator (consumer))
+ exitStatus = ((errorCount + fatalCount) > 0) ? 1 : 0;
+ else if (fatalCount == 0)
+ exitStatus = 0;
+ }
+
+ } catch (java.net.MalformedURLException e) {
+ System.err.println ("** Malformed URL: " + e.getMessage ());
+ System.err.println ("Is '" + argv [0] + "' a non-existent file?");
+ e.printStackTrace ();
+ // e.g. FNF
+
+ } catch (SAXParseException e) {
+ if (e != fatal) {
+ System.err.print (printParseException ("Parsing Aborted", e));
+ e.printStackTrace ();
+ if (e.getException () != null) {
+ System.err.println ("++ Wrapped exception:");
+ e.getException ().printStackTrace ();
+ }
+ }
+
+ } catch (SAXException e) {
+ Exception x = e;
+ if (e.getException () != null)
+ x = e.getException ();
+ x.printStackTrace ();
+
+ } catch (Throwable t) {
+ t.printStackTrace ();
+ }
+
+ System.exit (exitStatus);
+ }
+
+ // returns true if saw a validator (before end or unrecognized node)
+ // false otherwise
+ private static boolean hasValidator (EventConsumer e)
+ {
+ if (e == null)
+ return false;
+ if (e instanceof ValidationConsumer)
+ return true;
+ if (e instanceof TeeConsumer) {
+ TeeConsumer t = (TeeConsumer) e;
+ return hasValidator (t.getFirst ())
+ || hasValidator (t.getRest ());
+ }
+ if (e instanceof WellFormednessFilter
+ || e instanceof NSFilter
+ )
+ return hasValidator (((EventFilter)e).getNext ());
+
+ // else ... gee, we can't know. Assume not.
+
+ return false;
+ }
+
+ static class MyErrorHandler implements ErrorHandler
+ {
+ // dump validation errors, but continue
+ public void error (SAXParseException e)
+ throws SAXParseException
+ {
+ errorCount++;
+ System.err.print (printParseException ("Error", e));
+ }
+
+ public void warning (SAXParseException e)
+ throws SAXParseException
+ {
+ // System.err.print (printParseException ("Warning", e));
+ }
+
+ // try to continue fatal errors, in case a parser reports more
+ public void fatalError (SAXParseException e)
+ throws SAXParseException
+ {
+ fatalCount++;
+ if (fatal == null)
+ fatal = e;
+ System.err.print (printParseException ("Nonrecoverable Error", e));
+ }
+ }
+
+ static private String printParseException (
+ String label,
+ SAXParseException e
+ ) {
+ StringBuffer buf = new StringBuffer ();
+ int temp;
+
+ buf.append ("** ");
+ buf.append (label);
+ buf.append (": ");
+ buf.append (e.getMessage ());
+ buf.append ('\n');
+ if (e.getSystemId () != null) {
+ buf.append (" URI: ");
+ buf.append (e.getSystemId ());
+ buf.append ('\n');
+ }
+ if ((temp = e.getLineNumber ()) != -1) {
+ buf.append (" line: ");
+ buf.append (temp);
+ buf.append ('\n');
+ }
+ if ((temp = e.getColumnNumber ()) != -1) {
+ buf.append (" char: ");
+ buf.append (temp);
+ buf.append ('\n');
+ }
+
+ return buf.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/xml/util/DomParser.java b/libjava/classpath/gnu/xml/util/DomParser.java
new file mode 100644
index 0000000..b28b610
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/DomParser.java
@@ -0,0 +1,804 @@
+/* DomParser.java --
+ Copyright (C) 1999,2000,2001 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 gnu.xml.util;
+
+import java.util.Enumeration;
+import java.util.Locale;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.NamespaceSupport;
+import org.xml.sax.ext.DeclHandler;
+import org.xml.sax.ext.DefaultHandler2;
+import org.xml.sax.ext.LexicalHandler;
+
+import org.w3c.dom.*;
+
+
+/**
+ * This parser emits SAX2 parsing events as it traverses a DOM tree, using
+ * any conformant implementation of DOM. It exposes all SAX1 features,
+ * and the following SAX2 features and properties (as
+ * identified by standard URIs which are not fully provided here). Note
+ * that if a Level 1 DOM implementation is given, then this behaves as if
+ * namespaces were disabled, and namespace prefixes were enabled. The consequences of modifying a DOM document tree as it is being walked
+ * by this "parser" are unspecified; don't do it! This implementation is preliminary.
+ *
+ * @see gnu.xml.pipeline.XsltFilter
+ *
+ * @author David Brownell
+ */
+public class SAXNullTransformerFactory extends SAXTransformerFactory
+{
+
+ private ErrorListener errListener;
+ private URIResolver uriResolver;
+
+ /** Default constructor */
+ public SAXNullTransformerFactory () { }
+
+ //
+ // only has stuff that makes sense with null transforms
+ //
+
+ /**
+ * Returns true if the requested feature is supported.
+ * All three kinds of input and output are accepted:
+ * XML text, SAX events, and DOM nodes.
+ */
+ public boolean getFeature (String feature)
+ {
+ return SAXTransformerFactory.FEATURE.equals (feature)
+ || SAXResult.FEATURE.equals (feature)
+ || SAXSource.FEATURE.equals (feature)
+ || DOMResult.FEATURE.equals (feature)
+ || DOMSource.FEATURE.equals (feature)
+ || StreamResult.FEATURE.equals (feature)
+ || StreamSource.FEATURE.equals (feature)
+ ;
+ }
+
+ public void setFeature(String name, boolean value)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException(name);
+ }
+
+
+ /** Throws an exception (no implementation attributes are supported) */
+ public void setAttribute (String key, Object value)
+ {
+ throw new IllegalArgumentException ();
+ }
+
+ /** Throws an exception (no implementation attributes are supported) */
+ public Object getAttribute (String key)
+ {
+ throw new IllegalArgumentException ();
+ }
+
+ /** (not yet implemented) */
+ public Source getAssociatedStylesheet (Source source,
+ String media,
+ String title,
+ String charset)
+ throws TransformerConfigurationException
+ {
+ // parse, and find the appropriate xsl-stylesheet PI contents
+ throw new IllegalArgumentException ();
+ }
+
+ public Transformer newTransformer ()
+ throws TransformerConfigurationException
+ {
+ return new NullTransformer ();
+ }
+
+ /**
+ * Returns a TransformerHandler that knows how to generate output
+ * in all three standard formats. Output text is generated using
+ * {@link XMLWriter}, and the GNU implementation of
+ * {@link DomDocument DOM} is used.
+ *
+ * @see SAXResult
+ * @see StreamResult
+ * @see DOMResult
+ */
+ public TransformerHandler newTransformerHandler ()
+ throws TransformerConfigurationException
+ {
+ NullTransformer transformer = new NullTransformer ();
+ return transformer.handler;
+ }
+
+ //
+ // Stuff that depends on XSLT support, which we don't provide
+ //
+ private static final String noXSLT = "No XSLT support";
+
+ /** Throws an exception (XSLT is not supported). */
+ public Transformer newTransformer (Source stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public Templates newTemplates (Source stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public TemplatesHandler newTemplatesHandler ()
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public TransformerHandler newTransformerHandler (Source stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public TransformerHandler newTransformerHandler (Templates stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public XMLFilter newXMLFilter (Source stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public XMLFilter newXMLFilter (Templates stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Returns the value assigned by {@link #setErrorListener}. */
+ public ErrorListener getErrorListener ()
+ {
+ return errListener;
+ }
+
+ /** Assigns a value that would be used when parsing stylesheets */
+ public void setErrorListener (ErrorListener e)
+ {
+ errListener = e;
+ }
+
+ /** Returns the value assigned by {@link #setURIResolver}. */
+ public URIResolver getURIResolver ()
+ {
+ return uriResolver;
+ }
+
+ /** Assigns a value that would be used when parsing stylesheets */
+ public void setURIResolver (URIResolver u)
+ {
+ uriResolver = u;
+ }
+
+
+ //
+ // Helper classes. These might in theory be subclassed
+ // by an XSLT implementation, if they were exported.
+ //
+
+ static class DomTerminus
+ extends DomConsumer
+ {
+
+ DomTerminus (DOMResult result)
+ throws SAXException
+ {
+ // won't really throw SAXException
+ super (DomDocument.class);
+ setHandler (new DomHandler (this, result));
+ }
+
+ }
+
+ static class DomHandler
+ extends Consumer.Backdoor
+ {
+
+ private DOMResult result;
+
+ DomHandler (DomConsumer c, DOMResult r)
+ throws SAXException
+ {
+ // won't really throw SAXException
+ super (c);
+ result = r;
+ }
+
+ public void endDocument ()
+ throws SAXException
+ {
+ super.endDocument ();
+ result.setNode (getDocument ());
+ }
+
+ }
+
+ private static OutputStream getOutputStream (String uri)
+ throws IOException
+ {
+ // JDK stupidity: file "protocol does not support output" ...
+ if (uri.startsWith ("file:"))
+ return new FileOutputStream (uri.substring (5));
+
+ // Otherwise ...
+ URL url = new URL (uri);
+ URLConnection conn = url.openConnection ();
+
+ conn.setDoOutput (true);
+ return conn.getOutputStream ();
+ }
+
+
+ static class NullHandler
+ extends EventFilter
+ implements TransformerHandler
+ {
+
+ private String systemId;
+ private Transformer transformer;
+
+ NullHandler (Transformer t)
+ {
+ transformer = t;
+ }
+
+ public Transformer getTransformer ()
+ {
+ return transformer;
+ }
+
+ public String getSystemId ()
+ {
+ return systemId;
+ }
+
+ public void setSystemId (String id)
+ {
+ systemId = id;
+ }
+
+ public void setResult (Result result)
+ {
+ if (result.getSystemId () != null)
+ systemId = result.getSystemId ();
+
+ try
+ {
+
+ // output to partial SAX event stream?
+ if (result instanceof SAXResult)
+ {
+ SAXResult r = (SAXResult) result;
+
+ setContentHandler (r.getHandler ());
+ setProperty (LEXICAL_HANDLER, r.getLexicalHandler ());
+ // DTD info is filtered out by javax.transform
+
+ // output to DOM tree?
+ }
+ else if (result instanceof DOMResult)
+ {
+ DomTerminus out = new DomTerminus ((DOMResult) result);
+
+ setContentHandler (out.getContentHandler ());
+ setProperty (LEXICAL_HANDLER,
+ out.getProperty (LEXICAL_HANDLER));
+ // save DTD-derived info, if any.
+ setDTDHandler (out.getDTDHandler ());
+ setProperty (DECL_HANDLER,
+ out.getProperty (DECL_HANDLER));
+
+ // node is saved into result on endDocument()
+
+ // output to (XML) text?
+ }
+ else if (result instanceof StreamResult)
+ {
+ StreamResult r = (StreamResult) result;
+ XMLWriter out;
+
+ // FIXME: when do output properties take effect?
+ // encoding, standalone decl, xml/xhtml/... ...
+
+ // FIXME: maybe put nsfix filter up front
+
+ try
+ {
+ if (r.getWriter () != null)
+ out = new XMLWriter (r.getWriter ());
+ else if (r.getOutputStream () != null)
+ out = new XMLWriter (r.getOutputStream ());
+ else if (r.getSystemId () != null)
+ out = new XMLWriter (
+ getOutputStream (r.getSystemId ()));
+ else
+ throw new IllegalArgumentException (
+ "bad StreamResult");
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace ();
+ // on jdk 1.4, pass the root cause ...
+ throw new IllegalArgumentException (e.getMessage ());
+ }
+
+ // out.setExpandingEntities (true);
+ // out.setPrettyPrinting (true);
+ // out.setXhtml (true);
+
+ setContentHandler (out);
+ setProperty (LEXICAL_HANDLER, out);
+ // save DTD info, if any; why not?
+ setDTDHandler (out);
+ setProperty (DECL_HANDLER, out);
+ }
+
+ }
+ catch (SAXException e)
+ {
+ // SAXNotSupportedException or SAXNotRecognizedException:
+ // "can't happen" ... but SAXException for DOM build probs
+ // could happen, so ...
+ // on jdk 1.4, pass the root cause ...
+ throw new IllegalArgumentException (e.getMessage ());
+ }
+ }
+ }
+
+ // an interface that adds no value
+ static class LocatorAdapter
+ extends LocatorImpl
+ implements SourceLocator
+ {
+
+ LocatorAdapter (SAXParseException e)
+ {
+ setSystemId (e.getSystemId ());
+ setPublicId (e.getPublicId ());
+ setLineNumber (e.getLineNumber ());
+ setColumnNumber (e.getColumnNumber ());
+ }
+
+ }
+
+ // another interface that adds no value
+ static class ListenerAdapter
+ implements ErrorHandler
+ {
+
+ NullTransformer transformer;
+
+ ListenerAdapter (NullTransformer t)
+ {
+ transformer = t;
+ }
+
+ private TransformerException map (SAXParseException e)
+ {
+ return new TransformerException (
+ e.getMessage (),
+ new LocatorAdapter (e),
+ e);
+ }
+
+ public void error (SAXParseException e)
+ throws SAXParseException
+ {
+ try
+ {
+ if (transformer.errListener != null)
+ transformer.errListener.error (map (e));
+ }
+ catch (TransformerException ex)
+ {
+ transformer.ex = ex;
+ throw e;
+ }
+ }
+
+ public void fatalError (SAXParseException e)
+ throws SAXParseException
+ {
+ try
+ {
+ if (transformer.errListener != null)
+ transformer.errListener.fatalError (map (e));
+ else
+ throw map (e);
+ } catch (TransformerException ex) {
+ transformer.ex = ex;
+ throw e;
+ }
+ }
+
+ public void warning (SAXParseException e)
+ throws SAXParseException
+ {
+ try
+ {
+ if (transformer.errListener != null)
+ transformer.errListener.warning (map (e));
+ }
+ catch (TransformerException ex)
+ {
+ transformer.ex = ex;
+ throw e;
+ }
+ }
+ }
+
+ static class NullTransformer
+ extends Transformer
+ {
+
+ private URIResolver uriResolver;
+ private Properties props = new Properties ();
+ private Hashtable params = new Hashtable (7);
+
+ ErrorListener errListener = null;
+ TransformerException ex = null;
+ NullHandler handler;
+
+ NullTransformer ()
+ {
+ super ();
+ handler = new NullHandler (this);
+ }
+
+ public ErrorListener getErrorListener ()
+ {
+ return errListener;
+ }
+
+ public void setErrorListener (ErrorListener e)
+ {
+ errListener = e;
+ }
+
+ public URIResolver getURIResolver ()
+ {
+ return uriResolver;
+ }
+
+ public void setURIResolver (URIResolver u)
+ {
+ uriResolver = u;
+ }
+
+ public void setOutputProperties (Properties p)
+ {
+ props = (Properties) p.clone ();
+ }
+
+ public Properties getOutputProperties ()
+ {
+ return (Properties) props.clone ();
+ }
+
+ public void setOutputProperty (String name, String value)
+ {
+ props.setProperty (name, value);
+ }
+
+ public String getOutputProperty (String name)
+ {
+ return props.getProperty (name);
+ }
+
+ public void clearParameters ()
+ {
+ params.clear ();
+ }
+
+ public void setParameter (String name, Object value)
+ {
+ props.put (name, value);
+ }
+
+ public Object getParameter (String name)
+ {
+ return props.get (name);
+ }
+
+ public void transform (Source in, Result out)
+ throws TransformerException
+ {
+ try
+ {
+ XMLReader producer;
+ InputSource input;
+
+ // Input from DOM?
+ if (in instanceof DOMSource)
+ {
+ DOMSource source = (DOMSource) in;
+
+ if (source.getNode () == null)
+ throw new IllegalArgumentException ("no DOM node");
+ producer = new DomParser (source.getNode ());
+ input = null;
+
+ // Input from SAX?
+ }
+ else if (in instanceof SAXSource)
+ {
+ SAXSource source = (SAXSource) in;
+
+ producer = source.getXMLReader ();
+ if (producer == null)
+ producer = XMLReaderFactory.createXMLReader ();
+
+ input = source.getInputSource ();
+ if (input == null)
+ {
+ if (source.getSystemId () != null)
+ input = new InputSource (source.getSystemId ());
+ else
+ throw new IllegalArgumentException (
+ "missing SAX input");
+ }
+
+ // Input from a stream or something?
+ }
+ else
+ {
+ producer = XMLReaderFactory.createXMLReader ();
+ input = SAXSource.sourceToInputSource (in);
+ if (input == null)
+ throw new IllegalArgumentException ("missing input");
+ }
+
+ // preserve original namespace prefixes
+ try
+ {
+ producer.setFeature(EventFilter.FEATURE_URI +
+ "namespace-prefixes",
+ true);
+ }
+ catch (Exception e)
+ {
+ /* ignore */
+ // FIXME if we couldn't, "NsFix" stage before the output ..
+ }
+
+ // arrange the output
+ handler.setResult (out);
+ EventFilter.bind (producer, handler);
+
+ // then parse ... single element pipeline
+ producer.parse (input);
+
+ }
+ catch (IOException e)
+ {
+ throw new TransformerException ("transform failed", e);
+
+ }
+ catch (SAXException e)
+ {
+ if (ex == null && ex.getCause () == e)
+ throw ex;
+ else
+ throw new TransformerException ("transform failed", e);
+
+ }
+ finally
+ {
+ ex = null;
+ }
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/util/XCat.java b/libjava/classpath/gnu/xml/util/XCat.java
new file mode 100644
index 0000000..0f16338
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/XCat.java
@@ -0,0 +1,1609 @@
+/* XCat.java --
+ Copyright (C) 2001 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 gnu.xml.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import java.util.Stack;
+import java.util.Vector;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+
+import org.xml.sax.ext.DefaultHandler2;
+import org.xml.sax.ext.EntityResolver2;
+
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * Packages OASIS XML Catalogs,
+ * primarily for entity resolution by parsers.
+ * That specification defines an XML syntax for mappings between
+ * identifiers declared in DTDs (particularly PUBLIC identifiers) and
+ * locations. SAX has always supported such mappings, but conventions for
+ * an XML file syntax to maintain them have previously been lacking.
+ *
+ * This has three main operational modes. The primary intended mode is
+ * to create a resolver, then preloading it with one or more site-standard
+ * catalogs before using it with one or more SAX parsers: A second mode is to arrange that your application uses instances of
+ * this class as its entity resolver, and automatically loads catalogs
+ * referenced by <?oasis-xml-catalog...?> processing
+ * instructions found before the DTD in documents it parses.
+ * It would then discard the resolver after each parse.
+ *
+ * A third mode applies catalogs in contexts other than entity
+ * resolution for parsers.
+ * The {@link #resolveURI resolveURI()} method supports resolving URIs
+ * stored in XML application data, rather than inside DTDs.
+ * Catalogs would be loaded as shown above, and the catalog could
+ * be used concurrently for parser entity resolution and for
+ * application URI resolution.
+ * Errors in catalogs implicitly loaded (during resolution) are ignored
+ * beyond being reported through any ErrorHandler assigned using
+ * {@link #setErrorHandler setErrorHandler()}. SAX exceptions
+ * thrown from such a handler won't abort resolution, although throwing a
+ * RuntimeException or Error will normally abort both
+ * resolution and parsing. Useful diagnostic information is available to
+ * any ErrorHandler used to report problems, or from any exception
+ * thrown from an explicit {@link #loadCatalog loadCatalog()} invocation.
+ * Applications can use that information as troubleshooting aids.
+ *
+ * While this class requires SAX2 Extensions 1.1 classes in
+ * its class path, basic functionality does not require using a SAX2
+ * parser that supports the extended entity resolution functionality.
+ * See the original SAX1
+ * {@link #resolveEntity(java.lang.String,java.lang.String) resolveEntity()}
+ * method for a list of restrictions which apply when it is used with
+ * older SAX parsers.
+ *
+ * @see EntityResolver2
+ *
+ * @author David Brownell
+ */
+public class XCat implements EntityResolver2
+{
+ private Catalog catalogs [];
+ private boolean usingPublic = true;
+ private boolean loadingPermitted = true;
+ private boolean unified = true;
+ private String parserClass;
+ private ErrorHandler errorHandler;
+
+ // private EntityResolver next; // chain to next if we fail...
+
+ //
+ // NOTE: This is a straightforward implementation, and if
+ // there are lots of "nextCatalog" or "delegate*" entries
+ // in use, two tweaks would be worth considering:
+ //
+ // - Centralize some sort of cache (key by URI) for individual
+ // resolvers. That'd avoid multiple copies of a given catalog.
+ //
+ // - Have resolution track what catalogs (+modes) have been
+ // searched. This would support loop detection.
+ //
+
+
+ /**
+ * Initializes without preloading a catalog.
+ * This API is convenient when you may want to arrange that catalogs
+ * are automatically loaded when explicitly referenced in documents,
+ * using the oasis-xml-catalog processing instruction.
+ * In such cases you won't usually be able to preload catalogs.
+ */
+ public XCat () { }
+
+ /**
+ * Initializes, and preloads a catalog using the default SAX parser.
+ * This API is convenient when you operate with one or more standard
+ * catalogs.
+ *
+ * This just delegates to {@link #loadCatalog loadCatalog()};
+ * see it for exception information.
+ *
+ * @param uri absolute URI for the catalog file.
+ */
+ public XCat (String uri)
+ throws SAXException, IOException
+ { loadCatalog (uri); }
+
+
+ /**
+ * Loads an OASIS XML Catalog.
+ * It is appended to the list of currently active catalogs, or
+ * reloaded if a catalog with the same URI was already loaded.
+ * Callers have control over what parser is used, how catalog parsing
+ * errors are reported, and whether URIs will be resolved consistently.
+ *
+ * The OASIS specification says that errors detected when loading
+ * catalogs "must recover by ignoring the catalog entry file that
+ * failed, and proceeding." In this API, that action can be the
+ * responsibility of applications, when they explicitly load any
+ * catalog using this method.
+ *
+ * Note that catalogs referenced by this one will not be loaded
+ * at this time. Catalogs referenced through nextCatalog
+ * or delegate* elements are normally loaded only if needed.
+ *
+ * @see #setErrorHandler
+ * @see #setParserClass
+ * @see #setUnified
+ *
+ * @param uri absolute URI for the catalog file.
+ *
+ * @exception IOException As thrown by the parser, typically to
+ * indicate problems reading data from that URI.
+ * @exception SAXException As thrown by the parser, typically to
+ * indicate problems parsing data from that URI. It may also
+ * be thrown if the parser doesn't support necessary handlers.
+ * @exception IllegalStateException When attempting to load a
+ * catalog after loading has been {@link #disableLoading disabled},
+ * such as after any entity or URI lookup has been performed.
+ */
+ public synchronized void loadCatalog (String uri)
+ throws SAXException, IOException
+ {
+ Catalog catalog;
+ int index = -1;
+
+ if (!loadingPermitted)
+ throw new IllegalStateException ();
+
+ uri = normalizeURI (uri);
+ if (catalogs != null) {
+ // maybe just reload
+ for (index = 0; index < catalogs.length; index++)
+ if (uri.equals (catalogs [index].catalogURI))
+ break;
+ }
+ catalog = loadCatalog (parserClass, errorHandler, uri, unified);
+
+ // add to list of catalogs
+ if (catalogs == null) {
+ index = 0;
+ catalogs = new Catalog [1];
+ } else if (index == catalogs.length) {
+ Catalog tmp [];
+
+ tmp = new Catalog [index + 1];
+ System.arraycopy (catalogs, 0, tmp, 0, index);
+ catalogs = tmp;
+ }
+ catalogs [index] = catalog;
+ }
+
+
+ /**
+ * "New Style" external entity resolution for parsers.
+ * Calls to this method prevent explicit loading of additional catalogs
+ * using {@link #loadCatalog loadCatalog()}.
+ *
+ * This supports the full core catalog functionality for locating
+ * (and relocating) parsed entities that have been declared in a
+ * document's DTD.
+ *
+ * @param name Entity name, such as "dudley", "%nell", or "[dtd]".
+ * @param publicId Either a normalized public ID, or null.
+ * @param baseURI Absolute base URI associated with systemId.
+ * @param systemId URI found in entity declaration (may be
+ * relative to baseURI).
+ *
+ * @return Input source for accessing the external entity, or null
+ * if no mapping was found. The input source may have opened
+ * the stream, and will have a fully resolved URI.
+ *
+ * @see #getExternalSubset
+ */
+ public InputSource resolveEntity (
+ String name, // UNUSED ... systemId is always non-null
+ String publicId,
+ String baseURI, // UNUSED ... it just lets sysId be relative
+ String systemId
+ ) throws SAXException, IOException
+ {
+ if (loadingPermitted)
+ disableLoading ();
+
+ try {
+ // steps as found in OASIS XML catalog spec 7.1.2
+ // steps 1, 8 involve looping over the list of catalogs
+ for (int i = 0; i < catalogs.length; i++) {
+ InputSource retval;
+ retval = catalogs [i].resolve (usingPublic, publicId, systemId);
+ if (retval != null)
+ return retval;;
+ }
+ } catch (DoneDelegation x) {
+ // done!
+ }
+ // step 9 involves returning "no match"
+ return null;
+ }
+
+
+ /**
+ * "New Style" parser callback to add an external subset.
+ * For documents that don't include an external subset, this may
+ * return one according to doctype catalog entries.
+ * (This functionality is not a core part of the OASIS XML Catalog
+ * specification, though it's presented in an appendix.)
+ * If no such entry is defined, this returns null to indicate that
+ * this document will not be modified to include such a subset.
+ * Calls to this method prevent explicit loading of additional catalogs
+ * using {@link #loadCatalog loadCatalog()}.
+ *
+ * Warning: That catalog functionality can be dangerous.
+ * It can provide definitions of general entities, and thereby mask
+ * certain well formedess errors.
+ *
+ * @param name Name of the document element, either as declared in
+ * a DOCTYPE declaration or as observed in the text.
+ * @param baseURI Document's base URI (absolute).
+ *
+ * @return Input source for accessing the external subset, or null
+ * if no mapping was found. The input source may have opened
+ * the stream, and will have a fully resolved URI.
+ */
+ public InputSource getExternalSubset (String name, String baseURI)
+ throws SAXException, IOException
+ {
+ if (loadingPermitted)
+ disableLoading ();
+ try {
+ for (int i = 0; i < catalogs.length; i++) {
+ InputSource retval = catalogs [i].getExternalSubset (name);
+ if (retval != null)
+ return retval;
+ }
+ } catch (DoneDelegation x) {
+ // done!
+ }
+ return null;
+ }
+
+
+ /**
+ * "Old Style" external entity resolution for parsers.
+ * This API provides only core functionality.
+ * Calls to this method prevent explicit loading of additional catalogs
+ * using {@link #loadCatalog loadCatalog()}.
+ *
+ * The functional limitations of this interface include: Applications can tell whether this limited functionality will be
+ * used: if the feature flag associated with the {@link EntityResolver2}
+ * interface is not true, the limitations apply. Applications
+ * can't usually know whether a given document and catalog will trigger
+ * those limitations. The issue can only be bypassed by operational
+ * procedures such as not using catalogs or documents which involve
+ * those features.
+ *
+ * @param publicId Either a normalized public ID, or null
+ * @param systemId Always an absolute URI.
+ *
+ * @return Input source for accessing the external entity, or null
+ * if no mapping was found. The input source may have opened
+ * the stream, and will have a fully resolved URI.
+ */
+ final public InputSource resolveEntity (String publicId, String systemId)
+ throws SAXException, IOException
+ {
+ return resolveEntity (null, publicId, null, systemId);
+ }
+
+
+ /**
+ * Resolves a URI reference that's not defined to the DTD.
+ * This is intended for use with URIs found in document text, such as
+ * xml-stylesheet processing instructions and in attribute
+ * values, where they are not recognized as URIs by XML parsers.
+ * Calls to this method prevent explicit loading of additional catalogs
+ * using {@link #loadCatalog loadCatalog()}.
+ *
+ * This functionality is supported by the OASIS XML Catalog
+ * specification, but will never be invoked by an XML parser.
+ * It corresponds closely to functionality for mapping system
+ * identifiers for entities declared in DTDs; closely enough that
+ * this implementation's default behavior is that they be
+ * identical, to minimize potential confusion.
+ *
+ * This method could be useful when implementing the
+ * {@link javax.xml.transform.URIResolver} interface, wrapping the
+ * input source in a {@link javax.xml.transform.sax.SAXSource}.
+ *
+ * @see #isUnified
+ * @see #setUnified
+ *
+ * @param baseURI The relevant base URI as specified by the XML Base
+ * specification. This recognizes xml:base attributes
+ * as overriding the actual (physical) base URI.
+ * @param uri Either an absolute URI, or one relative to baseURI
+ *
+ * @return Input source for accessing the mapped URI, or null
+ * if no mapping was found. The input source may have opened
+ * the stream, and will have a fully resolved URI.
+ */
+ public InputSource resolveURI (String baseURI, String uri)
+ throws SAXException, IOException
+ {
+ if (loadingPermitted)
+ disableLoading ();
+
+ // NOTE: baseURI isn't used here, but caller MUST have it,
+ // and heuristics _might_ use it in the future ... plus,
+ // it's symmetric with resolveEntity ().
+
+ // steps 1, 6 involve looping
+ try {
+ for (int i = 0; i < catalogs.length; i++) {
+ InputSource tmp = catalogs [i].resolveURI (uri);
+ if (tmp != null)
+ return tmp;
+ }
+ } catch (DoneDelegation x) {
+ // done
+ }
+ // step 7 reports no match
+ return null;
+ }
+
+
+ /**
+ * Records that catalog loading is no longer permitted.
+ * Loading is automatically disabled when lookups are performed,
+ * and should be manually disabled when startDTD() (or
+ * any other DTD declaration callback) is invoked, or at the latest
+ * when the document root element is seen.
+ */
+ public synchronized void disableLoading ()
+ {
+ // NOTE: this method and loadCatalog() are synchronized
+ // so that it's impossible to load (top level) catalogs
+ // after lookups start. Likewise, deferred loading is also
+ // synchronized (for "next" and delegated catalogs) to
+ // ensure that parsers can share resolvers.
+ loadingPermitted = false;
+ }
+
+
+ /**
+ * Returns the error handler used to report catalog errors.
+ * Null is returned if the parser's default error handling
+ * will be used.
+ *
+ * @see #setErrorHandler
+ */
+ public ErrorHandler getErrorHandler ()
+ { return errorHandler; }
+
+ /**
+ * Assigns the error handler used to report catalog errors.
+ * These errors may come either from the SAX2 parser or
+ * from the catalog parsing code driven by the parser.
+ *
+ * If you're sharing the resolver between parsers, don't
+ * change this once lookups have begun.
+ *
+ * @see #getErrorHandler
+ *
+ * @param parser The error handler, or null saying to use the default
+ * (no diagnostics, and only fatal errors terminate loading).
+ */
+ public void setErrorHandler (ErrorHandler handler)
+ { errorHandler = handler; }
+
+
+ /**
+ * Returns the name of the SAX2 parser class used to parse catalogs.
+ * Null is returned if the system default is used.
+ * @see #setParserClass
+ */
+ public String getParserClass ()
+ { return parserClass; }
+
+ /**
+ * Names the SAX2 parser class used to parse catalogs.
+ *
+ * If you're sharing the resolver between parsers, don't change
+ * this once lookups have begun.
+ *
+ * Note that in order to properly support the xml:base
+ * attribute and relative URI resolution, the SAX parser used to parse
+ * the catalog must provide a {@link Locator} and support the optional
+ * declaration and lexical handlers.
+ *
+ * @see #getParserClass
+ *
+ * @param parser The parser class name, or null saying to use the
+ * system default SAX2 parser.
+ */
+ public void setParserClass (String parser)
+ { parserClass = parser; }
+
+
+ /**
+ * Returns true (the default) if all methods resolve
+ * a given URI in the same way.
+ * Returns false if calls resolving URIs as entities (such as
+ * {@link #resolveEntity resolveEntity()}) use different catalog entries
+ * than those resolving them as URIs ({@link #resolveURI resolveURI()}),
+ * which will generally produce different results.
+ *
+ * The OASIS XML Catalog specification defines two related schemes
+ * to map URIs "as URIs" or "as system IDs".
+ * URIs use uri, rewriteURI, and delegateURI
+ * elements. System IDs do the same things with systemId,
+ * rewriteSystemId, and delegateSystemId.
+ * It's confusing and error prone to maintain two parallel copies of
+ * such data. Accordingly, this class makes that behavior optional.
+ * The unified interpretation of URI mappings is preferred,
+ * since it prevents surprises where one URI gets mapped to different
+ * contents depending on whether the reference happens to have come
+ * from a DTD (or not).
+ *
+ * @see #setUnified
+ */
+ public boolean isUnified ()
+ { return unified; }
+
+ /**
+ * Assigns the value of the flag returned by {@link #isUnified}.
+ * Set it to false to be strictly conformant with the OASIS XML Catalog
+ * specification. Set it to true to make all mappings for a given URI
+ * give the same result, regardless of the reason for the mapping.
+ *
+ * Don't change this once you've loaded the first catalog.
+ *
+ * @param value new flag setting
+ */
+ public void setUnified (boolean value)
+ { unified = value; }
+
+
+ /**
+ * Returns true (the default) if a catalog's public identifier
+ * mappings will be used.
+ * When false is returned, such mappings are ignored except when
+ * system IDs are discarded, such as for
+ * entities using the urn:publicid: URI scheme in their
+ * system identifiers. (See RFC 3151 for information about that
+ * URI scheme. Using it in system identifiers may not work well
+ * with many SAX parsers unless the resolve-dtd-uris
+ * feature flag is set to false.)
+ * @see #setUsingPublic
+ */
+ public boolean isUsingPublic ()
+ { return usingPublic; }
+
+ /**
+ * Specifies which catalog search mode is used.
+ * By default, public identifier mappings are able to override system
+ * identifiers when both are available.
+ * Applications may choose to ignore public
+ * identifier mappings in such cases, so that system identifiers
+ * declared in DTDs will only be overridden by an explicit catalog
+ * match for that system ID.
+ *
+ * If you're sharing the resolver between parsers, don't
+ * change this once lookups have begun.
+ * @see #isUsingPublic
+ *
+ * @param value true to always use public identifier mappings,
+ * false to only use them for system ids using the urn:publicid:
+ * URI scheme.
+ */
+ public void setUsingPublic (boolean value)
+ { usingPublic = value; }
+
+
+
+ // hmm, what's this do? :)
+ private static Catalog loadCatalog (
+ String parserClass,
+ ErrorHandler eh,
+ String uri,
+ boolean unified
+ ) throws SAXException, IOException
+ {
+ XMLReader parser;
+ Loader loader;
+ boolean doesIntern = false;
+
+ if (parserClass == null)
+ parser = XMLReaderFactory.createXMLReader ();
+ else
+ parser = XMLReaderFactory.createXMLReader (parserClass);
+ if (eh != null)
+ parser.setErrorHandler (eh);
+ // resolve-dtd-entities is at default value (unrecognized == true)
+
+ try {
+ doesIntern = parser.getFeature (
+ "http://xml.org/sax/features/string-interning");
+ } catch (SAXNotRecognizedException e) { }
+
+ loader = new Loader (doesIntern, eh, unified);
+ loader.cat.parserClass = parserClass;
+ loader.cat.catalogURI = uri;
+
+ parser.setContentHandler (loader);
+ parser.setProperty (
+ "http://xml.org/sax/properties/declaration-handler",
+ loader);
+ parser.setProperty (
+ "http://xml.org/sax/properties/lexical-handler",
+ loader);
+ parser.parse (uri);
+
+ return loader.cat;
+ }
+
+ // perform one or both the normalizations for public ids
+ private static String normalizePublicId (boolean full, String publicId)
+ {
+ if (publicId.startsWith ("urn:publicid:")) {
+ StringBuffer buf = new StringBuffer ();
+ char chars [] = publicId.toCharArray ();
+boolean hasbug = false;
+
+ for (int i = 13; i < chars.length; i++) {
+ switch (chars [i]) {
+ case '+': buf.append (' '); continue;
+ case ':': buf.append ("//"); continue;
+ case ';': buf.append ("::"); continue;
+ case '%':
+// FIXME unhex that char! meanwhile, warn and fallthrough ...
+ hasbug = true;
+ default: buf.append (chars [i]); continue;
+ }
+ }
+ publicId = buf.toString ();
+if (hasbug)
+System.err.println ("nyet unhexing public id: " + publicId);
+ full = true;
+ }
+
+ // SAX parsers do everything except that URN mapping, but
+ // we can't trust other sources to normalize correctly
+ if (full) {
+ StringTokenizer tokens;
+ String token;
+
+ tokens = new StringTokenizer (publicId, " \r\n");
+ publicId = null;
+ while (tokens.hasMoreTokens ()) {
+ if (publicId == null)
+ publicId = tokens.nextToken ();
+ else
+ publicId += " " + tokens.nextToken ();
+ }
+ }
+ return publicId;
+ }
+
+ private static boolean isUriExcluded (int c)
+ { return c <= 0x20 || c >= 0x7f || "\"<>^`{|}".indexOf (c) != -1; }
+
+ private static int hexNibble (int c)
+ {
+ if (c < 10)
+ return c + '0';
+ return ('a' - 10) + c;
+ }
+
+ // handles URIs with "excluded" characters
+ private static String normalizeURI (String systemId)
+ {
+ int length = systemId.length ();
+
+ for (int i = 0; i < length; i++) {
+ char c = systemId.charAt (i);
+
+ // escape non-ASCII plus "excluded" characters
+ if (isUriExcluded (c)) {
+ byte buf [];
+ ByteArrayOutputStream out;
+ int b;
+
+ // a JVM that doesn't know UTF8 and 8859_1 is unusable!
+ try {
+ buf = systemId.getBytes ("UTF8");
+ out = new ByteArrayOutputStream (buf.length + 10);
+
+ for (i = 0; i < buf.length; i++) {
+ b = buf [i] & 0x0ff;
+ if (isUriExcluded (b)) {
+ out.write ((int) '%');
+ out.write (hexNibble (b >> 4));
+ out.write (hexNibble (b & 0x0f));
+ } else
+ out.write (b);
+ }
+ return out.toString ("8859_1");
+ } catch (IOException e) {
+ throw new RuntimeException (
+ "can't normalize URI: " + e.getMessage ());
+ }
+ }
+ }
+ return systemId;
+ }
+
+ // thrown to mark authoritative end of a search
+ private static class DoneDelegation extends SAXException
+ {
+ DoneDelegation () { }
+ }
+
+
+ /**
+ * Represents a OASIS XML Catalog, and encapsulates much of
+ * the catalog functionality.
+ */
+ private static class Catalog
+ {
+ // loading infrastructure
+ String catalogURI;
+ ErrorHandler eh;
+ boolean unified;
+ String parserClass;
+
+ // catalog data
+ boolean hasPreference;
+ boolean usingPublic;
+
+ Hashtable publicIds;
+ Hashtable publicDelegations;
+
+ Hashtable systemIds;
+ Hashtable systemRewrites;
+ Hashtable systemDelegations;
+
+ Hashtable uris;
+ Hashtable uriRewrites;
+ Hashtable uriDelegations;
+
+ Hashtable doctypes;
+
+ Vector next;
+
+ // nonpublic!
+ Catalog () { }
+
+
+ // steps as found in OASIS XML catalog spec 7.1.2
+ private InputSource locatePublicId (String publicId)
+ throws SAXException, IOException
+ {
+ // 5. return (first) 'public' entry
+ if (publicIds != null) {
+ String retval = (String) publicIds.get (publicId);
+ if (retval != null) {
+ // IF the URI is accessible ...
+ return new InputSource (retval);
+ }
+ }
+
+ // 6. return delegatePublic catalog match [complex]
+ if (publicDelegations != null)
+ return checkDelegations (publicDelegations, publicId,
+ publicId, null);
+
+ return null;
+ }
+
+ // steps as found in OASIS XML catalog spec 7.1.2 or 7.2.2
+ private InputSource mapURI (
+ String uri,
+ Hashtable ids,
+ Hashtable rewrites,
+ Hashtable delegations
+ ) throws SAXException, IOException
+ {
+ // 7.1.2: 2. return (first) 'system' entry
+ // 7.2.2: 2. return (first) 'uri' entry
+ if (ids != null) {
+ String retval = (String) ids.get (uri);
+ if (retval != null) {
+ // IF the URI is accessible ...
+ return new InputSource (retval);
+ }
+ }
+
+ // 7.1.2: 3. return 'rewriteSystem' entries
+ // 7.2.2: 3. return 'rewriteURI' entries
+ if (rewrites != null) {
+ String prefix = null;
+ String replace = null;
+ int prefixLen = -1;
+
+ for (Enumeration e = rewrites.keys ();
+ e.hasMoreElements ();
+ /* NOP */) {
+ String temp = (String) e.nextElement ();
+ int len = -1;
+
+ if (!uri.startsWith (temp))
+ continue;
+ if (prefix != null
+ && (len = temp.length ()) < prefixLen)
+ continue;
+ prefix = temp;
+ prefixLen = len;
+ replace = (String) rewrites.get (temp);
+ }
+ if (prefix != null) {
+ StringBuffer buf = new StringBuffer (replace);
+ buf.append (uri.substring (prefixLen));
+ // IF the URI is accessible ...
+ return new InputSource (buf.toString ());
+ }
+ }
+
+ // 7.1.2: 4. return 'delegateSystem' catalog match [complex]
+ // 7.2.2: 4. return 'delegateURI' catalog match [complex]
+ if (delegations != null)
+ return checkDelegations (delegations, uri, null, uri);
+
+ return null;
+ }
+
+
+ /**
+ * Returns a URI for an external entity.
+ */
+ public InputSource resolve (
+ boolean usingPublic,
+ String publicId,
+ String systemId
+ ) throws SAXException, IOException
+ {
+ boolean preferSystem;
+ InputSource retval;
+
+ if (hasPreference)
+ preferSystem = !this.usingPublic;
+ else
+ preferSystem = !usingPublic;
+
+ if (publicId != null)
+ publicId = normalizePublicId (false, publicId);
+
+ // behavior here matches section 7.1.1 of the oasis spec
+ if (systemId != null) {
+ if (systemId.startsWith ("urn:publicid:")) {
+ String temp = normalizePublicId (true, systemId);
+ if (publicId == null) {
+ publicId = temp;
+ systemId = null;
+ } else if (!publicId.equals (temp)) {
+ // error; ok to recover by:
+ systemId = null;
+ }
+ } else
+ systemId = normalizeURI (systemId);
+ }
+
+ if (systemId == null && publicId == null)
+ return null;
+
+ if (systemId != null) {
+ retval = mapURI (systemId, systemIds, systemRewrites,
+ systemDelegations);
+ if (retval != null) {
+ retval.setPublicId (publicId);
+ return retval;
+ }
+ }
+
+ if (publicId != null
+ && !(systemId != null && preferSystem)) {
+ retval = locatePublicId (publicId);
+ if (retval != null) {
+ retval.setPublicId (publicId);
+ return retval;
+ }
+ }
+
+ // 7. apply nextCatalog entries
+ if (next != null) {
+ int length = next.size ();
+ for (int i = 0; i < length; i++) {
+ Catalog n = getNext (i);
+ retval = n.resolve (usingPublic, publicId, systemId);
+ if (retval != null)
+ return retval;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Maps one URI into another, for resources that are not defined
+ * using XML external entity or notation syntax.
+ */
+ public InputSource resolveURI (String uri)
+ throws SAXException, IOException
+ {
+ if (uri.startsWith ("urn:publicid:"))
+ return resolve (true, normalizePublicId (true, uri), null);
+
+ InputSource retval;
+
+ uri = normalizeURI (uri);
+
+ // 7.2.2 steps 2-4
+ retval = mapURI (uri, uris, uriRewrites, uriDelegations);
+ if (retval != null)
+ return retval;
+
+ // 7.2.2 step 5. apply nextCatalog entries
+ if (next != null) {
+ int length = next.size ();
+ for (int i = 0; i < length; i++) {
+ Catalog n = getNext (i);
+ retval = n.resolveURI (uri);
+ if (retval != null)
+ return retval;
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Finds the external subset associated with a given root element.
+ */
+ public InputSource getExternalSubset (String name)
+ throws SAXException, IOException
+ {
+ if (doctypes != null) {
+ String value = (String) doctypes.get (name);
+ if (value != null) {
+ // IF the URI is accessible ...
+ return new InputSource (value);
+ }
+ }
+ if (next != null) {
+ int length = next.size ();
+ for (int i = 0; i < length; i++) {
+ Catalog n = getNext (i);
+ if (n == null)
+ continue;
+ InputSource retval = n.getExternalSubset (name);
+ if (retval != null)
+ return retval;
+ }
+ }
+ return null;
+ }
+
+ private synchronized Catalog getNext (int i)
+ throws SAXException, IOException
+ {
+ Object obj;
+
+ if (next == null || i < 0 || i >= next.size ())
+ return null;
+ obj = next.elementAt (i);
+ if (obj instanceof Catalog)
+ return (Catalog) obj;
+
+ // ok, we deferred reading that catalog till now.
+ // load and cache it.
+ Catalog cat = null;
+
+ try {
+ cat = loadCatalog (parserClass, eh, (String) obj, unified);
+ next.setElementAt (cat, i);
+ } catch (SAXException e) {
+ // must fail quietly, says the OASIS spec
+ } catch (IOException e) {
+ // same applies here
+ }
+ return cat;
+ }
+
+ private InputSource checkDelegations (
+ Hashtable delegations,
+ String id,
+ String publicId, // only one of public/system
+ String systemId // will be non-null...
+ ) throws SAXException, IOException
+ {
+ Vector matches = null;
+ int length = 0;
+
+ // first, see if any prefixes match.
+ for (Enumeration e = delegations.keys ();
+ e.hasMoreElements ();
+ /* NOP */) {
+ String prefix = (String) e.nextElement ();
+
+ if (!id.startsWith (prefix))
+ continue;
+ if (matches == null)
+ matches = new Vector ();
+
+ // maintain in longer->shorter sorted order
+ // NOTE: assumes not many matches will fire!
+ int index;
+
+ for (index = 0; index < length; index++) {
+ String temp = (String) matches.elementAt (index);
+ if (prefix.length () > temp.length ()) {
+ matches.insertElementAt (prefix, index);
+ break;
+ }
+ }
+ if (index == length)
+ matches.addElement (prefix);
+ length++;
+ }
+ if (matches == null)
+ return null;
+
+ // now we know the list of catalogs to replace our "top level"
+ // list ... we use it here, rather than somehow going back and
+ // restarting, since this helps avoid reading most catalogs.
+ // this assumes stackspace won't be a problem.
+ for (int i = 0; i < length; i++) {
+ Catalog catalog = null;
+ InputSource result;
+
+ // get this catalog. we may not have read it yet.
+ synchronized (delegations) {
+ Object prefix = matches.elementAt (i);
+ Object cat = delegations.get (prefix);
+
+ if (cat instanceof Catalog)
+ catalog = (Catalog) cat;
+ else {
+ try {
+ // load and cache that catalog
+ catalog = loadCatalog (parserClass, eh,
+ (String) cat, unified);
+ delegations.put (prefix, catalog);
+ } catch (SAXException e) {
+ // must ignore, says the OASIS spec
+ } catch (IOException e) {
+ // same applies here
+ }
+ }
+ }
+
+ // ignore failed loads, and proceed
+ if (catalog == null)
+ continue;
+
+ // we have a catalog ... resolve!
+ // usingPublic value can't matter, there's no choice
+ result = catalog.resolve (true, publicId, systemId);
+ if (result != null)
+ return result;
+ }
+
+ // if there were no successes, the entire
+ // lookup failed (all the way to top level)
+ throw new DoneDelegation ();
+ }
+ }
+
+
+ /** This is the namespace URI used for OASIS XML Catalogs. */
+ private static final String catalogNamespace =
+ "urn:oasis:names:tc:entity:xmlns:xml:catalog";
+
+
+ /**
+ * Loads/unmarshals one catalog.
+ */
+ private static class Loader extends DefaultHandler2
+ {
+ private boolean preInterned;
+ private ErrorHandler handler;
+ private boolean unified;
+ private int ignoreDepth;
+ private Locator locator;
+ private boolean started;
+ private Hashtable externals;
+ private Stack bases;
+
+ Catalog cat = new Catalog ();
+
+
+ /**
+ * Constructor.
+ * @param flag true iff the parser already interns strings.
+ * @param eh Errors and warnings are delegated to this.
+ * @param unified true keeps one table for URI mappings;
+ * false matches OASIS spec, storing mappings
+ * for URIs and SYSTEM ids in parallel tables.
+ */
+ Loader (boolean flag, ErrorHandler eh, boolean unified)
+ {
+ preInterned = flag;
+ handler = eh;
+ this.unified = unified;
+ cat.unified = unified;
+ cat.eh = eh;
+ }
+
+
+ // strips out fragments
+ private String nofrag (String uri)
+ throws SAXException
+ {
+ if (uri.indexOf ('#') != -1) {
+ warn ("URI with fragment: " + uri);
+ uri = uri.substring (0, uri.indexOf ('#'));
+ }
+ return uri;
+ }
+
+ // absolutizes relative URIs
+ private String absolutize (String uri)
+ throws SAXException
+ {
+ // avoid creating URLs if they're already absolutized,
+ // or if the URI is already using a known scheme
+ if (uri.startsWith ("file:/")
+ || uri.startsWith ("http:/")
+ || uri.startsWith ("https:/")
+ || uri.startsWith ("ftp:/")
+ || uri.startsWith ("urn:")
+ )
+ return uri;
+
+ // otherwise, let's hope the JDK handles this URI scheme.
+ try {
+ URL base = (URL) bases.peek ();
+ return new URL (base, uri).toString ();
+ } catch (Exception e) {
+ fatal ("can't absolutize URI: " + uri);
+ return null;
+ }
+ }
+
+ // recoverable error
+ private void error (String message)
+ throws SAXException
+ {
+ if (handler == null)
+ return;
+ handler.error (new SAXParseException (message, locator));
+ }
+
+ // nonrecoverable error
+ private void fatal (String message)
+ throws SAXException
+ {
+ SAXParseException spe;
+
+ spe = new SAXParseException (message, locator);
+ if (handler != null)
+ handler.fatalError (spe);
+ throw spe;
+ }
+
+ // low severity problem
+ private void warn (String message)
+ throws SAXException
+ {
+ if (handler == null)
+ return;
+ handler.warning (new SAXParseException (message, locator));
+ }
+
+ // callbacks:
+
+ public void setDocumentLocator (Locator l)
+ { locator = l; }
+
+ public void startDocument ()
+ throws SAXException
+ {
+ if (locator == null)
+ error ("no locator!");
+ bases = new Stack ();
+ String uri = locator.getSystemId ();
+ try {
+ bases.push (new URL (uri));
+ } catch (IOException e) {
+ fatal ("bad document base URI: " + uri);
+ }
+ }
+
+ public void endDocument ()
+ throws SAXException
+ {
+ try {
+ if (!started)
+ error ("not a catalog!");
+ } finally {
+ locator = null;
+ handler = null;
+ externals = null;
+ bases = null;
+ }
+ }
+
+ // XML Base support for external entities.
+
+ // NOTE: expects parser is in default "resolve-dtd-uris" mode.
+ public void externalEntityDecl (String name, String pub, String sys)
+ throws SAXException
+ {
+ if (externals == null)
+ externals = new Hashtable ();
+ if (externals.get (name) == null)
+ externals.put (name, pub);
+ }
+
+ public void startEntity (String name)
+ throws SAXException
+ {
+ if (externals == null)
+ return;
+ String uri = (String) externals.get (name);
+
+ // NOTE: breaks if an EntityResolver substitutes these URIs.
+ // If toplevel loader supports one, must intercept calls...
+ if (uri != null) {
+ try {
+ bases.push (new URL (uri));
+ } catch (IOException e) {
+ fatal ("entity '" + name + "', bad URI: " + uri);
+ }
+ }
+ }
+
+ public void endEntity (String name)
+ {
+ if (externals == null)
+ return;
+ String value = (String) externals.get (name);
+
+ if (value != null)
+ bases.pop ();
+ }
+
+ /**
+ * Processes catalog elements, saving their data.
+ */
+ public void startElement (String namespace, String local,
+ String qName, Attributes atts)
+ throws SAXException
+ {
+ // must ignore non-catalog elements, and their contents
+ if (ignoreDepth != 0 || !catalogNamespace.equals (namespace)) {
+ ignoreDepth++;
+ return;
+ }
+
+ // basic sanity checks
+ if (!preInterned)
+ local = local.intern ();
+ if (!started) {
+ started = true;
+ if ("catalog" != local)
+ fatal ("root element not 'catalog': " + local);
+ }
+
+ // Handle any xml:base attribute
+ String xmlbase = atts.getValue ("xml:base");
+
+ if (xmlbase != null) {
+ URL base = (URL) bases.peek ();
+ try {
+ base = new URL (base, xmlbase);
+ } catch (IOException e) {
+ fatal ("can't resolve xml:base attribute: " + xmlbase);
+ }
+ bases.push (base);
+ } else
+ bases.push (bases.peek ());
+
+ // fetch multi-element attributes, apply standard tweaks
+ // values (uri, catalog, rewritePrefix) get normalized too,
+ // as a precaution and since we may compare the values
+ String catalog = atts.getValue ("catalog");
+ if (catalog != null)
+ catalog = normalizeURI (absolutize (catalog));
+
+ String rewritePrefix = atts.getValue ("rewritePrefix");
+ if (rewritePrefix != null)
+ rewritePrefix = normalizeURI (absolutize (rewritePrefix));
+
+ String systemIdStartString;
+ systemIdStartString = atts.getValue ("systemIdStartString");
+ if (systemIdStartString != null) {
+ systemIdStartString = normalizeURI (systemIdStartString);
+ // unmatchable By default, text is generated "as-is", but some optional modes
+ * are supported. Pretty-printing is supported, to make life easier
+ * for people reading the output. XHTML (1.0) output has can be made
+ * particularly pretty; all the built-in character entities are known.
+ * Canonical XML can also be generated, assuming the input is properly
+ * formed.
+ *
+ * Some of the methods on this class are intended for applications to
+ * use directly, rather than as pure SAX2 event callbacks. Some of those
+ * methods access the JavaBeans properties (used to tweak output formats,
+ * for example canonicalization and pretty printing). Subclasses
+ * are expected to add new behaviors, not to modify current behavior, so
+ * many such methods are final. The write*() methods may be slightly simpler for some
+ * applications to use than direct callbacks. For example, they support
+ * a simple policy for encoding data items as the content of a single element.
+ *
+ * To reuse an XMLWriter you must provide it with a new Writer, since
+ * this handler closes the writer it was given as part of its endDocument()
+ * handling. (XML documents have an end of input, and the way to encode
+ * that on a stream is to close it.) Note that any relative URIs in the source document, as found in
+ * entity and notation declarations, ought to have been fully resolved by
+ * the parser providing events to this handler. This means that the
+ * output text should only have fully resolved URIs, which may not be
+ * the desired behavior in cases where later binding is desired. Note that due to SAX2 defaults, you may need to manually
+ * ensure that the input events are XML-conformant with respect to namespace
+ * prefixes and declarations. {@link gnu.xml.pipeline.NSFilter} is
+ * one solution to this problem, in the context of processing pipelines.
+ * Something as simple as connecting this handler to a parser might not
+ * generate the correct output. Another workaround is to ensure that the
+ * namespace-prefixes feature is always set to true, if you're
+ * hooking this directly up to some XMLReader implementation.
+ *
+ * @see gnu.xml.pipeline.TextConsumer
+ *
+ * @author David Brownell
+ */
+public class XMLWriter
+ implements ContentHandler, LexicalHandler, DTDHandler, DeclHandler
+{
+ // text prints/escapes differently depending on context
+ // CTX_ENTITY ... entity literal value
+ // CTX_ATTRIBUTE ... attribute literal value
+ // CTX_CONTENT ... content of an element
+ // CTX_UNPARSED ... CDATA, comment, PI, names, etc
+ // CTX_NAME ... name or nmtoken, no escapes possible
+ private static final int CTX_ENTITY = 1;
+ private static final int CTX_ATTRIBUTE = 2;
+ private static final int CTX_CONTENT = 3;
+ private static final int CTX_UNPARSED = 4;
+ private static final int CTX_NAME = 5;
+
+// FIXME: names (element, attribute, PI, notation, etc) are not
+// currently written out with range checks (escapeChars).
+// In non-XHTML, some names can't be directly written; panic!
+
+ private static String sysEOL;
+
+ static {
+ try {
+ sysEOL = System.getProperty ("line.separator", "\n");
+
+ // don't use the system's EOL if it's illegal XML.
+ if (!isLineEnd (sysEOL))
+ sysEOL = "\n";
+
+ } catch (SecurityException e) {
+ sysEOL = "\n";
+ }
+ }
+
+ private static boolean isLineEnd (String eol)
+ {
+ return "\n".equals (eol)
+ || "\r".equals (eol)
+ || "\r\n".equals (eol);
+ }
+
+ private Writer out;
+ private boolean inCDATA;
+ private int elementNestLevel;
+ private String eol = sysEOL;
+
+ private short dangerMask;
+ private StringBuffer stringBuf;
+ private Locator locator;
+ private ErrorHandler errHandler;
+
+ private boolean expandingEntities = false;
+ private int entityNestLevel;
+ private boolean xhtml;
+ private boolean startedDoctype;
+ private String encoding;
+
+ private boolean canonical;
+ private boolean inDoctype;
+ private boolean inEpilogue;
+
+ // pretty printing controls
+ private boolean prettyPrinting;
+ private int column;
+ private boolean noWrap;
+ private Stack space = new Stack ();
+
+ // this is not a hard'n'fast rule -- longer lines are OK,
+ // but are to be avoided. Here, prettyprinting is more to
+ // show structure "cleanly" than to be precise about it.
+ // better to have ragged layout than one line 24Kb long.
+ private static final int lineLength = 75;
+
+
+ /**
+ * Constructs this handler with System.out used to write SAX events
+ * using the UTF-8 encoding. Avoid using this except when you know
+ * it's safe to close System.out at the end of the document.
+ */
+ public XMLWriter () throws IOException
+ { this (System.out); }
+
+ /**
+ * Constructs a handler which writes all input to the output stream
+ * in the UTF-8 encoding, and closes it when endDocument is called.
+ * (Yes it's annoying that this throws an exception -- but there's
+ * really no way around it, since it's barely possible a JDK may
+ * exist somewhere that doesn't know how to emit UTF-8.)
+ */
+ public XMLWriter (OutputStream out) throws IOException
+ {
+ this (new OutputStreamWriter (out, "UTF8"));
+ }
+
+ /**
+ * Constructs a handler which writes all input to the writer, and then
+ * closes the writer when the document ends. If an XML declaration is
+ * written onto the output, and this class can determine the name of
+ * the character encoding for this writer, that encoding name will be
+ * included in the XML declaration.
+ *
+ * See the description of the constructor which takes an encoding
+ * name for imporant information about selection of encodings.
+ *
+ * @param writer XML text is written to this writer.
+ */
+ public XMLWriter (Writer writer)
+ {
+ this (writer, null);
+ }
+
+ /**
+ * Constructs a handler which writes all input to the writer, and then
+ * closes the writer when the document ends. If an XML declaration is
+ * written onto the output, this class will use the specified encoding
+ * name in that declaration. If no encoding name is specified, no
+ * encoding name will be declared unless this class can otherwise
+ * determine the name of the character encoding for this writer.
+ *
+ * At this time, only the UTF-8 ("UTF8") and UTF-16 ("Unicode")
+ * output encodings are fully lossless with respect to XML data. If you
+ * use any other encoding you risk having your data be silently mangled
+ * on output, as the standard Java character encoding subsystem silently
+ * maps non-encodable characters to a question mark ("?") and will not
+ * report such errors to applications.
+ *
+ * For a few other encodings the risk can be reduced. If the writer is
+ * a java.io.OutputStreamWriter, and uses either the ISO-8859-1 ("8859_1",
+ * "ISO8859_1", etc) or US-ASCII ("ASCII") encodings, content which
+ * can't be encoded in those encodings will be written safely. Where
+ * relevant, the XHTML entity names will be used; otherwise, numeric
+ * character references will be emitted.
+ *
+ * However, there remain a number of cases where substituting such
+ * entity or character references is not an option. Such references are
+ * not usable within a DTD, comment, PI, or CDATA section. Neither may
+ * they be used when element, attribute, entity, or notation names have
+ * the problematic characters.
+ *
+ * @param writer XML text is written to this writer.
+ * @param encoding if non-null, and an XML declaration is written,
+ * this is the name that will be used for the character encoding.
+ */
+ public XMLWriter (Writer writer, String encoding)
+ {
+ setWriter (writer, encoding);
+ }
+
+ private void setEncoding (String encoding)
+ {
+ if (encoding == null && out instanceof OutputStreamWriter)
+ encoding = ((OutputStreamWriter)out).getEncoding ();
+
+ if (encoding != null) {
+ encoding = encoding.toUpperCase ();
+
+ // Use official encoding names where we know them,
+ // avoiding the Java-only names. When using common
+ // encodings where we can easily tell if characters
+ // are out of range, we'll escape out-of-range
+ // characters using character refs for safety.
+
+ // I _think_ these are all the main synonyms for these!
+ if ("UTF8".equals (encoding)) {
+ encoding = "UTF-8";
+ } else if ("US-ASCII".equals (encoding)
+ || "ASCII".equals (encoding)) {
+ dangerMask = (short) 0xff80;
+ encoding = "US-ASCII";
+ } else if ("ISO-8859-1".equals (encoding)
+ || "8859_1".equals (encoding)
+ || "ISO8859_1".equals (encoding)) {
+ dangerMask = (short) 0xff00;
+ encoding = "ISO-8859-1";
+ } else if ("UNICODE".equals (encoding)
+ || "UNICODE-BIG".equals (encoding)
+ || "UNICODE-LITTLE".equals (encoding)) {
+ encoding = "UTF-16";
+
+ // TODO: UTF-16BE, UTF-16LE ... no BOM; what
+ // release of JDK supports those Unicode names?
+ }
+
+ if (dangerMask != 0)
+ stringBuf = new StringBuffer ();
+ }
+
+ this.encoding = encoding;
+ }
+
+
+ /**
+ * Resets the handler to write a new text document.
+ *
+ * @param writer XML text is written to this writer.
+ * @param encoding if non-null, and an XML declaration is written,
+ * this is the name that will be used for the character encoding.
+ *
+ * @exception IllegalStateException if the current
+ * document hasn't yet ended (with {@link #endDocument})
+ */
+ final public void setWriter (Writer writer, String encoding)
+ {
+ if (out != null)
+ throw new IllegalStateException (
+ "can't change stream in mid course");
+ out = writer;
+ if (out != null)
+ setEncoding (encoding);
+ if (!(out instanceof BufferedWriter))
+ out = new BufferedWriter (out);
+ space.push ("default");
+ }
+
+ /**
+ * Assigns the line ending style to be used on output.
+ * @param eolString null to use the system default; else
+ * "\n", "\r", or "\r\n".
+ */
+ final public void setEOL (String eolString)
+ {
+ if (eolString == null)
+ eol = sysEOL;
+ else if (!isLineEnd (eolString))
+ eol = eolString;
+ else
+ throw new IllegalArgumentException (eolString);
+ }
+
+ /**
+ * Assigns the error handler to be used to present most fatal
+ * errors.
+ */
+ public void setErrorHandler (ErrorHandler handler)
+ {
+ errHandler = handler;
+ }
+
+ /**
+ * Used internally and by subclasses, this encapsulates the logic
+ * involved in reporting fatal errors. It uses locator information
+ * for good diagnostics, if available, and gives the application's
+ * ErrorHandler the opportunity to handle the error before throwing
+ * an exception.
+ */
+ protected void fatal (String message, Exception e)
+ throws SAXException
+ {
+ SAXParseException x;
+
+ if (locator == null)
+ x = new SAXParseException (message, null, null, -1, -1, e);
+ else
+ x = new SAXParseException (message, locator, e);
+ if (errHandler != null)
+ errHandler.fatalError (x);
+ throw x;
+ }
+
+
+ // JavaBeans properties
+
+ /**
+ * Controls whether the output should attempt to follow the "transitional"
+ * XHTML rules so that it meets the "HTML Compatibility Guidelines"
+ * appendix in the XHTML specification. A "transitional" Document Type
+ * Declaration (DTD) is placed near the beginning of the output document,
+ * instead of whatever DTD would otherwise have been placed there, and
+ * XHTML empty elements are printed specially. When writing text in
+ * US-ASCII or ISO-8859-1 encodings, the predefined XHTML internal
+ * entity names are used (in preference to character references) when
+ * writing content characters which can't be expressed in those encodings.
+ *
+ * When this option is enabled, it is the caller's responsibility
+ * to ensure that the input is otherwise valid as XHTML. Things to
+ * be careful of in all cases, as described in the appendix referenced
+ * above, include: Additionally, some of the oldest browsers have additional
+ * quirks, to address with guidelines such as: Also, some characteristics of the resulting output may be
+ * a function of whether the document is later given a MIME
+ * content type of text/html rather than one indicating
+ * XML (application/xml or text/xml). Worse,
+ * some browsers ignore MIME content types and prefer to rely URI
+ * name suffixes -- so an "index.xml" could always be XML, never
+ * XHTML, no matter its MIME type.
+ */
+ final public void setXhtml (boolean value)
+ {
+ if (locator != null)
+ throw new IllegalStateException ("started parsing");
+ xhtml = value;
+ if (xhtml)
+ canonical = false;
+ }
+
+ /**
+ * Returns true if the output attempts to echo the input following
+ * "transitional" XHTML rules and matching the "HTML Compatibility
+ * Guidelines" so that an HTML version 3 browser can read the output
+ * as HTML; returns false (the default) othewise.
+ */
+ final public boolean isXhtml ()
+ {
+ return xhtml;
+ }
+
+ /**
+ * Controls whether the output text contains references to
+ * entities (the default), or instead contains the expanded
+ * values of those entities.
+ */
+ final public void setExpandingEntities (boolean value)
+ {
+ if (locator != null)
+ throw new IllegalStateException ("started parsing");
+ expandingEntities = value;
+ if (!expandingEntities)
+ canonical = false;
+ }
+
+ /**
+ * Returns true if the output will have no entity references;
+ * returns false (the default) otherwise.
+ */
+ final public boolean isExpandingEntities ()
+ {
+ return expandingEntities;
+ }
+
+ /**
+ * Controls pretty-printing, which by default is not enabled
+ * (and currently is most useful for XHTML output).
+ * Pretty printing enables structural indentation, sorting of attributes
+ * by name, line wrapping, and potentially other mechanisms for making
+ * output more or less readable.
+ *
+ * At this writing, structural indentation and line wrapping are
+ * enabled when pretty printing is enabled and the xml:space
+ * attribute has the value default (its other legal value is
+ * preserve, as defined in the XML specification). The three
+ * XHTML element types which use another value are recognized by their
+ * names (namespaces are ignored).
+ *
+ * Also, for the record, the "pretty" aspect of printing here
+ * is more to provide basic structure on outputs that would otherwise
+ * risk being a single long line of text. For now, expect the
+ * structure to be ragged ... unless you'd like to submit a patch
+ * to make this be more strictly formatted!
+ *
+ * @exception IllegalStateException thrown if this method is invoked
+ * after output has begun.
+ */
+ final public void setPrettyPrinting (boolean value)
+ {
+ if (locator != null)
+ throw new IllegalStateException ("started parsing");
+ prettyPrinting = value;
+ if (prettyPrinting)
+ canonical = false;
+ }
+
+ /**
+ * Returns value of flag controlling pretty printing.
+ */
+ final public boolean isPrettyPrinting ()
+ {
+ return prettyPrinting;
+ }
+
+
+ /**
+ * Sets the output style to be canonicalized. Input events must
+ * meet requirements that are slightly more stringent than the
+ * basic well-formedness ones, and include: Note that fragments of XML documents, as specified by an XPath
+ * node set, may be canonicalized. In such cases, elements may need
+ * some fixup (for xml:* attributes and application-specific
+ * context).
+ *
+ * @exception IllegalArgumentException if the output encoding
+ * is anything other than UTF-8.
+ */
+ final public void setCanonical (boolean value)
+ {
+ if (value && !"UTF-8".equals (encoding))
+ throw new IllegalArgumentException ("encoding != UTF-8");
+ canonical = value;
+ if (canonical) {
+ prettyPrinting = xhtml = false;
+ expandingEntities = true;
+ eol = "\n";
+ }
+ }
+
+
+ /**
+ * Returns value of flag controlling canonical output.
+ */
+ final public boolean isCanonical ()
+ {
+ return canonical;
+ }
+
+
+ /**
+ * Flushes the output stream. When this handler is used in long lived
+ * pipelines, it can be important to flush buffered state, for example
+ * so that it can reach the disk as part of a state checkpoint.
+ */
+ final public void flush ()
+ throws IOException
+ {
+ if (out != null)
+ out.flush ();
+ }
+
+
+ // convenience routines
+
+// FIXME: probably want a subclass that holds a lot of these...
+// and maybe more!
+
+ /**
+ * Writes the string as if characters() had been called on the contents
+ * of the string. This is particularly useful when applications act as
+ * producers and write data directly to event consumers.
+ */
+ final public void write (String data)
+ throws SAXException
+ {
+ char buf [] = data.toCharArray ();
+ characters (buf, 0, buf.length);
+ }
+
+
+ /**
+ * Writes an element that has content consisting of a single string.
+ * @see #writeEmptyElement
+ * @see #startElement
+ */
+ public void writeElement (
+ String uri,
+ String localName,
+ String qName,
+ Attributes atts,
+ String content
+ ) throws SAXException
+ {
+ if (content == null || content.length () == 0) {
+ writeEmptyElement (uri, localName, qName, atts);
+ return;
+ }
+ startElement (uri, localName, qName, atts);
+ char chars [] = content.toCharArray ();
+ characters (chars, 0, chars.length);
+ endElement (uri, localName, qName);
+ }
+
+
+ /**
+ * Writes an element that has content consisting of a single integer,
+ * encoded as a decimal string.
+ * @see #writeEmptyElement
+ * @see #startElement
+ */
+ public void writeElement (
+ String uri,
+ String localName,
+ String qName,
+ Attributes atts,
+ int content
+ ) throws SAXException
+ {
+ writeElement (uri, localName, qName, atts, Integer.toString (content));
+ }
+
+
+ // SAX1 ContentHandler
+ /** SAX1: provides parser status information */
+ final public void setDocumentLocator (Locator l)
+ {
+ locator = l;
+ }
+
+
+ // URL for dtd that validates against all normal HTML constructs
+ private static final String xhtmlFullDTD =
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";
+
+
+ /**
+ * SAX1: indicates the beginning of a document parse.
+ * If you're writing (well formed) fragments of XML, neither
+ * this nor endDocument should be called.
+ */
+ // NOT final
+ public void startDocument ()
+ throws SAXException
+ {
+ try {
+ if (out == null)
+ throw new IllegalStateException (
+ "null Writer given to XMLWriter");
+
+ // Not all parsers provide the locator we want; this also
+ // flags whether events are being sent to this object yet.
+ // We could only have this one call if we only printed whole
+ // documents ... but we also print fragments, so most of the
+ // callbacks here replicate this test.
+
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ // Unless the data is in US-ASCII or we're canonicalizing, write
+ // the XML declaration if we know the encoding. US-ASCII won't
+ // normally get mangled by web server confusion about the
+ // character encodings used. Plus, it's an easy way to
+ // ensure we can write ASCII that's unlikely to confuse
+ // elderly HTML parsers.
+
+ if (!canonical
+ && dangerMask != (short) 0xff80
+ && encoding != null) {
+ rawWrite ("");
+ newline ();
+ }
+
+ if (xhtml) {
+
+ rawWrite ("");
+ newline ();
+ newline ();
+
+ // fake the rest of the handler into ignoring
+ // everything until the root element, so any
+ // XHTML DTD comments, PIs, etc are ignored
+ startedDoctype = true;
+ }
+
+ entityNestLevel = 0;
+
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * SAX1: indicates the completion of a parse.
+ * Note that all complete SAX event streams make this call, even
+ * if an error is reported during a parse.
+ */
+ // NOT final
+ public void endDocument ()
+ throws SAXException
+ {
+ try {
+ if (!canonical) {
+ newline ();
+ newline ();
+ }
+ out.close ();
+ out = null;
+ locator = null;
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ // XHTML elements declared as EMPTY print differently
+ final private static boolean isEmptyElementTag (String tag)
+ {
+ switch (tag.charAt (0)) {
+ case 'a': return "area".equals (tag);
+ case 'b': return "base".equals (tag)
+ || "basefont".equals (tag)
+ || "br".equals (tag);
+ case 'c': return "col".equals (tag);
+ case 'f': return "frame".equals (tag);
+ case 'h': return "hr".equals (tag);
+ case 'i': return "img".equals (tag)
+ || "input".equals (tag)
+ || "isindex".equals (tag);
+ case 'l': return "link".equals (tag);
+ case 'm': return "meta".equals (tag);
+ case 'p': return "param".equals (tag);
+ }
+ return false;
+ }
+
+ private static boolean indentBefore (String tag)
+ {
+ // basically indent before block content
+ // and within structure like tables, lists
+ switch (tag.charAt (0)) {
+ case 'a': return "applet".equals (tag);
+ case 'b': return "body".equals (tag)
+ || "blockquote".equals (tag);
+ case 'c': return "center".equals (tag);
+ case 'f': return "frame".equals (tag)
+ || "frameset".equals (tag);
+ case 'h': return "head".equals (tag);
+ case 'm': return "meta".equals (tag);
+ case 'o': return "object".equals (tag);
+ case 'p': return "param".equals (tag)
+ || "pre".equals (tag);
+ case 's': return "style".equals (tag);
+ case 't': return "title".equals (tag)
+ || "td".equals (tag)
+ || "th".equals (tag);
+ }
+ // ... but not inline elements like "em", "b", "font"
+ return false;
+ }
+
+ private static boolean spaceBefore (String tag)
+ {
+ // blank line AND INDENT before certain structural content
+ switch (tag.charAt (0)) {
+ case 'h': return "h1".equals (tag)
+ || "h2".equals (tag)
+ || "h3".equals (tag)
+ || "h4".equals (tag)
+ || "h5".equals (tag)
+ || "h6".equals (tag)
+ || "hr".equals (tag);
+ case 'l': return "li".equals (tag);
+ case 'o': return "ol".equals (tag);
+ case 'p': return "p".equals (tag);
+ case 't': return "table".equals (tag)
+ || "tr".equals (tag);
+ case 'u': return "ul".equals (tag);
+ }
+ return false;
+ }
+
+ // XHTML DTDs say these three have xml:space="preserve"
+ private static boolean spacePreserve (String tag)
+ {
+ return "pre".equals (tag)
+ || "style".equals (tag)
+ || "script".equals (tag);
+ }
+
+ /**
+ * SAX2: ignored.
+ */
+ final public void startPrefixMapping (String prefix, String uri)
+ {}
+
+ /**
+ * SAX2: ignored.
+ */
+ final public void endPrefixMapping (String prefix)
+ {}
+
+ private void writeStartTag (
+ String name,
+ Attributes atts,
+ boolean isEmpty
+ ) throws SAXException, IOException
+ {
+ rawWrite ('<');
+ rawWrite (name);
+
+ // write out attributes ... sorting is particularly useful
+ // with output that's been heavily defaulted.
+ if (atts != null && atts.getLength () != 0) {
+
+ // Set up to write, with optional sorting
+ int indices [] = new int [atts.getLength ()];
+
+ for (int i= 0; i < indices.length; i++)
+ indices [i] = i;
+
+ // optionally sort
+
+// FIXME: canon xml demands xmlns nodes go first,
+// and sorting by URI first (empty first) then localname
+// it should maybe use a different sort
+
+ if (canonical || prettyPrinting) {
+
+ // insertion sort by attribute name
+ for (int i = 1; i < indices.length; i++) {
+ int n = indices [i], j;
+ String s = atts.getQName (n);
+
+ for (j = i - 1; j >= 0; j--) {
+ if (s.compareTo (atts.getQName (indices [j]))
+ >= 0)
+ break;
+ indices [j + 1] = indices [j];
+ }
+ indices [j + 1] = n;
+ }
+ }
+
+ // write, sorted or no
+ for (int i= 0; i < indices.length; i++) {
+ String s = atts.getQName (indices [i]);
+
+ if (s == null || "".equals (s))
+ throw new IllegalArgumentException ("no XML name");
+ rawWrite (" ");
+ rawWrite (s);
+ rawWrite ("=");
+ writeQuotedValue (atts.getValue (indices [i]),
+ CTX_ATTRIBUTE);
+ }
+ }
+ if (isEmpty)
+ rawWrite (" /");
+ rawWrite ('>');
+ }
+
+ /**
+ * SAX2: indicates the start of an element.
+ * When XHTML is in use, avoid attribute values with
+ * line breaks or multiple whitespace characters, since
+ * not all user agents handle them correctly.
+ */
+ final public void startElement (
+ String uri,
+ String localName,
+ String qName,
+ Attributes atts
+ ) throws SAXException
+ {
+ startedDoctype = false;
+
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ if (qName == null || "".equals (qName))
+ throw new IllegalArgumentException ("no XML name");
+
+ try {
+ if (entityNestLevel != 0)
+ return;
+ if (prettyPrinting) {
+ String whitespace = null;
+
+ if (xhtml && spacePreserve (qName))
+ whitespace = "preserve";
+ else if (atts != null)
+ whitespace = atts.getValue ("xml:space");
+ if (whitespace == null)
+ whitespace = (String) space.peek ();
+ space.push (whitespace);
+
+ if ("default".equals (whitespace)) {
+ if (xhtml) {
+ if (spaceBefore (qName)) {
+ newline ();
+ doIndent ();
+ } else if (indentBefore (qName))
+ doIndent ();
+ // else it's inlined, modulo line length
+ // FIXME: incrementing element nest level
+ // for inlined elements causes ugliness
+ } else
+ doIndent ();
+ }
+ }
+ elementNestLevel++;
+ writeStartTag (qName, atts, xhtml && isEmptyElementTag (qName));
+
+ if (xhtml) {
+// FIXME: if this is an XHTML "pre" element, turn
+// off automatic wrapping.
+ }
+
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * Writes an empty element.
+ * @see #startElement
+ */
+ public void writeEmptyElement (
+ String uri,
+ String localName,
+ String qName,
+ Attributes atts
+ ) throws SAXException
+ {
+ if (canonical) {
+ startElement (uri, localName, qName, atts);
+ endElement (uri, localName, qName);
+ } else {
+ try {
+ writeStartTag (qName, atts, true);
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+ }
+
+
+ /** SAX2: indicates the end of an element */
+ final public void endElement (String uri, String localName, String qName)
+ throws SAXException
+ {
+ if (qName == null || "".equals (qName))
+ throw new IllegalArgumentException ("no XML name");
+
+ try {
+ elementNestLevel--;
+ if (entityNestLevel != 0)
+ return;
+ if (xhtml && isEmptyElementTag (qName))
+ return;
+ rawWrite ("");
+ rawWrite (qName);
+ rawWrite ('>');
+
+ if (prettyPrinting) {
+ if (!space.empty ())
+ space.pop ();
+ else
+ fatal ("stack discipline", null);
+ }
+ if (elementNestLevel == 0)
+ inEpilogue = true;
+
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** SAX1: reports content characters */
+ final public void characters (char ch [], int start, int length)
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ try {
+ if (entityNestLevel != 0)
+ return;
+ if (inCDATA) {
+ escapeChars (ch, start, length, CTX_UNPARSED);
+ } else {
+ escapeChars (ch, start, length, CTX_CONTENT);
+ }
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** SAX1: reports ignorable whitespace */
+ final public void ignorableWhitespace (char ch [], int start, int length)
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ try {
+ if (entityNestLevel != 0)
+ return;
+ // don't forget to map NL to CRLF, CR, etc
+ escapeChars (ch, start, length, CTX_CONTENT);
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * SAX1: reports a PI.
+ * This doesn't check for illegal target names, such as "xml" or "XML",
+ * or namespace-incompatible ones like "big:dog"; the caller is
+ * responsible for ensuring those names are legal.
+ */
+ final public void processingInstruction (String target, String data)
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ // don't print internal subset for XHTML
+ if (xhtml && startedDoctype)
+ return;
+
+ // ancient HTML browsers might render these ... their loss.
+ // to prevent: "if (xhtml) return;".
+
+ try {
+ if (entityNestLevel != 0)
+ return;
+ if (canonical && inEpilogue)
+ newline ();
+ rawWrite ("");
+ rawWrite (target);
+ rawWrite (' ');
+ escapeChars (data.toCharArray (), -1, -1, CTX_UNPARSED);
+ rawWrite ("?>");
+ if (elementNestLevel == 0 && !(canonical && inEpilogue))
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** SAX1: indicates a non-expanded entity reference */
+ public void skippedEntity (String name)
+ throws SAXException
+ {
+ try {
+ rawWrite ("&");
+ rawWrite (name);
+ rawWrite (";");
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ // SAX2 LexicalHandler
+
+ /** SAX2: called before parsing CDATA characters */
+ final public void startCDATA ()
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ if (canonical)
+ return;
+
+ try {
+ inCDATA = true;
+ if (entityNestLevel == 0)
+ rawWrite ("SAX2: called after parsing CDATA characters */
+ final public void endCDATA ()
+ throws SAXException
+ {
+ if (canonical)
+ return;
+
+ try {
+ inCDATA = false;
+ if (entityNestLevel == 0)
+ rawWrite ("]]>");
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * SAX2: called when the doctype is partially parsed
+ * Note that this, like other doctype related calls, is ignored
+ * when XHTML is in use.
+ */
+ final public void startDTD (String name, String publicId, String systemId)
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+ if (xhtml)
+ return;
+ try {
+ inDoctype = startedDoctype = true;
+ if (canonical)
+ return;
+ rawWrite ("SAX2: called after the doctype is parsed */
+ final public void endDTD ()
+ throws SAXException
+ {
+ inDoctype = false;
+ if (canonical || xhtml)
+ return;
+ try {
+ rawWrite ("]>");
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * SAX2: called before parsing a general entity in content
+ */
+ final public void startEntity (String name)
+ throws SAXException
+ {
+ try {
+ boolean writeEOL = true;
+
+ // Predefined XHTML entities (for characters) will get
+ // mapped back later.
+ if (xhtml || expandingEntities)
+ return;
+
+ entityNestLevel++;
+ if (name.equals ("[dtd]"))
+ return;
+ if (entityNestLevel != 1)
+ return;
+ if (!name.startsWith ("%")) {
+ writeEOL = false;
+ rawWrite ('&');
+ }
+ rawWrite (name);
+ rawWrite (';');
+ if (writeEOL)
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * SAX2: called after parsing a general entity in content
+ */
+ final public void endEntity (String name)
+ throws SAXException
+ {
+ if (xhtml || expandingEntities)
+ return;
+ entityNestLevel--;
+ }
+
+ /**
+ * SAX2: called when comments are parsed.
+ * When XHTML is used, the old HTML tradition of using comments
+ * to for inline CSS, or for JavaScript code is discouraged.
+ * This is because XML processors are encouraged to discard, on
+ * the grounds that comments are for users (and perhaps text
+ * editors) not programs. Instead, use external scripts
+ */
+ final public void comment (char ch [], int start, int length)
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ // don't print internal subset for XHTML
+ if (xhtml && startedDoctype)
+ return;
+ // don't print comment in doctype for canon xml
+ if (canonical && inDoctype)
+ return;
+
+ try {
+ boolean indent;
+
+ if (prettyPrinting && space.empty ())
+ fatal ("stack discipline", null);
+ indent = prettyPrinting && "default".equals (space.peek ());
+ if (entityNestLevel != 0)
+ return;
+ if (indent)
+ doIndent ();
+ if (canonical && inEpilogue)
+ newline ();
+ rawWrite ("");
+ if (indent)
+ doIndent ();
+ if (elementNestLevel == 0 && !(canonical && inEpilogue))
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ // SAX1 DTDHandler
+
+ /** SAX1: called on notation declarations */
+ final public void notationDecl (String name,
+ String publicId, String systemId)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype)
+ return;
+
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("");
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** SAX1: called on unparsed entity declarations */
+ final public void unparsedEntityDecl (String name,
+ String publicId, String systemId,
+ String notationName)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype) {
+ // FIXME: write to temporary buffer, and make the start
+ // of the root element write these declarations.
+ return;
+ }
+
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("");
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ // SAX2 DeclHandler
+
+ /** SAX2: called on attribute declarations */
+ final public void attributeDecl (String eName, String aName,
+ String type, String mode, String value)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype)
+ return;
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("');
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** SAX2: called on element declarations */
+ final public void elementDecl (String name, String model)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype)
+ return;
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("');
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** SAX2: called on external entity declarations */
+ final public void externalEntityDecl (
+ String name,
+ String publicId,
+ String systemId)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype)
+ return;
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("");
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** SAX2: called on internal entity declarations */
+ final public void internalEntityDecl (String name, String value)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype)
+ return;
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("');
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ private void writeQuotedValue (String value, int code)
+ throws SAXException, IOException
+ {
+ char buf [] = value.toCharArray ();
+ int off = 0, len = buf.length;
+
+ // we can't add line breaks to attribute/entity/... values
+ noWrap = true;
+ rawWrite ('"');
+ escapeChars (buf, off, len, code);
+ rawWrite ('"');
+ noWrap = false;
+ }
+
+ // From "HTMLlat1x.ent" ... names of entities for ISO-8859-1
+ // (Latin/1) characters, all codes: 160-255 (0xA0-0xFF).
+ // Codes 128-159 have no assigned values.
+ private static final String HTMLlat1x [] = {
+ // 160
+ "nbsp", "iexcl", "cent", "pound", "curren",
+ "yen", "brvbar", "sect", "uml", "copy",
+
+ // 170
+ "ordf", "laquo", "not", "shy", "reg",
+ "macr", "deg", "plusmn", "sup2", "sup3",
+
+ // 180
+ "acute", "micro", "para", "middot", "cedil",
+ "sup1", "ordm", "raquo", "frac14", "frac12",
+
+ // 190
+ "frac34", "iquest", "Agrave", "Aacute", "Acirc",
+ "Atilde", "Auml", "Aring", "AElig", "Ccedil",
+
+ // 200
+ "Egrave", "Eacute", "Ecirc", "Euml", "Igrave",
+ "Iacute", "Icirc", "Iuml", "ETH", "Ntilde",
+
+ // 210
+ "Ograve", "Oacute", "Ocirc", "Otilde", "Ouml",
+ "times", "Oslash", "Ugrave", "Uacute", "Ucirc",
+
+ // 220
+ "Uuml", "Yacute", "THORN", "szlig", "agrave",
+ "aacute", "acirc", "atilde", "auml", "aring",
+
+ // 230
+ "aelig", "ccedil", "egrave", "eacute", "ecirc",
+ "euml", "igrave", "iacute", "icirc", "iuml",
+
+ // 240
+ "eth", "ntilde", "ograve", "oacute", "ocirc",
+ "otilde", "ouml", "divide", "oslash", "ugrave",
+
+ // 250
+ "uacute", "ucirc", "uuml", "yacute", "thorn",
+ "yuml"
+ };
+
+ // From "HTMLsymbolx.ent" ... some of the symbols that
+ // we can conveniently handle. Entities for the Greek.
+ // alphabet (upper and lower cases) are compact.
+ private static final String HTMLsymbolx_GR [] = {
+ // 913
+ "Alpha", "Beta", "Gamma", "Delta", "Epsilon",
+ "Zeta", "Eta", "Theta", "Iota", "Kappa",
+
+ // 923
+ "Lambda", "Mu", "Nu", "Xi", "Omicron",
+ "Pi", "Rho", null, "Sigma", "Tau",
+
+ // 933
+ "Upsilon", "Phi", "Chi", "Psi", "Omega"
+ };
+
+ private static final String HTMLsymbolx_gr [] = {
+ // 945
+ "alpha", "beta", "gamma", "delta", "epsilon",
+ "zeta", "eta", "theta", "iota", "kappa",
+
+ // 955
+ "lambda", "mu", "nu", "xi", "omicron",
+ "pi", "rho", "sigmaf", "sigma", "tau",
+
+ // 965
+ "upsilon", "phi", "chi", "psi", "omega"
+ };
+
+
+ // General routine to write text and substitute predefined
+ // entities (XML, and a special case for XHTML) as needed.
+ private void escapeChars (char buf [], int off, int len, int code)
+ throws SAXException, IOException
+ {
+ int first = 0;
+
+ if (off < 0) {
+ off = 0;
+ len = buf.length;
+ }
+ for (int i = 0; i < len; i++) {
+ String esc;
+ char c = buf [off + i];
+
+ switch (c) {
+ // Note that CTX_ATTRIBUTE isn't explicitly tested here;
+ // all syntax delimiters are escaped in CTX_ATTRIBUTE,
+ // otherwise it's similar to CTX_CONTENT
+
+ // ampersand flags entity references; entity replacement
+ // text has unexpanded references, other text doesn't.
+ case '&':
+ if (code == CTX_ENTITY || code == CTX_UNPARSED)
+ continue;
+ esc = "amp";
+ break;
+
+ // attributes and text may NOT have literal '<', but
+ // entities may have markup constructs
+ case '<':
+ if (code == CTX_ENTITY || code == CTX_UNPARSED)
+ continue;
+ esc = "lt";
+ break;
+
+ // as above re markup constructs; but otherwise
+ // except when canonicalizing, this is for consistency
+ case '>':
+ if (code == CTX_ENTITY || code == CTX_UNPARSED)
+ continue;
+ esc = "gt";
+ break;
+ case '\'':
+ if (code == CTX_CONTENT || code == CTX_UNPARSED)
+ continue;
+ if (canonical)
+ continue;
+ esc = "apos";
+ break;
+
+ // needed when printing quoted attribute/entity values
+ case '"':
+ if (code == CTX_CONTENT || code == CTX_UNPARSED)
+ continue;
+ esc = "quot";
+ break;
+
+ // make line ends work per host OS convention
+ case '\n':
+ esc = eol;
+ break;
+
+ //
+ // No other characters NEED special treatment ... except
+ // for encoding-specific issues, like whether the character
+ // can really be represented in that encoding.
+ //
+ default:
+ //
+ // There are characters we can never write safely; getting
+ // them is an error.
+ //
+ // (a) They're never legal in XML ... detected by range
+ // checks, and (eventually) by remerging surrogate
+ // pairs on output. (Easy error for apps to prevent.)
+ //
+ // (b) This encoding can't represent them, and we
+ // can't make reference substitution (e.g. inside
+ // CDATA sections, names, PI data, etc). (Hard for
+ // apps to prevent, except by using UTF-8 or UTF-16
+ // as their output encoding.)
+ //
+ // We know a very little bit about what characters
+ // the US-ASCII and ISO-8859-1 encodings support. For
+ // other encodings we can't detect the second type of
+ // error at all. (Never an issue for UTF-8 or UTF-16.)
+ //
+
+// FIXME: CR in CDATA is an error; in text, turn to a char ref
+
+// FIXME: CR/LF/TAB in attributes should become char refs
+
+ if ((c > 0xfffd)
+ || ((c < 0x0020) && !((c == 0x0009)
+ || (c == 0x000A) || (c == 0x000D)))
+ || (((c & dangerMask) != 0)
+ && (code == CTX_UNPARSED))) {
+
+ // if case (b) in CDATA, we might end the section,
+ // write a reference, then restart ... possible
+ // in one DOM L3 draft.
+
+ throw new CharConversionException (
+ "Illegal or non-writable character: U+"
+ + Integer.toHexString (c));
+ }
+
+ //
+ // If the output encoding represents the character
+ // directly, let it do so! Else we'll escape it.
+ //
+ if ((c & dangerMask) == 0)
+ continue;
+ esc = null;
+
+ // Avoid numeric refs where symbolic ones exist, as
+ // symbolic ones make more sense to humans reading!
+ if (xhtml) {
+ // all the HTMLlat1x.ent entities
+ // (all the "ISO-8859-1" characters)
+ if (c >= 160 && c <= 255)
+ esc = HTMLlat1x [c - 160];
+
+ // not quite half the HTMLsymbolx.ent entities
+ else if (c >= 913 && c <= 937)
+ esc = HTMLsymbolx_GR [c - 913];
+ else if (c >= 945 && c <= 969)
+ esc = HTMLsymbolx_gr [c - 945];
+
+ else switch (c) {
+ // all of the HTMLspecialx.ent entities
+ case 338: esc = "OElig"; break;
+ case 339: esc = "oelig"; break;
+ case 352: esc = "Scaron"; break;
+ case 353: esc = "scaron"; break;
+ case 376: esc = "Yuml"; break;
+ case 710: esc = "circ"; break;
+ case 732: esc = "tilde"; break;
+ case 8194: esc = "ensp"; break;
+ case 8195: esc = "emsp"; break;
+ case 8201: esc = "thinsp"; break;
+ case 8204: esc = "zwnj"; break;
+ case 8205: esc = "zwj"; break;
+ case 8206: esc = "lrm"; break;
+ case 8207: esc = "rlm"; break;
+ case 8211: esc = "ndash"; break;
+ case 8212: esc = "mdash"; break;
+ case 8216: esc = "lsquo"; break;
+ case 8217: esc = "rsquo"; break;
+ case 8218: esc = "sbquo"; break;
+ case 8220: esc = "ldquo"; break;
+ case 8221: esc = "rdquo"; break;
+ case 8222: esc = "bdquo"; break;
+ case 8224: esc = "dagger"; break;
+ case 8225: esc = "Dagger"; break;
+ case 8240: esc = "permil"; break;
+ case 8249: esc = "lsaquo"; break;
+ case 8250: esc = "rsaquo"; break;
+ case 8364: esc = "euro"; break;
+
+ // the other HTMLsymbox.ent entities
+ case 402: esc = "fnof"; break;
+ case 977: esc = "thetasym"; break;
+ case 978: esc = "upsih"; break;
+ case 982: esc = "piv"; break;
+ case 8226: esc = "bull"; break;
+ case 8230: esc = "hellip"; break;
+ case 8242: esc = "prime"; break;
+ case 8243: esc = "Prime"; break;
+ case 8254: esc = "oline"; break;
+ case 8260: esc = "frasl"; break;
+ case 8472: esc = "weierp"; break;
+ case 8465: esc = "image"; break;
+ case 8476: esc = "real"; break;
+ case 8482: esc = "trade"; break;
+ case 8501: esc = "alefsym"; break;
+ case 8592: esc = "larr"; break;
+ case 8593: esc = "uarr"; break;
+ case 8594: esc = "rarr"; break;
+ case 8595: esc = "darr"; break;
+ case 8596: esc = "harr"; break;
+ case 8629: esc = "crarr"; break;
+ case 8656: esc = "lArr"; break;
+ case 8657: esc = "uArr"; break;
+ case 8658: esc = "rArr"; break;
+ case 8659: esc = "dArr"; break;
+ case 8660: esc = "hArr"; break;
+ case 8704: esc = "forall"; break;
+ case 8706: esc = "part"; break;
+ case 8707: esc = "exist"; break;
+ case 8709: esc = "empty"; break;
+ case 8711: esc = "nabla"; break;
+ case 8712: esc = "isin"; break;
+ case 8713: esc = "notin"; break;
+ case 8715: esc = "ni"; break;
+ case 8719: esc = "prod"; break;
+ case 8721: esc = "sum"; break;
+ case 8722: esc = "minus"; break;
+ case 8727: esc = "lowast"; break;
+ case 8730: esc = "radic"; break;
+ case 8733: esc = "prop"; break;
+ case 8734: esc = "infin"; break;
+ case 8736: esc = "ang"; break;
+ case 8743: esc = "and"; break;
+ case 8744: esc = "or"; break;
+ case 8745: esc = "cap"; break;
+ case 8746: esc = "cup"; break;
+ case 8747: esc = "int"; break;
+ case 8756: esc = "there4"; break;
+ case 8764: esc = "sim"; break;
+ case 8773: esc = "cong"; break;
+ case 8776: esc = "asymp"; break;
+ case 8800: esc = "ne"; break;
+ case 8801: esc = "equiv"; break;
+ case 8804: esc = "le"; break;
+ case 8805: esc = "ge"; break;
+ case 8834: esc = "sub"; break;
+ case 8835: esc = "sup"; break;
+ case 8836: esc = "nsub"; break;
+ case 8838: esc = "sube"; break;
+ case 8839: esc = "supe"; break;
+ case 8853: esc = "oplus"; break;
+ case 8855: esc = "otimes"; break;
+ case 8869: esc = "perp"; break;
+ case 8901: esc = "sdot"; break;
+ case 8968: esc = "lceil"; break;
+ case 8969: esc = "rceil"; break;
+ case 8970: esc = "lfloor"; break;
+ case 8971: esc = "rfloor"; break;
+ case 9001: esc = "lang"; break;
+ case 9002: esc = "rang"; break;
+ case 9674: esc = "loz"; break;
+ case 9824: esc = "spades"; break;
+ case 9827: esc = "clubs"; break;
+ case 9829: esc = "hearts"; break;
+ case 9830: esc = "diams"; break;
+ }
+ }
+
+ // else escape with numeric char refs
+ if (esc == null) {
+ stringBuf.setLength (0);
+ stringBuf.append ("#x");
+ stringBuf.append (Integer.toHexString (c).toUpperCase ());
+ esc = stringBuf.toString ();
+
+ // FIXME: We don't write surrogate pairs correctly.
+ // They should work as one ref per character, since
+ // each pair is one character. For reading back into
+ // Unicode, it matters beginning in Unicode 3.1 ...
+ }
+ break;
+ }
+ if (i != first)
+ rawWrite (buf, off + first, i - first);
+ first = i + 1;
+ if (esc == eol)
+ newline ();
+ else {
+ rawWrite ('&');
+ rawWrite (esc);
+ rawWrite (';');
+ }
+ }
+ if (first < len)
+ rawWrite (buf, off + first, len - first);
+ }
+
+
+
+ private void newline ()
+ throws SAXException, IOException
+ {
+ out.write (eol);
+ column = 0;
+ }
+
+ private void doIndent ()
+ throws SAXException, IOException
+ {
+ int space = elementNestLevel * 2;
+
+ newline ();
+ column = space;
+ // track tabs only at line starts
+ while (space > 8) {
+ out.write ("\t");
+ space -= 8;
+ }
+ while (space > 0) {
+ out.write (" ");
+ space -= 2;
+ }
+ }
+
+ private void rawWrite (char c)
+ throws IOException
+ {
+ out.write (c);
+ column++;
+ }
+
+ private void rawWrite (String s)
+ throws SAXException, IOException
+ {
+ if (prettyPrinting && "default".equals (space.peek ())) {
+ char data [] = s.toCharArray ();
+ rawWrite (data, 0, data.length);
+ } else {
+ out.write (s);
+ column += s.length ();
+ }
+ }
+
+ // NOTE: if xhtml, the REC gives some rules about whitespace
+ // which we could follow ... notably, many places where conformant
+ // agents "must" consolidate/normalize whitespace. Line ends can
+ // be removed there, etc. This may not be the right place to do
+ // such mappings though.
+
+ // Line buffering may help clarify algorithms and improve results.
+
+ // It's likely xml:space needs more attention.
+
+ private void rawWrite (char buf [], int offset, int length)
+ throws SAXException, IOException
+ {
+ boolean wrap;
+
+ if (prettyPrinting && space.empty ())
+ fatal ("stack discipline", null);
+
+ wrap = prettyPrinting && "default".equals (space.peek ());
+ if (!wrap) {
+ out.write (buf, offset, length);
+ column += length;
+ return;
+ }
+
+ // we're pretty printing and want to fill lines out only
+ // to the desired line length.
+ while (length > 0) {
+ int target = lineLength - column;
+ boolean wrote = false;
+
+ // Do we even have a problem?
+ if (target > length || noWrap) {
+ out.write (buf, offset, length);
+ column += length;
+ return;
+ }
+
+ // break the line at a space character, trying to fill
+ // as much of the line as possible.
+ char c;
+
+ for (int i = target - 1; i >= 0; i--) {
+ if ((c = buf [offset + i]) == ' ' || c == '\t') {
+ i++;
+ out.write (buf, offset, i);
+ doIndent ();
+ offset += i;
+ length -= i;
+ wrote = true;
+ break;
+ }
+ }
+ if (wrote)
+ continue;
+
+ // no space character permitting break before target
+ // line length is filled. So, take the next one.
+ if (target < 0)
+ target = 0;
+ for (int i = target; i < length; i++)
+ if ((c = buf [offset + i]) == ' ' || c == '\t') {
+ i++;
+ out.write (buf, offset, i);
+ doIndent ();
+ offset += i;
+ length -= i;
+ wrote = true;
+ break;
+ }
+ if (wrote)
+ continue;
+
+ // no such luck.
+ out.write (buf, offset, length);
+ column += length;
+ break;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/xml/util/package.html b/libjava/classpath/gnu/xml/util/package.html
new file mode 100644
index 0000000..6e6c0d7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/package.html
@@ -0,0 +1,20 @@
+
+
+ This package contains XML utilities, including SAX2 XML writers
+ and a parser of DOM trees, plus a command line driver.
+ That driver
+ connects parsers simple processing pipelines.
+ It can be handy for command line validation or
+ transformation tasks, possibly in batch mode,
+ or within Makefiles. Programming Models
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Producers: XMLReader or Custom
+
+org.xml.sax.helpers.XMLReaderFactory
) or a DOM tree
+(using a DomParser
)
+These may be bound to event consumer using a convenience routine,
+EventFilter.bind().
+Once bound, these producers may be given additional documents to
+sent through its pipeline.
+
+ Consume to Standard or Custom Data Representations
+
+Pipe Fitting
+
+
+
+
+
+ Coding Conventions: Filter and Terminus Stages
+
+
+
+
+
+ Debugging Tip: "Tee" Joints can Snapshot Data
+
+ Debugging Tip: Non-XML Producers
+
+number
instruction.
+ *
+ * @author Chris Burdess
+ */
+abstract class AbstractNumberNode
+ extends TemplateNode
+{
+
+ static final int ALPHABETIC = 0;
+ static final int TRADITIONAL = 1;
+
+ final TemplateNode format;
+ final String lang;
+ final int letterValue;
+ final String groupingSeparator;
+ final int groupingSize;
+
+ AbstractNumberNode(TemplateNode format, String lang,
+ int letterValue, String groupingSeparator,
+ int groupingSize)
+ {
+ this.format = format;
+ this.lang = lang;
+ this.letterValue = letterValue;
+ this.groupingSeparator = groupingSeparator;
+ this.groupingSize = groupingSize;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ Document doc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ DocumentFragment fragment = doc.createDocumentFragment();
+ format.apply(stylesheet, mode, context, pos, len, fragment, null);
+ String f = Expr._string(context, Collections.singleton(fragment));
+ String value = format(f, compute(stylesheet, context, pos, len));
+ Text text = doc.createTextNode(value);
+ if (nextSibling != null)
+ {
+ parent.insertBefore(text, nextSibling);
+ }
+ else
+ {
+ parent.appendChild(text);
+ }
+ // xsl:number doesn't process children
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ String format(String format, int[] number)
+ {
+ if (number.length == 0)
+ {
+ return "";
+ }
+ int start = 0, end = 0, len = format.length(); // region of format
+ // Tokenize
+ List tokens = new ArrayList((number.length * 2) + 1);
+ List types = new ArrayList(tokens.size());
+ while (end < len)
+ {
+ while (end < len && !isAlphanumeric(format.charAt(end)))
+ {
+ end++;
+ }
+ if (end > start)
+ {
+ tokens.add(format.substring(start, end));
+ types.add(Boolean.FALSE);
+ }
+ start = end;
+ while (end < len && isAlphanumeric(format.charAt(end)))
+ {
+ end++;
+ }
+ if (end > start)
+ {
+ tokens.add(format.substring(start, end));
+ types.add(Boolean.TRUE);
+ }
+ start = end;
+ }
+ // Process tokens
+ StringBuffer buf = new StringBuffer();
+ len = tokens.size();
+ int pos = 0;
+ for (int i = 0; i < len; i++)
+ {
+ String token = (i < 0) ? "." : (String) tokens.get(i);
+ boolean alpha = (i < 0) ? true :
+ ((Boolean) types.get(i)).booleanValue();
+ if (!alpha)
+ {
+ buf.append(token);
+ }
+ else
+ {
+ if (pos < number.length)
+ {
+ format(buf, number[pos++], token);
+ if (((i + 1 == len) || (i + 2 == len)) &&
+ (pos < number.length))
+ {
+ // More numbers than tokens, reuse last token
+ i -= 2;
+ }
+ }
+ if (pos == number.length && i < (len - 2))
+ {
+ // No more numbers. Skip to the end...
+ i = len - 2;
+ if (((Boolean) types.get(i + 1)).booleanValue())
+ {
+ // number formatting token, ignore
+ i++;
+ }
+ }
+ }
+ }
+ //System.err.println("format: '"+format+"' "+asList(number)+" = '"+buf.toString()+"'");
+ return buf.toString();
+ }
+
+ /*List asList(int[] number)
+ {
+ List l = new ArrayList();
+ for (int i = 0; i < number.length; i++)
+ l.add(new Integer(number[i]));
+ return l;
+ }*/
+
+ void format(StringBuffer buf, int number, String formatToken)
+ {
+ int len = formatToken.length();
+ char c = formatToken.charAt(len - 1);
+ if (Character.digit(c, 10) == 1)
+ {
+ // Check preceding characters
+ for (int i = len - 2; i >= 0; i--)
+ {
+ if (formatToken.charAt(i) != (c - 1))
+ {
+ format(buf, number, "1");
+ return;
+ }
+ }
+ // Decimal representation
+ String val = Integer.toString(number);
+ for (int d = len - val.length(); d > 0; d--)
+ {
+ buf.append('0');
+ }
+ buf.append(val);
+ }
+ else if ("A".equals(formatToken))
+ {
+ buf.append(alphabetic('@', number));
+ }
+ else if ("a".equals(formatToken))
+ {
+ buf.append(alphabetic('`', number));
+ }
+ else if ("i".equals(formatToken))
+ {
+ buf.append(roman(false, number));
+ }
+ else if ("I".equals(formatToken))
+ {
+ buf.append(roman(true, number));
+ }
+ else
+ {
+ // Unknown numbering sequence
+ format(buf, number, "1");
+ }
+ }
+
+ static final boolean isAlphanumeric(char c)
+ {
+ switch (Character.getType(c))
+ {
+ case Character.DECIMAL_DIGIT_NUMBER: // Nd
+ case Character.LETTER_NUMBER: // Nl
+ case Character.OTHER_NUMBER: // No
+ case Character.UPPERCASE_LETTER: // Lu
+ case Character.LOWERCASE_LETTER: // Ll
+ case Character.TITLECASE_LETTER: // Lt
+ case Character.MODIFIER_LETTER: // Lm
+ case Character.OTHER_LETTER: // Lo
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static final String alphabetic(char offset, int number)
+ {
+ StringBuffer buf = new StringBuffer();
+ while (number > 0)
+ {
+ int r = number % 26;
+ number = number / 26;
+ buf.insert(0, (char) (offset + r));
+ }
+ return buf.toString();
+ }
+
+ static final int[] roman_numbers = {1, 5, 10, 50, 100, 500, 1000};
+ static final char[] roman_chars = {'i', 'v', 'x', 'l', 'c', 'd', 'm'};
+
+ static final String roman(boolean upper, int number)
+ {
+ StringBuffer buf = new StringBuffer();
+ for (int pos = roman_numbers.length - 1; pos >= 0; pos -= 2)
+ {
+ int f = number / roman_numbers[pos];
+ if (f != 0)
+ {
+ number = number % (f * roman_numbers[pos]);
+ }
+ if (f > 4 && f < 9)
+ {
+ buf.append(roman_chars[pos + 1]);
+ f -= 5;
+ }
+ if (f == 4)
+ {
+ buf.append(roman_chars[pos]);
+ buf.append(roman_chars[pos + 1]);
+ }
+ else if (f == 9)
+ {
+ buf.append(roman_chars[pos]);
+ buf.append(roman_chars[pos + 2]);
+ }
+ else
+ {
+ for (; f > 0; f--)
+ {
+ buf.append(roman_chars[pos]);
+ }
+ }
+ }
+ return upper ? buf.toString().toUpperCase() : buf.toString();
+ }
+
+ abstract int[] compute(Stylesheet stylesheet, Node context, int pos, int len)
+ throws TransformerException;
+
+ public boolean references(QName var)
+ {
+ if (format.references(var))
+ {
+ return true;
+ }
+ return super.references(var);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("format=");
+ buf.append(format);
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/ApplyImportsNode.java b/libjava/classpath/gnu/xml/transform/ApplyImportsNode.java
new file mode 100644
index 0000000..60dec85
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/ApplyImportsNode.java
@@ -0,0 +1,86 @@
+/* ApplyImportsNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+
+/**
+ * A template node representing an XSLT apply-imports
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class ApplyImportsNode
+ extends TemplateNode
+{
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new ApplyImportsNode();
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ TemplateNode t = stylesheet.getTemplate(mode, context, true);
+ if (t != null)
+ {
+ t.apply(stylesheet, mode, context, pos, len,
+ parent, nextSibling);
+ }
+ if (next != null)
+ {
+ next.apply(stylesheet, mode, context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java b/libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java
new file mode 100644
index 0000000..ab26058
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java
@@ -0,0 +1,235 @@
+/* ApplyTemplatesNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing the XSL apply-templates
+ * instruction.
+ *
+ * @author Chris Burdess
+ */
+final class ApplyTemplatesNode
+ extends TemplateNode
+{
+
+ final Expr select;
+ final QName mode;
+ final List sortKeys;
+ final List withParams;
+ final boolean isDefault;
+
+ ApplyTemplatesNode(Expr select, QName mode,
+ List sortKeys, List withParams, boolean isDefault)
+ {
+ this.select = select;
+ this.mode = mode;
+ this.sortKeys = sortKeys;
+ this.withParams = withParams;
+ this.isDefault = isDefault;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ int len = sortKeys.size();
+ List sortKeys2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ sortKeys2.add(((Key) sortKeys.get(i)).clone(stylesheet));
+ }
+ len = withParams.size();
+ List withParams2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ withParams2.add(((WithParam) withParams.get(i)).clone(stylesheet));
+ }
+ TemplateNode ret = new ApplyTemplatesNode(select.clone(stylesheet),
+ mode, sortKeys2, withParams2,
+ isDefault);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ Object ret = select.evaluate(context, pos, len);
+ if (ret != null && ret instanceof Collection)
+ {
+ if (withParams != null)
+ {
+ // compute the parameter values
+ LinkedList values = new LinkedList();
+ for (Iterator i = withParams.iterator(); i.hasNext(); )
+ {
+ WithParam p = (WithParam) i.next();
+ Object value = p.getValue(stylesheet, mode, context, pos, len);
+ Object[] pair = new Object[2];
+ pair[0] = p.name;
+ pair[1] = value;
+ values.add(pair);
+ }
+ // push the parameter context
+ stylesheet.bindings.push(Bindings.WITH_PARAM);
+ // set the parameters
+ for (Iterator i = values.iterator(); i.hasNext(); )
+ {
+ Object[] pair = (Object[]) i.next();
+ QName name = (QName) pair[0];
+ Object value = pair[1];
+ stylesheet.bindings.set(name, value, Bindings.WITH_PARAM);
+ }
+ }
+ Collection ns = (Collection) ret;
+ List nodes = new ArrayList(ns);
+ if (sortKeys != null)
+ {
+ for (Iterator i = sortKeys.iterator(); i.hasNext(); )
+ {
+ SortKey sortKey = (SortKey) i.next();
+ sortKey.init(stylesheet, mode, context, pos, len, parent,
+ nextSibling);
+ }
+ Collections.sort(nodes, new XSLComparator(sortKeys));
+ }
+ else
+ {
+ Collections.sort(nodes, documentOrderComparator);
+ }
+ int l = nodes.size();
+ QName effectiveMode = isDefault ? mode : this.mode;
+ for (int i = 0; i < l; i++)
+ {
+ Node node = (Node) nodes.get(i);
+ TemplateNode t = stylesheet.getTemplate(effectiveMode, node,
+ false);
+ if (t != null)
+ {
+ stylesheet.current = node;
+ t.apply(stylesheet, effectiveMode, node, i + 1, l,
+ parent, nextSibling);
+ }
+ }
+ if (withParams != null)
+ {
+ // pop the variable context
+ stylesheet.bindings.pop(Bindings.WITH_PARAM);
+ }
+ }
+ // apply-templates doesn't have processable children
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public boolean references(QName var)
+ {
+ if (select != null && select.references(var))
+ {
+ return true;
+ }
+ if (withParams != null)
+ {
+ for (Iterator i = withParams.iterator(); i.hasNext(); )
+ {
+ if (((WithParam) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ }
+ if (sortKeys != null)
+ {
+ for (Iterator i = sortKeys.iterator(); i.hasNext(); )
+ {
+ if (((SortKey) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ }
+ return super.references(var);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ boolean o = false;
+ if (select != null)
+ {
+ buf.append("select=");
+ buf.append(select);
+ o = true;
+ }
+ if (mode != null)
+ {
+ if (o)
+ {
+ buf.append(',');
+ }
+ buf.append("mode=");
+ buf.append(mode);
+ }
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/AttributeNode.java b/libjava/classpath/gnu/xml/transform/AttributeNode.java
new file mode 100644
index 0000000..1e0eb1e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/AttributeNode.java
@@ -0,0 +1,264 @@
+/* AttributeNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing an XSL attribute
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class AttributeNode
+ extends TemplateNode
+{
+
+ final TemplateNode name;
+ final TemplateNode namespace;
+ final Node source;
+
+ AttributeNode(TemplateNode name,
+ TemplateNode namespace, Node source)
+ {
+ this.name = name;
+ this.namespace = namespace;
+ this.source = source;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new AttributeNode(name.clone(stylesheet),
+ (namespace == null) ? null :
+ namespace.clone(stylesheet),
+ source);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ Document doc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ // Create a document fragment to hold the name
+ DocumentFragment fragment = doc.createDocumentFragment();
+ // Apply name to the fragment
+ name.apply(stylesheet, mode,
+ context, pos, len,
+ fragment, null);
+ // Use XPath string-value of fragment
+ String nameValue = Expr.stringValue(fragment);
+
+ String namespaceValue = null;
+ if (namespace != null)
+ {
+ // Create a document fragment to hold the namespace
+ fragment = doc.createDocumentFragment();
+ // Apply namespace to the fragment
+ namespace.apply(stylesheet, mode,
+ context, pos, len,
+ fragment, null);
+ // Use XPath string-value of fragment
+ namespaceValue = Expr.stringValue(fragment);
+ if (namespaceValue.length() == 0)
+ {
+ namespaceValue = null;
+ }
+ }
+
+ String prefix = getPrefix(nameValue);
+ if (namespaceValue == null)
+ {
+ if (prefix != null)
+ {
+ if (XMLConstants.XML_NS_PREFIX.equals(prefix))
+ {
+ namespaceValue = XMLConstants.XML_NS_URI;
+ }
+ else
+ {
+ // Resolve namespace for this prefix
+ namespaceValue = source.lookupNamespaceURI(prefix);
+ }
+ }
+ }
+ else
+ {
+ if (prefix != null)
+ {
+ String ns2 = source.lookupNamespaceURI(prefix);
+ if (ns2 != null && !ns2.equals(namespaceValue))
+ {
+ // prefix clashes, reset it
+ prefix = null;
+ int ci = nameValue.indexOf(':');
+ nameValue = nameValue.substring(ci + 1);
+ }
+ }
+ }
+ if (prefix == null)
+ {
+ // Resolve prefix for this namespace
+ prefix = source.lookupPrefix(namespaceValue);
+ if (prefix != null)
+ {
+ nameValue = prefix + ":" + nameValue;
+ }
+ else
+ {
+ if (namespaceValue != null)
+ {
+ // Must invent a prefix
+ prefix = inventPrefix(parent);
+ nameValue = prefix + ":" + nameValue;
+ }
+ }
+ }
+ NamedNodeMap attrs = parent.getAttributes();
+ boolean insert = true;
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceValue) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(nameValue) ||
+ nameValue.startsWith("xmlns:"))
+ {
+ // Namespace declaration, do not output
+ insert = false;
+ }
+ if (prefix != null && namespaceValue == null)
+ {
+ // Not a QName
+ insert = false;
+ }
+ if (parent.getNodeType() == Node.ELEMENT_NODE &&
+ parent.getFirstChild() != null)
+ {
+ // XSLT 7.1.3 Adding an attribute to an element after children have
+ // been added to it is an error
+ insert = false;
+ }
+ if (insert)
+ {
+ // Insert attribute
+ Attr attr = (namespaceValue != null) ?
+ doc.createAttributeNS(namespaceValue, nameValue) :
+ doc.createAttribute(nameValue);
+ if (attrs != null)
+ {
+ if (namespace != null)
+ {
+ attrs.setNamedItemNS(attr);
+ }
+ else
+ {
+ attrs.setNamedItem(attr);
+ }
+ }
+ if (children != null)
+ {
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ attr, null);
+ }
+ }
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ final String getPrefix(String name)
+ {
+ int ci = name.indexOf(':');
+ return (ci == -1) ? null : name.substring(0, ci);
+ }
+
+ final String inventPrefix(Node parent)
+ {
+ String base = "ns";
+ int count = 0;
+ String ret = base + Integer.toString(count);
+ while (parent.lookupNamespaceURI(ret) != null)
+ {
+ count++;
+ ret = base + Integer.toString(count);
+ }
+ return ret;
+ }
+
+ public boolean references(QName var)
+ {
+ if (name != null && name.references(var))
+ {
+ return true;
+ }
+ if (namespace != null && namespace.references(var))
+ {
+ return true;
+ }
+ return super.references(var);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("name=");
+ buf.append(name);
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/AttributeSet.java b/libjava/classpath/gnu/xml/transform/AttributeSet.java
new file mode 100644
index 0000000..3ece9c8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/AttributeSet.java
@@ -0,0 +1,67 @@
+/* AttributeSet.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+/**
+ * An attribute-set entry in a stylesheet.
+ *
+ * @author Chris Burdess
+ */
+final class AttributeSet
+{
+
+ final TemplateNode children;
+ final String name;
+ final String uas;
+
+ AttributeSet(TemplateNode children, String name, String uas)
+ {
+ this.children = children;
+ this.name = name;
+ this.uas = uas;
+ }
+
+ AttributeSet clone(Stylesheet stylesheet)
+ {
+ return new AttributeSet((children == null) ? null :
+ children.clone(stylesheet),
+ name, uas);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/Bindings.java b/libjava/classpath/gnu/xml/transform/Bindings.java
new file mode 100644
index 0000000..c372ea8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/Bindings.java
@@ -0,0 +1,325 @@
+/* Bindings.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathVariableResolver;
+import org.w3c.dom.Node;
+
+/**
+ * The set of variable bindings in effect for a stylesheet.
+ *
+ * @author Chris Burdess
+ */
+public class Bindings
+ implements XPathVariableResolver, Cloneable
+{
+
+ static final int VARIABLE = 0;
+ static final int PARAM = 1;
+ static final int WITH_PARAM = 2;
+
+ final Stylesheet stylesheet;
+
+ /**
+ * Global variables.
+ */
+ final LinkedList variables;
+
+ /**
+ * Parameter value stack.
+ */
+ final LinkedList parameters;
+
+ /**
+ * Argument (with-param) value stack.
+ */
+ final LinkedList withParameters;
+
+ Bindings(Stylesheet stylesheet)
+ {
+ this.stylesheet = stylesheet;
+ variables = new LinkedList();
+ parameters = new LinkedList();
+ withParameters = new LinkedList();
+ for (int i = 0; i < 3; i++)
+ {
+ push(i);
+ }
+ }
+
+ public Object clone()
+ {
+ try
+ {
+ return (Bindings) super.clone();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new Error(e.getMessage());
+ }
+ }
+
+ void push(int type)
+ {
+ switch (type)
+ {
+ case VARIABLE:
+ variables.addFirst(new HashMap());
+ break;
+ case PARAM:
+ parameters.addFirst(new HashMap());
+ break;
+ case WITH_PARAM:
+ withParameters.addFirst(new HashMap());
+ break;
+ }
+ }
+
+ void pop(int type)
+ {
+ switch (type)
+ {
+ case VARIABLE:
+ variables.removeFirst();
+ break;
+ case PARAM:
+ parameters.removeFirst();
+ break;
+ case WITH_PARAM:
+ withParameters.removeFirst();
+ break;
+ }
+ }
+
+ public boolean containsKey(QName name, int type)
+ {
+ Iterator i = null;
+ switch (type)
+ {
+ case VARIABLE:
+ i = variables.iterator();
+ break;
+ case PARAM:
+ i = parameters.iterator();
+ break;
+ case WITH_PARAM:
+ Map ctx = (Map) withParameters.getFirst();
+ return ctx.containsKey(name);
+ }
+ if (i != null)
+ {
+ while (i.hasNext())
+ {
+ Map ctx = (Map) i.next();
+ if (ctx.containsKey(name))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public Object get(QName name, Node context, int pos, int len)
+ {
+ //System.err.println("bindings.get: "+name);
+ //System.err.println("\t"+toString());
+ Object ret = null;
+ //if (parameters.size() > 1 && containsKey(name, PARAM))
+ // check that template defines parameter
+ {
+ Map cwp = (Map) withParameters.getFirst();
+ ret = cwp.get(name);
+ //System.err.println("\twith-param: ret="+ret);
+ }
+ if (ret == null)
+ {
+ for (Iterator i = variables.iterator(); i.hasNext() && ret == null; )
+ {
+ Map vctx = (Map) i.next();
+ ret = vctx.get(name);
+ }
+ //System.err.println("\tvariable: ret="+ret);
+ }
+ if (ret == null)
+ {
+ for (Iterator i = parameters.iterator(); i.hasNext() && ret == null; )
+ {
+ Map pctx = (Map) i.next();
+ ret = pctx.get(name);
+ }
+ //System.err.println("\tparam: ret="+ret);
+ }
+ /*if (ret instanceof Expr && context != null)
+ {
+ Expr expr = (Expr) ret;
+ ret = expr.evaluate(context, 1, 1);
+ }*/
+ if (ret instanceof Node)
+ {
+ ret = Collections.singleton(ret);
+ }
+ if (ret == null)
+ {
+ ret = "";
+ }
+ //System.err.println("\tret="+ret);
+ return ret;
+ }
+
+ void set(QName name, Object value, int type)
+ {
+ switch (type)
+ {
+ case VARIABLE:
+ Map vctx = (Map) variables.getFirst();
+ vctx.put(name, value);
+ break;
+ case PARAM:
+ Map pctx = (Map) parameters.getFirst();
+ pctx.put(name, value);
+ break;
+ case WITH_PARAM:
+ Map wctx = (Map) withParameters.getFirst();
+ wctx.put(name, value);
+ break;
+ }
+ //System.err.println("Set "+name+"="+value);
+ }
+
+ public Object resolveVariable(QName qName)
+ {
+ return get(qName, null, 1, 1);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ boolean next = false;
+ Collection seen = new HashSet();
+ Map wctx = (Map) withParameters.getFirst();
+ buf.append('(');
+ for (Iterator i = wctx.entrySet().iterator(); i.hasNext(); )
+ {
+ if (next)
+ {
+ buf.append(',');
+ }
+ else
+ {
+ next = true;
+ }
+ Map.Entry entry = (Map.Entry) i.next();
+ Object key = entry.getKey();
+ if (!seen.contains(key))
+ {
+ buf.append(key);
+ buf.append('=');
+ buf.append(entry.getValue());
+ seen.add(key);
+ }
+ }
+ buf.append(')');
+ next = false;
+ seen.clear();
+ buf.append('{');
+ for (Iterator i = variables.iterator(); i.hasNext(); )
+ {
+ Map ctx = (Map) i.next();
+ for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); )
+ {
+ if (next)
+ {
+ buf.append(',');
+ }
+ else
+ {
+ next = true;
+ }
+ Map.Entry entry = (Map.Entry) j.next();
+ Object key = entry.getKey();
+ if (!seen.contains(key))
+ {
+ buf.append(key);
+ buf.append('=');
+ buf.append(entry.getValue());
+ seen.add(key);
+ }
+ }
+ }
+ buf.append('}');
+ next = false;
+ seen.clear();
+ buf.append('[');
+ for (Iterator i = parameters.iterator(); i.hasNext(); )
+ {
+ Map ctx = (Map) i.next();
+ for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); )
+ {
+ if (next)
+ {
+ buf.append(',');
+ }
+ else
+ {
+ next = true;
+ }
+ Map.Entry entry = (Map.Entry) j.next();
+ Object key = entry.getKey();
+ if (!seen.contains(key))
+ {
+ buf.append(key);
+ buf.append('=');
+ buf.append(entry.getValue());
+ seen.add(key);
+ }
+ }
+ }
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/CallTemplateNode.java b/libjava/classpath/gnu/xml/transform/CallTemplateNode.java
new file mode 100644
index 0000000..b678219
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/CallTemplateNode.java
@@ -0,0 +1,165 @@
+/* CallTemplateNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+
+/**
+ * A template node representing the XSL call-template
+ * instruction.
+ *
+ * @author Chris Burdess
+ */
+final class CallTemplateNode
+ extends TemplateNode
+{
+
+ final QName name;
+ final List withParams;
+
+ CallTemplateNode(QName name, List withParams)
+ {
+ this.name = name;
+ this.withParams = withParams;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ int len = withParams.size();
+ List withParams2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ withParams2.add(((WithParam) withParams.get(i)).clone(stylesheet));
+ }
+ TemplateNode ret = new CallTemplateNode(name, withParams2);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ if (withParams != null)
+ {
+ // compute the parameter values
+ LinkedList values = new LinkedList();
+ for (Iterator i = withParams.iterator(); i.hasNext(); )
+ {
+ WithParam p = (WithParam) i.next();
+ Object value = p.getValue(stylesheet, mode, context, pos, len);
+ Object[] pair = new Object[2];
+ pair[0] = p.name;
+ pair[1] = value;
+ values.add(pair);
+ }
+ // push the parameter context
+ stylesheet.bindings.push(Bindings.WITH_PARAM);
+ // set the parameters
+ for (Iterator i = values.iterator(); i.hasNext(); )
+ {
+ Object[] pair = (Object[]) i.next();
+ QName name = (QName) pair[0];
+ Object value = pair[1];
+ stylesheet.bindings.set(name, value, Bindings.WITH_PARAM);
+ if (stylesheet.debug)
+ {
+ System.err.println("with-param: " + name + " = " + value);
+ }
+ }
+ }
+ TemplateNode t = stylesheet.getTemplate(mode, name);
+ if (t != null)
+ {
+ t.apply(stylesheet, mode, context, pos, len,
+ parent, nextSibling);
+ }
+ if (withParams != null)
+ {
+ // pop the variable context
+ stylesheet.bindings.pop(Bindings.WITH_PARAM);
+ }
+ // call-template doesn't have processable children
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public boolean references(QName var)
+ {
+ if (withParams != null)
+ {
+ for (Iterator i = withParams.iterator(); i.hasNext(); )
+ {
+ if (((WithParam) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ }
+ return super.references(var);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("name=");
+ buf.append(name);
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/ChooseNode.java b/libjava/classpath/gnu/xml/transform/ChooseNode.java
new file mode 100644
index 0000000..fb1f2c4
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/ChooseNode.java
@@ -0,0 +1,94 @@
+/* ChooseNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+
+/**
+ * A template node representing an XSL choose
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class ChooseNode
+ extends TemplateNode
+{
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new ChooseNode();
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ if (children != null)
+ {
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/CommentNode.java b/libjava/classpath/gnu/xml/transform/CommentNode.java
new file mode 100644
index 0000000..1428a46
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/CommentNode.java
@@ -0,0 +1,116 @@
+/* CommentNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing the XSL comment
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class CommentNode
+ extends TemplateNode
+{
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new CommentNode();
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ String value = "";
+ Document doc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ if (children != null)
+ {
+ // Create a document fragment to hold the text
+ DocumentFragment fragment = doc.createDocumentFragment();
+ // Apply children to the fragment
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ fragment, null);
+ // Use XPath string-value of fragment
+ value = Expr.stringValue(fragment);
+ }
+ Comment comment = doc.createComment(value);
+ // Insert into result tree
+ if (nextSibling != null)
+ {
+ parent.insertBefore(comment, nextSibling);
+ }
+ else
+ {
+ parent.appendChild(comment);
+ }
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/CopyNode.java b/libjava/classpath/gnu/xml/transform/CopyNode.java
new file mode 100644
index 0000000..3e01944
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/CopyNode.java
@@ -0,0 +1,183 @@
+/* CopyNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.Iterator;
+import java.util.StringTokenizer;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ * A template node representing the XSL copy
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class CopyNode
+ extends TemplateNode
+{
+
+ final String uas;
+
+ CopyNode(String uas)
+ {
+ this.uas = uas;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new CopyNode(uas);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ Node copy = parent;
+ switch (context.getNodeType())
+ {
+ case Node.TEXT_NODE:
+ case Node.ATTRIBUTE_NODE:
+ case Node.ELEMENT_NODE:
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ case Node.COMMENT_NODE:
+ Document doc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ copy = context.cloneNode(false);
+ copy = doc.adoptNode(copy);
+ if (copy.getNodeType() == Node.ATTRIBUTE_NODE)
+ {
+ if (parent.getFirstChild() != null)
+ {
+ // Ignore attempt to add attribute after children
+ }
+ else
+ {
+ NamedNodeMap attrs = parent.getAttributes();
+ if (attrs != null)
+ {
+ attrs.setNamedItemNS(copy);
+ }
+ }
+ }
+ else
+ {
+ if (nextSibling != null)
+ {
+ parent.insertBefore(copy, nextSibling);
+ }
+ else
+ {
+ parent.appendChild(copy);
+ }
+ }
+ }
+ if (uas != null)
+ {
+ StringTokenizer st = new StringTokenizer(uas, " ");
+ while (st.hasMoreTokens())
+ {
+ addAttributeSet(stylesheet, mode, context, pos, len,
+ copy, null, st.nextToken());
+ }
+ }
+ if (children != null)
+ {
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ copy, null);
+ }
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ void addAttributeSet(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling, String attributeSet)
+ throws TransformerException
+ {
+ for (Iterator i = stylesheet.attributeSets.iterator(); i.hasNext(); )
+ {
+ AttributeSet as = (AttributeSet) i.next();
+ if (!as.name.equals(attributeSet))
+ {
+ continue;
+ }
+ if (as.uas != null)
+ {
+ StringTokenizer st = new StringTokenizer(as.uas, " ");
+ while (st.hasMoreTokens())
+ {
+ addAttributeSet(stylesheet, mode, context, pos, len,
+ parent, nextSibling, st.nextToken());
+ }
+ }
+ if (as.children != null)
+ {
+ as.children.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/CopyOfNode.java b/libjava/classpath/gnu/xml/transform/CopyOfNode.java
new file mode 100644
index 0000000..a43e3ba
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/CopyOfNode.java
@@ -0,0 +1,192 @@
+/* CopyOfNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing an XSLT copy-of
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class CopyOfNode
+ extends TemplateNode
+{
+
+ final Expr select;
+
+ CopyOfNode(Expr select)
+ {
+ this.select = select;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new CopyOfNode(select.clone(stylesheet));
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ Object ret = select.evaluate(context, pos, len);
+ Document doc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ if (ret instanceof Collection)
+ {
+ Collection ns = (Collection) ret;
+ List list = new ArrayList(ns);
+ Collections.sort(list, documentOrderComparator);
+ for (Iterator i = list.iterator(); i.hasNext(); )
+ {
+ Node src = (Node) i.next();
+ short nodeType = src.getNodeType();
+ if (nodeType == Node.DOCUMENT_NODE)
+ {
+ // Use document element
+ src = ((Document) src).getDocumentElement();
+ if (src == null)
+ {
+ continue;
+ }
+ nodeType = Node.ELEMENT_NODE;
+ }
+ else if (nodeType == Node.ATTRIBUTE_NODE)
+ {
+ if (parent.getFirstChild() != null)
+ {
+ // Ignore attempt to add attribute after children
+ continue;
+ }
+ }
+ if (parent.getNodeType() == Node.ATTRIBUTE_NODE &&
+ nodeType != Node.TEXT_NODE &&
+ nodeType != Node.ENTITY_REFERENCE_NODE)
+ {
+ // Ignore
+ continue;
+ }
+ Node node = src.cloneNode(true);
+ node = doc.adoptNode(node);
+ if (nodeType == Node.ATTRIBUTE_NODE)
+ {
+ NamedNodeMap attrs = parent.getAttributes();
+ if (attrs != null)
+ {
+ attrs.setNamedItemNS(node);
+ }
+ }
+ else
+ {
+ if (nextSibling != null)
+ {
+ parent.insertBefore(node, nextSibling);
+ }
+ else
+ {
+ parent.appendChild(node);
+ }
+ }
+ }
+ }
+ else
+ {
+ String value = Expr._string(context, ret);
+ if (value != null && value.length() > 0)
+ {
+ Text textNode = doc.createTextNode(value);
+ if (nextSibling != null)
+ {
+ parent.insertBefore(textNode, nextSibling);
+ }
+ else
+ {
+ parent.appendChild(textNode);
+ }
+ }
+ }
+ // copy-of doesn't process children
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public boolean references(QName var)
+ {
+ if (select != null && select.references(var))
+ {
+ return true;
+ }
+ return super.references(var);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("select=");
+ buf.append(select);
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/CurrentFunction.java b/libjava/classpath/gnu/xml/transform/CurrentFunction.java
new file mode 100644
index 0000000..0395396
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/CurrentFunction.java
@@ -0,0 +1,104 @@
+/* CurrentFunction.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.Collections;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Function;
+
+/**
+ * The XSLT current()
function.
+ *
+ * @author Chris Burdess
+ */
+final class CurrentFunction
+ extends Expr
+ implements Function, XPathFunction
+{
+
+ final Stylesheet stylesheet;
+
+ CurrentFunction(Stylesheet stylesheet)
+ {
+ this.stylesheet = stylesheet;
+ }
+
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ // We can't do anything useful here.
+ // So much for the JAXP API...
+ return Collections.EMPTY_SET;
+ }
+
+ public void setArguments(List args)
+ {
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return Collections.singleton(stylesheet.current);
+ }
+
+ public Expr clone(Object context)
+ {
+ Stylesheet s = stylesheet;
+ if (context instanceof Stylesheet)
+ {
+ s = (Stylesheet) context;
+ }
+ return new CurrentFunction(s);
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "current()";
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/DOMSourceLocator.java b/libjava/classpath/gnu/xml/transform/DOMSourceLocator.java
new file mode 100644
index 0000000..9bc8fb1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/DOMSourceLocator.java
@@ -0,0 +1,84 @@
+/* DOMSourceLocator.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.transform.dom.DOMLocator;
+import org.w3c.dom.Node;
+
+/**
+ * Simple DOMLocator implementation.
+ *
+ * @author Chris Burdess
+ */
+class DOMSourceLocator
+ implements DOMLocator
+{
+
+ final Node node;
+
+ DOMSourceLocator(Node node)
+ {
+ this.node = node;
+ }
+
+ public Node getOriginatingNode()
+ {
+ return node;
+ }
+
+ public String getPublicId()
+ {
+ return null;
+ }
+
+ public String getSystemId()
+ {
+ return null;
+ }
+
+ public int getLineNumber()
+ {
+ return -1;
+ }
+
+ public int getColumnNumber()
+ {
+ return -1;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/DocumentFunction.java b/libjava/classpath/gnu/xml/transform/DocumentFunction.java
new file mode 100644
index 0000000..d8f6090
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/DocumentFunction.java
@@ -0,0 +1,256 @@
+/* DocumentFunction.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TreeSet;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Constant;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Function;
+import gnu.xml.xpath.IdFunction;
+
+/**
+ * The XSLT document()
function.
+ *
+ * @author Chris Burdess
+ */
+final class DocumentFunction
+ extends Expr
+ implements Function, XPathFunction
+{
+
+ final Stylesheet stylesheet;
+ final Node base;
+ List args;
+ List values;
+
+ DocumentFunction(Stylesheet stylesheet, Node base)
+ {
+ this.stylesheet = stylesheet;
+ this.base = base;
+ }
+
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ values = args;
+ return evaluate(null, 1, 1);
+ }
+
+ public void setArguments(List args)
+ {
+ this.args = args;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ int arity = args.size();
+ if (values == null)
+ {
+ values = new ArrayList(arity);
+ for (int i = 0; i < arity; i++)
+ {
+ Expr arg = (Expr) args.get(i);
+ values.add(arg.evaluate(context, pos, len));
+ }
+ }
+ Object ret;
+ switch (arity)
+ {
+ case 1:
+ Object arg = values.get(0);
+ if (arg instanceof Collection)
+ {
+ Collection ns = (Collection) arg;
+ Collection acc = new TreeSet();
+ for (Iterator i = ns.iterator(); i.hasNext(); )
+ {
+ Node node = (Node) i.next();
+ String s = Expr.stringValue(node);
+ acc.addAll(document(s, node.getBaseURI()));
+ }
+ ret = acc;
+ }
+ else
+ {
+ String s = Expr._string(context, arg);
+ ret = document(s, base.getBaseURI());
+ }
+ break;
+ case 2:
+ Object arg1 = values.get(0);
+ Object arg2 = values.get(1);
+ if (!(arg2 instanceof Collection))
+ {
+ throw new RuntimeException("second argument is not a node-set");
+ }
+ Collection arg2ns = (Collection) arg2;
+ String base2 = arg2ns.isEmpty() ? null :
+ ((Node) arg2ns.iterator().next()).getBaseURI();
+ if (arg1 instanceof Collection)
+ {
+ Collection arg1ns = (Collection) arg1;
+ Collection acc = new TreeSet();
+ for (Iterator i = arg1ns.iterator(); i.hasNext(); )
+ {
+ Node node = (Node) i.next();
+ String s = Expr.stringValue(node);
+ acc.addAll(document(s, base2));
+ }
+ ret = acc;
+ }
+ else
+ {
+ String s = Expr._string(context, arg1);
+ ret = document(s, base2);
+ }
+ break;
+ default:
+ throw new RuntimeException("invalid arity");
+ }
+ values = null;
+ return ret;
+ }
+
+ /**
+ * The XSL document
function.
+ * @see XSLT 12.1
+ * @param uri the URI from which to retrieve nodes
+ * @param base the base URI for relative URIs
+ */
+ Collection document(String uri, String base)
+ {
+ if ("".equals(uri) || uri == null)
+ {
+ uri = this.base.getBaseURI();
+ }
+
+ // Get fragment
+ Expr fragment = null;
+ int hi = uri.indexOf('#');
+ if (hi != -1)
+ {
+ String f = uri.substring(hi + 1);
+ uri = uri.substring(0, hi);
+ // TODO handle xpointer() here
+ // this only handles IDs
+ fragment = new IdFunction(new Constant(f));
+ }
+
+ // Get document source
+ try
+ {
+ DOMSource source;
+ XSLURIResolver resolver = stylesheet.factory.resolver;
+ synchronized (resolver)
+ {
+ if (stylesheet.transformer != null)
+ {
+ resolver.setUserResolver(stylesheet.transformer.uriResolver);
+ resolver.setUserListener(stylesheet.transformer.errorListener);
+ }
+ source = resolver.resolveDOM(null, base, uri);
+ }
+ Node node = source.getNode();
+ if (fragment == null)
+ {
+ return Collections.singleton(node);
+ }
+ else
+ {
+ Object ret = fragment.evaluate(node, 1, 1);
+ if (!(ret instanceof Collection))
+ {
+ // XXX Report error?
+ return Collections.EMPTY_SET;
+ }
+ return (Collection) ret;
+ }
+ }
+ catch (TransformerException e)
+ {
+ String msg = "can't open " + uri;
+ if (base != null)
+ {
+ msg += " with base " + base;
+ }
+ throw new RuntimeException(msg);
+ }
+ }
+
+ public Expr clone(Object context)
+ {
+ Stylesheet s = stylesheet;
+ if (context instanceof Stylesheet)
+ {
+ s = (Stylesheet) context;
+ }
+ DocumentFunction f = new DocumentFunction(s, base);
+ int len = args.size();
+ List args2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(((Expr) args.get(i)).clone(context));
+ }
+ f.setArguments(args2);
+ return f;
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator i = args.iterator(); i.hasNext(); )
+ {
+ if (((Expr) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java b/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java
new file mode 100644
index 0000000..84cb620
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java
@@ -0,0 +1,183 @@
+/* ElementAvailableFunction.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TreeSet;
+import javax.xml.namespace.QName;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Function;
+
+/**
+ * The XSLT element-available
function.
+ *
+ * @author Chris Burdess
+ */
+class ElementAvailableFunction
+ extends Expr
+ implements Function, XPathFunction
+{
+
+ static final Collection elements;
+ static
+ {
+ TreeSet acc = new TreeSet();
+ acc.add("stylesheet");
+ acc.add("template");
+ acc.add("param");
+ acc.add("variable");
+ acc.add("include");
+ acc.add("import");
+ acc.add("output");
+ acc.add("preserve-space");
+ acc.add("strip-space");
+ acc.add("key");
+ acc.add("decimal-format");
+ acc.add("namespace-alias");
+ acc.add("attribute-set");
+ acc.add("apply-templates");
+ acc.add("call-template");
+ acc.add("value-of");
+ acc.add("for-each");
+ acc.add("if");
+ acc.add("choose");
+ acc.add("when");
+ acc.add("otherwise");
+ acc.add("element");
+ acc.add("attribute");
+ acc.add("text");
+ acc.add("copy");
+ acc.add("processing-instruction");
+ acc.add("comment");
+ acc.add("number");
+ acc.add("copy-of");
+ acc.add("message");
+ acc.add("sort");
+ acc.add("with-param");
+ acc.add("fallback");
+ acc.add("apply-imports");
+ elements = Collections.unmodifiableSet(acc);
+ }
+
+ final NamespaceContext nsctx;
+ List args;
+
+ ElementAvailableFunction(NamespaceContext nsctx)
+ {
+ this.nsctx = nsctx;
+ }
+
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ // Useless...
+ return Collections.EMPTY_SET;
+ }
+
+ public void setArguments(List args)
+ {
+ this.args = args;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Expr arg = (Expr) args.get(0);
+ Object val = arg.evaluate(context, pos, len);
+ String name = _string(context, val);
+ String prefix, localName, uri;
+ int ci = name.indexOf(':');
+ if (ci == -1)
+ {
+ prefix = null;
+ localName = name;
+ }
+ else
+ {
+ prefix = name.substring(0, ci);
+ localName = name.substring(ci + 1);
+ }
+ uri = nsctx.getNamespaceURI(prefix);
+ if (Stylesheet.XSL_NS.equals(uri))
+ {
+ return elements.contains(localName) ?
+ Boolean.TRUE : Boolean.FALSE;
+ // TODO extension elements
+ }
+ return Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ NamespaceContext n = nsctx;
+ if (context instanceof NamespaceContext)
+ {
+ n = (NamespaceContext) context;
+ }
+ ElementAvailableFunction f = new ElementAvailableFunction(n);
+ int len = args.size();
+ List args2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(((Expr) args.get(i)).clone(context));
+ }
+ f.setArguments(args2);
+ return f;
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator i = args.iterator(); i.hasNext(); )
+ {
+ if (((Expr) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/ElementNode.java b/libjava/classpath/gnu/xml/transform/ElementNode.java
new file mode 100644
index 0000000..d8f7f6d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/ElementNode.java
@@ -0,0 +1,296 @@
+/* ElementNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing an XSL element
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class ElementNode
+ extends TemplateNode
+{
+
+ final TemplateNode name;
+ final TemplateNode namespace;
+ final String uas;
+ final Node source;
+ final Collection elementExcludeResultPrefixes;
+
+ ElementNode(TemplateNode name,
+ TemplateNode namespace, String uas, Node source)
+ {
+ this.name = name;
+ this.namespace = namespace;
+ this.uas = uas;
+ this.source = source;
+ NamedNodeMap attrs = source.getAttributes();
+ Node attr = attrs.getNamedItemNS(Stylesheet.XSL_NS,
+ "exclude-result-prefixes");
+ if (attr != null)
+ {
+ elementExcludeResultPrefixes = new HashSet();
+ StringTokenizer st = new StringTokenizer(attr.getNodeValue());
+ while (st.hasMoreTokens())
+ {
+ elementExcludeResultPrefixes.add(st.nextToken());
+ }
+ }
+ else
+ {
+ elementExcludeResultPrefixes = Collections.EMPTY_SET;
+ }
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new ElementNode(name.clone(stylesheet),
+ (namespace == null) ? null :
+ namespace.clone(stylesheet),
+ uas, source);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ Document doc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ // Create a document fragment to hold the name
+ DocumentFragment fragment = doc.createDocumentFragment();
+ // Apply name to the fragment
+ name.apply(stylesheet, mode,
+ context, pos, len,
+ fragment, null);
+ // Use XPath string-value of fragment
+ String nameValue = Expr.stringValue(fragment);
+
+ String namespaceValue = null;
+ if (namespace != null)
+ {
+ // Create a document fragment to hold the namespace
+ fragment = doc.createDocumentFragment();
+ // Apply namespace to the fragment
+ namespace.apply(stylesheet, mode,
+ context, pos, len,
+ fragment, null);
+ // Use XPath string-value of fragment
+ namespaceValue = Expr.stringValue(fragment);
+ if (namespaceValue.length() == 0)
+ {
+ namespaceValue = null;
+ }
+ }
+
+ String prefix = getPrefix(nameValue);
+ if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
+ {
+ int ci = nameValue.indexOf(':');
+ nameValue = nameValue.substring(ci + 1);
+ }
+ else
+ {
+ // Namespace aliasing
+ if (prefix == null)
+ {
+ prefix = "#default";
+ }
+ String resultPrefix =
+ (String) stylesheet.namespaceAliases.get(prefix);
+ if (resultPrefix != null)
+ {
+ if ("#default".equals(resultPrefix))
+ {
+ resultPrefix = null;
+ }
+ namespaceValue = source.lookupNamespaceURI(resultPrefix);
+ }
+ if (prefix == "#default")
+ {
+ prefix = null;
+ }
+ // Look up ordinary namespace for this prefix
+ if (namespaceValue == null)
+ {
+ if (XMLConstants.XML_NS_PREFIX.equals(prefix))
+ {
+ namespaceValue = XMLConstants.XML_NS_URI;
+ }
+ else
+ {
+ // Resolve namespace for this prefix
+ namespaceValue = source.lookupNamespaceURI(prefix);
+ }
+ }
+ /*if (prefix == null)
+ {
+ // Resolve prefix for this namespace
+ prefix = parent.lookupPrefix(namespaceValue);
+ if (prefix != null)
+ {
+ nameValue = prefix + ":" + nameValue;
+ }
+ }*/
+ }
+ // Create element
+ Element element = (namespaceValue != null) ?
+ doc.createElementNS(namespaceValue, nameValue) :
+ doc.createElement(nameValue);
+ if (nextSibling != null)
+ {
+ parent.insertBefore(element, nextSibling);
+ }
+ else
+ {
+ parent.appendChild(element);
+ }
+ stylesheet.addNamespaceNodes(source, element, doc,
+ elementExcludeResultPrefixes);
+ if (uas != null)
+ {
+ StringTokenizer st = new StringTokenizer(uas, " ");
+ while (st.hasMoreTokens())
+ {
+ addAttributeSet(stylesheet, mode, context, pos, len,
+ element, null, st.nextToken());
+ }
+ }
+ if (children != null)
+ {
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ element, null);
+ }
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ final String getPrefix(String name)
+ {
+ int ci = name.indexOf(':');
+ return (ci == -1) ? null : name.substring(0, ci);
+ }
+
+ void addAttributeSet(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling, String attributeSet)
+ throws TransformerException
+ {
+ for (Iterator i = stylesheet.attributeSets.iterator(); i.hasNext(); )
+ {
+ AttributeSet as = (AttributeSet) i.next();
+ if (!as.name.equals(attributeSet))
+ {
+ continue;
+ }
+ if (as.uas != null)
+ {
+ StringTokenizer st = new StringTokenizer(as.uas, " ");
+ while (st.hasMoreTokens())
+ {
+ addAttributeSet(stylesheet, mode, context, pos, len,
+ parent, nextSibling, st.nextToken());
+ }
+ }
+ if (as.children != null)
+ {
+ as.children.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+ }
+
+ public boolean references(QName var)
+ {
+ if (name != null && name.references(var))
+ {
+ return true;
+ }
+ if (namespace != null && namespace.references(var))
+ {
+ return true;
+ }
+ return super.references(var);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("name=");
+ buf.append(name);
+ if (uas != null)
+ {
+ buf.append(",uas=");
+ buf.append(uas);
+ }
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java b/libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java
new file mode 100644
index 0000000..d79bb15
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java
@@ -0,0 +1,101 @@
+/* ErrorListenerErrorHandler.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.TransformerException;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * An ErrorHandler that wraps an ErrorListener.
+ *
+ * @author Chris Burdess
+ */
+class ErrorListenerErrorHandler
+ implements ErrorHandler
+{
+
+ final ErrorListener listener;
+
+ ErrorListenerErrorHandler(ErrorListener listener)
+ {
+ this.listener = listener;
+ }
+
+ public void warning(SAXParseException e)
+ throws SAXException
+ {
+ try
+ {
+ listener.warning(new TransformerException(e));
+ }
+ catch (TransformerException e2)
+ {
+ throw new SAXException(e2);
+ }
+ }
+
+ public void error(SAXParseException e)
+ throws SAXException
+ {
+ try
+ {
+ listener.error(new TransformerException(e));
+ }
+ catch (TransformerException e2)
+ {
+ throw new SAXException(e2);
+ }
+ }
+
+ public void fatalError(SAXParseException e)
+ throws SAXException
+ {
+ try
+ {
+ listener.fatalError(new TransformerException(e));
+ }
+ catch (TransformerException e2)
+ {
+ throw new SAXException(e2);
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/ForEachNode.java b/libjava/classpath/gnu/xml/transform/ForEachNode.java
new file mode 100644
index 0000000..8f9220f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/ForEachNode.java
@@ -0,0 +1,171 @@
+/* ForEachNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing an XSLT for-each
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class ForEachNode
+ extends TemplateNode
+{
+
+ final Expr select;
+ final List sortKeys;
+
+ ForEachNode(Expr select, List sortKeys)
+ {
+ this.select = select;
+ this.sortKeys = sortKeys;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ int len = sortKeys.size();
+ List sortKeys2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ sortKeys2.add(((Key) sortKeys.get(i)).clone(stylesheet));
+ }
+ TemplateNode ret = new ForEachNode(select.clone(stylesheet),
+ sortKeys2);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ if (children != null)
+ {
+ // Set current template to null
+ Template saved = stylesheet.currentTemplate;
+ stylesheet.currentTemplate = null;
+ Object ret = select.evaluate(context, pos, len);
+ //System.err.println(toString() + ": " + context+" -> "+ret);
+ if (ret instanceof Collection)
+ {
+ Collection ns = (Collection) ret;
+ List list = new ArrayList(ns);
+ if (sortKeys != null)
+ {
+ for (Iterator i = sortKeys.iterator(); i.hasNext(); )
+ {
+ SortKey sortKey = (SortKey) i.next();
+ sortKey.init(stylesheet, mode, context, pos, len, parent,
+ nextSibling);
+ }
+ Collections.sort(list, new XSLComparator(sortKeys));
+ }
+ else
+ {
+ Collections.sort(list, documentOrderComparator);
+ }
+ // Perform children for each node
+ int l = list.size();
+ int p = 1;
+ for (Iterator i = list.iterator(); i.hasNext(); )
+ {
+ Node node = (Node) i.next();
+ stylesheet.current = node;
+ children.apply(stylesheet, mode,
+ node, p++, l,
+ parent, nextSibling);
+ }
+ }
+ // Restore current template
+ stylesheet.currentTemplate = saved;
+ }
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public boolean references(QName var)
+ {
+ if (select != null && select.references(var))
+ {
+ return true;
+ }
+ if (sortKeys != null)
+ {
+ for (Iterator i = sortKeys.iterator(); i.hasNext(); )
+ {
+ if (((SortKey) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ }
+ return super.references(var);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("select=");
+ buf.append(select);
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/FormatNumberFunction.java b/libjava/classpath/gnu/xml/transform/FormatNumberFunction.java
new file mode 100644
index 0000000..34717b3
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/FormatNumberFunction.java
@@ -0,0 +1,146 @@
+/* FormatNumberFunction.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Function;
+
+/**
+ * The XSLT format-number()
function.
+ *
+ * @author Chris Burdess
+ */
+final class FormatNumberFunction
+ extends Expr
+ implements XPathFunction, Function
+{
+
+ final Stylesheet stylesheet;
+ List args;
+
+ FormatNumberFunction(Stylesheet stylesheet)
+ {
+ this.stylesheet = stylesheet;
+ }
+
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ // Useless...
+ return Collections.EMPTY_SET;
+ }
+
+ public void setArguments(List args)
+ {
+ this.args = args;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ int arity = args.size();
+ List values = new ArrayList(arity);
+ for (int i = 0; i < arity; i++)
+ {
+ Expr arg = (Expr) args.get(i);
+ values.add(arg.evaluate(context, pos, len));
+ }
+ double number = _number(context, values.get(0));
+ String pattern = _string(context, values.get(1));
+ // Currency symbol ¤ is not supposed to be present
+ if (pattern.indexOf('\u00a4') != -1)
+ {
+ // Replace with $ (Xalan does this)
+ pattern = pattern.replace('\u00a4', '$');
+ }
+ String dfName = null;
+ if (arity > 2)
+ {
+ dfName = _string(context, values.get(2));
+ // otherwise the default decimal-format will be used
+ }
+ DecimalFormat df = (DecimalFormat) stylesheet.decimalFormats.get(dfName);
+ if (df == null)
+ {
+ throw new IllegalArgumentException("No such decimal-format: " +
+ dfName);
+ }
+ df.applyLocalizedPattern(pattern);
+ return df.format(number);
+ }
+
+ public Expr clone(Object context)
+ {
+ Stylesheet s = stylesheet;
+ if (context instanceof Stylesheet)
+ {
+ s = (Stylesheet) context;
+ }
+ FormatNumberFunction f = new FormatNumberFunction(s);
+ int len = args.size();
+ List args2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(((Expr) args.get(i)).clone(context));
+ }
+ f.setArguments(args2);
+ return f;
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator i = args.iterator(); i.hasNext(); )
+ {
+ if (((Expr) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java b/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java
new file mode 100644
index 0000000..7daf7ea
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java
@@ -0,0 +1,189 @@
+/* FunctionAvailableFunction.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TreeSet;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Function;
+
+/**
+ * The XSLT function-available
function.
+ *
+ * @author Chris Burdess
+ */
+class FunctionAvailableFunction
+ extends Expr
+ implements Function, XPathFunction
+{
+
+ static final Collection xsltFunctions;
+ static final Collection xpathFunctions;
+ static
+ {
+ TreeSet acc = new TreeSet();
+ acc.add("document");
+ acc.add("key");
+ acc.add("format-number");
+ acc.add("current");
+ acc.add("unparsed-entity-uri");
+ acc.add("generate-id");
+ acc.add("system-property");
+ acc.add("element-available");
+ acc.add("function-available");
+ xsltFunctions = Collections.unmodifiableSet(acc);
+ acc = new TreeSet();
+ acc.add("boolean");
+ acc.add("ceiling");
+ acc.add("concat");
+ acc.add("contains");
+ acc.add("count");
+ acc.add("false");
+ acc.add("floor");
+ acc.add("id");
+ acc.add("lang");
+ acc.add("last");
+ acc.add("local-name");
+ acc.add("name");
+ acc.add("namespace-uri");
+ acc.add("normalize-space");
+ acc.add("not");
+ acc.add("number");
+ acc.add("position");
+ acc.add("round");
+ acc.add("starts-with");
+ acc.add("string");
+ acc.add("string-length");
+ acc.add("substring-after");
+ acc.add("substring-before");
+ acc.add("substring");
+ acc.add("sum");
+ acc.add("translate");
+ acc.add("true");
+ xpathFunctions = Collections.unmodifiableSet(acc);
+ }
+
+ final NamespaceContext nsctx;
+ List args;
+
+ FunctionAvailableFunction(NamespaceContext nsctx)
+ {
+ this.nsctx = nsctx;
+ }
+
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ // Useless...
+ return Collections.EMPTY_SET;
+ }
+
+ public void setArguments(List args)
+ {
+ this.args = args;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Expr arg = (Expr) args.get(0);
+ Object val = arg.evaluate(context, pos, len);
+ String name = _string(context, val);
+ String prefix, localName, uri;
+ int ci = name.indexOf(':');
+ if (ci == -1)
+ {
+ prefix = null;
+ localName = name;
+ }
+ else
+ {
+ prefix = name.substring(0, ci);
+ localName = name.substring(ci + 1);
+ }
+ uri = nsctx.getNamespaceURI(prefix);
+ if (uri == null)
+ {
+ return xsltFunctions.contains(localName) ||
+ xpathFunctions.contains(localName) ?
+ Boolean.TRUE : Boolean.FALSE;
+ // TODO extension functions
+ }
+ return Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ NamespaceContext n = nsctx;
+ if (context instanceof NamespaceContext)
+ {
+ n = (NamespaceContext) context;
+ }
+ FunctionAvailableFunction f = new FunctionAvailableFunction(n);
+ int len = args.size();
+ List args2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(((Expr) args.get(i)).clone(context));
+ }
+ f.setArguments(args2);
+ return f;
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator i = args.iterator(); i.hasNext(); )
+ {
+ if (((Expr) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/GenerateIdFunction.java b/libjava/classpath/gnu/xml/transform/GenerateIdFunction.java
new file mode 100644
index 0000000..f0d3e6d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/GenerateIdFunction.java
@@ -0,0 +1,140 @@
+/* GenerateIdFunction.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Function;
+
+/**
+ * The XSLT generate-id()
function.
+ *
+ * @author Chris Burdess
+ */
+final class GenerateIdFunction
+ extends Expr
+ implements XPathFunction, Function
+{
+
+ List args;
+
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ // Useless...
+ return Collections.EMPTY_SET;
+ }
+
+ public void setArguments(List args)
+ {
+ this.args = args;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ int arity = args.size();
+ List values = new ArrayList(arity);
+ for (int i = 0; i < arity; i++)
+ {
+ Expr arg = (Expr) args.get(i);
+ values.add(arg.evaluate(context, pos, len));
+ }
+ Node node;
+ Collection ns = (arity == 0) ? Collections.EMPTY_SET :
+ (Collection) values.get(0);
+ if (ns.isEmpty())
+ {
+ node = context;
+ }
+ else
+ {
+ List list = new ArrayList(ns);
+ Collections.sort(list, documentOrderComparator);
+ node = (Node) list.get(0);
+ }
+
+ String name = node.getNodeName();
+ int index = 0, depth = 0;
+ for (Node ctx = node.getPreviousSibling(); ctx != null;
+ ctx = ctx.getPreviousSibling())
+ {
+ index++;
+ }
+ for (Node ctx = node.getParentNode(); ctx != null;
+ ctx = ctx.getParentNode())
+ {
+ depth++;
+ }
+ return name + "-" + index + "-" + depth;
+ }
+
+ public Expr clone(Object context)
+ {
+ GenerateIdFunction f = new GenerateIdFunction();
+ int len = args.size();
+ List args2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(((Expr) args.get(i)).clone(context));
+ }
+ f.setArguments(args2);
+ return f;
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator i = args.iterator(); i.hasNext(); )
+ {
+ if (((Expr) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/IfNode.java b/libjava/classpath/gnu/xml/transform/IfNode.java
new file mode 100644
index 0000000..17e2486
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/IfNode.java
@@ -0,0 +1,120 @@
+/* IfNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing an XSL if
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class IfNode
+ extends TemplateNode
+{
+
+ final Expr test;
+
+ IfNode(Expr test)
+ {
+ this.test = test;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new IfNode(test.clone(stylesheet));
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ Object ret = test.evaluate(context, pos, len);
+ boolean success = (ret instanceof Boolean) ?
+ ((Boolean) ret).booleanValue() :
+ Expr._boolean(context, ret);
+ if (success)
+ {
+ if (children != null)
+ {
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public boolean references(QName var)
+ {
+ if (test != null && test.references(var))
+ {
+ return true;
+ }
+ return super.references(var);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("test=");
+ buf.append(test);
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/Key.java b/libjava/classpath/gnu/xml/transform/Key.java
new file mode 100644
index 0000000..72bd90a
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/Key.java
@@ -0,0 +1,71 @@
+/* Key.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.namespace.QName;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Pattern;
+
+/**
+ * An XSL key.
+ *
+ * @author Chris Burdess
+ */
+class Key
+{
+
+ final QName name;
+ final Pattern match;
+ final Expr use;
+
+ Key(QName name, Pattern match, Expr use)
+ {
+ this.name = name;
+ this.match = match;
+ this.use = use;
+ }
+
+ Key clone(Stylesheet stylesheet)
+ {
+ return new Key(name,
+ (Pattern) match.clone(stylesheet),
+ use.clone(stylesheet));
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/KeyFunction.java b/libjava/classpath/gnu/xml/transform/KeyFunction.java
new file mode 100644
index 0000000..a705dc6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/KeyFunction.java
@@ -0,0 +1,228 @@
+/* KeyFunction.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Function;
+import gnu.xml.xpath.Pattern;
+
+/**
+ * The XSLT key()
function.
+ *
+ * @author Chris Burdess
+ */
+final class KeyFunction
+ extends Pattern
+ implements XPathFunction, Function
+{
+
+ final Stylesheet stylesheet;
+ List args;
+
+ KeyFunction(Stylesheet stylesheet)
+ {
+ this.stylesheet = stylesheet;
+ }
+
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ // Useless...
+ return Collections.EMPTY_SET;
+ }
+
+ public void setArguments(List args)
+ {
+ this.args = args;
+ }
+
+ public boolean matches(Node context)
+ {
+ Object ret = evaluate(context, 1, 1);
+ return !((Collection) ret).isEmpty();
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ // Evaluate arguments
+ int arity = args.size();
+ List values = new ArrayList(arity);
+ for (int i = 0; i < arity; i++)
+ {
+ Expr arg = (Expr) args.get(i);
+ values.add(arg.evaluate(context, pos, len));
+ }
+ // Get key name
+ QName keyName = QName.valueOf(_string(context, values.get(0)));
+ // Expand qualified name
+ String uri = keyName.getNamespaceURI();
+ String prefix = keyName.getPrefix();
+ if ((uri == null || uri.length() == 0) &&
+ (prefix != null && prefix.length() > 0))
+ {
+ uri = stylesheet.getNamespaceURI(prefix);
+ if (uri != null && uri.length() > 0)
+ {
+ String localName = keyName.getLocalPart();
+ keyName = new QName(uri, localName, prefix);
+ }
+ }
+ // Compute matching key set
+ Collection keySet = new LinkedList();
+ for (Iterator i = stylesheet.keys.iterator(); i.hasNext(); )
+ {
+ Key key = (Key) i.next();
+ if (key.name.equals(keyName))
+ {
+ keySet.add(key);
+ }
+ }
+ // Get target
+ Object target = values.get(1);
+ Collection acc = new LinkedHashSet();
+ Document doc = (context instanceof Document) ? (Document) context :
+ context.getOwnerDocument();
+ if (target instanceof Collection)
+ {
+ for (Iterator i = ((Collection) target).iterator(); i.hasNext(); )
+ {
+ String val = Expr.stringValue((Node) i.next());
+ addKeyNodes(doc, keySet, val, acc);
+ }
+ }
+ else
+ {
+ String val = Expr._string(context, target);
+ addKeyNodes(doc, keySet, val, acc);
+ }
+ List ret = new ArrayList(acc);
+ Collections.sort(ret, documentOrderComparator);
+ return ret;
+ }
+
+ final void addKeyNodes(Node node, Collection keySet,
+ String value, Collection acc)
+ {
+ addKeyNodeIfMatch(node, keySet, value, acc);
+ // Apply children
+ for (Node ctx = node.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ addKeyNodes(ctx, keySet, value, acc);
+ }
+ }
+
+ final void addKeyNodeIfMatch(Node node, Collection keySet,
+ String value, Collection acc)
+ {
+ for (Iterator i = keySet.iterator(); i.hasNext(); )
+ {
+ Key key = (Key) i.next();
+ if (key.match.matches(node))
+ {
+ Object eval = key.use.evaluate(node, 1, 1);
+ if (eval instanceof Collection)
+ {
+ for (Iterator j = ((Collection) eval).iterator();
+ j.hasNext(); )
+ {
+ String keyValue = Expr.stringValue((Node) j.next());
+ if (value.equals(keyValue))
+ {
+ acc.add(node);
+ return;
+ }
+ }
+ }
+ else
+ {
+ String keyValue = Expr._string(node, eval);
+ if (value.equals(keyValue))
+ {
+ acc.add(node);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ public Expr clone(Object context)
+ {
+ Stylesheet s = stylesheet;
+ if (context instanceof Stylesheet)
+ {
+ s = (Stylesheet) context;
+ }
+ KeyFunction f = new KeyFunction(s);
+ int len = args.size();
+ List args2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(((Expr) args.get(i)).clone(context));
+ }
+ f.setArguments(args2);
+ return f;
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator i = args.iterator(); i.hasNext(); )
+ {
+ if (((Expr) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/LiteralNode.java b/libjava/classpath/gnu/xml/transform/LiteralNode.java
new file mode 100644
index 0000000..0be2b35
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/LiteralNode.java
@@ -0,0 +1,231 @@
+/* LiteralNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.StringTokenizer;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ * A template node that copies a DOM node in the template to the result
+ * tree.
+ *
+ * @author Chris Burdess
+ */
+final class LiteralNode
+ extends TemplateNode
+{
+
+ /**
+ * The source node in the XSL template.
+ */
+ final Node source;
+
+ final Collection elementExcludeResultPrefixes;
+
+ LiteralNode(Node source)
+ {
+ this.source = source;
+ if (source.getNodeType() == Node.ELEMENT_NODE)
+ {
+ NamedNodeMap attrs = source.getAttributes();
+ Node attr = attrs.getNamedItemNS(Stylesheet.XSL_NS,
+ "exclude-result-prefixes");
+ if (attr != null)
+ {
+ elementExcludeResultPrefixes = new HashSet();
+ StringTokenizer st = new StringTokenizer(attr.getNodeValue());
+ while (st.hasMoreTokens())
+ {
+ elementExcludeResultPrefixes.add(st.nextToken());
+ }
+ }
+ else
+ {
+ elementExcludeResultPrefixes = Collections.EMPTY_SET;
+ }
+ }
+ else
+ {
+ elementExcludeResultPrefixes = null;
+ }
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new LiteralNode(source);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ Node result = null;
+ Document doc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ short nodeType = source.getNodeType();
+ if (nodeType == Node.ATTRIBUTE_NODE &&
+ parent.getFirstChild() != null)
+ {
+ // Ignore attributes added after child elements
+ }
+ else
+ {
+ // Namespace aliasing
+ if (nodeType == Node.ELEMENT_NODE)
+ {
+ String prefix = source.getPrefix();
+ if (prefix == null)
+ {
+ prefix = "#default";
+ }
+ String resultPrefix =
+ (String) stylesheet.namespaceAliases.get(prefix);
+ if (resultPrefix != null)
+ {
+ if ("#default".equals(resultPrefix))
+ {
+ resultPrefix = null;
+ }
+ String uri = source.lookupNamespaceURI(resultPrefix);
+ String name = source.getNodeName();
+ // Create a new element node in the result document
+ result = doc.createElementNS(uri, name);
+ // copy attributes
+ NamedNodeMap srcAttrs = source.getAttributes();
+ NamedNodeMap dstAttrs = result.getAttributes();
+ int l = srcAttrs.getLength();
+ for (int i = 0; i < l; i++)
+ {
+ Node attr = srcAttrs.item(i);
+ if (!Stylesheet.XSL_NS.equals(attr.getNamespaceURI()))
+ {
+ attr = attr.cloneNode(true);
+ attr = doc.adoptNode(attr);
+ dstAttrs.setNamedItemNS(attr);
+ }
+ }
+ }
+ }
+ if (result == null)
+ {
+ // Create result node
+ result = source.cloneNode(false);
+ // Remove any XSL attributes
+ NamedNodeMap attrs = result.getAttributes();
+ if (attrs != null)
+ {
+ int l = attrs.getLength();
+ for (int i = 0; i < l; i++)
+ {
+ Node attr = attrs.item(i);
+ if (Stylesheet.XSL_NS.equals(attr.getNamespaceURI()))
+ {
+ attrs.removeNamedItem(attr.getNodeName());
+ i--;
+ l--;
+ }
+ }
+ }
+ Node result2 = doc.adoptNode(result);
+ if (result2 == null)
+ {
+ String msg = "Error adopting node to result tree: " +
+ result + " (" + result.getClass().getName() + ")";
+ DOMSourceLocator l = new DOMSourceLocator(context);
+ throw new TransformerException(msg, l);
+ }
+ result = result2;
+ }
+ if (nextSibling != null)
+ {
+ parent.insertBefore(result, nextSibling);
+ }
+ else
+ {
+ parent.appendChild(result);
+ }
+ if (nodeType == Node.ELEMENT_NODE)
+ {
+ stylesheet.addNamespaceNodes(source, result, doc,
+ elementExcludeResultPrefixes);
+ }
+ // children
+ if (children != null)
+ {
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ result, null);
+ }
+ }
+ // next sibling
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("source=");
+ buf.append(source);
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/MessageNode.java b/libjava/classpath/gnu/xml/transform/MessageNode.java
new file mode 100644
index 0000000..1df7168
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/MessageNode.java
@@ -0,0 +1,101 @@
+/* MessageNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * An XSL message
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class MessageNode
+ extends TemplateNode
+{
+
+ final boolean terminate;
+
+ MessageNode(boolean terminate)
+ {
+ this.terminate = terminate;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new MessageNode(terminate);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ if (children != null)
+ {
+ Document doc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ DocumentFragment fragment = doc.createDocumentFragment();
+ children.apply(stylesheet, mode, context, pos, len, fragment, null);
+ String message = Expr.stringValue(fragment);
+ System.err.println(message);
+ if (terminate)
+ {
+ stylesheet.terminated = true;
+ }
+ }
+ if (next != null && !terminate)
+ {
+ next.apply(stylesheet, mode, context, pos, len, parent, nextSibling);
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/NodeNumberNode.java b/libjava/classpath/gnu/xml/transform/NodeNumberNode.java
new file mode 100644
index 0000000..0427686
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/NodeNumberNode.java
@@ -0,0 +1,269 @@
+/* NodeNumberNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Pattern;
+import gnu.xml.xpath.Selector;
+import gnu.xml.xpath.UnionExpr;
+
+/**
+ * A template node representing the XSL number
instruction
+ * with no value
expression, i.e. the value is computed from
+ * the document position of the context node.
+ *
+ * @author Chris Burdess
+ */
+final class NodeNumberNode
+ extends AbstractNumberNode
+{
+
+ static final int SINGLE = 0;
+ static final int MULTIPLE = 1;
+ static final int ANY = 2;
+
+ final int level;
+ final Pattern count;
+ final Pattern from;
+
+ NodeNumberNode(int level, Pattern count, Pattern from,
+ TemplateNode format, String lang,
+ int letterValue, String groupingSeparator, int groupingSize)
+ {
+ super(format, lang, letterValue, groupingSeparator, groupingSize);
+ this.level = level;
+ this.count = count;
+ this.from = from;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new NodeNumberNode(level,
+ (count == null) ? null :
+ (Pattern) count.clone(stylesheet),
+ (from == null) ? from :
+ (Pattern) from.clone(stylesheet),
+ format, lang, letterValue,
+ groupingSeparator, groupingSize);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ int[] compute(Stylesheet stylesheet, Node context, int pos, int len)
+ throws TransformerException
+ {
+ /*if (from != null)
+ {
+ Object ret = from.evaluate(context, pos, len);
+ if (ret instanceof Collection)
+ {
+ Collection ns = (Collection) ret;
+ if (ns.size() > 0)
+ {
+ List list = new ArrayList(ns);
+ Collections.sort(list, documentOrderComparator);
+ context = (Node) list.get(0);
+ }
+ else
+ {
+ return new int[0];
+ }
+ }
+ else
+ {
+ return new int[0];
+ }
+ }*/
+ Node current = context;
+ switch (level)
+ {
+ case SINGLE:
+ if (from == null)
+ {
+ while (context != null && !countMatches(current, context))
+ {
+ context = context.getParentNode();
+ }
+ }
+ else
+ {
+ while (context != null && !countMatches(current, context) &&
+ !fromMatches(context))
+ {
+ context = context.getParentNode();
+ }
+ }
+ return (context == null) ? new int[0] :
+ new int[] { (context == current) ? pos : getIndex(current, context) };
+ case MULTIPLE:
+ List ancestors = new ArrayList();
+ while (context != null)
+ {
+ if (countMatches(current, context))
+ {
+ if (from == null || fromMatches(context))
+ {
+ ancestors.add(context);
+ }
+ }
+ context = context.getParentNode();
+ }
+ Collections.sort(ancestors, documentOrderComparator);
+ int[] ret = new int[ancestors.size()];
+ for (int i = 0; i < ret.length; i++)
+ {
+ ret[i] = getIndex(current, (Node) ancestors.get(i));
+ }
+ return ret;
+ case ANY:
+ Expr preceding = new Selector(Selector.PRECEDING,
+ Collections.EMPTY_LIST);
+ Expr ancestorOrSelf = new Selector(Selector.ANCESTOR_OR_SELF,
+ Collections.EMPTY_LIST);
+ Expr any = new UnionExpr(preceding, ancestorOrSelf);
+ Object eval = any.evaluate(context, pos, len);
+ if (eval instanceof Collection)
+ {
+ Collection ns = (Collection) eval;
+ List candidates = new ArrayList();
+ for (Iterator i = ns.iterator(); i.hasNext(); )
+ {
+ Node candidate = (Node) i.next();
+ if (countMatches(current, candidate))
+ {
+ candidates.add(candidate);
+ if (from != null && from.matches(candidate))
+ {
+ break;
+ }
+ }
+ }
+ return new int[] { candidates.size() };
+ }
+ return new int[0];
+ default:
+ throw new TransformerException("invalid level");
+ }
+ }
+
+ boolean countMatches(Node current, Node node)
+ {
+ if (count == null)
+ {
+ int cnt = current.getNodeType();
+ int nnt = node.getNodeType();
+ if (cnt != nnt)
+ {
+ return false;
+ }
+ if (nnt == Node.ELEMENT_NODE || nnt == Node.ATTRIBUTE_NODE)
+ {
+ String curi = current.getNamespaceURI();
+ String nuri = node.getNamespaceURI();
+ if ((curi == null && nuri != null) ||
+ (curi != null && !curi.equals(nuri)))
+ {
+ return false;
+ }
+ String cn = current.getLocalName();
+ if (cn == null)
+ {
+ cn = current.getNodeName();
+ }
+ String nn = node.getLocalName();
+ if (nn == null)
+ {
+ nn = node.getNodeName();
+ }
+ if (!cn.equals(nn))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return count.matches(node);
+ }
+ }
+
+ boolean fromMatches(Node node)
+ {
+ for (Node ctx = node.getParentNode(); ctx != null;
+ ctx = ctx.getParentNode())
+ {
+ if (from.matches(ctx))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ int getIndex(Node current, Node node)
+ {
+ int index = 0;
+ do
+ {
+ do
+ {
+ node = node.getPreviousSibling();
+ }
+ while (node != null && !countMatches(current, node));
+ index++;
+ }
+ while (node != null);
+ return index;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/NumberNode.java b/libjava/classpath/gnu/xml/transform/NumberNode.java
new file mode 100644
index 0000000..b19a7b5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/NumberNode.java
@@ -0,0 +1,88 @@
+/* NumberNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing the XSL number
instruction
+ * with a value
expression.
+ *
+ * @author Chris Burdess
+ */
+final class NumberNode
+ extends AbstractNumberNode
+{
+
+ final Expr value;
+
+ NumberNode(Expr value, TemplateNode format, String lang,
+ int letterValue, String groupingSeparator, int groupingSize)
+ {
+ super(format, lang, letterValue, groupingSeparator, groupingSize);
+ this.value = value;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new NumberNode(value.clone(stylesheet),
+ format, lang, letterValue,
+ groupingSeparator, groupingSize);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ int[] compute(Stylesheet stylesheet, Node context, int pos, int len)
+ throws TransformerException
+ {
+ Object ret = value.evaluate(context, pos, len);
+ Double d = (ret instanceof Double) ? ((Double) ret) :
+ new Double(Expr._number(context, ret));
+ return new int[] { d.intValue() };
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/OtherwiseNode.java b/libjava/classpath/gnu/xml/transform/OtherwiseNode.java
new file mode 100644
index 0000000..570310f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/OtherwiseNode.java
@@ -0,0 +1,94 @@
+/* OtherwiseNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+
+/**
+ * A template node representing an XSL otherwise
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class OtherwiseNode
+ extends TemplateNode
+{
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new OtherwiseNode();
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ if (children != null)
+ {
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/ParameterNode.java b/libjava/classpath/gnu/xml/transform/ParameterNode.java
new file mode 100644
index 0000000..ef09ea5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/ParameterNode.java
@@ -0,0 +1,198 @@
+/* ParameterNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.Collections;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node that sets a variable or parameter during template
+ * processing.
+ *
+ * @author Chris Burdess
+ */
+final class ParameterNode
+ extends TemplateNode
+ implements Comparable
+{
+
+ final QName name;
+ final Expr select;
+ final int type;
+
+ ParameterNode(QName name, Expr select, int type)
+ {
+ this.name = name;
+ this.select = select;
+ this.type = type;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new ParameterNode(name,
+ select.clone(stylesheet),
+ type);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ // push the variable context
+ stylesheet.bindings.push(type);
+ // set the variable
+ Object value = getValue(stylesheet, mode, context, pos, len);
+ if (value != null)
+ {
+ stylesheet.bindings.set(name, value, type);
+ if (stylesheet.debug)
+ {
+ System.err.println(this + ": set to " + value);
+ }
+ }
+ // variable and param don't process children as such
+ // all subsequent instructions are processed with that variable context
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ // pop the variable context
+ stylesheet.bindings.pop(type);
+ }
+
+ Object getValue(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len)
+ throws TransformerException
+ {
+ if (select != null)
+ {
+ return select.evaluate(context, pos, len);
+ }
+ else if (children != null)
+ {
+ Document doc = (context instanceof Document) ? (Document) context :
+ context.getOwnerDocument();
+ DocumentFragment fragment = doc.createDocumentFragment();
+ children.apply(stylesheet, mode, context, pos, len, fragment, null);
+ return Collections.singleton(fragment);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public boolean references(QName var)
+ {
+ if (select != null && select.references(var))
+ {
+ return true;
+ }
+ return super.references(var);
+ }
+
+ public int compareTo(Object other)
+ {
+ if (other instanceof ParameterNode)
+ {
+ ParameterNode pn = (ParameterNode) other;
+ boolean r1 = references(pn.name);
+ boolean r2 = pn.references(name);
+ if (r1 && r2)
+ {
+ throw new IllegalArgumentException("circular definitions");
+ }
+ if (r1)
+ {
+ return 1;
+ }
+ if (r2)
+ {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("name=");
+ buf.append(name);
+ if (select != null)
+ {
+ buf.append(",select=");
+ buf.append(select);
+ }
+ buf.append(",type=");
+ switch (type)
+ {
+ case Bindings.VARIABLE:
+ buf.append("variable");
+ break;
+ case Bindings.PARAM:
+ buf.append("param");
+ break;
+ case Bindings.WITH_PARAM:
+ buf.append("with-param");
+ break;
+ }
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java b/libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java
new file mode 100644
index 0000000..d75f693
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java
@@ -0,0 +1,126 @@
+/* ProcessingInstructionNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing the XSL processing-instruction
+ * instruction.
+ *
+ * @author Chris Burdess
+ */
+final class ProcessingInstructionNode
+ extends TemplateNode
+{
+
+ final String name;
+
+ ProcessingInstructionNode(String name)
+ {
+ this.name = name;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new ProcessingInstructionNode(name);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ String data = null;
+ Document doc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ if (children != null)
+ {
+ // Create a document fragment to hold the text
+ DocumentFragment fragment = doc.createDocumentFragment();
+ // Apply children to the fragment
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ fragment, null);
+ // Use XPath string-value of fragment
+ data = Expr.stringValue(fragment);
+ }
+ ProcessingInstruction pi = doc.createProcessingInstruction(name, data);
+ // Insert into result tree
+ if (nextSibling != null)
+ {
+ parent.insertBefore(pi, nextSibling);
+ }
+ else
+ {
+ parent.appendChild(pi);
+ }
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("name=");
+ buf.append(name);
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/SAXSerializer.java b/libjava/classpath/gnu/xml/transform/SAXSerializer.java
new file mode 100644
index 0000000..9650e3e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/SAXSerializer.java
@@ -0,0 +1,305 @@
+/* SAXSerializer.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import org.w3c.dom.Attr;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
+
+/**
+ * Serializes a DOM node to a sequence of SAX events.
+ *
+ * @author Chris Burdess
+ */
+class SAXSerializer
+ implements Attributes
+{
+
+ transient NamedNodeMap attrs;
+ transient LinkedList namespaces = new LinkedList();
+
+ boolean isDefined(String prefix, String uri)
+ {
+ for (Iterator i = namespaces.iterator(); i.hasNext(); )
+ {
+ HashMap ctx = (HashMap) i.next();
+ if (uri.equals(ctx.get(prefix)))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void define(String prefix, String uri)
+ {
+ for (Iterator i = namespaces.iterator(); i.hasNext(); )
+ {
+ HashMap ctx = (HashMap) i.next();
+ if (ctx.containsKey(prefix))
+ {
+ HashMap newCtx = new HashMap();
+ newCtx.put(prefix, uri);
+ namespaces.addFirst(newCtx);
+ return;
+ }
+ }
+ HashMap ctx;
+ if (namespaces.isEmpty())
+ {
+ ctx = new HashMap();
+ namespaces.add(ctx);
+ }
+ else
+ {
+ ctx = (HashMap) namespaces.getFirst();
+ }
+ ctx.put(prefix, uri);
+ }
+
+ void undefine(String prefix, String uri)
+ {
+ for (Iterator i = namespaces.iterator(); i.hasNext(); )
+ {
+ HashMap ctx = (HashMap) i.next();
+ if (uri.equals(ctx.get(prefix)))
+ {
+ ctx.remove(prefix);
+ if (ctx.isEmpty())
+ {
+ namespaces.remove(ctx);
+ }
+ return;
+ }
+ }
+ }
+
+ public int getLength()
+ {
+ return attrs.getLength();
+ }
+
+ public String getURI(int index)
+ {
+ return attrs.item(index).getNamespaceURI();
+ }
+
+ public String getLocalName(int index)
+ {
+ return attrs.item(index).getLocalName();
+ }
+
+ public String getQName(int index)
+ {
+ return attrs.item(index).getNodeName();
+ }
+
+ public String getType(int index)
+ {
+ Attr attr = (Attr) attrs.item(index);
+ return attr.isId() ? "ID" : "CDATA";
+ }
+
+ public String getValue(int index)
+ {
+ return attrs.item(index).getNodeValue();
+ }
+
+ public int getIndex(String uri, String localName)
+ {
+ int len = attrs.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ Node attr = attrs.item(i);
+ String a_uri = attr.getNamespaceURI();
+ String a_localName = attr.getLocalName();
+ if (((a_uri == null && uri == null) ||
+ (a_uri != null && a_uri.equals(uri))) &&
+ a_localName.equals(localName))
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public int getIndex(String qName)
+ {
+ int len = attrs.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ Node attr = attrs.item(i);
+ String a_name = attr.getNodeName();
+ if (a_name.equals(qName))
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public String getType(String uri, String localName)
+ {
+ Attr attr = (Attr) attrs.getNamedItemNS(uri, localName);
+ return attr.isId() ? "ID" : "CDATA";
+ }
+
+ public String getType(String qName)
+ {
+ Attr attr = (Attr) attrs.getNamedItem(qName);
+ return attr.isId() ? "ID" : "CDATA";
+ }
+
+ public String getValue(String uri, String localName)
+ {
+ return attrs.getNamedItemNS(uri, localName).getNodeValue();
+ }
+
+ public String getValue(String qName)
+ {
+ return attrs.getNamedItem(qName).getNodeValue();
+ }
+
+ void serialize(Node node, ContentHandler ch, LexicalHandler lh)
+ throws SAXException
+ {
+ attrs = node.getAttributes();
+ Node children;
+ Node next = node.getNextSibling();
+ switch (node.getNodeType())
+ {
+ case Node.ELEMENT_NODE:
+ String uri = node.getNamespaceURI();
+ String prefix = node.getPrefix();
+ boolean defined = isDefined(prefix, uri);
+ if (!defined)
+ {
+ define(prefix, uri);
+ ch.startPrefixMapping(prefix, uri);
+ }
+ String localName = node.getLocalName();
+ String qName = node.getNodeName();
+ ch.startElement(uri, localName, qName, this);
+ children = node.getFirstChild();
+ if (children != null)
+ {
+ serialize(children, ch, lh);
+ }
+ ch.endElement(uri, localName, qName);
+ if (!defined)
+ {
+ ch.endPrefixMapping(prefix);
+ undefine(prefix, uri);
+ }
+ break;
+ case Node.TEXT_NODE:
+ char[] chars = node.getNodeValue().toCharArray();
+ ch.characters(chars, 0, chars.length);
+ break;
+ case Node.CDATA_SECTION_NODE:
+ char[] cdata = node.getNodeValue().toCharArray();
+ if (lh != null)
+ {
+ lh.startCDATA();
+ ch.characters(cdata, 0, cdata.length);
+ lh.endCDATA();
+ }
+ else
+ {
+ ch.characters(cdata, 0, cdata.length);
+ }
+ break;
+ case Node.COMMENT_NODE:
+ if (lh != null)
+ {
+ char[] comment = node.getNodeValue().toCharArray();
+ lh.comment(comment, 0, comment.length);
+ }
+ break;
+ case Node.DOCUMENT_NODE:
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ ch.startDocument();
+ children = node.getFirstChild();
+ if (children != null)
+ {
+ serialize(children, ch, lh);
+ }
+ ch.endDocument();
+ break;
+ case Node.DOCUMENT_TYPE_NODE:
+ if (lh != null)
+ {
+ DocumentType doctype = (DocumentType) node;
+ String publicId = doctype.getPublicId();
+ String systemId = doctype.getSystemId();
+ lh.startDTD(node.getNodeName(), publicId, systemId);
+ NamedNodeMap entities = doctype.getEntities();
+ int len = entities.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ Node entity = entities.item(i);
+ String entityName = entity.getNodeName();
+ lh.startEntity(entityName);
+ lh.endEntity(entityName);
+ }
+ lh.endDTD();
+ }
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ ch.processingInstruction(node.getNodeName(), node.getNodeValue());
+ break;
+ case Node.ENTITY_REFERENCE_NODE:
+ ch.skippedEntity(node.getNodeName());
+ break;
+ }
+ attrs = null;
+ if (next != null)
+ {
+ serialize(next, ch, lh);
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/SortKey.java b/libjava/classpath/gnu/xml/transform/SortKey.java
new file mode 100644
index 0000000..d4ffb05
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/SortKey.java
@@ -0,0 +1,179 @@
+/* SortKey.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * An XSL sort key.
+ *
+ * @author Chris Burdess
+ */
+final class SortKey
+{
+
+ static final int DEFAULT = 0;
+ static final int UPPER_FIRST = 1;
+ static final int LOWER_FIRST = 2;
+
+ final Expr select;
+ final TemplateNode langTemplate;
+ final TemplateNode dataTypeTemplate;
+ final TemplateNode orderTemplate;
+ final TemplateNode caseOrderTemplate;
+
+ transient String lang;
+ transient String dataType;
+ transient boolean descending;
+ transient int caseOrder;
+
+ SortKey(Expr select, TemplateNode lang, TemplateNode dataType,
+ TemplateNode order, TemplateNode caseOrder)
+ {
+ this.select = select;
+ this.langTemplate = lang;
+ this.dataTypeTemplate = dataType;
+ this.orderTemplate = order;
+ this.caseOrderTemplate = caseOrder;
+ }
+
+ String key(Node node)
+ {
+ Object ret = select.evaluate(node, 1, 1);
+ if (ret instanceof String)
+ {
+ return (String) ret;
+ }
+ else
+ {
+ return Expr._string(node, ret);
+ }
+ }
+
+ /**
+ * Prepare for a sort.
+ * This sets all transient variables from their AVTs.
+ */
+ void init(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ Document doc = (context instanceof Document) ? (Document) context :
+ context.getOwnerDocument();
+ if (langTemplate == null)
+ {
+ lang = null;
+ }
+ else
+ {
+ DocumentFragment fragment = doc.createDocumentFragment();
+ langTemplate.apply(stylesheet, mode, context, pos, len,
+ fragment, null);
+ lang = Expr.stringValue(fragment);
+ }
+ if (dataTypeTemplate == null)
+ {
+ dataType = "text";
+ }
+ else
+ {
+ DocumentFragment fragment = doc.createDocumentFragment();
+ dataTypeTemplate.apply(stylesheet, mode, context, pos, len,
+ fragment, null);
+ dataType = Expr.stringValue(fragment);
+ }
+ if (orderTemplate == null)
+ {
+ descending = false;
+ }
+ else
+ {
+ DocumentFragment fragment = doc.createDocumentFragment();
+ orderTemplate.apply(stylesheet, mode, context, pos, len,
+ fragment, null);
+ String order = Expr.stringValue(fragment);
+ descending = "descending".equals(order);
+ }
+ if (caseOrderTemplate == null)
+ {
+ caseOrder = DEFAULT;
+ }
+ else
+ {
+ DocumentFragment fragment = doc.createDocumentFragment();
+ caseOrderTemplate.apply(stylesheet, mode, context, pos, len,
+ fragment, null);
+ String co = Expr.stringValue(fragment);
+ caseOrder = "upper-first".equals(co) ? UPPER_FIRST :
+ "lower-first".equals(co) ? LOWER_FIRST :
+ DEFAULT;
+ }
+ }
+
+ boolean references(QName var)
+ {
+ if (select != null && select.references(var))
+ {
+ return true;
+ }
+ if (langTemplate != null && langTemplate.references(var))
+ {
+ return true;
+ }
+ if (dataTypeTemplate != null && dataTypeTemplate.references(var))
+ {
+ return true;
+ }
+ if (orderTemplate != null && orderTemplate.references(var))
+ {
+ return true;
+ }
+ if (caseOrderTemplate != null && caseOrderTemplate.references(var))
+ {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/StreamSerializer.java b/libjava/classpath/gnu/xml/transform/StreamSerializer.java
new file mode 100644
index 0000000..eb04539
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/StreamSerializer.java
@@ -0,0 +1,762 @@
+/* StreamSerializer.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import javax.xml.XMLConstants;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ * Serializes a DOM node to an output stream.
+ *
+ * @author Chris Burdess
+ */
+public class StreamSerializer
+{
+
+ static final int SPACE = 0x20;
+ static final int BANG = 0x21; // !
+ static final int APOS = 0x27; // '
+ static final int SLASH = 0x2f; // /
+ static final int BRA = 0x3c; // <
+ static final int KET = 0x3e; // >
+ static final int EQ = 0x3d; // =
+
+ /**
+ * HTML 4.01 boolean attributes
+ */
+ static final Map HTML_BOOLEAN_ATTRIBUTES = new HashMap();
+ static
+ {
+ HashSet set;
+
+ set = new HashSet();
+ set.add("nohref");
+ HTML_BOOLEAN_ATTRIBUTES.put("area", set);
+
+ set = new HashSet();
+ set.add("ismap");
+ HTML_BOOLEAN_ATTRIBUTES.put("img", set);
+
+ set = new HashSet();
+ set.add("declare");
+ HTML_BOOLEAN_ATTRIBUTES.put("object", set);
+
+ set = new HashSet();
+ set.add("noshade");
+ HTML_BOOLEAN_ATTRIBUTES.put("hr", set);
+
+ set = new HashSet();
+ set.add("compact");
+ HTML_BOOLEAN_ATTRIBUTES.put("dl", set);
+ HTML_BOOLEAN_ATTRIBUTES.put("ol", set);
+ HTML_BOOLEAN_ATTRIBUTES.put("ul", set);
+ HTML_BOOLEAN_ATTRIBUTES.put("dir", set);
+ HTML_BOOLEAN_ATTRIBUTES.put("menu", set);
+
+ set = new HashSet();
+ set.add("checked");
+ set.add("disabled");
+ set.add("readonly");
+ set.add("ismap");
+ HTML_BOOLEAN_ATTRIBUTES.put("input", set);
+
+ set = new HashSet();
+ set.add("multiple");
+ set.add("disabled");
+ HTML_BOOLEAN_ATTRIBUTES.put("select", set);
+
+ set = new HashSet();
+ set.add("disabled");
+ HTML_BOOLEAN_ATTRIBUTES.put("optgroup", set);
+
+ set = new HashSet();
+ set.add("selected");
+ set.add("disabled");
+ HTML_BOOLEAN_ATTRIBUTES.put("option", set);
+
+ set = new HashSet();
+ set.add("disabled");
+ set.add("readonly");
+ HTML_BOOLEAN_ATTRIBUTES.put("textarea", set);
+
+ set = new HashSet();
+ set.add("disabled");
+ HTML_BOOLEAN_ATTRIBUTES.put("button", set);
+
+ set = new HashSet();
+ set.add("nowrap");
+ HTML_BOOLEAN_ATTRIBUTES.put("th", set);
+ HTML_BOOLEAN_ATTRIBUTES.put("td", set);
+
+ set = new HashSet();
+ set.add("noresize");
+ HTML_BOOLEAN_ATTRIBUTES.put("frame", set);
+
+ set = new HashSet();
+ set.add("defer");
+ HTML_BOOLEAN_ATTRIBUTES.put("script", set);
+ }
+
+ protected final String encoding;
+ final Charset charset;
+ final CharsetEncoder encoder;
+ final int mode;
+ final Map namespaces;
+ protected String eol;
+ Collection cdataSectionElements = Collections.EMPTY_SET;
+
+ protected boolean discardDefaultContent;
+ protected boolean xmlDeclaration = true;
+
+ public StreamSerializer()
+ {
+ this(Stylesheet.OUTPUT_XML, null, null);
+ }
+
+ public StreamSerializer(String encoding)
+ {
+ this(Stylesheet.OUTPUT_XML, encoding, null);
+ }
+
+ public StreamSerializer(int mode, String encoding, String eol)
+ {
+ this.mode = mode;
+ if (encoding == null)
+ {
+ encoding = "UTF-8";
+ }
+ this.encoding = encoding.intern();
+ charset = Charset.forName(this.encoding);
+ encoder = charset.newEncoder();
+ this.eol = (eol != null) ? eol : System.getProperty("line.separator");
+ namespaces = new HashMap();
+ }
+
+ void setCdataSectionElements(Collection c)
+ {
+ cdataSectionElements = c;
+ }
+
+ public void serialize(final Node node, final OutputStream out)
+ throws IOException
+ {
+ serialize(node, out, false);
+ }
+
+ void serialize(Node node, final OutputStream out,
+ boolean convertToCdata)
+ throws IOException
+ {
+ while (node != null)
+ {
+ Node next = node.getNextSibling();
+ doSerialize(node, out, convertToCdata);
+ node = next;
+ }
+ }
+
+ private void doSerialize(final Node node, final OutputStream out,
+ boolean convertToCdata)
+ throws IOException
+ {
+ if (out == null)
+ {
+ throw new NullPointerException("no output stream");
+ }
+ String value, prefix;
+ Node children;
+ String uri = node.getNamespaceURI();
+ boolean defined = false;
+ short nt = node.getNodeType();
+ if (convertToCdata && nt == Node.TEXT_NODE)
+ {
+ nt = Node.CDATA_SECTION_NODE;
+ }
+ switch (nt)
+ {
+ case Node.ATTRIBUTE_NODE:
+ prefix = node.getPrefix();
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) ||
+ (prefix != null && prefix.startsWith("xmlns:")))
+ {
+ String nsuri = node.getNodeValue();
+ if (isDefined(nsuri))
+ {
+ break;
+ }
+ String name = node.getLocalName();
+ if (name == null)
+ {
+ name = node.getNodeName();
+ }
+ define(nsuri, name);
+ }
+ else if (uri != null && !isDefined(uri))
+ {
+ prefix = define(uri, prefix);
+ String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix;
+ out.write(SPACE);
+ out.write(encodeText(nsname));
+ out.write(EQ);
+ String nsvalue = "'" + encode(uri, true, true) + "'";
+ out.write(nsvalue.getBytes(encoding));
+ defined = true;
+ }
+ out.write(SPACE);
+ String a_nodeName = node.getNodeName();
+ out.write(encodeText(a_nodeName));
+ String a_nodeValue = node.getNodeValue();
+ if (mode == Stylesheet.OUTPUT_HTML &&
+ a_nodeName.equals(a_nodeValue) &&
+ isHTMLBoolean((Attr) node, a_nodeName))
+ {
+ break;
+ }
+ out.write(EQ);
+ value = "'" + encode(a_nodeValue, true, true) + "'";
+ out.write(encodeText(value));
+ break;
+ case Node.ELEMENT_NODE:
+ value = node.getNodeName();
+ out.write(BRA);
+ out.write(encodeText(value));
+ if (uri != null && !isDefined(uri))
+ {
+ prefix = define(uri, node.getPrefix());
+ String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix;
+ out.write(SPACE);
+ out.write(encodeText(nsname));
+ out.write(EQ);
+ String nsvalue = "'" + encode(uri, true, true) + "'";
+ out.write(encodeText(nsvalue));
+ defined = true;
+ }
+ NamedNodeMap attrs = node.getAttributes();
+ if (attrs != null)
+ {
+ int len = attrs.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ Attr attr = (Attr) attrs.item(i);
+ if (discardDefaultContent && !attr.getSpecified())
+ {
+ // NOOP
+ }
+ else
+ {
+ serialize(attr, out, false);
+ }
+ }
+ }
+ convertToCdata = cdataSectionElements.contains(value);
+ children = node.getFirstChild();
+ if (children == null)
+ {
+ out.write(SLASH);
+ out.write(KET);
+ }
+ else
+ {
+ out.write(KET);
+ serialize(children, out, convertToCdata);
+ out.write(BRA);
+ out.write(SLASH);
+ out.write(encodeText(value));
+ out.write(KET);
+ }
+ break;
+ case Node.TEXT_NODE:
+ value = node.getNodeValue();
+ if (!"yes".equals(node.getUserData("disable-output-escaping")))
+ {
+ value = encode(value, false, false);
+ }
+ out.write(encodeText(value));
+ break;
+ case Node.CDATA_SECTION_NODE:
+ value = "";
+ out.write(encodeText(value));
+ break;
+ case Node.COMMENT_NODE:
+ value = "";
+ out.write(encodeText(value));
+ Node cp = node.getParentNode();
+ if (cp != null && cp.getNodeType() == Node.DOCUMENT_NODE)
+ {
+ out.write(encodeText(eol));
+ }
+ break;
+ case Node.DOCUMENT_NODE:
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ if (mode == Stylesheet.OUTPUT_XML)
+ {
+ if ("UTF-16".equalsIgnoreCase(encoding))
+ {
+ out.write(0xfe);
+ out.write(0xff);
+ }
+ if (!"yes".equals(node.getUserData("omit-xml-declaration")) &&
+ xmlDeclaration)
+ {
+ Document doc = (node instanceof Document) ?
+ (Document) node : null;
+ String version = (doc != null) ? doc.getXmlVersion() : null;
+ if (version == null)
+ {
+ version = (String) node.getUserData("version");
+ }
+ if (version == null)
+ {
+ version = "1.0";
+ }
+ out.write(BRA);
+ out.write(0x3f);
+ out.write("xml version='".getBytes("US-ASCII"));
+ out.write(version.getBytes("US-ASCII"));
+ out.write(APOS);
+ if (!("UTF-8".equalsIgnoreCase(encoding)))
+ {
+ out.write(" encoding='".getBytes("US-ASCII"));
+ out.write(encoding.getBytes("US-ASCII"));
+ out.write(APOS);
+ }
+ if ((doc != null && doc.getXmlStandalone()) ||
+ "yes".equals(node.getUserData("standalone")))
+ {
+ out.write(" standalone='yes'".getBytes("US-ASCII"));
+ }
+ out.write(0x3f);
+ out.write(KET);
+ out.write(encodeText(eol));
+ }
+ // TODO warn if not outputting the declaration would be a
+ // problem
+ }
+ else if (mode == Stylesheet.OUTPUT_HTML)
+ {
+ // Ensure that encoding is accessible
+ String mediaType = (String) node.getUserData("media-type");
+ if (mediaType == null)
+ {
+ mediaType = "text/html";
+ }
+ String contentType = mediaType + "; charset=" +
+ ((encoding.indexOf(' ') != -1) ?
+ "\"" + encoding + "\"" :
+ encoding);
+ Document doc = (node instanceof Document) ? (Document) node :
+ node.getOwnerDocument();
+ Node html = null;
+ for (Node ctx = node.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ if (ctx.getNodeType() == Node.ELEMENT_NODE)
+ {
+ html = ctx;
+ break;
+ }
+ }
+ if (html == null)
+ {
+ html = doc.createElement("html");
+ node.appendChild(html);
+ }
+ Node head = null;
+ for (Node ctx = html.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ if (ctx.getNodeType() == Node.ELEMENT_NODE)
+ {
+ String name = ctx.getLocalName();
+ if (name == null)
+ {
+ name = ctx.getNodeName();
+ }
+ if ("head".equalsIgnoreCase(name))
+ {
+ head = ctx;
+ break;
+ }
+ }
+ }
+ if (head == null)
+ {
+ head = doc.createElement("head");
+ Node c1 = null;
+ for (Node ctx = html.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ if (ctx.getNodeType() == Node.ELEMENT_NODE)
+ {
+ c1 = ctx;
+ break;
+ }
+ }
+ if (c1 != null)
+ {
+ html.insertBefore(head, c1);
+ }
+ else
+ {
+ html.appendChild(head);
+ }
+ }
+ Node meta = null;
+ Node metaContent = null;
+ for (Node ctx = head.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ if (ctx.getNodeType() == Node.ELEMENT_NODE)
+ {
+ String name = ctx.getLocalName();
+ if (name == null)
+ {
+ name = ctx.getNodeName();
+ }
+ if ("meta".equalsIgnoreCase(name))
+ {
+ NamedNodeMap metaAttrs = ctx.getAttributes();
+ int len = metaAttrs.getLength();
+ String httpEquiv = null;
+ Node content = null;
+ for (int i = 0; i < len; i++)
+ {
+ Node attr = metaAttrs.item(i);
+ String attrName = attr.getNodeName();
+ if ("http-equiv".equalsIgnoreCase(attrName))
+ {
+ httpEquiv = attr.getNodeValue();
+ }
+ else if ("content".equalsIgnoreCase(attrName))
+ {
+ content = attr;
+ }
+ }
+ if ("Content-Type".equalsIgnoreCase(httpEquiv))
+ {
+ meta = ctx;
+ metaContent = content;
+ break;
+ }
+ }
+ }
+ }
+ if (meta == null)
+ {
+ meta = doc.createElement("meta");
+ // Insert first
+ Node first = head.getFirstChild();
+ if (first == null)
+ {
+ head.appendChild(meta);
+ }
+ else
+ {
+ head.insertBefore(meta, first);
+ }
+ Node metaHttpEquiv = doc.createAttribute("http-equiv");
+ meta.getAttributes().setNamedItem(metaHttpEquiv);
+ metaHttpEquiv.setNodeValue("Content-Type");
+ }
+ if (metaContent == null)
+ {
+ metaContent = doc.createAttribute("content");
+ meta.getAttributes().setNamedItem(metaContent);
+ }
+ metaContent.setNodeValue(contentType);
+ // phew
+ }
+ children = node.getFirstChild();
+ if (children != null)
+ {
+ serialize(children, out, convertToCdata);
+ }
+ break;
+ case Node.DOCUMENT_TYPE_NODE:
+ DocumentType doctype = (DocumentType) node;
+ out.write(BRA);
+ out.write(BANG);
+ out.write(encodeText("DOCTYPE "));
+ value = doctype.getNodeName();
+ out.write(encodeText(value));
+ String publicId = doctype.getPublicId();
+ if (publicId != null)
+ {
+ out.write(encodeText(" PUBLIC "));
+ out.write(APOS);
+ out.write(encodeText(publicId));
+ out.write(APOS);
+ }
+ String systemId = doctype.getSystemId();
+ if (systemId != null)
+ {
+ out.write(encodeText(" SYSTEM "));
+ out.write(APOS);
+ out.write(encodeText(systemId));
+ out.write(APOS);
+ }
+ String internalSubset = doctype.getInternalSubset();
+ if (internalSubset != null)
+ {
+ out.write(encodeText(internalSubset));
+ }
+ out.write(KET);
+ out.write(eol.getBytes(encoding));
+ break;
+ case Node.ENTITY_REFERENCE_NODE:
+ value = "&" + node.getNodeValue() + ";";
+ out.write(encodeText(value));
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ value = "" + node.getNodeName() + " " + node.getNodeValue() + "?>";
+ out.write(encodeText(value));
+ Node pp = node.getParentNode();
+ if (pp != null && pp.getNodeType() == Node.DOCUMENT_NODE)
+ {
+ out.write(encodeText(eol));
+ }
+ break;
+ }
+ if (defined)
+ {
+ undefine(uri);
+ }
+ }
+
+ boolean isDefined(String uri)
+ {
+ return XMLConstants.XML_NS_URI.equals(uri) ||
+ XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
+ namespaces.containsKey(uri);
+ }
+
+ String define(String uri, String prefix)
+ {
+ while (namespaces.containsValue(prefix))
+ {
+ // Fabricate new prefix
+ prefix = prefix + "_";
+ }
+ namespaces.put(uri, prefix);
+ return prefix;
+ }
+
+ void undefine(String uri)
+ {
+ namespaces.remove(uri);
+ }
+
+ final byte[] encodeText(String text)
+ throws IOException
+ {
+ encoder.reset();
+ if (!encoder.canEncode(text))
+ {
+ // Check each character
+ StringBuffer buf = new StringBuffer();
+ int len = text.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = text.charAt(i);
+ if (encoder.canEncode(c))
+ {
+ buf.append(c);
+ }
+ else
+ {
+ // Replace with character entity reference
+ String hex = Integer.toHexString((int) c);
+ buf.append("");
+ buf.append(hex);
+ buf.append(';');
+ }
+ }
+ text = buf.toString();
+ }
+ ByteBuffer encoded = encoder.encode(CharBuffer.wrap(text));
+ int len = encoded.limit() - encoded.position();
+ if (encoded.hasArray())
+ {
+ byte[] ret = encoded.array();
+ if (ret.length > len)
+ {
+ // Why?
+ byte[] ret2 = new byte[len];
+ System.arraycopy(ret, 0, ret2, 0, len);
+ ret = ret2;
+ }
+ return ret;
+ }
+ encoded.flip();
+ byte[] ret = new byte[len];
+ encoded.get(ret, 0, len);
+ return ret;
+ }
+
+ String encode(String text, boolean encodeCtl, boolean inAttr)
+ {
+ int len = text.length();
+ StringBuffer buf = null;
+ for (int i = 0; i < len; i++)
+ {
+ char c = text.charAt(i);
+ if (c == '<')
+ {
+ if (buf == null)
+ {
+ buf = new StringBuffer(text.substring(0, i));
+ }
+ buf.append("<");
+ }
+ else if (c == '>')
+ {
+ if (buf == null)
+ {
+ buf = new StringBuffer(text.substring(0, i));
+ }
+ buf.append(">");
+ }
+ else if (c == '&')
+ {
+ if (mode == Stylesheet.OUTPUT_HTML && (i + 1) < len &&
+ text.charAt(i + 1) == '{')
+ {
+ if (buf != null)
+ {
+ buf.append(c);
+ }
+ }
+ else
+ {
+ if (buf == null)
+ {
+ buf = new StringBuffer(text.substring(0, i));
+ }
+ buf.append("&");
+ }
+ }
+ else if (c == '\'' && inAttr)
+ {
+ if (buf == null)
+ {
+ buf = new StringBuffer(text.substring(0, i));
+ }
+ buf.append("'");
+ }
+ else if (c == '"' && inAttr)
+ {
+ if (buf == null)
+ {
+ buf = new StringBuffer(text.substring(0, i));
+ }
+ buf.append(""");
+ }
+ else if (encodeCtl)
+ {
+ if (c < 0x20)
+ {
+ if (buf == null)
+ {
+ buf = new StringBuffer(text.substring(0, i));
+ }
+ buf.append('&');
+ buf.append('#');
+ buf.append((int) c);
+ buf.append(';');
+ }
+ else if (buf != null)
+ {
+ buf.append(c);
+ }
+ }
+ else if (buf != null)
+ {
+ buf.append(c);
+ }
+ }
+ return (buf == null) ? text : buf.toString();
+ }
+
+ String toString(Node node)
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try
+ {
+ serialize(node, out);
+ return new String(out.toByteArray(), encoding);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ boolean isHTMLBoolean(Attr attr, String attrName)
+ {
+ attrName = attrName.toLowerCase();
+ Node element = attr.getOwnerElement();
+ String elementName = element.getLocalName();
+ if (elementName == null)
+ {
+ elementName = element.getNodeName();
+ }
+ elementName = elementName.toLowerCase();
+ Collection attributes =
+ (Collection) HTML_BOOLEAN_ATTRIBUTES.get(elementName);
+ return (attributes != null && attributes.contains(attrName));
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/Stylesheet.java b/libjava/classpath/gnu/xml/transform/Stylesheet.java
new file mode 100644
index 0000000..99431b6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/Stylesheet.java
@@ -0,0 +1,1832 @@
+/* Stylesheet.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionResolver;
+import javax.xml.xpath.XPathExpressionException;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import org.w3c.dom.UserDataHandler;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.NameTest;
+import gnu.xml.xpath.NodeTypeTest;
+import gnu.xml.xpath.Pattern;
+import gnu.xml.xpath.Selector;
+import gnu.xml.xpath.Root;
+import gnu.xml.xpath.Test;
+import gnu.xml.xpath.XPathImpl;
+
+/**
+ * An XSL stylesheet.
+ *
+ * @author Chris Burdess
+ */
+class Stylesheet
+ implements NamespaceContext, XPathFunctionResolver, UserDataHandler, Cloneable
+{
+
+ static final String XSL_NS = "http://www.w3.org/1999/XSL/Transform";
+
+ static final int OUTPUT_XML = 0;
+ static final int OUTPUT_HTML = 1;
+ static final int OUTPUT_TEXT = 2;
+
+ final TransformerFactoryImpl factory;
+ TransformerImpl transformer;
+ Stylesheet parent;
+ final XPathImpl xpath;
+ final String systemId;
+ final int precedence;
+
+ final boolean debug;
+
+ /**
+ * Version of XSLT.
+ */
+ String version;
+
+ Collection extensionElementPrefixes;
+ Collection excludeResultPrefixes;
+
+ /**
+ * Set of element names for which we should strip whitespace.
+ */
+ Set stripSpace;
+
+ /**
+ * Set of element names for which we should preserve whitespace.
+ */
+ Set preserveSpace;
+
+ /**
+ * Output options.
+ */
+ Node output;
+ int outputMethod;
+ String outputVersion;
+ String outputEncoding;
+ boolean outputOmitXmlDeclaration;
+ boolean outputStandalone;
+ String outputPublicId;
+ String outputSystemId;
+ Collection outputCdataSectionElements;
+ boolean outputIndent;
+ String outputMediaType;
+
+ /**
+ * Keys.
+ */
+ Collection keys;
+
+ /**
+ * Decimal formats.
+ */
+ Map decimalFormats;
+
+ /**
+ * Namespace aliases.
+ */
+ Map namespaceAliases;
+
+ /**
+ * Attribute-sets.
+ */
+ List attributeSets;
+
+ /**
+ * Variables.
+ */
+ List variables;
+
+ /**
+ * Variable and parameter bindings.
+ */
+ Bindings bindings;
+
+ /**
+ * Templates.
+ */
+ LinkedList templates;
+
+ TemplateNode builtInNodeTemplate;
+ TemplateNode builtInTextTemplate;
+
+ /**
+ * Holds the current node while parsing.
+ * Necessary to associate the document function with its declaring node,
+ * to resolve namespaces, and to maintain the current node for the
+ * current() function.
+ */
+ Node current;
+
+ /**
+ * Set by a terminating message.
+ */
+ transient boolean terminated;
+
+ /**
+ * Current template in force.
+ */
+ transient Template currentTemplate;
+
+ Stylesheet(TransformerFactoryImpl factory,
+ Stylesheet parent,
+ Document doc,
+ String systemId,
+ int precedence)
+ throws TransformerConfigurationException
+ {
+ this.factory = factory;
+ this.systemId = systemId;
+ this.precedence = precedence;
+ this.parent = parent;
+ extensionElementPrefixes = new HashSet();
+ excludeResultPrefixes = new HashSet();
+ stripSpace = new LinkedHashSet();
+ preserveSpace = new LinkedHashSet();
+ outputCdataSectionElements = new LinkedHashSet();
+ xpath = (XPathImpl) factory.xpathFactory.newXPath();
+ if (parent == null)
+ {
+ bindings = new Bindings(this);
+ attributeSets = new LinkedList();
+ variables = new LinkedList();
+ namespaceAliases = new LinkedHashMap();
+ templates = new LinkedList();
+ keys = new LinkedList();
+ decimalFormats = new LinkedHashMap();
+ initDefaultDecimalFormat();
+ xpath.setNamespaceContext(this);
+ xpath.setXPathFunctionResolver(this);
+ }
+ else
+ {
+ /* Test for import circularity */
+ for (Stylesheet ctx = this; ctx.parent != null; ctx = ctx.parent)
+ {
+ if (systemId != null && systemId.equals(ctx.parent.systemId))
+ {
+ String msg = "circularity importing " + systemId;
+ throw new TransformerConfigurationException(msg);
+ }
+ }
+ /* OK */
+ Stylesheet root = getRootStylesheet();
+ bindings = root.bindings;
+ attributeSets = root.attributeSets;
+ variables = root.variables;
+ namespaceAliases = root.namespaceAliases;
+ templates = root.templates;
+ keys = root.keys;
+ decimalFormats = root.decimalFormats;
+ xpath.setNamespaceContext(root);
+ xpath.setXPathFunctionResolver(root);
+ }
+ xpath.setXPathVariableResolver(bindings);
+
+ Test anyNode = new NodeTypeTest((short) 0);
+ List tests = Collections.singletonList(anyNode);
+ builtInNodeTemplate =
+ new ApplyTemplatesNode(new Selector(Selector.CHILD, tests),
+ null, null, null, true);
+ builtInTextTemplate =
+ new ValueOfNode(new Selector(Selector.SELF, tests),
+ false);
+
+ parse(doc.getDocumentElement(), true);
+ current = doc; // Alow namespace resolution during processing
+
+ debug = ("yes".equals(System.getProperty("xsl.debug")));
+
+ if (debug)
+ {
+ System.err.println("Stylesheet: " + doc.getDocumentURI());
+ for (Iterator i = templates.iterator(); i.hasNext(); )
+ {
+ Template t = (Template) i.next();
+ t.list(System.err);
+ System.err.println("--------------------");
+ }
+ }
+ }
+
+ Stylesheet getRootStylesheet()
+ {
+ Stylesheet stylesheet = this;
+ while (stylesheet.parent != null)
+ {
+ stylesheet = stylesheet.parent;
+ }
+ return stylesheet;
+ }
+
+ void initDefaultDecimalFormat()
+ {
+ DecimalFormat defaultDecimalFormat = new DecimalFormat();
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+ symbols.setDecimalSeparator('.');
+ symbols.setGroupingSeparator(',');
+ symbols.setPercent('%');
+ symbols.setPerMill('\u2030');
+ symbols.setZeroDigit('0');
+ symbols.setDigit('#');
+ symbols.setPatternSeparator(';');
+ symbols.setInfinity("Infinity");
+ symbols.setNaN("NaN");
+ symbols.setMinusSign('-');
+ defaultDecimalFormat.setDecimalFormatSymbols(symbols);
+ decimalFormats.put(null, defaultDecimalFormat);
+ }
+
+ // -- Cloneable --
+
+ public Object clone()
+ {
+ try
+ {
+ Stylesheet clone = (Stylesheet) super.clone();
+ clone.bindings = (Bindings) bindings.clone();
+
+ LinkedList templates2 = new LinkedList();
+ for (Iterator i = templates.iterator(); i.hasNext(); )
+ {
+ Template t = (Template) i.next();
+ templates2.add(t.clone(clone));
+ }
+ clone.templates = templates2;
+
+ LinkedList attributeSets2 = new LinkedList();
+ for (Iterator i = attributeSets.iterator(); i.hasNext(); )
+ {
+ AttributeSet as = (AttributeSet) i.next();
+ attributeSets2.add(as.clone(clone));
+ }
+ clone.attributeSets = attributeSets2;
+
+ LinkedList variables2 = new LinkedList();
+ for (Iterator i = variables.iterator(); i.hasNext(); )
+ {
+ ParameterNode var = (ParameterNode) i.next();
+ variables2.add(var.clone(clone));
+ }
+ clone.variables = variables2;
+
+ LinkedList keys2 = new LinkedList();
+ for (Iterator i = keys.iterator(); i.hasNext(); )
+ {
+ Key k = (Key) i.next();
+ keys2.add(k.clone(clone));
+ }
+ clone.keys = keys2;
+
+ return clone;
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new Error(e.getMessage());
+ }
+ }
+
+ // -- Variable evaluation --
+
+ void initTopLevelVariables(Node context)
+ throws TransformerException
+ {
+ current = context;
+ // Sort the variables into order
+ // See XSLT 11.4: "If the template or expression specifying the value of
+ // a global variable x references a global variable y, then the value
+ // for y must be computed before the value of x."
+ List topLevel = new ArrayList(variables);
+ Collections.sort(topLevel);
+ for (Iterator i = topLevel.iterator(); i.hasNext(); )
+ {
+ ParameterNode var = (ParameterNode) i.next();
+ bindings.set(var.name,
+ var.getValue(this, null, context, 1, 1),
+ var.type);
+ }
+ current = null;
+ }
+
+ // -- NamespaceContext --
+
+ public String getNamespaceURI(String prefix)
+ {
+ return (current == null) ? null : current.lookupNamespaceURI(prefix);
+ }
+
+ public String getPrefix(String namespaceURI)
+ {
+ return (current == null) ? null : current.lookupPrefix(namespaceURI);
+ }
+
+ public Iterator getPrefixes(String namespaceURI)
+ {
+ // TODO
+ return Collections.singleton(getPrefix(namespaceURI)).iterator();
+ }
+
+ final QName getQName(String name)
+ {
+ String localName = name, uri = null, prefix = null;
+ int ci = name.indexOf(':');
+ if (ci != -1)
+ {
+ prefix = name.substring(0, ci);
+ localName = name.substring(ci + 1);
+ uri = getNamespaceURI(prefix);
+ }
+ return new QName(uri, localName, prefix);
+ }
+
+ // -- Template selection --
+
+ TemplateNode getTemplate(QName mode, Node context, boolean applyImports)
+ throws TransformerException
+ {
+ if (debug)
+ {
+ System.err.println("getTemplate: mode="+mode+" context="+context);
+ }
+ Set candidates = new TreeSet();
+ for (Iterator j = templates.iterator(); j.hasNext(); )
+ {
+ Template t = (Template) j.next();
+ boolean isMatch = t.matches(mode, context);
+ if (applyImports)
+ {
+ if (currentTemplate == null)
+ {
+ String msg = "current template may not be null " +
+ "during apply-imports";
+ throw new TransformerException(msg);
+ }
+ if (!currentTemplate.imports(t))
+ {
+ isMatch = false;
+ }
+ }
+ //System.err.println("\t"+context+" "+t+"="+isMatch);
+ if (isMatch)
+ {
+ candidates.add(t);
+ }
+ }
+ //System.err.println("\tcandidates="+candidates);
+ if (candidates.isEmpty())
+ {
+ // Apply built-in template
+ // Current template is unchanged
+ if (debug)
+ {
+ System.err.println("\tbuiltInTemplate context="+context);
+ }
+ switch (context.getNodeType())
+ {
+ case Node.ELEMENT_NODE:
+ case Node.DOCUMENT_NODE:
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ case Node.COMMENT_NODE:
+ return builtInNodeTemplate;
+ case Node.TEXT_NODE:
+ case Node.ATTRIBUTE_NODE:
+ return builtInTextTemplate;
+ default:
+ return null;
+ }
+ }
+ else
+ {
+ Template t = (Template) candidates.iterator().next();
+ // Set current template
+ currentTemplate = t;
+ if (debug)
+ {
+ System.err.println("\ttemplate="+t+" context="+context);
+ }
+ return t.node;
+ }
+ }
+
+ TemplateNode getTemplate(QName mode, QName name)
+ throws TransformerException
+ {
+ //System.err.println("getTemplate: mode="+mode+" name="+name);
+ Set candidates = new TreeSet();
+ for (Iterator j = templates.iterator(); j.hasNext(); )
+ {
+ Template t = (Template) j.next();
+ boolean isMatch = t.matches(name);
+ //System.err.println("\t"+name+" "+t+"="+isMatch);
+ if (isMatch)
+ {
+ candidates.add(t);
+ }
+ }
+ if (candidates.isEmpty())
+ {
+ return null;
+ //throw new TransformerException("template '" + name + "' not found");
+ }
+ Template t = (Template) candidates.iterator().next();
+ //System.err.println("\ttemplate="+t+" context="+context);
+ return t.node;
+ }
+
+ /**
+ * template
+ */
+ final Template parseTemplate(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ String n = getAttribute(attrs, "name");
+ QName name = (n == null) ? null : getQName(n);
+ String m = getAttribute(attrs, "match");
+ Pattern match = null;
+ if (m != null)
+ {
+ try
+ {
+ match = (Pattern) xpath.compile(m);
+ }
+ catch (ClassCastException e)
+ {
+ String msg = "illegal pattern: " + m;
+ throw new TransformerConfigurationException(msg);
+ }
+ }
+ String p = getAttribute(attrs, "priority");
+ String mm = getAttribute(attrs, "mode");
+ QName mode = (mm == null) ? null : getQName(mm);
+ double priority = (p == null) ? Template.DEFAULT_PRIORITY :
+ Double.parseDouble(p);
+ Node children = node.getFirstChild();
+ return new Template(this, name, match, parse(children),
+ precedence, priority, mode);
+ }
+
+ /**
+ * output
+ */
+ final void parseOutput(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException
+ {
+ output = node;
+ String method = getAttribute(attrs, "method");
+ if ("xml".equals(method) || method == null)
+ {
+ outputMethod = OUTPUT_XML;
+ }
+ else if ("html".equals(method))
+ {
+ outputMethod = OUTPUT_HTML;
+ }
+ else if ("text".equals(method))
+ {
+ outputMethod = OUTPUT_TEXT;
+ }
+ else
+ {
+ String msg = "unsupported output method: " + method;
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ outputPublicId = getAttribute(attrs, "public-id");
+ outputSystemId = getAttribute(attrs, "system-id");
+ outputEncoding = getAttribute(attrs, "encoding");
+ String indent = getAttribute(attrs, "indent");
+ if (indent != null)
+ {
+ outputIndent = "yes".equals(indent);
+ }
+ outputVersion = getAttribute(attrs, "version");
+ String omitXmlDecl = getAttribute(attrs, "omit-xml-declaration");
+ if (omitXmlDecl != null)
+ {
+ outputOmitXmlDeclaration = "yes".equals(omitXmlDecl);
+ }
+ String standalone = getAttribute(attrs, "standalone");
+ if (standalone != null)
+ {
+ outputStandalone = "yes".equals(standalone);
+ }
+ outputMediaType = getAttribute(attrs, "media-type");
+ String cdataSectionElements =
+ getAttribute(attrs, "cdata-section-elements");
+ if (cdataSectionElements != null)
+ {
+ StringTokenizer st = new StringTokenizer(cdataSectionElements, " ");
+ while (st.hasMoreTokens())
+ {
+ outputCdataSectionElements.add(st.nextToken());
+ }
+ }
+ }
+
+ /**
+ * key
+ */
+ final void parseKey(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ String n = getRequiredAttribute(attrs, "name", node);
+ String m = getRequiredAttribute(attrs, "match", node);
+ String u = getRequiredAttribute(attrs, "use", node);
+ QName name = getQName(n);
+ Expr use = (Expr) xpath.compile(u);
+ try
+ {
+ Pattern match = (Pattern) xpath.compile(m);
+ Key key = new Key(name, match, use);
+ keys.add(key);
+ }
+ catch (ClassCastException e)
+ {
+ throw new TransformerConfigurationException("invalid pattern: " + m);
+ }
+ }
+
+ /**
+ * decimal-format
+ */
+ final void parseDecimalFormat(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException
+ {
+ String dfName = getAttribute(attrs, "name");
+ DecimalFormat df = new DecimalFormat();
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+ symbols.setDecimalSeparator(parseDFChar(attrs, "decimal-separator", '.'));
+ symbols.setGroupingSeparator(parseDFChar(attrs, "grouping-separator", ','));
+ symbols.setInfinity(parseDFString(attrs, "infinity", "Infinity"));
+ symbols.setMinusSign(parseDFChar(attrs, "minus-sign", '-'));
+ symbols.setNaN(parseDFString(attrs, "NaN", "NaN"));
+ symbols.setPercent(parseDFChar(attrs, "percent", '%'));
+ symbols.setPerMill(parseDFChar(attrs, "per-mille", '\u2030'));
+ symbols.setZeroDigit(parseDFChar(attrs, "zero-digit", '0'));
+ symbols.setDigit(parseDFChar(attrs, "digit", '#'));
+ symbols.setPatternSeparator(parseDFChar(attrs, "pattern-separator", ';'));
+ df.setDecimalFormatSymbols(symbols);
+ decimalFormats.put(dfName, df);
+ }
+
+ private final char parseDFChar(NamedNodeMap attrs, String name, char def)
+ throws TransformerConfigurationException
+ {
+ Node attr = attrs.getNamedItem(name);
+ try
+ {
+ return (attr == null) ? def : attr.getNodeValue().charAt(0);
+ }
+ catch (StringIndexOutOfBoundsException e)
+ {
+ throw new TransformerConfigurationException("empty attribute '" +
+ name +
+ "' in decimal-format", e);
+ }
+ }
+
+ private final String parseDFString(NamedNodeMap attrs, String name,
+ String def)
+ {
+ Node attr = attrs.getNamedItem(name);
+ return (attr == null) ? def : attr.getNodeValue();
+ }
+
+ /**
+ * namespace-alias
+ */
+ final void parseNamespaceAlias(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException
+ {
+ String sp = getRequiredAttribute(attrs, "stylesheet-prefix", node);
+ String rp = getRequiredAttribute(attrs, "result-prefix", node);
+ namespaceAliases.put(sp, rp);
+ }
+
+ /**
+ * attribute-set
+ */
+ final void parseAttributeSet(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ TemplateNode children = parse(node.getFirstChild());
+ String name = getRequiredAttribute(attrs, "name", node);
+ String uas = getAttribute(attrs, "use-attribute-sets");
+ attributeSets.add(new AttributeSet(children, name, uas));
+ }
+
+ /**
+ * Parse top-level elements.
+ */
+ void parse(Node node, boolean root)
+ throws TransformerConfigurationException
+ {
+ while (node != null)
+ {
+ current = node;
+ doParse(node, root);
+ node = node.getNextSibling();
+ }
+ }
+
+ void doParse(Node node, boolean root)
+ throws TransformerConfigurationException
+ {
+ try
+ {
+ String namespaceUri = node.getNamespaceURI();
+ if (XSL_NS.equals(namespaceUri) &&
+ node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ String name = node.getLocalName();
+ NamedNodeMap attrs = node.getAttributes();
+ if ("stylesheet".equals(name))
+ {
+ version = getAttribute(attrs, "version");
+ String eep = getAttribute(attrs, "extension-element-prefixes");
+ if (eep != null)
+ {
+ StringTokenizer st = new StringTokenizer(eep);
+ while (st.hasMoreTokens())
+ {
+ extensionElementPrefixes.add(st.nextToken());
+ }
+ }
+ String erp = getAttribute(attrs, "exclude-result-prefixes");
+ if (erp != null)
+ {
+ StringTokenizer st = new StringTokenizer(erp);
+ while (st.hasMoreTokens())
+ {
+ excludeResultPrefixes.add(st.nextToken());
+ }
+ }
+ parse(node.getFirstChild(), false);
+ }
+ else if ("template".equals(name))
+ {
+ templates.add(parseTemplate(node, attrs));
+ }
+ else if ("param".equals(name) ||
+ "variable".equals(name))
+ {
+ int type = "variable".equals(name) ?
+ Bindings.VARIABLE : Bindings.PARAM;
+ TemplateNode content = parse(node.getFirstChild());
+ QName paramName =
+ getQName(getRequiredAttribute(attrs, "name", node));
+ String select = getAttribute(attrs, "select");
+ ParameterNode param;
+ if (select != null && select.length() > 0)
+ {
+ if (content != null)
+ {
+ String msg = "parameter '" + paramName +
+ "' has both select and content";
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ Expr expr = (Expr) xpath.compile(select);
+ param = new ParameterNode(paramName, expr, type);
+ }
+ else
+ {
+ param = new ParameterNode(paramName, null, type);
+ param.children = content;
+ }
+ variables.add(param);
+ }
+ else if ("include".equals(name) || "import".equals(name))
+ {
+ int delta = "import".equals(name) ? -1 : 0;
+ String href = getRequiredAttribute(attrs, "href", node);
+ Source source;
+ synchronized (factory.resolver)
+ {
+ if (transformer != null)
+ {
+ factory.resolver
+ .setUserResolver(transformer.getURIResolver());
+ factory.resolver
+ .setUserListener(transformer.getErrorListener());
+ }
+ source = factory.resolver.resolve(systemId, href);
+ }
+ factory.newStylesheet(source, precedence + delta, this);
+ }
+ else if ("output".equals(name))
+ {
+ parseOutput(node, attrs);
+ }
+ else if ("preserve-space".equals(name))
+ {
+ String elements =
+ getRequiredAttribute(attrs, "elements", node);
+ StringTokenizer st = new StringTokenizer(elements,
+ " \t\n\r");
+ while (st.hasMoreTokens())
+ {
+ preserveSpace.add(parseNameTest(st.nextToken()));
+ }
+ }
+ else if ("strip-space".equals(name))
+ {
+ String elements =
+ getRequiredAttribute(attrs, "elements", node);
+ StringTokenizer st = new StringTokenizer(elements,
+ " \t\n\r");
+ while (st.hasMoreTokens())
+ {
+ stripSpace.add(parseNameTest(st.nextToken()));
+ }
+ }
+ else if ("key".equals(name))
+ {
+ parseKey(node, attrs);
+ }
+ else if ("decimal-format".equals(name))
+ {
+ parseDecimalFormat(node, attrs);
+ }
+ else if ("namespace-alias".equals(name))
+ {
+ parseNamespaceAlias(node, attrs);
+ }
+ else if ("attribute-set".equals(name))
+ {
+ parseAttributeSet(node, attrs);
+ }
+ }
+ else if (root)
+ {
+ // Literal document element
+ Attr versionNode =
+ ((Element)node).getAttributeNodeNS(XSL_NS, "version");
+ if (versionNode == null)
+ {
+ String msg = "no xsl:version attribute on literal result node";
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ version = versionNode.getValue();
+ Node rootClone = node.cloneNode(true);
+ NamedNodeMap attrs = rootClone.getAttributes();
+ attrs.removeNamedItemNS(XSL_NS, "version");
+ templates.add(new Template(this, null, new Root(),
+ parse(rootClone),
+ precedence,
+ Template.DEFAULT_PRIORITY,
+ null));
+ }
+ else
+ {
+ // Skip unknown elements, text, comments, etc
+ }
+ }
+ catch (TransformerException e)
+ {
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(e.getMessage(), l, e);
+ }
+ catch (DOMException e)
+ {
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(e.getMessage(), l, e);
+ }
+ catch (XPathExpressionException e)
+ {
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(e.getMessage(), l, e);
+ }
+ }
+
+ final NameTest parseNameTest(String token)
+ {
+ if ("*".equals(token))
+ {
+ return new NameTest(null, true, true);
+ }
+ else if (token.endsWith(":*"))
+ {
+ QName qName = getQName(token.substring(0, token.length() - 2));
+ return new NameTest(qName, true, false);
+ }
+ else
+ {
+ QName qName = getQName(token);
+ return new NameTest(qName, false, false);
+ }
+ }
+
+ final TemplateNode parseAttributeValueTemplate(String value, Node source)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ current = source;
+ // Tokenize
+ int len = value.length();
+ int off = 0;
+ List tokens = new ArrayList(); // text tokens
+ List types = new ArrayList(); // literal or expression
+ int depth = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '{')
+ {
+ if (i < (len - 1) && value.charAt(i + 1) == '{')
+ {
+ tokens.add(value.substring(off, i + 1));
+ types.add(Boolean.FALSE);
+ i++;
+ off = i + 1;
+ continue;
+ }
+ if (depth == 0)
+ {
+ if (i - off > 0)
+ {
+ tokens.add(value.substring(off, i));
+ types.add(Boolean.FALSE);
+ }
+ off = i + 1;
+ }
+ depth++;
+ }
+ else if (c == '}')
+ {
+ if (i < (len - 1) && value.charAt(i + 1) == '}')
+ {
+ tokens.add(value.substring(off, i + 1));
+ types.add(Boolean.FALSE);
+ i++;
+ off = i + 1;
+ continue;
+ }
+ if (depth == 1)
+ {
+ if (i - off > 0)
+ {
+ tokens.add(value.substring(off, i));
+ types.add(Boolean.TRUE);
+ }
+ else
+ {
+ String msg = "attribute value template " +
+ "must contain expression: " + value;
+ DOMSourceLocator l = new DOMSourceLocator(source);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ off = i + 1;
+ }
+ depth--;
+ }
+ }
+ if (depth > 0)
+ {
+ String msg = "invalid attribute value template: " + value;
+ throw new TransformerConfigurationException(msg);
+ }
+ if (len - off > 0)
+ {
+ // Trailing text
+ tokens.add(value.substring(off));
+ types.add(Boolean.FALSE);
+ }
+
+ // Construct template node tree
+ TemplateNode ret = null;
+ Document doc = source.getOwnerDocument();
+ len = tokens.size();
+ for (int i = len - 1; i >= 0; i--)
+ {
+ String token = (String) tokens.get(i);
+ Boolean type = (Boolean) types.get(i);
+ if (type == Boolean.TRUE)
+ {
+ // Expression text
+ Expr select = (Expr) xpath.compile(token);
+ TemplateNode ret2 = new ValueOfNode(select, false);
+ ret2.next = ret;
+ ret = ret2;
+ }
+ else
+ {
+ // Verbatim text
+ TemplateNode ret2 = new LiteralNode(doc.createTextNode(token));
+ ret2.next = ret;
+ ret = ret2;
+ }
+ }
+ return ret;
+ }
+
+ boolean isPreserved(Text text)
+ throws TransformerConfigurationException
+ {
+ // Check characters in text
+ String value = text.getData();
+ if (value != null)
+ {
+ int len = value.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c != 0x20 && c != 0x09 && c != 0x0a && c != 0x0d)
+ {
+ return true;
+ }
+ }
+ }
+ // Check parent node
+ Node ctx = text.getParentNode();
+ if (!preserveSpace.isEmpty())
+ {
+ for (Iterator i = preserveSpace.iterator(); i.hasNext(); )
+ {
+ NameTest preserveTest = (NameTest) i.next();
+ if (preserveTest.matches(ctx, 1, 1))
+ {
+ boolean override = false;
+ if (!stripSpace.isEmpty())
+ {
+ for (Iterator j = stripSpace.iterator(); j.hasNext(); )
+ {
+ NameTest stripTest = (NameTest) j.next();
+ if (stripTest.matches(ctx, 1, 1))
+ {
+ override = true;
+ break;
+ }
+ }
+ }
+ if (!override)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ // Check whether any ancestor specified xml:space
+ while (ctx != null)
+ {
+ if (ctx.getNodeType() == Node.ELEMENT_NODE)
+ {
+ Element element = (Element) ctx;
+ String xmlSpace = element.getAttribute("xml:space");
+ if ("default".equals(xmlSpace))
+ {
+ break;
+ }
+ else if ("preserve".equals(xmlSpace))
+ {
+ return true;
+ }
+ else if (xmlSpace.length() > 0)
+ {
+ String msg = "Illegal value for xml:space: " + xmlSpace;
+ throw new TransformerConfigurationException(msg);
+ }
+ else if ("text".equals(ctx.getLocalName()) &&
+ XSL_NS.equals(ctx.getNamespaceURI()))
+ {
+ // xsl:text implies xml:space='preserve'
+ return true;
+ }
+ }
+ ctx = ctx.getParentNode();
+ }
+ return false;
+ }
+
+ public XPathFunction resolveFunction(QName name, int arity)
+ {
+ String uri = name.getNamespaceURI();
+ if (XSL_NS.equals(uri) || uri == null || uri.length() == 0)
+ {
+ String localName = name.getLocalPart();
+ if ("document".equals(localName) && (arity == 1 || arity == 2))
+ {
+ if (current == null)
+ {
+ throw new RuntimeException("current is null");
+ }
+ return new DocumentFunction(getRootStylesheet(), current);
+ }
+ else if ("key".equals(localName) && (arity == 2))
+ {
+ return new KeyFunction(getRootStylesheet());
+ }
+ else if ("format-number".equals(localName) &&
+ (arity == 2 || arity == 3))
+ {
+ return new FormatNumberFunction(getRootStylesheet());
+ }
+ else if ("current".equals(localName) && (arity == 0))
+ {
+ return new CurrentFunction(getRootStylesheet());
+ }
+ else if ("unparsed-entity-uri".equals(localName) && (arity == 1))
+ {
+ return new UnparsedEntityUriFunction();
+ }
+ else if ("generate-id".equals(localName) &&
+ (arity == 1 || arity == 0))
+ {
+ return new GenerateIdFunction();
+ }
+ else if ("system-property".equals(localName) && (arity == 1))
+ {
+ return new SystemPropertyFunction();
+ }
+ else if ("element-available".equals(localName) && (arity == 1))
+ {
+ return new ElementAvailableFunction(this);
+ }
+ else if ("function-available".equals(localName) && (arity == 1))
+ {
+ return new FunctionAvailableFunction(this);
+ }
+ }
+ return null;
+ }
+
+ // -- Parsing --
+
+ /**
+ * apply-templates
+ */
+ final TemplateNode parseApplyTemplates(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String m = getAttribute(attrs, "mode");
+ QName mode = (m == null) ? null : getQName(m);
+ String s = getAttribute(attrs, "select");
+ if (s == null)
+ {
+ s = "child::node()";
+ }
+ Node children = node.getFirstChild();
+ List sortKeys = parseSortKeys(children);
+ List withParams = parseWithParams(children);
+ Expr select = (Expr) xpath.compile(s);
+ return new ApplyTemplatesNode(select, mode,
+ sortKeys, withParams, false);
+ }
+
+ /**
+ * call-template
+ */
+ final TemplateNode parseCallTemplate(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String n = getRequiredAttribute(attrs, "name", node);
+ QName name = getQName(n);
+ Node children = node.getFirstChild();
+ List withParams = parseWithParams(children);
+ return new CallTemplateNode(name, withParams);
+ }
+
+ /**
+ * value-of
+ */
+ final TemplateNode parseValueOf(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String s = getRequiredAttribute(attrs, "select", node);
+ String doe = getAttribute(attrs, "disable-output-escaping");
+ boolean d = "yes".equals(doe);
+ Expr select = (Expr) xpath.compile(s);
+ return new ValueOfNode(select, d);
+ }
+
+ /**
+ * for-each
+ */
+ final TemplateNode parseForEach(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String s = getRequiredAttribute(attrs, "select", node);
+ Node children = node.getFirstChild();
+ List sortKeys = parseSortKeys(children);
+ Expr select = (Expr) xpath.compile(s);
+ ForEachNode ret = new ForEachNode(select, sortKeys);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * if
+ */
+ final TemplateNode parseIf(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String t = getRequiredAttribute(attrs, "test", node);
+ Expr test = (Expr) xpath.compile(t);
+ Node children = node.getFirstChild();
+ IfNode ret = new IfNode(test);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * when
+ */
+ final TemplateNode parseWhen(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String t = getRequiredAttribute(attrs, "test", node);
+ Expr test = (Expr) xpath.compile(t);
+ Node children = node.getFirstChild();
+ WhenNode ret = new WhenNode(test);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * element
+ */
+ final TemplateNode parseElement(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String name = getRequiredAttribute(attrs, "name", node);
+ String namespace = getAttribute(attrs, "namespace");
+ String uas = getAttribute(attrs, "use-attribute-sets");
+ TemplateNode n = parseAttributeValueTemplate(name, node);
+ TemplateNode ns = (namespace == null) ? null :
+ parseAttributeValueTemplate(namespace, node);
+ Node children = node.getFirstChild();
+ ElementNode ret = new ElementNode(n, ns, uas, node);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * attribute
+ */
+ final TemplateNode parseAttribute(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String name = getRequiredAttribute(attrs, "name", node);
+ String namespace = getAttribute(attrs, "namespace");
+ TemplateNode n = parseAttributeValueTemplate(name, node);
+ TemplateNode ns = (namespace == null) ? null :
+ parseAttributeValueTemplate(namespace, node);
+ Node children = node.getFirstChild();
+ AttributeNode ret = new AttributeNode(n, ns, node);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * text
+ */
+ final TemplateNode parseText(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String doe = getAttribute(attrs, "disable-output-escaping");
+ boolean d = "yes".equals(doe);
+ Node children = node.getFirstChild();
+ TextNode ret = new TextNode(d);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * copy
+ */
+ final TemplateNode parseCopy(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String uas = getAttribute(attrs, "use-attribute-sets");
+ Node children = node.getFirstChild();
+ CopyNode ret = new CopyNode(uas);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * processing-instruction
+ */
+ final TemplateNode parseProcessingInstruction(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String name = getRequiredAttribute(attrs, "name", node);
+ Node children = node.getFirstChild();
+ ProcessingInstructionNode ret = new ProcessingInstructionNode(name);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * number
+ */
+ final TemplateNode parseNumber(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String v = getAttribute(attrs, "value");
+ String ff = getAttribute(attrs, "format");
+ if (ff == null)
+ {
+ ff = "1";
+ }
+ TemplateNode format = parseAttributeValueTemplate(ff, node);
+ String lang = getAttribute(attrs, "lang");
+ String lv = getAttribute(attrs, "letter-value");
+ int letterValue = "traditional".equals(lv) ?
+ AbstractNumberNode.TRADITIONAL :
+ AbstractNumberNode.ALPHABETIC;
+ String gs = getAttribute(attrs, "grouping-separator");
+ String gz = getAttribute(attrs, "grouping-size");
+ int gz2 = (gz != null && gz.length() > 0) ?
+ Integer.parseInt(gz) : 1;
+ Node children = node.getFirstChild();
+ TemplateNode ret;
+ if (v != null && v.length() > 0)
+ {
+ Expr value = (Expr) xpath.compile(v);
+ ret = new NumberNode(value, format, lang,
+ letterValue, gs, gz2);
+ }
+ else
+ {
+ String l = getAttribute(attrs, "level");
+ int level =
+ "multiple".equals(l) ? NodeNumberNode.MULTIPLE :
+ "any".equals(l) ? NodeNumberNode.ANY :
+ NodeNumberNode.SINGLE;
+ String c = getAttribute(attrs, "count");
+ String f = getAttribute(attrs, "from");
+ Pattern count = null;
+ Pattern from = null;
+ if (c != null)
+ {
+ try
+ {
+ count = (Pattern) xpath.compile(c);
+ }
+ catch (ClassCastException e)
+ {
+ String msg = "invalid pattern: " + c;
+ throw new TransformerConfigurationException(msg);
+ }
+ }
+ if (f != null)
+ {
+ try
+ {
+ from = (Pattern) xpath.compile(f);
+ }
+ catch (ClassCastException e)
+ {
+ String msg = "invalid pattern: " + f;
+ throw new TransformerConfigurationException(msg);
+ }
+ }
+ ret = new NodeNumberNode(level, count, from,
+ format, lang,
+ letterValue, gs, gz2);
+ }
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * copy-of
+ */
+ final TemplateNode parseCopyOf(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String s = getRequiredAttribute(attrs, "select", node);
+ Expr select = (Expr) xpath.compile(s);
+ Node children = node.getFirstChild();
+ CopyOfNode ret = new CopyOfNode(select);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * message
+ */
+ final TemplateNode parseMessage(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String t = getAttribute(attrs, "terminate");
+ boolean terminate = "yes".equals(t);
+ Node children = node.getFirstChild();
+ MessageNode ret = new MessageNode(terminate);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * Parse template-level elements.
+ */
+ final TemplateNode parse(Node node)
+ throws TransformerConfigurationException
+ {
+ TemplateNode first = null;
+ TemplateNode previous = null;
+ while (node != null)
+ {
+ Node next = node.getNextSibling();
+ TemplateNode tnode = doParse(node);
+ if (tnode != null)
+ {
+ if (first == null)
+ {
+ first = tnode;
+ }
+ if (previous != null)
+ {
+ previous.next = tnode;
+ }
+ previous = tnode;
+ }
+ node = next;
+ }
+ return first;
+ }
+
+ private final TemplateNode doParse(Node node)
+ throws TransformerConfigurationException
+ {
+ // Hack to associate the document function with its declaring node
+ current = node;
+ try
+ {
+ String namespaceUri = node.getNamespaceURI();
+ if (Stylesheet.XSL_NS.equals(namespaceUri) &&
+ Node.ELEMENT_NODE == node.getNodeType())
+ {
+ String name = node.getLocalName();
+ if ("apply-templates".equals(name))
+ {
+ return parseApplyTemplates(node);
+ }
+ else if ("call-template".equals(name))
+ {
+ return parseCallTemplate(node);
+ }
+ else if ("value-of".equals(name))
+ {
+ return parseValueOf(node);
+ }
+ else if ("for-each".equals(name))
+ {
+ return parseForEach(node);
+ }
+ else if ("if".equals(name))
+ {
+ return parseIf(node);
+ }
+ else if ("choose".equals(name))
+ {
+ Node children = node.getFirstChild();
+ ChooseNode ret = new ChooseNode();
+ ret.children = parse(children);
+ return ret;
+ }
+ else if ("when".equals(name))
+ {
+ return parseWhen(node);
+ }
+ else if ("otherwise".equals(name))
+ {
+ Node children = node.getFirstChild();
+ OtherwiseNode ret = new OtherwiseNode();
+ ret.children = parse(children);
+ return ret;
+ }
+ else if ("element".equals(name))
+ {
+ return parseElement(node);
+ }
+ else if ("attribute".equals(name))
+ {
+ return parseAttribute(node);
+ }
+ else if ("text".equals(name))
+ {
+ return parseText(node);
+ }
+ else if ("copy".equals(name))
+ {
+ return parseCopy(node);
+ }
+ else if ("processing-instruction".equals(name))
+ {
+ return parseProcessingInstruction(node);
+ }
+ else if ("comment".equals(name))
+ {
+ Node children = node.getFirstChild();
+ CommentNode ret = new CommentNode();
+ ret.children = parse(children);
+ return ret;
+ }
+ else if ("number".equals(name))
+ {
+ return parseNumber(node);
+ }
+ else if ("param".equals(name) ||
+ "variable".equals(name))
+ {
+ int type = "variable".equals(name) ?
+ Bindings.VARIABLE : Bindings.PARAM;
+ NamedNodeMap attrs = node.getAttributes();
+ Node children = node.getFirstChild();
+ TemplateNode content = parse(children);
+ QName paramName =
+ getQName(getRequiredAttribute(attrs, "name", node));
+ String select = getAttribute(attrs, "select");
+ ParameterNode ret;
+ if (select != null)
+ {
+ if (content != null)
+ {
+ String msg = "parameter '" + paramName +
+ "' has both select and content";
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ Expr expr = (Expr) xpath.compile(select);
+ ret = new ParameterNode(paramName, expr, type);
+ }
+ else
+ {
+ ret = new ParameterNode(paramName, null, type);
+ ret.children = content;
+ }
+ return ret;
+ }
+ else if ("copy-of".equals(name))
+ {
+ return parseCopyOf(node);
+ }
+ else if ("message".equals(name))
+ {
+ return parseMessage(node);
+ }
+ else if ("apply-imports".equals(name))
+ {
+ Node children = node.getFirstChild();
+ ApplyImportsNode ret = new ApplyImportsNode();
+ ret.children = parse(children);
+ return ret;
+ }
+ else
+ {
+ // xsl:fallback
+ // Pass over any other XSLT nodes
+ return null;
+ }
+ }
+ String prefix = node.getPrefix();
+ if (extensionElementPrefixes.contains(prefix))
+ {
+ // Pass over extension elements
+ return null;
+ }
+ switch (node.getNodeType())
+ {
+ case Node.TEXT_NODE:
+ // Determine whether to strip whitespace
+ Text text = (Text) node;
+ if (!isPreserved(text))
+ {
+ // Strip
+ /*String data = text.getData().trim();
+ if (data.length() > 0)
+ {
+ text.setData(data);
+ } // else */
+ text.getParentNode().removeChild(text);
+ return null;
+ }
+ break;
+ case Node.COMMENT_NODE:
+ // Ignore comments
+ return null;
+ case Node.ELEMENT_NODE:
+ // Check for attribute value templates and use-attribute-sets
+ NamedNodeMap attrs = node.getAttributes();
+ boolean convert = false;
+ String useAttributeSets = null;
+ int len = attrs.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ Node attr = attrs.item(i);
+ String value = attr.getNodeValue();
+ if (Stylesheet.XSL_NS.equals(attr.getNamespaceURI()) &&
+ "use-attribute-sets".equals(attr.getLocalName()))
+ {
+ useAttributeSets = value;
+ convert = true;
+ break;
+ }
+ int start = value.indexOf('{');
+ int end = value.indexOf('}');
+ if (start != -1 || end != -1)
+ {
+ convert = true;
+ break;
+ }
+ }
+ if (convert)
+ {
+ // Create an element-producing template node instead
+ // with appropriate attribute-producing child template nodes
+ Node children = node.getFirstChild();
+ TemplateNode child = parse(children);
+ for (int i = 0; i < len; i++)
+ {
+ Node attr = attrs.item(i);
+ String ans = attr.getNamespaceURI();
+ String aname = attr.getNodeName();
+ if (Stylesheet.XSL_NS.equals(ans) &&
+ "use-attribute-sets".equals(attr.getLocalName()))
+ {
+ continue;
+ }
+ String value = attr.getNodeValue();
+ TemplateNode grandchild =
+ parseAttributeValueTemplate(value, node);
+ TemplateNode n =
+ parseAttributeValueTemplate(aname, node);
+ TemplateNode ns = (ans == null) ? null :
+ parseAttributeValueTemplate(ans, node);
+ TemplateNode newChild = new AttributeNode(n, ns, attr);
+ newChild.children = grandchild;
+ newChild.next = child;
+ child = newChild;
+ }
+ String ename = node.getNodeName();
+ TemplateNode n = parseAttributeValueTemplate(ename, node);
+ TemplateNode ns = (namespaceUri == null) ? null :
+ parseAttributeValueTemplate(namespaceUri, node);
+ ElementNode ret = new ElementNode(n, ns, useAttributeSets,
+ node);
+ ret.children = child;
+ return ret;
+ }
+ // Otherwise fall through
+ break;
+ }
+ }
+ catch (XPathExpressionException e)
+ {
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(e.getMessage(), l, e);
+ }
+ Node children = node.getFirstChild();
+ LiteralNode ret = new LiteralNode(node);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ final List parseSortKeys(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ List ret = new LinkedList();
+ while (node != null)
+ {
+ String namespaceUri = node.getNamespaceURI();
+ if (Stylesheet.XSL_NS.equals(namespaceUri) &&
+ Node.ELEMENT_NODE == node.getNodeType() &&
+ "sort".equals(node.getLocalName()))
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String s = getAttribute(attrs, "select");
+ if (s == null)
+ {
+ s = ".";
+ }
+ Expr select = (Expr) xpath.compile(s);
+ String l = getAttribute(attrs, "lang");
+ TemplateNode lang = (l == null) ? null :
+ parseAttributeValueTemplate(l, node);
+ String dt = getAttribute(attrs, "data-type");
+ TemplateNode dataType = (dt == null) ? null :
+ parseAttributeValueTemplate(dt, node);
+ String o = getAttribute(attrs, "order");
+ TemplateNode order = (o == null) ? null :
+ parseAttributeValueTemplate(o, node);
+ String co = getAttribute(attrs, "case-order");
+ TemplateNode caseOrder = (co == null) ? null :
+ parseAttributeValueTemplate(co, node);
+ ret.add(new SortKey(select, lang, dataType, order, caseOrder));
+ }
+ node = node.getNextSibling();
+ }
+ return ret.isEmpty() ? null : ret;
+ }
+
+ final List parseWithParams(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ List ret = new LinkedList();
+ while (node != null)
+ {
+ String namespaceUri = node.getNamespaceURI();
+ if (Stylesheet.XSL_NS.equals(namespaceUri) &&
+ Node.ELEMENT_NODE == node.getNodeType() &&
+ "with-param".equals(node.getLocalName()))
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ TemplateNode content = parse(node.getFirstChild());
+ QName name =
+ getQName(getRequiredAttribute(attrs, "name", node));
+ String select = getAttribute(attrs, "select");
+ if (select != null)
+ {
+ if (content != null)
+ {
+ String msg = "parameter '" + name +
+ "' has both select and content";
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ Expr expr = (Expr) xpath.compile(select);
+ ret.add(new WithParam(name, expr));
+ }
+ else
+ {
+ ret.add(new WithParam(name, content));
+ }
+ }
+ node = node.getNextSibling();
+ }
+ return ret.isEmpty() ? null : ret;
+ }
+
+ /**
+ * Created element nodes have a copy of the namespace nodes in the
+ * stylesheet, except the XSLT namespace, extension namespaces, and
+ * exclude-result-prefixes.
+ */
+ final void addNamespaceNodes(Node source, Node target, Document doc,
+ Collection elementExcludeResultPrefixes)
+ {
+ NamedNodeMap attrs = source.getAttributes();
+ if (attrs != null)
+ {
+ int len = attrs.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ Node attr = attrs.item(i);
+ String uri = attr.getNamespaceURI();
+ if (uri == XMLConstants.XMLNS_ATTRIBUTE_NS_URI)
+ {
+ String prefix = attr.getLocalName();
+ if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
+ {
+ prefix = "#default";
+ }
+ String ns = attr.getNodeValue();
+ // Should the namespace be excluded?
+ if (XSL_NS.equals(ns) ||
+ extensionElementPrefixes.contains(prefix) ||
+ elementExcludeResultPrefixes.contains(prefix) ||
+ excludeResultPrefixes.contains(prefix))
+ {
+ continue;
+ }
+ // Is the namespace already defined on the target?
+ if (prefix == "#default")
+ {
+ prefix = null;
+ }
+ if (target.lookupNamespaceURI(prefix) != null)
+ {
+ continue;
+ }
+ attr = attr.cloneNode(true);
+ attr = doc.adoptNode(attr);
+ target.getAttributes().setNamedItemNS(attr);
+ }
+ }
+ }
+ Node parent = source.getParentNode();
+ if (parent != null)
+ {
+ addNamespaceNodes(parent, target, doc, elementExcludeResultPrefixes);
+ }
+ }
+
+ static final String getAttribute(NamedNodeMap attrs, String name)
+ {
+ Node attr = attrs.getNamedItem(name);
+ if (attr == null)
+ {
+ return null;
+ }
+ String ret = attr.getNodeValue();
+ if (ret.length() == 0)
+ {
+ return null;
+ }
+ return ret;
+ }
+
+ static final String getRequiredAttribute(NamedNodeMap attrs, String name,
+ Node source)
+ throws TransformerConfigurationException
+ {
+ String value = getAttribute(attrs, name);
+ if (value == null || value.length() == 0)
+ {
+ String msg =
+ name + " attribute is required on " + source.getNodeName();
+ DOMSourceLocator l = new DOMSourceLocator(source);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ return value;
+ }
+
+ // Handle user data changes when nodes are cloned etc
+
+ public void handle(short op, String key, Object data, Node src, Node dst)
+ {
+ dst.setUserData(key, data, this);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/SystemPropertyFunction.java b/libjava/classpath/gnu/xml/transform/SystemPropertyFunction.java
new file mode 100644
index 0000000..038df01
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/SystemPropertyFunction.java
@@ -0,0 +1,141 @@
+/* SystemPropertyFunction.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Function;
+
+/**
+ * The XSLT system-property()
function.
+ *
+ * @author Chris Burdess
+ */
+final class SystemPropertyFunction
+ extends Expr
+ implements XPathFunction, Function
+{
+
+ List args;
+
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ String name = (String) args.get(0);
+ return systemProperty(QName.valueOf(name));
+ }
+
+ public void setArguments(List args)
+ {
+ this.args = args;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ int arity = args.size();
+ List values = new ArrayList(arity);
+ for (int i = 0; i < arity; i++)
+ {
+ Expr arg = (Expr) args.get(i);
+ values.add(arg.evaluate(context, pos, len));
+ }
+ String name = _string(context, values.get(0));
+ return systemProperty(QName.valueOf(name));
+ }
+
+ Object systemProperty(QName name)
+ {
+ String localName = name.getLocalPart();
+ String prefix = name.getPrefix();
+ String uri = name.getNamespaceURI();
+ if (Stylesheet.XSL_NS.equals(uri) ||
+ "xsl".equals(prefix))
+ {
+ if ("version".equals(localName))
+ {
+ return new Double(1.0d);
+ }
+ else if ("vendor".equals(localName))
+ {
+ return "The Free Software Foundation";
+ }
+ else if ("vendor-url".equals(localName))
+ {
+ return "http://www.gnu.org/";
+ }
+ else
+ {
+ return "";
+ }
+ }
+ return System.getProperty(localName);
+ }
+
+ public Expr clone(Object context)
+ {
+ SystemPropertyFunction f = new SystemPropertyFunction();
+ int len = args.size();
+ List args2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(((Expr) args.get(i)).clone(context));
+ }
+ f.setArguments(args2);
+ return f;
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator i = args.iterator(); i.hasNext(); )
+ {
+ if (((Expr) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/Template.java b/libjava/classpath/gnu/xml/transform/Template.java
new file mode 100644
index 0000000..e3c172f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/Template.java
@@ -0,0 +1,252 @@
+/* Template.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.io.PrintStream;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.NameTest;
+import gnu.xml.xpath.NodeTypeTest;
+import gnu.xml.xpath.Pattern;
+import gnu.xml.xpath.Selector;
+import gnu.xml.xpath.Test;
+
+/**
+ * A template in an XSL stylesheet.
+ *
+ * @author Chris Burdess
+ */
+class Template
+ implements Comparable
+{
+
+ static final double DEFAULT_PRIORITY = 0.5d;
+
+ final Stylesheet stylesheet;
+ final QName name;
+ final Pattern match;
+ final TemplateNode node;
+ final double priority;
+ final int precedence;
+ final QName mode;
+
+ Template(Stylesheet stylesheet,
+ QName name, Pattern match, TemplateNode node,
+ int precedence, double priority, QName mode)
+ {
+ this.stylesheet = stylesheet;
+ this.name = name;
+ this.match = match;
+ this.node = node;
+ // adjust priority if necessary
+ // see XSLT section 5.5
+ Test test = getNodeTest(match);
+ if (test != null)
+ {
+ if (test instanceof NameTest)
+ {
+ NameTest nameTest = (NameTest) test;
+ if (nameTest.matchesAny() ||
+ nameTest.matchesAnyLocalName())
+ {
+ priority = -0.25d;
+ }
+ else
+ {
+ priority = 0.0d;
+ }
+ }
+ else
+ {
+ NodeTypeTest nodeTypeTest = (NodeTypeTest) test;
+ if (nodeTypeTest.getNodeType() ==
+ Node.PROCESSING_INSTRUCTION_NODE &&
+ nodeTypeTest.getData() != null)
+ {
+ priority = 0.0d;
+ }
+ else
+ {
+ priority = -0.5d;
+ }
+ }
+ }
+ this.precedence = precedence;
+ this.priority = priority;
+ this.mode = mode;
+ }
+
+ Template clone(Stylesheet stylesheet)
+ {
+ // FIXME by cloning we lose the imports() functionality, so
+ // apply-imports will be broken.
+ return new Template(stylesheet,
+ name,
+ (match == null) ? null :
+ (Pattern) match.clone(stylesheet),
+ (node == null) ? null : node.clone(stylesheet),
+ precedence,
+ priority,
+ mode);
+ }
+
+ public int compareTo(Object other)
+ {
+ if (other instanceof Template)
+ {
+ Template t = (Template) other;
+ int d = t.precedence - precedence;
+ if (d != 0)
+ {
+ return d;
+ }
+ double d2 = t.priority - priority;
+ if (d2 != 0.0d)
+ {
+ return (int) Math.round(d2 * 1000.0d);
+ }
+ }
+ return 0;
+ }
+
+ Test getNodeTest(Expr expr)
+ {
+ if (expr instanceof Selector)
+ {
+ Selector selector = (Selector) expr;
+ Test[] tests = selector.getTests();
+ if (tests.length > 0)
+ {
+ return tests[0];
+ }
+ }
+ return null;
+ }
+
+ boolean matches(QName mode, Node node)
+ {
+ if ((mode == null && this.mode != null) ||
+ (mode != null && !mode.equals(this.mode)))
+ {
+ return false;
+ }
+ if (match == null)
+ {
+ return false;
+ }
+ return match.matches(node);
+ }
+
+ boolean matches(QName name)
+ {
+ return name.equals(this.name);
+ }
+
+ boolean imports(Template other)
+ {
+ for (Stylesheet ctx = other.stylesheet.parent;
+ ctx != null;
+ ctx = ctx.parent)
+ {
+ if (ctx == stylesheet)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param stylesheet the stylesheet
+ * @param parent the parent of result nodes
+ * @param context the context node in the source document
+ * @param pos the context position
+ * @param len the context size
+ * @param nextSibling if non-null, add result nodes before this node
+ */
+ void apply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ System.err.println("...applying " + toString() + " to " + context);
+ if (node != null)
+ {
+ node.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ if (name != null)
+ {
+ buf.append("name=");
+ buf.append(name);
+ }
+ else if (match != null)
+ {
+ buf.append("match=");
+ buf.append(match);
+ }
+ if (mode != null)
+ {
+ buf.append(",mode=");
+ buf.append(mode);
+ }
+ buf.append(']');
+ return buf.toString();
+
+ //return (name != null) ? name.toString() : match.toString();
+ }
+
+ void list(PrintStream out)
+ {
+ out.println(toString());
+ if (node != null)
+ {
+ node.list(1, out, true);
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TemplateNode.java b/libjava/classpath/gnu/xml/transform/TemplateNode.java
new file mode 100644
index 0000000..36b25cf
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TemplateNode.java
@@ -0,0 +1,124 @@
+/* TemplateNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.io.PrintStream;
+import java.util.Comparator;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.DocumentOrderComparator;
+
+/**
+ * Wrapper for a source node in a template.
+ *
+ * @author Chris Burdess
+ */
+abstract class TemplateNode
+{
+
+ static final Comparator documentOrderComparator =
+ new DocumentOrderComparator();
+
+ TemplateNode children;
+ TemplateNode next;
+
+ final void apply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ if (stylesheet.terminated)
+ {
+ return;
+ }
+ if (Thread.currentThread().isInterrupted())
+ {
+ // Try to head off any infinite loops at the pass
+ return;
+ }
+ if (stylesheet.debug)
+ {
+ System.err.println("Applying " + toString());
+ System.err.println("\twith context=" + context + ", pos=" + pos +
+ ", len=" + len);
+ }
+ doApply(stylesheet, mode, context, pos, len, parent, nextSibling);
+ }
+
+ abstract void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException;
+
+ abstract TemplateNode clone(Stylesheet stylesheet);
+
+ public boolean references(QName var)
+ {
+ if (children != null && children.references(var))
+ {
+ return true;
+ }
+ if (next != null && next.references(var))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Debugging
+ */
+ void list(int depth, PrintStream out, boolean listNext)
+ {
+ for (int i = 0; i < depth; i++)
+ {
+ out.print(" ");
+ }
+ out.println(toString());
+ if (children != null)
+ {
+ children.list(depth + 1, out, true);
+ }
+ if (listNext && next != null)
+ {
+ next.list(depth, out, listNext);
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TemplatesImpl.java b/libjava/classpath/gnu/xml/transform/TemplatesImpl.java
new file mode 100644
index 0000000..527bd97
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TemplatesImpl.java
@@ -0,0 +1,80 @@
+/* TemplatesImpl.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.Properties;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+
+/**
+ * GNU precompiled stylesheet implementation.
+ *
+ * @author Chris Burdess
+ */
+class TemplatesImpl
+ implements Templates
+{
+
+ final TransformerFactoryImpl factory;
+ final Stylesheet stylesheet;
+ final Properties outputProperties;
+
+ TemplatesImpl(TransformerFactoryImpl factory, Stylesheet stylesheet)
+ {
+ this.factory = factory;
+ this.stylesheet = stylesheet;
+ outputProperties = new TransformerOutputProperties(stylesheet);
+ }
+
+ public Transformer newTransformer()
+ throws TransformerConfigurationException
+ {
+ Stylesheet stylesheet = (Stylesheet) this.stylesheet.clone();
+ TransformerImpl transformer =
+ new TransformerImpl(factory, stylesheet, outputProperties);
+ stylesheet.transformer = transformer;
+ return transformer;
+ }
+
+ public Properties getOutputProperties()
+ {
+ return (Properties) outputProperties.clone();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TextNode.java b/libjava/classpath/gnu/xml/transform/TextNode.java
new file mode 100644
index 0000000..1b581e5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TextNode.java
@@ -0,0 +1,119 @@
+/* TextNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing the XSL text
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class TextNode
+ extends TemplateNode
+{
+
+ final boolean disableOutputEscaping;
+
+ TextNode(boolean disableOutputEscaping)
+ {
+ this.disableOutputEscaping = disableOutputEscaping;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new TextNode(disableOutputEscaping);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ String value = "";
+ Document doc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ if (children != null)
+ {
+ // Create a document fragment to hold the text
+ DocumentFragment fragment = doc.createDocumentFragment();
+ // Apply children to the fragment
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ fragment, null);
+ // Use XPath string-value of fragment
+ value = Expr.stringValue(fragment);
+ }
+ Text text = doc.createTextNode(value);
+ if (disableOutputEscaping)
+ {
+ text.setUserData("disable-output-escaping", "yes", stylesheet);
+ }
+ // Insert into result tree
+ if (nextSibling != null)
+ {
+ parent.insertBefore(text, nextSibling);
+ }
+ else
+ {
+ parent.appendChild(text);
+ }
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java b/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java
new file mode 100644
index 0000000..dde2017
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java
@@ -0,0 +1,345 @@
+/* TransformerFactoryImpl.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Properties;
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.xpath.XPathFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import gnu.xml.dom.DomDocument;
+
+/**
+ * GNU transformer factory implementation.
+ *
+ * @author Chris Burdess
+ */
+public class TransformerFactoryImpl
+ extends TransformerFactory
+{
+
+ final XPathFactory xpathFactory;
+ final XSLURIResolver resolver;
+ ErrorListener userListener;
+ URIResolver userResolver;
+
+ public TransformerFactoryImpl()
+ {
+ xpathFactory = new gnu.xml.xpath.XPathFactoryImpl();
+ resolver = new XSLURIResolver();
+ }
+
+ public Transformer newTransformer(Source source)
+ throws TransformerConfigurationException
+ {
+ Stylesheet stylesheet = newStylesheet(source, 0, null);
+ Properties outputProperties =
+ new TransformerOutputProperties(stylesheet);
+ TransformerImpl transformer =
+ new TransformerImpl(this, stylesheet, outputProperties);
+ stylesheet.transformer = transformer;
+ return transformer;
+ }
+
+ public Transformer newTransformer()
+ throws TransformerConfigurationException
+ {
+ return new TransformerImpl(this, null, new Properties());
+ }
+
+ public Templates newTemplates(Source source)
+ throws TransformerConfigurationException
+ {
+ Stylesheet stylesheet = newStylesheet(source, 0, null);
+ return new TemplatesImpl(this, stylesheet);
+ }
+
+ Stylesheet newStylesheet(Source source, int precedence, Stylesheet parent)
+ throws TransformerConfigurationException
+ {
+ Document doc = null;
+ String systemId = null;
+ if (source != null)
+ {
+ try
+ {
+ DOMSource ds;
+ synchronized (resolver)
+ {
+ resolver.setUserResolver(userResolver);
+ resolver.setUserListener(userListener);
+ ds = resolver.resolveDOM(source, null, null);
+ }
+ Node node = ds.getNode();
+ if (node == null)
+ {
+ throw new TransformerConfigurationException("no source document");
+ }
+ doc = (node instanceof Document) ? (Document) node :
+ node.getOwnerDocument();
+ systemId = ds.getSystemId();
+ }
+ catch (TransformerException e)
+ {
+ throw new TransformerConfigurationException(e);
+ }
+ }
+ return new Stylesheet(this, parent, doc, systemId, precedence);
+ }
+
+ public Source getAssociatedStylesheet(Source source,
+ String media,
+ String title,
+ String charset)
+ throws TransformerConfigurationException
+ {
+ try
+ {
+ DOMSource ds;
+ synchronized (resolver)
+ {
+ resolver.setUserResolver(userResolver);
+ resolver.setUserListener(userListener);
+ ds = resolver.resolveDOM(source, null, null);
+ }
+ Node node = ds.getNode();
+ if (node == null)
+ {
+ throw new TransformerConfigurationException("no source document");
+ }
+ Document doc = (node instanceof Document) ? (Document) node :
+ node.getOwnerDocument();
+ LinkedList matches = new LinkedList();
+ for (node = doc.getFirstChild();
+ node != null;
+ node = node.getNextSibling())
+ {
+ if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE &&
+ "xml-stylesheet".equals(node.getNodeName()))
+ {
+ Map params = parseParameters(node.getNodeValue());
+ if (media != null && !media.equals(params.get("media")))
+ {
+ continue;
+ }
+ if (title != null && !title.equals(params.get("title")))
+ {
+ continue;
+ }
+ if (charset != null && !charset.equals(params.get("charset")))
+ {
+ continue;
+ }
+ String href = (String) params.get("href");
+ URL url = resolver.resolveURL(null, node.getBaseURI(), href);
+ matches.add(url);
+ }
+ }
+ switch (matches.size())
+ {
+ case 0:
+ return null;
+ case 1:
+ return new StreamSource(((URL) matches.getFirst()).toString());
+ default:
+ // Create a source representing a stylesheet with a list of
+ // imports
+ DomDocument ssDoc = new DomDocument();
+ ssDoc.setBuilding(true);
+ // Create document element
+ Node root =
+ ssDoc.createElementNS(Stylesheet.XSL_NS, "stylesheet");
+ Node version =
+ ssDoc.createAttributeNS(null, "version");
+ version.setNodeValue("1.0");
+ root.getAttributes().setNamedItemNS(version);
+ ssDoc.appendChild(root);
+ // Create xsl:import for each URL
+ for (Iterator i = matches.iterator(); i.hasNext(); )
+ {
+ URL url = (URL) i.next();
+ Node imp =
+ ssDoc.createElementNS(Stylesheet.XSL_NS, "import");
+ Node href =
+ ssDoc.createAttributeNS(null, "href");
+ href.setNodeValue(url.toString());
+ imp.getAttributes().setNamedItemNS(href);
+ root.appendChild(imp);
+ }
+ ssDoc.setBuilding(false);
+ return new DOMSource(ssDoc);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new TransformerConfigurationException(e);
+ }
+ catch (TransformerException e)
+ {
+ throw new TransformerConfigurationException(e);
+ }
+ }
+
+ Map parseParameters(String data)
+ {
+ Map ret = new LinkedHashMap();
+ int len = data.length();
+ String key = null;
+ int start = 0;
+ char quoteChar = '\u0000';
+ for (int i = 0; i < len; i++)
+ {
+ char c = data.charAt(i);
+ if (quoteChar == '\u0000' && c == ' ')
+ {
+ if (key == null && start < i)
+ {
+ key = data.substring(start, i);
+ }
+ else
+ {
+ String val = unquote(data.substring(start, i).trim());
+ ret.put(key, val);
+ key = null;
+ }
+ start = i + 1;
+ }
+ else if (c == '"')
+ {
+ quoteChar = (quoteChar == c) ? '\u0000' : c;
+ }
+ else if (c == '\'')
+ {
+ quoteChar = (quoteChar == c) ? '\u0000' : c;
+ }
+ }
+ if (start < len && key != null)
+ {
+ String val = unquote(data.substring(start, len).trim());
+ ret.put(key, val);
+ }
+ return ret;
+ }
+
+ String unquote(String text)
+ {
+ int end = text.length() - 1;
+ if (text.charAt(0) == '\'' && text.charAt(end) == '\'')
+ {
+ return text.substring(1, end);
+ }
+ if (text.charAt(0) == '"' && text.charAt(end) == '"')
+ {
+ return text.substring(1, end);
+ }
+ return text;
+ }
+
+ public void setURIResolver(URIResolver resolver)
+ {
+ userResolver = resolver;
+ }
+
+ public URIResolver getURIResolver()
+ {
+ return userResolver;
+ }
+
+ public void setFeature(String name, boolean value)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException("not supported");
+ }
+
+ public boolean getFeature(String name)
+ {
+ if (SAXSource.FEATURE.equals(name) ||
+ SAXResult.FEATURE.equals(name) ||
+ StreamSource.FEATURE.equals(name) ||
+ StreamResult.FEATURE.equals(name) ||
+ DOMSource.FEATURE.equals(name) ||
+ DOMResult.FEATURE.equals(name))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ public void setAttribute(String name, Object value)
+ throws IllegalArgumentException
+ {
+ throw new IllegalArgumentException("not supported");
+ }
+
+ public Object getAttribute(String name)
+ throws IllegalArgumentException
+ {
+ throw new IllegalArgumentException("not supported");
+ }
+
+ public void setErrorListener(ErrorListener listener)
+ throws IllegalArgumentException
+ {
+ userListener = listener;
+ }
+
+ public ErrorListener getErrorListener()
+ {
+ return userListener;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TransformerImpl.java b/libjava/classpath/gnu/xml/transform/TransformerImpl.java
new file mode 100644
index 0000000..a36aa61
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TransformerImpl.java
@@ -0,0 +1,769 @@
+/* TransformerImpl.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.UnknownServiceException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import javax.xml.namespace.QName;
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.stream.StreamResult;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
+import gnu.xml.dom.DomDoctype;
+import gnu.xml.dom.DomDocument;
+import gnu.xml.dom.ls.WriterOutputStream;
+
+/**
+ * The transformation process for a given stylesheet.
+ *
+ * @author Chris Burdess
+ */
+class TransformerImpl
+ extends Transformer
+{
+
+ final TransformerFactoryImpl factory;
+ final Stylesheet stylesheet;
+ URIResolver uriResolver;
+ ErrorListener errorListener;
+ Properties outputProperties;
+
+ TransformerImpl(TransformerFactoryImpl factory,
+ Stylesheet stylesheet,
+ Properties outputProperties)
+ throws TransformerConfigurationException
+ {
+ this.factory = factory;
+ uriResolver = factory.userResolver;
+ errorListener = factory.userListener;
+ this.stylesheet = stylesheet;
+ this.outputProperties = outputProperties;
+ if (stylesheet != null)
+ {
+ // Set up parameter context for this transformer
+ stylesheet.bindings.push(Bindings.PARAM);
+ }
+ }
+
+ public void transform(Source xmlSource, Result outputTarget)
+ throws TransformerException
+ {
+ // Get the source tree
+ DOMSource source;
+ synchronized (factory.resolver)
+ {
+ factory.resolver.setUserResolver(uriResolver);
+ factory.resolver.setUserListener(errorListener);
+ source = factory.resolver.resolveDOM(xmlSource, null, null);
+ }
+ Node context = source.getNode();
+ Document doc = (context instanceof Document) ? (Document) context :
+ context.getOwnerDocument();
+ if (doc instanceof DomDocument)
+ {
+ // Suppress mutation events
+ ((DomDocument) doc).setBuilding(true);
+ // TODO find a better/more generic way of doing this than
+ // casting
+ }
+ // Get the result tree
+ Node parent = null, nextSibling = null;
+ if (outputTarget instanceof DOMResult)
+ {
+ DOMResult dr = (DOMResult) outputTarget;
+ parent = dr.getNode();
+ nextSibling = dr.getNextSibling();
+
+ Document rdoc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ if (rdoc instanceof DomDocument)
+ {
+ // Suppress mutation events and allow multiple root elements
+ DomDocument drdoc = (DomDocument) rdoc;
+ drdoc.setBuilding(true);
+ drdoc.setCheckWellformedness(false);
+ // TODO find a better/more generic way of doing this than
+ // casting
+ }
+ }
+ boolean created = false;
+ // Transformation
+ if (stylesheet != null)
+ {
+ if (parent == null)
+ {
+ // Create a new document to hold the result
+ DomDocument resultDoc = new DomDocument();
+ resultDoc.setBuilding(true);
+ resultDoc.setCheckWellformedness(false);
+ parent = resultDoc;
+ created = true;
+ }
+ // Make a copy of the source node, and strip it
+ context = context.cloneNode(true);
+ strip(context);
+ // XSLT transformation
+ try
+ {
+ // Set output properties in the underlying stylesheet
+ ((TransformerOutputProperties) outputProperties).apply();
+ stylesheet.initTopLevelVariables(context);
+ TemplateNode t = stylesheet.getTemplate(null, context, false);
+ if (t != null)
+ {
+ stylesheet.current = context;
+ t.apply(stylesheet, null, context, 1, 1, parent, nextSibling);
+ }
+ }
+ catch (TransformerException e)
+ {
+ // Done transforming, reset document
+ if (doc instanceof DomDocument)
+ {
+ ((DomDocument) doc).setBuilding(false);
+ }
+ throw e;
+ }
+ }
+ else
+ {
+ // Identity transform
+ Node clone = context.cloneNode(true);
+ if (context.getNodeType() != Node.DOCUMENT_NODE)
+ {
+ Document resultDoc;
+ if (parent == null)
+ {
+ // Create a new document to hold the result
+ DomDocument rd = new DomDocument();
+ rd.setBuilding(true);
+ rd.setCheckWellformedness(false);
+ parent = resultDoc = rd;
+ created = true;
+ }
+ else
+ {
+ resultDoc = (parent instanceof Document) ?
+ (Document) parent :
+ parent.getOwnerDocument();
+ }
+ Document sourceDoc = context.getOwnerDocument();
+ if (sourceDoc != resultDoc)
+ {
+ clone = resultDoc.adoptNode(clone);
+ }
+ if (nextSibling != null)
+ {
+ parent.insertBefore(clone, nextSibling);
+ }
+ else
+ {
+ parent.appendChild(clone);
+ }
+ }
+ else
+ {
+ // Cannot append document to another tree
+ parent = clone;
+ created = true;
+ }
+ }
+ String method = outputProperties.getProperty(OutputKeys.METHOD);
+ int outputMethod = "html".equals(method) ? Stylesheet.OUTPUT_HTML :
+ "text".equals(method) ? Stylesheet.OUTPUT_TEXT :
+ Stylesheet.OUTPUT_XML;
+ String encoding = outputProperties.getProperty(OutputKeys.ENCODING);
+ String publicId = outputProperties.getProperty(OutputKeys.DOCTYPE_PUBLIC);
+ String systemId = outputProperties.getProperty(OutputKeys.DOCTYPE_SYSTEM);
+ String version = outputProperties.getProperty(OutputKeys.VERSION);
+ boolean omitXmlDeclaration =
+ "yes".equals(outputProperties.getProperty(OutputKeys.OMIT_XML_DECLARATION));
+ boolean standalone =
+ "yes".equals(outputProperties.getProperty(OutputKeys.STANDALONE));
+ String mediaType = outputProperties.getProperty(OutputKeys.MEDIA_TYPE);
+ String cdataSectionElements =
+ outputProperties.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS);
+ boolean indent =
+ "yes".equals(outputProperties.getProperty(OutputKeys.INDENT));
+ if (created)
+ {
+ // Discover document element
+ DomDocument resultDoc = (DomDocument) parent;
+ Node root = resultDoc.getDocumentElement();
+ // Add doctype if specified
+ if ((publicId != null || systemId != null) &&
+ root != null)
+ {
+ // We must know the name of the root element to
+ // create the document type
+ resultDoc.appendChild(new DomDoctype(resultDoc,
+ root.getNodeName(),
+ publicId,
+ systemId));
+ }
+ resultDoc.setBuilding(false);
+ resultDoc.setCheckWellformedness(true);
+ }
+ else if (publicId != null || systemId != null)
+ {
+ switch (parent.getNodeType())
+ {
+ case Node.DOCUMENT_NODE:
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ Document resultDoc = (parent instanceof Document) ?
+ (Document) parent :
+ parent.getOwnerDocument();
+ DOMImplementation impl = resultDoc.getImplementation();
+ DocumentType doctype =
+ impl.createDocumentType(resultDoc.getNodeName(),
+ publicId,
+ systemId);
+ // Try to insert doctype before first element
+ Node ctx = parent.getFirstChild();
+ for (; ctx != null &&
+ ctx.getNodeType() != Node.ELEMENT_NODE;
+ ctx = ctx.getNextSibling())
+ {
+ }
+ if (ctx != null)
+ {
+ parent.insertBefore(doctype, ctx);
+ }
+ else
+ {
+ parent.appendChild(doctype);
+ }
+ }
+ }
+ if (version != null)
+ {
+ parent.setUserData("version", version, stylesheet);
+ }
+ if (omitXmlDeclaration)
+ {
+ parent.setUserData("omit-xml-declaration", "yes", stylesheet);
+ }
+ if (standalone)
+ {
+ parent.setUserData("standalone", "yes", stylesheet);
+ }
+ if (mediaType != null)
+ {
+ parent.setUserData("media-type", mediaType, stylesheet);
+ }
+ if (cdataSectionElements != null)
+ {
+ List list = new LinkedList();
+ StringTokenizer st = new StringTokenizer(cdataSectionElements);
+ while (st.hasMoreTokens())
+ {
+ String name = st.nextToken();
+ String localName = name;
+ String uri = null;
+ String prefix = null;
+ int ci = name.indexOf(':');
+ if (ci != -1)
+ {
+ // Use namespaces defined on xsl:output node to resolve
+ // namespaces for QName
+ prefix = name.substring(0, ci);
+ localName = name.substring(ci + 1);
+ uri = stylesheet.output.lookupNamespaceURI(prefix);
+ }
+ list.add(new QName(uri, localName, prefix));
+ }
+ if (!list.isEmpty())
+ {
+ Document resultDoc = (parent instanceof Document) ?
+ (Document) parent :
+ parent.getOwnerDocument();
+ convertCdataSectionElements(resultDoc, parent, list);
+ }
+ }
+ if (indent)
+ {
+ parent.normalize();
+ strip(parent);
+ Document resultDoc = (parent instanceof Document) ?
+ (Document) parent :
+ parent.getOwnerDocument();
+ reindent(resultDoc, parent, 0);
+ }
+ // Render result to the target device
+ if (outputTarget instanceof DOMResult)
+ {
+ if (created)
+ {
+ DOMResult dr = (DOMResult) outputTarget;
+ dr.setNode(parent);
+ dr.setNextSibling(null);
+ }
+ }
+ else if (outputTarget instanceof StreamResult)
+ {
+ StreamResult sr = (StreamResult) outputTarget;
+ IOException ex = null;
+ try
+ {
+ writeStreamResult(parent, sr, outputMethod, encoding);
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ try
+ {
+ writeStreamResult(parent, sr, outputMethod, "UTF-8");
+ }
+ catch (IOException e2)
+ {
+ ex = e2;
+ }
+ }
+ catch (IOException e)
+ {
+ ex = e;
+ }
+ if (ex != null)
+ {
+ if (errorListener != null)
+ {
+ errorListener.error(new TransformerException(ex));
+ }
+ else
+ {
+ ex.printStackTrace(System.err);
+ }
+ }
+ }
+ else if (outputTarget instanceof SAXResult)
+ {
+ SAXResult sr = (SAXResult) outputTarget;
+ try
+ {
+ ContentHandler ch = sr.getHandler();
+ LexicalHandler lh = sr.getLexicalHandler();
+ if (lh == null && ch instanceof LexicalHandler)
+ {
+ lh = (LexicalHandler) ch;
+ }
+ SAXSerializer serializer = new SAXSerializer();
+ serializer.serialize(parent, ch, lh);
+ }
+ catch (SAXException e)
+ {
+ if (errorListener != null)
+ {
+ errorListener.error(new TransformerException(e));
+ }
+ else
+ {
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ }
+
+ /**
+ * Strip whitespace from the source tree.
+ */
+ void strip(Node node)
+ throws TransformerConfigurationException
+ {
+ short nt = node.getNodeType();
+ if (nt == Node.ENTITY_REFERENCE_NODE)
+ {
+ // Replace entity reference with its content
+ Node parent = node.getParentNode();
+ Node child = node.getFirstChild();
+ if (child != null)
+ {
+ strip(child);
+ }
+ while (child != null)
+ {
+ Node next = child.getNextSibling();
+ node.removeChild(child);
+ parent.insertBefore(child, node);
+ child = next;
+ }
+ parent.removeChild(node);
+ }
+ if (nt == Node.TEXT_NODE || nt == Node.CDATA_SECTION_NODE)
+ {
+ if (!stylesheet.isPreserved((Text) node))
+ {
+ node.getParentNode().removeChild(node);
+ }
+ else
+ {
+ String text = node.getNodeValue();
+ String stripped = text.trim();
+ if (!text.equals(stripped))
+ {
+ node.setNodeValue(stripped);
+ }
+ }
+ }
+ else
+ {
+ for (Node child = node.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ strip(child);
+ }
+ }
+ }
+
+ /**
+ * Obtain a suitable output stream for writing the result to,
+ * and use the StreamSerializer to write the result tree to the stream.
+ */
+ void writeStreamResult(Node node, StreamResult sr, int outputMethod,
+ String encoding)
+ throws IOException
+ {
+ OutputStream out = null;
+ try
+ {
+ out = sr.getOutputStream();
+ if (out == null)
+ {
+ Writer writer = sr.getWriter();
+ if (writer != null)
+ {
+ out = new WriterOutputStream(writer);
+ }
+ }
+ if (out == null)
+ {
+ String systemId = sr.getSystemId();
+ try
+ {
+ URL url = new URL(systemId);
+ URLConnection connection = url.openConnection();
+ connection.setDoOutput(true);
+ out = connection.getOutputStream();
+ }
+ catch (MalformedURLException e)
+ {
+ out = new FileOutputStream(systemId);
+ }
+ catch (UnknownServiceException e)
+ {
+ URL url = new URL(systemId);
+ out = new FileOutputStream(url.getPath());
+ }
+ }
+ out = new BufferedOutputStream(out);
+ StreamSerializer serializer =
+ new StreamSerializer(outputMethod, encoding, null);
+ if (stylesheet != null)
+ {
+ Collection celem = stylesheet.outputCdataSectionElements;
+ serializer.setCdataSectionElements(celem);
+ }
+ serializer.serialize(node, out);
+ out.flush();
+ }
+ finally
+ {
+ try
+ {
+ if (out != null)
+ {
+ out.close();
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ void copyChildren(Document dstDoc, Node src, Node dst)
+ {
+ Node srcChild = src.getFirstChild();
+ while (srcChild != null)
+ {
+ Node dstChild = dstDoc.adoptNode(srcChild);
+ dst.appendChild(dstChild);
+ srcChild = srcChild.getNextSibling();
+ }
+ }
+
+ public void setParameter(String name, Object value)
+ {
+ if (stylesheet != null)
+ {
+ stylesheet.bindings.set(new QName(null, name), value, Bindings.PARAM);
+ }
+ }
+
+ public Object getParameter(String name)
+ {
+ if (stylesheet != null)
+ {
+ return stylesheet.bindings.get(new QName(null, name), null, 1, 1);
+ }
+ return null;
+ }
+
+ public void clearParameters()
+ {
+ if (stylesheet != null)
+ {
+ stylesheet.bindings.pop(Bindings.PARAM);
+ stylesheet.bindings.push(Bindings.PARAM);
+ }
+ }
+
+ public void setURIResolver(URIResolver resolver)
+ {
+ uriResolver = resolver;
+ }
+
+ public URIResolver getURIResolver()
+ {
+ return uriResolver;
+ }
+
+ public void setOutputProperties(Properties oformat)
+ throws IllegalArgumentException
+ {
+ if (oformat == null)
+ {
+ outputProperties.clear();
+ }
+ else
+ {
+ outputProperties.putAll(oformat);
+ }
+ }
+
+ public Properties getOutputProperties()
+ {
+ return (Properties) outputProperties.clone();
+ }
+
+ public void setOutputProperty(String name, String value)
+ throws IllegalArgumentException
+ {
+ outputProperties.put(name, value);
+ }
+
+ public String getOutputProperty(String name)
+ throws IllegalArgumentException
+ {
+ return outputProperties.getProperty(name);
+ }
+
+ public void setErrorListener(ErrorListener listener)
+ {
+ errorListener = listener;
+ }
+
+ public ErrorListener getErrorListener()
+ {
+ return errorListener;
+ }
+
+ static final String INDENT_WHITESPACE = " ";
+
+ /*
+ * Apply indent formatting to the given tree.
+ */
+ void reindent(Document doc, Node node, int offset)
+ {
+ if (node.hasChildNodes())
+ {
+ boolean markupContent = false;
+ boolean textContent = false;
+ List children = new LinkedList();
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ switch (ctx.getNodeType())
+ {
+ case Node.ELEMENT_NODE:
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ case Node.DOCUMENT_TYPE_NODE:
+ markupContent = true;
+ break;
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ case Node.ENTITY_REFERENCE_NODE:
+ case Node.COMMENT_NODE:
+ textContent = true;
+ break;
+ }
+ children.add(ctx);
+ ctx = ctx.getNextSibling();
+ }
+ if (markupContent)
+ {
+ if (textContent)
+ {
+ // XXX handle mixed content differently?
+ }
+ int nodeType = node.getNodeType();
+ if (nodeType == Node.DOCUMENT_NODE)
+ {
+ for (Iterator i = children.iterator(); i.hasNext(); )
+ {
+ ctx = (Node) i.next();
+ reindent(doc, ctx, offset + 1);
+ }
+ }
+ else
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append('\n');
+ for (int i = 0; i < offset + 1; i++)
+ {
+ buf.append(INDENT_WHITESPACE);
+ }
+ String ws = buf.toString();
+ for (Iterator i = children.iterator(); i.hasNext(); )
+ {
+ ctx = (Node) i.next();
+ node.insertBefore(doc.createTextNode(ws), ctx);
+ reindent(doc, ctx, offset + 1);
+ }
+ buf = new StringBuffer();
+ buf.append('\n');
+ ws = buf.toString();
+ for (int i = 0; i < offset; i++)
+ {
+ buf.append(INDENT_WHITESPACE);
+ }
+ node.appendChild(doc.createTextNode(ws));
+ }
+ }
+ }
+ }
+
+ /**
+ * Converts the text node children of any cdata-section-elements in the
+ * tree to CDATA section nodes.
+ */
+ void convertCdataSectionElements(Document doc, Node node, List list)
+ {
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ boolean match = false;
+ for (Iterator i = list.iterator(); i.hasNext(); )
+ {
+ QName qname = (QName) i.next();
+ if (match(qname, node))
+ {
+ match = true;
+ break;
+ }
+ }
+ if (match)
+ {
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ if (ctx.getNodeType() == Node.TEXT_NODE)
+ {
+ Node cdata = doc.createCDATASection(ctx.getNodeValue());
+ node.replaceChild(cdata, ctx);
+ ctx = cdata;
+ }
+ ctx = ctx.getNextSibling();
+ }
+ }
+ }
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ if (ctx.hasChildNodes())
+ {
+ convertCdataSectionElements(doc, ctx, list);
+ }
+ ctx = ctx.getNextSibling();
+ }
+ }
+
+ boolean match(QName qname, Node node)
+ {
+ String ln1 = qname.getLocalPart();
+ String ln2 = node.getLocalName();
+ if (ln2 == null)
+ {
+ return ln1.equals(node.getNodeName());
+ }
+ else
+ {
+ String uri1 = qname.getNamespaceURI();
+ String uri2 = node.getNamespaceURI();
+ return (uri1.equals(uri2) && ln1.equals(ln2));
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TransformerOutputProperties.java b/libjava/classpath/gnu/xml/transform/TransformerOutputProperties.java
new file mode 100644
index 0000000..cc8593c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TransformerOutputProperties.java
@@ -0,0 +1,185 @@
+/* TransformerOutputProperties.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import javax.xml.transform.OutputKeys;
+
+/**
+ * Helper class to manage JAXP user setting of output properties.
+ *
+ * @author Chris Burdess
+ */
+class TransformerOutputProperties
+ extends Properties
+{
+
+ final Properties defaultProperties;
+ final Stylesheet stylesheet;
+ boolean dirty;
+
+ TransformerOutputProperties(Stylesheet stylesheet)
+ {
+ this.stylesheet = stylesheet;
+ defaultProperties = new Properties();
+ switch (stylesheet.outputMethod)
+ {
+ case Stylesheet.OUTPUT_XML:
+ defaultProperties.put(OutputKeys.METHOD, "xml");
+ break;
+ case Stylesheet.OUTPUT_HTML:
+ defaultProperties.put(OutputKeys.METHOD, "html");
+ break;
+ case Stylesheet.OUTPUT_TEXT:
+ defaultProperties.put(OutputKeys.METHOD, "text");
+ break;
+ }
+ if (stylesheet.outputVersion != null)
+ {
+ defaultProperties.put(OutputKeys.VERSION, stylesheet.outputVersion);
+ }
+ if (stylesheet.outputEncoding != null)
+ {
+ defaultProperties.put(OutputKeys.ENCODING, stylesheet.outputEncoding);
+ }
+ defaultProperties.put(OutputKeys.OMIT_XML_DECLARATION,
+ stylesheet.outputOmitXmlDeclaration ? "yes" : "no");
+ defaultProperties.put(OutputKeys.STANDALONE,
+ stylesheet.outputStandalone ? "yes" : "no");
+ if (stylesheet.outputPublicId != null)
+ {
+ defaultProperties.put(OutputKeys.DOCTYPE_PUBLIC,
+ stylesheet.outputPublicId);
+ }
+ if (stylesheet.outputSystemId != null)
+ {
+ defaultProperties.put(OutputKeys.DOCTYPE_SYSTEM,
+ stylesheet.outputSystemId);
+ }
+ StringBuffer buf = new StringBuffer();
+ for (Iterator i = stylesheet.outputCdataSectionElements.iterator();
+ i.hasNext(); )
+ {
+ if (buf.length() > 0)
+ {
+ buf.append(' ');
+ }
+ buf.append((String) i.next());
+ }
+ defaultProperties.put(OutputKeys.CDATA_SECTION_ELEMENTS, buf.toString());
+ defaultProperties.put(OutputKeys.INDENT,
+ stylesheet.outputIndent ? "yes" : "no");
+ if (stylesheet.outputMediaType != null)
+ {
+ defaultProperties.put(OutputKeys.MEDIA_TYPE,
+ stylesheet.outputMediaType);
+ }
+ }
+
+ public String getProperty(String key)
+ {
+ String val = super.getProperty(key);
+ if (val == null)
+ {
+ val = defaultProperties.getProperty(key);
+ }
+ return val;
+ }
+
+ public Object put(Object key, Object value)
+ {
+ Object ret = super.put(key, value);
+ dirty = true;
+ return ret;
+ }
+
+ public void clear()
+ {
+ super.clear();
+ dirty = true;
+ }
+
+ /**
+ * Applies the current set of properties to the underlying stylesheet.
+ */
+ void apply()
+ {
+ if (!dirty)
+ {
+ return;
+ }
+ String method = getProperty(OutputKeys.METHOD);
+ if ("xml".equals(method))
+ {
+ stylesheet.outputMethod = Stylesheet.OUTPUT_XML;
+ }
+ else if ("html".equals(method))
+ {
+ stylesheet.outputMethod = Stylesheet.OUTPUT_HTML;
+ }
+ else if ("text".equals(method))
+ {
+ stylesheet.outputMethod = Stylesheet.OUTPUT_TEXT;
+ }
+ stylesheet.outputVersion = getProperty(OutputKeys.VERSION);
+ stylesheet.outputEncoding = getProperty(OutputKeys.ENCODING);
+ stylesheet.outputOmitXmlDeclaration =
+ "yes".equals(getProperty(OutputKeys.OMIT_XML_DECLARATION));
+ stylesheet.outputStandalone =
+ "yes".equals(getProperty(OutputKeys.STANDALONE));
+ stylesheet.outputPublicId = getProperty(OutputKeys.DOCTYPE_PUBLIC);
+ stylesheet.outputSystemId = getProperty(OutputKeys.DOCTYPE_SYSTEM);
+ StringTokenizer st =
+ new StringTokenizer(getProperty(OutputKeys.CDATA_SECTION_ELEMENTS));
+ Collection acc = new LinkedHashSet();
+ while (st.hasMoreTokens())
+ {
+ acc.add(st.nextToken());
+ }
+ stylesheet.outputCdataSectionElements = acc;
+ stylesheet.outputIndent = "yes".equals(getProperty(OutputKeys.INDENT));
+ stylesheet.outputMediaType = getProperty(OutputKeys.MEDIA_TYPE);
+ dirty = false;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/URIResolverEntityResolver.java b/libjava/classpath/gnu/xml/transform/URIResolverEntityResolver.java
new file mode 100644
index 0000000..762416f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/URIResolverEntityResolver.java
@@ -0,0 +1,83 @@
+/* URIResolverEntityResolver.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.io.IOException;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.sax.SAXSource;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * EntityResolver that wraps a URIResolver.
+ *
+ * @author Chris Burdess
+ */
+class URIResolverEntityResolver
+ implements EntityResolver
+{
+
+ final URIResolver resolver;
+
+ URIResolverEntityResolver(URIResolver resolver)
+ {
+ this.resolver = resolver;
+ }
+
+ public InputSource resolveEntity(String publicId, String systemId)
+ throws SAXException, IOException
+ {
+ try
+ {
+ Source source = resolver.resolve(null, systemId);
+ if (source == null)
+ {
+ return null;
+ }
+ return SAXSource.sourceToInputSource(source);
+ }
+ catch (TransformerException e)
+ {
+ throw new SAXException(e);
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/UnparsedEntityUriFunction.java b/libjava/classpath/gnu/xml/transform/UnparsedEntityUriFunction.java
new file mode 100644
index 0000000..92002f1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/UnparsedEntityUriFunction.java
@@ -0,0 +1,132 @@
+/* UnparsedEntityUriFunction.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.Notation;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Function;
+
+/**
+ * The XSLT unparsed-entity-uri()
function.
+ *
+ * @author Chris Burdess
+ */
+final class UnparsedEntityUriFunction
+ extends Expr
+ implements XPathFunction, Function
+{
+
+ List args;
+
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ // Useless...
+ return Collections.EMPTY_SET;
+ }
+
+ public void setArguments(List args)
+ {
+ this.args = args;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ int arity = args.size();
+ List values = new ArrayList(arity);
+ for (int i = 0; i < arity; i++)
+ {
+ Expr arg = (Expr) args.get(i);
+ values.add(arg.evaluate(context, pos, len));
+ }
+ String name = _string(context, values.get(0));
+ DocumentType doctype = context.getOwnerDocument().getDoctype();
+ if (doctype != null)
+ {
+ NamedNodeMap notations = doctype.getNotations();
+ Notation notation = (Notation) notations.getNamedItem(name);
+ if (notation != null)
+ {
+ String systemId = notation.getSystemId();
+ // XXX absolutize?
+ if (systemId != null)
+ {
+ return systemId;
+ }
+ }
+ }
+ return "";
+ }
+
+ public Expr clone(Object context)
+ {
+ UnparsedEntityUriFunction f = new UnparsedEntityUriFunction();
+ int len = args.size();
+ List args2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(((Expr) args.get(i)).clone(context));
+ }
+ f.setArguments(args2);
+ return f;
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator i = args.iterator(); i.hasNext(); )
+ {
+ if (((Expr) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/ValueOfNode.java b/libjava/classpath/gnu/xml/transform/ValueOfNode.java
new file mode 100644
index 0000000..430598a
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/ValueOfNode.java
@@ -0,0 +1,161 @@
+/* ValueOfNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.Collection;
+import java.util.Iterator;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing an XSLT value-of
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class ValueOfNode
+ extends TemplateNode
+{
+
+ final Expr select;
+ final boolean disableOutputEscaping;
+
+ ValueOfNode(Expr select, boolean disableOutputEscaping)
+ {
+ this.select = select;
+ this.disableOutputEscaping = disableOutputEscaping;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new ValueOfNode(select.clone(stylesheet),
+ disableOutputEscaping);
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ Object ret = select.evaluate(context, pos, len);
+ /*if (stylesheet.debug)
+ {
+ System.err.println("value-of: " + select + " -> " + ret);
+ }*/
+ String value;
+ if (ret instanceof Collection)
+ {
+ StringBuffer buf = new StringBuffer();
+ for (Iterator i = ((Collection) ret).iterator(); i.hasNext(); )
+ {
+ Node node = (Node) i.next();
+ buf.append(Expr.stringValue(node));
+ }
+ value = buf.toString();
+ }
+ else
+ {
+ value = Expr._string(context, ret);
+ }
+ if (stylesheet.debug)
+ {
+ System.err.println("value-of: "+context+" "+ select + " -> "+ value);
+ }
+ if (value != null && value.length() > 0)
+ {
+ Document doc = (parent instanceof Document) ?
+ (Document) parent : parent.getOwnerDocument();
+ Text textNode = doc.createTextNode(value);
+ if (disableOutputEscaping)
+ {
+ textNode.setUserData("disable-output-escaping", "yes", stylesheet);
+ }
+ if (nextSibling != null)
+ {
+ parent.insertBefore(textNode, nextSibling);
+ }
+ else
+ {
+ parent.appendChild(textNode);
+ }
+ }
+ // value-of doesn't process children
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+
+ public boolean references(QName var)
+ {
+ if (select != null && select.references(var))
+ {
+ return true;
+ }
+ return super.references(var);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("select=");
+ buf.append(select);
+ if (disableOutputEscaping)
+ {
+ buf.append(",disableOutputEscaping");
+ }
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/WhenNode.java b/libjava/classpath/gnu/xml/transform/WhenNode.java
new file mode 100644
index 0000000..231f269
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/WhenNode.java
@@ -0,0 +1,123 @@
+/* WhenNode.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing an XSL when
instruction.
+ *
+ * @author Chris Burdess
+ */
+final class WhenNode
+ extends TemplateNode
+{
+
+ final Expr test;
+
+ WhenNode(Expr test)
+ {
+ this.test = test;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new WhenNode(test.clone(stylesheet));
+ if (children != null)
+ {
+ ret.children = children.clone(stylesheet);
+ }
+ if (next != null)
+ {
+ ret.next = next.clone(stylesheet);
+ }
+ return ret;
+ }
+
+ void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ Object ret = test.evaluate(context, pos, len);
+ boolean success = (ret instanceof Boolean) ?
+ ((Boolean) ret).booleanValue() :
+ Expr._boolean(context, ret);
+ if (success)
+ {
+ if (children != null)
+ {
+ children.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+ else
+ {
+ if (next != null)
+ {
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+ }
+ }
+
+ public boolean references(QName var)
+ {
+ if (test != null && test.references(var))
+ {
+ return true;
+ }
+ return super.references(var);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer(getClass().getName());
+ buf.append('[');
+ buf.append("test=");
+ buf.append(test);
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/WithParam.java b/libjava/classpath/gnu/xml/transform/WithParam.java
new file mode 100644
index 0000000..0fb09d6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/WithParam.java
@@ -0,0 +1,123 @@
+/* WithParam.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.Collections;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A specification for setting a variable or parameter during template
+ * processing with apply-templates
or
+ * call-template
.
+ *
+ * @author Chris Burdess
+ */
+final class WithParam
+{
+
+ final QName name;
+ final Expr select;
+ final TemplateNode content;
+
+ WithParam(QName name, Expr select)
+ {
+ this.name = name;
+ this.select = select;
+ content = null;
+ }
+
+ WithParam(QName name, TemplateNode content)
+ {
+ this.name = name;
+ this.content = content;
+ select = null;
+ }
+
+ Object getValue(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len)
+ throws TransformerException
+ {
+ if (select != null)
+ {
+ return select.evaluate(context, pos, len);
+ }
+ else
+ {
+ Document doc = (context instanceof Document) ? (Document) context :
+ context.getOwnerDocument();
+ DocumentFragment fragment = doc.createDocumentFragment();
+ content.apply(stylesheet, mode,
+ context, pos, len,
+ fragment, null);
+ return Collections.singleton(fragment);
+ }
+ }
+
+ WithParam clone(Stylesheet stylesheet)
+ {
+ if (content == null)
+ {
+ return new WithParam(name,
+ select.clone(stylesheet));
+ }
+ else
+ {
+ return new WithParam(name,
+ content.clone(stylesheet));
+ }
+ }
+
+ boolean references(QName var)
+ {
+ if (select != null && select.references(var))
+ {
+ return true;
+ }
+ if (content != null && content.references(var))
+ {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/XSLComparator.java b/libjava/classpath/gnu/xml/transform/XSLComparator.java
new file mode 100644
index 0000000..222f370
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/XSLComparator.java
@@ -0,0 +1,124 @@
+/* XSLComparator.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.text.Collator;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * Comparator for sorting lists of nodes according to a list of sort keys.
+ *
+ * @author Chris Burdess
+ */
+class XSLComparator
+ implements Comparator
+{
+
+ final List sortKeys;
+
+ XSLComparator(List sortKeys)
+ {
+ this.sortKeys = sortKeys;
+ }
+
+ public int compare(Object o1, Object o2)
+ {
+ if (o1 instanceof Node && o2 instanceof Node)
+ {
+ Node n1 = (Node) o1;
+ Node n2 = (Node) o2;
+ for (Iterator i = sortKeys.iterator(); i.hasNext(); )
+ {
+ SortKey sortKey = (SortKey) i.next();
+ String k1 = sortKey.key(n1);
+ String k2 = sortKey.key(n2);
+ if ("text".equals(sortKey.dataType))
+ {
+ Locale locale = (sortKey.lang == null) ? Locale.getDefault() :
+ new Locale(sortKey.lang);
+ Collator collator = Collator.getInstance(locale);
+ int d = collator.compare(k1, k2);
+ if (d != 0)
+ {
+ switch (sortKey.caseOrder)
+ {
+ case SortKey.UPPER_FIRST:
+ // TODO
+ break;
+ case SortKey.LOWER_FIRST:
+ // TODO
+ break;
+ }
+ if (sortKey.descending)
+ {
+ d = -d;
+ }
+ return d;
+ }
+ }
+ else if ("number".equals(sortKey.dataType))
+ {
+ double kn1 = Expr._number(n1, k1);
+ double kn2 = Expr._number(n2, k2);
+ int d;
+ if (Double.isNaN(kn1) || Double.isInfinite(kn2))
+ {
+ d = -1;
+ }
+ else if (Double.isNaN(kn2) || Double.isInfinite(kn1))
+ {
+ d = 1;
+ }
+ else
+ {
+ // conversion to int may give 0 for small numbers
+ d = (kn1 > kn2) ? 1 : (kn1 < kn2) ? -1 : 0;
+ }
+ return (sortKey.descending) ? -d : d;
+ }
+ }
+ }
+ return 0;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/XSLURIResolver.java b/libjava/classpath/gnu/xml/transform/XSLURIResolver.java
new file mode 100644
index 0000000..6a49caa
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/XSLURIResolver.java
@@ -0,0 +1,282 @@
+/* XSLURIResolver.java --
+ Copyright (C) 2004 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 gnu.xml.transform;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.Map;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamSource;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import gnu.xml.dom.ls.ReaderInputStream;
+
+/**
+ * URI resolver for XSLT.
+ * This resolver parses external entities into DOMSources. It
+ * maintains a cache of URIs to DOMSources to avoid expensive re-parsing.
+ *
+ * @author Chris Burdess
+ */
+class XSLURIResolver
+ implements URIResolver
+{
+
+ Map lastModifiedCache = new HashMap();
+ Map nodeCache = new HashMap();
+ DocumentBuilder builder;
+ URIResolver userResolver;
+ ErrorListener userListener;
+
+ void setUserResolver(URIResolver userResolver)
+ {
+ this.userResolver = userResolver;
+ }
+
+ void setUserListener(ErrorListener userListener)
+ {
+ this.userListener = userListener;
+ }
+
+ /**
+ * Clear the cache.
+ */
+ void flush()
+ {
+ lastModifiedCache.clear();
+ nodeCache.clear();
+ }
+
+ public Source resolve(String href, String base)
+ throws TransformerException
+ {
+ Source source = null;
+ if (userResolver != null)
+ {
+ source = userResolver.resolve(base, href);
+ }
+ return resolveDOM(source, href, base);
+ }
+
+ DOMSource resolveDOM(Source source, String base, String href)
+ throws TransformerException
+ {
+ if (source != null && source instanceof DOMSource)
+ {
+ return (DOMSource) source;
+ }
+ String systemId = (source == null) ? null : source.getSystemId();
+ long lastModified = 0L, lastLastModified = 0L;
+
+ try
+ {
+ URL url = resolveURL(systemId, base, href);
+ Node node = null;
+ InputStream in = null;
+ if (source instanceof StreamSource)
+ {
+ StreamSource ss = (StreamSource) source;
+ in = ss.getInputStream();
+ if (in == null)
+ {
+ Reader reader = ss.getReader();
+ if (reader != null)
+ {
+ in = new ReaderInputStream(reader);
+ }
+ }
+ }
+ if (in == null)
+ {
+ if (url != null)
+ {
+ systemId = url.toString();
+ node = (Node) nodeCache.get(systemId);
+ // Is the resource up to date?
+ URLConnection conn = url.openConnection();
+ Long llm = (Long) lastModifiedCache.get(systemId);
+ if (llm != null)
+ {
+ lastLastModified = llm.longValue();
+ conn.setIfModifiedSince(lastLastModified);
+ }
+ conn.connect();
+ lastModified = conn.getLastModified();
+ if (node != null &&
+ lastModified > 0L &&
+ lastModified <= lastLastModified)
+ {
+ // Resource unchanged
+ return new DOMSource(node, systemId);
+ }
+ else
+ {
+ // Resource new or modified
+ in = conn.getInputStream();
+ nodeCache.put(systemId, node);
+ lastModifiedCache.put(systemId, new Long(lastModified));
+ }
+ }
+ else
+ {
+ throw new TransformerException("can't resolve URL: " +
+ systemId);
+ }
+ }
+ InputSource input = new InputSource(in);
+ input.setSystemId(systemId);
+ DocumentBuilder builder = getDocumentBuilder();
+ node = builder.parse(input);
+ return new DOMSource(node, systemId);
+ }
+ catch (IOException e)
+ {
+ throw new TransformerException(e);
+ }
+ catch (SAXException e)
+ {
+ throw new TransformerException(e);
+ }
+ }
+
+ URL resolveURL(String systemId, String base, String href)
+ throws IOException
+ {
+ URL url = null;
+ try
+ {
+ if (systemId != null)
+ {
+ try
+ {
+ url = new URL(systemId);
+ }
+ catch (MalformedURLException e)
+ {
+ // Try building from base + href
+ }
+ }
+ if (url == null)
+ {
+ if (base != null)
+ {
+ URL baseURL = new URL(base);
+ url = new URL(baseURL, href);
+ }
+ else if (href != null)
+ {
+ url = new URL(href);
+ }
+ else
+ {
+ // See below
+ throw new MalformedURLException(systemId);
+ }
+ }
+ return url;
+ }
+ catch (MalformedURLException e)
+ {
+ // Fall back to local filesystem
+ File file = null;
+ if (href == null)
+ {
+ href = systemId;
+ }
+ if (base != null)
+ {
+ int lsi = base.lastIndexOf(File.separatorChar);
+ if (lsi != -1 && lsi < base.length() - 1)
+ {
+ base = base.substring(0, lsi);
+ }
+ File baseFile = new File(base);
+ file = new File(baseFile, href);
+ }
+ else if (href != null)
+ {
+ file = new File(href);
+ }
+ return (file == null) ? null : file.toURL();
+ }
+ }
+
+ DocumentBuilder getDocumentBuilder()
+ throws TransformerException
+ {
+ try
+ {
+ if (builder == null)
+ {
+ DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setExpandEntityReferences(true);
+ builder = factory.newDocumentBuilder();
+ }
+ if (userResolver != null)
+ {
+ builder.setEntityResolver(new URIResolverEntityResolver(userResolver));
+ }
+ if (userListener != null)
+ {
+ builder.setErrorHandler(new ErrorListenerErrorHandler(userListener));
+ }
+ return builder;
+ }
+ catch (Exception e)
+ {
+ throw new TransformerException(e);
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/xml/transform/package.html b/libjava/classpath/gnu/xml/transform/package.html
new file mode 100644
index 0000000..d435596
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/package.html
@@ -0,0 +1,77 @@
+
+GNU JAXP XSL transformer
+
+javax.xml.transform.TransformerFactory
to the value
+gnu.xml.transform.TransformerFactoryImpl
. You can then
+instantiate TransformerFactory
+and transformers in the ordinary manner. Reuse of stylesheets is
+supported using the JAXP Templates
+mechanism.
+Architecture
+
+apply
on its
+corresponding TemplateNode. This in turn processes its children and next
+TemplateNode, depending on the semantics of each node type.
+Conformance
+
+Known bugs
+
+
+
+
+apply-imports
instructions will not work.position()
function,
+as well as select
expressions and numbering.
+ *
+ * nsfix | validate to validate the input document
+ * nsfix | write ( stdout ) to echo the file as XML text
+ * dom | nsfix | write ( stdout ) parse into DOM, print the result
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * Name
+ * Notes
+ *
+ *
+ * (URL)/external-general-entities
+ * false (does no parsing)
+ * (URL)/external-parameter-entities
+ * false (does no parsing)
+ * (URL)/namespaces
+ * Value is fixed at true
+ * (URL)/namespace-prefixes
+ * Value is settable, defaulting to false
+ * ( xmlns
attributes hidden, and names aren't prefixed)
+ *
+ * (URL)/string-interning
+ * Value is fixed at false (DOM provides no
+ * guarantees as to interning)
+ * (URL)/validation
+ * false (does no parsing)
+ *
+ * (URL)/lexical-handler/parameter-entities
+ * false (DOM doesn't do parameter entities)
+ *
+ *
+ *
+ * (URL)/dom-node
+ * This property may be set before parsing to hold a DOM
+ * Document node; any arguments given to parse
+ * methods are ignored. When retrieved
+ * during a parse, this value contains the "current" DOM node.
+ *
+ * (URL)/declaration-handler
+ * A declaration handler may be provided. Declaration of external
+ * general entities is exposed, but not parameter entities; none of the
+ * entity names reported here will begin with "%".
+ * (URL)/lexical-handler
+ * A lexical handler may be provided. While the start and end of
+ * any external subset are reported, expansion of other parameter
+ * entities (e.g. inside attribute list declarations) is not exposed.
+ * Expansion of general entities within attributes is also not exposed
+ * (see below). charset=...
attribute
+ */
+ static public String getEncoding (String contentType)
+ {
+ // currently a dumb parsing algorithm that works "mostly" and handles
+ // ..anything...charset=ABC
+ // ..anything...charset=ABC;otherAttr=DEF
+ // ..anything...charset=ABC (comment);otherAttr=DEF
+ // ..anything...charset= "ABC" (comment);otherAttr=DEF
+
+ int temp;
+ String encoding;
+ String defValue = null;
+
+ if (contentType.startsWith ("text/"))
+ defValue = contentType.startsWith ("text/html")
+ ? "ISO-8859-1" : "US-ASCII";
+
+ // Assumes 'charset' is only an attribute name, not part
+ // of a value, comment, or other attribute name
+ // ALSO assumes no escaped values like "\;" or "\)"
+ if ((temp = contentType.indexOf ("charset")) != -1) {
+ // strip out everything up to '=' ...
+ temp = contentType.indexOf ('=', temp);
+ if (temp == -1)
+ return defValue;
+ encoding = contentType.substring (temp + 1);
+ // ... and any subsequent attributes
+ if ((temp = encoding.indexOf (';')) != -1)
+ encoding = encoding.substring (0, temp);
+ // ... and any comments after value
+ if ((temp = encoding.indexOf ('(')) != -1)
+ encoding = encoding.substring (0, temp);
+ // ... then whitespace, and any (double) quotes
+ encoding = encoding.trim ();
+ if (encoding.charAt (0) == '"')
+ encoding = encoding.substring (1, encoding.length () - 1);
+ } else
+ encoding = defValue;
+ return encoding;
+ }
+
+
+ /**
+ * Uses a local dictionary of public identifiers to resolve URIs,
+ * normally with the goal of minimizing network traffic or latencies.
+ */
+ public InputSource resolveEntity (String publicId, String systemId)
+ throws IOException, SAXException
+ {
+ InputSource retval = null;
+ String uri;
+
+ if (publicId != null
+ && ((uri = (String) pubidMapping.get (publicId)) != null)) {
+ retval = new InputSource (uri);
+ retval.setPublicId (publicId);
+ }
+
+ // Could do URN resolution here
+
+ // URL resolution always done by parser
+
+ // FIXME: chain to "next" resolver
+
+ return retval;
+ }
+}
diff --git a/libjava/classpath/gnu/xml/util/SAXNullTransformerFactory.java b/libjava/classpath/gnu/xml/util/SAXNullTransformerFactory.java
new file mode 100644
index 0000000..81ad823
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/SAXNullTransformerFactory.java
@@ -0,0 +1,676 @@
+/* SAXNullTransformerFactory.java --
+ Copyright (C) 2001 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 gnu.xml.util;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import gnu.xml.dom.Consumer;
+import gnu.xml.dom.DomDocument;
+import gnu.xml.pipeline.DomConsumer;
+import gnu.xml.pipeline.EventFilter;
+
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.sax.*;
+import javax.xml.transform.stream.*;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.XMLReaderFactory;
+import org.xml.sax.helpers.LocatorImpl;
+
+
+/**
+ * Implements null transforms. XSLT stylesheets are not supported.
+ * This class provides a way to translate three representations of
+ * XML data (SAX event stream, DOM tree, and XML text) into each other.
+ * In essence it's a thinnish wrapper around basic SAX event
+ * pipeline facilities, which
+ * exposes only limited functionality. The javax.xml.transform
+ * functionality is implemented as follows:
+ *
+ *
+ *
+ *
+ * XCat catalog = new XCat ();
+ * catalog.setErrorHandler (diagnosticErrorHandler);
+ * catalog.loadCatalog ("file:/local/catalogs/catalog.cat");
+ * catalog.loadCatalog ("http://shared/catalog.cat");
+ * ...
+ * catalog.disableLoading ();
+ * parser1.setEntityResolver (catalog);
+ * parser2.setEntityResolver (catalog);
+ * ...
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * boolean
function converts its argument to a boolean as
+ * follows:
+ *
+ *
+ *
+ * @author Chris Burdess
+ */
+final class BooleanFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ BooleanFunction(List args)
+ {
+ this((Expr) args.get(0));
+ }
+
+ BooleanFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ return _boolean(context, val) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new BooleanFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "boolean(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/CeilingFunction.java b/libjava/classpath/gnu/xml/xpath/CeilingFunction.java
new file mode 100644
index 0000000..7db08fc
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/CeilingFunction.java
@@ -0,0 +1,89 @@
+/* CeilingFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The ceiling
function returns the smallest (closest to
+ * negative infinity) number that is not less than the argument and that
+ * is an integer.
+ *
+ * @author Chris Burdess
+ */
+final class CeilingFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ CeilingFunction(List args)
+ {
+ this((Expr) args.get(0));
+ }
+
+ CeilingFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ double n = _number(context, val);
+ return new Double(Math.ceil(n));
+ }
+
+ public Expr clone(Object context)
+ {
+ return new CeilingFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "ceiling(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/ConcatFunction.java b/libjava/classpath/gnu/xml/xpath/ConcatFunction.java
new file mode 100644
index 0000000..fddd7ae
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/ConcatFunction.java
@@ -0,0 +1,113 @@
+/* ConcatFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The concat
function returns the concatenation of its arguments.
+ *
+ * @author Chris Burdess
+ */
+final class ConcatFunction
+ extends Expr
+{
+
+ final List args;
+
+ ConcatFunction(List args)
+ {
+ this.args = args;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ StringBuffer buf = new StringBuffer();
+ for (Iterator i = args.iterator(); i.hasNext(); )
+ {
+ Expr arg = (Expr) i.next();
+ Object val = arg.evaluate(context, pos, len);
+ buf.append(_string(context, val));
+ }
+ return buf.toString();
+ }
+
+ public Expr clone(Object context)
+ {
+ int len = args.size();
+ List args2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(((Expr) args.get(i)).clone(context));
+ }
+ return new ConcatFunction(args2);
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator i = args.iterator(); i.hasNext(); )
+ {
+ if (((Expr) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer("concat(");
+ int len = args.size();
+ for (int i = 0; i < len; i++)
+ {
+ if (i > 0)
+ {
+ buf.append(',');
+ }
+ buf.append(args.get(i));
+ }
+ buf.append(')');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Constant.java b/libjava/classpath/gnu/xml/xpath/Constant.java
new file mode 100644
index 0000000..d5ca764
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Constant.java
@@ -0,0 +1,98 @@
+/* Constant.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Constant value (string literal or number).
+ *
+ * @author Chris Burdess
+ */
+public final class Constant
+ extends Expr
+{
+
+ final Object value;
+
+ public Constant(Object value)
+ {
+ this.value = value;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return value;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new Constant(value);
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ String ret = value.toString();
+ if (value instanceof String)
+ {
+ if (ret.indexOf('\'') == -1)
+ {
+ return '\'' + ret + '\'';
+ }
+ else
+ {
+ return '"' + ret + '"';
+ }
+ }
+ if (value instanceof Double)
+ {
+ if (ret.endsWith(".0"))
+ {
+ ret = ret.substring(0, ret.length() - 2);
+ }
+ }
+ return ret;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/ContainsFunction.java b/libjava/classpath/gnu/xml/xpath/ContainsFunction.java
new file mode 100644
index 0000000..fc2f33f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/ContainsFunction.java
@@ -0,0 +1,92 @@
+/* ContainsFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The contains
function returns true if the first argument
+ * string contains the second argument string, and otherwise returns false.
+ *
+ * @author Chris Burdess
+ */
+final class ContainsFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+
+ ContainsFunction(List args)
+ {
+ this((Expr) args.get(0), (Expr) args.get(1));
+ }
+
+ ContainsFunction(Expr arg1, Expr arg2)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ String s1 = _string(context, val1);
+ String s2 = _string(context, val2);
+ return (s1.indexOf(s2) != -1) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new ContainsFunction(arg1.clone(context), arg2.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var));
+ }
+
+ public String toString()
+ {
+ return "contains(" + arg1 + "," + arg2 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/CountFunction.java b/libjava/classpath/gnu/xml/xpath/CountFunction.java
new file mode 100644
index 0000000..cb534bf
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/CountFunction.java
@@ -0,0 +1,88 @@
+/* CountFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.Collection;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The count
function returns the number of nodes in the
+ * argument node-set.
+ *
+ * @author Chris Burdess
+ */
+final class CountFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ CountFunction(List args)
+ {
+ this((Expr) args.get(0));
+ }
+
+ CountFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ return new Double((double) ((Collection) val).size());
+ }
+
+ public Expr clone(Object context)
+ {
+ return new CountFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "count(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/DocumentOrderComparator.java b/libjava/classpath/gnu/xml/xpath/DocumentOrderComparator.java
new file mode 100644
index 0000000..c7d7de9
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/DocumentOrderComparator.java
@@ -0,0 +1,63 @@
+/* DocumentOrderComparator.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.Comparator;
+import org.w3c.dom.Node;
+
+/**
+ * Sorts nodes into document order.
+ *
+ * @author Chris Burdess
+ */
+public class DocumentOrderComparator
+ implements Comparator
+{
+
+ public int compare(Object o1, Object o2)
+ {
+ if (o1 instanceof Node && o2 instanceof Node)
+ {
+ Node n1 = (Node)o1;
+ Node n2 = (Node)o2;
+ return (int) n1.compareDocumentPosition(n2);
+ }
+ return 0;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/EqualityExpr.java b/libjava/classpath/gnu/xml/xpath/EqualityExpr.java
new file mode 100644
index 0000000..6d00cee
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/EqualityExpr.java
@@ -0,0 +1,268 @@
+/* EqualityExpr.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.Collection;
+import java.util.Iterator;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Boolean equality expression.
+ *
+ * @author Chris Burdess
+ */
+final class EqualityExpr
+ extends Expr
+{
+
+ final Expr lhs;
+ final Expr rhs;
+ final boolean invert;
+
+ EqualityExpr(Expr lhs, Expr rhs, boolean invert)
+ {
+ this.lhs = lhs;
+ this.rhs = rhs;
+ this.invert = invert;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ boolean val = evaluateImpl(context, pos, len);
+ if (invert)
+ {
+ return val ? Boolean.FALSE : Boolean.TRUE;
+ }
+ else
+ {
+ return val ? Boolean.TRUE : Boolean.FALSE;
+ }
+ }
+
+ private boolean evaluateImpl(Node context, int pos, int len)
+ {
+ Object left = lhs.evaluate(context, pos, len);
+ Object right = rhs.evaluate(context, pos, len);
+
+ /*
+ * If both objects to be compared are node-sets, then the comparison
+ * will be true if and only if there is a node in the first node-set and
+ * a node in the second node-set such that the result of performing the
+ * comparison on the string-values of the two nodes is true.
+ */
+ boolean flns = left instanceof Collection;
+ boolean frns = right instanceof Collection;
+ if (flns && frns)
+ {
+ Collection lns = (Collection) left;
+ Collection rns = (Collection) right;
+ if (lns.isEmpty())
+ {
+ return false;
+ }
+ boolean all = true;
+ for (Iterator i = lns.iterator(); i.hasNext(); )
+ {
+ Node ltest = (Node) i.next();
+ for (Iterator j = rns.iterator(); j.hasNext(); )
+ {
+ Node rtest = (Node) j.next();
+ if (ltest == rtest || ltest.equals(rtest))
+ {
+ // much shorter
+ if (!invert)
+ {
+ return true;
+ }
+ }
+ else if (stringValue(ltest).equals(stringValue(rtest)))
+ {
+ if (!invert)
+ {
+ return true;
+ }
+ }
+ else
+ {
+ all = false;
+ }
+ }
+ }
+ return all;
+ }
+ /*
+ * If one object to be compared is a node-set and the other is a number,
+ * then the comparison will be true if and only if there is a node in
+ * the node-set such that the result of performing the comparison on the
+ * number to be compared and on the result of converting the
+ * string-value of that node to a number using the number function is
+ * true.
+ */
+ boolean fln = left instanceof Double;
+ boolean frn = right instanceof Double;
+ if ((flns && frn) || (frns && fln))
+ {
+ Collection ns = flns ? (Collection) left : (Collection) right;
+ double n = fln ? ((Double) left).doubleValue() :
+ ((Double) right).doubleValue();
+ boolean all = true;
+ for (Iterator i = ns.iterator(); i.hasNext(); )
+ {
+ Node test = (Node) i.next();
+ double nn = _number(context, stringValue(test));
+ if (nn == n)
+ {
+ if (!invert)
+ {
+ return true;
+ }
+ }
+ else
+ {
+ all = false;
+ }
+ }
+ return invert ? all : false;
+ }
+ /*
+ * If one object to be compared is a node-set and the other is a
+ * string, then the comparison will be true if and only if there is a
+ * node in the node-set such that the result of performing the
+ * comparison on the string-value of the node and the other string is
+ * true.
+ */
+ boolean fls = left instanceof String;
+ boolean frs = right instanceof String;
+ if ((flns && frs) || (frns && fls))
+ {
+ Collection ns = flns ? (Collection) left : (Collection) right;
+ String s = fls ? (String) left : (String) right;
+ boolean all = true;
+ for (Iterator i = ns.iterator(); i.hasNext(); )
+ {
+ Node test = (Node) i.next();
+ if (stringValue(test).equals(s))
+ {
+ if (!invert)
+ {
+ return true;
+ }
+ }
+ else
+ {
+ all = false;
+ }
+ }
+ return invert ? all : false;
+ }
+ /*
+ * If one object to be compared is a node-set and the other is a
+ * boolean, then the comparison will be true if and only if the result
+ * of performing the comparison on the boolean and on the result of
+ * converting the node-set to a boolean using the boolean function is
+ * true.
+ */
+ boolean flb = left instanceof Boolean;
+ boolean frb = right instanceof Boolean;
+ if ((flns && frb) || (frns && flb))
+ {
+ Collection ns = flns ? (Collection) left : (Collection) right;
+ boolean b = flb ? ((Boolean) left).booleanValue() :
+ ((Boolean) right).booleanValue();
+ return _boolean(context, ns) == b;
+ }
+ /*
+ * If at least one object to be compared is a boolean, then each object
+ * to be compared is converted to a boolean as if by applying the
+ * boolean function.
+ */
+ if (flb || frb)
+ {
+ boolean lb = flb ? ((Boolean) left).booleanValue() :
+ _boolean(context, left);
+ boolean rb = frb ? ((Boolean) right).booleanValue() :
+ _boolean(context, right);
+ return lb == rb;
+ }
+ /*
+ * Otherwise, if at least one object to be compared is
+ * a number, then each object to be compared is converted to a number as
+ * if by applying the number function.
+ */
+ if (fln || frn)
+ {
+ double ln = fln ? ((Double) left).doubleValue() :
+ _number(context, left);
+ double rn = frn ? ((Double) right).doubleValue() :
+ _number(context, right);
+ return ln == rn;
+ }
+ /*
+ * Otherwise, both objects to be
+ * compared are converted to strings as if by applying the string
+ * function.
+ */
+ String ls = fls ? (String) left : _string(context, left);
+ String rs = frs ? (String) right : _string(context, right);
+ return ls.equals(rs);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new EqualityExpr(lhs.clone(context), rhs.clone(context), invert);
+ }
+
+ public boolean references(QName var)
+ {
+ return (lhs.references(var) || rhs.references(var));
+ }
+
+ public String toString()
+ {
+ if (invert)
+ {
+ return lhs + " != " + rhs;
+ }
+ else
+ {
+ return lhs + " = " + rhs;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Expr.java b/libjava/classpath/gnu/xml/xpath/Expr.java
new file mode 100644
index 0000000..b4b55dc
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Expr.java
@@ -0,0 +1,476 @@
+/* Expr.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.StringTokenizer;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * An XPath expression.
+ * This can be evaluated in the context of a node to produce a result.
+ *
+ * @author Chris Burdess
+ */
+public abstract class Expr
+ implements XPathExpression
+{
+
+ protected static final Comparator documentOrderComparator =
+ new DocumentOrderComparator();
+
+ protected static final DecimalFormat decimalFormat =
+ new DecimalFormat("####################################################" +
+ ".####################################################",
+ new DecimalFormatSymbols(Locale.US));
+
+ public Object evaluate(Object item, QName returnType)
+ throws XPathExpressionException
+ {
+ Object ret = null;
+ Node context = null;
+ if (item instanceof Node)
+ {
+ context = (Node) item;
+ ret = evaluate(context, 1, 1);
+ if (XPathConstants.STRING == returnType &&
+ !(ret instanceof String))
+ {
+ ret = _string(context, ret);
+ }
+ else if (XPathConstants.NUMBER == returnType &&
+ !(ret instanceof Double))
+ {
+ ret = new Double(_number(context, ret));
+ }
+ else if (XPathConstants.BOOLEAN == returnType &&
+ !(ret instanceof Boolean))
+ {
+ ret = _boolean(context, ret) ? Boolean.TRUE : Boolean.FALSE;
+ }
+ else if (XPathConstants.NODE == returnType)
+ {
+ if (ret instanceof Collection)
+ {
+ Collection ns = (Collection) ret;
+ switch (ns.size())
+ {
+ case 0:
+ ret = null;
+ break;
+ case 1:
+ ret = (Node) ns.iterator().next();
+ break;
+ default:
+ throw new XPathExpressionException("multiple nodes in node-set");
+ }
+ }
+ else if (ret != null)
+ {
+ throw new XPathExpressionException("return value is not a node-set");
+ }
+ }
+ else if (XPathConstants.NODESET == returnType)
+ {
+ if (ret != null && !(ret instanceof Collection))
+ {
+ throw new XPathExpressionException("return value is not a node-set");
+ }
+ }
+ }
+ return ret;
+ }
+
+ public String evaluate(Object item)
+ throws XPathExpressionException
+ {
+ return (String) evaluate(item, XPathConstants.STRING);
+ }
+
+ public Object evaluate(InputSource source, QName returnType)
+ throws XPathExpressionException
+ {
+ try
+ {
+ DocumentBuilderFactory factory =
+ new gnu.xml.dom.JAXPFactory();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document doc = builder.parse(source);
+ return evaluate(doc, returnType);
+ }
+ catch (ParserConfigurationException e)
+ {
+ throw new XPathExpressionException(e);
+ }
+ catch (SAXException e)
+ {
+ throw new XPathExpressionException(e);
+ }
+ catch (IOException e)
+ {
+ throw new XPathExpressionException(e);
+ }
+ }
+
+ public String evaluate(InputSource source)
+ throws XPathExpressionException
+ {
+ return (String) evaluate(source, XPathConstants.STRING);
+ }
+
+ public abstract Object evaluate(Node context, int pos, int len);
+
+ public abstract Expr clone(Object context);
+
+ public abstract boolean references(QName var);
+
+ /* -- 4.1 Node Set Functions -- */
+
+ /**
+ * The id function selects elements by their unique ID.
+ * When the argument to id is of type node-set, then the result is
+ * the union of the result of applying id to the string-value of each of
+ * the nodes in the argument node-set. When the argument to id is of any
+ * other type, the argument is converted to a string as if by a call to
+ * the string function; the string is split into a whitespace-separated
+ * list of tokens (whitespace is any sequence of characters matching the
+ * production S); the result is a node-set containing the elements in the
+ * same document as the context node that have a unique ID equal to any of
+ * the tokens in the list.
+ */
+ public static Collection _id(Node context, Object object)
+ {
+ Set ret = new HashSet();
+ if (object instanceof Collection)
+ {
+ Collection nodeSet = (Collection) object;
+ for (Iterator i = nodeSet.iterator(); i.hasNext(); )
+ {
+ String string = stringValue((Node) i.next());
+ ret.addAll(_id (context, string));
+ }
+ }
+ else
+ {
+ Document doc = (context instanceof Document) ? (Document) context :
+ context.getOwnerDocument();
+ String string = _string(context, object);
+ StringTokenizer st = new StringTokenizer(string, " \t\r\n");
+ while (st.hasMoreTokens())
+ {
+ Node element = doc.getElementById(st.nextToken());
+ if (element != null)
+ {
+ ret.add(element);
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * The local-name function returns the local part of the expanded-name of
+ * the node in the argument node-set that is first in document order. If
+ * the argument node-set is empty or the first node has no expanded-name,
+ * an empty string is returned. If the argument is omitted, it defaults to
+ * a node-set with the context node as its only member.
+ */
+ public static String _local_name(Node context, Collection nodeSet)
+ {
+ Node node = (nodeSet == null || nodeSet.size() == 0) ? context :
+ firstNode(nodeSet);
+ return node.getLocalName();
+ }
+
+ /**
+ * The namespace-uri function returns the namespace URI of the
+ * expanded-name of the node in the argument node-set that is first in
+ * document order. If the argument node-set is empty, the first node has
+ * no expanded-name, or the namespace URI of the expanded-name is null, an
+ * empty string is returned. If the argument is omitted, it defaults to a
+ * node-set with the context node as its only member.
+ */
+ public static String _namespace_uri(Node context, Collection nodeSet)
+ {
+ Node node = (nodeSet == null || nodeSet.size() == 0) ? context :
+ firstNode(nodeSet);
+ return node.getNamespaceURI();
+ }
+
+ /**
+ * The name function returns a string containing a QName representing the
+ * expanded-name of the node in the argument node-set that is first in
+ * document order. The QName must represent the expanded-name with respect
+ * to the namespace declarations in effect on the node whose expanded-name
+ * is being represented. Typically, this will be the QName that occurred
+ * in the XML source. This need not be the case if there are namespace
+ * declarations in effect on the node that associate multiple prefixes
+ * with the same namespace. However, an implementation may include
+ * information about the original prefix in its representation of nodes;
+ * in this case, an implementation can ensure that the returned string is
+ * always the same as the QName used in the XML source. If the argument
+ * node-set is empty or the first node has no expanded-name, an empty
+ * string is returned. If the argument it omitted, it defaults to a
+ * node-set with the context node as its only member.
+ */
+ public static String _name(Node context, Collection nodeSet)
+ {
+ Node node = (nodeSet == null || nodeSet.size() == 0) ? context :
+ firstNode(nodeSet);
+ switch (node.getNodeType())
+ {
+ case Node.ATTRIBUTE_NODE:
+ case Node.ELEMENT_NODE:
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ return node.getNodeName();
+ default:
+ return "";
+ }
+ }
+
+ /**
+ * Returns the first node in the set in document order.
+ */
+ static Node firstNode(Collection nodeSet)
+ {
+ List list = new ArrayList(nodeSet);
+ Collections.sort(list, documentOrderComparator);
+ return (Node) list.get(0);
+ }
+
+ /* -- 4.2 String Functions -- */
+
+ /**
+ * Implementation of the XPath string
function.
+ */
+ public static String _string(Node context, Object object)
+ {
+ if (object == null)
+ {
+ return stringValue(context);
+ }
+ if (object instanceof String)
+ {
+ return (String) object;
+ }
+ if (object instanceof Boolean)
+ {
+ return object.toString();
+ }
+ if (object instanceof Double)
+ {
+ double d = ((Double) object).doubleValue();
+ if (Double.isNaN(d))
+ {
+ return "NaN";
+ }
+ else if (d == 0.0d)
+ {
+ return "0";
+ }
+ else if (Double.isInfinite(d))
+ {
+ if (d < 0)
+ {
+ return "-Infinity";
+ }
+ else
+ {
+ return "Infinity";
+ }
+ }
+ else
+ {
+ String ret = decimalFormat.format(d);
+ if (ret.endsWith (".0"))
+ {
+ ret = ret.substring(0, ret.length() - 2);
+ }
+ return ret;
+ }
+ }
+ if (object instanceof Collection)
+ {
+ Collection nodeSet = (Collection) object;
+ if (nodeSet.isEmpty())
+ {
+ return "";
+ }
+ Node node = firstNode(nodeSet);
+ return stringValue(node);
+ }
+ throw new IllegalArgumentException(object.toString());
+ }
+
+ /* -- 4.3 Boolean Functions -- */
+
+ /**
+ * Implementation of the XPath boolean
function.
+ */
+ public static boolean _boolean(Node context, Object object)
+ {
+ if (object instanceof Boolean)
+ {
+ return ((Boolean) object).booleanValue();
+ }
+ if (object instanceof Double)
+ {
+ return ((Double) object).doubleValue() != 0.0;
+ }
+ if (object instanceof String)
+ {
+ return ((String) object).length() != 0;
+ }
+ if (object instanceof Collection)
+ {
+ return ((Collection) object).size() != 0;
+ }
+ return false; // TODO user defined types
+ }
+
+ /* -- 4.4 Number Functions -- */
+
+ /**
+ * Implementation of the XPath number
function.
+ */
+ public static double _number(Node context, Object object)
+ {
+ if (object == null)
+ {
+ object = Collections.singleton(context);
+ }
+ if (object instanceof Double)
+ {
+ return ((Double) object).doubleValue();
+ }
+ if (object instanceof Boolean)
+ {
+ return ((Boolean) object).booleanValue() ? 1.0 : 0.0;
+ }
+ if (object instanceof Collection)
+ {
+ // Convert node-set to string
+ object = stringValue((Collection) object);
+ }
+ if (object instanceof String)
+ {
+ String string = ((String) object).trim();
+ try
+ {
+ return Double.parseDouble(string);
+ }
+ catch (NumberFormatException e)
+ {
+ return Double.NaN;
+ }
+ }
+ return Double.NaN; // TODO user-defined types
+ }
+
+ /**
+ * Computes the XPath string-value of the specified node-set.
+ */
+ public static String stringValue(Collection nodeSet)
+ {
+ StringBuffer buf = new StringBuffer();
+ for (Iterator i = nodeSet.iterator(); i.hasNext(); )
+ {
+ buf.append(stringValue((Node) i.next()));
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Computes the XPath string-value of the specified node.
+ */
+ public static String stringValue(Node node)
+ {
+ return stringValue(node, false);
+ }
+
+ static String stringValue(Node node, boolean elementMode)
+ {
+ switch (node.getNodeType())
+ {
+ case Node.DOCUMENT_NODE: // 5.1 Root Node
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ case Node.ELEMENT_NODE: // 5.2 Element Nodes
+ StringBuffer buf = new StringBuffer();
+ for (Node ctx = node.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ buf.append(stringValue(ctx, true));
+ }
+ return buf.toString();
+ case Node.TEXT_NODE: // 5.7 Text Nodes
+ case Node.CDATA_SECTION_NODE:
+ return node.getNodeValue();
+ case Node.ATTRIBUTE_NODE: // 5.3 Attribute Nodes
+ case Node.PROCESSING_INSTRUCTION_NODE: // 5.5 Processing Instruction
+ case Node.COMMENT_NODE: // 5.6 Comment Nodes
+ if (!elementMode)
+ {
+ return node.getNodeValue();
+ }
+ default:
+ return "";
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/FalseFunction.java b/libjava/classpath/gnu/xml/xpath/FalseFunction.java
new file mode 100644
index 0000000..87660ec
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/FalseFunction.java
@@ -0,0 +1,72 @@
+/* FalseFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The false
function returns false.
+ *
+ * @author Chris Burdess
+ */
+final class FalseFunction
+ extends Expr
+{
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new FalseFunction();
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "false()";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/FloorFunction.java b/libjava/classpath/gnu/xml/xpath/FloorFunction.java
new file mode 100644
index 0000000..c03c0e7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/FloorFunction.java
@@ -0,0 +1,89 @@
+/* FloorFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The floor
function returns the largest (closest to positive
+ * infinity) number that is not greater than the argument and that is an
+ * integer.
+ *
+ * @author Chris Burdess
+ */
+final class FloorFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ FloorFunction(List args)
+ {
+ this((Expr) args.get(0));
+ }
+
+ FloorFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ double n = _number(context, val);
+ return new Double(Math.floor(n));
+ }
+
+ public Expr clone(Object context)
+ {
+ return new FloorFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "floor(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Function.java b/libjava/classpath/gnu/xml/xpath/Function.java
new file mode 100644
index 0000000..aecd49d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Function.java
@@ -0,0 +1,57 @@
+/* Function.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+
+/**
+ * Interface to be implemented by external functions that need to receive
+ * parameter values.
+ *
+ * @author Chris Burdess
+ */
+public interface Function
+{
+
+ /**
+ * Sets the list of expressions to evaluate as parameter values.
+ */
+ void setArguments(List args);
+
+}
+
diff --git a/libjava/classpath/gnu/xml/xpath/FunctionCall.java b/libjava/classpath/gnu/xml/xpath/FunctionCall.java
new file mode 100644
index 0000000..669efbf
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/FunctionCall.java
@@ -0,0 +1,163 @@
+/* FunctionCall.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+import javax.xml.xpath.XPathFunctionResolver;
+import org.w3c.dom.Node;
+
+/**
+ * Executes an XPath core or extension function.
+ *
+ * @author Chris Burdess
+ */
+public final class FunctionCall
+ extends Expr
+{
+
+ final XPathFunctionResolver resolver;
+ final String name;
+ final List args;
+
+ public FunctionCall(XPathFunctionResolver resolver, String name)
+ {
+ this(resolver, name, Collections.EMPTY_LIST);
+ }
+
+ public FunctionCall(XPathFunctionResolver resolver, String name, List args)
+ {
+ this.resolver = resolver;
+ this.name = name;
+ this.args = args;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ if (resolver != null)
+ {
+ QName qname = QName.valueOf(name);
+ int arity = args.size();
+ XPathFunction function = resolver.resolveFunction(qname, arity);
+ if (function != null)
+ {
+ //System.err.println("Calling "+toString()+" with "+values);
+ if (function instanceof Expr)
+ {
+ if (function instanceof Function)
+ {
+ ((Function) function).setArguments(args);
+ }
+ return ((Expr) function).evaluate(context, pos, len);
+ }
+ else
+ {
+ List values = new ArrayList(arity);
+ for (int i = 0; i < arity; i++)
+ {
+ Expr arg = (Expr) args.get(i);
+ values.add(arg.evaluate(context, pos, len));
+ }
+ try
+ {
+ return function.evaluate(values);
+ }
+ catch (XPathFunctionException e)
+ {
+ e.printStackTrace(System.err); // FIXME
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ throw new IllegalArgumentException("Invalid function call: " +
+ toString());
+ }
+
+ public Expr clone(Object context)
+ {
+ int len = args.size();
+ List args2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(((Expr) args.get(i)).clone(context));
+ }
+ XPathFunctionResolver r = resolver;
+ if (context instanceof XPathFunctionResolver)
+ {
+ r = (XPathFunctionResolver) context;
+ }
+ return new FunctionCall(r, name, args2);
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator i = args.iterator(); i.hasNext(); )
+ {
+ if (((Expr) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append(name);
+ buf.append('(');
+ int len = args.size();
+ for (int i = 0; i < len; i++)
+ {
+ if (i > 0)
+ {
+ buf.append(',');
+ }
+ buf.append(args.get(i));
+ }
+ buf.append(')');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/IdFunction.java b/libjava/classpath/gnu/xml/xpath/IdFunction.java
new file mode 100644
index 0000000..7497954
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/IdFunction.java
@@ -0,0 +1,102 @@
+/* IdFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.Collection;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The id
function selects elements by their unique ID.
+ * When the argument to id is of type node-set, then the result is
+ * the union of the result of applying id to the string-value of each of the
+ * nodes in the argument node-set. When the argument to id is of any other
+ * type, the argument is converted to a string as if by a call to the string
+ * function; the string is split into a whitespace-separated list of tokens
+ * (whitespace is any sequence of characters matching the production S); the
+ * result is a node-set containing the elements in the same document as the
+ * context node that have a unique ID equal to any of the tokens in the
+ * list.
+ *
+ * @author Chris Burdess
+ */
+public final class IdFunction
+ extends Pattern
+{
+
+ final Expr arg;
+
+ IdFunction(List args)
+ {
+ this((Expr) args.get(0));
+ }
+
+ public IdFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public boolean matches(Node context)
+ {
+ Object ret = evaluate(context, 1, 1);
+ return !((Collection) ret).isEmpty();
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ return _id(context, val);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new IdFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "id(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/LangFunction.java b/libjava/classpath/gnu/xml/xpath/LangFunction.java
new file mode 100644
index 0000000..2c2506d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/LangFunction.java
@@ -0,0 +1,116 @@
+/* LangFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * The lang
function returns true or false depending on whether
+ * the language of the context node as specified by xml:lang attributes is
+ * the same as or is a sublanguage of the language specified by the argument
+ * string. The language of the context node is determined by the value of
+ * the xml:lang attribute on the context node, or, if the context node has
+ * no xml:lang attribute, by the value of the xml:lang attribute on the
+ * nearest ancestor of the context node that has an xml:lang attribute. If
+ * there is no such attribute, then lang returns false. If there is such an
+ * attribute, then lang returns true if the attribute value is equal to the
+ * argument ignoring case, or if there is some suffix starting with - such
+ * that the attribute value is equal to the argument ignoring that suffix of
+ * the attribute value and ignoring case.
+ *
+ * @author Chris Burdess
+ */
+final class LangFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ LangFunction(List args)
+ {
+ this((Expr) args.get(0));
+ }
+
+ LangFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ String lang = _string(context, val);
+ String clang = getLang(context);
+ while (clang == null && context != null)
+ {
+ context = context.getParentNode();
+ clang = getLang(context);
+ }
+ boolean ret = (clang == null) ? false :
+ clang.toLowerCase().startsWith(lang.toLowerCase());
+ return ret ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ String getLang(Node node)
+ {
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ return ((Element) node).getAttribute("xml:lang");
+ }
+ return null;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new IdFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "lang(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/LastFunction.java b/libjava/classpath/gnu/xml/xpath/LastFunction.java
new file mode 100644
index 0000000..751a0a9
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/LastFunction.java
@@ -0,0 +1,73 @@
+/* LastFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The last
function returns a number equal to the context
+ * size from the expression evaluation context.
+ *
+ * @author Chris Burdess
+ */
+final class LastFunction
+ extends Expr
+{
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return new Double((double) len);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new LastFunction();
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "last()";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/LocalNameFunction.java b/libjava/classpath/gnu/xml/xpath/LocalNameFunction.java
new file mode 100644
index 0000000..f8ace9c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/LocalNameFunction.java
@@ -0,0 +1,93 @@
+/* LocalNameFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.Collection;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The local-name
function returns the local part of the
+ * expanded-name of the node in the argument node-set that is first in
+ * document order.
+ * If the argument node-set is empty or the first node has no expanded-name,
+ * an empty string is returned. If the argument is omitted, it defaults to a
+ * node-set with the context node as its only member.
+ *
+ * @author Chris Burdess
+ */
+final class LocalNameFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ LocalNameFunction(List args)
+ {
+ this(args.size() > 0 ? (Expr) args.get(0) : null);
+ }
+
+ LocalNameFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ return _local_name(context, (Collection) val);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new LocalNameFunction((arg == null) ? null :
+ arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ public String toString()
+ {
+ return (arg == null) ? "local-name()" : "local-name(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NameFunction.java b/libjava/classpath/gnu/xml/xpath/NameFunction.java
new file mode 100644
index 0000000..dc5e612
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NameFunction.java
@@ -0,0 +1,101 @@
+/* NameFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.Collection;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The name
function returns a string containing a QName
+ * representing the expanded-name of the node in the argument node-set that
+ * is first in document order. The QName must represent the expanded-name
+ * with respect to the namespace declarations in effect on the node whose
+ * expanded-name is being represented. Typically, this will be the QName
+ * that occurred in the XML source. This need not be the case if there are
+ * namespace declarations in effect on the node that associate multiple
+ * prefixes with the same namespace. However, an implementation may include
+ * information about the original prefix in its representation of nodes; in
+ * this case, an implementation can ensure that the returned string is
+ * always the same as the QName used in the XML source. If the argument
+ * node-set is empty or the first node has no expanded-name, an empty string
+ * is returned. If the argument it omitted, it defaults to a node-set with
+ * the context node as its only member.
+ *
+ * @author Chris Burdess
+ */
+final class NameFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ NameFunction(List args)
+ {
+ this(args.size() > 0 ? (Expr) args.get(0) : null);
+ }
+
+ NameFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ return _name(context, (Collection) val);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new NameFunction((arg == null) ? null :
+ arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ public String toString()
+ {
+ return (arg == null) ? "name()" : "name(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NameTest.java b/libjava/classpath/gnu/xml/xpath/NameTest.java
new file mode 100644
index 0000000..c89ba4d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NameTest.java
@@ -0,0 +1,142 @@
+/* NameTest.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Tests whether a node has the specified name.
+ *
+ * @author Chris Burdess
+ */
+public final class NameTest
+ extends Test
+{
+
+ final QName qName;
+ final boolean anyLocalName;
+ final boolean any;
+
+ public NameTest(QName qName, boolean anyLocalName, boolean any)
+ {
+ this.anyLocalName = anyLocalName;
+ this.any = any;
+ this.qName = qName;
+ }
+
+ public boolean matchesAny()
+ {
+ return any;
+ }
+
+ public boolean matchesAnyLocalName()
+ {
+ return anyLocalName;
+ }
+
+ public boolean matches(Node node, int pos, int len)
+ {
+ switch (node.getNodeType())
+ {
+ case Node.ATTRIBUTE_NODE:
+ // Do not match namespace attributes
+ String uri = node.getNamespaceURI();
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getPrefix()) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getNodeName()))
+ {
+ return false;
+ }
+ // Fall through
+ case Node.ELEMENT_NODE:
+ break;
+ default:
+ return false;
+ }
+ if (any)
+ {
+ return true;
+ }
+ String uri = qName.getNamespaceURI();
+ String nodeUri = node.getNamespaceURI();
+ String nodeLocalName = node.getLocalName();
+ if (nodeLocalName != null && !equal(uri, nodeUri))
+ {
+ return false;
+ }
+ if (anyLocalName)
+ {
+ return true;
+ }
+ String localName = qName.getLocalPart();
+ if (nodeLocalName != null)
+ {
+ nodeLocalName = node.getNodeName();
+ }
+ return (localName.equals(nodeLocalName));
+ }
+
+ final boolean equal(String s1, String s2)
+ {
+ return (((s1 == null || s1.length() == 0) &&
+ (s2 == null || s2.length() == 0)) ||
+ s1 != null && s1.equals(s2));
+ }
+
+ public Test clone(Object context)
+ {
+ return new NameTest(qName, anyLocalName, any);
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString ()
+ {
+ if (any)
+ {
+ return "*";
+ }
+ return qName.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NamespaceTest.java b/libjava/classpath/gnu/xml/xpath/NamespaceTest.java
new file mode 100644
index 0000000..6d41166
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NamespaceTest.java
@@ -0,0 +1,128 @@
+/* NamespaceTest.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Tests whether a namespace attribute has the specified name.
+ *
+ * @author Chris Burdess
+ */
+public final class NamespaceTest
+ extends Test
+{
+
+ final QName qName;
+ final boolean anyLocalName;
+ final boolean any;
+
+ public NamespaceTest(QName qName, boolean anyLocalName, boolean any)
+ {
+ this.anyLocalName = anyLocalName;
+ this.any = any;
+ this.qName = qName;
+ }
+
+ public boolean matchesAny()
+ {
+ return any;
+ }
+
+ public boolean matchesAnyLocalName()
+ {
+ return anyLocalName;
+ }
+
+ public boolean matches(Node node, int pos, int len)
+ {
+ switch (node.getNodeType())
+ {
+ case Node.ATTRIBUTE_NODE:
+ // Only match namespace attributes
+ String uri = node.getNamespaceURI();
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getPrefix()) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getNodeName()))
+ {
+ break;
+ }
+ // Fall through
+ default:
+ // Only process namespace attributes
+ return false;
+ }
+ if (any)
+ {
+ return true;
+ }
+ if (anyLocalName)
+ {
+ return true;
+ }
+ String localName = qName.getLocalPart();
+ String nodeLocalName = node.getLocalName();
+ if (nodeLocalName == null)
+ {
+ nodeLocalName = node.getNodeName();
+ }
+ return (localName.equals(nodeLocalName));
+ }
+
+ public Test clone(Object context)
+ {
+ return new NamespaceTest(qName, anyLocalName, any);
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString ()
+ {
+ if (any)
+ {
+ return "*";
+ }
+ return qName.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java b/libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java
new file mode 100644
index 0000000..e67ec42
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java
@@ -0,0 +1,93 @@
+/* NamespaceUriFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.Collection;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The namespace-uri
function returns the namespace URI of the
+ * expanded-name of the node in the argument node-set that is first in
+ * document order. If the argument node-set is empty, the first node has no
+ * expanded-name, or the namespace URI of the expanded-name is null, an
+ * empty string is returned. If the argument is omitted, it defaults to a
+ * node-set with the context node as its only member.
+ *
+ * @author Chris Burdess
+ */
+final class NamespaceUriFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ NamespaceUriFunction(List args)
+ {
+ this(args.size() > 0 ? (Expr) args.get(0) : null);
+ }
+
+ NamespaceUriFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ return _namespace_uri(context, (Collection) val);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new NamespaceUriFunction((arg == null) ? null :
+ arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ public String toString()
+ {
+ return (arg == null) ? "namespace-uri()" : "namespace-uri(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NegativeExpr.java b/libjava/classpath/gnu/xml/xpath/NegativeExpr.java
new file mode 100644
index 0000000..9e24aff
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NegativeExpr.java
@@ -0,0 +1,81 @@
+/* NegativeExpr.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Unary negative.
+ *
+ * @author Chris Burdess
+ */
+final class NegativeExpr
+ extends Expr
+{
+
+ final Expr expr;
+
+ NegativeExpr(Expr expr)
+ {
+ this.expr = expr;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = expr.evaluate(context, pos, len);
+ double n = _number(context, val);
+ return new Double(-n);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new NegativeExpr(expr.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return expr.references(var);
+ }
+
+ public String toString()
+ {
+ return "-" + expr;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NodeTypeTest.java b/libjava/classpath/gnu/xml/xpath/NodeTypeTest.java
new file mode 100644
index 0000000..8073741
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NodeTypeTest.java
@@ -0,0 +1,136 @@
+/* NodeTypeTest.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Tests whether a node is of a given type.
+ *
+ * @author Chris Burdess
+ */
+public final class NodeTypeTest
+ extends Test
+{
+
+ final short type;
+ final String data;
+
+ public NodeTypeTest(short type)
+ {
+ this(type, null);
+ }
+
+ public NodeTypeTest(short type, String data)
+ {
+ this.type = type;
+ this.data = data;
+ }
+
+ public short getNodeType()
+ {
+ return type;
+ }
+
+ public String getData()
+ {
+ return data;
+ }
+
+ public boolean matches(Node node, int pos, int len)
+ {
+ short nodeType = node.getNodeType();
+ switch (nodeType)
+ {
+ case Node.ELEMENT_NODE:
+ case Node.ATTRIBUTE_NODE:
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ case Node.COMMENT_NODE:
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ if (type > 0)
+ {
+ if (nodeType != type)
+ {
+ return false;
+ }
+ if (data != null && !data.equals(node.getNodeValue()))
+ {
+ return false;
+ }
+ }
+ return true;
+ default:
+ // Not part of XPath data model
+ return false;
+ }
+ }
+
+ public Test clone(Object context)
+ {
+ return new NodeTypeTest(type, data);
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ switch (type)
+ {
+ case 0:
+ return "node()";
+ case Node.TEXT_NODE:
+ return "text()";
+ case Node.COMMENT_NODE:
+ return "comment()";
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ if (data != null)
+ {
+ return "processing-instruction('" + data + "')";
+ }
+ return "processing-instruction()";
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NormalizeSpaceFunction.java b/libjava/classpath/gnu/xml/xpath/NormalizeSpaceFunction.java
new file mode 100644
index 0000000..b7358e8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NormalizeSpaceFunction.java
@@ -0,0 +1,105 @@
+/* NormalizeSpaceFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import java.util.StringTokenizer;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The normalize-space
function returns the argument string
+ * with whitespace normalized by stripping leading and trailing whitespace
+ * and replacing sequences of whitespace characters by a single space.
+ * Whitespace characters are the same as those allowed by the S production
+ * in XML. If the argument is omitted, it defaults to the context node
+ * converted to a string, in other words the string-value of the context
+ * node.
+ *
+ * @author Chris Burdess
+ */
+final class NormalizeSpaceFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ NormalizeSpaceFunction(List args)
+ {
+ this((Expr) args.get(0));
+ }
+
+ NormalizeSpaceFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ String s = _string(context, val);
+ StringTokenizer st = new StringTokenizer(s, " \t\r\n");
+ StringBuffer buf = new StringBuffer();
+ if (st.hasMoreTokens())
+ {
+ buf.append(st.nextToken());
+ while (st.hasMoreTokens())
+ {
+ buf.append(' ');
+ buf.append(st.nextToken());
+ }
+ }
+ return buf.toString();
+ }
+
+ public Expr clone(Object context)
+ {
+ return new NormalizeSpaceFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ public String toString()
+ {
+ return (arg == null) ? "normalize-space()" : "normalize-space(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NotFunction.java b/libjava/classpath/gnu/xml/xpath/NotFunction.java
new file mode 100644
index 0000000..bbed66a
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NotFunction.java
@@ -0,0 +1,87 @@
+/* NotFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The not
function returns true if its argument is false,
+ * and false otherwise.
+ *
+ * @author Chris Burdess
+ */
+final class NotFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ NotFunction(List args)
+ {
+ this((Expr) args.get(0));
+ }
+
+ NotFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ return _boolean(context, val) ? Boolean.FALSE : Boolean.TRUE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new NotFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "not(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NumberFunction.java b/libjava/classpath/gnu/xml/xpath/NumberFunction.java
new file mode 100644
index 0000000..79553ce
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NumberFunction.java
@@ -0,0 +1,102 @@
+/* NumberFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The number
function converts its argument to a number as
+ * follows:
+ *
+ *
+ * If the argument is omitted, it defaults to a node-set with the context
+ * node as its only member.
+ *
+ * @author Chris Burdess
+ */
+final class NumberFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ NumberFunction(List args)
+ {
+ this(args.size() > 0 ? (Expr) args.get(0) : null);
+ }
+
+ NumberFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ return new Double(_number(context, val));
+ }
+
+ public Expr clone(Object context)
+ {
+ return new NumberFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "number(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/OrExpr.java b/libjava/classpath/gnu/xml/xpath/OrExpr.java
new file mode 100644
index 0000000..1085f51
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/OrExpr.java
@@ -0,0 +1,87 @@
+/* OrExpr.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Logical or.
+ *
+ * @author Chris Burdess
+ */
+public final class OrExpr
+ extends Expr
+{
+
+ final Expr lhs;
+ final Expr rhs;
+
+ public OrExpr(Expr lhs, Expr rhs)
+ {
+ this.lhs = lhs;
+ this.rhs = rhs;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object left = lhs.evaluate(context, pos, len);
+ if (_boolean(context, left))
+ {
+ return Boolean.TRUE;
+ }
+ Object right = rhs.evaluate(context, pos, len);
+ return _boolean(context, right) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new OrExpr(lhs.clone(context), rhs.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (lhs.references(var) || rhs.references(var));
+ }
+
+ public String toString()
+ {
+ return lhs + " or " + rhs;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/ParenthesizedExpr.java b/libjava/classpath/gnu/xml/xpath/ParenthesizedExpr.java
new file mode 100644
index 0000000..f343857
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/ParenthesizedExpr.java
@@ -0,0 +1,90 @@
+/* ParenthesizedExpr.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Simple subexpression.
+ *
+ * @author Chris Burdess
+ */
+final class ParenthesizedExpr
+ extends Expr
+{
+
+ final Expr expr;
+
+ ParenthesizedExpr(Expr expr)
+ {
+ this.expr = expr;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object ret = expr.evaluate(context, pos, len);
+ if (ret instanceof Collection)
+ {
+ List list = new ArrayList((Collection) ret);
+ Collections.sort(list, documentOrderComparator);
+ ret = list;
+ }
+ return ret;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new ParenthesizedExpr(expr.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return expr.references(var);
+ }
+
+ public String toString()
+ {
+ return "(" + expr + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Path.java b/libjava/classpath/gnu/xml/xpath/Path.java
new file mode 100644
index 0000000..4b01f09
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Path.java
@@ -0,0 +1,54 @@
+/* Path.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.Collection;
+import org.w3c.dom.Node;
+
+/**
+ * An XPath path component expression.
+ *
+ * @author Chris Burdess
+ */
+abstract class Path
+ extends Pattern
+{
+
+ abstract Collection evaluate(Node context, Collection nodeSet);
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Pattern.java b/libjava/classpath/gnu/xml/xpath/Pattern.java
new file mode 100644
index 0000000..859ab56
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Pattern.java
@@ -0,0 +1,54 @@
+/* Pattern.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import org.w3c.dom.Node;
+
+/**
+ * Interface implemented by expressions that can form part of XSL patterns.
+ *
+ * @author Chris Burdess
+ */
+public abstract class Pattern
+ extends Expr
+{
+
+ public abstract boolean matches(Node context);
+
+}
+
diff --git a/libjava/classpath/gnu/xml/xpath/PositionFunction.java b/libjava/classpath/gnu/xml/xpath/PositionFunction.java
new file mode 100644
index 0000000..3060eea
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/PositionFunction.java
@@ -0,0 +1,73 @@
+/* PositionFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The position
function returns a number equal to the context
+ * position from the expression evaluation context.
+ *
+ * @author Chris Burdess
+ */
+final class PositionFunction
+ extends Expr
+{
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return new Double((double) pos);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new PositionFunction();
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "position()";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Predicate.java b/libjava/classpath/gnu/xml/xpath/Predicate.java
new file mode 100644
index 0000000..5538c55
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Predicate.java
@@ -0,0 +1,85 @@
+/* Predicate.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Tests whether an expression matches against a given context node.
+ *
+ * @author Chris Burdess
+ */
+class Predicate
+ extends Test
+{
+
+ final Expr expr;
+
+ Predicate(Expr expr)
+ {
+ this.expr = expr;
+ }
+
+ public boolean matches(Node node, int pos, int len)
+ {
+ Object ret = expr.evaluate(node, pos, len);
+ if (ret instanceof Double)
+ {
+ // Same as [position() = x]
+ return ((Double) ret).intValue() == pos;
+ }
+ return Expr._boolean(node, expr.evaluate(node, pos, len));
+ }
+
+ public Test clone(Object context)
+ {
+ return new Predicate(expr.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return expr.references(var);
+ }
+
+ public String toString()
+ {
+ return "[" + expr + "]";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/RelationalExpr.java b/libjava/classpath/gnu/xml/xpath/RelationalExpr.java
new file mode 100644
index 0000000..5cbb6bb
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/RelationalExpr.java
@@ -0,0 +1,107 @@
+/* RelationalExpr.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Numerical comparison expression.
+ *
+ * @author Chris Burdess
+ */
+final class RelationalExpr
+ extends Expr
+{
+
+ final Expr lhs;
+ final Expr rhs;
+ final boolean lt;
+ final boolean eq;
+
+ RelationalExpr(Expr lhs, Expr rhs, boolean lt, boolean eq)
+ {
+ this.lhs = lhs;
+ this.rhs = rhs;
+ this.lt = lt;
+ this.eq = eq;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object left = lhs.evaluate(context, pos, len);
+ Object right = rhs.evaluate(context, pos, len);
+ double ln = _number(context, left);
+ double rn = _number(context, right);
+ if (eq && ln == rn)
+ {
+ return Boolean.TRUE;
+ }
+ if (lt)
+ {
+ if (ln < rn || Double.isInfinite(rn))
+ {
+ return Boolean.TRUE;
+ }
+ }
+ else
+ {
+ if (ln > rn || Double.isInfinite(ln))
+ {
+ return Boolean.TRUE;
+ }
+ }
+ return Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new RelationalExpr(lhs.clone(context), rhs.clone(context), lt, eq);
+ }
+
+ public boolean references(QName var)
+ {
+ return (lhs.references(var) || rhs.references(var));
+ }
+
+ public String toString()
+ {
+ return lhs + " " + (lt ? "<" : ">") + (eq ? "=" : "") + " " + rhs;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Root.java b/libjava/classpath/gnu/xml/xpath/Root.java
new file mode 100644
index 0000000..1f79b39
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Root.java
@@ -0,0 +1,87 @@
+/* Root.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.Collection;
+import java.util.Collections;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/**
+ * Expression that evaluates to the document root.
+ *
+ * @author Chris Burdess
+ */
+public final class Root
+ extends Path
+{
+
+ public boolean matches(Node node)
+ {
+ return (node.getNodeType() == Node.DOCUMENT_NODE);
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return evaluate(context, Collections.EMPTY_SET);
+ }
+
+ Collection evaluate(Node context, Collection ns)
+ {
+ Document doc = (context instanceof Document) ? (Document) context :
+ context.getOwnerDocument();
+ return Collections.singleton(doc);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new Root();
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "/";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/RoundFunction.java b/libjava/classpath/gnu/xml/xpath/RoundFunction.java
new file mode 100644
index 0000000..bfbfd35
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/RoundFunction.java
@@ -0,0 +1,96 @@
+/* RoundFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The round
function returns the number that is closest to the
+ * argument and that is an integer. If there are two such numbers, then the
+ * one that is closest to positive infinity is returned. If the argument is
+ * NaN, then NaN is returned. If the argument is positive infinity, then
+ * positive infinity is returned. If the argument is negative infinity, then
+ * negative infinity is returned. If the argument is positive zero, then
+ * positive zero is returned. If the argument is negative zero, then
+ * negative zero is returned. If the argument is less than zero, but greater
+ * than or equal to -0.5, then negative zero is returned.
+ *
+ * @author Chris Burdess
+ */
+final class RoundFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ RoundFunction(List args)
+ {
+ this((Expr) args.get(0));
+ }
+
+ RoundFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ double n = _number(context, val);
+ return (Double.isNaN(n) || Double.isInfinite(n)) ?
+ new Double(n) : new Double(Math.round(n));
+ }
+
+ public Expr clone(Object context)
+ {
+ return new RoundFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "round(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Selector.java b/libjava/classpath/gnu/xml/xpath/Selector.java
new file mode 100644
index 0000000..5980380
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Selector.java
@@ -0,0 +1,519 @@
+/* Selector.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ * A single component of a location path.
+ *
+ * @author Chris Burdess
+ */
+public final class Selector
+ extends Path
+{
+
+ public static final int ANCESTOR = 0;
+ public static final int ANCESTOR_OR_SELF = 1;
+ public static final int ATTRIBUTE = 2;
+ public static final int CHILD = 3;
+ public static final int DESCENDANT = 4;
+ public static final int DESCENDANT_OR_SELF = 5;
+ public static final int FOLLOWING = 6;
+ public static final int FOLLOWING_SIBLING = 7;
+ public static final int NAMESPACE = 8;
+ public static final int PARENT = 9;
+ public static final int PRECEDING = 10;
+ public static final int PRECEDING_SIBLING = 11;
+ public static final int SELF = 12;
+
+ /**
+ * Axis to select nodes in.
+ */
+ final int axis;
+
+ /**
+ * List of tests to perform on candidates.
+ */
+ final Test[] tests;
+
+ public Selector(int axis, List tests)
+ {
+ this.axis = axis;
+ this.tests = new Test[tests.size()];
+ tests.toArray(this.tests);
+ if (axis == NAMESPACE &&
+ this.tests.length > 0 &&
+ this.tests[0] instanceof NameTest)
+ {
+ NameTest nt = (NameTest) this.tests[0];
+ this.tests[0] = new NamespaceTest(nt.qName, nt.anyLocalName, nt.any);
+ }
+ }
+
+ /**
+ * Returns the list of tests to perform on candidates.
+ */
+ public Test[] getTests()
+ {
+ return tests;
+ }
+
+ public boolean matches(Node context)
+ {
+ short nodeType = context.getNodeType();
+ switch (axis)
+ {
+ case CHILD:
+ if (nodeType == Node.ATTRIBUTE_NODE)
+ {
+ return false;
+ }
+ break;
+ case ATTRIBUTE:
+ case NAMESPACE:
+ if (nodeType != Node.ATTRIBUTE_NODE)
+ {
+ return false;
+ }
+ break;
+ case DESCENDANT_OR_SELF:
+ return true;
+ default:
+ return false;
+ }
+ int tlen = tests.length;
+ if (tlen > 0)
+ {
+ int pos = getContextPosition(context);
+ int len = getContextSize(context);
+ for (int j = 0; j < tlen && len > 0; j++)
+ {
+ Test test = tests[j];
+ if (!test.matches(context, pos, len))
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private int getContextPosition(Node ctx)
+ {
+ int pos = 1;
+ for (ctx = ctx.getPreviousSibling(); ctx != null;
+ ctx = ctx.getPreviousSibling())
+ {
+ pos++;
+ }
+ return pos;
+ }
+
+ private int getContextSize(Node ctx)
+ {
+ if (ctx.getNodeType() == Node.ATTRIBUTE_NODE)
+ {
+ Node parent = ((Attr) ctx).getOwnerElement();
+ return parent.getAttributes().getLength();
+ }
+ Node parent = ctx.getParentNode();
+ if (parent != null)
+ {
+ return parent.getChildNodes().getLength();
+ }
+ return 1;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Set acc = new LinkedHashSet();
+ addCandidates(context, acc);
+ List candidates = new ArrayList(acc);
+ //Collections.sort(candidates, documentOrderComparator);
+ List ret = filterCandidates(candidates, false);
+ return ret;
+ }
+
+ Collection evaluate(Node context, Collection ns)
+ {
+ Set acc = new LinkedHashSet();
+ for (Iterator i = ns.iterator(); i.hasNext(); )
+ {
+ addCandidates((Node) i.next(), acc);
+ }
+ List candidates = new ArrayList(acc);
+ //Collections.sort(candidates, documentOrderComparator);
+ List ret = filterCandidates(candidates, true);
+ return ret;
+ }
+
+ /**
+ * Filter the given list of candidates according to the node tests.
+ */
+ List filterCandidates(List candidates, boolean cascade)
+ {
+ int len = candidates.size();
+ int tlen = tests.length;
+ if (tlen > 0 && len > 0)
+ {
+ // Present the result of each successful generation to the next test
+ for (int j = 0; j < tlen && len > 0; j++)
+ {
+ Test test = tests[j];
+ List successful = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ Node node = (Node) candidates.get(i);
+ if (cascade)
+ {
+ // Documents and DocumentFragments should be considered
+ // if part of a location path where the axis involves
+ // the SELF concept
+ short nodeType = node.getNodeType();
+ if ((nodeType == Node.DOCUMENT_NODE ||
+ nodeType == Node.DOCUMENT_FRAGMENT_NODE) &&
+ (axis == DESCENDANT_OR_SELF ||
+ axis == ANCESTOR_OR_SELF ||
+ axis == SELF) &&
+ (tests.length == 1 &&
+ tests[0] instanceof NodeTypeTest &&
+ ((NodeTypeTest) tests[0]).type == (short) 0))
+ {
+ successful.add(node);
+ continue;
+ }
+ }
+ if (test.matches(node, i + 1, len))
+ {
+ successful.add(node);
+ }
+ /*
+ System.err.println("Testing "+node);
+ int p = getContextPosition(node);
+ int l = getContextSize(node);
+ if (test.matches(node, p, l))
+ {
+ successful.add(node);
+ }*/
+ }
+ candidates = successful;
+ len = candidates.size();
+ }
+ }
+ return candidates;
+ }
+
+ void addCandidates(Node context, Collection candidates)
+ {
+ // Build list of candidates
+ switch (axis)
+ {
+ case CHILD:
+ addChildNodes(context, candidates, false);
+ break;
+ case DESCENDANT:
+ addChildNodes(context, candidates, true);
+ break;
+ case DESCENDANT_OR_SELF:
+ candidates.add (context);
+ addChildNodes(context, candidates, true);
+ break;
+ case PARENT:
+ addParentNode(context, candidates, false);
+ break;
+ case ANCESTOR:
+ addParentNode(context, candidates, true);
+ break;
+ case ANCESTOR_OR_SELF:
+ candidates.add(context);
+ addParentNode(context, candidates, true);
+ break;
+ case FOLLOWING_SIBLING:
+ addFollowingNodes(context, candidates, false);
+ break;
+ case PRECEDING_SIBLING:
+ addPrecedingNodes(context, candidates, false);
+ break;
+ case FOLLOWING:
+ addFollowingNodes(context, candidates, true);
+ break;
+ case PRECEDING:
+ addPrecedingNodes(context, candidates, true);
+ break;
+ case ATTRIBUTE:
+ addAttributes(context, candidates);
+ break;
+ case NAMESPACE:
+ addNamespaceAttributes(context, candidates);
+ break;
+ case SELF:
+ candidates.add(context);
+ break;
+ }
+ }
+
+ void addChildNodes(Node context, Collection acc, boolean recurse)
+ {
+ Node child = context.getFirstChild();
+ while (child != null)
+ {
+ acc.add(child);
+ if (recurse)
+ {
+ addChildNodes(child, acc, recurse);
+ }
+ child = child.getNextSibling();
+ }
+ }
+
+ void addParentNode(Node context, Collection acc, boolean recurse)
+ {
+ Node parent = (context.getNodeType() == Node.ATTRIBUTE_NODE) ?
+ ((Attr) context).getOwnerElement() : context.getParentNode();
+ if (parent != null)
+ {
+ acc.add(parent);
+ if (recurse)
+ {
+ addParentNode(parent, acc, recurse);
+ }
+ }
+ }
+
+ void addFollowingNodes(Node context, Collection acc, boolean recurse)
+ {
+ Node cur = context.getNextSibling();
+ while (cur != null)
+ {
+ acc.add(cur);
+ if (recurse)
+ {
+ addChildNodes(cur, acc, true);
+ }
+ cur = cur.getNextSibling();
+ }
+ if (recurse)
+ {
+ context = (context.getNodeType() == Node.ATTRIBUTE_NODE) ?
+ ((Attr) context).getOwnerElement() : context.getParentNode();
+ if (context != null)
+ {
+ addFollowingNodes(context, acc, recurse);
+ }
+ }
+ }
+
+ void addPrecedingNodes(Node context, Collection acc, boolean recurse)
+ {
+ Node cur = context.getPreviousSibling();
+ while (cur != null)
+ {
+ acc.add(cur);
+ if (recurse)
+ {
+ addChildNodes(cur, acc, true);
+ }
+ cur = cur.getPreviousSibling();
+ }
+ if (recurse)
+ {
+ context = (context.getNodeType() == Node.ATTRIBUTE_NODE) ?
+ ((Attr) context).getOwnerElement() : context.getParentNode();
+ if (context != null)
+ {
+ addPrecedingNodes(context, acc, recurse);
+ }
+ }
+ }
+
+ void addAttributes(Node context, Collection acc)
+ {
+ NamedNodeMap attrs = context.getAttributes();
+ if (attrs != null)
+ {
+ int attrLen = attrs.getLength();
+ for (int i = 0; i < attrLen; i++)
+ {
+ Node attr = attrs.item(i);
+ if (!isNamespaceAttribute(attr))
+ {
+ acc.add(attr);
+ }
+ }
+ }
+ }
+
+ void addNamespaceAttributes(Node context, Collection acc)
+ {
+ NamedNodeMap attrs = context.getAttributes();
+ if (attrs != null)
+ {
+ int attrLen = attrs.getLength();
+ for (int i = 0; i < attrLen; i++)
+ {
+ Node attr = attrs.item(i);
+ if (isNamespaceAttribute(attr))
+ {
+ acc.add(attr);
+ }
+ }
+ }
+ }
+
+ final boolean isNamespaceAttribute(Node node)
+ {
+ String uri = node.getNamespaceURI();
+ return (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getPrefix()) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getNodeName()));
+ }
+
+ public Expr clone(Object context)
+ {
+ int len = tests.length;
+ List tests2 = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ tests2.add(tests[i].clone(context));
+ }
+ return new Selector(axis, tests2);
+ }
+
+ public boolean references(QName var)
+ {
+ for (int i = 0; i < tests.length; i++)
+ {
+ if (tests[i].references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ switch (axis)
+ {
+ case ANCESTOR:
+ buf.append("ancestor::");
+ break;
+ case ANCESTOR_OR_SELF:
+ buf.append("ancestor-or-self::");
+ break;
+ case ATTRIBUTE:
+ if (tests.length == 0 ||
+ (tests[0] instanceof NameTest))
+ {
+ buf.append('@');
+ }
+ else
+ {
+ buf.append("attribute::");
+ }
+ break;
+ case CHILD:
+ //buf.append("child::");
+ break;
+ case DESCENDANT:
+ buf.append("descendant::");
+ break;
+ case DESCENDANT_OR_SELF:
+ buf.append("descendant-or-self::");
+ break;
+ case FOLLOWING:
+ buf.append("following::");
+ break;
+ case FOLLOWING_SIBLING:
+ buf.append("following-sibling::");
+ break;
+ case NAMESPACE:
+ buf.append("namespace::");
+ break;
+ case PARENT:
+ if (tests.length == 0 ||
+ (tests[0] instanceof NodeTypeTest &&
+ ((NodeTypeTest) tests[0]).type == 0))
+ {
+ return "..";
+ }
+ buf.append("parent::");
+ break;
+ case PRECEDING:
+ buf.append("preceding::");
+ break;
+ case PRECEDING_SIBLING:
+ buf.append("preceding-sibling::");
+ break;
+ case SELF:
+ if (tests.length == 0 ||
+ (tests[0] instanceof NodeTypeTest &&
+ ((NodeTypeTest) tests[0]).type == 0))
+ {
+ return ".";
+ }
+ buf.append("self::");
+ break;
+ }
+ if (tests.length == 0)
+ {
+ buf.append('*');
+ }
+ else
+ {
+ for (int i = 0; i < tests.length; i++)
+ {
+ buf.append(tests[i]);
+ }
+ }
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/StartsWithFunction.java b/libjava/classpath/gnu/xml/xpath/StartsWithFunction.java
new file mode 100644
index 0000000..ec02155
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/StartsWithFunction.java
@@ -0,0 +1,92 @@
+/* StartsWithFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The starts-with
function returns true if the first argument
+ * string starts with the second argument string, and otherwise returns false.
+ *
+ * @author Chris Burdess
+ */
+final class StartsWithFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+
+ StartsWithFunction(List args)
+ {
+ this((Expr) args.get(0), (Expr) args.get(1));
+ }
+
+ StartsWithFunction(Expr arg1, Expr arg2)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ String s1 = _string(context, val1);
+ String s2 = _string(context, val2);
+ return s1.startsWith(s2) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new StartsWithFunction(arg1.clone(context), arg2.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var));
+ }
+
+ public String toString()
+ {
+ return "starts-with(" + arg1 + "," + arg2 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Steps.java b/libjava/classpath/gnu/xml/xpath/Steps.java
new file mode 100644
index 0000000..9ef6cd3
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Steps.java
@@ -0,0 +1,253 @@
+/* Steps.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.Set;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Node;
+
+/**
+ * A list of transitions between components in a location path.
+ *
+ * @author Chris Burdess
+ */
+public final class Steps
+ extends Path
+{
+
+ final LinkedList path;
+
+ public Steps()
+ {
+ this(new LinkedList());
+ }
+
+ Steps(LinkedList path)
+ {
+ this.path = path;
+ }
+
+ public boolean matches(Node context)
+ {
+ // Right to left
+ return matches(context, path.size() - 1);
+ }
+
+ boolean matches(Node context, int pos)
+ {
+ Pattern right = (Pattern) path.get(pos);
+ if (!right.matches(context))
+ {
+ return false;
+ }
+ if (pos > 0)
+ {
+ Pattern left = (Pattern) path.get(pos - 1);
+ Iterator j = possibleContexts(right, context).iterator();
+ while (j.hasNext())
+ {
+ Node candidate = (Node) j.next();
+ if (left.matches(candidate) &&
+ matches(candidate, pos - 1))
+ {
+ return true;
+ }
+ // keep going, there may be another candidate
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Essentially the reverse of Selector.addCandidates.
+ * The idea is to determine possible context nodes for a match.
+ */
+ Collection possibleContexts(Pattern pattern, Node context)
+ {
+ if (pattern instanceof Selector)
+ {
+ Selector s = (Selector) pattern;
+ Collection candidates = new LinkedHashSet();
+ switch (s.axis)
+ {
+ case Selector.PARENT:
+ s.addChildNodes(context, candidates, false);
+ break;
+ case Selector.ANCESTOR:
+ s.addChildNodes(context, candidates, true);
+ break;
+ case Selector.ANCESTOR_OR_SELF:
+ candidates.add (context);
+ s.addChildNodes(context, candidates, true);
+ break;
+ case Selector.CHILD:
+ s.addParentNode(context, candidates, false);
+ break;
+ case Selector.DESCENDANT:
+ s.addParentNode(context, candidates, true);
+ break;
+ case Selector.DESCENDANT_OR_SELF:
+ candidates.add(context);
+ s.addParentNode(context, candidates, true);
+ break;
+ case Selector.PRECEDING_SIBLING:
+ s.addFollowingNodes(context, candidates, false);
+ break;
+ case Selector.FOLLOWING_SIBLING:
+ s.addPrecedingNodes(context, candidates, false);
+ break;
+ case Selector.PRECEDING:
+ s.addFollowingNodes(context, candidates, true);
+ break;
+ case Selector.FOLLOWING:
+ s.addPrecedingNodes(context, candidates, true);
+ break;
+ case Selector.ATTRIBUTE:
+ case Selector.NAMESPACE:
+ if (context.getNodeType() == Node.ATTRIBUTE_NODE)
+ {
+ candidates.add(((Attr) context).getOwnerElement());
+ }
+ break;
+ case Selector.SELF:
+ candidates.add(context);
+ break;
+ }
+ return candidates;
+ }
+ return Collections.EMPTY_SET;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ //System.err.println(toString()+" evaluate");
+ // Left to right
+ Iterator i = path.iterator();
+ Expr lhs = (Expr) i.next();
+ Object val = lhs.evaluate(context, pos, len);
+ //System.err.println("\tevaluate "+lhs+" = "+val);
+ while (val instanceof Collection && i.hasNext())
+ {
+ Path rhs = (Path) i.next();
+ val = rhs.evaluate(context, (Collection) val);
+ //System.err.println("\tevaluate "+rhs+" = "+val);
+ }
+ return val;
+ }
+
+ Collection evaluate(Node context, Collection ns)
+ {
+ // Left to right
+ Iterator i = path.iterator();
+ Expr lhs = (Expr) i.next();
+ if (lhs instanceof Path)
+ {
+ ns = ((Path) lhs).evaluate(context, ns);
+ }
+ else
+ {
+ Set acc = new LinkedHashSet();
+ int pos = 1, len = ns.size();
+ for (Iterator j = ns.iterator(); j.hasNext(); )
+ {
+ Node node = (Node) j.next();
+ Object ret = lhs.evaluate(node, pos++, len);
+ if (ret instanceof Collection)
+ {
+ acc.addAll((Collection) ret);
+ }
+ }
+ ns = acc;
+ }
+ while (i.hasNext())
+ {
+ Path rhs = (Path) i.next();
+ ns = rhs.evaluate(context, ns);
+ }
+ return ns;
+ }
+
+ public Expr clone(Object context)
+ {
+ int len = path.size();
+ LinkedList path2 = new LinkedList();
+ for (int i = 0; i < len; i++)
+ {
+ path2.add(((Expr) path.get(i)).clone(context));
+ }
+ return new Steps(path2);
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator i = path.iterator(); i.hasNext(); )
+ {
+ if (((Expr) i.next()).references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ Iterator i = path.iterator();
+ Expr expr = (Expr) i.next();
+ if (!(expr instanceof Root))
+ {
+ buf.append(expr);
+ }
+ while (i.hasNext())
+ {
+ expr = (Expr) i.next();
+ buf.append('/');
+ buf.append(expr);
+ }
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/StringFunction.java b/libjava/classpath/gnu/xml/xpath/StringFunction.java
new file mode 100644
index 0000000..0a4c681
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/StringFunction.java
@@ -0,0 +1,119 @@
+/* StringFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The string function converts an object to a string as follows:
+ *
+ *
+ * If the argument is omitted, it defaults to a node-set with the context
+ * node as its only member.
+ *
+ * @author Chris Burdess
+ */
+final class StringFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ StringFunction(List args)
+ {
+ this(args.size() > 0 ? (Expr) args.get(0) : null);
+ }
+
+ StringFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ return _string(context, val);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new StringFunction((arg == null) ? null :
+ arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ public String toString()
+ {
+ return (arg == null) ? "string()" : "string(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/StringLengthFunction.java b/libjava/classpath/gnu/xml/xpath/StringLengthFunction.java
new file mode 100644
index 0000000..7f5ceaf
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/StringLengthFunction.java
@@ -0,0 +1,91 @@
+/* StringLengthFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The
+ *
+ * string-length
function returns the number of characters
+ * in the string.
+ * If the argument is omitted, it defaults to the context node converted to
+ * a string, in other words the string-value of the context node.
+ *
+ * @author Chris Burdess
+ */
+final class StringLengthFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ StringLengthFunction(List args)
+ {
+ this(args.isEmpty() ? null : (Expr) args.get(0));
+ }
+
+ StringLengthFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ String s = _string(context, val);
+ return new Double((double) s.length());
+ }
+
+ public Expr clone(Object context)
+ {
+ return new StringLengthFunction((arg == null) ? null :
+ arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ public String toString()
+ {
+ return (arg == null) ? "string-length()" : "string-length(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/SubstringAfterFunction.java b/libjava/classpath/gnu/xml/xpath/SubstringAfterFunction.java
new file mode 100644
index 0000000..8144cf8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/SubstringAfterFunction.java
@@ -0,0 +1,98 @@
+/* SubstringAfterFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The substring-after
function returns the substring of the
+ * first argument string that follows the first occurrence of the second
+ * argument string in the first argument string, or the empty string if the
+ * first argument string does not contain the second argument string. For
+ * example, substring-after("1999/04/01","/") returns 04/01, and
+ * substring-after("1999/04/01","19") returns 99/04/01.
+ *
+ * @author Chris Burdess
+ */
+final class SubstringAfterFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+
+ SubstringAfterFunction(List args)
+ {
+ this((Expr) args.get(0), (Expr) args.get(1));
+ }
+
+ SubstringAfterFunction(Expr arg1, Expr arg2)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ String s1 = _string(context, val1);
+ String s2 = _string(context, val2);
+ int index = s1.indexOf(s2);
+ return (index == -1) ? "" : s1.substring(index + s2.length());
+ }
+
+ public Expr clone(Object context)
+ {
+ return new SubstringAfterFunction(arg1.clone(context),
+ arg2.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var));
+ }
+
+ public String toString()
+ {
+ return "substring-after(" + arg1 + "," + arg2 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/SubstringBeforeFunction.java b/libjava/classpath/gnu/xml/xpath/SubstringBeforeFunction.java
new file mode 100644
index 0000000..2d92a3e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/SubstringBeforeFunction.java
@@ -0,0 +1,97 @@
+/* SubstringBeforeFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The substring-before
function returns the substring of the
+ * first argument string that precedes the first occurrence of the second
+ * argument string in the first argument string, or the empty string if the
+ * first argument string does not contain the second argument string. For
+ * example, substring-before("1999/04/01","/") returns 1999.
+ *
+ * @author Chris Burdess
+ */
+final class SubstringBeforeFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+
+ SubstringBeforeFunction(List args)
+ {
+ this((Expr) args.get(0), (Expr) args.get(1));
+ }
+
+ SubstringBeforeFunction(Expr arg1, Expr arg2)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ String s1 = _string(context, val1);
+ String s2 = _string(context, val2);
+ int index = s1.indexOf(s2);
+ return (index == -1) ? "" : s1.substring(0, index);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new SubstringBeforeFunction(arg1.clone(context),
+ arg2.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var));
+ }
+
+ public String toString()
+ {
+ return "substring-before(" + arg1 + "," + arg2 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/SubstringFunction.java b/libjava/classpath/gnu/xml/xpath/SubstringFunction.java
new file mode 100644
index 0000000..d65c4fa
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/SubstringFunction.java
@@ -0,0 +1,129 @@
+/* SubstringFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The substring function returns the substring of the first argument
+ * starting at the position specified in the second argument with length
+ * specified in the third argument. For example, substring("12345",2,3)
+ * returns "234". If the third argument is not specified, it returns the
+ * substring starting at the position specified in the second argument and
+ * continuing to the end of the string. For example, substring("12345",2)
+ * returns "2345".
+ *
+ * @author Chris Burdess
+ */
+final class SubstringFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+ final Expr arg3;
+
+ SubstringFunction(List args)
+ {
+ this((Expr) args.get(0), (Expr) args.get(1),
+ (args.size() > 2) ? (Expr) args.get(2) : null);
+ }
+
+ SubstringFunction(Expr arg1, Expr arg2, Expr arg3)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ this.arg3 = arg3;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ String s = _string(context, val1);
+ int p = (val2 instanceof Double) ?
+ ((Double) val2).intValue() :
+ (int) Math.round(_number(context, val2));
+ p--;
+ if (p < 0)
+ {
+ p = 0;
+ }
+
+ int l = s.length() - p;
+ if (l <= 0)
+ {
+ return "";
+ }
+
+ if (arg3 != null)
+ {
+ Object val3 = arg3.evaluate(context, pos, len);
+ int v3 = (val3 instanceof Double) ?
+ ((Double) val3).intValue() :
+ (int) Math.round(_number(context, val3));
+ if (v3 < l)
+ {
+ l = v3;
+ }
+ }
+
+ return s.substring(p, p + l);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new SubstringFunction(arg1.clone(context), arg2.clone(context),
+ (arg3 == null) ? null : arg3.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var) ||
+ (arg3 == null) ? false : arg3.references(var));
+ }
+
+ public String toString()
+ {
+ return (arg3 == null) ? "substring(" + arg1 + "," + arg2 + ")" :
+ "substring(" + arg1 + "," + arg2 + "," + arg3 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/SumFunction.java b/libjava/classpath/gnu/xml/xpath/SumFunction.java
new file mode 100644
index 0000000..93c2e80
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/SumFunction.java
@@ -0,0 +1,100 @@
+/* SumFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The sum
function returns the sum, for each node in the
+ * argument node-set, of the result of converting the string-values of the
+ * node to a number.
+ *
+ * @author Chris Burdess
+ */
+final class SumFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ SumFunction(List args)
+ {
+ this((Expr) args.get(0));
+ }
+
+ SumFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ double sum = 0.0d;
+ if (val instanceof Collection)
+ {
+ for (Iterator i = ((Collection) val).iterator(); i.hasNext(); )
+ {
+ Node node = (Node) i.next();
+ String s = stringValue(node);
+ sum += _number(context, s);
+ }
+ }
+ return new Double(sum);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new SumFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "sum(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Test.java b/libjava/classpath/gnu/xml/xpath/Test.java
new file mode 100644
index 0000000..94837ff
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Test.java
@@ -0,0 +1,58 @@
+/* Test.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * A test that can be performed on a node to determine whether to include it
+ * in a selection.
+ *
+ * @author Chris Burdess
+ */
+public abstract class Test
+{
+
+ public abstract boolean matches(Node node, int pos, int len);
+
+ public abstract Test clone(Object context);
+
+ public abstract boolean references(QName var);
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/TranslateFunction.java b/libjava/classpath/gnu/xml/xpath/TranslateFunction.java
new file mode 100644
index 0000000..54e8b9c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/TranslateFunction.java
@@ -0,0 +1,133 @@
+/* TranslateFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The translate
function returns the first argument string
+ * with occurrences of characters in the second argument string replaced by
+ * the character at the corresponding position in the third argument string.
+ * For example, translate("bar","abc","ABC") returns the string BAr. If
+ * there is a character in the second argument string with no character at a
+ * corresponding position in the third argument string (because the second
+ * argument string is longer than the third argument string), then
+ * occurrences of that character in the first argument string are removed.
+ * For example, translate("--aaa--","abc-","ABC") returns "AAA". If a
+ * character occurs more than once in the second argument string, then the
+ * first occurrence determines the replacement character. If the third
+ * argument string is longer than the second argument string, then excess
+ * characters are ignored.
+ *
+ * @author Chris Burdess
+ */
+final class TranslateFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+ final Expr arg3;
+
+ TranslateFunction(List args)
+ {
+ this((Expr) args.get(0), (Expr) args.get(1), (Expr) args.get(2));
+ }
+
+ TranslateFunction(Expr arg1, Expr arg2, Expr arg3)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ this.arg3 = arg3;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ Object val3 = arg3.evaluate(context, pos, len);
+ String string = _string(context, val1);
+ String search = _string(context, val2);
+ String replace = _string(context, val3);
+ StringBuffer buf = new StringBuffer();
+ int l1 = string.length();
+ int l2 = search.length();
+ int l3 = replace.length();
+ for (int i = 0; i < l1; i++)
+ {
+ char c = string.charAt(i);
+ boolean replaced = false;
+ for (int j = 0; j < l2; j++)
+ {
+ if (c == search.charAt(j))
+ {
+ if (j < l3)
+ {
+ buf.append(replace.charAt(j));
+ }
+ replaced = true;
+ }
+ }
+ if (!replaced)
+ {
+ buf.append(c);
+ }
+ }
+ return new String(buf);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new TranslateFunction(arg1.clone(context), arg2.clone(context),
+ arg3.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var) ||
+ arg3.references(var));
+ }
+
+ public String toString()
+ {
+ return "translate(" + arg1 + "," + arg2 + "," + arg3 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/TrueFunction.java b/libjava/classpath/gnu/xml/xpath/TrueFunction.java
new file mode 100644
index 0000000..6ad42d7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/TrueFunction.java
@@ -0,0 +1,72 @@
+/* TrueFunction.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The true
function returns true.
+ *
+ * @author Chris Burdess
+ */
+final class TrueFunction
+ extends Expr
+{
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return Boolean.TRUE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new TrueFunction();
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "true()";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/UnionExpr.java b/libjava/classpath/gnu/xml/xpath/UnionExpr.java
new file mode 100644
index 0000000..5078713
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/UnionExpr.java
@@ -0,0 +1,108 @@
+/* UnionExpr.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The union of two node-sets.
+ *
+ * @author Chris Burdess
+ */
+public final class UnionExpr
+ extends Pattern
+{
+
+ final Expr lhs;
+ final Expr rhs;
+
+ public UnionExpr(Expr lhs, Expr rhs)
+ {
+ this.lhs = lhs;
+ this.rhs = rhs;
+ }
+
+ public boolean matches(Node context)
+ {
+ if (lhs instanceof Pattern && rhs instanceof Pattern)
+ {
+ return ((Pattern) lhs).matches(context) ||
+ ((Pattern) rhs).matches(context);
+ }
+ return false;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object left = lhs.evaluate(context, pos, len);
+ Object right = rhs.evaluate(context, pos, len);
+ if (left instanceof Collection && right instanceof Collection)
+ {
+ Set set = new HashSet();
+ set.addAll ((Collection) left);
+ set.addAll ((Collection) right);
+ List list = new ArrayList(set);
+ Collections.sort(list, documentOrderComparator);
+ return list;
+ }
+ return Collections.EMPTY_SET;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new UnionExpr(lhs.clone(context), rhs.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (lhs.references(var) || rhs.references(var));
+ }
+
+ public String toString()
+ {
+ return lhs + " | " + rhs;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/VariableReference.java b/libjava/classpath/gnu/xml/xpath/VariableReference.java
new file mode 100644
index 0000000..813a37f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/VariableReference.java
@@ -0,0 +1,100 @@
+/* VariableReference.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathVariableResolver;
+import org.w3c.dom.Node;
+import gnu.xml.transform.Bindings;
+
+public class VariableReference
+ extends Expr
+{
+
+ final XPathVariableResolver resolver;
+ final QName name;
+
+ public VariableReference(XPathVariableResolver resolver, QName name)
+ {
+ this.resolver = resolver;
+ this.name = name;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ if (resolver != null)
+ {
+ if (resolver instanceof Bindings)
+ {
+ // Needs context to operate properly
+ return ((Bindings) resolver).get(name, context, pos, len);
+ }
+ return resolver.resolveVariable(name);
+ }
+ throw new IllegalStateException("no variable resolver");
+ }
+
+ public Expr clone(Object context)
+ {
+ XPathVariableResolver r = resolver;
+ if (context instanceof XPathVariableResolver)
+ {
+ r = (XPathVariableResolver) context;
+ }
+ return new VariableReference(r, name);
+ }
+
+ public boolean references(QName var)
+ {
+ return name.equals(var);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer("$");
+ String prefix = name.getPrefix();
+ if (prefix != null && !"".equals(prefix))
+ {
+ buf.append(prefix);
+ buf.append(':');
+ }
+ buf.append(name.getLocalPart());
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/XPathFactoryImpl.java b/libjava/classpath/gnu/xml/xpath/XPathFactoryImpl.java
new file mode 100644
index 0000000..45dc57e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/XPathFactoryImpl.java
@@ -0,0 +1,90 @@
+/* XPathFactoryImpl.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathFactory;
+import javax.xml.xpath.XPathFactoryConfigurationException;
+import javax.xml.xpath.XPathFunctionResolver;
+import javax.xml.xpath.XPathVariableResolver;
+
+/**
+ * GNU XPath factory implementation.
+ *
+ * @author Chris Burdess
+ */
+public class XPathFactoryImpl
+ extends XPathFactory
+{
+
+ XPathVariableResolver variableResolver;
+ XPathFunctionResolver functionResolver;
+
+ public boolean isObjectModelSupported(String objectModel)
+ {
+ return XPathFactory.DEFAULT_OBJECT_MODEL_URI.equals(objectModel);
+ }
+
+ public void setFeature(String name, boolean value)
+ throws XPathFactoryConfigurationException
+ {
+ throw new XPathFactoryConfigurationException(name);
+ }
+
+ public boolean getFeature(String name)
+ throws XPathFactoryConfigurationException
+ {
+ throw new XPathFactoryConfigurationException(name);
+ }
+
+ public void setXPathVariableResolver(XPathVariableResolver resolver)
+ {
+ variableResolver = resolver;
+ }
+
+ public void setXPathFunctionResolver(XPathFunctionResolver resolver)
+ {
+ functionResolver = resolver;
+ }
+
+ public XPath newXPath()
+ {
+ return new XPathImpl(null, variableResolver, functionResolver);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/XPathImpl.java b/libjava/classpath/gnu/xml/xpath/XPathImpl.java
new file mode 100644
index 0000000..3511834
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/XPathImpl.java
@@ -0,0 +1,164 @@
+/* XPathImpl.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.io.IOException;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFunctionResolver;
+import javax.xml.xpath.XPathVariableResolver;
+import org.xml.sax.InputSource;
+
+/**
+ * JAXP XPath implementation.
+ *
+ * @author Chris Burdess
+ */
+public class XPathImpl
+ implements XPath
+{
+
+ XPathParser parser;
+ NamespaceContext namespaceContext;
+ XPathVariableResolver variableResolver;
+ XPathFunctionResolver functionResolver;
+
+ XPathImpl(NamespaceContext namespaceContext,
+ XPathVariableResolver variableResolver,
+ XPathFunctionResolver functionResolver)
+ {
+ parser = new XPathParser();
+ this.namespaceContext = namespaceContext;
+ this.variableResolver = variableResolver;
+ this.functionResolver = functionResolver;
+ reset();
+ }
+
+ public void reset()
+ {
+ parser.namespaceContext = namespaceContext;
+ parser.variableResolver = variableResolver;
+ parser.functionResolver = functionResolver;
+ }
+
+ public void setXPathVariableResolver(XPathVariableResolver resolver)
+ {
+ parser.variableResolver = resolver;
+ }
+
+ public XPathVariableResolver getXPathVariableResolver()
+ {
+ return parser.variableResolver;
+ }
+
+ public void setXPathFunctionResolver(XPathFunctionResolver resolver)
+ {
+ parser.functionResolver = resolver;
+ }
+
+ public XPathFunctionResolver getXPathFunctionResolver()
+ {
+ return parser.functionResolver;
+ }
+
+ public void setNamespaceContext(NamespaceContext nsContext)
+ {
+ parser.namespaceContext = nsContext;
+ }
+
+ public NamespaceContext getNamespaceContext()
+ {
+ return parser.namespaceContext;
+ }
+
+ public XPathExpression compile(String expression)
+ throws XPathExpressionException
+ {
+ XPathTokenizer tokenizer = new XPathTokenizer(expression);
+ try
+ {
+ return (Expr) parser.yyparse(tokenizer);
+ }
+ catch (IOException e)
+ {
+ throw new XPathExpressionException(e);
+ }
+ catch (XPathParser.yyException e)
+ {
+ throw new XPathExpressionException(expression);
+ }
+ }
+
+ public Object evaluate(String expression,
+ Object item,
+ QName returnType)
+ throws XPathExpressionException
+ {
+ XPathExpression expr = compile(expression);
+ return expr.evaluate(item, returnType);
+ }
+
+ public String evaluate(String expression,
+ Object item)
+ throws XPathExpressionException
+ {
+ XPathExpression expr = compile(expression);
+ return expr.evaluate(item);
+ }
+
+ public Object evaluate(String expression,
+ InputSource source,
+ QName returnType)
+ throws XPathExpressionException
+ {
+ XPathExpression expr = compile(expression);
+ return expr.evaluate(source, returnType);
+ }
+
+ public String evaluate(String expression,
+ InputSource source)
+ throws XPathExpressionException
+ {
+ XPathExpression expr = compile(expression);
+ return expr.evaluate(source);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/XPathParser.java b/libjava/classpath/gnu/xml/xpath/XPathParser.java
new file mode 100644
index 0000000..624dcd8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/XPathParser.java
@@ -0,0 +1,1464 @@
+// created by jay 0.8 (c) 1998 Axel.Schreiner@informatik.uni-osnabrueck.de
+
+ // line 2 "XPathParser.y"
+/*
+ * XPathParser.java
+ * Copyright (C) 2004 The Free Software Foundation
+ *
+ * This file is part of GNU JAXP, a library.
+ *
+ * GNU JAXP 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 of the License, or
+ * (at your option) any later version.
+ *
+ * GNU JAXP 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
+ * obliged to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ */
+
+package gnu.xml.xpath;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunctionResolver;
+import javax.xml.xpath.XPathVariableResolver;
+import org.w3c.dom.Node;
+
+/**
+ * An XPath 1.0 parser.
+ *
+ * @author Chris Burdess
+ */
+public class XPathParser
+{
+
+ NamespaceContext namespaceContext;
+ XPathVariableResolver variableResolver;
+ XPathFunctionResolver functionResolver;
+
+ QName getQName(String name)
+ {
+ QName qName = QName.valueOf(name);
+ if (namespaceContext != null)
+ {
+ String prefix = qName.getPrefix();
+ String uri = qName.getNamespaceURI();
+ if (prefix != null && (uri == null || uri.length() == 0))
+ {
+ uri = namespaceContext.getNamespaceURI(prefix);
+ String localName = qName.getLocalPart();
+ qName = new QName(uri, localName, prefix);
+ }
+ }
+ return qName;
+ }
+
+ Expr lookupFunction(String name, List args)
+ {
+ int arity = args.size();
+ if ("position".equals(name) && arity == 0)
+ {
+ return new PositionFunction();
+ }
+ else if ("last".equals(name) && arity == 0)
+ {
+ return new LastFunction();
+ }
+ else if ("string".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new StringFunction(args);
+ }
+ else if ("number".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NumberFunction(args);
+ }
+ else if ("boolean".equals(name) && arity == 1)
+ {
+ return new BooleanFunction(args);
+ }
+ else if ("count".equals(name) && arity == 1)
+ {
+ return new CountFunction(args);
+ }
+ else if ("not".equals(name) && arity == 1)
+ {
+ return new NotFunction(args);
+ }
+ else if ("id".equals(name) && arity == 1)
+ {
+ return new IdFunction(args);
+ }
+ else if ("concat".equals(name) && arity > 1)
+ {
+ return new ConcatFunction(args);
+ }
+ else if ("true".equals(name) && arity == 0)
+ {
+ return new TrueFunction();
+ }
+ else if ("false".equals(name) && arity == 0)
+ {
+ return new FalseFunction();
+ }
+ else if ("name".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NameFunction(args);
+ }
+ else if ("local-name".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new LocalNameFunction(args);
+ }
+ else if ("namespace-uri".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NamespaceUriFunction(args);
+ }
+ else if ("starts-with".equals(name) && arity == 2)
+ {
+ return new StartsWithFunction(args);
+ }
+ else if ("contains".equals(name) && arity == 2)
+ {
+ return new ContainsFunction(args);
+ }
+ else if ("string-length".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new StringLengthFunction(args);
+ }
+ else if ("translate".equals(name) && arity == 3)
+ {
+ return new TranslateFunction(args);
+ }
+ else if ("normalize-space".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NormalizeSpaceFunction(args);
+ }
+ else if ("substring".equals(name) && (arity == 2 || arity == 3))
+ {
+ return new SubstringFunction(args);
+ }
+ else if ("substring-before".equals(name) && arity == 2)
+ {
+ return new SubstringBeforeFunction(args);
+ }
+ else if ("substring-after".equals(name) && arity == 2)
+ {
+ return new SubstringAfterFunction(args);
+ }
+ else if ("lang".equals(name) && arity == 1)
+ {
+ return new LangFunction(args);
+ }
+ else if ("sum".equals(name) && arity == 1)
+ {
+ return new SumFunction(args);
+ }
+ else if ("floor".equals(name) && arity == 1)
+ {
+ return new FloorFunction(args);
+ }
+ else if ("ceiling".equals(name) && arity == 1)
+ {
+ return new CeilingFunction(args);
+ }
+ else if ("round".equals(name) && arity == 1)
+ {
+ return new RoundFunction(args);
+ }
+ else if (functionResolver != null)
+ {
+ QName qName = QName.valueOf(name);
+ Object function = functionResolver.resolveFunction(qName, arity);
+ if (function != null &&
+ function instanceof Function &&
+ function instanceof Expr)
+ {
+ Function f = (Function) function;
+ f.setArguments(args);
+ return (Expr) function;
+ }
+ }
+ return new FunctionCall(functionResolver, name, args);
+ }
+
+ // line 211 "-"
+// %token constants
+
+ public static final int LITERAL = 257;
+ public static final int DIGITS = 258;
+ public static final int NAME = 259;
+ public static final int LP = 260;
+ public static final int RP = 261;
+ public static final int LB = 262;
+ public static final int RB = 263;
+ public static final int COMMA = 264;
+ public static final int PIPE = 265;
+ public static final int SLASH = 266;
+ public static final int DOUBLE_SLASH = 267;
+ public static final int EQ = 268;
+ public static final int NE = 269;
+ public static final int GT = 270;
+ public static final int LT = 271;
+ public static final int GTE = 272;
+ public static final int LTE = 273;
+ public static final int PLUS = 274;
+ public static final int MINUS = 275;
+ public static final int AT = 276;
+ public static final int STAR = 277;
+ public static final int DOLLAR = 278;
+ public static final int COLON = 279;
+ public static final int DOUBLE_COLON = 280;
+ public static final int DOT = 281;
+ public static final int DOUBLE_DOT = 282;
+ public static final int ANCESTOR = 283;
+ public static final int ANCESTOR_OR_SELF = 284;
+ public static final int ATTRIBUTE = 285;
+ public static final int CHILD = 286;
+ public static final int DESCENDANT = 287;
+ public static final int DESCENDANT_OR_SELF = 288;
+ public static final int FOLLOWING = 289;
+ public static final int FOLLOWING_SIBLING = 290;
+ public static final int NAMESPACE = 291;
+ public static final int PARENT = 292;
+ public static final int PRECEDING = 293;
+ public static final int PRECEDING_SIBLING = 294;
+ public static final int SELF = 295;
+ public static final int DIV = 296;
+ public static final int MOD = 297;
+ public static final int OR = 298;
+ public static final int AND = 299;
+ public static final int COMMENT = 300;
+ public static final int PROCESSING_INSTRUCTION = 301;
+ public static final int TEXT = 302;
+ public static final int NODE = 303;
+ public static final int UNARY = 304;
+ public static final int yyErrorCode = 256;
+
+ /** thrown for irrecoverable syntax errors and stack overflow.
+ */
+ public static class yyException extends java.lang.Exception {
+ public yyException (String message) {
+ super(message);
+ }
+ }
+
+ /** must be implemented by a scanner object to supply input to the parser.
+ */
+ public interface yyInput {
+ /** move on to next token.
+ @return false if positioned beyond tokens.
+ @throws IOException on input error.
+ */
+ boolean advance () throws java.io.IOException;
+ /** classifies current token.
+ Should not be called if advance() returned false.
+ @return current %token or single character.
+ */
+ int token ();
+ /** associated with current token.
+ Should not be called if advance() returned false.
+ @return value for token().
+ */
+ Object value ();
+ }
+
+ /** simplified error message.
+ @see yyerror
+ */
+ public void yyerror (String message) {
+ yyerror(message, null);
+ }
+
+ /** (syntax) error message.
+ Can be overwritten to control message format.
+ @param message text to be displayed.
+ @param expected vector of acceptable tokens, if available.
+ */
+ public void yyerror (String message, String[] expected) {
+ if (expected != null && expected.length > 0) {
+ System.err.print(message+", expecting");
+ for (int n = 0; n < expected.length; ++ n)
+ System.err.print(" "+expected[n]);
+ System.err.println();
+ } else
+ System.err.println(message);
+ }
+
+ /** debugging support, requires the package jay.yydebug.
+ Set to null to suppress debugging messages.
+ */
+//t protected jay.yydebug.yyDebug yydebug;
+
+ protected static final int yyFinal = 30;
+
+ /** index-checked interface to yyName[].
+ @param token single character or %token value.
+ @return token name or [illegal] or [unknown].
+ */
+//t public static final String yyname (int token) {
+//t if (token < 0 || token > YyNameClass.yyName.length) return "[illegal]";
+//t String name;
+//t if ((name = YyNameClass.yyName[token]) != null) return name;
+//t return "[unknown]";
+//t }
+
+ /** computes list of expected tokens on error by tracing the tables.
+ @param state for which to compute the list.
+ @return list of token names.
+ */
+ protected String[] yyExpecting (int state) {
+ int token, n, len = 0;
+ boolean[] ok = new boolean[YyNameClass.yyName.length];
+
+ if ((n = YySindexClass.yySindex[state]) != 0)
+ for (token = n < 0 ? -n : 0;
+ token < YyNameClass.yyName.length && n+token < YyTableClass.yyTable.length; ++ token)
+ if (YyCheckClass.yyCheck[n+token] == token && !ok[token] && YyNameClass.yyName[token] != null) {
+ ++ len;
+ ok[token] = true;
+ }
+ if ((n = YyRindexClass.yyRindex[state]) != 0)
+ for (token = n < 0 ? -n : 0;
+ token < YyNameClass.yyName.length && n+token < YyTableClass.yyTable.length; ++ token)
+ if (YyCheckClass.yyCheck[n+token] == token && !ok[token] && YyNameClass.yyName[token] != null) {
+ ++ len;
+ ok[token] = true;
+ }
+
+ String result[] = new String[len];
+ for (n = token = 0; n < len; ++ token)
+ if (ok[token]) result[n++] = YyNameClass.yyName[token];
+ return result;
+ }
+
+ /** the generated parser, with debugging messages.
+ Maintains a state and a value stack, currently with fixed maximum size.
+ @param yyLex scanner.
+ @param yydebug debug message writer implementing yyDebug, or null.
+ @return result of the last reduction, if any.
+ @throws yyException on irrecoverable parse error.
+ */
+ public Object yyparse (yyInput yyLex, Object yydebug)
+ throws java.io.IOException, yyException {
+//t this.yydebug = (jay.yydebug.yyDebug)yydebug;
+ return yyparse(yyLex);
+ }
+
+ /** initial size and increment of the state/value stack [default 256].
+ This is not final so that it can be overwritten outside of invocations
+ of yyparse().
+ */
+ protected int yyMax;
+
+ /** executed at the beginning of a reduce action.
+ Used as $$ = yyDefault($1), prior to the user-specified action, if any.
+ Can be overwritten to provide deep copy, etc.
+ @param first value for $1, or null.
+ @return first.
+ */
+ protected Object yyDefault (Object first) {
+ return first;
+ }
+
+ /** the generated parser.
+ Maintains a state and a value stack, currently with fixed maximum size.
+ @param yyLex scanner.
+ @return result of the last reduction, if any.
+ @throws yyException on irrecoverable parse error.
+ */
+ public Object yyparse (yyInput yyLex)
+ throws java.io.IOException, yyException {
+ if (yyMax <= 0) yyMax = 256; // initial size
+ int yyState = 0, yyStates[] = new int[yyMax]; // state stack
+ Object yyVal = null, yyVals[] = new Object[yyMax]; // value stack
+ int yyToken = -1; // current input
+ int yyErrorFlag = 0; // #tks to shift
+
+ yyLoop: for (int yyTop = 0;; ++ yyTop) {
+ if (yyTop >= yyStates.length) { // dynamically increase
+ int[] i = new int[yyStates.length+yyMax];
+ System.arraycopy(yyStates, 0, i, 0, yyStates.length);
+ yyStates = i;
+ Object[] o = new Object[yyVals.length+yyMax];
+ System.arraycopy(yyVals, 0, o, 0, yyVals.length);
+ yyVals = o;
+ }
+ yyStates[yyTop] = yyState;
+ yyVals[yyTop] = yyVal;
+//t if (yydebug != null) yydebug.push(yyState, yyVal);
+
+ yyDiscarded: for (;;) { // discarding a token does not change stack
+ int yyN;
+ if ((yyN = YyDefRedClass.yyDefRed[yyState]) == 0) { // else [default] reduce (yyN)
+ if (yyToken < 0) {
+ yyToken = yyLex.advance() ? yyLex.token() : 0;
+//t if (yydebug != null)
+//t yydebug.lex(yyState, yyToken, yyname(yyToken), yyLex.value());
+ }
+ if ((yyN = YySindexClass.yySindex[yyState]) != 0 && (yyN += yyToken) >= 0
+ && yyN < YyTableClass.yyTable.length && YyCheckClass.yyCheck[yyN] == yyToken) {
+//t if (yydebug != null)
+//t yydebug.shift(yyState, YyTableClass.yyTable[yyN], yyErrorFlag-1);
+ yyState = YyTableClass.yyTable[yyN]; // shift to yyN
+ yyVal = yyLex.value();
+ yyToken = -1;
+ if (yyErrorFlag > 0) -- yyErrorFlag;
+ continue yyLoop;
+ }
+ if ((yyN = YyRindexClass.yyRindex[yyState]) != 0 && (yyN += yyToken) >= 0
+ && yyN < YyTableClass.yyTable.length && YyCheckClass.yyCheck[yyN] == yyToken)
+ yyN = YyTableClass.yyTable[yyN]; // reduce (yyN)
+ else
+ switch (yyErrorFlag) {
+
+ case 0:
+ yyerror("syntax error", yyExpecting(yyState));
+//t if (yydebug != null) yydebug.error("syntax error");
+
+ case 1: case 2:
+ yyErrorFlag = 3;
+ do {
+ if ((yyN = YySindexClass.yySindex[yyStates[yyTop]]) != 0
+ && (yyN += yyErrorCode) >= 0 && yyN < YyTableClass.yyTable.length
+ && YyCheckClass.yyCheck[yyN] == yyErrorCode) {
+//t if (yydebug != null)
+//t yydebug.shift(yyStates[yyTop], YyTableClass.yyTable[yyN], 3);
+ yyState = YyTableClass.yyTable[yyN];
+ yyVal = yyLex.value();
+ continue yyLoop;
+ }
+//t if (yydebug != null) yydebug.pop(yyStates[yyTop]);
+ } while (-- yyTop >= 0);
+//t if (yydebug != null) yydebug.reject();
+ throw new yyException("irrecoverable syntax error");
+
+ case 3:
+ if (yyToken == 0) {
+//t if (yydebug != null) yydebug.reject();
+ throw new yyException("irrecoverable syntax error at end-of-file");
+ }
+//t if (yydebug != null)
+//t yydebug.discard(yyState, yyToken, yyname(yyToken),
+//t yyLex.value());
+ yyToken = -1;
+ continue yyDiscarded; // leave stack alone
+ }
+ }
+ int yyV = yyTop + 1-YyLenClass.yyLen[yyN];
+//t if (yydebug != null)
+//t yydebug.reduce(yyState, yyStates[yyV-1], yyN, YyRuleClass.yyRule[yyN], YyLenClass.yyLen[yyN]);
+ yyVal = yyDefault(yyV > yyTop ? null : yyVals[yyV]);
+ switch (yyN) {
+case 4:
+ // line 277 "XPathParser.y"
+ {
+ yyVal = new Root();
+ }
+ break;
+case 5:
+ // line 281 "XPathParser.y"
+ {
+ Steps steps;
+ if (yyVals[0+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[0+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst(yyVals[0+yyTop]);
+ }
+ steps.path.addFirst(new Root());
+ yyVal = steps;
+ /*$$ = new Step(new Root(), (Path) $2);*/
+ }
+ break;
+case 6:
+ // line 297 "XPathParser.y"
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList (nt));
+ Steps steps;
+ if (yyVals[0+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[0+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst(yyVals[0+yyTop]);
+ }
+ steps.path.addFirst(s);
+ steps.path.addFirst(new Root());
+ yyVal = steps;
+ /*Step step = new Step(s, (Path) $2);*/
+ /*$$ = new Step(new Root(), step);*/
+ }
+ break;
+case 8:
+ // line 322 "XPathParser.y"
+ {
+ Steps steps;
+ if (yyVals[-2+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[-2+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst(yyVals[-2+yyTop]);
+ }
+ steps.path.addLast(yyVals[0+yyTop]);
+ yyVal = steps;
+ /*$$ = new Step((Expr) $1, (Path) $3);*/
+ }
+ break;
+case 9:
+ // line 338 "XPathParser.y"
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList (nt));
+ Steps steps;
+ if (yyVals[-2+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[-2+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst(yyVals[-2+yyTop]);
+ }
+ steps.path.addLast(s);
+ steps.path.addLast(yyVals[0+yyTop]);
+ yyVal = steps;
+ /*Step step = new Step(s, (Path) $3);*/
+ /*$$ = new Step((Expr) $1, step);*/
+ }
+ break;
+case 10:
+ // line 362 "XPathParser.y"
+ {
+ yyVal = new Selector (Selector.CHILD, (List) yyVals[0+yyTop]);
+ }
+ break;
+case 11:
+ // line 366 "XPathParser.y"
+ {
+ yyVal = new Selector (Selector.ATTRIBUTE, (List) yyVals[0+yyTop]);
+ }
+ break;
+case 12:
+ // line 370 "XPathParser.y"
+ {
+ yyVal = new Selector (((Integer) yyVals[-2+yyTop]).intValue (), (List) yyVals[0+yyTop]);
+ }
+ break;
+case 13:
+ // line 374 "XPathParser.y"
+ {
+ yyVal = new Selector (Selector.SELF, Collections.EMPTY_LIST);
+ }
+ break;
+case 14:
+ // line 378 "XPathParser.y"
+ {
+ yyVal = new Selector (Selector.PARENT, Collections.EMPTY_LIST);
+ }
+ break;
+case 15:
+ // line 385 "XPathParser.y"
+ {
+ List list = new ArrayList();
+ list.add(yyVals[0+yyTop]);
+ yyVal = list;
+ }
+ break;
+case 16:
+ // line 391 "XPathParser.y"
+ {
+ List list = (List)yyVals[-1+yyTop];
+ list.add(yyVals[0+yyTop]);
+ yyVal = list;
+ }
+ break;
+case 17:
+ // line 415 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.ANCESTOR);
+ }
+ break;
+case 18:
+ // line 419 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.ANCESTOR_OR_SELF);
+ }
+ break;
+case 19:
+ // line 423 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.ATTRIBUTE);
+ }
+ break;
+case 20:
+ // line 427 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.CHILD);
+ }
+ break;
+case 21:
+ // line 431 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.DESCENDANT);
+ }
+ break;
+case 22:
+ // line 435 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.DESCENDANT_OR_SELF);
+ }
+ break;
+case 23:
+ // line 439 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.FOLLOWING);
+ }
+ break;
+case 24:
+ // line 443 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.FOLLOWING_SIBLING);
+ }
+ break;
+case 25:
+ // line 447 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.NAMESPACE);
+ }
+ break;
+case 26:
+ // line 451 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.PARENT);
+ }
+ break;
+case 27:
+ // line 455 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.PRECEDING);
+ }
+ break;
+case 28:
+ // line 459 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.PRECEDING_SIBLING);
+ }
+ break;
+case 29:
+ // line 463 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.SELF);
+ }
+ break;
+case 31:
+ // line 472 "XPathParser.y"
+ {
+ yyVal = new NodeTypeTest(Node.PROCESSING_INSTRUCTION_NODE, (String) yyVals[-1+yyTop]);
+ }
+ break;
+case 32:
+ // line 477 "XPathParser.y"
+ {
+ yyVal = new NodeTypeTest(((Short) yyVals[-1+yyTop]).shortValue());
+ }
+ break;
+case 33:
+ // line 484 "XPathParser.y"
+ {
+ yyVal = new Predicate((Expr) yyVals[-1+yyTop]);
+ }
+ break;
+case 35:
+ // line 492 "XPathParser.y"
+ {
+ yyVal = new ParenthesizedExpr((Expr) yyVals[-1+yyTop]);
+ }
+ break;
+case 36:
+ // line 496 "XPathParser.y"
+ {
+ yyVal = new Constant(yyVals[0+yyTop]);
+ }
+ break;
+case 37:
+ // line 500 "XPathParser.y"
+ {
+ yyVal = new Constant(yyVals[0+yyTop]);
+ }
+ break;
+case 39:
+ // line 508 "XPathParser.y"
+ {
+ yyVal = lookupFunction((String) yyVals[-2+yyTop], Collections.EMPTY_LIST);
+ }
+ break;
+case 40:
+ // line 512 "XPathParser.y"
+ {
+ yyVal = lookupFunction((String) yyVals[-3+yyTop], (List) yyVals[-1+yyTop]);
+ }
+ break;
+case 41:
+ // line 519 "XPathParser.y"
+ {
+ List list = new ArrayList();
+ list.add(yyVals[0+yyTop]);
+ yyVal = list;
+ }
+ break;
+case 42:
+ // line 525 "XPathParser.y"
+ {
+ List list = (List) yyVals[0+yyTop];
+ list.add(0, yyVals[-2+yyTop]);
+ yyVal = list;
+ }
+ break;
+case 44:
+ // line 535 "XPathParser.y"
+ {
+ yyVal = new UnionExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop]);
+ }
+ break;
+case 47:
+ // line 544 "XPathParser.y"
+ {
+ Steps steps;
+ if (yyVals[0+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[0+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst(yyVals[0+yyTop]);
+ }
+ steps.path.addFirst(yyVals[-2+yyTop]);
+ yyVal = steps;
+ /*$$ = new Step ((Expr) $1, (Path) $3);*/
+ }
+ break;
+case 48:
+ // line 560 "XPathParser.y"
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList(nt));
+ Steps steps;
+ if (yyVals[0+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[0+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst(yyVals[0+yyTop]);
+ }
+ steps.path.addFirst(s);
+ steps.path.addFirst(yyVals[-2+yyTop]);
+ yyVal = steps;
+ /*Step step = new Step (s, (Path) $3);*/
+ /*$$ = new Step ((Expr) $1, step);*/
+ }
+ break;
+case 50:
+ // line 585 "XPathParser.y"
+ {
+ Predicate filter = (Predicate) yyVals[0+yyTop];
+ Selector s = new Selector(Selector.SELF,
+ Collections.singletonList(filter));
+ Steps steps;
+ if (yyVals[-1+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[-1+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst(yyVals[-1+yyTop]);
+ }
+ steps.path.addLast(s);
+ yyVal = steps;
+ /*$$ = new Step ((Expr) $1, s);*/
+ }
+ break;
+case 52:
+ // line 608 "XPathParser.y"
+ {
+ yyVal = new OrExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop]);
+ }
+ break;
+case 54:
+ // line 616 "XPathParser.y"
+ {
+ yyVal = new AndExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop]);
+ }
+ break;
+case 56:
+ // line 624 "XPathParser.y"
+ {
+ yyVal = new EqualityExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], false);
+ }
+ break;
+case 57:
+ // line 628 "XPathParser.y"
+ {
+ yyVal = new EqualityExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], true);
+ }
+ break;
+case 59:
+ // line 636 "XPathParser.y"
+ {
+ yyVal = new RelationalExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], true, false);
+ }
+ break;
+case 60:
+ // line 640 "XPathParser.y"
+ {
+ yyVal = new RelationalExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], false, false);
+ }
+ break;
+case 61:
+ // line 644 "XPathParser.y"
+ {
+ yyVal = new RelationalExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], true, true);
+ }
+ break;
+case 62:
+ // line 648 "XPathParser.y"
+ {
+ yyVal = new RelationalExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], false, true);
+ }
+ break;
+case 64:
+ // line 656 "XPathParser.y"
+ {
+ yyVal = new ArithmeticExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], ArithmeticExpr.ADD);
+ }
+ break;
+case 65:
+ // line 660 "XPathParser.y"
+ {
+ yyVal = new ArithmeticExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], ArithmeticExpr.SUBTRACT);
+ }
+ break;
+case 67:
+ // line 668 "XPathParser.y"
+ {
+ yyVal = new ArithmeticExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], ArithmeticExpr.MULTIPLY);
+ }
+ break;
+case 68:
+ // line 672 "XPathParser.y"
+ {
+ yyVal = new ArithmeticExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], ArithmeticExpr.DIVIDE);
+ }
+ break;
+case 69:
+ // line 676 "XPathParser.y"
+ {
+ yyVal = new ArithmeticExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], ArithmeticExpr.MODULO);
+ }
+ break;
+case 71:
+ // line 684 "XPathParser.y"
+ {
+ yyVal = new NegativeExpr((Expr) yyVals[0+yyTop]);
+ }
+ break;
+case 72:
+ // line 691 "XPathParser.y"
+ {
+ yyVal = new Double((String) yyVals[0+yyTop] + ".0");
+ }
+ break;
+case 73:
+ // line 695 "XPathParser.y"
+ {
+ yyVal = new Double((String) yyVals[-1+yyTop] + ".0");
+ }
+ break;
+case 74:
+ // line 699 "XPathParser.y"
+ {
+ yyVal = new Double((String) yyVals[-2+yyTop] + "." + (String) yyVals[0+yyTop]);
+ }
+ break;
+case 75:
+ // line 703 "XPathParser.y"
+ {
+ yyVal = new Double("0." + (String) yyVals[0+yyTop]);
+ }
+ break;
+case 77:
+ // line 732 "XPathParser.y"
+ {
+ String name = (String) yyVals[0+yyTop];
+ yyVal = new VariableReference(variableResolver, getQName(name));
+ }
+ break;
+case 78:
+ // line 740 "XPathParser.y"
+ {
+ yyVal = new NameTest(null, true, true);
+ }
+ break;
+case 79:
+ // line 744 "XPathParser.y"
+ {
+ QName qName = getQName((String) yyVals[-2+yyTop]);
+ yyVal = new NameTest(qName, true, false);
+ }
+ break;
+case 80:
+ // line 749 "XPathParser.y"
+ {
+ QName qName = getQName((String) yyVals[0+yyTop]);
+ yyVal = new NameTest(qName, false, false);
+ }
+ break;
+case 82:
+ // line 758 "XPathParser.y"
+ {
+ yyVal = (String) yyVals[-2+yyTop] + ':' + (String) yyVals[0+yyTop];
+ }
+ break;
+case 83:
+ // line 765 "XPathParser.y"
+ {
+ yyVal = new Short(Node.COMMENT_NODE);
+ }
+ break;
+case 84:
+ // line 769 "XPathParser.y"
+ {
+ yyVal = new Short(Node.TEXT_NODE);
+ }
+ break;
+case 85:
+ // line 773 "XPathParser.y"
+ {
+ yyVal = new Short(Node.PROCESSING_INSTRUCTION_NODE);
+ }
+ break;
+case 86:
+ // line 777 "XPathParser.y"
+ {
+ yyVal = new Short((short) 0);
+ }
+ break;
+ // line 988 "-"
+ }
+ yyTop -= YyLenClass.yyLen[yyN];
+ yyState = yyStates[yyTop];
+ int yyM = YyLhsClass.yyLhs[yyN];
+ if (yyState == 0 && yyM == 0) {
+//t if (yydebug != null) yydebug.shift(0, yyFinal);
+ yyState = yyFinal;
+ if (yyToken < 0) {
+ yyToken = yyLex.advance() ? yyLex.token() : 0;
+//t if (yydebug != null)
+//t yydebug.lex(yyState, yyToken,yyname(yyToken), yyLex.value());
+ }
+ if (yyToken == 0) {
+//t if (yydebug != null) yydebug.accept(yyVal);
+ return yyVal;
+ }
+ continue yyLoop;
+ }
+ if ((yyN = YyGindexClass.yyGindex[yyM]) != 0 && (yyN += yyState) >= 0
+ && yyN < YyTableClass.yyTable.length && YyCheckClass.yyCheck[yyN] == yyState)
+ yyState = YyTableClass.yyTable[yyN];
+ else
+ yyState = YyDgotoClass.yyDgoto[yyM];
+//t if (yydebug != null) yydebug.shift(yyStates[yyTop], yyState);
+ continue yyLoop;
+ }
+ }
+ }
+
+ protected static final class YyLhsClass {
+
+ public static final short yyLhs [] = { -1,
+ 0, 2, 2, 4, 4, 4, 3, 3, 3, 5,
+ 5, 5, 5, 5, 6, 6, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 8,
+ 8, 8, 9, 12, 12, 12, 12, 12, 15, 15,
+ 17, 17, 18, 18, 19, 19, 19, 19, 20, 20,
+ 1, 1, 21, 21, 22, 22, 22, 23, 23, 23,
+ 23, 23, 24, 24, 24, 25, 25, 25, 25, 26,
+ 26, 14, 14, 14, 14, 16, 13, 10, 10, 10,
+ 27, 27, 11, 11, 11, 11,
+ };
+ } /* End of class YyLhsClass */
+
+ protected static final class YyLenClass {
+
+ public static final short yyLen [] = { 2,
+ 1, 1, 1, 1, 2, 2, 1, 3, 3, 1,
+ 2, 3, 1, 1, 1, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 2, 3, 1, 3, 1, 1, 1, 3, 4,
+ 1, 3, 1, 3, 1, 1, 3, 3, 1, 2,
+ 1, 3, 1, 3, 1, 3, 3, 1, 3, 3,
+ 3, 3, 1, 3, 3, 1, 3, 3, 3, 1,
+ 2, 1, 2, 3, 2, 1, 2, 1, 3, 1,
+ 1, 3, 1, 1, 1, 1,
+ };
+ } /* End class YyLenClass */
+
+ protected static final class YyDefRedClass {
+
+ public static final short yyDefRed [] = { 0,
+ 36, 0, 0, 0, 0, 0, 0, 0, 78, 0,
+ 0, 14, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 83, 0, 84, 86, 0,
+ 0, 45, 0, 3, 7, 0, 0, 15, 30, 0,
+ 49, 34, 37, 38, 0, 0, 43, 0, 0, 0,
+ 0, 0, 0, 66, 0, 0, 0, 0, 13, 0,
+ 80, 0, 71, 0, 0, 77, 75, 0, 0, 0,
+ 0, 0, 16, 0, 32, 0, 0, 0, 0, 50,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 74, 82, 79, 35, 0, 31, 0, 8,
+ 9, 0, 0, 39, 0, 0, 44, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 67, 68,
+ 69, 33, 0, 40, 42,
+ };
+ } /* End of class YyDefRedClass */
+
+ protected static final class YyDgotoClass {
+
+ public static final short yyDgoto [] = { 105,
+ 31, 32, 33, 34, 35, 36, 37, 38, 73, 39,
+ 40, 41, 42, 43, 44, 45, 106, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55,
+ };
+ } /* End of class YyDgotoClass */
+
+ protected static final class YySindexClass {
+
+ public static final short yySindex [] = { -97,
+ 0, -271, -267, -97, -239, -239, -97, -199, 0, -236,
+ -222, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -218, 0, 0, 0,
+ -257, 0, -241, 0, 0, -205, -221, 0, 0, -194,
+ 0, 0, 0, 0, -190, -185, 0, -238, -211, -234,
+ -255, -209, -275, 0, 0, -169, -250, -168, 0, -241,
+ 0, -241, 0, -205, -187, 0, 0, -167, -97, -239,
+ -239, -97, 0, -199, 0, -151, -43, -239, -239, 0,
+ -97, -97, -97, -97, -97, -97, -97, -97, -97, -97,
+ -97, -97, 0, 0, 0, 0, -164, 0, -211, 0,
+ 0, -166, -205, 0, -165, -163, 0, -241, -241, -234,
+ -255, -255, -209, -209, -209, -209, -275, -275, 0, 0,
+ 0, 0, -97, 0, 0,
+ };
+ } /* End of class YySindexClass */
+
+ protected static final class YyRindexClass {
+
+ public static final short yyRindex [] = { 0,
+ 0, 58, 1, 0, 420, 0, 0, 0, 0, 0,
+ 129, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -161, 0, 0, 0,
+ 40, 0, 237, 0, 0, 168, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 459, 0, 277, 557, 544,
+ 656, 561, 474, 0, 19, 75, 0, 0, 0, 295,
+ 0, 334, 0, 183, 114, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 686, 0,
+ 0, 0, 222, 0, -156, 0, 0, 351, 405, 553,
+ 665, 697, 577, 600, 617, 639, 513, 528, 0, 0,
+ 0, 0, 0, 0, 0,
+ };
+ } /* End of class YyRindexClass */
+
+ protected static final class YyGindexClass {
+
+ public static final short yyGindex [] = { 7,
+ 0, 0, 8, 0, 3, -3, 0, 0, 48, 0,
+ 0, 0, 0, 0, 0, 0, -12, 0, 35, 0,
+ 44, 36, -1, -54, 2, -7, -2,
+ };
+ } /* End of class YyGindexClass */
+
+ protected static final class YyTableClass {
+
+ public static final short yyTable [] = { 63,
+ 81, 90, 61, 61, 64, 61, 30, 66, 94, 56,
+ 58, 57, 60, 62, 84, 85, 86, 87, 80, 3,
+ 91, 92, 65, 72, 70, 71, 95, 78, 79, 113,
+ 114, 115, 116, 82, 83, 67, 8, 9, 68, 1,
+ 69, 59, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 72, 72, 74, 3,
+ 26, 27, 28, 29, 88, 89, 75, 61, 61, 76,
+ 103, 61, 100, 101, 73, 61, 61, 9, 102, 77,
+ 111, 112, 119, 120, 121, 108, 109, 81, 93, 117,
+ 118, 97, 96, 98, 94, 80, 122, 124, 123, 85,
+ 26, 27, 28, 29, 41, 1, 2, 3, 4, 104,
+ 125, 107, 99, 81, 5, 6, 110, 0, 0, 0,
+ 0, 0, 0, 7, 8, 9, 10, 0, 13, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 0, 0, 0, 0, 26, 27,
+ 28, 29, 0, 0, 0, 0, 0, 0, 0, 1,
+ 2, 3, 4, 0, 0, 0, 0, 10, 5, 6,
+ 0, 0, 0, 0, 0, 0, 0, 7, 8, 9,
+ 10, 0, 11, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 0, 0,
+ 0, 0, 26, 27, 28, 29, 0, 0, 0, 0,
+ 0, 0, 0, 1, 2, 3, 4, 0, 0, 0,
+ 0, 12, 5, 6, 0, 0, 0, 0, 0, 0,
+ 0, 0, 8, 9, 10, 0, 2, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 0, 0, 0, 0, 26, 27, 28, 29,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 46, 81, 76, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 5, 80, 81, 81, 81, 81,
+ 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 80, 80, 80, 80, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 6, 72, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 47, 73, 0, 72, 72, 72, 72, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 73, 73, 73, 73, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 13,
+ 81, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 48, 13, 0, 0, 0, 81,
+ 81, 81, 81, 0, 0, 0, 0, 0, 0, 4,
+ 0, 0, 0, 0, 13, 13, 13, 13, 10, 0,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 11, 10, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 70, 11,
+ 0, 0, 0, 10, 10, 10, 10, 0, 0, 0,
+ 0, 0, 0, 63, 0, 0, 0, 0, 11, 11,
+ 11, 11, 12, 0, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 2, 12, 2,
+ 2, 2, 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 64, 2, 0, 0, 0, 12, 12, 12,
+ 12, 0, 0, 0, 0, 0, 0, 65, 0, 0,
+ 0, 0, 2, 2, 2, 2, 0, 46, 0, 46,
+ 46, 46, 0, 53, 46, 46, 46, 46, 46, 46,
+ 46, 46, 54, 46, 0, 5, 51, 5, 5, 5,
+ 58, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 0, 5, 46, 46, 46, 46, 60, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 5, 6, 0, 6, 6, 6, 59,
+ 0, 6, 6, 6, 6, 6, 6, 6, 6, 0,
+ 6, 47, 0, 47, 47, 47, 62, 0, 47, 47,
+ 47, 47, 47, 47, 47, 47, 0, 47, 0, 6,
+ 6, 6, 6, 0, 0, 0, 0, 0, 61, 0,
+ 0, 0, 0, 0, 0, 0, 47, 47, 47, 47,
+ 0, 0, 0, 0, 0, 55, 0, 0, 0, 0,
+ 0, 0, 0, 0, 56, 48, 0, 48, 48, 48,
+ 0, 0, 48, 48, 48, 48, 48, 48, 48, 48,
+ 4, 48, 4, 4, 4, 52, 0, 4, 4, 4,
+ 4, 4, 4, 4, 4, 0, 57, 0, 0, 0,
+ 48, 48, 48, 48, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 4, 4, 4, 4, 70,
+ 0, 70, 70, 0, 0, 0, 70, 70, 70, 70,
+ 70, 70, 70, 70, 63, 70, 63, 63, 0, 0,
+ 0, 63, 63, 63, 63, 63, 63, 63, 63, 0,
+ 0, 0, 0, 0, 70, 70, 70, 70, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 63, 63, 64, 0, 64, 64, 0, 0, 0,
+ 64, 64, 64, 64, 64, 64, 64, 64, 65, 0,
+ 65, 65, 0, 0, 0, 65, 65, 65, 65, 65,
+ 65, 65, 65, 0, 53, 0, 53, 53, 0, 0,
+ 64, 64, 0, 54, 0, 54, 54, 51, 0, 51,
+ 51, 58, 0, 58, 58, 65, 65, 0, 58, 58,
+ 58, 58, 58, 58, 0, 0, 0, 60, 0, 60,
+ 60, 53, 53, 0, 60, 60, 60, 60, 60, 60,
+ 54, 54, 0, 0, 51, 0, 0, 0, 58, 58,
+ 59, 0, 59, 59, 0, 0, 0, 59, 59, 59,
+ 59, 59, 59, 0, 60, 60, 0, 62, 0, 62,
+ 62, 0, 0, 0, 62, 62, 62, 62, 62, 62,
+ 0, 0, 0, 0, 0, 0, 0, 59, 59, 61,
+ 0, 61, 61, 0, 0, 0, 61, 61, 61, 61,
+ 61, 61, 0, 0, 62, 62, 55, 0, 55, 55,
+ 0, 0, 0, 55, 55, 56, 0, 56, 56, 0,
+ 0, 0, 56, 56, 0, 0, 61, 61, 0, 0,
+ 0, 0, 0, 0, 0, 0, 52, 0, 52, 52,
+ 0, 0, 0, 55, 55, 0, 0, 57, 0, 57,
+ 57, 0, 56, 56, 57, 57, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 52, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 57, 57,
+ };
+ } /* End of class YyTableClass */
+
+ protected static final class YyCheckClass {
+
+ public static final short yyCheck [] = { 7,
+ 0, 277, 5, 6, 8, 8, 0, 10, 259, 281,
+ 4, 279, 5, 6, 270, 271, 272, 273, 0, 259,
+ 296, 297, 259, 262, 266, 267, 277, 266, 267, 84,
+ 85, 86, 87, 268, 269, 258, 276, 277, 257, 0,
+ 298, 281, 282, 283, 284, 285, 286, 287, 288, 289,
+ 290, 291, 292, 293, 294, 295, 262, 0, 280, 259,
+ 300, 301, 302, 303, 274, 275, 261, 70, 71, 260,
+ 74, 74, 70, 71, 0, 78, 79, 277, 72, 265,
+ 82, 83, 90, 91, 92, 78, 79, 299, 258, 88,
+ 89, 279, 261, 261, 259, 48, 263, 261, 264, 261,
+ 300, 301, 302, 303, 261, 257, 258, 259, 260, 261,
+ 123, 77, 69, 0, 266, 267, 81, -1, -1, -1,
+ -1, -1, -1, 275, 276, 277, 278, -1, 0, 281,
+ 282, 283, 284, 285, 286, 287, 288, 289, 290, 291,
+ 292, 293, 294, 295, -1, -1, -1, -1, 300, 301,
+ 302, 303, -1, -1, -1, -1, -1, -1, -1, 257,
+ 258, 259, 260, -1, -1, -1, -1, 0, 266, 267,
+ -1, -1, -1, -1, -1, -1, -1, 275, 276, 277,
+ 278, -1, 0, 281, 282, 283, 284, 285, 286, 287,
+ 288, 289, 290, 291, 292, 293, 294, 295, -1, -1,
+ -1, -1, 300, 301, 302, 303, -1, -1, -1, -1,
+ -1, -1, -1, 257, 258, 259, 260, -1, -1, -1,
+ -1, 0, 266, 267, -1, -1, -1, -1, -1, -1,
+ -1, -1, 276, 277, 278, -1, 0, 281, 282, 283,
+ 284, 285, 286, 287, 288, 289, 290, 291, 292, 293,
+ 294, 295, -1, -1, -1, -1, 300, 301, 302, 303,
+ 260, 261, 262, 263, 264, 265, 266, 267, 268, 269,
+ 270, 271, 272, 273, 274, 275, 0, 277, 260, 261,
+ 262, 263, 264, 265, 266, 267, 268, 269, 270, 271,
+ 272, 273, 274, 275, 0, 277, 296, 297, 298, 299,
+ 261, -1, 263, 264, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 296, 297, 298, 299, 261, 262,
+ 263, 264, 265, 266, 267, 268, 269, 270, 271, 272,
+ 273, 274, 275, 0, 277, 261, 262, 263, 264, 265,
+ 266, 267, 268, 269, 270, 271, 272, 273, 274, 275,
+ 0, 277, -1, 296, 297, 298, 299, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 296, 297, 298, 299, 261, 262, 263, 264, 265, 266,
+ 267, 268, 269, 270, 271, 272, 273, 274, 275, 261,
+ 277, 263, 264, 265, 266, 267, 268, 269, 270, 271,
+ 272, 273, 274, 275, 0, 277, -1, -1, -1, 296,
+ 297, 298, 299, -1, -1, -1, -1, -1, -1, 0,
+ -1, -1, -1, -1, 296, 297, 298, 299, 261, -1,
+ 263, 264, 265, 266, 267, 268, 269, 270, 271, 272,
+ 273, 274, 275, 261, 277, 263, 264, 265, 266, 267,
+ 268, 269, 270, 271, 272, 273, 274, 275, 0, 277,
+ -1, -1, -1, 296, 297, 298, 299, -1, -1, -1,
+ -1, -1, -1, 0, -1, -1, -1, -1, 296, 297,
+ 298, 299, 261, -1, 263, 264, 265, 266, 267, 268,
+ 269, 270, 271, 272, 273, 274, 275, 261, 277, 263,
+ 264, 265, -1, -1, 268, 269, 270, 271, 272, 273,
+ 274, 275, 0, 277, -1, -1, -1, 296, 297, 298,
+ 299, -1, -1, -1, -1, -1, -1, 0, -1, -1,
+ -1, -1, 296, 297, 298, 299, -1, 261, -1, 263,
+ 264, 265, -1, 0, 268, 269, 270, 271, 272, 273,
+ 274, 275, 0, 277, -1, 261, 0, 263, 264, 265,
+ 0, -1, 268, 269, 270, 271, 272, 273, 274, 275,
+ -1, 277, 296, 297, 298, 299, 0, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 296, 297, 298, 299, 261, -1, 263, 264, 265, 0,
+ -1, 268, 269, 270, 271, 272, 273, 274, 275, -1,
+ 277, 261, -1, 263, 264, 265, 0, -1, 268, 269,
+ 270, 271, 272, 273, 274, 275, -1, 277, -1, 296,
+ 297, 298, 299, -1, -1, -1, -1, -1, 0, -1,
+ -1, -1, -1, -1, -1, -1, 296, 297, 298, 299,
+ -1, -1, -1, -1, -1, 0, -1, -1, -1, -1,
+ -1, -1, -1, -1, 0, 261, -1, 263, 264, 265,
+ -1, -1, 268, 269, 270, 271, 272, 273, 274, 275,
+ 261, 277, 263, 264, 265, 0, -1, 268, 269, 270,
+ 271, 272, 273, 274, 275, -1, 0, -1, -1, -1,
+ 296, 297, 298, 299, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 296, 297, 298, 299, 261,
+ -1, 263, 264, -1, -1, -1, 268, 269, 270, 271,
+ 272, 273, 274, 275, 261, 277, 263, 264, -1, -1,
+ -1, 268, 269, 270, 271, 272, 273, 274, 275, -1,
+ -1, -1, -1, -1, 296, 297, 298, 299, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 298, 299, 261, -1, 263, 264, -1, -1, -1,
+ 268, 269, 270, 271, 272, 273, 274, 275, 261, -1,
+ 263, 264, -1, -1, -1, 268, 269, 270, 271, 272,
+ 273, 274, 275, -1, 261, -1, 263, 264, -1, -1,
+ 298, 299, -1, 261, -1, 263, 264, 261, -1, 263,
+ 264, 261, -1, 263, 264, 298, 299, -1, 268, 269,
+ 270, 271, 272, 273, -1, -1, -1, 261, -1, 263,
+ 264, 298, 299, -1, 268, 269, 270, 271, 272, 273,
+ 298, 299, -1, -1, 298, -1, -1, -1, 298, 299,
+ 261, -1, 263, 264, -1, -1, -1, 268, 269, 270,
+ 271, 272, 273, -1, 298, 299, -1, 261, -1, 263,
+ 264, -1, -1, -1, 268, 269, 270, 271, 272, 273,
+ -1, -1, -1, -1, -1, -1, -1, 298, 299, 261,
+ -1, 263, 264, -1, -1, -1, 268, 269, 270, 271,
+ 272, 273, -1, -1, 298, 299, 261, -1, 263, 264,
+ -1, -1, -1, 268, 269, 261, -1, 263, 264, -1,
+ -1, -1, 268, 269, -1, -1, 298, 299, -1, -1,
+ -1, -1, -1, -1, -1, -1, 261, -1, 263, 264,
+ -1, -1, -1, 298, 299, -1, -1, 261, -1, 263,
+ 264, -1, 298, 299, 268, 269, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 298, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 298, 299,
+ };
+ } /* End of class YyCheckClass */
+
+
+//t protected static final class YyRuleClass {
+
+//t public static final String yyRule [] = {
+//t "$accept : expr",
+//t "expr : or_expr",
+//t "location_path : relative_location_path",
+//t "location_path : absolute_location_path",
+//t "absolute_location_path : SLASH",
+//t "absolute_location_path : SLASH relative_location_path",
+//t "absolute_location_path : DOUBLE_SLASH relative_location_path",
+//t "relative_location_path : step",
+//t "relative_location_path : relative_location_path SLASH step",
+//t "relative_location_path : relative_location_path DOUBLE_SLASH step",
+//t "step : step_node_test",
+//t "step : AT step_node_test",
+//t "step : axis_name DOUBLE_COLON step_node_test",
+//t "step : DOT",
+//t "step : DOUBLE_DOT",
+//t "step_node_test : node_test",
+//t "step_node_test : step_node_test predicate",
+//t "axis_name : ANCESTOR",
+//t "axis_name : ANCESTOR_OR_SELF",
+//t "axis_name : ATTRIBUTE",
+//t "axis_name : CHILD",
+//t "axis_name : DESCENDANT",
+//t "axis_name : DESCENDANT_OR_SELF",
+//t "axis_name : FOLLOWING",
+//t "axis_name : FOLLOWING_SIBLING",
+//t "axis_name : NAMESPACE",
+//t "axis_name : PARENT",
+//t "axis_name : PRECEDING",
+//t "axis_name : PRECEDING_SIBLING",
+//t "axis_name : SELF",
+//t "node_test : name_test",
+//t "node_test : PROCESSING_INSTRUCTION LITERAL RP",
+//t "node_test : node_type RP",
+//t "predicate : LB expr RB",
+//t "primary_expr : variable_reference",
+//t "primary_expr : LP expr RP",
+//t "primary_expr : LITERAL",
+//t "primary_expr : number",
+//t "primary_expr : function_call",
+//t "function_call : function_name LP RP",
+//t "function_call : function_name LP argument_list RP",
+//t "argument_list : expr",
+//t "argument_list : expr COMMA argument_list",
+//t "union_expr : path_expr",
+//t "union_expr : union_expr PIPE path_expr",
+//t "path_expr : location_path",
+//t "path_expr : filter_expr",
+//t "path_expr : filter_expr SLASH relative_location_path",
+//t "path_expr : filter_expr DOUBLE_SLASH relative_location_path",
+//t "filter_expr : primary_expr",
+//t "filter_expr : filter_expr predicate",
+//t "or_expr : and_expr",
+//t "or_expr : or_expr OR and_expr",
+//t "and_expr : equality_expr",
+//t "and_expr : and_expr AND equality_expr",
+//t "equality_expr : relational_expr",
+//t "equality_expr : equality_expr EQ relational_expr",
+//t "equality_expr : equality_expr NE relational_expr",
+//t "relational_expr : additive_expr",
+//t "relational_expr : relational_expr LT additive_expr",
+//t "relational_expr : relational_expr GT additive_expr",
+//t "relational_expr : relational_expr LTE additive_expr",
+//t "relational_expr : relational_expr GTE additive_expr",
+//t "additive_expr : multiplicative_expr",
+//t "additive_expr : additive_expr PLUS multiplicative_expr",
+//t "additive_expr : additive_expr MINUS multiplicative_expr",
+//t "multiplicative_expr : unary_expr",
+//t "multiplicative_expr : multiplicative_expr STAR unary_expr",
+//t "multiplicative_expr : multiplicative_expr DIV unary_expr",
+//t "multiplicative_expr : multiplicative_expr MOD unary_expr",
+//t "unary_expr : union_expr",
+//t "unary_expr : MINUS unary_expr",
+//t "number : DIGITS",
+//t "number : DIGITS DOT",
+//t "number : DIGITS DOT DIGITS",
+//t "number : DOT DIGITS",
+//t "function_name : qname",
+//t "variable_reference : DOLLAR qname",
+//t "name_test : STAR",
+//t "name_test : NAME COLON STAR",
+//t "name_test : qname",
+//t "qname : NAME",
+//t "qname : NAME COLON NAME",
+//t "node_type : COMMENT",
+//t "node_type : TEXT",
+//t "node_type : PROCESSING_INSTRUCTION",
+//t "node_type : NODE",
+//t };
+//t } /* End of class YyRuleClass */
+
+ protected static final class YyNameClass {
+
+ public static final String yyName [] = {
+ "end-of-file",null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,"LITERAL","DIGITS","NAME","LP",
+ "RP","LB","RB","COMMA","PIPE","SLASH","DOUBLE_SLASH","EQ","NE","GT",
+ "LT","GTE","LTE","PLUS","MINUS","AT","STAR","DOLLAR","COLON",
+ "DOUBLE_COLON","DOT","DOUBLE_DOT","ANCESTOR","ANCESTOR_OR_SELF",
+ "ATTRIBUTE","CHILD","DESCENDANT","DESCENDANT_OR_SELF","FOLLOWING",
+ "FOLLOWING_SIBLING","NAMESPACE","PARENT","PRECEDING",
+ "PRECEDING_SIBLING","SELF","DIV","MOD","OR","AND","COMMENT",
+ "PROCESSING_INSTRUCTION","TEXT","NODE","UNARY",
+ };
+ } /* End of class YyNameClass */
+
+
+ // line 783 "XPathParser.y"
+
+}
+ // line 1463 "-"
diff --git a/libjava/classpath/gnu/xml/xpath/XPathParser.y b/libjava/classpath/gnu/xml/xpath/XPathParser.y
new file mode 100644
index 0000000..d7dc4f1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/XPathParser.y
@@ -0,0 +1,784 @@
+%{
+/*
+ * XPathParser.java
+ * Copyright (C) 2004 The Free Software Foundation
+ *
+ * This file is part of GNU JAXP, a library.
+ *
+ * GNU JAXP 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 of the License, or
+ * (at your option) any later version.
+ *
+ * GNU JAXP 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
+ * obliged to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ */
+
+package gnu.xml.xpath;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunctionResolver;
+import javax.xml.xpath.XPathVariableResolver;
+import org.w3c.dom.Node;
+
+/**
+ * An XPath 1.0 parser.
+ *
+ * @author Chris Burdess
+ */
+public class XPathParser
+{
+
+ NamespaceContext namespaceContext;
+ XPathVariableResolver variableResolver;
+ XPathFunctionResolver functionResolver;
+
+ QName getQName(String name)
+ {
+ QName qName = QName.valueOf(name);
+ if (namespaceContext != null)
+ {
+ String prefix = qName.getPrefix();
+ String uri = qName.getNamespaceURI();
+ if (prefix != null && (uri == null || uri.length() == 0))
+ {
+ uri = namespaceContext.getNamespaceURI(prefix);
+ String localName = qName.getLocalPart();
+ qName = new QName(uri, localName, prefix);
+ }
+ }
+ return qName;
+ }
+
+ Expr lookupFunction(String name, List args)
+ {
+ int arity = args.size();
+ if ("position".equals(name) && arity == 0)
+ {
+ return new PositionFunction();
+ }
+ else if ("last".equals(name) && arity == 0)
+ {
+ return new LastFunction();
+ }
+ else if ("string".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new StringFunction(args);
+ }
+ else if ("number".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NumberFunction(args);
+ }
+ else if ("boolean".equals(name) && arity == 1)
+ {
+ return new BooleanFunction(args);
+ }
+ else if ("count".equals(name) && arity == 1)
+ {
+ return new CountFunction(args);
+ }
+ else if ("not".equals(name) && arity == 1)
+ {
+ return new NotFunction(args);
+ }
+ else if ("id".equals(name) && arity == 1)
+ {
+ return new IdFunction(args);
+ }
+ else if ("concat".equals(name) && arity > 1)
+ {
+ return new ConcatFunction(args);
+ }
+ else if ("true".equals(name) && arity == 0)
+ {
+ return new TrueFunction();
+ }
+ else if ("false".equals(name) && arity == 0)
+ {
+ return new FalseFunction();
+ }
+ else if ("name".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NameFunction(args);
+ }
+ else if ("local-name".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new LocalNameFunction(args);
+ }
+ else if ("namespace-uri".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NamespaceUriFunction(args);
+ }
+ else if ("starts-with".equals(name) && arity == 2)
+ {
+ return new StartsWithFunction(args);
+ }
+ else if ("contains".equals(name) && arity == 2)
+ {
+ return new ContainsFunction(args);
+ }
+ else if ("string-length".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new StringLengthFunction(args);
+ }
+ else if ("translate".equals(name) && arity == 3)
+ {
+ return new TranslateFunction(args);
+ }
+ else if ("normalize-space".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NormalizeSpaceFunction(args);
+ }
+ else if ("substring".equals(name) && (arity == 2 || arity == 3))
+ {
+ return new SubstringFunction(args);
+ }
+ else if ("substring-before".equals(name) && arity == 2)
+ {
+ return new SubstringBeforeFunction(args);
+ }
+ else if ("substring-after".equals(name) && arity == 2)
+ {
+ return new SubstringAfterFunction(args);
+ }
+ else if ("lang".equals(name) && arity == 1)
+ {
+ return new LangFunction(args);
+ }
+ else if ("sum".equals(name) && arity == 1)
+ {
+ return new SumFunction(args);
+ }
+ else if ("floor".equals(name) && arity == 1)
+ {
+ return new FloorFunction(args);
+ }
+ else if ("ceiling".equals(name) && arity == 1)
+ {
+ return new CeilingFunction(args);
+ }
+ else if ("round".equals(name) && arity == 1)
+ {
+ return new RoundFunction(args);
+ }
+ else if (functionResolver != null)
+ {
+ QName qName = QName.valueOf(name);
+ Object function = functionResolver.resolveFunction(qName, arity);
+ if (function != null &&
+ function instanceof Function &&
+ function instanceof Expr)
+ {
+ Function f = (Function) function;
+ f.setArguments(args);
+ return (Expr) function;
+ }
+ }
+ return new FunctionCall(functionResolver, name, args);
+ }
+
+%}
+
+%token LITERAL
+%token DIGITS
+%token NAME
+
+%token LP // '('
+%token RP // ')'
+%token LB // '['
+%token RB // ']'
+%token COMMA // ','
+%token PIPE // '|'
+%token SLASH // '/'
+%token DOUBLE_SLASH // '//'
+%token EQ // '='
+%token NE // '!='
+%token GT // '>'
+%token LT // '<'
+%token GTE // '>='
+%token LTE // '<='
+%token PLUS // '+'
+%token MINUS // '-'
+%token AT // '@'
+%token STAR // '*'
+%token DOLLAR // '$'
+%token COLON // ':'
+%token DOUBLE_COLON // '::'
+%token DOT // '.'
+%token DOUBLE_DOT // '..'
+
+%token ANCESTOR
+%token ANCESTOR_OR_SELF
+%token ATTRIBUTE
+%token CHILD
+%token DESCENDANT
+%token DESCENDANT_OR_SELF
+%token FOLLOWING
+%token FOLLOWING_SIBLING
+%token NAMESPACE
+%token PARENT
+%token PRECEDING
+%token PRECEDING_SIBLING
+%token SELF
+%token DIV
+%token MOD
+%token OR
+%token AND
+%token COMMENT
+%token PROCESSING_INSTRUCTION
+%token TEXT
+%token NODE
+
+%right UNARY
+
+%start expr
+
+%%
+
+expr:
+ or_expr
+ ;
+
+location_path:
+ relative_location_path
+ | absolute_location_path
+ ;
+
+absolute_location_path:
+ SLASH
+ {
+ $$ = new Root();
+ }
+ | SLASH relative_location_path
+ {
+ Steps steps;
+ if ($2 instanceof Steps)
+ {
+ steps = (Steps) $2;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst($2);
+ }
+ steps.path.addFirst(new Root());
+ $$ = steps;
+ //$$ = new Step(new Root(), (Path) $2);
+ }
+ | DOUBLE_SLASH relative_location_path
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList (nt));
+ Steps steps;
+ if ($2 instanceof Steps)
+ {
+ steps = (Steps) $2;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst($2);
+ }
+ steps.path.addFirst(s);
+ steps.path.addFirst(new Root());
+ $$ = steps;
+ //Step step = new Step(s, (Path) $2);
+ //$$ = new Step(new Root(), step);
+ }
+ ;
+
+relative_location_path:
+ step
+ | relative_location_path SLASH step
+ {
+ Steps steps;
+ if ($1 instanceof Steps)
+ {
+ steps = (Steps) $1;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst($1);
+ }
+ steps.path.addLast($3);
+ $$ = steps;
+ //$$ = new Step((Expr) $1, (Path) $3);
+ }
+ | relative_location_path DOUBLE_SLASH step
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList (nt));
+ Steps steps;
+ if ($1 instanceof Steps)
+ {
+ steps = (Steps) $1;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst($1);
+ }
+ steps.path.addLast(s);
+ steps.path.addLast($3);
+ $$ = steps;
+ //Step step = new Step(s, (Path) $3);
+ //$$ = new Step((Expr) $1, step);
+ }
+ ;
+
+step:
+ step_node_test
+ {
+ $$ = new Selector (Selector.CHILD, (List) $1);
+ }
+ | AT step_node_test
+ {
+ $$ = new Selector (Selector.ATTRIBUTE, (List) $2);
+ }
+ | axis_name DOUBLE_COLON step_node_test
+ {
+ $$ = new Selector (((Integer) $1).intValue (), (List) $3);
+ }
+ | DOT
+ {
+ $$ = new Selector (Selector.SELF, Collections.EMPTY_LIST);
+ }
+ | DOUBLE_DOT
+ {
+ $$ = new Selector (Selector.PARENT, Collections.EMPTY_LIST);
+ }
+ ;
+
+step_node_test:
+ node_test
+ {
+ List list = new ArrayList();
+ list.add($1);
+ $$ = list;
+ }
+ | step_node_test predicate
+ {
+ List list = (List)$1;
+ list.add($2);
+ $$ = list;
+ }
+ ;
+
+/*predicate_list:
+ predicate
+ {
+ List list = new ArrayList ();
+ list.add ($1);
+ $$ = list;
+ }
+ | predicate predicate_list
+ {
+ List list = (List) $3;
+ list.add (0, $1);
+ $$ = list;
+ }
+ ;*/
+
+axis_name:
+ ANCESTOR
+ {
+ $$ = new Integer(Selector.ANCESTOR);
+ }
+ | ANCESTOR_OR_SELF
+ {
+ $$ = new Integer(Selector.ANCESTOR_OR_SELF);
+ }
+ | ATTRIBUTE
+ {
+ $$ = new Integer(Selector.ATTRIBUTE);
+ }
+ | CHILD
+ {
+ $$ = new Integer(Selector.CHILD);
+ }
+ | DESCENDANT
+ {
+ $$ = new Integer(Selector.DESCENDANT);
+ }
+ | DESCENDANT_OR_SELF
+ {
+ $$ = new Integer(Selector.DESCENDANT_OR_SELF);
+ }
+ | FOLLOWING
+ {
+ $$ = new Integer(Selector.FOLLOWING);
+ }
+ | FOLLOWING_SIBLING
+ {
+ $$ = new Integer(Selector.FOLLOWING_SIBLING);
+ }
+ | NAMESPACE
+ {
+ $$ = new Integer(Selector.NAMESPACE);
+ }
+ | PARENT
+ {
+ $$ = new Integer(Selector.PARENT);
+ }
+ | PRECEDING
+ {
+ $$ = new Integer(Selector.PRECEDING);
+ }
+ | PRECEDING_SIBLING
+ {
+ $$ = new Integer(Selector.PRECEDING_SIBLING);
+ }
+ | SELF
+ {
+ $$ = new Integer(Selector.SELF);
+ }
+ ;
+
+node_test:
+ name_test
+ /*| PROCESSING_INSTRUCTION LP LITERAL RP*/
+ | PROCESSING_INSTRUCTION LITERAL RP
+ {
+ $$ = new NodeTypeTest(Node.PROCESSING_INSTRUCTION_NODE, (String) $2);
+ }
+ /*| node_type LP RP*/
+ | node_type RP
+ {
+ $$ = new NodeTypeTest(((Short) $1).shortValue());
+ }
+ ;
+
+predicate:
+ LB expr RB
+ {
+ $$ = new Predicate((Expr) $2);
+ }
+ ;
+
+primary_expr:
+ variable_reference
+ | LP expr RP
+ {
+ $$ = new ParenthesizedExpr((Expr) $2);
+ }
+ | LITERAL
+ {
+ $$ = new Constant($1);
+ }
+ | number
+ {
+ $$ = new Constant($1);
+ }
+ | function_call
+ ;
+
+function_call:
+ function_name LP RP
+ {
+ $$ = lookupFunction((String) $1, Collections.EMPTY_LIST);
+ }
+ | function_name LP argument_list RP
+ {
+ $$ = lookupFunction((String) $1, (List) $3);
+ }
+ ;
+
+argument_list:
+ expr
+ {
+ List list = new ArrayList();
+ list.add($1);
+ $$ = list;
+ }
+ | expr COMMA argument_list
+ {
+ List list = (List) $3;
+ list.add(0, $1);
+ $$ = list;
+ }
+ ;
+
+union_expr:
+ path_expr
+ | union_expr PIPE path_expr
+ {
+ $$ = new UnionExpr((Expr) $1, (Expr) $3);
+ }
+ ;
+
+path_expr:
+ location_path
+ | filter_expr
+ | filter_expr SLASH relative_location_path
+ {
+ Steps steps;
+ if ($3 instanceof Steps)
+ {
+ steps = (Steps) $3;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst($3);
+ }
+ steps.path.addFirst($1);
+ $$ = steps;
+ //$$ = new Step ((Expr) $1, (Path) $3);
+ }
+ | filter_expr DOUBLE_SLASH relative_location_path
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList(nt));
+ Steps steps;
+ if ($3 instanceof Steps)
+ {
+ steps = (Steps) $3;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst($3);
+ }
+ steps.path.addFirst(s);
+ steps.path.addFirst($1);
+ $$ = steps;
+ //Step step = new Step (s, (Path) $3);
+ //$$ = new Step ((Expr) $1, step);
+ }
+ ;
+
+filter_expr:
+ primary_expr
+ | filter_expr predicate
+ {
+ Predicate filter = (Predicate) $2;
+ Selector s = new Selector(Selector.SELF,
+ Collections.singletonList(filter));
+ Steps steps;
+ if ($1 instanceof Steps)
+ {
+ steps = (Steps) $1;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst($1);
+ }
+ steps.path.addLast(s);
+ $$ = steps;
+ //$$ = new Step ((Expr) $1, s);
+ }
+ ;
+
+or_expr:
+ and_expr
+ | or_expr OR and_expr
+ {
+ $$ = new OrExpr((Expr) $1, (Expr) $3);
+ }
+ ;
+
+and_expr:
+ equality_expr
+ | and_expr AND equality_expr
+ {
+ $$ = new AndExpr((Expr) $1, (Expr) $3);
+ }
+ ;
+
+equality_expr:
+ relational_expr
+ | equality_expr EQ relational_expr
+ {
+ $$ = new EqualityExpr((Expr) $1, (Expr) $3, false);
+ }
+ | equality_expr NE relational_expr
+ {
+ $$ = new EqualityExpr((Expr) $1, (Expr) $3, true);
+ }
+ ;
+
+relational_expr:
+ additive_expr
+ | relational_expr LT additive_expr
+ {
+ $$ = new RelationalExpr((Expr) $1, (Expr) $3, true, false);
+ }
+ | relational_expr GT additive_expr
+ {
+ $$ = new RelationalExpr((Expr) $1, (Expr) $3, false, false);
+ }
+ | relational_expr LTE additive_expr
+ {
+ $$ = new RelationalExpr((Expr) $1, (Expr) $3, true, true);
+ }
+ | relational_expr GTE additive_expr
+ {
+ $$ = new RelationalExpr((Expr) $1, (Expr) $3, false, true);
+ }
+ ;
+
+additive_expr:
+ multiplicative_expr
+ | additive_expr PLUS multiplicative_expr
+ {
+ $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.ADD);
+ }
+ | additive_expr MINUS multiplicative_expr
+ {
+ $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.SUBTRACT);
+ }
+ ;
+
+multiplicative_expr:
+ unary_expr
+ | multiplicative_expr STAR unary_expr
+ {
+ $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.MULTIPLY);
+ }
+ | multiplicative_expr DIV unary_expr
+ {
+ $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.DIVIDE);
+ }
+ | multiplicative_expr MOD unary_expr
+ {
+ $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.MODULO);
+ }
+ ;
+
+unary_expr:
+ union_expr
+ | MINUS unary_expr %prec UNARY
+ {
+ $$ = new NegativeExpr((Expr) $2);
+ }
+ ;
+
+number:
+ DIGITS
+ {
+ $$ = new Double((String) $1 + ".0");
+ }
+ | DIGITS DOT
+ {
+ $$ = new Double((String) $1 + ".0");
+ }
+ | DIGITS DOT DIGITS
+ {
+ $$ = new Double((String) $1 + "." + (String) $3);
+ }
+ | DOT DIGITS
+ {
+ $$ = new Double("0." + (String) $2);
+ }
+ ;
+
+function_name:
+ qname
+/* | node_type
+ {
+ switch (((Short) $1).shortValue ())
+ {
+ case Node.COMMENT_NODE:
+ $$ = "comment";
+ break;
+ case Node.TEXT_NODE:
+ $$ = "text";
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ $$ = "processing-instruction";
+ break;
+ default:
+ $$ = "node";
+ break;
+ }
+ }*/
+ ;
+
+variable_reference:
+ DOLLAR qname
+ {
+ String name = (String) $2;
+ $$ = new VariableReference(variableResolver, getQName(name));
+ }
+ ;
+
+name_test:
+ STAR
+ {
+ $$ = new NameTest(null, true, true);
+ }
+ | NAME COLON STAR
+ {
+ QName qName = getQName((String) $1);
+ $$ = new NameTest(qName, true, false);
+ }
+ | qname
+ {
+ QName qName = getQName((String) $1);
+ $$ = new NameTest(qName, false, false);
+ }
+ ;
+
+qname:
+ NAME
+ | NAME COLON NAME
+ {
+ $$ = (String) $1 + ':' + (String) $3;
+ }
+ ;
+
+node_type:
+ COMMENT
+ {
+ $$ = new Short(Node.COMMENT_NODE);
+ }
+ | TEXT
+ {
+ $$ = new Short(Node.TEXT_NODE);
+ }
+ | PROCESSING_INSTRUCTION
+ {
+ $$ = new Short(Node.PROCESSING_INSTRUCTION_NODE);
+ }
+ | NODE
+ {
+ $$ = new Short((short) 0);
+ }
+ ;
+
+%%
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/XPathTokenizer.java b/libjava/classpath/gnu/xml/xpath/XPathTokenizer.java
new file mode 100644
index 0000000..a287137
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/XPathTokenizer.java
@@ -0,0 +1,592 @@
+/* XPathTokenizer.java --
+ Copyright (C) 2004 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 gnu.xml.xpath;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Map;
+import java.util.TreeMap;
+
+/*import antlr.Token;
+import antlr.TokenStream;
+import antlr.TokenStreamException;
+import antlr.TokenStreamIOException;*/
+
+/**
+ * XPath 1.0 expression tokenizer.
+ *
+ * @author Chris Burdess
+ */
+public class XPathTokenizer
+implements XPathParser.yyInput
+//implements TokenStream
+{
+
+ static class XPathToken
+ //extends Token
+ {
+
+ int type;
+ String val;
+
+ XPathToken (int type)
+ {
+ this (type, null);
+ }
+
+ XPathToken (int type, String val)
+ {
+ //super (type);
+ this.type = type;
+ this.val = val;
+ }
+
+ public String getText ()
+ {
+ return val;
+ }
+
+ public String toString ()
+ {
+ return val;
+ }
+
+ }
+
+ static final Map keywords = new TreeMap ();
+ static
+ {
+ keywords.put ("ancestor", new Integer (XPathParser.ANCESTOR));
+ keywords.put ("ancestor-or-self", new Integer (XPathParser.ANCESTOR_OR_SELF));
+ keywords.put ("attribute", new Integer (XPathParser.ATTRIBUTE));
+ keywords.put ("child", new Integer (XPathParser.CHILD));
+ keywords.put ("descendant", new Integer (XPathParser.DESCENDANT));
+ keywords.put ("descendant-or-self", new Integer (XPathParser.DESCENDANT_OR_SELF));
+ keywords.put ("following", new Integer (XPathParser.FOLLOWING));
+ keywords.put ("following-sibling", new Integer (XPathParser.FOLLOWING_SIBLING));
+ keywords.put ("namespace", new Integer (XPathParser.NAMESPACE));
+ keywords.put ("parent", new Integer (XPathParser.PARENT));
+ keywords.put ("preceding", new Integer (XPathParser.PRECEDING));
+ keywords.put ("preceding-sibling", new Integer (XPathParser.PRECEDING_SIBLING));
+ keywords.put ("self", new Integer (XPathParser.SELF));
+ keywords.put ("div", new Integer (XPathParser.DIV));
+ keywords.put ("mod", new Integer (XPathParser.MOD));
+ keywords.put ("or", new Integer (XPathParser.OR));
+ keywords.put ("and", new Integer (XPathParser.AND));
+ keywords.put ("comment", new Integer (XPathParser.COMMENT));
+ keywords.put ("processing-instruction", new Integer (XPathParser.PROCESSING_INSTRUCTION));
+ keywords.put ("text", new Integer (XPathParser.TEXT));
+ keywords.put ("node", new Integer (XPathParser.NODE));
+ }
+
+ Reader in;
+ XPathToken token;
+ XPathToken lastToken;
+
+ public XPathTokenizer (String expr)
+ {
+ this (new StringReader (expr));
+ }
+
+ XPathTokenizer (Reader in)
+ {
+ this.in = in.markSupported () ? in : new BufferedReader (in);
+ }
+
+ /* Begin ANTLR specific *
+
+ public Token nextToken ()
+ throws TokenStreamException
+ {
+ try
+ {
+ if (!advance ())
+ {
+ throw new TokenStreamException ("eof");
+ }
+ token ();
+ return token;
+ }
+ catch (IOException e)
+ {
+ throw new TokenStreamIOException (e);
+ }
+ }
+
+ * End ANTLR specific */
+
+ public boolean advance ()
+ throws IOException
+ {
+ lastToken = token;
+ int c = in.read ();
+ switch (c)
+ {
+ case -1: // eof
+ return false;
+ case 0x20:
+ case 0x09:
+ case 0x0d:
+ case 0x0a: // skip whitespace
+ return advance ();
+ case 0x22: // "
+ case 0x27: // '
+ token = consume_literal (c);
+ break;
+ case 0x28: // (
+ token = new XPathToken (XPathParser.LP);
+ break;
+ case 0x29: // )
+ token = new XPathToken (XPathParser.RP);
+ break;
+ case 0x5b: // [
+ token = new XPathToken (XPathParser.LB);
+ break;
+ case 0x5d: // ]
+ token = new XPathToken (XPathParser.RB);
+ break;
+ case 0x2c: // ,
+ token = new XPathToken (XPathParser.COMMA);
+ break;
+ case 0x7c: // |
+ token = new XPathToken (XPathParser.PIPE);
+ break;
+ case 0x2f: // /
+ in.mark (1);
+ int d1 = in.read ();
+ if (d1 == 0x2f)
+ {
+ token = new XPathToken (XPathParser.DOUBLE_SLASH);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.SLASH);
+ }
+ break;
+ case 0x3d: // =
+ token = new XPathToken (XPathParser.EQ);
+ break;
+ case 0x21: // !
+ in.mark (1);
+ int d2 = in.read ();
+ if (d2 == 0x3d) // =
+ {
+ token = new XPathToken (XPathParser.NE);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.yyErrorCode);
+ }
+ break;
+ case 0x3e: // >
+ in.mark (1);
+ int d3 = in.read ();
+ if (d3 == 0x3d) // =
+ {
+ token = new XPathToken (XPathParser.GTE);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.GT);
+ }
+ break;
+ case 0x3c: // <
+ in.mark (1);
+ int d4 = in.read ();
+ if (d4 == 0x3d) // =
+ {
+ token = new XPathToken (XPathParser.LTE);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.LT);
+ }
+ break;
+ case 0x2b: // +
+ token = new XPathToken (XPathParser.PLUS);
+ break;
+ case 0x2d: // -
+ token = new XPathToken (XPathParser.MINUS);
+ break;
+ case 0x40: // @
+ token = new XPathToken (XPathParser.AT);
+ break;
+ case 0x2a: // *
+ token = new XPathToken (XPathParser.STAR);
+ break;
+ case 0x24: // $
+ token = new XPathToken (XPathParser.DOLLAR);
+ break;
+ case 0x3a: // :
+ in.mark (1);
+ int d5 = in.read ();
+ if (d5 == 0x3a)
+ {
+ token = new XPathToken (XPathParser.DOUBLE_COLON);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.COLON);
+ }
+ break;
+ case 0x2e: // .
+ in.mark (1);
+ int d6 = in.read ();
+ if (d6 == 0x2e)
+ {
+ token = new XPathToken (XPathParser.DOUBLE_DOT);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.DOT);
+ }
+ break;
+ default:
+ if (c >= 0x30 && c <= 0x39)
+ {
+ token = consume_digits (c);
+ }
+ else if (c == 0x5f || Character.isLetter ((char) c))
+ {
+ token = consume_name (c);
+ }
+ else
+ {
+ token = new XPathToken (XPathParser.yyErrorCode);
+ }
+ }
+ return true;
+ }
+
+ public int token ()
+ {
+ return token.type;
+ }
+
+ public Object value ()
+ {
+ return token.val;
+ }
+
+ XPathToken consume_literal (int delimiter)
+ throws IOException
+ {
+ StringBuffer buf = new StringBuffer ();
+ while (true)
+ {
+ int c = in.read ();
+ if (c == -1)
+ {
+ return new XPathToken (XPathParser.yyErrorCode);
+ }
+ else if (c == delimiter)
+ {
+ return new XPathToken (XPathParser.LITERAL, buf.toString ());
+ }
+ else
+ {
+ buf.append ((char) c);
+ }
+ }
+ }
+
+ XPathToken consume_digits (int c)
+ throws IOException
+ {
+ StringBuffer buf = new StringBuffer ();
+ buf.append ((char) c);
+ while (true)
+ {
+ in.mark (1);
+ c = in.read ();
+ if (c >= 0x30 && c <= 0x39)
+ {
+ buf.append ((char) c);
+ }
+ else
+ {
+ in.reset ();
+ return new XPathToken (XPathParser.DIGITS, buf.toString ());
+ }
+ }
+ }
+
+ XPathToken consume_name (int c)
+ throws IOException
+ {
+ StringBuffer buf = new StringBuffer ();
+ buf.append ((char) c);
+ while (true)
+ {
+ in.mark (1);
+ c = in.read ();
+ if (isNameChar (c))
+ {
+ buf.append ((char) c);
+ }
+ else
+ {
+ in.reset ();
+ String name = buf.toString ();
+ Integer keyword = (Integer) keywords.get (name);
+ if (keyword == null)
+ {
+ return new XPathToken (XPathParser.NAME, name);
+ }
+ else
+ {
+ int val = keyword.intValue ();
+ switch (val)
+ {
+ case XPathParser.NODE:
+ case XPathParser.COMMENT:
+ case XPathParser.TEXT:
+ case XPathParser.PROCESSING_INSTRUCTION:
+ // Consume subsequent (
+ in.mark (1);
+ do
+ {
+ c = in.read ();
+ }
+ while (c == 0x20 || c == 0x09);
+ if (c != 0x28)
+ {
+ in.reset ();
+ return new XPathToken (XPathParser.NAME, name);
+ }
+ break;
+ case XPathParser.CHILD:
+ case XPathParser.PARENT:
+ case XPathParser.SELF:
+ case XPathParser.DESCENDANT:
+ case XPathParser.ANCESTOR:
+ case XPathParser.DESCENDANT_OR_SELF:
+ case XPathParser.ANCESTOR_OR_SELF:
+ case XPathParser.ATTRIBUTE:
+ case XPathParser.NAMESPACE:
+ case XPathParser.FOLLOWING:
+ case XPathParser.FOLLOWING_SIBLING:
+ case XPathParser.PRECEDING:
+ case XPathParser.PRECEDING_SIBLING:
+ // Check that this is an axis specifier
+ in.mark(1);
+ do
+ {
+ c = in.read();
+ }
+ while (c == 0x20 || c == 0x09);
+ if (c == 0x3a)
+ {
+ c = in.read();
+ if (c == 0x3a)
+ {
+ in.reset();
+ return new XPathToken(val);
+ }
+ }
+ in.reset();
+ return new XPathToken(XPathParser.NAME, name);
+ case XPathParser.DIV:
+ case XPathParser.MOD:
+ // May be a name
+ if (lastToken == null)
+ {
+ return new XPathToken(XPathParser.NAME, name);
+ }
+ switch (lastToken.type)
+ {
+ case XPathParser.LP:
+ case XPathParser.LB:
+ case XPathParser.COMMA:
+ case XPathParser.PIPE:
+ case XPathParser.EQ:
+ case XPathParser.NE:
+ case XPathParser.GT:
+ case XPathParser.LT:
+ case XPathParser.GTE:
+ case XPathParser.LTE:
+ case XPathParser.PLUS:
+ case XPathParser.MINUS:
+ case XPathParser.STAR:
+ case XPathParser.AT:
+ case XPathParser.DOLLAR:
+ case XPathParser.COLON:
+ case XPathParser.DOUBLE_COLON:
+ case XPathParser.DIV:
+ case XPathParser.MOD:
+ case XPathParser.OR:
+ case XPathParser.AND:
+ case XPathParser.SLASH:
+ return new XPathToken(XPathParser.NAME, name);
+ }
+ break;
+ }
+ return new XPathToken (val);
+ }
+ }
+ }
+ }
+
+ boolean isNameChar (int c)
+ {
+ /* Name */
+ return (c == 0x5f
+ || c == 0x2d
+ || c == 0x2e
+ || (c >= 0x30 && c <= 0x39)
+ /* CombiningChar */
+ || (c >= 0x0300 && c <= 0x0345)
+ || (c >= 0x0360 && c <= 0x0361)
+ || (c >= 0x0483 && c <= 0x0486)
+ || (c >= 0x0591 && c <= 0x05A1)
+ || (c >= 0x05A3 && c <= 0x05B9)
+ || (c >= 0x05BB && c <= 0x05BD)
+ || c == 0x05BF
+ || (c >= 0x05C1 && c <= 0x05C2)
+ || c == 0x05C4
+ || (c >= 0x064B && c <= 0x0652)
+ || c == 0x0670
+ || (c >= 0x06D6 && c <= 0x06DC)
+ || (c >= 0x06DD && c <= 0x06DF)
+ || (c >= 0x06E0 && c <= 0x06E4)
+ || (c >= 0x06E7 && c <= 0x06E8)
+ || (c >= 0x06EA && c <= 0x06ED)
+ || (c >= 0x0901 && c <= 0x0903)
+ || c == 0x093C
+ || (c >= 0x093E && c <= 0x094C)
+ || c == 0x094D
+ || (c >= 0x0951 && c <= 0x0954)
+ || (c >= 0x0962 && c <= 0x0963)
+ || (c >= 0x0981 && c <= 0x0983)
+ || c == 0x09BC
+ || c == 0x09BE
+ || c == 0x09BF
+ || (c >= 0x09C0 && c <= 0x09C4)
+ || (c >= 0x09C7 && c <= 0x09C8)
+ || (c >= 0x09CB && c <= 0x09CD)
+ || c == 0x09D7
+ || (c >= 0x09E2 && c <= 0x09E3)
+ || c == 0x0A02
+ || c == 0x0A3C
+ || c == 0x0A3E
+ || c == 0x0A3F
+ || (c >= 0x0A40 && c <= 0x0A42)
+ || (c >= 0x0A47 && c <= 0x0A48)
+ || (c >= 0x0A4B && c <= 0x0A4D)
+ || (c >= 0x0A70 && c <= 0x0A71)
+ || (c >= 0x0A81 && c <= 0x0A83)
+ || c == 0x0ABC
+ || (c >= 0x0ABE && c <= 0x0AC5)
+ || (c >= 0x0AC7 && c <= 0x0AC9)
+ || (c >= 0x0ACB && c <= 0x0ACD)
+ || (c >= 0x0B01 && c <= 0x0B03)
+ || c == 0x0B3C
+ || (c >= 0x0B3E && c <= 0x0B43)
+ || (c >= 0x0B47 && c <= 0x0B48)
+ || (c >= 0x0B4B && c <= 0x0B4D)
+ || (c >= 0x0B56 && c <= 0x0B57)
+ || (c >= 0x0B82 && c <= 0x0B83)
+ || (c >= 0x0BBE && c <= 0x0BC2)
+ || (c >= 0x0BC6 && c <= 0x0BC8)
+ || (c >= 0x0BCA && c <= 0x0BCD)
+ || c == 0x0BD7
+ || (c >= 0x0C01 && c <= 0x0C03)
+ || (c >= 0x0C3E && c <= 0x0C44)
+ || (c >= 0x0C46 && c <= 0x0C48)
+ || (c >= 0x0C4A && c <= 0x0C4D)
+ || (c >= 0x0C55 && c <= 0x0C56)
+ || (c >= 0x0C82 && c <= 0x0C83)
+ || (c >= 0x0CBE && c <= 0x0CC4)
+ || (c >= 0x0CC6 && c <= 0x0CC8)
+ || (c >= 0x0CCA && c <= 0x0CCD)
+ || (c >= 0x0CD5 && c <= 0x0CD6)
+ || (c >= 0x0D02 && c <= 0x0D03)
+ || (c >= 0x0D3E && c <= 0x0D43)
+ || (c >= 0x0D46 && c <= 0x0D48)
+ || (c >= 0x0D4A && c <= 0x0D4D)
+ || c == 0x0D57
+ || c == 0x0E31
+ || (c >= 0x0E34 && c <= 0x0E3A)
+ || (c >= 0x0E47 && c <= 0x0E4E)
+ || c == 0x0EB1
+ || (c >= 0x0EB4 && c <= 0x0EB9)
+ || (c >= 0x0EBB && c <= 0x0EBC)
+ || (c >= 0x0EC8 && c <= 0x0ECD)
+ || (c >= 0x0F18 && c <= 0x0F19)
+ || c == 0x0F35
+ || c == 0x0F37
+ || c == 0x0F39
+ || c == 0x0F3E
+ || c == 0x0F3F
+ || (c >= 0x0F71 && c <= 0x0F84)
+ || (c >= 0x0F86 && c <= 0x0F8B)
+ || (c >= 0x0F90 && c <= 0x0F95)
+ || c == 0x0F97
+ || (c >= 0x0F99 && c <= 0x0FAD)
+ || (c >= 0x0FB1 && c <= 0x0FB7)
+ || c == 0x0FB9
+ || (c >= 0x20D0 && c <= 0x20DC)
+ || c == 0x20E1
+ || (c >= 0x302A && c <= 0x302F)
+ || c == 0x3099
+ || c == 0x309A
+ /* Extender */
+ || c == 0x00B7
+ || c == 0x02D0
+ || c == 0x02D1
+ || c == 0x0387
+ || c == 0x0640
+ || c == 0x0E46
+ || c == 0x0EC6
+ || c == 0x3005
+ || (c >= 0x3031 && c <= 0x3035)
+ || (c >= 0x309D && c <= 0x309E)
+ || (c >= 0x30FC && c <= 0x30FE)
+ /* Name */
+ || Character.isLetter ((char) c));
+ }
+
+}
--
cgit v1.1