summaryrefslogtreecommitdiff
path: root/libjava/classpath/java/io
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/java/io
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libjava/classpath/java/io')
-rw-r--r--libjava/classpath/java/io/BufferedInputStream.java379
-rw-r--r--libjava/classpath/java/io/BufferedOutputStream.java191
-rw-r--r--libjava/classpath/java/io/BufferedReader.java575
-rw-r--r--libjava/classpath/java/io/BufferedWriter.java262
-rw-r--r--libjava/classpath/java/io/ByteArrayInputStream.java251
-rw-r--r--libjava/classpath/java/io/ByteArrayOutputStream.java284
-rw-r--r--libjava/classpath/java/io/CharArrayReader.java305
-rw-r--r--libjava/classpath/java/io/CharArrayWriter.java352
-rw-r--r--libjava/classpath/java/io/CharConversionException.java73
-rw-r--r--libjava/classpath/java/io/Closeable.java63
-rw-r--r--libjava/classpath/java/io/DataInput.java456
-rw-r--r--libjava/classpath/java/io/DataInputStream.java785
-rw-r--r--libjava/classpath/java/io/DataOutput.java325
-rw-r--r--libjava/classpath/java/io/DataOutputStream.java539
-rw-r--r--libjava/classpath/java/io/DeleteFileHelper.java106
-rw-r--r--libjava/classpath/java/io/EOFException.java76
-rw-r--r--libjava/classpath/java/io/Externalizable.java107
-rw-r--r--libjava/classpath/java/io/File.java1605
-rw-r--r--libjava/classpath/java/io/FileDescriptor.java140
-rw-r--r--libjava/classpath/java/io/FileFilter.java65
-rw-r--r--libjava/classpath/java/io/FileInputStream.java322
-rw-r--r--libjava/classpath/java/io/FileNotFoundException.java73
-rw-r--r--libjava/classpath/java/io/FileOutputStream.java309
-rw-r--r--libjava/classpath/java/io/FilePermission.java293
-rw-r--r--libjava/classpath/java/io/FileReader.java91
-rw-r--r--libjava/classpath/java/io/FileWriter.java137
-rw-r--r--libjava/classpath/java/io/FilenameFilter.java75
-rw-r--r--libjava/classpath/java/io/FilterInputStream.java203
-rw-r--r--libjava/classpath/java/io/FilterOutputStream.java149
-rw-r--r--libjava/classpath/java/io/FilterReader.java184
-rw-r--r--libjava/classpath/java/io/FilterWriter.java146
-rw-r--r--libjava/classpath/java/io/Flushable.java62
-rw-r--r--libjava/classpath/java/io/IOException.java74
-rw-r--r--libjava/classpath/java/io/InputStream.java270
-rw-r--r--libjava/classpath/java/io/InputStreamReader.java509
-rw-r--r--libjava/classpath/java/io/InterruptedIOException.java94
-rw-r--r--libjava/classpath/java/io/InvalidClassException.java110
-rw-r--r--libjava/classpath/java/io/InvalidObjectException.java66
-rw-r--r--libjava/classpath/java/io/LineNumberInputStream.java315
-rw-r--r--libjava/classpath/java/io/LineNumberReader.java416
-rw-r--r--libjava/classpath/java/io/NotActiveException.java72
-rw-r--r--libjava/classpath/java/io/NotSerializableException.java74
-rw-r--r--libjava/classpath/java/io/ObjectInput.java140
-rw-r--r--libjava/classpath/java/io/ObjectInputStream.java2142
-rw-r--r--libjava/classpath/java/io/ObjectInputValidation.java67
-rw-r--r--libjava/classpath/java/io/ObjectOutput.java110
-rw-r--r--libjava/classpath/java/io/ObjectOutputStream.java1490
-rw-r--r--libjava/classpath/java/io/ObjectStreamClass.java1161
-rw-r--r--libjava/classpath/java/io/ObjectStreamConstants.java226
-rw-r--r--libjava/classpath/java/io/ObjectStreamException.java74
-rw-r--r--libjava/classpath/java/io/ObjectStreamField.java401
-rw-r--r--libjava/classpath/java/io/OptionalDataException.java91
-rw-r--r--libjava/classpath/java/io/OutputStream.java140
-rw-r--r--libjava/classpath/java/io/OutputStreamWriter.java429
-rw-r--r--libjava/classpath/java/io/PipedInputStream.java413
-rw-r--r--libjava/classpath/java/io/PipedOutputStream.java181
-rw-r--r--libjava/classpath/java/io/PipedReader.java364
-rw-r--r--libjava/classpath/java/io/PipedWriter.java182
-rw-r--r--libjava/classpath/java/io/PrintStream.java675
-rw-r--r--libjava/classpath/java/io/PrintWriter.java689
-rw-r--r--libjava/classpath/java/io/PushbackInputStream.java335
-rw-r--r--libjava/classpath/java/io/PushbackReader.java383
-rw-r--r--libjava/classpath/java/io/RandomAccessFile.java1049
-rw-r--r--libjava/classpath/java/io/Reader.java286
-rw-r--r--libjava/classpath/java/io/SequenceInputStream.java223
-rw-r--r--libjava/classpath/java/io/Serializable.java54
-rw-r--r--libjava/classpath/java/io/SerializablePermission.java112
-rw-r--r--libjava/classpath/java/io/StreamCorruptedException.java73
-rw-r--r--libjava/classpath/java/io/StreamTokenizer.java718
-rw-r--r--libjava/classpath/java/io/StringBufferInputStream.java187
-rw-r--r--libjava/classpath/java/io/StringReader.java208
-rw-r--r--libjava/classpath/java/io/StringWriter.java212
-rw-r--r--libjava/classpath/java/io/SyncFailedException.java66
-rw-r--r--libjava/classpath/java/io/UTFDataFormatException.java74
-rw-r--r--libjava/classpath/java/io/UnsupportedEncodingException.java73
-rw-r--r--libjava/classpath/java/io/WriteAbortedException.java109
-rw-r--r--libjava/classpath/java/io/Writer.java211
-rw-r--r--libjava/classpath/java/io/package.html46
78 files changed, 24377 insertions, 0 deletions
diff --git a/libjava/classpath/java/io/BufferedInputStream.java b/libjava/classpath/java/io/BufferedInputStream.java
new file mode 100644
index 000000000..7013b0948
--- /dev/null
+++ b/libjava/classpath/java/io/BufferedInputStream.java
@@ -0,0 +1,379 @@
+/* BufferedInputStream.java -- An input stream that implements buffering
+ Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * This subclass of <code>FilterInputStream</code> buffers input from an
+ * underlying implementation to provide a possibly more efficient read
+ * mechanism. It maintains the buffer and buffer state in instance
+ * variables that are available to subclasses. The default buffer size
+ * of 2048 bytes can be overridden by the creator of the stream.
+ * <p>
+ * This class also implements mark/reset functionality. It is capable
+ * of remembering any number of input bytes, to the limits of
+ * system memory or the size of <code>Integer.MAX_VALUE</code>
+ * <p>
+ * Please note that this class does not properly handle character
+ * encodings. Consider using the <code>BufferedReader</code> class which
+ * does.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @author Jeroen Frijters (jeroen@frijters.net)
+ */
+public class BufferedInputStream extends FilterInputStream
+{
+
+ /**
+ * This is the default buffer size
+ */
+ private static final int DEFAULT_BUFFER_SIZE = 2048;
+
+ /**
+ * The buffer used for storing data from the underlying stream.
+ */
+ protected byte[] buf;
+
+ /**
+ * The number of valid bytes currently in the buffer. It is also the index
+ * of the buffer position one byte past the end of the valid data.
+ */
+ protected int count;
+
+ /**
+ * The index of the next character that will by read from the buffer.
+ * When <code>pos == count</code>, the buffer is empty.
+ */
+ protected int pos;
+
+ /**
+ * The value of <code>pos</code> when the <code>mark()</code> method was
+ * called.
+ * This is set to -1 if there is no mark set.
+ */
+ protected int markpos = -1;
+
+ /**
+ * This is the maximum number of bytes than can be read after a
+ * call to <code>mark()</code> before the mark can be discarded.
+ * After this may bytes are read, the <code>reset()</code> method
+ * may not be called successfully.
+ */
+ protected int marklimit;
+
+ /**
+ * This is the initial buffer size. When the buffer is grown because
+ * of marking requirements, it will be grown by bufferSize increments.
+ * The underlying stream will be read in chunks of bufferSize.
+ */
+ private final int bufferSize;
+
+ /**
+ * This method initializes a new <code>BufferedInputStream</code> that will
+ * read from the specified subordinate stream with a default buffer size
+ * of 2048 bytes
+ *
+ * @param in The subordinate stream to read from
+ */
+ public BufferedInputStream(InputStream in)
+ {
+ this(in, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * This method initializes a new <code>BufferedInputStream</code> that will
+ * read from the specified subordinate stream with a buffer size that
+ * is specified by the caller.
+ *
+ * @param in The subordinate stream to read from
+ * @param size The buffer size to use
+ *
+ * @exception IllegalArgumentException when size is smaller then 1
+ */
+ public BufferedInputStream(InputStream in, int size)
+ {
+ super(in);
+ if (size <= 0)
+ throw new IllegalArgumentException();
+ buf = new byte[size];
+ // initialize pos & count to bufferSize, to prevent refill from
+ // allocating a new buffer (if the caller starts out by calling mark()).
+ pos = count = bufferSize = size;
+ }
+
+ /**
+ * This method returns the number of bytes that can be read from this
+ * stream before a read can block. A return of 0 indicates that blocking
+ * might (or might not) occur on the very next read attempt.
+ * <p>
+ * The number of available bytes will be the number of read ahead bytes
+ * stored in the internal buffer plus the number of available bytes in
+ * the underlying stream.
+ *
+ * @return The number of bytes that can be read before blocking could occur
+ *
+ * @exception IOException If an error occurs
+ */
+ public synchronized int available() throws IOException
+ {
+ return count - pos + super.available();
+ }
+
+ /**
+ * This method closes the underlying input stream and frees any
+ * resources associated with it. Sets <code>buf</code> to <code>null</code>.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public void close() throws IOException
+ {
+ // Free up the array memory.
+ buf = null;
+ pos = count = 0;
+ markpos = -1;
+ super.close();
+ }
+
+ /**
+ * This method marks a position in the input to which the stream can be
+ * "reset" by calling the <code>reset()</code> method. The parameter
+ * <code>readlimit</code> is the number of bytes that can be read from the
+ * stream after setting the mark before the mark becomes invalid. For
+ * example, if <code>mark()</code> is called with a read limit of 10, then
+ * when 11 bytes of data are read from the stream before the
+ * <code>reset()</code> method is called, then the mark is invalid and the
+ * stream object instance is not required to remember the mark.
+ * <p>
+ * Note that the number of bytes that can be remembered by this method
+ * can be greater than the size of the internal read buffer. It is also
+ * not dependent on the subordinate stream supporting mark/reset
+ * functionality.
+ *
+ * @param readlimit The number of bytes that can be read before the mark
+ * becomes invalid
+ */
+ public synchronized void mark(int readlimit)
+ {
+ marklimit = readlimit;
+ markpos = pos;
+ }
+
+ /**
+ * This method returns <code>true</code> to indicate that this class
+ * supports mark/reset functionality.
+ *
+ * @return <code>true</code> to indicate that mark/reset functionality is
+ * supported
+ *
+ */
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ /**
+ * This method reads an unsigned byte from the input stream and returns it
+ * as an int in the range of 0-255. This method also will return -1 if
+ * the end of the stream has been reached.
+ * <p>
+ * This method will block until the byte can be read.
+ *
+ * @return The byte read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public synchronized int read() throws IOException
+ {
+ if (pos >= count && !refill())
+ return -1; // EOF
+
+ return buf[pos++] & 0xFF;
+ }
+
+ /**
+ * This method reads bytes from a stream and stores them into a caller
+ * supplied buffer. It starts storing the data at index <code>off</code>
+ * into the buffer and attempts to read <code>len</code> bytes. This method
+ * can return before reading the number of bytes requested, but it will try
+ * to read the requested number of bytes by repeatedly calling the underlying
+ * stream as long as available() for this stream continues to return a
+ * non-zero value (or until the requested number of bytes have been read).
+ * The actual number of bytes read is returned as an int. A -1 is returned
+ * to indicate the end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ *
+ * @param b The array into which the bytes read should be stored
+ * @param off The offset into the array 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.
+ *
+ * @exception IOException If an error occurs.
+ * @exception IndexOutOfBoundsException when <code>off</code> or
+ * <code>len</code> are negative, or when <code>off + len</code>
+ * is larger then the size of <code>b</code>,
+ */
+ public synchronized int read(byte[] b, int off, int len) throws IOException
+ {
+ if (off < 0 || len < 0 || b.length - off < len)
+ throw new IndexOutOfBoundsException();
+
+ if (len == 0)
+ return 0;
+
+ if (pos >= count && !refill())
+ return -1; // No bytes were read before EOF.
+
+ int totalBytesRead = Math.min(count - pos, len);
+ System.arraycopy(buf, pos, b, off, totalBytesRead);
+ pos += totalBytesRead;
+ off += totalBytesRead;
+ len -= totalBytesRead;
+
+ while (len > 0 && super.available() > 0 && refill())
+ {
+ int remain = Math.min(count - pos, len);
+ System.arraycopy(buf, pos, b, off, remain);
+ pos += remain;
+ off += remain;
+ len -= remain;
+ totalBytesRead += remain;
+ }
+
+ return totalBytesRead;
+ }
+
+ /**
+ * This method resets a stream to the point where the <code>mark()</code>
+ * method was called. Any bytes that were read after the mark point was
+ * set will be re-read during subsequent reads.
+ * <p>
+ * This method will throw an IOException if the number of bytes read from
+ * the stream since the call to <code>mark()</code> exceeds the mark limit
+ * passed when establishing the mark.
+ *
+ * @exception IOException If <code>mark()</code> was never called or more
+ * then <code>marklimit</code> bytes were read since the last
+ * call to <code>mark()</code>
+ */
+ public synchronized void reset() throws IOException
+ {
+ if (markpos == -1)
+ throw new IOException(buf == null ? "Stream closed." : "Invalid mark.");
+
+ pos = markpos;
+ }
+
+ /**
+ * This method skips the specified number of bytes in the stream. It
+ * returns the actual number of bytes skipped, which may be less than the
+ * requested amount.
+ *
+ * @param n The requested number of bytes to skip
+ *
+ * @return The actual number of bytes skipped.
+ *
+ * @exception IOException If an error occurs
+ */
+ public synchronized long skip(long n) throws IOException
+ {
+ if (buf == null)
+ throw new IOException("Stream closed.");
+
+ final long origN = n;
+
+ while (n > 0L)
+ {
+ if (pos >= count && !refill())
+ break;
+
+ int numread = (int) Math.min((long) (count - pos), n);
+ pos += numread;
+ n -= numread;
+ }
+
+ return origN - n;
+ }
+
+ /**
+ * Called to refill the buffer (when count is equal to pos).
+ *
+ * @return <code>true</code> when at least one additional byte was read
+ * into <code>buf</code>, <code>false</code> otherwise (at EOF).
+ */
+ private boolean refill() throws IOException
+ {
+ if (buf == null)
+ throw new IOException("Stream closed.");
+
+ if (markpos == -1 || count - markpos >= marklimit)
+ {
+ markpos = -1;
+ pos = count = 0;
+ }
+ else
+ {
+ byte[] newbuf = buf;
+ if (markpos < bufferSize)
+ {
+ newbuf = new byte[count - markpos + bufferSize];
+ }
+ System.arraycopy(buf, markpos, newbuf, 0, count - markpos);
+ buf = newbuf;
+ count -= markpos;
+ pos -= markpos;
+ markpos = 0;
+ }
+
+ int numread = super.read(buf, count, bufferSize);
+
+ if (numread <= 0) // EOF
+ return false;
+
+ count += numread;
+ return true;
+ }
+}
diff --git a/libjava/classpath/java/io/BufferedOutputStream.java b/libjava/classpath/java/io/BufferedOutputStream.java
new file mode 100644
index 000000000..e6027cad6
--- /dev/null
+++ b/libjava/classpath/java/io/BufferedOutputStream.java
@@ -0,0 +1,191 @@
+/* BufferedOutputStream.java -- Buffer output into large blocks before writing
+ Copyright (C) 1998, 2000, 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 java.io;
+
+/**
+ * This class accumulates bytes written in a buffer instead of immediately
+ * writing the data to the underlying output sink. The bytes are instead
+ * as one large block when the buffer is filled, or when the stream is
+ * closed or explicitly flushed. This mode operation can provide a more
+ * efficient mechanism for writing versus doing numerous small unbuffered
+ * writes.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class BufferedOutputStream extends FilterOutputStream
+{
+ /**
+ * This is the default buffer size
+ */
+ private static final int DEFAULT_BUFFER_SIZE = 512;
+
+ /**
+ * This is the internal byte array used for buffering output before
+ * writing it.
+ */
+ protected byte[] buf;
+
+ /**
+ * This is the number of bytes that are currently in the buffer and
+ * are waiting to be written to the underlying stream. It always points to
+ * the index into the buffer where the next byte of data will be stored
+ */
+ protected int count;
+
+ /**
+ * This method initializes a new <code>BufferedOutputStream</code> instance
+ * that will write to the specified subordinate <code>OutputStream</code>
+ * and which will use a default buffer size of 512 bytes.
+ *
+ * @param out The underlying <code>OutputStream</code> to write data to
+ */
+ public BufferedOutputStream(OutputStream out)
+ {
+ this(out, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * This method initializes a new <code>BufferedOutputStream</code> instance
+ * that will write to the specified subordinate <code>OutputStream</code>
+ * and which will use the specified buffer size
+ *
+ * @param out The underlying <code>OutputStream</code> to write data to
+ * @param size The size of the internal buffer
+ */
+ public BufferedOutputStream(OutputStream out, int size)
+ {
+ super(out);
+
+ buf = new byte[size];
+ }
+
+ /**
+ * This method causes any currently buffered bytes to be immediately
+ * written to the underlying output stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ public synchronized void flush() throws IOException
+ {
+ if (count == 0)
+ return;
+
+ out.write(buf, 0, count);
+ count = 0;
+ out.flush();
+ }
+
+ /**
+ * This method flushes any remaining buffered bytes then closes the
+ * underlying output stream. Any further attempts to write to this stream
+ * may throw an exception
+ *
+ public synchronized void close() throws IOException
+ {
+ flush();
+ out.close();
+ }
+ */
+
+ /**
+ * This method runs when the object is garbage collected. It is
+ * responsible for ensuring that all buffered bytes are written and
+ * for closing the underlying stream.
+ *
+ * @exception IOException If an error occurs (ignored by the Java runtime)
+ *
+ protected void finalize() throws IOException
+ {
+ close();
+ }
+ */
+
+ /**
+ * This method writes a single byte of data. This will be written to the
+ * buffer instead of the underlying data source. However, if the buffer
+ * is filled as a result of this write request, it will be flushed to the
+ * underlying output stream.
+ *
+ * @param b The byte of data to be written, passed as an int
+ *
+ * @exception IOException If an error occurs
+ */
+ public synchronized void write(int b) throws IOException
+ {
+ if (count == buf.length)
+ flush();
+
+ buf[count] = (byte)(b & 0xFF);
+ ++count;
+ }
+
+ /**
+ * This method writes <code>len</code> bytes from the byte array
+ * <code>buf</code> starting at position <code>offset</code> in the buffer.
+ * These bytes will be written to the internal buffer. However, if this
+ * write operation fills the buffer, the buffer will be flushed to the
+ * underlying output stream.
+ *
+ * @param buf The array of bytes to write.
+ * @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
+ {
+ // Buffer can hold everything. Note that the case where LEN < 0
+ // is automatically handled by the downstream write.
+ if (len < (this.buf.length - count))
+ {
+ System.arraycopy(buf, offset, this.buf, count, len);
+ count += len;
+ }
+ else
+ {
+ // The write was too big. So flush the buffer and write the new
+ // bytes directly to the underlying stream, per the JDK 1.2
+ // docs.
+ flush();
+ out.write (buf, offset, len);
+ }
+ }
+
+} // class BufferedOutputStream
diff --git a/libjava/classpath/java/io/BufferedReader.java b/libjava/classpath/java/io/BufferedReader.java
new file mode 100644
index 000000000..868fa3a94
--- /dev/null
+++ b/libjava/classpath/java/io/BufferedReader.java
@@ -0,0 +1,575 @@
+/* BufferedReader.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 java.io;
+
+import gnu.java.lang.CPStringBuilder;
+
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * This subclass of <code>FilterReader</code> buffers input from an
+ * underlying implementation to provide a possibly more efficient read
+ * mechanism. It maintains the buffer and buffer state in instance
+ * variables that are available to subclasses. The default buffer size
+ * of 8192 chars can be overridden by the creator of the stream.
+ * <p>
+ * This class also implements mark/reset functionality. It is capable
+ * of remembering any number of input chars, to the limits of
+ * system memory or the size of <code>Integer.MAX_VALUE</code>
+ *
+ * @author Per Bothner (bothner@cygnus.com)
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class BufferedReader extends Reader
+{
+ Reader in;
+ char[] buffer;
+ /* Index of current read position. Must be >= 0 and <= limit. */
+ /* There is a special case where pos may be equal to limit+1; this
+ * is used as an indicator that a readLine was done with a '\r' was
+ * the very last char in the buffer. Since we don't want to read-ahead
+ * and potentially block, we set pos this way to indicate the situation
+ * and deal with it later. Doing it this way rather than having a
+ * separate boolean field to indicate the condition has the advantage
+ * that it is self-clearing on things like mark/reset.
+ */
+ int pos;
+ /* Limit of valid data in buffer. Must be >= pos and <= buffer.length. */
+ /* This can be < pos in the one special case described above. */
+ int limit;
+
+ /* The value -1 means there is no mark, or the mark has been invalidated.
+ Otherwise, markPos is the index in the buffer of the marked position.
+ Must be >= 0 and <= pos.
+ Note we do not explicitly store the read-limit.
+ The implicit read-limit is (buffer.length - markPos), which is
+ guaranteed to be >= the read-limit requested in the call to mark. */
+ int markPos = -1;
+
+ // The JCL book specifies the default buffer size as 8K characters.
+ // This is package-private because it is used by LineNumberReader.
+ static final int DEFAULT_BUFFER_SIZE = 8192;
+
+ /**
+ * Create a new <code>BufferedReader</code> that will read from the
+ * specified subordinate stream with a default buffer size of 8192 chars.
+ *
+ * @param in The subordinate stream to read from
+ */
+ public BufferedReader(Reader in)
+ {
+ this(in, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * Create a new <code>BufferedReader</code> that will read from the
+ * specified subordinate stream with a buffer size that is specified by the
+ * caller.
+ *
+ * @param in The subordinate stream to read from
+ * @param size The buffer size to use
+ *
+ * @exception IllegalArgumentException if size &lt;= 0
+ */
+ public BufferedReader(Reader in, int size)
+ {
+ super(in.lock);
+ if (size <= 0)
+ throw new IllegalArgumentException("Illegal buffer size: " + size);
+ this.in = in;
+ buffer = new char[size];
+ }
+
+ /**
+ * This method closes the underlying stream and frees any associated
+ * resources.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (in != null)
+ in.close();
+ in = null;
+ buffer = null;
+ }
+ }
+
+ /**
+ * Returns <code>true</code> to indicate that this class supports mark/reset
+ * functionality.
+ *
+ * @return <code>true</code>
+ */
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ /**
+ * Mark a position in the input to which the stream can be
+ * "reset" by calling the <code>reset()</code> method. The parameter
+ * <code>readLimit</code> is the number of chars that can be read from the
+ * stream after setting the mark before the mark becomes invalid. For
+ * example, if <code>mark()</code> is called with a read limit of 10, then
+ * when 11 chars of data are read from the stream before the
+ * <code>reset()</code> method is called, then the mark is invalid and the
+ * stream object instance is not required to remember the mark.
+ * <p>
+ * Note that the number of chars that can be remembered by this method
+ * can be greater than the size of the internal read buffer. It is also
+ * not dependent on the subordinate stream supporting mark/reset
+ * functionality.
+ *
+ * @param readLimit The number of chars that can be read before the mark
+ * becomes invalid
+ *
+ * @exception IOException If an error occurs
+ * @exception IllegalArgumentException if readLimit is negative.
+ */
+ public void mark(int readLimit) throws IOException
+ {
+ if (readLimit < 0)
+ throw new IllegalArgumentException("Read-ahead limit is negative");
+
+ synchronized (lock)
+ {
+ checkStatus();
+ // In this method we need to be aware of the special case where
+ // pos + 1 == limit. This indicates that a '\r' was the last char
+ // in the buffer during a readLine. We'll want to maintain that
+ // condition after we shift things around and if a larger buffer is
+ // needed to track readLimit, we'll have to make it one element
+ // larger to ensure we don't invalidate the mark too early, if the
+ // char following the '\r' is NOT a '\n'. This is ok because, per
+ // the spec, we are not required to invalidate when passing readLimit.
+ //
+ // Note that if 'pos > limit', then doing 'limit -= pos' will cause
+ // limit to be negative. This is the only way limit will be < 0.
+
+ if (pos + readLimit > limit)
+ {
+ char[] old_buffer = buffer;
+ int extraBuffSpace = 0;
+ if (pos > limit)
+ extraBuffSpace = 1;
+ if (readLimit + extraBuffSpace > limit)
+ buffer = new char[readLimit + extraBuffSpace];
+ limit -= pos;
+ if (limit >= 0)
+ {
+ System.arraycopy(old_buffer, pos, buffer, 0, limit);
+ pos = 0;
+ }
+ }
+
+ if (limit < 0)
+ {
+ // Maintain the relationship of 'pos > limit'.
+ pos = 1;
+ limit = markPos = 0;
+ }
+ else
+ markPos = pos;
+ // Now pos + readLimit <= buffer.length. thus if we need to read
+ // beyond buffer.length, then we are allowed to invalidate markPos.
+ }
+ }
+
+ /**
+ * Reset the stream to the point where the <code>mark()</code> method
+ * was called. Any chars that were read after the mark point was set will
+ * be re-read during subsequent reads.
+ * <p>
+ * This method will throw an IOException if the number of chars read from
+ * the stream since the call to <code>mark()</code> exceeds the mark limit
+ * passed when establishing the mark.
+ *
+ * @exception IOException If an error occurs;
+ */
+ public void reset() throws IOException
+ {
+ synchronized (lock)
+ {
+ checkStatus();
+ if (markPos < 0)
+ throw new IOException("mark never set or invalidated");
+
+ // Need to handle the extremely unlikely case where a readLine was
+ // done with a '\r' as the last char in the buffer; which was then
+ // immediately followed by a mark and a reset with NO intervening
+ // read of any sort. In that case, setting pos to markPos would
+ // lose that info and a subsequent read would thus not skip a '\n'
+ // (if one exists). The value of limit in this rare case is zero.
+ // We can assume that if limit is zero for other reasons, then
+ // pos is already set to zero and doesn't need to be readjusted.
+ if (limit > 0)
+ pos = markPos;
+ }
+ }
+
+ /**
+ * This method determines whether or not a stream is ready to be read. If
+ * this method returns <code>false</code> then this stream could (but is
+ * not guaranteed to) block on the next read attempt.
+ *
+ * @return <code>true</code> if this stream is ready to be read,
+ * <code>false</code> otherwise
+ *
+ * @exception IOException If an error occurs
+ */
+ public boolean ready() throws IOException
+ {
+ synchronized (lock)
+ {
+ checkStatus();
+ return pos < limit || in.ready();
+ }
+ }
+
+ /**
+ * This method read chars from a stream and stores them into a caller
+ * supplied buffer. It starts storing the data at index
+ * <code>offset</code> into
+ * the buffer and attempts to read <code>len</code> chars. This method can
+ * return before reading the number of chars requested. The actual number
+ * of chars read is returned as an int. A -1 is returned to indicate the
+ * end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ *
+ * @param buf The array into which the chars read should be stored
+ * @param offset The offset into the array to start storing chars
+ * @param count The requested number of chars to read
+ *
+ * @return The actual number of chars read, or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs.
+ * @exception IndexOutOfBoundsException If offset and count are not
+ * valid regarding buf.
+ */
+ public int read(char[] buf, int offset, int count) throws IOException
+ {
+ if (offset < 0 || offset + count > buf.length || count < 0)
+ throw new IndexOutOfBoundsException();
+
+ synchronized (lock)
+ {
+ checkStatus();
+ // Once again, we need to handle the special case of a readLine
+ // that has a '\r' at the end of the buffer. In this case, we'll
+ // need to skip a '\n' if it is the next char to be read.
+ // This special case is indicated by 'pos > limit'.
+ boolean retAtEndOfBuffer = false;
+
+ int avail = limit - pos;
+ if (count > avail)
+ {
+ if (avail > 0)
+ count = avail;
+ else // pos >= limit
+ {
+ if (limit == buffer.length)
+ markPos = -1; // read too far - invalidate the mark.
+ if (pos > limit)
+ {
+ // Set a boolean and make pos == limit to simplify things.
+ retAtEndOfBuffer = true;
+ --pos;
+ }
+ if (markPos < 0)
+ {
+ // Optimization: can read directly into buf.
+ if (count >= buffer.length && !retAtEndOfBuffer)
+ return in.read(buf, offset, count);
+ pos = limit = 0;
+ }
+ avail = in.read(buffer, limit, buffer.length - limit);
+ if (retAtEndOfBuffer && avail > 0 && buffer[limit] == '\n')
+ {
+ --avail;
+ limit++;
+ }
+ if (avail < count)
+ {
+ if (avail <= 0)
+ return avail;
+ count = avail;
+ }
+ limit += avail;
+ }
+ }
+ System.arraycopy(buffer, pos, buf, offset, count);
+ pos += count;
+ return count;
+ }
+ }
+
+ /* Read more data into the buffer. Update pos and limit appropriately.
+ Assumes pos==limit initially. May invalidate the mark if read too much.
+ Return number of chars read (never 0), or -1 on eof. */
+ private int fill() throws IOException
+ {
+ checkStatus();
+ // Handle the special case of a readLine that has a '\r' at the end of
+ // the buffer. In this case, we'll need to skip a '\n' if it is the
+ // next char to be read. This special case is indicated by 'pos > limit'.
+ boolean retAtEndOfBuffer = false;
+ if (pos > limit)
+ {
+ retAtEndOfBuffer = true;
+ --pos;
+ }
+
+ if (markPos >= 0 && limit == buffer.length)
+ markPos = -1;
+ if (markPos < 0)
+ pos = limit = 0;
+ int count = in.read(buffer, limit, buffer.length - limit);
+ if (count > 0)
+ limit += count;
+
+ if (retAtEndOfBuffer && buffer[pos] == '\n')
+ {
+ --count;
+ // If the mark was set to the location of the \n, then we
+ // must change it to fully pretend that the \n does not
+ // exist.
+ if (markPos == pos)
+ ++markPos;
+ ++pos;
+ }
+
+ return count;
+ }
+
+ public int read() throws IOException
+ {
+ synchronized (lock)
+ {
+ checkStatus();
+ if (pos >= limit && fill () <= 0)
+ return -1;
+ return buffer[pos++];
+ }
+ }
+
+ /* Return the end of the line starting at this.pos and ending at limit.
+ * The index returns is *before* any line terminators, or limit
+ * if no line terminators were found.
+ */
+ private int lineEnd(int limit)
+ {
+ int i = pos;
+ for (; i < limit; i++)
+ {
+ char ch = buffer[i];
+ if (ch == '\n' || ch == '\r')
+ break;
+ }
+ return i;
+ }
+
+ /**
+ * This method reads a single line of text from the input stream, returning
+ * it as a <code>String</code>. A line is terminated by "\n", a "\r", or
+ * an "\r\n" sequence. The system dependent line separator is not used.
+ * The line termination characters are not returned in the resulting
+ * <code>String</code>.
+ *
+ * @return The line of text read, or <code>null</code> if end of stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ public String readLine() throws IOException
+ {
+ checkStatus();
+ // Handle the special case where a previous readLine (with no intervening
+ // reads/skips) had a '\r' at the end of the buffer.
+ // In this case, we'll need to skip a '\n' if it's the next char to be read.
+ // This special case is indicated by 'pos > limit'.
+ if (pos > limit)
+ {
+ int ch = read();
+ if (ch < 0)
+ return null;
+ if (ch != '\n')
+ --pos;
+ }
+ int i = lineEnd(limit);
+ if (i < limit)
+ {
+ String str = String.valueOf(buffer, pos, i - pos);
+ pos = i + 1;
+ // If the last char in the buffer is a '\r', we must remember
+ // to check if the next char to be read after the buffer is refilled
+ // is a '\n'. If so, skip it. To indicate this condition, we set pos
+ // to be limit + 1, which normally is never possible.
+ if (buffer[i] == '\r')
+ if (pos == limit || buffer[pos] == '\n')
+ pos++;
+ return str;
+ }
+ CPStringBuilder sbuf = new CPStringBuilder(200);
+ sbuf.append(buffer, pos, i - pos);
+ pos = i;
+ // We only want to return null when no characters were read before
+ // EOF. So we must keep track of this separately. Otherwise we
+ // would treat an empty `sbuf' as an EOF condition, which is wrong
+ // when there is just a newline.
+ boolean eof = false;
+ for (;;)
+ {
+ // readLine should block. So we must not return until a -1 is reached.
+ if (pos >= limit)
+ {
+ // here count == 0 isn't sufficient to give a failure.
+ int count = fill();
+ if (count < 0)
+ {
+ eof = true;
+ break;
+ }
+ continue;
+ }
+ int ch = buffer[pos++];
+ if (ch == '\n' || ch == '\r')
+ {
+ // Check here if a '\r' was the last char in the buffer; if so,
+ // mark it as in the comment above to indicate future reads
+ // should skip a newline that is the next char read after
+ // refilling the buffer.
+ if (ch == '\r')
+ if (pos == limit || buffer[pos] == '\n')
+ pos++;
+ break;
+ }
+ i = lineEnd(limit);
+ sbuf.append(buffer, pos - 1, i - (pos - 1));
+ pos = i;
+ }
+ return (sbuf.length() == 0 && eof) ? null : sbuf.toString();
+ }
+
+ /**
+ * This method skips the specified number of chars in the stream. It
+ * returns the actual number of chars skipped, which may be less than the
+ * requested amount.
+ * <p>
+ * This method first discards chars in the buffer, then calls the
+ * <code>skip</code> method on the underlying stream to skip the
+ * remaining chars.
+ *
+ * @param count The requested number of chars to skip
+ *
+ * @return The actual number of chars skipped.
+ *
+ * @exception IOException If an error occurs.
+ * @exception IllegalArgumentException If count is negative.
+ */
+ public long skip(long count) throws IOException
+ {
+ synchronized (lock)
+ {
+ checkStatus();
+ if (count < 0)
+ throw new IllegalArgumentException("skip value is negative");
+ if (count == 0)
+ return 0;
+ // Yet again, we need to handle the special case of a readLine
+ // that has a '\r' at the end of the buffer. In this case, we need
+ // to ignore a '\n' if it is the next char to be read.
+ // This special case is indicated by 'pos > limit' (i.e. avail < 0).
+ // To simplify things, if we're dealing with the special case for
+ // readLine, just read the next char (since the fill method will
+ // skip the '\n' for us). By doing this, we'll have to back up pos.
+ // That's easier than trying to keep track of whether we've skipped
+ // one element or not.
+ if (pos > limit)
+ {
+ if (read() < 0)
+ return 0;
+ else
+ --pos;
+ }
+
+ int avail = limit - pos;
+
+ if (count < avail)
+ {
+ pos += count;
+ return count;
+ }
+
+ pos = limit;
+ long todo = count - avail;
+ if (todo > buffer.length)
+ {
+ markPos = -1;
+ todo -= in.skip(todo);
+ }
+ else
+ {
+ while (todo > 0)
+ {
+ avail = fill();
+ if (avail <= 0)
+ break;
+ if (avail > todo)
+ avail = (int) todo;
+ pos += avail;
+ todo -= avail;
+ }
+ }
+ return count - todo;
+ }
+ }
+
+ private void checkStatus() throws IOException
+ {
+ if (in == null)
+ throw new IOException("Stream closed");
+ }
+}
diff --git a/libjava/classpath/java/io/BufferedWriter.java b/libjava/classpath/java/io/BufferedWriter.java
new file mode 100644
index 000000000..ae6751c43
--- /dev/null
+++ b/libjava/classpath/java/io/BufferedWriter.java
@@ -0,0 +1,262 @@
+/* BufferedWriter.java -- Buffer output into large blocks before writing
+ Copyright (C) 1998, 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 java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Complete to version 1.1.
+ */
+
+/**
+ * This class accumulates chars written in a buffer instead of immediately
+ * writing the data to the underlying output sink. The chars are instead
+ * as one large block when the buffer is filled, or when the stream is
+ * closed or explicitly flushed. This mode operation can provide a more
+ * efficient mechanism for writing versus doing numerous small unbuffered
+ * writes.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ * @date September 25, 1998
+ */
+public class BufferedWriter extends Writer
+{
+ /**
+ * This is the default buffer size
+ */
+ private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+ /**
+ * This is the underlying <code>Writer</code> to which this object
+ * sends its output.
+ */
+ private Writer out;
+
+ /**
+ * This is the internal char array used for buffering output before
+ * writing it.
+ */
+ char[] buffer;
+
+ /**
+ * This is the number of chars that are currently in the buffer and
+ * are waiting to be written to the underlying stream. It always points to
+ * the index into the buffer where the next char of data will be stored
+ */
+ int count;
+
+ /**
+ * This method initializes a new <code>BufferedWriter</code> instance
+ * that will write to the specified subordinate <code>Writer</code>
+ * and which will use a default buffer size of 8192 chars.
+ *
+ * @param out The underlying <code>Writer</code> to write data to
+ */
+ public BufferedWriter (Writer out)
+ {
+ this (out, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * This method initializes a new <code>BufferedWriter</code> instance
+ * that will write to the specified subordinate <code>Writer</code>
+ * and which will use the specified buffer size
+ *
+ * @param out The underlying <code>Writer</code> to write data to
+ * @param size The size of the internal buffer
+ */
+ public BufferedWriter (Writer out, int size)
+ {
+ super(out.lock);
+ this.out = out;
+ this.buffer = new char[size];
+ this.count = 0;
+ }
+
+ /**
+ * This method flushes any remaining buffered chars then closes the
+ * underlying output stream. Any further attempts to write to this stream
+ * may throw an exception
+ *
+ * @exception IOException If an error occurs.
+ */
+ public void close () throws IOException
+ {
+ synchronized (lock)
+ {
+ // It is safe to call localFlush even if the stream is already
+ // closed.
+ localFlush ();
+ out.close();
+ buffer = null;
+ }
+ }
+
+ /**
+ * This method causes any currently buffered chars to be immediately
+ * written to the underlying output stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void flush () throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buffer == null)
+ throw new IOException ("Stream closed");
+ localFlush ();
+ out.flush();
+ }
+ }
+
+ /**
+ * This method writes out a system depedent line separator sequence. The
+ * actual value written is detemined from the <xmp>line.separator</xmp>
+ * system property.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void newLine () throws IOException
+ {
+ write (System.getProperty("line.separator"));
+ }
+
+ /**
+ * This method writes a single char of data. This will be written to the
+ * buffer instead of the underlying data source. However, if the buffer
+ * is filled as a result of this write request, it will be flushed to the
+ * underlying output stream.
+ *
+ * @param oneChar The char of data to be written, passed as an int
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (int oneChar) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buffer == null)
+ throw new IOException ("Stream closed");
+ buffer[count++] = (char) oneChar;
+ if (count == buffer.length)
+ localFlush ();
+ }
+ }
+
+ /**
+ * This method writes <code>len</code> chars from the char array
+ * <code>buf</code> starting at position <code>offset</code> in the buffer.
+ * These chars will be written to the internal buffer. However, if this
+ * write operation fills the buffer, the buffer will be flushed to the
+ * underlying output stream.
+ *
+ * @param buf The array of chars to write.
+ * @param offset The index into the char array to start writing from.
+ * @param len The number of chars to write.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (char[] buf, int offset, int len) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buffer == null)
+ throw new IOException ("Stream closed");
+
+ // Bypass buffering if there is too much incoming data.
+ if (count + len > buffer.length)
+ {
+ localFlush ();
+ out.write(buf, offset, len);
+ }
+ else
+ {
+ System.arraycopy(buf, offset, buffer, count, len);
+ count += len;
+ if (count == buffer.length)
+ localFlush ();
+ }
+ }
+ }
+
+ /**
+ * This method writes <code>len</code> chars from the <code>String</code>
+ * <code>str</code> starting at position <code>offset</code> in the string.
+ * These chars will be written to the internal buffer. However, if this
+ * write operation fills the buffer, the buffer will be flushed to the
+ * underlying output stream.
+ *
+ * @param str The <code>String</code> to write.
+ * @param offset The index into the string to start writing from.
+ * @param len The number of chars to write.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (String str, int offset, int len) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buffer == null)
+ throw new IOException ("Stream closed");
+
+ if (count + len > buffer.length)
+ {
+ localFlush ();
+ out.write(str, offset, len);
+ }
+ else
+ {
+ str.getChars(offset, offset + len, buffer, count);
+ count += len;
+ if (count == buffer.length)
+ localFlush ();
+ }
+ }
+ }
+
+ // This should only be called with the lock held.
+ private void localFlush () throws IOException
+ {
+ if (count > 0)
+ {
+ out.write(buffer, 0, count);
+ count = 0;
+ }
+ }
+}
diff --git a/libjava/classpath/java/io/ByteArrayInputStream.java b/libjava/classpath/java/io/ByteArrayInputStream.java
new file mode 100644
index 000000000..f46ee3c0f
--- /dev/null
+++ b/libjava/classpath/java/io/ByteArrayInputStream.java
@@ -0,0 +1,251 @@
+/* ByteArrayInputStream.java -- Read an array as a stream
+ Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+/**
+ * This class permits an array of bytes to be read as an input stream.
+ *
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class ByteArrayInputStream extends InputStream
+{
+ /**
+ * The array that contains the data supplied during read operations
+ */
+ protected byte[] buf;
+
+ /**
+ * The array index of the next byte to be read from the buffer
+ * <code>buf</code>
+ */
+ protected int pos;
+
+ /**
+ * The currently marked position in the stream. This defaults to 0, so a
+ * reset operation on the stream resets it to read from array index 0 in
+ * the buffer - even if the stream was initially created with an offset
+ * greater than 0
+ */
+ protected int mark;
+
+ /**
+ * This indicates the maximum number of bytes that can be read from this
+ * stream. It is the array index of the position after the last valid
+ * byte in the buffer <code>buf</code>
+ */
+ protected int count;
+
+ /**
+ * Create a new ByteArrayInputStream that will read bytes from the passed
+ * in byte array. This stream will read from the beginning to the end
+ * of the array. It is identical to calling an overloaded constructor
+ * as <code>ByteArrayInputStream(buf, 0, buf.length)</code>.
+ * <p>
+ * Note that this array is not copied. If its contents are changed
+ * while this stream is being read, those changes will be reflected in the
+ * bytes supplied to the reader. Please use caution in changing the
+ * contents of the buffer while this stream is open.
+ *
+ * @param buffer The byte array buffer this stream will read from.
+ */
+ public ByteArrayInputStream(byte[] buffer)
+ {
+ this(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Create a new ByteArrayInputStream that will read bytes from the
+ * passed in byte array. This stream will read from position
+ * <code>offset</code> in the array for a length of
+ * <code>length</code> bytes past <code>offset</code>. If the
+ * stream is reset to a position before <code>offset</code> then
+ * more than <code>length</code> bytes can be read from the stream.
+ * The <code>length</code> value should be viewed as the array index
+ * one greater than the last position in the buffer to read.
+ * <p>
+ * Note that this array is not copied. If its contents are changed
+ * while this stream is being read, those changes will be reflected in the
+ * bytes supplied to the reader. Please use caution in changing the
+ * contents of the buffer while this stream is open.
+ *
+ * @param buffer The byte array buffer this stream will read from.
+ * @param offset The index into the buffer to start reading bytes from
+ * @param length The number of bytes to read from the buffer
+ */
+ public ByteArrayInputStream(byte[] buffer, int offset, int length)
+ {
+ if (offset < 0 || length < 0 || offset > buffer.length)
+ throw new IllegalArgumentException();
+
+ buf = buffer;
+
+ count = offset + length;
+ if (count > buf.length)
+ count = buf.length;
+
+ pos = offset;
+ mark = pos;
+ }
+
+ /**
+ * This method returns the number of bytes available to be read from this
+ * stream. The value returned will be equal to <code>count - pos</code>.
+ *
+ * @return The number of bytes that can be read from this stream
+ * before blocking, which is all of them
+ */
+ public synchronized int available()
+ {
+ return count - pos;
+ }
+
+ /**
+ * This method sets the mark position in this stream to the current
+ * position. Note that the <code>readlimit</code> parameter in this
+ * method does nothing as this stream is always capable of
+ * remembering all the bytes int it.
+ * <p>
+ * Note that in this class the mark position is set by default to
+ * position 0 in the stream. This is in constrast to some other
+ * stream types where there is no default mark position.
+ *
+ * @param readLimit The number of bytes this stream must remember.
+ * This parameter is ignored.
+ */
+ public synchronized void mark(int readLimit)
+ {
+ // readLimit is ignored per Java Class Lib. book, p.220.
+ mark = pos;
+ }
+
+ /**
+ * This method overrides the <code>markSupported</code> method in
+ * <code>InputStream</code> in order to return <code>true</code> -
+ * indicating that this stream class supports mark/reset
+ * functionality.
+ *
+ * @return <code>true</code> to indicate that this class supports
+ * mark/reset.
+ */
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ /**
+ * This method reads one byte from the stream. The <code>pos</code>
+ * counter is advanced to the next byte to be read. The byte read is
+ * returned as an int in the range of 0-255. If the stream position
+ * is already at the end of the buffer, no byte is read and a -1 is
+ * returned in order to indicate the end of the stream.
+ *
+ * @return The byte read, or -1 if end of stream
+ */
+ public synchronized int read()
+ {
+ if (pos < count)
+ return ((int) buf[pos++]) & 0xFF;
+ return -1;
+ }
+
+ /**
+ * This method reads bytes from the stream and stores them into a
+ * caller supplied buffer. It starts storing the data at index
+ * <code>offset</code> into the buffer and attempts to read
+ * <code>len</code> bytes. This method can return before reading
+ * the number of bytes requested if the end of the stream is
+ * encountered first. The actual number of bytes read is returned.
+ * If no bytes can be read because the stream is already at the end
+ * of stream position, a -1 is returned.
+ * <p>
+ * This method does not block.
+ *
+ * @param buffer The array into which the bytes read should be stored.
+ * @param offset The offset into the array to start storing bytes
+ * @param length The requested number of bytes to read
+ *
+ * @return The actual number of bytes read, or -1 if end of stream.
+ */
+ public synchronized int read(byte[] buffer, int offset, int length)
+ {
+ if (pos >= count)
+ return -1;
+
+ int numBytes = Math.min(count - pos, length);
+ System.arraycopy(buf, pos, buffer, offset, numBytes);
+ pos += numBytes;
+ return numBytes;
+ }
+
+ /**
+ * This method sets the read position in the stream to the mark
+ * point by setting the <code>pos</code> variable equal to the
+ * <code>mark</code> variable. Since a mark can be set anywhere in
+ * the array, the mark/reset methods int this class can be used to
+ * provide random search capabilities for this type of stream.
+ */
+ public synchronized void reset()
+ {
+ pos = mark;
+ }
+
+ /**
+ * This method attempts to skip the requested number of bytes in the
+ * input stream. It does this by advancing the <code>pos</code>
+ * value by the specified number of bytes. It this would exceed the
+ * length of the buffer, then only enough bytes are skipped to
+ * position the stream at the end of the buffer. The actual number
+ * of bytes skipped is returned.
+ *
+ * @param num The requested number of bytes to skip
+ *
+ * @return The actual number of bytes skipped.
+ */
+ public synchronized long skip(long num)
+ {
+ // Even though the var numBytes is a long, in reality it can never
+ // be larger than an int since the result of subtracting 2 positive
+ // ints will always fit in an int. Since we have to return a long
+ // anyway, numBytes might as well just be a long.
+ long numBytes = Math.min((long) (count - pos), num < 0 ? 0L : num);
+ pos += numBytes;
+ return numBytes;
+ }
+}
diff --git a/libjava/classpath/java/io/ByteArrayOutputStream.java b/libjava/classpath/java/io/ByteArrayOutputStream.java
new file mode 100644
index 000000000..9c1a86b7f
--- /dev/null
+++ b/libjava/classpath/java/io/ByteArrayOutputStream.java
@@ -0,0 +1,284 @@
+/* BufferedReader.java
+ Copyright (C) 1998, 1999, 2000, 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 java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Complete to version 1.1.
+ */
+
+/**
+ * This class allows data to be written to a byte array buffer and
+ * and then retrieved by an application. The internal byte array
+ * buffer is dynamically resized to hold all the data written. Please
+ * be aware that writing large amounts to data to this stream will
+ * cause large amounts of memory to be allocated.
+ * <p>
+ * The size of the internal buffer defaults to 32 and it is resized
+ * by doubling the size of the buffer. This default size can be
+ * overridden by using the
+ * <code>gnu.java.io.ByteArrayOutputStream.initialBufferSize</code>
+ * property.
+ * <p>
+ * There is a constructor that specified the initial buffer size and
+ * that is the preferred way to set that value because it it portable
+ * across all Java class library implementations.
+ * <p>
+ * Note that this class also has methods that convert the byte array
+ * buffer to a <code>String</code> using either the system default or an
+ * application specified character encoding. Thus it can handle
+ * multibyte character encodings.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ * @date September 24, 1998
+ */
+public class ByteArrayOutputStream extends OutputStream
+{
+ /**
+ * This method initializes a new <code>ByteArrayOutputStream</code>
+ * with the default buffer size of 32 bytes. If a different initial
+ * buffer size is desired, see the constructor
+ * <code>ByteArrayOutputStream(int size)</code>. For applications
+ * where the source code is not available, the default buffer size
+ * can be set using the system property
+ * <code>gnu.java.io.ByteArrayOutputStream.initialBufferSize</code>
+ */
+ public ByteArrayOutputStream ()
+ {
+ this (initial_buffer_size);
+ }
+
+ /**
+ * This method initializes a new <code>ByteArrayOutputStream</code> with
+ * a specified initial buffer size.
+ *
+ * @param size The initial buffer size in bytes
+ */
+ public ByteArrayOutputStream (int size)
+ {
+ buf = new byte[size];
+ count = 0;
+ }
+
+ /**
+ * This method discards all of the bytes that have been written to
+ * the internal buffer so far by setting the <code>count</code>
+ * variable to 0. The internal buffer remains at its currently
+ * allocated size.
+ */
+ public synchronized void reset ()
+ {
+ count = 0;
+ }
+
+ /**
+ * This method returns the number of bytes that have been written to
+ * the buffer so far. This is the same as the value of the protected
+ * <code>count</code> variable. If the <code>reset</code> method is
+ * called, then this value is reset as well. Note that this method does
+ * not return the length of the internal buffer, but only the number
+ * of bytes that have been written to it.
+ *
+ * @return The number of bytes in the internal buffer
+ *
+ * @see #reset()
+ */
+ public int size ()
+ {
+ return count;
+ }
+
+ /**
+ * This method returns a byte array containing the bytes that have been
+ * written to this stream so far. This array is a copy of the valid
+ * bytes in the internal buffer and its length is equal to the number of
+ * valid bytes, not necessarily to the the length of the current
+ * internal buffer. Note that since this method allocates a new array,
+ * it should be used with caution when the internal buffer is very large.
+ */
+ public synchronized byte[] toByteArray ()
+ {
+ byte[] ret = new byte[count];
+ System.arraycopy(buf, 0, ret, 0, count);
+ return ret;
+ }
+
+ /**
+ * Returns the bytes in the internal array as a <code>String</code>. The
+ * bytes in the buffer are converted to characters using the system default
+ * encoding. There is an overloaded <code>toString()</code> method that
+ * allows an application specified character encoding to be used.
+ *
+ * @return A <code>String</code> containing the data written to this
+ * stream so far
+ */
+ public String toString ()
+ {
+ return new String (buf, 0, count);
+ }
+
+ /**
+ * Returns the bytes in the internal array as a <code>String</code>. The
+ * bytes in the buffer are converted to characters using the specified
+ * encoding.
+ *
+ * @param enc The name of the character encoding to use
+ *
+ * @return A <code>String</code> containing the data written to this
+ * stream so far
+ *
+ * @exception UnsupportedEncodingException If the named encoding is
+ * not available
+ */
+ public String toString (String enc) throws UnsupportedEncodingException
+ {
+ return new String (buf, 0, count, enc);
+ }
+
+ /**
+ * This method returns the bytes in the internal array as a
+ * <code>String</code>. It uses each byte in the array as the low
+ * order eight bits of the Unicode character value and the passed in
+ * parameter as the high eight bits.
+ * <p>
+ * This method does not convert bytes to characters in the proper way and
+ * so is deprecated in favor of the other overloaded <code>toString</code>
+ * methods which use a true character encoding.
+ *
+ * @param hibyte The high eight bits to use for each character in
+ * the <code>String</code>
+ *
+ * @return A <code>String</code> containing the data written to this
+ * stream so far
+ *
+ * @deprecated
+ */
+ public String toString (int hibyte)
+ {
+ return new String (buf, hibyte, 0, count);
+ }
+
+ // Resize buffer to accommodate new bytes.
+ private void resize (int add)
+ {
+ if (count + add > buf.length)
+ {
+ int newlen = buf.length * 2;
+ if (count + add > newlen)
+ newlen = count + add;
+ byte[] newbuf = new byte[newlen];
+ System.arraycopy(buf, 0, newbuf, 0, count);
+ buf = newbuf;
+ }
+ }
+
+ /**
+ * This method writes the writes the specified byte into the internal
+ * buffer.
+ *
+ * @param oneByte The byte to be read passed as an int
+ */
+ public synchronized void write (int oneByte)
+ {
+ resize (1);
+ buf[count++] = (byte) oneByte;
+ }
+
+ /**
+ * This method writes <code>len</code> bytes from the passed in array
+ * <code>buf</code> starting at index <code>offset</code> into the
+ * internal buffer.
+ *
+ * @param buffer The byte array to write data from
+ * @param offset The index into the buffer to start writing data from
+ * @param add The number of bytes to write
+ */
+ public synchronized void write (byte[] buffer, int offset, int add)
+ {
+ // If ADD < 0 then arraycopy will throw the appropriate error for
+ // us.
+ if (add >= 0)
+ resize (add);
+ System.arraycopy(buffer, offset, buf, count, add);
+ count += add;
+ }
+
+ /**
+ * This method writes all the bytes that have been written to this stream
+ * from the internal buffer to the specified <code>OutputStream</code>.
+ *
+ * @param out The <code>OutputStream</code> to write to
+ *
+ * @exception IOException If an error occurs
+ */
+ public synchronized void writeTo (OutputStream out) throws IOException
+ {
+ out.write(buf, 0, count);
+ }
+
+ /**
+ * The internal buffer where the data written is stored
+ */
+ protected byte[] buf;
+
+ /**
+ * The number of bytes that have been written to the buffer
+ */
+ protected int count;
+
+ /**
+ * The default initial buffer size. Specified by the JCL.
+ */
+ private static final int DEFAULT_INITIAL_BUFFER_SIZE = 32;
+
+ // The default buffer size which can be overridden by the user.
+ private static final int initial_buffer_size;
+
+ static
+ {
+ int r
+ = Integer.getInteger ("gnu.java.io.ByteArrayOutputStream.initialBufferSize",
+ DEFAULT_INITIAL_BUFFER_SIZE).intValue ();
+ if (r <= 0)
+ r = DEFAULT_INITIAL_BUFFER_SIZE;
+ initial_buffer_size = r;
+ }
+}
diff --git a/libjava/classpath/java/io/CharArrayReader.java b/libjava/classpath/java/io/CharArrayReader.java
new file mode 100644
index 000000000..8405f48f3
--- /dev/null
+++ b/libjava/classpath/java/io/CharArrayReader.java
@@ -0,0 +1,305 @@
+/* CharArrayReader.java -- Read an array of characters as a stream
+ Copyright (C) 1998, 2001, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+/**
+ * This class permits an array of chars to be read as an input stream.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public class CharArrayReader extends Reader
+{
+ /**
+ * The array that contains the data supplied during read operations
+ */
+ protected char[] buf;
+
+ /**
+ * The array index of the next char to be read from the buffer
+ * <code>buf</code>
+ */
+ protected int pos;
+
+ /**
+ * The currently marked position in the stream. This defaults to 0, so a
+ * reset operation on the stream resets it to read from array index 0 in
+ * the buffer - even if the stream was initially created with an offset
+ * greater than 0
+ */
+ protected int markedPos;
+
+ /**
+ * This indicates the maximum number of chars that can be read from this
+ * stream. It is the array index of the position after the last valid
+ * char in the buffer <code>buf</code>
+ */
+ protected int count;
+
+ /**
+ * Create a new CharArrayReader that will read chars from the passed
+ * in char array. This stream will read from the beginning to the end
+ * of the array. It is identical to calling an overloaded constructor
+ * as <code>CharArrayReader(buf, 0, buf.length)</code>.
+ * <p>
+ * Note that this array is not copied. If its contents are changed
+ * while this stream is being read, those changes will be reflected in the
+ * chars supplied to the reader. Please use caution in changing the
+ * contents of the buffer while this stream is open.
+ *
+ * @param buffer The char array buffer this stream will read from.
+ */
+ public CharArrayReader(char[] buffer)
+ {
+ this(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Create a new CharArrayReader that will read chars from the passed
+ * in char array. This stream will read from position
+ * <code>offset</code> in the array for a length of
+ * <code>length</code> chars past <code>offset</code>. If the
+ * stream is reset to a position before <code>offset</code> then
+ * more than <code>length</code> chars can be read from the stream.
+ * The <code>length</code> value should be viewed as the array index
+ * one greater than the last position in the buffer to read.
+ * <p>
+ * Note that this array is not copied. If its contents are changed
+ * while this stream is being read, those changes will be reflected in the
+ * chars supplied to the reader. Please use caution in changing the
+ * contents of the buffer while this stream is open.
+ *
+ * @param buffer The char array buffer this stream will read from.
+ * @param offset The index into the buffer to start reading chars from
+ * @param length The number of chars to read from the buffer
+ */
+ public CharArrayReader(char[] buffer, int offset, int length)
+ {
+ super();
+ if (offset < 0 || length < 0 || offset > buffer.length)
+ throw new IllegalArgumentException();
+
+ buf = buffer;
+
+ count = offset + length;
+ if (count > buf.length)
+ count = buf.length;
+
+ pos = offset;
+ markedPos = pos;
+ }
+
+ /**
+ * This method closes the stream.
+ */
+ public void close()
+ {
+ synchronized (lock)
+ {
+ buf = null;
+ }
+ }
+
+ /**
+ * This method sets the mark position in this stream to the current
+ * position. Note that the <code>readlimit</code> parameter in this
+ * method does nothing as this stream is always capable of
+ * remembering all the chars int it.
+ * <p>
+ * Note that in this class the mark position is set by default to
+ * position 0 in the stream. This is in constrast to some other
+ * stream types where there is no default mark position.
+ *
+ * @param readAheadLimit The number of chars this stream must
+ * remember. This parameter is ignored.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void mark(int readAheadLimit) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+ // readAheadLimit is ignored per Java Class Lib. book, p. 318.
+ markedPos = pos;
+ }
+ }
+
+ /**
+ * This method overrides the <code>markSupported</code> method in
+ * <code>Reader</code> in order to return <code>true</code> -
+ * indicating that this stream class supports mark/reset
+ * functionality.
+ *
+ * @return <code>true</code> to indicate that this class supports
+ * mark/reset.
+ */
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ /**
+ * This method reads one char from the stream. The <code>pos</code>
+ * counter is advanced to the next char to be read. The char read
+ * is returned as an int in the range of 0-65535. If the stream
+ * position is already at the end of the buffer, no char is read and
+ * a -1 is returned in order to indicate the end of the stream.
+ *
+ * @return The char read, or -1 if end of stream
+ */
+ public int read() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+
+ if (pos < 0)
+ throw new ArrayIndexOutOfBoundsException(pos);
+
+ if (pos < count)
+ return ((int) buf[pos++]) & 0xFFFF;
+ return -1;
+ }
+ }
+
+ /**
+ * This method reads chars from the stream and stores them into a
+ * caller supplied buffer. It starts storing the data at index
+ * <code>offset</code> into the buffer and attempts to read
+ * <code>len</code> chars. This method can return before reading
+ * the number of chars requested if the end of the stream is
+ * encountered first. The actual number of chars read is returned.
+ * If no chars can be read because the stream is already at the end
+ * of stream position, a -1 is returned.
+ * <p>
+ * This method does not block.
+ *
+ * @param b The array into which the chars read should be stored.
+ * @param off The offset into the array to start storing chars
+ * @param len The requested number of chars to read
+ *
+ * @return The actual number of chars read, or -1 if end of stream.
+ */
+ public int read(char[] b, int off, int len) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+
+ /* Don't need to check pos value, arraycopy will check it. */
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new IndexOutOfBoundsException();
+
+ if (pos >= count)
+ return -1;
+
+ int numChars = Math.min(count - pos, len);
+ System.arraycopy(buf, pos, b, off, numChars);
+ pos += numChars;
+ return numChars;
+ }
+ }
+
+ /**
+ * Return true if more characters are available to be read.
+ *
+ * @return <code>true</code> to indicate that this stream is ready
+ * to be read.
+ *
+ * @specnote The JDK 1.3 API docs are wrong here. This method will
+ * return false if there are no more characters available.
+ */
+ public boolean ready() throws IOException
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+
+ return (pos < count);
+ }
+
+ /**
+ * This method sets the read position in the stream to the mark
+ * point by setting the <code>pos</code> variable equal to the
+ * <code>mark</code> variable. Since a mark can be set anywhere in
+ * the array, the mark/reset methods int this class can be used to
+ * provide random search capabilities for this type of stream.
+ */
+ public void reset() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+
+ pos = markedPos;
+ }
+ }
+
+ /**
+ * This method attempts to skip the requested number of chars in the
+ * input stream. It does this by advancing the <code>pos</code> value by the
+ * specified number of chars. It this would exceed the length of the
+ * buffer, then only enough chars are skipped to position the stream at
+ * the end of the buffer. The actual number of chars skipped is returned.
+ *
+ * @param n The requested number of chars to skip
+ *
+ * @return The actual number of chars skipped.
+ */
+ public long skip(long n) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+
+ // Even though the var numChars is a long, in reality it can never
+ // be larger than an int since the result of subtracting 2 positive
+ // ints will always fit in an int. Since we have to return a long
+ // anyway, numChars might as well just be a long.
+ long numChars = Math.min((long) (count - pos), n < 0 ? 0L : n);
+ pos += numChars;
+ return numChars;
+ }
+ }
+}
diff --git a/libjava/classpath/java/io/CharArrayWriter.java b/libjava/classpath/java/io/CharArrayWriter.java
new file mode 100644
index 000000000..dea727aa1
--- /dev/null
+++ b/libjava/classpath/java/io/CharArrayWriter.java
@@ -0,0 +1,352 @@
+/* CharArrayWriter.java -- Write chars to a buffer
+ Copyright (C) 1998, 1999, 2001, 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 java.io;
+
+/**
+ * This class allows data to be written to a char array buffer and
+ * and then retrieved by an application. The internal char array
+ * buffer is dynamically resized to hold all the data written. Please
+ * be aware that writing large amounts to data to this stream will
+ * cause large amounts of memory to be allocated.
+ * <p>
+ * The size of the internal buffer defaults to 32 and it is resized
+ * in increments of 1024 chars. This behavior can be over-ridden by using the
+ * following two properties:
+ * <p>
+ * <ul>
+ * <li><xmp>gnu.java.io.CharArrayWriter.initialBufferSize</xmp></li>
+ * <li><xmp>gnu.java.io.CharArrayWriter.bufferIncrementSize</xmp></li>
+ * </ul>
+ * <p>
+ * There is a constructor that specified the initial buffer size and
+ * that is the preferred way to set that value because it it portable
+ * across all Java class library implementations.
+ * <p>
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ */
+public class CharArrayWriter extends Writer
+{
+ /**
+ * The default initial buffer size
+ */
+ private static final int DEFAULT_INITIAL_BUFFER_SIZE = 32;
+
+ /**
+ * This method initializes a new <code>CharArrayWriter</code> with
+ * the default buffer size of 32 chars. If a different initial
+ * buffer size is desired, see the constructor
+ * <code>CharArrayWriter(int size)</code>.
+ */
+ public CharArrayWriter ()
+ {
+ this (DEFAULT_INITIAL_BUFFER_SIZE);
+ }
+
+ /**
+ * This method initializes a new <code>CharArrayWriter</code> with
+ * a specified initial buffer size.
+ *
+ * @param size The initial buffer size in chars
+ */
+ public CharArrayWriter (int size)
+ {
+ super ();
+ buf = new char[size];
+ }
+
+ /**
+ * Closes the stream. This method is guaranteed not to free the contents
+ * of the internal buffer, which can still be retrieved.
+ */
+ public void close ()
+ {
+ }
+
+ /**
+ * This method flushes all buffered chars to the stream.
+ */
+ public void flush ()
+ {
+ }
+
+ /**
+ * This method discards all of the chars that have been written to the
+ * internal buffer so far by setting the <code>count</code> variable to
+ * 0. The internal buffer remains at its currently allocated size.
+ */
+ public void reset ()
+ {
+ synchronized (lock)
+ {
+ count = 0;
+ }
+ }
+
+ /**
+ * This method returns the number of chars that have been written to
+ * the buffer so far. This is the same as the value of the protected
+ * <code>count</code> variable. If the <code>reset</code> method is
+ * called, then this value is reset as well. Note that this method does
+ * not return the length of the internal buffer, but only the number
+ * of chars that have been written to it.
+ *
+ * @return The number of chars in the internal buffer
+ *
+ * @see #reset()
+ */
+ public int size ()
+ {
+ return count;
+ }
+
+ /**
+ * This method returns a char array containing the chars that have been
+ * written to this stream so far. This array is a copy of the valid
+ * chars in the internal buffer and its length is equal to the number of
+ * valid chars, not necessarily to the the length of the current
+ * internal buffer. Note that since this method allocates a new array,
+ * it should be used with caution when the internal buffer is very large.
+ */
+ public char[] toCharArray ()
+ {
+ synchronized (lock)
+ {
+ char[] nc = new char[count];
+ System.arraycopy(buf, 0, nc, 0, count);
+ return nc;
+ }
+ }
+
+ /**
+ * Returns the chars in the internal array as a <code>String</code>. The
+ * chars in the buffer are converted to characters using the system default
+ * encoding. There is an overloaded <code>toString()</code> method that
+ * allows an application specified character encoding to be used.
+ *
+ * @return A <code>String</code> containing the data written to this
+ * stream so far
+ */
+ public String toString ()
+ {
+ synchronized (lock)
+ {
+ return new String (buf, 0, count);
+ }
+ }
+
+ /**
+ * This method writes the writes the specified char into the internal
+ * buffer.
+ *
+ * @param oneChar The char to be read passed as an int
+ */
+ public void write (int oneChar)
+ {
+ synchronized (lock)
+ {
+ resize (1);
+ buf[count++] = (char) oneChar;
+ }
+ }
+
+ /**
+ * This method writes <code>len</code> chars from the passed in array
+ * <code>buf</code> starting at index <code>offset</code> into that buffer
+ *
+ * @param buffer The char array to write data from
+ * @param offset The index into the buffer to start writing data from
+ * @param len The number of chars to write
+ */
+ public void write (char[] buffer, int offset, int len)
+ {
+ synchronized (lock)
+ {
+ if (len >= 0)
+ resize (len);
+ System.arraycopy(buffer, offset, buf, count, len);
+ count += len;
+ }
+ }
+
+ /**
+ * This method writes <code>len</code> chars from the passed in
+ * <code>String</code> <code>buf</code> starting at index
+ * <code>offset</code> into the internal buffer.
+ *
+ * @param str The <code>String</code> to write data from
+ * @param offset The index into the string to start writing data from
+ * @param len The number of chars to write
+ */
+ public void write (String str, int offset, int len)
+ {
+ synchronized (lock)
+ {
+ if (len >= 0)
+ resize (len);
+ str.getChars(offset, offset + len, buf, count);
+ count += len;
+ }
+ }
+
+ /**
+ * This method writes all the chars that have been written to this stream
+ * from the internal buffer to the specified <code>Writer</code>.
+ *
+ * @param out The <code>Writer</code> to write to
+ *
+ * @exception IOException If an error occurs
+ */
+ public void writeTo (Writer out) throws IOException
+ {
+ synchronized (lock)
+ {
+ out.write(buf, 0, count);
+ }
+ }
+
+ /**
+ * Appends the Unicode character, <code>c</code>, to the output stream
+ * underlying this writer. This is equivalent to <code>write(c)</code>.
+ *
+ * @param c the character to append.
+ * @return a reference to this object.
+ * @since 1.5
+ */
+ public CharArrayWriter append(char c)
+ {
+ write(c);
+ return this;
+ }
+
+ /**
+ * Appends the specified sequence of Unicode characters to the
+ * output stream underlying this writer. This is equivalent to
+ * appending the results of calling <code>toString()</code> on the
+ * character sequence. As a result, the entire sequence may not be
+ * appended, as it depends on the implementation of
+ * <code>toString()</code> provided by the
+ * <code>CharSequence</code>. For example, if the character
+ * sequence is wrapped around an input buffer, the results will
+ * depend on the current position and length of that buffer.
+ *
+ * @param cs the character sequence to append. If seq is null,
+ * then the string "null" (the string representation of null)
+ * is appended.
+ * @return a reference to this object.
+ * @since 1.5
+ */
+ public CharArrayWriter append(CharSequence cs)
+ {
+ try
+ {
+ write(cs == null ? "null" : cs.toString());
+ }
+ catch (IOException _)
+ {
+ // Can't happen.
+ }
+ return this;
+ }
+
+ /**
+ * Appends the specified subsequence of Unicode characters to the
+ * output stream underlying this writer, starting and ending at the
+ * specified positions within the sequence. The behaviour of this
+ * method matches the behaviour of writing the result of
+ * <code>append(seq.subSequence(start,end))</code> when the sequence
+ * is not null.
+ *
+ * @param cs the character sequence to append. If seq is null,
+ * then the string "null" (the string representation of null)
+ * is appended.
+ * @param start the index of the first Unicode character to use from
+ * the sequence.
+ * @param end the index of the last Unicode character to use from the
+ * sequence.
+ * @return a reference to this object.
+ * @throws IndexOutOfBoundsException if either of the indices are negative,
+ * the start index occurs after the end index, or the end index is
+ * beyond the end of the sequence.
+ * @since 1.5
+ */
+ public CharArrayWriter append(CharSequence cs, int start, int end)
+ {
+ try
+ {
+ write(cs == null ? "null" : cs.subSequence(start, end).toString());
+ }
+ catch (IOException _)
+ {
+ // Can't happen.
+ }
+ return this;
+ }
+
+ /**
+ * This private method makes the buffer bigger when we run out of room
+ * by allocating a larger buffer and copying the valid chars from the
+ * old array into it. This is obviously slow and should be avoided by
+ * application programmers by setting their initial buffer size big
+ * enough to hold everything if possible.
+ */
+ private void resize (int len)
+ {
+ if (count + len >= buf.length)
+ {
+ int newlen = buf.length * 2;
+ if (count + len > newlen)
+ newlen = count + len;
+ char[] newbuf = new char[newlen];
+ System.arraycopy(buf, 0, newbuf, 0, count);
+ buf = newbuf;
+ }
+ }
+
+ /**
+ * The internal buffer where the data written is stored
+ */
+ protected char[] buf;
+
+ /**
+ * The number of chars that have been written to the buffer
+ */
+ protected int count;
+}
diff --git a/libjava/classpath/java/io/CharConversionException.java b/libjava/classpath/java/io/CharConversionException.java
new file mode 100644
index 000000000..a7a608429
--- /dev/null
+++ b/libjava/classpath/java/io/CharConversionException.java
@@ -0,0 +1,73 @@
+/* CharConversionException.java -- Character conversion exceptions
+ Copyright (C) 1998, 1999, 2001, 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 java.io;
+
+/**
+ * This exception is thrown to indicate that a problem occurred with
+ * an attempted character conversion.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class CharConversionException extends IOException
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = -8680016352018427031L;
+
+ /**
+ * Create an exception without a descriptive error message.
+ */
+ public CharConversionException()
+ {
+ }
+
+ /**
+ * Create an exception with a descriptive error message.
+ *
+ * @param message the descriptive error message
+ */
+ public CharConversionException(String message)
+ {
+ super(message);
+ }
+} // class CharConversionException
diff --git a/libjava/classpath/java/io/Closeable.java b/libjava/classpath/java/io/Closeable.java
new file mode 100644
index 000000000..b8523d79e
--- /dev/null
+++ b/libjava/classpath/java/io/Closeable.java
@@ -0,0 +1,63 @@
+/* Closeable.java -- Closeable object
+ 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 java.io;
+
+/**
+ * A <code>Closeable</code> class represents a stream of
+ * data, which can be closed when it is no longer needed.
+ * Closing a stream allows the resources it uses to be
+ * freed for an alternate use.
+ *
+ * @author Tom Tromey (tromey@redhat.com)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public interface Closeable
+{
+
+ /**
+ * Closes the stream represented by this class, thus freeing
+ * system resources. In that case that the stream is already
+ * in the closed state, this method has no effect.
+ *
+ * @throws IOException if an I/O error occurs in closing.
+ */
+ void close()
+ throws IOException;
+
+}
diff --git a/libjava/classpath/java/io/DataInput.java b/libjava/classpath/java/io/DataInput.java
new file mode 100644
index 000000000..a713319cf
--- /dev/null
+++ b/libjava/classpath/java/io/DataInput.java
@@ -0,0 +1,456 @@
+/* DataInput.java -- Interface for reading data from a stream
+ Copyright (C) 1998, 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 java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct. */
+
+/**
+ * This interface is implemented by classes that can data from streams
+ * into Java primitive types.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public interface DataInput
+{
+
+ /**
+ * 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 <code>false</code>. If the byte is non-zero, then
+ * the value returned is <code>true</code>.
+ * <p>
+ * This method can read a <code>boolean</code> written by an object
+ * implementing the <code>writeBoolean()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>boolean</code> 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 EOFException, IOException;
+
+ /**
+ * This method reads a Java byte value from an input stream. The value
+ * is in the range of -128 to 127.
+ * <p>
+ * This method can read a <code>byte</code> written by an object
+ * implementing the
+ * <code>writeByte()</code> method in the <code>DataOutput</code> interface.
+ * <p>
+ * @return The <code>byte</code> 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 EOFException, IOException;
+
+ /**
+ * This method reads 8 unsigned bits into a Java <code>int</code> value from
+ * the stream. The value returned is in the range of 0 to 255.
+ * <p>
+ * This method can read an unsigned byte written by an object
+ * implementing the
+ * <code>writeByte()</code> method in the <code>DataOutput</code>
+ * interface.
+ *
+ * @return The unsigned bytes value read as a Java <code>int</code>.
+ *
+ * @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 EOFException, IOException;
+
+ /**
+ * This method reads a Java <code>char</code> value from an input stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single 16-bit Java <code>char</code>. The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code> represent the
+ * first and second byte read from the stream respectively, they will be
+ * transformed to a <code>char</code> in the following manner:
+ * <p>
+ * <code>(char)((byte1 << 8) + byte2)</code>
+ * <p>
+ * This method can read a <code>char</code> written by an object implementing
+ * the
+ * <code>writeChar()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>char</code> 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 EOFException, 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 <code>short</code>. The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code> represent the
+ * first and second byte read from the stream respectively, they will be
+ * transformed to a <code>short</code> in the following manner:
+ * <p>
+ * <code>(short)(((byte1 & 0xFF) << 8) + (byte2 & 0xFF))</code>
+ * <p>
+ * The value returned is in the range of -32768 to 32767.
+ * <p>
+ * This method can read a <code>short</code> written by an object
+ * implementing
+ * the <code>writeShort()</code> method in the <code>DataOutput</code>
+ * interface.
+ *
+ * @return The <code>short</code> 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 EOFException, 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 <code>int</code>. The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code> represent the
+ * first and second byte read from the stream respectively, they will be
+ * transformed to an <code>int</code> in the following manner:
+ * <p>
+ * <code>(int)(((byte1 0xFF) << 8) + (byte2 & 0xFF))</code>
+ * <p>
+ * The value returned is in the range of 0 to 65535.
+ * <p>
+ * This method can read an unsigned short written by an object implementing
+ * the <code>writeShort()</code> method in the
+ * <code>DataOutput</code>
+ * interface.
+ *
+ * @return The unsigned short value read as a Java <code>int</code>.
+ *
+ * @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 EOFException, IOException;
+
+ /**
+ * This method reads a Java <code>int</code> value from an input stream
+ * It operates by reading four bytes from the stream and converting them to
+ * a single Java <code>int</code>. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte4</code> represent
+ * the first four bytes read from the stream, they will be
+ * transformed to an <code>int</code> in the following manner:
+ * <p>
+ * <code>(int)(((byte1 & 0xFF) << 24) + ((byte2 & 0xFF) << 16) +
+ * ((byte3 & 0xFF)<< 8) + (byte4 & 0xFF)))</code>
+ * <p>
+ * The value returned is in the range of -2147483648 to 2147483647.
+ * <p>
+ * This method can read an <code>int</code> written by an object
+ * implementing the <code>writeInt()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>int</code> 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 EOFException, IOException;
+
+ /**
+ * This method reads a Java <code>long</code> value from an input stream
+ * It operates by reading eight bytes from the stream and converting them to
+ * a single Java <code>long</code>. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte8</code> represent
+ * the first eight bytes read from the stream, they will be
+ * transformed to an <code>long</code> in the following manner:
+ * <p>
+ * <code>(long)(((byte1 & 0xFF) << 56) + ((byte2 & 0xFF) << 48) +
+ * ((byte3 & 0xFF) << 40) + ((byte4 & 0xFF) << 32) +
+ * ((byte5 & 0xFF) << 24) + ((byte6 & 0xFF) << 16) +
+ * ((byte7 & 0xFF) << 8) + (byte8 & 0xFF)))
+ * </code>
+ * <p>
+ * The value returned is in the range of -9223372036854775808 to
+ * 9223372036854775807.
+ * <p>
+ * This method can read an <code>long</code> written by an object
+ * implementing the <code>writeLong()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>long</code> 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 EOFException, IOException;
+
+ /**
+ * This method reads a Java float value from an input stream. It operates
+ * by first reading an <code>int</code> value from the stream by calling the
+ * <code>readInt()</code> method in this interface, then converts that
+ * <code>int</code> to a <code>float</code> using the
+ * <code>intBitsToFloat</code> method in the class
+ * <code>java.lang.Float</code>.
+ * <p>
+ * This method can read a <code>float</code> written by an object
+ * implementing
+ * the <code>writeFloat()</code> method in the <code>DataOutput</code>
+ * interface.
+ *
+ * @return The <code>float</code> 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 EOFException, IOException;
+
+ /**
+ * This method reads a Java double value from an input stream. It operates
+ * by first reading a <code>long</code> value from the stream by calling the
+ * <code>readLong()</code> method in this interface, then converts that
+ * <code>long</code> to a <code>double</code> using the
+ * <code>longBitsToDouble</code> method in the class
+ * <code>java.lang.Double</code>.
+ * <p>
+ * This method can read a <code>double</code> written by an object
+ * implementing the <code>writeDouble()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>double</code> 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 EOFException, IOException;
+
+ /**
+ * This method reads the next line of text data from an input stream.
+ * It operates by reading bytes and converting those bytes to
+ * <code>char</code>
+ * values by treating the byte read as the low eight bits of the
+ * <code>char</code> and using 0 as the high eight bits. Because of this,
+ * it does not support the full 16-bit Unicode character set.
+ * <P>
+ * 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
+ * <code>String</code>.
+ * A line terminator is a byte sequence consisting of either
+ * <code>\r</code>, <code>\n</code> or <code>\r\n</code>. These termination
+ * charaters are discarded and are not returned as part of the string.
+ * A line is also terminated by an end of file condition.
+ * <p>
+ *
+ * @return The line read as a <code>String</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ String readLine() throws IOException;
+
+ /**
+ * This method reads a <code>String</code> from an input stream that is
+ * encoded in a modified UTF-8 format. This format has a leading two byte
+ * sequence that contains the remaining number of bytes to read.
+ * This two byte
+ * sequence is read using the <code>readUnsignedShort()</code> method of this
+ * interface.
+ *
+ * After the number of remaining bytes have been determined, these bytes
+ * are read an transformed into <code>char</code> values. These
+ * <code>char</code> values are encoded in the stream using either a one,
+ * two, or three byte format.
+ * The particular format in use can be determined by examining the first
+ * byte read.
+ * <p>
+ * If the first byte has a high order bit of 0, then
+ * that character consists on only one byte. This character value consists
+ * of seven bits that are at positions 0 through 6 of the byte. As an
+ * example, if <code>byte1</code> is the byte read from the stream, it would
+ * be converted to a <code>char</code> like so:
+ * <p>
+ * <code>(char)byte1</code>
+ * <p>
+ * If the first byte has 110 as its high order bits, then the
+ * character consists of two bytes. The bits that make up the character
+ * value are in positions 0 through 4 of the first byte and bit positions
+ * 0 through 5 of the second byte. (The second byte should have
+ * 10 as its high order bits). These values are in most significant
+ * byte first (i.e., "big endian") order.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code> are the first
+ * two bytes read respectively, and the high order bits of them match the
+ * patterns which indicate a two byte character encoding, then they would be
+ * converted to a Java <code>char</code> like so:
+ * <p>
+ * <code>(char)(((byte1 &amp; 0x1F) &lt;&lt; 6) + (byte2 &amp; 0x3F))</code>
+ * <p>
+ * If the first byte has a 1110 as its high order bits, then the
+ * character consists of three bytes. The bits that make up the character
+ * value are in positions 0 through 3 of the first byte and bit positions
+ * 0 through 5 of the other two bytes. (The second and third bytes should
+ * have 10 as their high order bits). These values are in most
+ * significant byte first (i.e., "big endian") order.
+ * <p>
+ * As an example, if <code>byte1</code>, <code>byte2</code>, and
+ * <code>byte3</code> are the three bytes read, and the high order bits of
+ * them match the patterns which indicate a three byte character encoding,
+ * then they would be converted to a Java <code>char</code> like so:
+ *
+ * <code>
+ * (char)(((byte1 &amp; 0x0F) &lt;&lt; 12) + ((byte2 &amp; 0x3F) + (byte3 &amp; 0x3F))
+ * </code>
+ *
+ * Note that all characters are encoded in the method that requires the
+ * fewest number of bytes with the exception of the character with the
+ * value of <code>\&lt;llll&gt;u0000</code> which is encoded as two bytes.
+ * This is a modification of the UTF standard used to prevent C language
+ * style <code>NUL</code> values from appearing in the byte stream.
+ * <p>
+ * This method can read data that was written by an object implementing the
+ * <code>writeUTF()</code> method in <code>DataOutput</code>.
+ *
+ * @return The <code>String</code> read
+ *
+ * @exception EOFException If end of file is reached before reading the
+ * String
+ * @exception UTFDataFormatException If the data is not in UTF-8 format
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeUTF
+ */
+ String readUTF() throws EOFException, UTFDataFormatException, 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 buf 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[] buf) throws EOFException, IOException;
+
+ /**
+ * This method reads raw bytes into the passed array <code>buf</code>
+ * starting
+ * <code>offset</code> bytes into the buffer. The number of bytes read
+ * will be
+ * exactly <code>len</code>. 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 <code>len</code> 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
+ */
+ void readFully(byte[] buf, int offset, int len)
+ throws EOFException, IOException;
+
+ /**
+ * This method skips and discards the specified number of bytes in an
+ * input stream. Note that this method may skip less than the requested
+ * number of bytes. The actual number of bytes skipped is returned.
+ * No bytes are skipped if a negative number is passed to this method.
+ *
+ * @param numBytes The number of bytes to skip
+ *
+ * @return The number of bytes actually skipped, which will always be
+ * <code>numBytes</code>
+ *
+ * @exception EOFException If end of file is reached before all bytes can be
+ * skipped
+ * @exception IOException If any other error occurs
+ */
+ int skipBytes(int numBytes) throws EOFException, IOException;
+
+} // interface DataInput
diff --git a/libjava/classpath/java/io/DataInputStream.java b/libjava/classpath/java/io/DataInputStream.java
new file mode 100644
index 000000000..518205b24
--- /dev/null
+++ b/libjava/classpath/java/io/DataInputStream.java
@@ -0,0 +1,785 @@
+/* DataInputStream.java -- FilteredInputStream that implements DataInput
+ Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005, 2008
+ 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 java.io;
+
+import gnu.java.lang.CPStringBuilder;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * This subclass of <code>FilteredInputStream</code> implements the
+ * <code>DataInput</code> interface that provides method for reading primitive
+ * Java data types from a stream.
+ *
+ * @see DataInput
+ *
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @date October 20, 1998.
+ */
+public class DataInputStream extends FilterInputStream implements DataInput
+{
+ // Byte buffer, used to make primitive read calls more efficient.
+ byte[] buf = new byte [8];
+
+ /**
+ * This constructor initializes a new <code>DataInputStream</code>
+ * to read from the specified subordinate stream.
+ *
+ * @param in The subordinate <code>InputStream</code> to read from
+ */
+ public DataInputStream (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 final 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 <code>len</code> bytes and
+ * will start storing them at position <code>off</code> 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 final 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 <code>false</code>. If the byte is non-zero, then
+ * the value returned is <code>true</code>.
+ * <p>
+ * This method can read a <code>boolean</code> written by an object
+ * implementing the <code>writeBoolean()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>boolean</code> 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 final 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.
+ * <p>
+ * This method can read a <code>byte</code> written by an object
+ * implementing the <code>writeByte()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>byte</code> 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 final byte readByte () throws IOException
+ {
+ return convertToByte (in.read ());
+ }
+
+ /**
+ * This method reads a Java <code>char</code> value from an input stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single 16-bit Java <code>char</code>. The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to a <code>char</code> in
+ * the following manner:
+ * <p>
+ * <code>(char)(((byte1 &amp; 0xFF) &lt;&lt; 8) | (byte2 &amp; 0xFF)</code>
+ * <p>
+ * This method can read a <code>char</code> written by an object
+ * implementing the <code>writeChar()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>char</code> 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 final 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 <code>long</code> value from the stream by calling the
+ * <code>readLong()</code> method in this interface, then converts
+ * that <code>long</code> to a <code>double</code> using the
+ * <code>longBitsToDouble</code> method in the class
+ * <code>java.lang.Double</code>
+ * <p>
+ * This method can read a <code>double</code> written by an object
+ * implementing the <code>writeDouble()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>double</code> 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 final 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 <code>int</code> value from the
+ * stream by calling the <code>readInt()</code> method in this
+ * interface, then converts that <code>int</code> to a
+ * <code>float</code> using the <code>intBitsToFloat</code> method
+ * in the class <code>java.lang.Float</code>
+ * <p>
+ * This method can read a <code>float</code> written by an object
+ * implementing the <code>writeFloat()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>float</code> 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 final 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 final void readFully (byte[] b) throws IOException
+ {
+ readFully (b, 0, b.length);
+ }
+
+ /**
+ * This method reads raw bytes into the passed array <code>buf</code>
+ * starting
+ * <code>offset</code> bytes into the buffer. The number of bytes read
+ * will be
+ * exactly <code>len</code>. 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 <code>len</code> 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 final 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 <code>int</code> value from an input stream
+ * It operates by reading four bytes from the stream and converting them to
+ * a single Java <code>int</code>. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte4</code> represent
+ * the first four bytes read from the stream, they will be
+ * transformed to an <code>int</code> in the following manner:
+ * <p>
+ * <code>(int)(((byte1 &amp; 0xFF) &lt;&lt; 24) + ((byte2 &amp; 0xFF) &lt;&lt; 16) +
+ * ((byte3 &amp; 0xFF)&lt;&lt; 8) + (byte4 &amp; 0xFF)))</code>
+ * <p>
+ * The value returned is in the range of -2147483648 to 2147483647.
+ * <p>
+ * This method can read an <code>int</code> written by an object
+ * implementing the <code>writeInt()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>int</code> 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 final 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 <code>char</code> values by treating the byte read as the low
+ * eight bits of the <code>char</code> and using 0 as the high eight
+ * bits. Because of this, it does not support the full 16-bit
+ * Unicode character set.
+ * <p>
+ * 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
+ * <code>String</code> A line terminator is a byte sequence
+ * consisting of either <code>\r</code>, <code>\n</code> or
+ * <code>\r\n</code>. These termination charaters are discarded and
+ * are not returned as part of the string.
+ * <p>
+ * This method can read data that was written by an object implementing the
+ * <code>writeLine()</code> method in <code>DataOutput</code>.
+ *
+ * @return The line read as a <code>String</code>
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataOutput
+ *
+ * @deprecated
+ */
+ public final String readLine() throws IOException
+ {
+ CPStringBuilder strb = new CPStringBuilder();
+
+ 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 <code>long</code> value from an input stream
+ * It operates by reading eight bytes from the stream and converting them to
+ * a single Java <code>long</code>. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte8</code> represent
+ * the first eight bytes read from the stream, they will be
+ * transformed to an <code>long</code> in the following manner:
+ * <p>
+ * <code>(long)(((byte1 &amp; 0xFF) &lt;&lt; 56) + ((byte2 &amp; 0xFF) &lt;&lt; 48) +
+ * ((byte3 &amp; 0xFF) &lt;&lt; 40) + ((byte4 &amp; 0xFF) &lt;&lt; 32) +
+ * ((byte5 &amp; 0xFF) &lt;&lt; 24) + ((byte6 &amp; 0xFF) &lt;&lt; 16) +
+ * ((byte7 &amp; 0xFF) &lt;&lt; 8) + (byte8 &amp; 0xFF)))
+ * </code>
+ * <p>
+ * The value returned is in the range of -9223372036854775808 to
+ * 9223372036854775807.
+ * <p>
+ * This method can read an <code>long</code> written by an object
+ * implementing the <code>writeLong()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>long</code> 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 final 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 <code>short</code>. The
+ * two bytes are stored most significant byte first (i.e., "big
+ * endian") regardless of the native host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to a <code>short</code>. in
+ * the following manner:
+ * <p>
+ * <code>(short)(((byte1 &amp; 0xFF) &lt;&lt; 8) | (byte2 &amp; 0xFF))</code>
+ * <p>
+ * The value returned is in the range of -32768 to 32767.
+ * <p>
+ * This method can read a <code>short</code> written by an object
+ * implementing the <code>writeShort()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>short</code> 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 final short readShort () throws IOException
+ {
+ readFully (buf, 0, 2);
+ return convertToShort (buf);
+ }
+
+ /**
+ * This method reads 8 unsigned bits into a Java <code>int</code>
+ * value from the stream. The value returned is in the range of 0 to
+ * 255.
+ * <p>
+ * This method can read an unsigned byte written by an object
+ * implementing the <code>writeUnsignedByte()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The unsigned bytes value read as a Java <code>int</code>.
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeByte
+ */
+ public final 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 <code>int</code> The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to an <code>int</code> in
+ * the following manner:
+ * <p>
+ * <code>(int)(((byte1 &amp; 0xFF) &lt;&lt; 8) + (byte2 &amp; 0xFF))</code>
+ * <p>
+ * The value returned is in the range of 0 to 65535.
+ * <p>
+ * This method can read an unsigned short written by an object
+ * implementing the <code>writeUnsignedShort()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The unsigned short value read as a Java <code>int</code>
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeShort
+ */
+ public final int readUnsignedShort () throws IOException
+ {
+ readFully (buf, 0, 2);
+ return convertToUnsignedShort (buf);
+ }
+
+ /**
+ * This method reads a <code>String</code> from an input stream that
+ * is encoded in a modified UTF-8 format. This format has a leading
+ * two byte sequence that contains the remaining number of bytes to
+ * read. This two byte sequence is read using the
+ * <code>readUnsignedShort()</code> method of this interface.
+ * <p>
+ * After the number of remaining bytes have been determined, these
+ * bytes are read an transformed into <code>char</code> values.
+ * These <code>char</code> values are encoded in the stream using
+ * either a one, two, or three byte format. The particular format
+ * in use can be determined by examining the first byte read.
+ * <p>
+ * If the first byte has a high order bit of 0, then that character
+ * consists on only one byte. This character value consists of
+ * seven bits that are at positions 0 through 6 of the byte. As an
+ * example, if <code>byte1</code> is the byte read from the stream,
+ * it would be converted to a <code>char</code> like so:
+ * <p>
+ * <code>(char)byte1</code>
+ * <p>
+ * If the first byte has 110 as its high order bits, then the
+ * character consists of two bytes. The bits that make up the character
+ * value are in positions 0 through 4 of the first byte and bit positions
+ * 0 through 5 of the second byte. (The second byte should have
+ * 10 as its high order bits). These values are in most significant
+ * byte first (i.e., "big endian") order.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code> are
+ * the first two bytes read respectively, and the high order bits of
+ * them match the patterns which indicate a two byte character
+ * encoding, then they would be converted to a Java
+ * <code>char</code> like so:
+ * <p>
+ * <code>(char)(((byte1 & 0x1F) << 6) | (byte2 & 0x3F))</code>
+ * <p>
+ * If the first byte has a 1110 as its high order bits, then the
+ * character consists of three bytes. The bits that make up the character
+ * value are in positions 0 through 3 of the first byte and bit positions
+ * 0 through 5 of the other two bytes. (The second and third bytes should
+ * have 10 as their high order bits). These values are in most
+ * significant byte first (i.e., "big endian") order.
+ * <p>
+ * As an example, if <code>byte1</code> <code>byte2</code> and
+ * <code>byte3</code> are the three bytes read, and the high order
+ * bits of them match the patterns which indicate a three byte
+ * character encoding, then they would be converted to a Java
+ * <code>char</code> like so:
+ * <p>
+ * <code>(char)(((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) |
+ * (byte3 & 0x3F))</code>
+ * <p>
+ * Note that all characters are encoded in the method that requires
+ * the fewest number of bytes with the exception of the character
+ * with the value of <code>&#92;u0000</code> which is encoded as two
+ * bytes. This is a modification of the UTF standard used to
+ * prevent C language style <code>NUL</code> values from appearing
+ * in the byte stream.
+ * <p>
+ * This method can read data that was written by an object implementing the
+ * <code>writeUTF()</code> method in <code>DataOutput</code>
+ *
+ * @return The <code>String</code> read
+ *
+ * @exception EOFException If end of file is reached before reading
+ * the String
+ * @exception UTFDataFormatException If the data is not in UTF-8 format
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeUTF
+ */
+ public final String readUTF () throws IOException
+ {
+ return readUTF (this);
+ }
+
+ /**
+ * This method reads a String encoded in UTF-8 format from the
+ * specified <code>DataInput</code> source.
+ *
+ * @param in The <code>DataInput</code> source to read from
+ *
+ * @return The String read from the source
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readUTF
+ */
+ public static final String readUTF(DataInput in) throws IOException
+ {
+ final int UTFlen = in.readUnsignedShort ();
+
+ return readUTF(in, UTFlen);
+ }
+
+ /**
+ * This method is similar to <code>readUTF</code>, but the
+ * UTF-8 byte length is in 64 bits.
+ * This method is not public. It is used by <code>ObjectInputStream</code>.
+ *
+ * @return The <code>String</code> read
+ *
+ * @exception EOFException If end of file is reached before reading
+ * the String
+ * @exception UTFDataFormatException If the data is not in UTF-8 format
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput#writeUTFLong
+ */
+ final String readUTFLong () throws IOException
+ {
+ long l = readLong ();
+ if (l > Integer.MAX_VALUE)
+ throw new IOException("The string length > Integer.MAX_VALUE");
+ final int UTFlen = (int)l;
+ return readUTF (this, UTFlen);
+ }
+
+ /**
+ * This method performs the main task of <code>readUTF</code> and
+ * <code>readUTFLong</code>.
+ *
+ * @param in The <code>DataInput</code> source to read from
+ *
+ * @param len The UTF-8 byte length of the String to be read
+ *
+ * @return The String read from the source
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readUTF
+ */
+ private static final String readUTF(DataInput in, int len) throws IOException
+ {
+ byte[] buf = new byte [len];
+
+ // This blocks until the entire string is available rather than
+ // doing partial processing on the bytes that are available and then
+ // blocking. An advantage of the latter is that Exceptions
+ // could be thrown earlier. The former is a bit cleaner.
+ in.readFully (buf, 0, len);
+
+ return convertFromUTF (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 final int skipBytes (int n) throws IOException
+ {
+ if (n <= 0)
+ return 0;
+ try
+ {
+ return (int) in.skip (n);
+ }
+ catch (EOFException x)
+ {
+ // do nothing.
+ }
+ return n;
+ }
+
+ static boolean convertToBoolean (int b) throws EOFException
+ {
+ if (b < 0)
+ throw new EOFException ();
+
+ return (b != 0);
+ }
+
+ static byte convertToByte (int i) throws EOFException
+ {
+ if (i < 0)
+ throw new EOFException ();
+
+ return (byte) i;
+ }
+
+ static int convertToUnsignedByte (int i) throws EOFException
+ {
+ if (i < 0)
+ throw new EOFException ();
+
+ return (i & 0xFF);
+ }
+
+ static char convertToChar (byte[] buf)
+ {
+ return (char) ((buf [0] << 8)
+ | (buf [1] & 0xff));
+ }
+
+ static short convertToShort (byte[] buf)
+ {
+ return (short) ((buf [0] << 8)
+ | (buf [1] & 0xff));
+ }
+
+ static int convertToUnsignedShort (byte[] buf)
+ {
+ return (((buf [0] & 0xff) << 8)
+ | (buf [1] & 0xff));
+ }
+
+ static int convertToInt (byte[] buf)
+ {
+ return (((buf [0] & 0xff) << 24)
+ | ((buf [1] & 0xff) << 16)
+ | ((buf [2] & 0xff) << 8)
+ | (buf [3] & 0xff));
+ }
+
+ static long convertToLong (byte[] buf)
+ {
+ return (((long)(buf [0] & 0xff) << 56) |
+ ((long)(buf [1] & 0xff) << 48) |
+ ((long)(buf [2] & 0xff) << 40) |
+ ((long)(buf [3] & 0xff) << 32) |
+ ((long)(buf [4] & 0xff) << 24) |
+ ((long)(buf [5] & 0xff) << 16) |
+ ((long)(buf [6] & 0xff) << 8) |
+ ((long)(buf [7] & 0xff)));
+ }
+
+ // FIXME: This method should be re-thought. I suspect we have multiple
+ // UTF-8 decoders floating around. We should use the standard charset
+ // converters, maybe and adding a direct call into one of the new
+ // NIO converters for a super-fast UTF8 decode.
+ static String convertFromUTF (byte[] buf)
+ throws EOFException, UTFDataFormatException
+ {
+ // Give StringBuffer an initial estimated size to avoid
+ // enlarge buffer frequently
+ CPStringBuilder strbuf = new CPStringBuilder (buf.length / 2 + 2);
+
+ for (int i = 0; i < buf.length; )
+ {
+ if ((buf [i] & 0x80) == 0) // bit pattern 0xxxxxxx
+ strbuf.append ((char) (buf [i++] & 0xFF));
+ else if ((buf [i] & 0xE0) == 0xC0) // bit pattern 110xxxxx
+ {
+ if (i + 1 >= buf.length
+ || (buf [i + 1] & 0xC0) != 0x80)
+ throw new UTFDataFormatException ();
+
+ strbuf.append((char) (((buf [i++] & 0x1F) << 6)
+ | (buf [i++] & 0x3F)));
+ }
+ else if ((buf [i] & 0xF0) == 0xE0) // bit pattern 1110xxxx
+ {
+ if (i + 2 >= buf.length
+ || (buf [i + 1] & 0xC0) != 0x80
+ || (buf [i + 2] & 0xC0) != 0x80)
+ throw new UTFDataFormatException ();
+
+ strbuf.append ((char) (((buf [i++] & 0x0F) << 12)
+ | ((buf [i++] & 0x3F) << 6)
+ | (buf [i++] & 0x3F)));
+ }
+ else // must be ((buf [i] & 0xF0) == 0xF0 || (buf [i] & 0xC0) == 0x80)
+ throw new UTFDataFormatException (); // bit patterns 1111xxxx or
+ // 10xxxxxx
+ }
+
+ return strbuf.toString ();
+ }
+}
diff --git a/libjava/classpath/java/io/DataOutput.java b/libjava/classpath/java/io/DataOutput.java
new file mode 100644
index 000000000..6eee4b702
--- /dev/null
+++ b/libjava/classpath/java/io/DataOutput.java
@@ -0,0 +1,325 @@
+/* DataOutput.java -- Interface for writing data from a stream
+ Copyright (C) 1998, 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 java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Complete to version 1.1.
+ */
+
+/**
+ * This interface is implemented by classes that can wrte data to streams
+ * from Java primitive types. This data can subsequently be read back
+ * by classes implementing the <code>DataInput</code> interface.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ *
+ * @see DataInput
+ */
+public interface DataOutput
+{
+ /**
+ * This method writes a Java boolean value to an output stream. If
+ * <code>value</code> is <code>true</code>, 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 <code>readBoolean</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The boolean value to write
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readBoolean
+ */
+ 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
+ * <code>int</code> value passed.
+ *
+ * The value written can be read using the <code>readByte</code> or
+ * <code>readUnsignedByte</code> methods in <code>DataInput</code>.
+ *
+ * @param value The int value to write
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readByte
+ * @see DataInput#readUnsignedByte
+ */
+ void writeByte(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 <code>int</code>
+ * value passed. These bytes will be written "big endian". That is,
+ * with the high byte written first in the following manner:
+ * <p>
+ * <code>byte0 = (byte)((value & 0xFF00) >> 8);<br>
+ * byte1 = (byte)(value & 0x00FF);</code>
+ * <p>
+ *
+ * The value written can be read using the <code>readChar</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The char value to write
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readChar
+ */
+ void writeChar(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 <code>int</code>
+ * value passed. These bytes will be written "big endian". That is,
+ * with the high byte written first in the following manner:
+ * <p>
+ * <code>byte0 = (byte)((value & 0xFF00) >> 8);<br>
+ * byte1 = (byte)(value & 0x00FF);</code>
+ * <p>
+ *
+ * The value written can be read using the <code>readShort</code> and
+ * <code>readUnsignedShort</code> methods in <code>DataInput</code>.
+ *
+ * @param value The int value to write as a 16-bit value
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readShort
+ * @see DataInput#readUnsignedShort
+ */
+ void writeShort(int value) throws IOException;
+
+ /**
+ * This method writes a Java int value to an output stream. The 4 bytes
+ * of the passed value will be written "big endian". That is, with
+ * the high byte written first in the following manner:
+ * <p>
+ * <code>byte0 = (byte)((value & 0xFF000000) >> 24);<br>
+ * byte1 = (byte)((value & 0x00FF0000) >> 16);<br>
+ * byte2 = (byte)((value & 0x0000FF00) >> 8);<br>
+ * byte3 = (byte)(value & 0x000000FF);</code>
+ * <p>
+ *
+ * The value written can be read using the <code>readInt</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The int value to write
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readInt
+ */
+ void writeInt(int value) throws IOException;
+
+ /**
+ * This method writes a Java long value to an output stream. The 8 bytes
+ * of the passed value will be written "big endian". That is, with
+ * the high byte written first in the following manner:
+ * <p>
+ * <code>byte0 = (byte)((value & 0xFF00000000000000L) >> 56);<br>
+ * byte1 = (byte)((value & 0x00FF000000000000L) >> 48);<br>
+ * byte2 = (byte)((value & 0x0000FF0000000000L) >> 40);<br>
+ * byte3 = (byte)((value & 0x000000FF00000000L) >> 32);<br>
+ * byte4 = (byte)((value & 0x00000000FF000000L) >> 24);<br>
+ * byte5 = (byte)((value & 0x0000000000FF0000L) >> 16);<br>
+ * byte6 = (byte)((value & 0x000000000000FF00L) >> 8);<br>
+ * byte7 = (byte)(value & 0x00000000000000FFL);</code>
+ * <p>
+ *
+ * The value written can be read using the <code>readLong</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The long value to write
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readLong
+ */
+ void writeLong(long value) throws IOException;
+
+ /**
+ * This method writes a Java <code>float</code> value to the stream. This
+ * value is written by first calling the method
+ * <code>Float.floatToIntBits</code>
+ * to retrieve an <code>int</code> representing the floating point number,
+ * then writing this <code>int</code> value to the stream exactly the same
+ * as the <code>writeInt()</code> method does.
+ *
+ * The value written can be read using the <code>readFloat</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The float value to write
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see #writeInt
+ * @see DataInput#readFloat
+ * @see Float#floatToIntBits
+ */
+ void writeFloat(float value) throws IOException;
+
+ /**
+ * This method writes a Java <code>double</code> value to the stream. This
+ * value is written by first calling the method
+ * <code>Double.doubleToLongBits</code>
+ * to retrieve an <code>long</code> representing the floating point number,
+ * then writing this <code>long</code> value to the stream exactly the same
+ * as the <code>writeLong()</code> method does.
+ *
+ * The value written can be read using the <code>readDouble</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The double value to write
+ *
+ * @exception IOException If any other error occurs
+ *
+ * @see #writeLong
+ * @see DataInput#readDouble
+ * @see Double#doubleToLongBits
+ */
+ void writeDouble(double value) throws IOException;
+
+ /**
+ * This method writes all the bytes in a <code>String</code> out to the
+ * stream. One byte is written for each character in the
+ * <code>String</code>.
+ * The high eight bits of each character are discarded, thus this
+ * method is inappropriate for completely representing Unicode characters.
+ *
+ * @param value The <code>String</code> to write
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeBytes(String value) throws IOException;
+
+ /**
+ * This method writes all the characters of a <code>String</code> to an
+ * output stream as an array of <code>char</code>'s. Each character
+ * is written using the method specified in the <code>writeChar</code>
+ * method.
+ *
+ * @param value The String to write
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see #writeChar(int)
+ */
+ void writeChars(String value) throws IOException;
+
+ /**
+ * This method writes a Java <code>String</code> to the stream in a modified
+ * UTF-8 format. First, two bytes are written to the stream indicating the
+ * number of bytes to follow. This is written in the form of a Java
+ * <code>short</code> value in the same manner used by the
+ * <code>writeShort</code> method. Note that this is the number of
+ * bytes in the
+ * encoded <code>String</code> not the <code>String</code> length. Next
+ * come the encoded characters. Each character in the <code>String</code>
+ * is encoded as either one, two or three bytes. For characters in the
+ * range of <code>\u0001</code> to <code>\u007F</code>, one byte is used.
+ * The character
+ * value goes into bits 0-7 and bit eight is 0. For characters in the range
+ * of <code>\u0080</code> to <code>\u007FF</code>, two bytes are used. Bits
+ * 6-10 of the character value are encoded bits 0-4 of the first byte, with
+ * the high bytes having a value of "110". Bits 0-5 of the character value
+ * are stored in bits 0-5 of the second byte, with the high bits set to
+ * "10". This type of encoding is also done for the null character
+ * <code>\u0000</code>. This eliminates any C style NUL character values
+ * in the output. All remaining characters are stored as three bytes.
+ * Bits 12-15 of the character value are stored in bits 0-3 of the first
+ * byte. The high bits of the first bytes are set to "1110". Bits 6-11
+ * of the character value are stored in bits 0-5 of the second byte. The
+ * high bits of the second byte are set to "10". And bits 0-5 of the
+ * character value are stored in bits 0-5 of byte three, with the high bits
+ * of that byte set to "10".
+ *
+ * The value written can be read using the <code>readUTF</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The <code>String</code> to write
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readUTF
+ */
+ void writeUTF(String value) throws IOException;
+
+ /**
+ * This method writes an 8-bit value (passed into the method as a Java
+ * <code>int</code>) to an output stream. The low 8 bits of the
+ * passed value are written.
+ *
+ * @param value The <code>byte</code> to write to the output stream
+ *
+ * @exception IOException If an error occurs
+ */
+ void write(int value) throws IOException;
+
+ /**
+ * This method writes the raw byte array passed in to the output stream.
+ *
+ * @param buf The byte array to write
+ *
+ * @exception IOException If an error occurs
+ */
+ void write(byte[] buf) throws IOException;
+
+ /**
+ * This method writes raw bytes from the passed array <code>buf</code>
+ * starting
+ * <code>offset</code> bytes into the buffer. The number of bytes
+ * written will be exactly <code>len</code>.
+ *
+ * @param buf The buffer from which to write the data
+ * @param offset The offset into the buffer to start writing data from
+ * @param len The number of bytes to write from the buffer to the output
+ * stream
+ *
+ * @exception IOException If any other error occurs
+ */
+ void write(byte[] buf, int offset, int len) throws IOException;
+
+} // interface DataOutput
diff --git a/libjava/classpath/java/io/DataOutputStream.java b/libjava/classpath/java/io/DataOutputStream.java
new file mode 100644
index 000000000..4837795c6
--- /dev/null
+++ b/libjava/classpath/java/io/DataOutputStream.java
@@ -0,0 +1,539 @@
+/* DataOutputStream.java -- Writes primitive Java datatypes to streams
+ Copyright (C) 1998, 2001, 2003, 2005, 2008 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Complete to version 1.1.
+ */
+
+/**
+ * This class provides a mechanism for writing primitive Java datatypes
+ * to an <code>OutputStream</code> in a portable way. Data written to
+ * a stream using this class can be read back in using the
+ * <code>DataInputStream</code> class on any platform.
+ *
+ * @see DataInputStream
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ */
+public class DataOutputStream extends FilterOutputStream implements DataOutput
+{
+ /**
+ * This is the total number of bytes that have been written to the
+ * stream by this object instance.
+ */
+ protected int written;
+
+ /**
+ * Utf8 byte buffer, used by writeUTF()
+ */
+ private byte[] buf;
+
+ /**
+ * This method initializes an instance of <code>DataOutputStream</code> to
+ * write its data to the specified underlying <code>OutputStream</code>
+ *
+ * @param out The subordinate <code>OutputStream</code> to which this
+ * object will write
+ */
+ public DataOutputStream (OutputStream out)
+ {
+ super (out);
+ written = 0;
+ }
+
+ /**
+ * 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 returns the total number of bytes that have been written to
+ * the underlying output stream so far. This is the value of the
+ * <code>written</code> instance variable
+ *
+ * @return The number of bytes written to the stream.
+ */
+ public final int size ()
+ {
+ return written;
+ }
+
+ /**
+ * This method writes the specified byte (passed as an <code>int</code>)
+ * to the underlying output stream.
+ *
+ * @param value The <code>byte</code> to write, passed as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public synchronized void write (int value) throws IOException
+ {
+ out.write (value);
+ ++written;
+ }
+
+ /**
+ * This method writes <code>len</code> bytes from the specified byte array
+ * <code>buf</code> starting at position <code>offset</code> 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);
+ written += len;
+ }
+
+ /**
+ * This method writes a Java boolean value to an output stream. If
+ * <code>value</code> is <code>true</code>, 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 <code>readBoolean</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The <code>boolean</code> value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readBoolean
+ */
+ public final 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
+ * <code>int</code> value passed.
+ *
+ * The value written can be read using the <code>readByte</code> or
+ * <code>readUnsignedByte</code> methods in <code>DataInput</code>.
+ *
+ * @param value The <code>byte</code> to write to the stream, passed as
+ * the low eight bits of an <code>int</code>.
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readByte
+ * @see DataInput#readUnsignedByte
+ */
+ public final void writeByte (int value) throws IOException
+ {
+ write (value & 0xff);
+ }
+
+ /**
+ * 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 <code>int</code>
+ * value passed. These bytes will be written "big endian". That is,
+ * with the high byte written first in the following manner:
+ * <p>
+ * <code>byte0 = (byte)((value & 0xFF00) >> 8);<br>
+ * byte1 = (byte)(value & 0x00FF);</code>
+ * <p>
+ *
+ * The value written can be read using the <code>readShort</code> and
+ * <code>readUnsignedShort</code> methods in <code>DataInput</code>.
+ *
+ * @param value The <code>short</code> value to write to the stream,
+ * passed as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readShort
+ * @see DataInput#readUnsignedShort
+ */
+ public final synchronized void writeShort (int value) throws IOException
+ {
+ write ((byte) (0xff & (value >> 8)));
+ write ((byte) (0xff & value));
+ }
+
+ /**
+ * 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 <code>int</code>
+ * value passed. These bytes will be written "big endian". That is,
+ * with the high byte written first in the following manner:
+ * <p>
+ * <code>byte0 = (byte)((value & 0xFF00) >> 8);<br>
+ * byte1 = (byte)(value & 0x00FF);</code>
+ * <p>
+ *
+ * The value written can be read using the <code>readChar</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The <code>char</code> value to write,
+ * passed as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readChar
+ */
+ public final synchronized void writeChar (int value) throws IOException
+ {
+ write ((byte) (0xff & (value >> 8)));
+ write ((byte) (0xff & value));
+ }
+
+ /**
+ * This method writes a Java int value to an output stream. The 4 bytes
+ * of the passed value will be written "big endian". That is, with
+ * the high byte written first in the following manner:
+ * <p>
+ * <code>byte0 = (byte)((value & 0xFF000000) >> 24);<br>
+ * byte1 = (byte)((value & 0x00FF0000) >> 16);<br>
+ * byte2 = (byte)((value & 0x0000FF00) >> 8);<br>
+ * byte3 = (byte)(value & 0x000000FF);</code>
+ * <p>
+ *
+ * The value written can be read using the <code>readInt</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The <code>int</code> value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readInt
+ */
+ public final synchronized void writeInt (int value) throws IOException
+ {
+ write ((byte) (0xff & (value >> 24)));
+ write ((byte) (0xff & (value >> 16)));
+ write ((byte) (0xff & (value >> 8)));
+ write ((byte) (0xff & value));
+ }
+
+ /**
+ * This method writes a Java long value to an output stream. The 8 bytes
+ * of the passed value will be written "big endian". That is, with
+ * the high byte written first in the following manner:
+ * <p>
+ * <code>byte0 = (byte)((value & 0xFF00000000000000L) >> 56);<br>
+ * byte1 = (byte)((value & 0x00FF000000000000L) >> 48);<br>
+ * byte2 = (byte)((value & 0x0000FF0000000000L) >> 40);<br>
+ * byte3 = (byte)((value & 0x000000FF00000000L) >> 32);<br>
+ * byte4 = (byte)((value & 0x00000000FF000000L) >> 24);<br>
+ * byte5 = (byte)((value & 0x0000000000FF0000L) >> 16);<br>
+ * byte6 = (byte)((value & 0x000000000000FF00L) >> 8);<br>
+ * byte7 = (byte)(value & 0x00000000000000FFL);</code>
+ * <p>
+ *
+ * The value written can be read using the <code>readLong</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The <code>long</code> value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readLong
+ */
+ public final synchronized void writeLong (long value) throws IOException
+ {
+ write ((byte) (0xff & (value >> 56)));
+ write ((byte) (0xff & (value>> 48)));
+ write ((byte) (0xff & (value>> 40)));
+ write ((byte) (0xff & (value>> 32)));
+ write ((byte) (0xff & (value>> 24)));
+ write ((byte) (0xff & (value>> 16)));
+ write ((byte) (0xff & (value>> 8)));
+ write ((byte) (0xff & value));
+ }
+
+ /**
+ * This method writes a Java <code>float</code> value to the stream. This
+ * value is written by first calling the method
+ * <code>Float.floatToIntBits</code>
+ * to retrieve an <code>int</code> representing the floating point number,
+ * then writing this <code>int</code> value to the stream exactly the same
+ * as the <code>writeInt()</code> method does.
+ *
+ * The value written can be read using the <code>readFloat</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The <code>float</code> value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see #writeInt(int)
+ * @see DataInput#readFloat
+ * @see Float#floatToIntBits
+ */
+ public final void writeFloat (float value) throws IOException
+ {
+ writeInt (Float.floatToIntBits (value));
+ }
+
+ /**
+ * This method writes a Java <code>double</code> value to the stream. This
+ * value is written by first calling the method
+ * <code>Double.doubleToLongBits</code>
+ * to retrieve an <code>long</code> representing the floating point number,
+ * then writing this <code>long</code> value to the stream exactly the same
+ * as the <code>writeLong()</code> method does.
+ *
+ * The value written can be read using the <code>readDouble</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The <code>double</code> value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see #writeLong(long)
+ * @see DataInput#readDouble
+ * @see Double#doubleToLongBits
+ */
+ public final void writeDouble (double value) throws IOException
+ {
+ writeLong (Double.doubleToLongBits (value));
+ }
+
+ /**
+ * This method writes all the bytes in a <code>String</code> out to the
+ * stream. One byte is written for each character in the
+ * <code>String</code>.
+ * The high eight bits of each character are discarded, thus this
+ * method is inappropriate for completely representing Unicode characters.
+ *
+ * @param value The <code>String</code> to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public final void writeBytes (String value) throws IOException
+ {
+ int len = value.length();
+ for (int i = 0; i < len; ++i)
+ writeByte (value.charAt(i));
+ }
+
+ /**
+ * This method writes all the characters of a <code>String</code> to an
+ * output stream as an array of <code>char</code>'s. Each character
+ * is written using the method specified in the <code>writeChar</code>
+ * method.
+ *
+ * @param value The <code>String</code> to write to the stream
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see #writeChar(char)
+ */
+ public final void writeChars (String value) throws IOException
+ {
+ int len = value.length();
+ for (int i = 0; i < len; ++i)
+ writeChar (value.charAt(i));
+ }
+
+ /**
+ * Calculate the length, in bytes, of a <code>String</code> in Utf8 format.
+ * This method is package-private so that <code>ObjectOutputStream</code>
+ * may use it. The return type is long so that a long string whose
+ * Utf8 byte count is 64 bit long may be handled.
+ *
+ * @param value The <code>String</code> to measure
+ * @param start String index at which to begin count
+ * @param sum Starting Utf8 byte count
+ *
+ */
+ long getUTFlength(String value, int start, long sum)
+ {
+ int len = value.length();
+
+ for (int i = start; i < len; ++i)
+ {
+ char c = value.charAt(i);
+ if (c >= '\u0001' && c <= '\u007f')
+ sum += 1;
+ else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff'))
+ sum += 2;
+ else
+ sum += 3;
+ }
+
+ return sum;
+ }
+
+ /**
+ * This method writes a Java <code>String</code> to the stream in a modified
+ * UTF-8 format. First, two bytes are written to the stream indicating the
+ * number of bytes to follow. Note that this is the number of bytes in the
+ * encoded <code>String</code> not the <code>String</code> length. Next
+ * come the encoded characters. Each character in the <code>String</code>
+ * is encoded as either one, two or three bytes. For characters in the
+ * range of <code>\u0001</code> to <\u007F>, one byte is used. The character
+ * value goes into bits 0-7 and bit eight is 0. For characters in the range
+ * of <code>\u0080</code> to <code>\u007FF</code>, two bytes are used. Bits
+ * 6-10 of the character value are encoded bits 0-4 of the first byte, with
+ * the high bytes having a value of "110". Bits 0-5 of the character value
+ * are stored in bits 0-5 of the second byte, with the high bits set to
+ * "10". This type of encoding is also done for the null character
+ * <code>\u0000</code>. This eliminates any C style NUL character values
+ * in the output. All remaining characters are stored as three bytes.
+ * Bits 12-15 of the character value are stored in bits 0-3 of the first
+ * byte. The high bits of the first bytes are set to "1110". Bits 6-11
+ * of the character value are stored in bits 0-5 of the second byte. The
+ * high bits of the second byte are set to "10". And bits 0-5 of the
+ * character value are stored in bits 0-5 of byte three, with the high bits
+ * of that byte set to "10".
+ *
+ * The value written can be read using the <code>readUTF</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The <code>String</code> to write to the output in UTF format
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readUTF
+ */
+ public final synchronized void writeUTF(String value) throws IOException
+ {
+ long l = getUTFlength(value, 0, 0);
+ if (l > 65535)
+ throw new UTFDataFormatException ();
+ writeUTFShort(value, (int)l);
+ }
+
+ /**
+ * This method performs the main task of <code>writeUTF</code>.
+ * This method is package-private because ObjectOutputStream uses it.
+ *
+ * @param value The <code>String</code> to write to the output in UTF format
+ *
+ * @param bytelen The UTF-8 byte length of the <code>String</code>. When
+ * this method is called, the expected byte length must have been calculated
+ * by <code>getUTFlength</code>.
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataInput#readUTF
+ */
+ final synchronized void writeUTFShort(String value, int bytelen)
+ throws IOException
+ {
+ writeShort(bytelen);
+ writeUTFBytes(value);
+ }
+
+ /**
+ * This method is similar to <code>writeUTF</code>, but it writes the
+ * UTF-8 byte length in 64 bits.
+ * This method is not public but <code>ObjectOutputStream</code> uses it.
+ *
+ * @param value The <code>String</code> to write to the output in UTF format
+ *
+ * @param bytelen The UTF-8 byte length of the <code>String</code>. When
+ * this method is called, the expected byte length must have been calculated
+ * by <code>getUTFlength</code>.
+ *
+ * @exception IOException If an error occurs
+ *
+ */
+ final synchronized void writeUTFLong(String value, long bytelen)
+ throws IOException
+ {
+ writeLong(bytelen);
+ writeUTFBytes(value);
+ }
+
+ /**
+ * This method performes the main task of <code>writeUTF</code> and
+ * <code>WriteUTFLong</code>, which is to write the UTF-8 byte
+ * sequence to the output.
+ *
+ * @param value The <code>String</code> to write to the output in UTF format
+ *
+ * @exception IOException If an error occurs
+ *
+ */
+ private final synchronized void writeUTFBytes(String value)
+ throws IOException
+ {
+ int len = value.length();
+ int i = 0;
+ int pos = 0;
+
+ if (buf == null)
+ buf = new byte[512];
+
+ do
+ {
+ while (i < len && pos < buf.length - 3)
+ {
+ char c = value.charAt(i++);
+ if (c >= '\u0001' && c <= '\u007f')
+ buf[pos++] = (byte) c;
+ else if (c == '\u0000' || (c >= '\u0080' && c <= '\u07ff'))
+ {
+ buf[pos++] = (byte) (0xc0 | (0x1f & (c >> 6)));
+ buf[pos++] = (byte) (0x80 | (0x3f & c));
+ }
+ else
+ {
+ // JSL says the first byte should be or'd with 0xc0, but
+ // that is a typo. Unicode says 0xe0, and that is what is
+ // consistent with DataInputStream.
+ buf[pos++] = (byte) (0xe0 | (0x0f & (c >> 12)));
+ buf[pos++] = (byte) (0x80 | (0x3f & (c >> 6)));
+ buf[pos++] = (byte) (0x80 | (0x3f & c));
+ }
+ }
+ write(buf, 0, pos);
+ pos = 0;
+ }
+ while (i < len);
+ }
+
+} // class DataOutputStream
diff --git a/libjava/classpath/java/io/DeleteFileHelper.java b/libjava/classpath/java/io/DeleteFileHelper.java
new file mode 100644
index 000000000..a2b96bb41
--- /dev/null
+++ b/libjava/classpath/java/io/DeleteFileHelper.java
@@ -0,0 +1,106 @@
+/* DeleteFileHelper.java -- Helper class to delete files on VM exit
+ 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 java.io;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+
+/**
+ * @author Guilhem Lavaux (guilhem@kaffe.org)
+ * @author Jeroen Frijters (jeroen@sumatra.nl)
+ * @author Michael Koch (konqueror@gmx.de)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+final class DeleteFileHelper extends Thread
+{
+ private static ArrayList<File> filesToDelete;
+
+ static synchronized void add(File file)
+ {
+ if (filesToDelete == null)
+ {
+ filesToDelete = new ArrayList<File>();
+
+ AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ try
+ {
+ Runtime.getRuntime().addShutdownHook(new DeleteFileHelper());
+ }
+ catch (IllegalStateException e)
+ {
+ // Shutdown is already in progress, so we can't
+ // register ours.
+ }
+
+ return null;
+ }
+ });
+ }
+
+ filesToDelete.add(file);
+ }
+
+ private static synchronized void deleteFiles()
+ {
+ for (File file : filesToDelete)
+ {
+ try
+ {
+ file.delete();
+ }
+ catch (Exception e)
+ {
+ // Do nothing here.
+ }
+ }
+ }
+
+ // Package-private to avoid a trampoline constructor.
+ DeleteFileHelper()
+ {
+ }
+
+ public void run()
+ {
+ deleteFiles();
+ }
+}
diff --git a/libjava/classpath/java/io/EOFException.java b/libjava/classpath/java/io/EOFException.java
new file mode 100644
index 000000000..0d90a3f0f
--- /dev/null
+++ b/libjava/classpath/java/io/EOFException.java
@@ -0,0 +1,76 @@
+/* EOFException.java -- unexpected end of file exception
+ Copyright (C) 1998, 1999, 2001, 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 java.io;
+
+/**
+ * This exception is thrown when the end of the file or stream was
+ * encountered unexpectedly. This is not the normal way that an EOF
+ * condition is reported; such as a special value like -1 being returned.
+ * However, certain types of streams expecting certain data in a certain
+ * format might reach EOF before reading their expected data pattern and
+ * thus throw this exception.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ * @status updated to 1.4
+ */
+public class EOFException extends IOException
+{
+ /**
+ * Compatible with JDK 1.0+.
+ */
+ private static final long serialVersionUID = 6433858223774886977L;
+
+ /**
+ * Create an exception without a descriptive error message.
+ */
+ public EOFException()
+ {
+ }
+
+ /**
+ * Create an exception with a descriptive error message.
+ *
+ * @param message the descriptive error message
+ */
+ public EOFException(String message)
+ {
+ super(message);
+ }
+} // class EOFException
diff --git a/libjava/classpath/java/io/Externalizable.java b/libjava/classpath/java/io/Externalizable.java
new file mode 100644
index 000000000..7399dab3b
--- /dev/null
+++ b/libjava/classpath/java/io/Externalizable.java
@@ -0,0 +1,107 @@
+/* Externalizable.java -- Interface for saving and restoring object data
+ 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 java.io;
+
+/**
+ * This interface provides a way that classes can completely control how
+ * the data of their object instances are written and read to and from
+ * streams. It has two methods which are used to write the data to a stream
+ * and to read the data from a stream. The read method must read the data
+ * in exactly the way it was written by the write method.
+ * <p>
+ * Note that classes which implement this interface must take into account
+ * that all superclass data must also be written to the stream as well.
+ * The class implementing this interface must figure out how to make that
+ * happen.
+ * <p>
+ * This interface can be used to provide object persistence. When an
+ * object is to be stored externally, the <code>writeExternal</code> method is
+ * called to save state. When the object is restored, an instance is
+ * created using the default no-argument constructor and the
+ * <code>readExternal</code> method is used to restore the state.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public interface Externalizable extends Serializable
+{
+ /**
+ * This method restores an object's state by reading in the instance data
+ * for the object from the passed in stream. Note that this stream is not
+ * a subclass of <code>InputStream</code>, but rather is a class that
+ * implements
+ * the <code>ObjectInput</code> interface. That interface provides a
+ * mechanism for
+ * reading in Java data types from a stream.
+ * <p>
+ * Note that this method must be compatible with <code>writeExternal</code>.
+ * It must read back the exact same types that were written by that
+ * method in the exact order they were written.
+ * <p>
+ * If this method needs to read back an object instance, then the class
+ * for that object must be found and loaded. If that operation fails,
+ * then this method throws a <code>ClassNotFoundException</code>
+ *
+ * @param in An <code>ObjectInput</code> instance for reading in the object
+ * state
+ *
+ * @exception ClassNotFoundException If the class of an object being
+ * restored cannot be found
+ * @exception IOException If any other error occurs
+ */
+ void readExternal(ObjectInput in)
+ throws ClassNotFoundException, IOException;
+
+ /**
+ * This method is responsible for writing the instance data of an object
+ * to the passed in stream. Note that this stream is not a subclass of
+ * <code>OutputStream</code>, but rather is a class that implements the
+ * <code>ObjectOutput</code> interface. That interface provides a
+ * number of methods
+ * for writing Java data values to a stream.
+ * <p>
+ * Not that the implementation of this method must be coordinated with
+ * the implementation of <code>readExternal</code>.
+ *
+ * @param out An <code>ObjectOutput</code> instance for writing the
+ * object state
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeExternal(ObjectOutput out) throws IOException;
+}
diff --git a/libjava/classpath/java/io/File.java b/libjava/classpath/java/io/File.java
new file mode 100644
index 000000000..4f670e147
--- /dev/null
+++ b/libjava/classpath/java/io/File.java
@@ -0,0 +1,1605 @@
+/* File.java -- Class representing a file on disk
+ Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+import gnu.classpath.SystemProperties;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Complete to version 1.3.
+ */
+
+/**
+ * This class represents a file or directory on a local disk. It provides
+ * facilities for dealing with a variety of systems that use various
+ * types of path separators ("/" versus "\", for example). It also
+ * contains method useful for creating and deleting files and directories.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ */
+public class File implements Serializable, Comparable<File>
+{
+ private static final long serialVersionUID = 301077366599181567L;
+
+ /**
+ * This is the path separator string for the current host. This field
+ * contains the value of the <code>file.separator</code> system property.
+ * An example separator string would be "/" on the GNU system.
+ */
+ public static final String separator = SystemProperties.getProperty("file.separator");
+ private static final String dupSeparator = separator + separator;
+
+ /**
+ * This is the first character of the file separator string. On many
+ * hosts (for example, on the GNU system), this represents the entire
+ * separator string. The complete separator string is obtained from the
+ * <code>file.separator</code>system property.
+ */
+ public static final char separatorChar = separator.charAt(0);
+
+ /**
+ * This is the string that is used to separate the host name from the
+ * path name in paths that include the host name. It is the value of
+ * the <code>path.separator</code> system property.
+ */
+ public static final String pathSeparator
+ = SystemProperties.getProperty("path.separator");
+
+ /**
+ * This is the first character of the string used to separate the host name
+ * from the path name in paths that include a host. The separator string
+ * is taken from the <code>path.separator</code> system property.
+ */
+ public static final char pathSeparatorChar = pathSeparator.charAt(0);
+
+ /**
+ * This is the path to the file set when the object is created. It
+ * may be an absolute or relative path name.
+ */
+ private String path;
+
+
+ /**
+ * The time (millisecond), when the last temporary file was created.
+ */
+ private static long last_tmp;
+
+ /**
+ * The number of files, created during the current millisecond.
+ */
+ private static int n_created;
+
+ /**
+ * This method tests whether or not the current thread is allowed to
+ * to read the file pointed to by this object. This will be true if and
+ * and only if 1) the file exists and 2) the <code>SecurityManager</code>
+ * (if any) allows access to the file via it's <code>checkRead</code>
+ * method 3) the file is readable.
+ *
+ * @return <code>true</code> if reading is allowed,
+ * <code>false</code> otherwise
+ *
+ * @exception SecurityException If the <code>SecurityManager</code>
+ * does not allow access to the file
+ */
+ public boolean canRead()
+ {
+ // Test for existence. This also does the SecurityManager check
+ if (!exists())
+ return false;
+
+ return VMFile.canRead(path);
+ }
+
+ /**
+ * This method test whether or not the current thread is allowed to
+ * write to this object. This will be true if and only if 1) The
+ * <code>SecurityManager</code> (if any) allows write access to the
+ * file and 2) The file exists and 3) The file is writable. To determine
+ * whether or not a non-existent file can be created, check the parent
+ * directory for write access.
+ *
+ * @return <code>true</code> if writing is allowed, <code>false</code>
+ * otherwise
+ *
+ * @exception SecurityException If the <code>SecurityManager</code>
+ * does not allow access to the file
+ */
+ public boolean canWrite()
+ {
+ // First do a SecurityCheck before doing anything else.
+ checkWrite();
+
+ // Test for existence. This is required by the spec
+ if (! VMFile.exists(path))
+ return false;
+
+ if (VMFile.isDirectory(path))
+ return VMFile.canWriteDirectory(path);
+ else
+ return VMFile.canWrite(path);
+ }
+
+ /**
+ * This method tests whether or not the current thread is allowed to
+ * to execute the file pointed to by this object. This will be true if and
+ * and only if 1) the file exists and 2) the <code>SecurityManager</code>
+ * (if any) allows access to the file via it's <code>checkExec</code>
+ * method 3) the file is executable.
+ *
+ * @return <code>true</code> if execution is allowed,
+ * <code>false</code> otherwise
+ *
+ * @exception SecurityException If the <code>SecurityManager</code>
+ * does not allow access to the file
+ */
+ public boolean canExecute()
+ {
+ if (!VMFile.exists(path))
+ return false;
+
+ checkExec();
+
+ return VMFile.canExecute(path);
+ }
+
+ /**
+ * This method creates a new file of zero length with the same name as
+ * the path of this <code>File</code> object if an only if that file
+ * does not already exist.
+ * <p>
+ * A <code>SecurityManager.checkWrite</code> check is done prior
+ * to performing this action.
+ *
+ * @return <code>true</code> if the file was created, <code>false</code> if
+ * the file alread existed.
+ *
+ * @exception IOException If an I/O error occurs
+ * @exception SecurityException If the <code>SecurityManager</code> will
+ * not allow this operation to be performed.
+ *
+ * @since 1.2
+ */
+ public boolean createNewFile() throws IOException
+ {
+ checkWrite();
+ return VMFile.create(path);
+ }
+ /**
+ * This method deletes the file represented by this object. If this file
+ * is a directory, it must be empty in order for the delete to succeed.
+ *
+ * @return <code>true</code> if the file was deleted, <code>false</code>
+ * otherwise
+ *
+ * @exception SecurityException If deleting of the file is not allowed
+ */
+ public synchronized boolean delete()
+ {
+ SecurityManager s = System.getSecurityManager();
+
+ if (s != null)
+ s.checkDelete(path);
+
+ return VMFile.delete(path);
+ }
+
+ /**
+ * This method tests two <code>File</code> objects for equality by
+ * comparing the path of the specified <code>File</code> against the path
+ * of this object. The two objects are equal if an only if 1) The
+ * argument is not null 2) The argument is a <code>File</code> object and
+ * 3) The path of the <code>File</code>argument is equal to the path
+ * of this object.
+ * <p>
+ * The paths of the files are determined by calling the
+ * <code>getPath()</code>
+ * method on each object.
+ *
+ * @return <code>true</code> if the two objects are equal,
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if (! (obj instanceof File))
+ return false;
+
+ File other = (File) obj;
+
+ if (VMFile.IS_CASE_SENSITIVE)
+ return path.equals(other.path);
+ else
+ return path.equalsIgnoreCase(other.path);
+ }
+
+ /**
+ * This method tests whether or not the file represented by the object
+ * actually exists on the filesystem.
+ *
+ * @return <code>true</code> if the file exists, <code>false</code>otherwise.
+ *
+ * @exception SecurityException If reading of the file is not permitted
+ */
+ public boolean exists()
+ {
+ checkRead();
+ return VMFile.exists(path);
+ }
+
+ /**
+ * This method initializes a new <code>File</code> object to represent
+ * a file with the specified path.
+ *
+ * @param name The path name of the file
+ */
+ public File(String name)
+ {
+ path = normalizePath (name);
+ }
+
+ // Remove duplicate and redundant separator characters.
+ private String normalizePath(String p)
+ {
+ // On Windows, convert any '/' to '\'. This appears to be the same logic
+ // that Sun's Win32 Java performs.
+ if (separatorChar == '\\')
+ {
+ p = p.replace ('/', '\\');
+ // We have to special case the "\c:" prefix.
+ if (p.length() > 2 && p.charAt(0) == '\\' &&
+ ((p.charAt(1) >= 'a' && p.charAt(1) <= 'z') ||
+ (p.charAt(1) >= 'A' && p.charAt(1) <= 'Z')) &&
+ p.charAt(2) == ':')
+ p = p.substring(1);
+ }
+
+ int dupIndex = p.indexOf(dupSeparator);
+ int plen = p.length();
+
+ // Special case: permit Windows UNC path prefix.
+ if (dupSeparator.equals("\\\\") && dupIndex == 0)
+ dupIndex = p.indexOf(dupSeparator, 1);
+
+ if (dupIndex == -1)
+ {
+ // Ignore trailing separator (though on Windows "a:\", for
+ // example, is a valid and minimal path).
+ if (plen > 1 && p.charAt (plen - 1) == separatorChar)
+ {
+ if (! (separatorChar == '\\' && ((plen == 3 && p.charAt(1) == ':')
+ || (plen == 2 && p.charAt(0) == separatorChar))))
+ return p.substring (0, plen - 1);
+ }
+ else
+ return p;
+ }
+
+ CPStringBuilder newpath = new CPStringBuilder(plen);
+ int last = 0;
+ while (dupIndex != -1)
+ {
+ newpath.append(p.substring(last, dupIndex));
+ // Ignore the duplicate path characters.
+ while (p.charAt(dupIndex) == separatorChar)
+ {
+ dupIndex++;
+ if (dupIndex == plen)
+ {
+ if ((separatorChar == '\\'
+ && newpath.length() == 2
+ && newpath.charAt(1) == ':')
+ || (separatorChar != '\\' && newpath.length() == 0))
+ {
+ newpath.append(separatorChar);
+ }
+ return newpath.toString();
+ }
+ }
+ newpath.append(separatorChar);
+ last = dupIndex;
+ dupIndex = p.indexOf(dupSeparator, last);
+ }
+
+ // Again, ignore possible trailing separator (except special cases
+ // like "a:\" on Windows).
+ int end;
+ if (plen > 1 && p.charAt (plen - 1) == separatorChar)
+ {
+ if (separatorChar == '\\'
+ && ((plen == 3 && p.charAt(1) == ':')
+ || (plen == 2 && p.charAt(0) == separatorChar)))
+ end = plen;
+ else
+ end = plen - 1;
+ }
+ else
+ end = plen;
+ newpath.append(p.substring(last, end));
+
+ return newpath.toString();
+ }
+
+ /**
+ * This method initializes a new <code>File</code> object to represent
+ * a file in the specified named directory. The path name to the file
+ * will be the directory name plus the separator string plus the file
+ * name. If the directory path name ends in the separator string, another
+ * separator string will still be appended.
+ *
+ * @param dirPath The path to the directory the file resides in
+ * @param name The name of the file
+ */
+ public File(String dirPath, String name)
+ {
+ if (name == null)
+ throw new NullPointerException();
+ if (dirPath != null)
+ {
+ if (dirPath.length() > 0)
+ {
+ // Try to be smart about the number of separator characters.
+ if (dirPath.charAt(dirPath.length() - 1) == separatorChar
+ || name.length() == 0)
+ path = normalizePath(dirPath + name);
+ else
+ path = normalizePath(dirPath + separatorChar + name);
+ }
+ else
+ {
+ // If dirPath is empty, use a system dependant
+ // default prefix.
+ // Note that the leading separators in name have
+ // to be chopped off, to prevent them forming
+ // a UNC prefix on Windows.
+ if (separatorChar == '\\' /* TODO use ON_WINDOWS */)
+ {
+ int skip = 0;
+ while(name.length() > skip
+ && (name.charAt(skip) == separatorChar
+ || name.charAt(skip) == '/'))
+ {
+ skip++;
+ }
+ name = name.substring(skip);
+ }
+ path = normalizePath(separatorChar + name);
+ }
+ }
+ else
+ path = normalizePath(name);
+ }
+
+ /**
+ * This method initializes a new <code>File</code> object to represent
+ * a file in the specified directory. If the <code>directory</code>
+ * argument is <code>null</code>, the file is assumed to be in the
+ * current directory as specified by the <code>user.dir</code> system
+ * property
+ *
+ * @param directory The directory this file resides in
+ * @param name The name of the file
+ */
+ public File(File directory, String name)
+ {
+ this (directory == null ? null : directory.path, name);
+ }
+
+ /**
+ * This method initializes a new <code>File</code> object to represent
+ * a file corresponding to the specified <code>file:</code> protocol URI.
+ *
+ * @param uri The URI
+ * @throws IllegalArgumentException if the URI is not hierarchical
+ */
+ public File(URI uri)
+ {
+ if (uri == null)
+ throw new NullPointerException("uri is null");
+
+ if (!uri.getScheme().equals("file"))
+ throw new IllegalArgumentException("invalid uri protocol");
+
+ String name = uri.getPath();
+ if (name == null)
+ throw new IllegalArgumentException("URI \"" + uri
+ + "\" is not hierarchical");
+ path = normalizePath(name);
+ }
+
+ /**
+ * This method returns the path of this file as an absolute path name.
+ * If the path name is already absolute, then it is returned. Otherwise
+ * the value returned is the current directory plus the separatory
+ * string plus the path of the file. The current directory is determined
+ * from the <code>user.dir</code> system property.
+ *
+ * @return The absolute path of this file
+ */
+ public String getAbsolutePath()
+ {
+ if (isAbsolute())
+ return path;
+ else
+ return VMFile.getAbsolutePath(path);
+ }
+
+ /**
+ * This method returns a <code>File</code> object representing the
+ * absolute path of this object.
+ *
+ * @return A <code>File</code> with the absolute path of the object.
+ *
+ * @since 1.2
+ */
+ public File getAbsoluteFile()
+ {
+ return new File(getAbsolutePath());
+ }
+
+ /**
+ * This method returns a canonical representation of the pathname of
+ * this file. The actual form of the canonical representation is
+ * system-dependent. On the GNU system, conversion to canonical
+ * form involves the removal of redundant separators, references to
+ * "." and "..", and symbolic links.
+ * <p>
+ * Note that this method, unlike the other methods which return path
+ * names, can throw an IOException. This is because native method
+ * might be required in order to resolve the canonical path
+ *
+ * @exception IOException If an error occurs
+ */
+ public String getCanonicalPath() throws IOException
+ {
+ // On Windows, getAbsolutePath might end up calling us, so we
+ // have to special case that call to avoid infinite recursion.
+ if (separatorChar == '\\' && path.length() == 2 &&
+ ((path.charAt(0) >= 'a' && path.charAt(0) <= 'z') ||
+ (path.charAt(0) >= 'A' && path.charAt(0) <= 'Z')) &&
+ path.charAt(1) == ':')
+ {
+ return VMFile.toCanonicalForm(path);
+ }
+ // Call getAbsolutePath first to make sure that we do the
+ // current directory handling, because the native code
+ // may have a different idea of the current directory.
+ return VMFile.toCanonicalForm(getAbsolutePath());
+ }
+
+ /**
+ * This method returns a <code>File</code> object representing the
+ * canonical path of this object.
+ *
+ * @return A <code>File</code> instance representing the canonical path of
+ * this object.
+ *
+ * @exception IOException If an error occurs.
+ *
+ * @since 1.2
+ */
+ public File getCanonicalFile() throws IOException
+ {
+ return new File(getCanonicalPath());
+ }
+
+ /**
+ * This method returns the name of the file. This is everything in the
+ * complete path of the file after the last instance of the separator
+ * string.
+ *
+ * @return The file name
+ */
+ public String getName()
+ {
+ return VMFile.getName(path);
+ }
+
+ /**
+ * This method returns a <code>String</code> the represents this file's
+ * parent. <code>null</code> is returned if the file has no parent. The
+ * parent is determined via a simple operation which removes the name
+ * after the last file separator character, as determined by the platform.
+ *
+ * @return The parent directory of this file
+ */
+ public String getParent()
+ {
+ String prefix = null;
+ int nameSeqIndex = 0;
+
+ if (path.equals(""))
+ return null;
+
+ // The "prefix", if present, is the leading "/" on UNIX and
+ // either the drive specifier (e.g. "C:") or the leading "\\"
+ // of a UNC network path on Windows.
+ if (separatorChar == '/' && path.charAt (0) == '/')
+ {
+ prefix = "/";
+ nameSeqIndex = 1;
+ }
+ else if (separatorChar == '\\' && path.length() > 1)
+ {
+ if ((path.charAt (0) == '\\' && path.charAt (1) == '\\')
+ || (((path.charAt (0) >= 'a' && path.charAt (0) <= 'z')
+ || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z'))
+ && path.charAt (1) == ':'))
+ {
+ prefix = path.substring (0, 2);
+ nameSeqIndex = 2;
+ }
+ }
+
+ // According to the JDK docs, the returned parent path is the
+ // portion of the name sequence before the last separator
+ // character, if found, prefixed by the prefix, otherwise null.
+ if (nameSeqIndex < path.length())
+ {
+ String nameSeq = path.substring (nameSeqIndex, path.length());
+ int last = nameSeq.lastIndexOf (separatorChar);
+ if (last == -1)
+ return prefix;
+ else if (last == (nameSeq.length() - 1))
+ // Note: The path would not have a trailing separator
+ // except for cases like "C:\" on Windows (see
+ // normalizePath( )), where Sun's JRE 1.4 returns null.
+ return null;
+ else if (last == 0)
+ last++;
+
+ if (prefix != null)
+ return prefix + nameSeq.substring (0, last);
+ else
+ return nameSeq.substring (0, last);
+ }
+ else
+ // Sun's JRE 1.4 returns null if the prefix is the only
+ // component of the path - so "/" gives null on UNIX and
+ // "C:", "\\", etc. return null on Windows.
+ return null;
+ }
+
+ /**
+ * This method returns a <code>File</code> object representing the parent
+ * file of this one.
+ *
+ * @return a <code>File</code> for the parent of this object.
+ * <code>null</code>
+ * will be returned if this object does not have a parent.
+ *
+ * @since 1.2
+ */
+ public File getParentFile()
+ {
+ String parent = getParent();
+ return parent != null ? new File(parent) : null;
+ }
+
+ /**
+ * Returns the path name that represents this file. May be a relative
+ * or an absolute path name
+ *
+ * @return The pathname of this file
+ */
+ public String getPath()
+ {
+ return path;
+ }
+
+ /**
+ * This method returns a hash code representing this file. It is the
+ * hash code of the path of this file (as returned by <code>getPath()</code>)
+ * exclusived or-ed with the value 1234321.
+ *
+ * @return The hash code for this object
+ */
+ public int hashCode()
+ {
+ if (VMFile.IS_CASE_SENSITIVE)
+ return path.hashCode() ^ 1234321;
+ else
+ return path.toLowerCase().hashCode() ^ 1234321;
+ }
+
+ /**
+ * This method returns true if this object represents an absolute file
+ * path and false if it does not. The definition of an absolute path varies
+ * by system. As an example, on GNU systems, a path is absolute if it starts
+ * with a "/".
+ *
+ * @return <code>true</code> if this object represents an absolute
+ * file name, <code>false</code> otherwise.
+ */
+ public boolean isAbsolute()
+ {
+ return VMFile.isAbsolute(path);
+ }
+
+ /**
+ * This method tests whether or not the file represented by this object
+ * is a directory. In order for this method to return <code>true</code>,
+ * the file represented by this object must exist and be a directory.
+ *
+ * @return <code>true</code> if this file is a directory, <code>false</code>
+ * otherwise
+ *
+ * @exception SecurityException If reading of the file is not permitted
+ */
+ public boolean isDirectory()
+ {
+ checkRead();
+ return VMFile.isDirectory(path);
+ }
+
+ /**
+ * This method tests whether or not the file represented by this object
+ * is a "plain" file. A file is a plain file if and only if it 1) Exists,
+ * 2) Is not a directory or other type of special file.
+ *
+ * @return <code>true</code> if this is a plain file, <code>false</code>
+ * otherwise
+ *
+ * @exception SecurityException If reading of the file is not permitted
+ */
+ public boolean isFile()
+ {
+ checkRead();
+ return VMFile.isFile(path);
+ }
+
+ /**
+ * This method tests whether or not this file represents a "hidden" file.
+ * On GNU systems, a file is hidden if its name begins with a "."
+ * character. Files with these names are traditionally not shown with
+ * directory listing tools.
+ *
+ * @return <code>true</code> if the file is hidden, <code>false</code>
+ * otherwise.
+ *
+ * @since 1.2
+ */
+ public boolean isHidden()
+ {
+ return VMFile.isHidden(path);
+ }
+
+ /**
+ * This method returns the last modification time of this file. The
+ * time value returned is an abstract value that should not be interpreted
+ * as a specified time value. It is only useful for comparing to other
+ * such time values returned on the same system. In that case, the larger
+ * value indicates a more recent modification time.
+ * <p>
+ * If the file does not exist, then a value of 0 is returned.
+ *
+ * @return The last modification time of the file
+ *
+ * @exception SecurityException If reading of the file is not permitted
+ */
+ public long lastModified()
+ {
+ checkRead();
+ return VMFile.lastModified(path);
+ }
+
+ /**
+ * This method returns the length of the file represented by this object,
+ * or 0 if the specified file does not exist.
+ *
+ * @return The length of the file
+ *
+ * @exception SecurityException If reading of the file is not permitted
+ */
+ public long length()
+ {
+ checkRead();
+ return VMFile.length(path);
+ }
+
+ /**
+ * This method returns a array of <code>String</code>'s representing the
+ * list of files is then directory represented by this object. If this
+ * object represents a non-directory file or a non-existent file, then
+ * <code>null</code> is returned. The list of files will not contain
+ * any names such as "." or ".." which indicate the current or parent
+ * directory. Also, the names are not guaranteed to be sorted.
+ * <p>
+ * In this form of the <code>list()</code> method, a filter is specified
+ * that allows the caller to control which files are returned in the
+ * list. The <code>FilenameFilter</code> specified is called for each
+ * file returned to determine whether or not that file should be included
+ * in the list.
+ * <p>
+ * A <code>SecurityManager</code> check is made prior to reading the
+ * directory. If read access to the directory is denied, an exception
+ * will be thrown.
+ *
+ * @param filter An object which will identify files to exclude from
+ * the directory listing.
+ *
+ * @return An array of files in the directory, or <code>null</code>
+ * if this object does not represent a valid directory.
+ *
+ * @exception SecurityException If read access is not allowed to the
+ * directory by the <code>SecurityManager</code>
+ */
+ public String[] list(FilenameFilter filter)
+ {
+ checkRead();
+
+ if (!exists() || !isDirectory())
+ return null;
+
+ // Get the list of files
+ String files[] = VMFile.list(path);
+
+ // Check if an error occured in listInternal().
+ // This is an unreadable directory, pretend there is nothing inside.
+ if (files == null)
+ return new String[0];
+
+ if (filter == null)
+ return files;
+
+ // Apply the filter
+ int count = 0;
+ for (int i = 0; i < files.length; i++)
+ {
+ if (filter.accept(this, files[i]))
+ ++count;
+ else
+ files[i] = null;
+ }
+
+ String[] retfiles = new String[count];
+ count = 0;
+ for (int i = 0; i < files.length; i++)
+ if (files[i] != null)
+ retfiles[count++] = files[i];
+
+ return retfiles;
+ }
+
+ /**
+ * This method returns a array of <code>String</code>'s representing the
+ * list of files is then directory represented by this object. If this
+ * object represents a non-directory file or a non-existent file, then
+ * <code>null</code> is returned. The list of files will not contain
+ * any names such as "." or ".." which indicate the current or parent
+ * directory. Also, the names are not guaranteed to be sorted.
+ * <p>
+ * A <code>SecurityManager</code> check is made prior to reading the
+ * directory. If read access to the directory is denied, an exception
+ * will be thrown.
+ *
+ * @return An array of files in the directory, or <code>null</code> if
+ * this object does not represent a valid directory.
+ *
+ * @exception SecurityException If read access is not allowed to the
+ * directory by the <code>SecurityManager</code>
+ */
+ public String[] list()
+ {
+ return list(null);
+ }
+
+ /**
+ * This method returns an array of <code>File</code> objects representing
+ * all the files in the directory represented by this object. If this
+ * object does not represent a directory, <code>null</code> is returned.
+ * Each of the returned <code>File</code> object is constructed with this
+ * object as its parent.
+ * <p>
+ * A <code>SecurityManager</code> check is made prior to reading the
+ * directory. If read access to the directory is denied, an exception
+ * will be thrown.
+ *
+ * @return An array of <code>File</code> objects for this directory.
+ *
+ * @exception SecurityException If the <code>SecurityManager</code> denies
+ * access to this directory.
+ *
+ * @since 1.2
+ */
+ public File[] listFiles()
+ {
+ return listFiles((FilenameFilter) null);
+ }
+
+ /**
+ * This method returns an array of <code>File</code> objects representing
+ * all the files in the directory represented by this object. If this
+ * object does not represent a directory, <code>null</code> is returned.
+ * Each of the returned <code>File</code> object is constructed with this
+ * object as its parent.
+ * <p>
+ * In this form of the <code>listFiles()</code> method, a filter is specified
+ * that allows the caller to control which files are returned in the
+ * list. The <code>FilenameFilter</code> specified is called for each
+ * file returned to determine whether or not that file should be included
+ * in the list.
+ * <p>
+ * A <code>SecurityManager</code> check is made prior to reading the
+ * directory. If read access to the directory is denied, an exception
+ * will be thrown.
+ *
+ * @return An array of <code>File</code> objects for this directory.
+ *
+ * @exception SecurityException If the <code>SecurityManager</code> denies
+ * access to this directory.
+ *
+ * @since 1.2
+ */
+ public File[] listFiles(FilenameFilter filter)
+ {
+ String[] filelist = list(filter);
+
+ if (filelist == null)
+ return null;
+
+ File[] fobjlist = new File [filelist.length];
+
+ for (int i = 0; i < filelist.length; i++)
+ fobjlist [i] = new File(this, filelist [i]);
+
+ return fobjlist;
+ }
+
+ /**
+ * This method returns an array of <code>File</code> objects representing
+ * all the files in the directory represented by this object. If this
+ * object does not represent a directory, <code>null</code> is returned.
+ * Each of the returned <code>File</code> object is constructed with this
+ * object as its parent.
+ * <p>
+ * In this form of the <code>listFiles()</code> method, a filter is specified
+ * that allows the caller to control which files are returned in the
+ * list. The <code>FileFilter</code> specified is called for each
+ * file returned to determine whether or not that file should be included
+ * in the list.
+ * <p>
+ * A <code>SecurityManager</code> check is made prior to reading the
+ * directory. If read access to the directory is denied, an exception
+ * will be thrown.
+ *
+ * @return An array of <code>File</code> objects for this directory.
+ *
+ * @exception SecurityException If the <code>SecurityManager</code> denies
+ * access to this directory.
+ *
+ * @since 1.2
+ */
+ public File[] listFiles(FileFilter filter)
+ {
+ File[] fobjlist = listFiles((FilenameFilter) null);
+
+ if (fobjlist == null)
+ return null;
+
+ if (filter == null)
+ return fobjlist;
+
+ int count = 0;
+ for (int i = 0; i < fobjlist.length; i++)
+ if (filter.accept(fobjlist[i]) == true)
+ ++count;
+
+ File[] final_list = new File[count];
+ count = 0;
+ for (int i = 0; i < fobjlist.length; i++)
+ if (filter.accept(fobjlist[i]) == true)
+ {
+ final_list[count] = fobjlist[i];
+ ++count;
+ }
+
+ return final_list;
+ }
+
+ /**
+ * This method returns a <code>String</code> that is the path name of the
+ * file as returned by <code>getPath</code>.
+ *
+ * @return A <code>String</code> representation of this file
+ */
+ public String toString()
+ {
+ return path;
+ }
+
+ /**
+ * @return A <code>URI</code> for this object.
+ */
+ public URI toURI()
+ {
+ String abspath = getAbsolutePath();
+
+ if (isDirectory() || path.equals(""))
+ abspath = abspath + separatorChar;
+
+ if (separatorChar == '\\')
+ abspath = separatorChar + abspath;
+
+ try
+ {
+ return new URI("file", null, null, -1,
+ abspath.replace(separatorChar, '/'),
+ null, null);
+ }
+ catch (URISyntaxException use)
+ {
+ // Can't happen.
+ throw (InternalError) new InternalError("Unconvertible file: "
+ + this).initCause(use);
+ }
+ }
+
+ /**
+ * This method returns a <code>URL</code> with the <code>file:</code>
+ * protocol that represents this file. The exact form of this URL is
+ * system dependent.
+ *
+ * @return A <code>URL</code> for this object.
+ *
+ * @exception MalformedURLException If the URL cannot be created
+ * successfully.
+ */
+ public URL toURL() throws MalformedURLException
+ {
+ return VMFile.toURL(this);
+ }
+
+
+ /**
+ * This method creates a directory for the path represented by this object.
+ *
+ * @return <code>true</code> if the directory was created,
+ * <code>false</code> otherwise
+ *
+ * @exception SecurityException If write access is not allowed to this file
+ */
+ public boolean mkdir()
+ {
+ checkWrite();
+ return VMFile.mkdir(path);
+ }
+
+ /**
+ * This method creates a directory for the path represented by this file.
+ * It will also create any intervening parent directories if necessary.
+ *
+ * @return <code>true</code> if the directory was created,
+ * <code>false</code> otherwise
+ *
+ * @exception SecurityException If write access is not allowed to this file
+ */
+ public boolean mkdirs()
+ {
+ String parent = getParent();
+ if (parent == null)
+ {
+ return mkdir();
+ }
+
+ File f = new File(parent);
+ if (!f.exists())
+ {
+ boolean rc = f.mkdirs();
+ if (rc == false)
+ return false;
+ }
+
+ return mkdir();
+ }
+
+ /**
+ * This method creates a temporary file in the specified directory. If
+ * the directory name is null, then this method uses the system temporary
+ * directory. The files created are guaranteed not to currently exist and
+ * the same file name will never be used twice in the same virtual
+ * machine instance.
+ * The system temporary directory is determined by examinging the
+ * <code>java.io.tmpdir</code> system property.
+ * <p>
+ * The <code>prefix</code> parameter is a sequence of at least three
+ * characters that are used as the start of the generated filename. The
+ * <code>suffix</code> parameter is a sequence of characters that is used
+ * to terminate the file name. This parameter may be <code>null</code>
+ * and if it is, the suffix defaults to ".tmp".
+ * <p>
+ * If a <code>SecurityManager</code> exists, then its <code>checkWrite</code>
+ * method is used to verify that this operation is permitted.
+ *
+ * @param prefix The character prefix to use in generating the path name.
+ * @param suffix The character suffix to use in generating the path name.
+ * @param directory The directory to create the file in, or
+ * <code>null</code> for the default temporary directory
+ *
+ * @exception IllegalArgumentException If the patterns is not valid
+ * @exception SecurityException If there is no permission to perform
+ * this operation
+ * @exception IOException If an error occurs
+ *
+ * @since 1.2
+ */
+ public static synchronized File createTempFile(String prefix, String suffix,
+ File directory)
+ throws IOException
+ {
+ // Grab the system temp directory if necessary
+ if (directory == null)
+ {
+ String dirname = System.getProperty("java.io.tmpdir");
+ if (dirname == null)
+ throw new IOException("Cannot determine system temporary directory");
+
+ directory = new File(dirname);
+ if (! VMFile.exists(directory.path))
+ throw new IOException("System temporary directory "
+ + directory.getName() + " does not exist.");
+ if (! VMFile.isDirectory(directory.path))
+ throw new IOException("System temporary directory "
+ + directory.getName()
+ + " is not really a directory.");
+ }
+
+ // Check if prefix is at least 3 characters long
+ if (prefix.length() < 3)
+ throw new IllegalArgumentException("Prefix too short: " + prefix);
+
+ // Set default value of suffix
+ if (suffix == null)
+ suffix = ".tmp";
+
+ // Now identify a file name and make sure it doesn't exist.
+ File file;
+ if (!VMFile.IS_DOS_8_3)
+ {
+ do
+ {
+ long now = System.currentTimeMillis();
+ if (now > last_tmp)
+ {
+ // The last temporary file was created more than 1 ms ago.
+ last_tmp = now;
+ n_created = 0;
+ }
+ else
+ n_created++;
+
+ String name = Long.toHexString(now);
+ if (n_created > 0)
+ name += '_'+Integer.toHexString(n_created);
+ String filename = prefix + name + suffix;
+ file = new File(directory, filename);
+ }
+ while (VMFile.exists(file.path));
+ }
+ else
+ {
+ // make sure prefix is not longer than 7 characters
+ if (prefix.length() >= 8)
+ throw new IllegalArgumentException("Prefix too long: " + prefix + "(valid length 3..7)");
+
+ long mask = 0x000000ffffFFFFL >> (prefix.length() * 4);
+ do
+ {
+ int n = (int) (System.currentTimeMillis() & mask);
+ String filename = prefix + java.lang.Integer.toHexString(n) + suffix;
+ file = new File(directory, filename);
+ }
+ while (VMFile.exists(file.path));
+ }
+
+ // Verify that we are allowed to create this file
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkWrite(file.getAbsolutePath());
+
+ // Now create the file and return our file object
+ // XXX - FIXME race condition.
+ VMFile.create(file.getAbsolutePath());
+ return file;
+ }
+
+ /**
+ * This method sets the owner's read permission for the File represented by
+ * this object.
+ *
+ * It is the same as calling <code>setReadable(readable, true)</code>.
+ *
+ * @param <code>readable</code> <code>true</code> to set read permission,
+ * <code>false</code> to unset the read permission.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setReadable(boolean, boolean)
+ * @since 1.6
+ */
+ public boolean setReadable(boolean readable)
+ {
+ return setReadable(readable, true);
+ }
+
+ /**
+ * This method sets the read permissions for the File represented by
+ * this object.
+ *
+ * If <code>ownerOnly</code> is set to <code>true</code> then only the
+ * read permission bit for the owner of the file is changed.
+ *
+ * If <code>ownerOnly</code> is set to <code>false</code>, the file
+ * permissions are changed so that the file can be read by everyone.
+ *
+ * On unix like systems this sets the <code>user</code>, <code>group</code>
+ * and <code>other</code> read bits and is equal to call
+ * <code>chmod a+r</code> on the file.
+ *
+ * @param <code>readable</code> <code>true</code> to set read permission,
+ * <code>false</code> to unset the read permission.
+ * @param <code>ownerOnly</code> <code>true</code> to set read permission
+ * for owner only, <code>false</code> for all.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setReadable(boolean)
+ * @since 1.6
+ */
+ public boolean setReadable(boolean readable, boolean ownerOnly)
+ {
+ checkWrite();
+ return VMFile.setReadable(path, readable, ownerOnly);
+ }
+
+ /**
+ * This method sets the owner's write permission for the File represented by
+ * this object.
+ *
+ * It is the same as calling <code>setWritable(readable, true)</code>.
+ *
+ * @param <code>writable</code> <code>true</code> to set write permission,
+ * <code>false</code> to unset write permission.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setWritable(boolean, boolean)
+ * @since 1.6
+ */
+ public boolean setWritable(boolean writable)
+ {
+ return setWritable(writable, true);
+ }
+
+ /**
+ * This method sets the write permissions for the File represented by
+ * this object.
+ *
+ * If <code>ownerOnly</code> is set to <code>true</code> then only the
+ * write permission bit for the owner of the file is changed.
+ *
+ * If <code>ownerOnly</code> is set to <code>false</code>, the file
+ * permissions are changed so that the file can be written by everyone.
+ *
+ * On unix like systems this set the <code>user</code>, <code>group</code>
+ * and <code>other</code> write bits and is equal to call
+ * <code>chmod a+w</code> on the file.
+ *
+ * @param <code>writable</code> <code>true</code> to set write permission,
+ * <code>false</code> to unset write permission.
+ * @param <code>ownerOnly</code> <code>true</code> to set write permission
+ * for owner only, <code>false</code> for all.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setWritable(boolean)
+ * @since 1.6
+ */
+ public boolean setWritable(boolean writable, boolean ownerOnly)
+ {
+ checkWrite();
+ return VMFile.setWritable(path, writable, ownerOnly);
+ }
+
+ /**
+ * This method sets the owner's execute permission for the File represented
+ * by this object.
+ *
+ * It is the same as calling <code>setExecutable(readable, true)</code>.
+ *
+ * @param <code>executable</code> <code>true</code> to set execute permission,
+ * <code>false</code> to unset execute permission.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setExecutable(boolean, boolean)
+ * @since 1.6
+ */
+ public boolean setExecutable(boolean executable)
+ {
+ return setExecutable(executable, true);
+ }
+
+ /**
+ * This method sets the execute permissions for the File represented by
+ * this object.
+ *
+ * If <code>ownerOnly</code> is set to <code>true</code> then only the
+ * execute permission bit for the owner of the file is changed.
+ *
+ * If <code>ownerOnly</code> is set to <code>false</code>, the file
+ * permissions are changed so that the file can be executed by everyone.
+ *
+ * On unix like systems this set the <code>user</code>, <code>group</code>
+ * and <code>other</code> write bits and is equal to call
+ * <code>chmod a+x</code> on the file.
+ *
+ * @param <code>executable</code> <code>true</code> to set write permission,
+ * <code>false</code> to unset write permission.
+ * @param <code>ownerOnly</code> <code>true</code> to set write permission
+ * for owner only, <code>false</code> for all.
+ * @return <code>true</code> if the file permissions are changed,
+ * <code>false</code> otherwise.
+ * @exception SecurityException If write access of the file is not permitted.
+ * @see #setExecutable(boolean)
+ * @since 1.6
+ */
+ public boolean setExecutable(boolean executable, boolean ownerOnly)
+ {
+ checkWrite();
+ return VMFile.setExecutable(path, executable, ownerOnly);
+ }
+
+ /**
+ * Get the total space for the partition pointed by this file path, in bytes.
+ *
+ * @return the total number of bytes in this partition.
+ * @since 1.6
+ */
+ public long getTotalSpace()
+ {
+ // check security manager.
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+ checkRead();
+
+ return VMFile.getTotalSpace(path);
+ }
+
+ /**
+ * Get the free space in the partition pointed by this file path, in bytes.
+ *
+ * @return the number of free bytes in this partition.
+ * @since 1.6
+ */
+ public long getFreeSpace()
+ {
+ // check security manager.
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+ checkRead();
+
+ return VMFile.getFreeSpace(path);
+ }
+
+ /**
+ * Get the usable space in the partition pointed by this file path, in bytes.
+ * This is not necessarily the same as the number returned by
+ * {@link #getFreeSpace()}.
+ *
+ * <strong>Implementation note</strong>: Unlike the RI, on Linux and UNIX
+ * like systems this methods take into account the reserved space for the
+ * "root" user. This means that the returned results will be a little
+ * different if a normal user or root perform the query.
+ *
+ * Also, the bytes returned should be interpreted as an hint, and may be
+ * different at each call of this method or even right after the method
+ * returns.
+ *
+ * @return the number of usable bytes in this partition.
+ * @since 1.6
+ */
+ public long getUsableSpace()
+ {
+ // check security manager.
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+ checkRead();
+
+ // root users can use the reserved extra space
+ String user = System.getProperty("user.name");
+ if (user != null && user.equals("root"))
+ return VMFile.getFreeSpace(path);
+
+ return VMFile.getUsableSpace(path);
+ }
+
+ /**
+ * This method sets the file represented by this object to be read only.
+ * A read only file or directory cannot be modified. Please note that
+ * GNU systems allow read only files to be deleted if the directory it
+ * is contained in is writable.
+ *
+ * @return <code>true</code> if the operation succeeded, <code>false</code>
+ * otherwise.
+ *
+ * @exception SecurityException If the <code>SecurityManager</code> does
+ * not allow this operation.
+ *
+ * @since 1.2
+ */
+ public boolean setReadOnly()
+ {
+ // Do a security check before trying to do anything else.
+ checkWrite();
+
+ // Test for existence.
+ if (! VMFile.exists(path))
+ return false;
+
+ return VMFile.setReadOnly(path);
+ }
+
+ /**
+ * This method returns an array of filesystem roots. Some operating systems
+ * have volume oriented filesystem. This method provides a mechanism for
+ * determining which volumes exist. GNU systems use a single hierarchical
+ * filesystem, so will have only one "/" filesystem root.
+ *
+ * @return An array of <code>File</code> objects for each filesystem root
+ * available.
+ *
+ * @since 1.2
+ */
+ public static File[] listRoots()
+ {
+ File[] roots = VMFile.listRoots();
+
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ {
+ // Only return roots to which the security manager permits read access.
+ int count = roots.length;
+ for (int i = 0; i < roots.length; i++)
+ {
+ try
+ {
+ s.checkRead (roots[i].path);
+ }
+ catch (SecurityException sx)
+ {
+ roots[i] = null;
+ count--;
+ }
+ }
+ if (count != roots.length)
+ {
+ File[] newRoots = new File[count];
+ int k = 0;
+ for (int i = 0; i < roots.length; i++)
+ {
+ if (roots[i] != null)
+ newRoots[k++] = roots[i];
+ }
+ roots = newRoots;
+ }
+ }
+ return roots;
+ }
+
+ /**
+ * This method creates a temporary file in the system temporary directory.
+ * The files created are guaranteed not to currently exist and the same file
+ * name will never be used twice in the same virtual machine instance. The
+ * system temporary directory is determined by examinging the
+ * <code>java.io.tmpdir</code> system property.
+ * <p>
+ * The <code>prefix</code> parameter is a sequence of at least three
+ * characters that are used as the start of the generated filename. The
+ * <code>suffix</code> parameter is a sequence of characters that is used
+ * to terminate the file name. This parameter may be <code>null</code>
+ * and if it is, the suffix defaults to ".tmp".
+ * <p>
+ * If a <code>SecurityManager</code> exists, then its <code>checkWrite</code>
+ * method is used to verify that this operation is permitted.
+ * <p>
+ * This method is identical to calling
+ * <code>createTempFile(prefix, suffix, null)</code>.
+ *
+ * @param prefix The character prefix to use in generating the path name.
+ * @param suffix The character suffix to use in generating the path name.
+ *
+ * @exception IllegalArgumentException If the prefix or suffix are not valid.
+ * @exception SecurityException If there is no permission to perform
+ * this operation
+ * @exception IOException If an error occurs
+ */
+ public static File createTempFile(String prefix, String suffix)
+ throws IOException
+ {
+ return createTempFile(prefix, suffix, null);
+ }
+
+ /**
+ * This method compares the specified <code>File</code> to this one
+ * to test for equality. It does this by comparing the canonical path names
+ * of the files.
+ * <p>
+ * The canonical paths of the files are determined by calling the
+ * <code>getCanonicalPath</code> method on each object.
+ * <p>
+ * This method returns a 0 if the specified <code>Object</code> is equal
+ * to this one, a negative value if it is less than this one
+ * a positive value if it is greater than this one.
+ *
+ * @return An integer as described above
+ *
+ * @since 1.2
+ */
+ public int compareTo(File other)
+ {
+ if (VMFile.IS_CASE_SENSITIVE)
+ return path.compareTo (other.path);
+ else
+ return path.compareToIgnoreCase (other.path);
+ }
+
+ /**
+ * This method renames the file represented by this object to the path
+ * of the file represented by the argument <code>File</code>.
+ *
+ * @param dest The <code>File</code> object representing the target name
+ *
+ * @return <code>true</code> if the rename succeeds, <code>false</code>
+ * otherwise.
+ *
+ * @exception SecurityException If write access is not allowed to the
+ * file by the <code>SecurityMananger</code>.
+ */
+ public synchronized boolean renameTo(File dest)
+ {
+ checkWrite();
+ dest.checkWrite();
+ // Call our native rename method
+ return VMFile.renameTo(path, dest.path);
+ }
+
+ /**
+ * This method sets the modification time on the file to the specified
+ * value. This is specified as the number of seconds since midnight
+ * on January 1, 1970 GMT.
+ *
+ * @param time The desired modification time.
+ *
+ * @return <code>true</code> if the operation succeeded, <code>false</code>
+ * otherwise.
+ *
+ * @exception IllegalArgumentException If the specified time is negative.
+ * @exception SecurityException If the <code>SecurityManager</code> will
+ * not allow this operation.
+ *
+ * @since 1.2
+ */
+ public boolean setLastModified(long time)
+ {
+ if (time < 0)
+ throw new IllegalArgumentException("Negative modification time: " + time);
+
+ checkWrite();
+ return VMFile.setLastModified(path, time);
+ }
+
+ private void checkWrite()
+ {
+ // Check the SecurityManager
+ SecurityManager s = System.getSecurityManager();
+
+ if (s != null)
+ s.checkWrite(path);
+ }
+
+ private void checkRead()
+ {
+ // Check the SecurityManager
+ SecurityManager s = System.getSecurityManager();
+
+ if (s != null)
+ s.checkRead(path);
+ }
+
+ private void checkExec()
+ {
+ // Check the SecurityManager
+ SecurityManager s = System.getSecurityManager();
+
+ if (s != null)
+ s.checkExec(path);
+ }
+
+ /**
+ * Calling this method requests that the file represented by this object
+ * be deleted when the virtual machine exits. Note that this request cannot
+ * be cancelled. Also, it will only be carried out if the virtual machine
+ * exits normally.
+ *
+ * @exception SecurityException If deleting of the file is not allowed
+ *
+ * @since 1.2
+ */
+ public void deleteOnExit()
+ {
+ // Check the SecurityManager
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkDelete(path);
+
+ DeleteFileHelper.add(this);
+ }
+
+ private void writeObject(ObjectOutputStream oos) throws IOException
+ {
+ oos.defaultWriteObject();
+ oos.writeChar(separatorChar);
+ }
+
+ private void readObject(ObjectInputStream ois)
+ throws ClassNotFoundException, IOException
+ {
+ ois.defaultReadObject();
+
+ // If the file was from an OS with a different dir separator,
+ // fixup the path to use the separator on this OS.
+ char oldSeparatorChar = ois.readChar();
+
+ if (oldSeparatorChar != separatorChar)
+ path = path.replace(oldSeparatorChar, separatorChar);
+ }
+
+} // class File
diff --git a/libjava/classpath/java/io/FileDescriptor.java b/libjava/classpath/java/io/FileDescriptor.java
new file mode 100644
index 000000000..ce58a9fb0
--- /dev/null
+++ b/libjava/classpath/java/io/FileDescriptor.java
@@ -0,0 +1,140 @@
+/* FileDescriptor.java -- Opaque file handle class
+ Copyright (C) 1998, 1999, 2000, 2001, 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 java.io;
+
+import gnu.java.nio.FileChannelImpl;
+
+import java.nio.channels.ByteChannel;
+import java.nio.channels.FileChannel;
+
+/**
+ * This class represents an opaque file handle as a Java class. It should
+ * be used only to pass to other methods that expect an object of this
+ * type. No system specific information can be obtained from this object.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ * @date September 24, 1998
+ */
+public final class FileDescriptor
+{
+ /**
+ * A <code>FileDescriptor</code> representing the system standard input
+ * stream. This will usually be accessed through the
+ * <code>System.in</code>variable.
+ */
+ public static final FileDescriptor in
+ = new FileDescriptor (FileChannelImpl.in);
+
+ /**
+ * A <code>FileDescriptor</code> representing the system standard output
+ * stream. This will usually be accessed through the
+ * <code>System.out</code>variable.
+ */
+ public static final FileDescriptor out
+ = new FileDescriptor (FileChannelImpl.out);
+
+ /**
+ * A <code>FileDescriptor</code> representing the system standard error
+ * stream. This will usually be accessed through the
+ * <code>System.err</code>variable.
+ */
+ public static final FileDescriptor err
+ = new FileDescriptor (FileChannelImpl.err);
+
+ final ByteChannel channel;
+
+ /**
+ * This method is used to initialize an invalid FileDescriptor object.
+ */
+ public FileDescriptor()
+ {
+ channel = null;
+ }
+
+ /**
+ * This method is used to initialize a FileDescriptor object.
+ */
+ FileDescriptor(ByteChannel channel)
+ {
+ this.channel = channel;
+ }
+
+
+ /**
+ * This method forces all data that has not yet been physically written to
+ * the underlying storage medium associated with this
+ * <code>FileDescriptor</code>
+ * to be written out. This method will not return until all data has
+ * been fully written to the underlying device. If the device does not
+ * support this functionality or if an error occurs, then an exception
+ * will be thrown.
+ */
+ public void sync () throws SyncFailedException
+ {
+ if (channel instanceof FileChannel)
+ {
+ try
+ {
+ ((FileChannel) channel).force(true);
+ }
+ catch (IOException ex)
+ {
+ if (ex instanceof SyncFailedException)
+ throw (SyncFailedException) ex;
+ else
+ throw new SyncFailedException(ex.toString());
+ }
+ }
+ }
+
+ /**
+ * This methods tests whether or not this object represents a valid open
+ * native file handle.
+ *
+ * @return <code>true</code> if this object represents a valid
+ * native file handle, <code>false</code> otherwise
+ */
+ public boolean valid ()
+ {
+ ByteChannel c = channel;
+ return (c != null) && (c.isOpen());
+ }
+}
diff --git a/libjava/classpath/java/io/FileFilter.java b/libjava/classpath/java/io/FileFilter.java
new file mode 100644
index 000000000..087c5e9f0
--- /dev/null
+++ b/libjava/classpath/java/io/FileFilter.java
@@ -0,0 +1,65 @@
+/* FileFilter.java -- Filter a list of pathnames
+ Copyright (C) 1998,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 java.io;
+
+/**
+ * This interface has one method which is used for filtering pathnames
+ * returned in a pathname listing. It is currently used by the
+ * <code>File.listFiles(FileFilter)</code> method.
+ * <p>
+ * The method in this interface determines if a particular pathname should
+ * or should not be included in the pathname listing.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ *
+ * @see File#listFiles(java.io.FileFilter)
+ */
+public interface FileFilter
+{
+ /**
+ * This method determines whether or not a given pathname should be included
+ * in a pathname listing.
+ *
+ * @param pathname The pathname to test
+ *
+ * @return <code>true</code> if the path should be included in the list,
+ * <code>false</code> otherwise.
+ */
+ boolean accept(File pathname);
+}
diff --git a/libjava/classpath/java/io/FileInputStream.java b/libjava/classpath/java/io/FileInputStream.java
new file mode 100644
index 000000000..0e71caf37
--- /dev/null
+++ b/libjava/classpath/java/io/FileInputStream.java
@@ -0,0 +1,322 @@
+/* FileInputStream.java -- An input stream that reads from disk files.
+ Copyright (C) 1998, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+import gnu.java.nio.FileChannelImpl;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * This class is a stream that reads its bytes from a file.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public class FileInputStream extends InputStream
+{
+ /**
+ * This is the native file handle for the file this stream is reading from
+ */
+ private FileDescriptor fd;
+
+ private FileChannelImpl ch;
+
+ /**
+ * This method initializes a <code>FileInputStream</code> to read from the
+ * specified named file. A security check is first made to determine
+ * whether or not access to this file is allowed. This is done by
+ * calling the <code>checkRead()</code> method of the
+ * <code>SecurityManager</code>
+ * (if one exists) with the name of this file. An exception is thrown
+ * if reading is not allowed. If the file does not exist, an exception
+ * is also thrown.
+ *
+ * @param name The name of the file this stream should read from
+ *
+ * @exception SecurityException If read access to the file is not allowed
+ * @exception FileNotFoundException If the file does not exist
+ * or if it is a directory
+ */
+ public FileInputStream(String name) throws FileNotFoundException
+ {
+ this(new File(name));
+ }
+
+ /**
+ * This method initializes a <code>FileInputStream</code> to read from the
+ * specified <code>File</code> object. A security check is first
+ * made to determine
+ * whether or not access to this file is allowed. This is done by
+ * calling the <code>checkRead()</code> method of the
+ * <code>SecurityManager</code>
+ * (if one exists) with the name of this file. An exception is thrown
+ * if reading is not allowed. If the file does not exist, an exception
+ * is also thrown.
+ *
+ * @param file The <code>File</code> object this stream should read from
+ *
+ * @exception SecurityException If read access to the file is not allowed
+ * @exception FileNotFoundException If the file does not exist
+ * or if it is a directory.
+ */
+ public FileInputStream(File file) throws FileNotFoundException
+ {
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkRead(file.getPath());
+
+ try
+ {
+ ch = FileChannelImpl.create(file, FileChannelImpl.READ);
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ throw fnfe;
+ }
+ catch (IOException ioe)
+ {
+ FileNotFoundException fnfe = new FileNotFoundException(file.getPath());
+ fnfe.initCause(ioe);
+ throw fnfe;
+ }
+ }
+
+ /**
+ * This method initializes a <code>FileInputStream</code> to read from the
+ * specified <code>FileDescriptor</code> object. A security
+ * check is first made to
+ * determine whether or not access to this file is allowed. This is done by
+ * calling the <code>checkRead()</code> method of the
+ * <code>SecurityManager</code>
+ * (if one exists) with the specified <code>FileDescriptor</code>
+ * An exception is
+ * thrown if reading is not allowed.
+ *
+ * @param fdObj The <code>FileDescriptor</code> object this stream
+ * should read from
+ *
+ * @exception SecurityException If read access to the file is not allowed
+ */
+ public FileInputStream(FileDescriptor fdObj)
+ {
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkRead(fdObj);
+
+ fd = fdObj;
+ ch = (FileChannelImpl) fdObj.channel;
+ }
+
+ FileInputStream(FileChannelImpl ch)
+ {
+ this.ch = ch;
+ }
+
+ /**
+ * This method returns the number of bytes that can be read from this
+ * stream before a read can block. A return of 0 indicates that blocking
+ * might (or might not) occur on the very next read attempt.
+ * <p>
+ * This method returns the number of unread bytes remaining in the file if
+ * the descriptor being read from is an actual file. If this method is
+ * reading from a ''special'' file such a the standard input, this method
+ * will return the appropriate value for the stream being read.
+ * <p>
+ * Be aware that reads on plain files that do not reside locally might
+ * possibly block even if this method says they should not. For example,
+ * a remote server might crash, preventing an NFS mounted file from being
+ * read.
+ *
+ * @return The number of bytes that can be read before blocking could occur
+ *
+ * @exception IOException If an error occurs
+ */
+ public int available() throws IOException
+ {
+ return ch.available();
+ }
+
+ /**
+ * This method closes the stream. Any futher attempts to read from the
+ * stream will likely generate an IOException since the underlying file
+ * will be closed.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public void close() throws IOException
+ {
+ ch.close();
+ }
+
+ protected void finalize() throws IOException
+ {
+ // We don't actually need this, but we include it because it is
+ // mentioned in the JCL.
+ }
+
+ /**
+ * This method returns a <code>FileDescriptor</code> object representing the
+ * underlying native file handle of the file this stream is reading
+ * from
+ *
+ * @return A <code>FileDescriptor</code> for this stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public final FileDescriptor getFD() throws IOException
+ {
+ synchronized (this)
+ {
+ if (fd == null)
+ fd = new FileDescriptor (ch);
+ return fd;
+ }
+ }
+
+ /**
+ * This method reads an unsigned byte from the input stream and returns it
+ * as an int in the range of 0-255. This method also will return -1 if
+ * the end of the stream has been reached.
+ * <p>
+ * This method will block until the byte can be read.
+ *
+ * @return The byte read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read() throws IOException
+ {
+ return ch.read();
+ }
+
+ /**
+ * This method reads bytes from a stream and stores them into a caller
+ * supplied buffer. This method attempts to completely fill the buffer,
+ * but can return before doing so. The actual number of bytes read is
+ * returned as an int. A -1 is returned to indicate the end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ * <p>
+ * This method operates by calling an overloaded read method like so:
+ * <code>read(buf, 0, buf.length)</code>
+ *
+ * @param buf The buffer into which the bytes read will be stored.
+ *
+ * @return The number of bytes read or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read(byte[] buf) throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ /**
+ * This method read bytes from a stream and stores them into a caller
+ * supplied buffer. It starts storing the data at index
+ * <code>offset</code> into
+ * the buffer and attempts to read <code>len</code> bytes. This method can
+ * return before reading the number of bytes requested. The actual number
+ * of bytes read is returned as an int. A -1 is returned to indicate the
+ * end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ *
+ * @param buf The array into which the bytes read should be stored
+ * @param offset The offset into the array 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.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read(byte[] buf, int offset, int len) throws IOException
+ {
+ if (offset < 0
+ || len < 0
+ || offset + len > buf.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ return ch.read(ByteBuffer.wrap(buf, offset, len));
+ }
+
+ /**
+ * This method skips the specified number of bytes in the stream. It
+ * returns the actual number of bytes skipped, which may be less than the
+ * requested amount.
+ * <p>
+ * @param numBytes The requested number of bytes to skip
+ *
+ * @return The actual number of bytes skipped.
+ *
+ * @exception IOException If an error occurs
+ */
+ public synchronized long skip (long numBytes) throws IOException
+ {
+ if (numBytes < 0)
+ throw new IllegalArgumentException ("Can't skip negative bytes: " +
+ numBytes);
+
+ if (numBytes == 0)
+ return 0;
+
+ long oldPos = ch.position ();
+ ch.position(oldPos + numBytes);
+ return ch.position() - oldPos;
+ }
+
+ /**
+ * This method creates a java.nio.channels.FileChannel.
+ * Nio does not allow one to create a file channel directly.
+ * A file channel must be created by first creating an instance of
+ * Input/Output/RandomAccessFile and invoking the getChannel() method on it.
+ */
+ public synchronized FileChannel getChannel ()
+ {
+ return ch;
+ }
+
+} // class FileInputStream
diff --git a/libjava/classpath/java/io/FileNotFoundException.java b/libjava/classpath/java/io/FileNotFoundException.java
new file mode 100644
index 000000000..3c11e2960
--- /dev/null
+++ b/libjava/classpath/java/io/FileNotFoundException.java
@@ -0,0 +1,73 @@
+/* FileNotFoundException.java -- the requested file could not be found
+ Copyright (C) 1998, 1999, 2001, 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 java.io;
+
+/**
+ * This exception is thrown when an attempt is made to access a file that
+ * does not exist, or is inaccessible for some other reason (such as writing
+ * a read-only file).
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ * @status updated to 1.4
+ */
+public class FileNotFoundException extends IOException
+{
+ /**
+ * Compatible with JDK 1.0+.
+ */
+ private static final long serialVersionUID = -897856973823710492L;
+
+ /**
+ * Create an exception without a descriptive error message.
+ */
+ public FileNotFoundException()
+ {
+ }
+
+ /**
+ * Create an exception with a descriptive error message.
+ *
+ * @param message the descriptive error message
+ */
+ public FileNotFoundException(String message)
+ {
+ super(message);
+ }
+} // class FileNotFoundException
diff --git a/libjava/classpath/java/io/FileOutputStream.java b/libjava/classpath/java/io/FileOutputStream.java
new file mode 100644
index 000000000..6915822ea
--- /dev/null
+++ b/libjava/classpath/java/io/FileOutputStream.java
@@ -0,0 +1,309 @@
+/* FileOutputStream.java -- Writes to a file on disk.
+ Copyright (C) 1998, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+import gnu.java.nio.FileChannelImpl;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Complete to version 1.1.
+ */
+
+/**
+ * This classes allows a stream of data to be written to a disk file or
+ * any open <code>FileDescriptor</code>.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ */
+public class FileOutputStream extends OutputStream
+{
+ private FileDescriptor fd;
+
+ private final FileChannelImpl ch;
+
+ /**
+ * This method initializes a <code>FileOutputStream</code> object to write
+ * to the named file. The file is created if it does not exist, and
+ * the bytes written are written starting at the beginning of the file if
+ * the <code>append</code> argument is <code>false</code> or at the end
+ * of the file if the <code>append</code> argument is true.
+ * <p>
+ * Before opening a file, a security check is performed by calling the
+ * <code>checkWrite</code> method of the <code>SecurityManager</code> (if
+ * one exists) with the name of the file to be opened. An exception is
+ * thrown if writing is not allowed.
+ *
+ * @param path The name of the file this stream should write to
+ * @param append <code>true</code> to append bytes to the end of the file,
+ * or <code>false</code> to write bytes to the beginning
+ *
+ * @exception SecurityException If write access to the file is not allowed
+ * @exception FileNotFoundException If a non-security error occurs
+ */
+ public FileOutputStream (String path, boolean append)
+ throws SecurityException, FileNotFoundException
+ {
+ this (new File(path), append);
+ }
+
+ /**
+ * This method initializes a <code>FileOutputStream</code> object to write
+ * to the named file. The file is created if it does not exist, and
+ * the bytes written are written starting at the beginning of the file.
+ * <p>
+ * Before opening a file, a security check is performed by calling the
+ * <code>checkWrite</code> method of the <code>SecurityManager</code> (if
+ * one exists) with the name of the file to be opened. An exception is
+ * thrown if writing is not allowed.
+ *
+ * @param path The name of the file this stream should write to
+ *
+ * @exception SecurityException If write access to the file is not allowed
+ * @exception FileNotFoundException If a non-security error occurs
+ */
+ public FileOutputStream (String path)
+ throws SecurityException, FileNotFoundException
+ {
+ this (path, false);
+ }
+
+ /**
+ * This method initializes a <code>FileOutputStream</code> object to write
+ * to the specified <code>File</code> object. The file is created if it
+ * does not exist, and the bytes written are written starting at the
+ * beginning of the file.
+ * <p>
+ * Before opening a file, a security check is performed by calling the
+ * <code>checkWrite</code> method of the <code>SecurityManager</code> (if
+ * one exists) with the name of the file to be opened. An exception is
+ * thrown if writing is not allowed.
+ *
+ * @param file The <code>File</code> object this stream should write to
+ *
+ * @exception SecurityException If write access to the file is not allowed
+ * @exception FileNotFoundException If a non-security error occurs
+ */
+ public FileOutputStream (File file)
+ throws SecurityException, FileNotFoundException
+ {
+ this (file, false);
+ }
+
+ /**
+ * This method initializes a <code>FileOutputStream</code> object to write
+ * to the specified <code>File</code> object. The file is created if it
+ * does not exist, and the bytes written are written starting at the
+ * beginning of the file if the <code>append</code> parameter is
+ * <code>false</code>. Otherwise bytes are written at the end of the
+ * file.
+ * <p>
+ * Before opening a file, a security check is performed by calling the
+ * <code>checkWrite</code> method of the <code>SecurityManager</code> (if
+ * one exists) with the name of the file to be opened. An exception is
+ * thrown if writing is not allowed.
+ *
+ * @param file The <code>File</code> object this stream should write to
+ * @param append <code>true</code> to append bytes to the end of the file,
+ * or <code>false</code> to write bytes to the beginning
+ *
+ * @exception SecurityException If write access to the file is not allowed
+ * @exception FileNotFoundException If a non-security error occurs
+ */
+ public FileOutputStream (File file, boolean append)
+ throws FileNotFoundException
+ {
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkWrite(file.getPath());
+
+ try
+ {
+ ch = FileChannelImpl.create(file, (append
+ ? FileChannelImpl.WRITE
+ | FileChannelImpl.APPEND
+ : FileChannelImpl.WRITE));
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ throw fnfe;
+ }
+ catch (IOException ioe)
+ {
+ FileNotFoundException fnfe = new FileNotFoundException(file.getPath());
+ fnfe.initCause(ioe);
+ throw fnfe;
+ }
+ }
+
+ /**
+ * This method initializes a <code>FileOutputStream</code> object to write
+ * to the file represented by the specified <code>FileDescriptor</code>
+ * object. This method does not create any underlying disk file or
+ * reposition the file pointer of the given descriptor. It assumes that
+ * this descriptor is ready for writing as is.
+ * <p>
+ * Before opening a file, a security check is performed by calling the
+ * <code>checkWrite</code> method of the <code>SecurityManager</code> (if
+ * one exists) with the specified <code>FileDescriptor</code> as an argument.
+ * An exception is thrown if writing is not allowed.
+ *
+ * @param fdObj The <code>FileDescriptor</code> this stream should write to
+ *
+ * @exception SecurityException If write access to the file is not allowed
+ */
+ public FileOutputStream (FileDescriptor fdObj)
+ throws SecurityException
+ {
+ // Hmm, no other exception but this one to throw, but if the descriptor
+ // isn't valid, we surely don't have "permission" to write to it.
+ if (!fdObj.valid())
+ throw new SecurityException("Invalid FileDescriptor");
+
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ s.checkWrite(fdObj);
+
+ fd = fdObj;
+ ch = (FileChannelImpl) fdObj.channel;
+ }
+
+ FileOutputStream(FileChannelImpl ch)
+ {
+ this.ch = ch;
+ }
+
+ protected void finalize () throws IOException
+ {
+ // We don't actually need this, but we include it because it is
+ // mentioned in the JCL.
+ }
+
+ /**
+ * This method returns a <code>FileDescriptor</code> object representing
+ * the file that is currently being written to
+ *
+ * @return A <code>FileDescriptor</code> object for this stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public final FileDescriptor getFD () throws IOException
+ {
+ synchronized (this)
+ {
+ if (fd == null)
+ fd = new FileDescriptor (ch);
+ return fd;
+ }
+ }
+
+ /**
+ * This method writes a single byte of data to the file.
+ *
+ * @param b The byte of data to write, passed as an <code>int</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (int b) throws IOException
+ {
+ ch.write (b);
+ }
+
+ /**
+ * This method writes all the bytes in the specified array to the
+ * file.
+ *
+ * @param buf The array of bytes to write to the file
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (byte[] buf)
+ throws IOException
+ {
+ write (buf, 0, buf.length);
+ }
+
+ /**
+ * This method writes <code>len</code> bytes from the byte array
+ * <code>buf</code> to the file starting at index <code>offset</code>.
+ *
+ * @param buf The array of bytes to write to the file
+ * @param offset The offset into the array to start writing bytes from
+ * @param len The number of bytes to write to the file
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (byte[] buf, int offset, int len)
+ throws IOException
+ {
+ if (offset < 0
+ || len < 0
+ || offset + len > buf.length)
+ throw new ArrayIndexOutOfBoundsException ();
+
+ ch.write(ByteBuffer.wrap(buf, offset, len));
+ }
+
+ /**
+ * This method closes the underlying file. Any further attempts to
+ * write to this stream will likely generate an exception since the
+ * file is closed.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close () throws IOException
+ {
+ ch.close();
+ }
+
+ /**
+ * This method creates a java.nio.channels.FileChannel.
+ * Nio does not allow one to create a file channel directly.
+ * A file channel must be created by first creating an instance of
+ * Input/Output/RandomAccessFile and invoking the getChannel() method on it.
+ */
+ public synchronized FileChannel getChannel()
+ {
+ return ch;
+ }
+
+} // class FileOutputStream
diff --git a/libjava/classpath/java/io/FilePermission.java b/libjava/classpath/java/io/FilePermission.java
new file mode 100644
index 000000000..5aa10b3c0
--- /dev/null
+++ b/libjava/classpath/java/io/FilePermission.java
@@ -0,0 +1,293 @@
+/* FilePermission.java --
+ Copyright (C) 1998, 2000, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+import java.security.Permission;
+
+public final class FilePermission extends Permission implements Serializable
+{
+ private static final long serialVersionUID = 7930732926638008763L;
+
+ private static final String ALL_FILES = "<<ALL FILES>>";
+
+ private boolean readPerm = false;
+ private boolean writePerm = false;
+ private boolean executePerm = false;
+ private boolean deletePerm = false;
+ private final String actionsString;
+
+ // Checks and caches the actions
+ private void checkPerms() throws IllegalArgumentException
+ {
+ String action;
+ int i = actionsString.indexOf(',');
+ int startI = 0;
+ while (i != -1)
+ {
+ action = actionsString.substring(startI, i).trim().toLowerCase();
+ if (action.equals("read"))
+ readPerm = true;
+ else if (action.equals("write"))
+ writePerm = true;
+ else if (action.equals("execute"))
+ executePerm = true;
+ else if (action.equals("delete"))
+ deletePerm = true;
+ else
+ throw new IllegalArgumentException("Unknown action: " + action);
+
+ startI = i + 1;
+ i = actionsString.indexOf(',', startI);
+ }
+
+ action = actionsString.substring(startI).trim().toLowerCase();
+ if (action.equals("read"))
+ readPerm = true;
+ else if (action.equals("write"))
+ writePerm = true;
+ else if (action.equals("execute"))
+ executePerm = true;
+ else if (action.equals("delete"))
+ deletePerm = true;
+ else
+ throw new IllegalArgumentException("Unknown action: " + action);
+ }
+
+ /**
+ * Create a new FilePermission.
+ *
+ * @param pathExpression an expression specifying the paths this
+ * permission represents.
+ * @param actionsString a comma-separated list of the actions this
+ * permission represents. The actions must be "read", "write",
+ * "execute" and/or "delete".
+ */
+ public FilePermission(String pathExpression, String actionsString)
+ {
+ // FIXME: what to do when the file string is malformed?
+ super(pathExpression);
+ if (pathExpression == null)
+ throw new NullPointerException("pathExpression");
+ if (actionsString == null)
+ throw new IllegalArgumentException("actionsString");
+ this.actionsString = actionsString;
+ checkPerms();
+ }
+
+ /**
+ * Get the actions this FilePermission supports.
+ * @return the String representing the actions this FilePermission supports.
+ */
+ public String getActions()
+ {
+ return actionsString;
+ }
+
+ /**
+ * Get the hash code for this Object.<P>
+ * FilePermission's hash code is calculated as the exclusive or of the
+ * target
+ * String's hash code and the action String's hash code.
+ * @specnote Sun did not specify how to calculate the hash code;
+ * I made this up.
+ * @return the hash code for this Object.
+ */
+ public int hashCode()
+ {
+ return getName().hashCode() ^ actionsString.hashCode();
+ }
+
+ /**
+ * Check two FilePermissions for semantic equality.
+ * Two FilePermissions are exactly equivalent if they have identical path
+ * expressions and have exactly the same access permissions.
+ * @param o the Object to compare to.
+ * @return whether the Objects are semantically equivalent.
+ */
+ public boolean equals(Object o)
+ {
+ if (! (o instanceof FilePermission))
+ return false;
+ FilePermission p = (FilePermission) o;
+
+ String f1 = getName();
+ String f2 = p.getName();
+
+ // Compare names, taking into account if they refer to a directory
+ // and one has a separator and the other does not.
+ if (f1.length() > 0 && f1.charAt(f1.length() - 1) == File.separatorChar)
+ {
+ if (f2.length() > 0
+ && f2.charAt(f2.length() - 1) == File.separatorChar)
+ {
+ if (! f2.equals(f1))
+ return false;
+ }
+ else
+ {
+ if (! f2.equals(f1.substring(0, f1.length() - 1)))
+ return false;
+ }
+ }
+ else
+ {
+ if (f2.length() > 0
+ && f2.charAt(f2.length() - 1) == File.separatorChar)
+ {
+ if (! f1.equals(f2.substring(0, f2.length() - 1)))
+ return false;
+ }
+ else
+ {
+ if (! f1.equals(f2))
+ return false;
+ }
+ }
+ return (readPerm == p.readPerm
+ && writePerm == p.writePerm
+ && executePerm == p.executePerm
+ && deletePerm == p.deletePerm);
+ }
+
+ /**
+ * Check to see if this permission implies another.
+ * Permission A implies permission B if these things are all true:
+ * <OL>
+ * <LI>A and B are both FilePermissions.</LI>
+ * <LI>All possible files in B are included in A
+ * (possibly more are in A).</LI>
+ * <LI>All actions B supports, A also supports.</LI>
+ * </OL>
+ * @param p the Permission to compare against.
+ * @return whether this Permission implies p
+ */
+ public boolean implies(Permission p)
+ {
+ if (! (p instanceof FilePermission))
+ return false;
+
+ String f1 = getName();
+
+ if (f1.equals(ALL_FILES))
+ return true;
+
+ FilePermission fp = (FilePermission) p;
+ String f2 = fp.getName();
+
+ if (f2.equals(ALL_FILES))
+ return false;
+
+ try
+ {
+ f1 = new File(f1).getCanonicalPath();
+ f2 = new File(f2).getCanonicalPath();
+ }
+ catch (IOException ioe)
+ {
+ return false;
+ }
+
+ String sub1;
+
+ switch (f1.charAt(f1.length() - 1))
+ {
+ case '*':
+ sub1 = f1.substring(0, f1.length() - 1); // chop off "*"
+ if (f2.length() <= sub1.length())
+ {
+ // If it's smaller, there is no way it could be part of
+ // this directory. If it's the same (or length - 1), it
+ // could be the same directory but specifies access to
+ // the directory rather than the files in it.
+ return false;
+ }
+ else if (f2.charAt(sub1.length() - 1) == File.separatorChar)
+ {
+ // Make sure the part before the "/" is the same.
+ if (! f2.substring(0, sub1.length()).equals(sub1))
+ return false;
+ // Make sure there are no subdirectories specified
+ // underneath this one.
+ if (f2.substring(sub1.length() + 1).indexOf(File.separatorChar)
+ != -1)
+ return false;
+ }
+ else
+ {
+ // Obviously not equal: f2 is either not a directory or
+ // is not the same directory (its name continues further
+ // than we want).
+ return false;
+ }
+ break;
+ case '-':
+ // Chop off "/-".
+ sub1 = f1.substring(0, f1.length() - 2);
+ if (f2.length() < sub1.length())
+ {
+ // If it's smaller, there is no way it could be part of
+ // this directory.
+ return false;
+ }
+ else if (f2.length() > sub1.length()
+ && f2.charAt(sub1.length()) != File.separatorChar)
+ return false;
+ else if (! f2.substring(0, sub1.length()).equals(sub1))
+ return false;
+ break;
+
+ default:
+ if (!f1.equals(f2))
+ return false;
+ break;
+ }
+
+ if (fp.readPerm && ! readPerm)
+ return false;
+ if (fp.writePerm && ! writePerm)
+ return false;
+ if (fp.executePerm && ! executePerm)
+ return false;
+ if (fp.deletePerm && ! deletePerm)
+ return false;
+
+ return true;
+ }
+}
diff --git a/libjava/classpath/java/io/FileReader.java b/libjava/classpath/java/io/FileReader.java
new file mode 100644
index 000000000..05e14c376
--- /dev/null
+++ b/libjava/classpath/java/io/FileReader.java
@@ -0,0 +1,91 @@
+/* FileReader.java -- Convenience class for reading characters from a file
+ Copyright (C) 1998, 2000, 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 java.io;
+
+/**
+ * This class provides a convenient way to set up a <code>Reader</code>
+ * to read from a file. It opens the specified file for reading and creates
+ * the <code>InputStreamReader</code> to read from the
+ * resulting <code>FileInputStream</code>. This class can only be used
+ * to read from files using the default character encoding. Use
+ * <code>InputStreamReader</code> directly to use a non-default encoding.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class FileReader extends InputStreamReader
+{
+ /**
+ * This method initializes a <code>FileReader</code> instance to read from
+ * the specified <code>File</code> object.
+ *
+ * @param file The <code>File</code> object representing the file to read from
+ *
+ * @exception FileNotFoundException If the file is not found or some other
+ * error occurs
+ */
+ public FileReader(File file) throws FileNotFoundException
+ {
+ super(new FileInputStream(file));
+ }
+
+ /**
+ * This method initializes a <code>FileReader</code> instance to read from
+ * this specified <code>FileDescriptor</code> object.
+ *
+ * @param fd The <code>FileDescriptor</code> to read from.
+ */
+ public FileReader(FileDescriptor fd)
+ {
+ super(new FileInputStream(fd));
+ }
+
+ /**
+ * This method initializes a <code>FileReader</code> instance to read from
+ * the specified named file.
+ *
+ * @param name The name of the file to read from
+ *
+ * @exception FileNotFoundException If the file is not found or some other
+ * error occurs
+ */
+ public FileReader(String name) throws FileNotFoundException
+ {
+ super(new FileInputStream(name));
+ }
+} // class FileReader
diff --git a/libjava/classpath/java/io/FileWriter.java b/libjava/classpath/java/io/FileWriter.java
new file mode 100644
index 000000000..95d5eea3b
--- /dev/null
+++ b/libjava/classpath/java/io/FileWriter.java
@@ -0,0 +1,137 @@
+/* FileWriter.java -- Convenience class for writing to files.
+ Copyright (C) 1998, 1999, 2001, 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 java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Complete to version 1.1.
+ */
+
+/**
+ * This is a convenience class for writing to files. It creates an
+ * <code>FileOutputStream</code> and initializes an
+ * <code>OutputStreamWriter</code> to write to it.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ */
+public class FileWriter extends OutputStreamWriter
+{
+ /**
+ * This method initializes a new <code>FileWriter</code> object to write
+ * to the specified <code>File</code> object.
+ *
+ * @param file The <code>File</code> object to write to.
+ *
+ * @throws SecurityException If writing to this file is forbidden by the
+ * <code>SecurityManager</code>.
+ * @throws IOException If any other error occurs
+ */
+ public FileWriter(File file) throws SecurityException, IOException
+ {
+ super(new FileOutputStream(file));
+ }
+
+ /**
+ * This method initializes a new <code>FileWriter</code> object to write
+ * to the specified <code>File</code> object.
+ *
+ * @param file The <code>File</code> object to write to.
+ * @param append <code>true</code> to start adding data at the end of the
+ * file, <code>false</code> otherwise.
+ *
+ * @throws SecurityException If writing to this file is forbidden by the
+ * <code>SecurityManager</code>.
+ * @throws IOException If any other error occurs
+ */
+ public FileWriter(File file, boolean append) throws IOException
+ {
+ super(new FileOutputStream(file, append));
+ }
+
+ /**
+ * This method initializes a new <code>FileWriter</code> object to write
+ * to the specified <code>FileDescriptor</code> object.
+ *
+ * @param fd The <code>FileDescriptor</code> object to write to
+ *
+ * @throws SecurityException If writing to this file is forbidden by the
+ * <code>SecurityManager</code>.
+ */
+ public FileWriter(FileDescriptor fd) throws SecurityException
+ {
+ super(new FileOutputStream(fd));
+ }
+
+ /**
+ * This method intializes a new <code>FileWriter</code> object to
+ * write to the
+ * specified named file.
+ *
+ * @param name The name of the file to write to
+ *
+ * @throws SecurityException If writing to this file is forbidden by the
+ * <code>SecurityManager</code>.
+ * @throws IOException If any other error occurs
+ */
+ public FileWriter(String name) throws IOException
+ {
+ super(new FileOutputStream(name));
+ }
+
+ /**
+ * This method intializes a new <code>FileWriter</code> object to
+ * write to the
+ * specified named file. This form of the constructor allows the caller
+ * to determine whether data should be written starting at the beginning or
+ * the end of the file.
+ *
+ * @param name The name of the file to write to
+ * @param append <code>true</code> to start adding data at the end of the
+ * file, <code>false</code> otherwise.
+ *
+ * @throws SecurityException If writing to this file is forbidden by the
+ * <code>SecurityManager</code>.
+ * @throws IOException If any other error occurs
+ */
+ public FileWriter(String name, boolean append) throws IOException
+ {
+ super(new FileOutputStream(name, append));
+ }
+}
diff --git a/libjava/classpath/java/io/FilenameFilter.java b/libjava/classpath/java/io/FilenameFilter.java
new file mode 100644
index 000000000..5a9045f52
--- /dev/null
+++ b/libjava/classpath/java/io/FilenameFilter.java
@@ -0,0 +1,75 @@
+/* FilenameFilter.java -- Filter a list of filenames
+ Copyright (C) 1998, 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 java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Complete to 1.1.
+ */
+
+/**
+ * This interface has one method which is used for filtering filenames
+ * returned in a directory listing. It is currently used by the
+ * <code>File.list(FilenameFilter)</code> method and by the filename
+ * dialog in AWT.
+ * <p>
+ * The method in this interface determines if a particular file should
+ * or should not be included in the file listing.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ *
+ * @see File#listFiles(java.io.FilenameFilter)
+ * @see java.awt.FileDialog#setFilenameFilter(java.io.FilenameFilter)
+ */
+public interface FilenameFilter
+{
+ /**
+ * This method determines whether or not a given file should be included
+ * in a directory listing.
+ *
+ * @param dir The <code>File</code> instance for the directory being read
+ * @param name The name of the file to test
+ *
+ * @return <code>true</code> if the file should be included in the list,
+ * <code>false</code> otherwise.
+ */
+ boolean accept(File dir, String name);
+
+} // interface FilenameFilter
diff --git a/libjava/classpath/java/io/FilterInputStream.java b/libjava/classpath/java/io/FilterInputStream.java
new file mode 100644
index 000000000..c9d50e535
--- /dev/null
+++ b/libjava/classpath/java/io/FilterInputStream.java
@@ -0,0 +1,203 @@
+/* FilterInputStream.java -- Base class for classes that filter input
+ Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * This is the common superclass of all standard classes that filter
+ * input. It acts as a layer on top of an underlying <code>InputStream</code>
+ * and simply redirects calls made to it to the subordinate InputStream
+ * instead. Subclasses of this class perform additional filtering
+ * functions in addition to simply redirecting the call.
+ * <p>
+ * This class is not abstract. However, since it only redirects calls
+ * to a subordinate <code>InputStream</code> without adding any functionality
+ * on top of it, this class should not be used directly. Instead, various
+ * subclasses of this class should be used. This is enforced with a
+ * protected constructor. Do not try to hack around it.
+ * <p>
+ * When creating a subclass of <code>FilterInputStream</code>, override the
+ * appropriate methods to implement the desired filtering. However, note
+ * that the <code>read(byte[])</code> method does not need to be overridden
+ * as this class redirects calls to that method to
+ * <code>read(byte[], int, int)</code> instead of to the subordinate
+ * <code>InputStream read(byte[])</code> method.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public class FilterInputStream extends InputStream
+{
+ /**
+ * This is the subordinate <code>InputStream</code> to which method calls
+ * are redirected
+ */
+ protected InputStream in;
+
+ /**
+ * Create a <code>FilterInputStream</code> with the specified subordinate
+ * <code>InputStream</code>.
+ *
+ * @param in The subordinate <code>InputStream</code>
+ */
+ protected FilterInputStream(InputStream in)
+ {
+ this.in = in;
+ }
+
+ /**
+ * Calls the <code>in.mark(int)</code> method.
+ *
+ * @param readlimit The parameter passed to <code>in.mark(int)</code>
+ */
+ public void mark(int readlimit)
+ {
+ in.mark(readlimit);
+ }
+
+ /**
+ * Calls the <code>in.markSupported()</code> method.
+ *
+ * @return <code>true</code> if mark/reset is supported, <code>false</code>
+ * otherwise
+ */
+ public boolean markSupported()
+ {
+ return in.markSupported();
+ }
+
+ /**
+ * Calls the <code>in.reset()</code> method.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void reset() throws IOException
+ {
+ in.reset();
+ }
+
+ /**
+ * Calls the <code>in.available()</code> method.
+ *
+ * @return The value returned from <code>in.available()</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public int available() throws IOException
+ {
+ return in.available();
+ }
+
+ /**
+ * Calls the <code>in.skip(long)</code> method
+ *
+ * @param numBytes The requested number of bytes to skip.
+ *
+ * @return The value returned from <code>in.skip(long)</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public long skip(long numBytes) throws IOException
+ {
+ return in.skip(numBytes);
+ }
+
+ /**
+ * Calls the <code>in.read()</code> method
+ *
+ * @return The value returned from <code>in.read()</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read() throws IOException
+ {
+ return in.read();
+ }
+
+ /**
+ * Calls the <code>read(byte[], int, int)</code> overloaded method.
+ * Note that
+ * this method does not redirect its call directly to a corresponding
+ * method in <code>in</code>. This allows subclasses to override only the
+ * three argument version of <code>read</code>.
+ *
+ * @param buf The buffer to read bytes into
+ *
+ * @return The value retured from <code>in.read(byte[], int, int)</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read(byte[] buf) throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ /**
+ * Calls the <code>in.read(byte[], int, int)</code> method.
+ *
+ * @param buf The buffer to read bytes into
+ * @param offset The index into the buffer to start storing bytes
+ * @param len The maximum number of bytes to read.
+ *
+ * @return The value retured from <code>in.read(byte[], int, int)</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read(byte[] buf, int offset, int len) throws IOException
+ {
+ return in.read(buf, offset, len);
+ }
+
+ /**
+ * This method closes the input stream by closing the input stream that
+ * this object is filtering. Future attempts to access this stream may
+ * throw an exception.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ in.close();
+ }
+}
diff --git a/libjava/classpath/java/io/FilterOutputStream.java b/libjava/classpath/java/io/FilterOutputStream.java
new file mode 100644
index 000000000..401e5478c
--- /dev/null
+++ b/libjava/classpath/java/io/FilterOutputStream.java
@@ -0,0 +1,149 @@
+/* FilterOutputStream.java -- Parent class for output streams that filter
+ Copyright (C) 1998, 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 java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Complete to version 1.1.
+ */
+
+/**
+ * This class is the common superclass of output stream classes that
+ * filter the output they write. These classes typically transform the
+ * data in some way prior to writing it out to another underlying
+ * <code>OutputStream</code>. This class simply overrides all the
+ * methods in <code>OutputStream</code> to redirect them to the
+ * underlying stream. Subclasses provide actual filtering.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ */
+public class FilterOutputStream extends OutputStream
+{
+ /**
+ * This is the subordinate <code>OutputStream</code> that this class
+ * redirects its method calls to.
+ */
+ protected OutputStream out;
+
+ /**
+ * This method initializes an instance of <code>FilterOutputStream</code>
+ * to write to the specified subordinate <code>OutputStream</code>.
+ *
+ * @param out The <code>OutputStream</code> to write to
+ */
+ public FilterOutputStream(OutputStream out)
+ {
+ this.out = out;
+ }
+
+ /**
+ * This method closes the underlying <code>OutputStream</code>. Any
+ * further attempts to write to this stream may throw an exception.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ flush();
+ out.close();
+ }
+
+ /**
+ * This method attempt to flush all buffered output to be written to the
+ * underlying output sink.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void flush() throws IOException
+ {
+ out.flush();
+ }
+
+ /**
+ * This method writes a single byte of output to the underlying
+ * <code>OutputStream</code>.
+ *
+ * @param b The byte to write, passed as an int.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write(int b) throws IOException
+ {
+ out.write(b);
+ }
+
+ /**
+ * This method writes all the bytes in the specified array to the underlying
+ * <code>OutputStream</code>. It does this by calling the three parameter
+ * version of this method - <code>write(byte[], int, int)</code> in this
+ * class instead of writing to the underlying <code>OutputStream</code>
+ * directly. This allows most subclasses to avoid overriding this method.
+ *
+ * @param buf The byte array to write bytes from
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write(byte[] buf) throws IOException
+ {
+ // Don't do checking here, per Java Lang Spec.
+ write(buf, 0, buf.length);
+ }
+
+ /**
+ * This method calls the <code>write(int)</code> method <code>len</code>
+ * times for all bytes from the array <code>buf</code> starting at index
+ * <code>offset</code>. Subclasses should overwrite this method to get a
+ * more efficient implementation.
+ *
+ * @param buf The byte array to write bytes from
+ * @param offset The index into the array to start writing bytes 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
+ {
+ // Don't do checking here, per Java Lang Spec.
+ for (int i=0; i < len; i++)
+ write(buf[offset + i]);
+
+ }
+
+} // class FilterOutputStream
diff --git a/libjava/classpath/java/io/FilterReader.java b/libjava/classpath/java/io/FilterReader.java
new file mode 100644
index 000000000..0e57e21c5
--- /dev/null
+++ b/libjava/classpath/java/io/FilterReader.java
@@ -0,0 +1,184 @@
+/* FilterReader.java -- Base class for char stream classes that filter input
+ Copyright (C) 1998, 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 java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * This is the common superclass of all standard classes that filter
+ * input. It acts as a layer on top of an underlying <code>Reader</code>
+ * and simply redirects calls made to it to the subordinate Reader
+ * instead. Subclasses of this class perform additional filtering
+ * functions in addition to simply redirecting the call.
+ * <p>
+ * When creating a subclass of <code>FilterReader</code>, override the
+ * appropriate methods to implement the desired filtering. However, note
+ * that the <code>read(char[])</code> method does not need to be overridden
+ * as this class redirects calls to that method to
+ * <code>read(yte[], int, int)</code> instead of to the subordinate
+ * <code>Reader} read(yte[])</code> method.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public abstract class FilterReader extends Reader
+{
+ /**
+ * This is the subordinate <code>Reader</code> to which method calls
+ * are redirected
+ */
+ protected Reader in;
+
+ /**
+ * Create a <code>FilterReader</code> with the specified subordinate
+ * <code>Reader</code>.
+ * The <code>lock</code> of the new <code>FilterReader</code> will be set
+ * to <code>in.lock</code>.
+ *
+ * @param in The subordinate <code>Reader</code>
+ */
+ protected FilterReader(Reader in)
+ {
+ super(in.lock);
+ this.in = in;
+ }
+
+ /**
+ * Calls the <code>in.mark(int)</code> method.
+ *
+ * @param readlimit The parameter passed to <code>in.mark(int)</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public void mark(int readlimit) throws IOException
+ {
+ in.mark(readlimit);
+ }
+
+ /**
+ * Calls the <code>in.markSupported()</code> method.
+ *
+ * @return <code>true</code> if mark/reset is supported,
+ * <code>false</code> otherwise
+ */
+ public boolean markSupported()
+ {
+ return(in.markSupported());
+ }
+
+ /**
+ * Calls the <code>in.reset()</code> method.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void reset() throws IOException
+ {
+ in.reset();
+ }
+
+ /**
+ * Calls the <code>in.read()</code> method.
+ *
+ * @return The value returned from <code>in.available()</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public boolean ready() throws IOException
+ {
+ return(in.ready());
+ }
+
+ /**
+ * Calls the <code>in.skip(long)</code> method
+ *
+ * @param num_chars The requested number of chars to skip.
+ *
+ * @return The value returned from <code>in.skip(long)</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public long skip(long num_chars) throws IOException
+ {
+ return(in.skip(num_chars));
+ }
+
+ /**
+ * Calls the <code>in.read()</code> method
+ *
+ * @return The value returned from <code>in.read()</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read() throws IOException
+ {
+ return(in.read());
+ }
+
+ /**
+ * Calls the <code>in.read(char[], int, int)</code> method.
+ *
+ * @param buf The buffer to read chars into
+ * @param offset The index into the buffer to start storing chars
+ * @param len The maximum number of chars to read.
+ *
+ * @return The value retured from <code>in.read(char[], int, int)</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read(char[] buf, int offset, int len) throws IOException
+ {
+ return(in.read(buf, offset, len));
+ }
+
+ /**
+ * This method closes the stream by calling the <code>close()</code> method
+ * of the underlying stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ in.close();
+ }
+
+} // class FilterReader
diff --git a/libjava/classpath/java/io/FilterWriter.java b/libjava/classpath/java/io/FilterWriter.java
new file mode 100644
index 000000000..382dec06a
--- /dev/null
+++ b/libjava/classpath/java/io/FilterWriter.java
@@ -0,0 +1,146 @@
+/* FilterWriter.java -- Parent class for output streams that filter
+ Copyright (C) 1998, 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 java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Complete to version 1.1.
+ */
+
+/**
+ * This class is the common superclass of output character stream classes
+ * that filter the output they write. These classes typically transform the
+ * data in some way prior to writing it out to another underlying
+ * <code>Writer</code>. This class simply overrides all the
+ * methods in <code>Writer</code> to redirect them to the
+ * underlying stream. Subclasses provide actual filtering.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ */
+public abstract class FilterWriter extends Writer
+{
+ /**
+ * This is the subordinate <code>Writer</code> that this class
+ * redirects its method calls to.
+ */
+ protected Writer out;
+
+ /**
+ * This method initializes an instance of <code>FilterWriter</code>
+ * to write to the specified subordinate <code>Writer</code>.
+ * The given <code>Writer</code> will be used as <code>lock</code> for
+ * the newly created <code>FilterWriter</code>.
+ *
+ * @param out The <code>Writer</code> to write to
+ */
+ protected FilterWriter(Writer out)
+ {
+ super(out.lock);
+ this.out = out;
+ }
+
+ /**
+ * This method closes the underlying <code>Writer</code>. Any
+ * further attempts to write to this stream may throw an exception.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ out.close();
+ }
+
+ /**
+ * This method attempt to flush all buffered output to be written to the
+ * underlying output sink.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void flush() throws IOException
+ {
+ out.flush();
+ }
+
+ /**
+ * This method writes a single char of output to the underlying
+ * <code>Writer</code>.
+ *
+ * @param b The char to write, passed as an int.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write(int b) throws IOException
+ {
+ out.write(b);
+ }
+
+ /**
+ * This method writes <code>len</code> chars from the array <code>buf</code>
+ * starting at index <code>offset</code> to the underlying
+ * <code>Writer</code>.
+ *
+ * @param buf The char array to write chars from
+ * @param offset The index into the array to start writing chars from
+ * @param len The number of chars to write
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write(char[] buf, int offset, int len) throws IOException
+ {
+ out.write(buf, offset, len);
+ }
+
+ /**
+ * This method writes <code>len</code> chars from the <code>String</code>
+ * starting at position <code>offset</code>.
+ *
+ * @param str The <code>String</code> that is to be written
+ * @param offset The character offset into the <code>String</code>
+ * to start writing from
+ * @param len The number of chars to write
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write(String str, int offset, int len) throws IOException
+ {
+ out.write(str, offset, len);
+ }
+
+} // class FilterWriter
diff --git a/libjava/classpath/java/io/Flushable.java b/libjava/classpath/java/io/Flushable.java
new file mode 100644
index 000000000..e9718d60a
--- /dev/null
+++ b/libjava/classpath/java/io/Flushable.java
@@ -0,0 +1,62 @@
+/* Flushable.java -- Flushable object
+ 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 java.io;
+
+/**
+ * A <code>Flushable</code> class represents a stream of
+ * data, for which internally buffered data can be `flushed'.
+ * Flushing such a stream causes the buffered data to be
+ * written to the stream.
+ *
+ * @author Tom Tromey (tromey@redhat.com)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ * @since 1.5
+ */
+public interface Flushable
+{
+
+ /**
+ * Flushes the stream represented by this class,
+ * so that any buffered data is written to the stream.
+ *
+ * @throws IOException if an I/O error occurs in flushing.
+ */
+ void flush()
+ throws IOException;
+
+}
diff --git a/libjava/classpath/java/io/IOException.java b/libjava/classpath/java/io/IOException.java
new file mode 100644
index 000000000..cf3ad1946
--- /dev/null
+++ b/libjava/classpath/java/io/IOException.java
@@ -0,0 +1,74 @@
+/* IOException.java -- Generic input/output exception
+ Copyright (C) 1998, 1999, 2001, 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 java.io;
+
+/**
+ * This exception is thrown to indicate an I/O problem of some sort
+ * occurred. Since this is a fairly generic exception, often a subclass
+ * of IOException will actually be thrown in order to provide a more
+ * detailed indication of what happened.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ * @status updated to 1.4
+ */
+public class IOException extends Exception
+{
+ /**
+ * Compatible with JDK 1.0+.
+ */
+ private static final long serialVersionUID = 7818375828146090155L;
+
+ /**
+ * Create an exception without a descriptive error message.
+ */
+ public IOException()
+ {
+ }
+
+ /**
+ * Create an exception with a descriptive error message.
+ *
+ * @param message the descriptive error message
+ */
+ public IOException(String message)
+ {
+ super(message);
+ }
+} // class IOException
diff --git a/libjava/classpath/java/io/InputStream.java b/libjava/classpath/java/io/InputStream.java
new file mode 100644
index 000000000..58b3dbd19
--- /dev/null
+++ b/libjava/classpath/java/io/InputStream.java
@@ -0,0 +1,270 @@
+/* InputStream.java -- Base class for input
+ Copyright (C) 1998, 1999, 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 java.io;
+
+/**
+ * This abstract class forms the base of the hierarchy of classes that read
+ * input as a stream of bytes. It provides a common set of methods for
+ * reading bytes from streams. Subclasses implement and extend these
+ * methods to read bytes from a particular input source such as a file
+ * or network connection.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public abstract class InputStream implements Closeable
+{
+ /**
+ * Default, no-arg, public constructor
+ */
+ public InputStream()
+ {
+ }
+
+ /**
+ * This method returns the number of bytes that can be read from this
+ * stream before a read can block. A return of 0 indicates that blocking
+ * might (or might not) occur on the very next read attempt.
+ * <p>
+ * This method always returns 0 in this class
+ *
+ * @return The number of bytes that can be read before blocking could occur
+ *
+ * @exception IOException If an error occurs
+ */
+ public int available() throws IOException
+ {
+ return 0;
+ }
+
+ /**
+ * This method closes the stream. Any futher attempts to read from the
+ * stream may generate an <code>IOException</code>
+ * <p>
+ * This method does nothing in this class, but subclasses may override
+ * this method in order to provide additional functionality.
+ *
+ * @exception IOException If an error occurs, which can only happen
+ * in a subclass
+ */
+ public void close() throws IOException
+ {
+ // Do nothing
+ }
+
+ /**
+ * This method marks a position in the input to which the stream can
+ * be "reset" by calling the <code>reset()</code> method. The
+ * parameter @code{readlimit} is the number of bytes that can be read
+ * from the stream after setting the mark before the mark becomes
+ * invalid. For example, if <code>mark()</code> is called with a
+ * read limit of 10, then when 11 bytes of data are read from the
+ * stream before the <code>reset()</code> method is called, then the
+ * mark is invalid and the stream object instance is not required to
+ * remember the mark.
+ * <p>
+ * This method does nothing in this class, but subclasses may override it
+ * to provide mark/reset functionality.
+ *
+ * @param readLimit The number of bytes that can be read before the
+ * mark becomes invalid
+ */
+ public void mark(int readLimit)
+ {
+ // Do nothing
+ }
+
+ /**
+ * This method returns a boolean that indicates whether the mark/reset
+ * methods are supported in this class. Those methods can be used to
+ * remember a specific point in the stream and reset the stream to that
+ * point.
+ * <p>
+ * This method always returns <code>false</code> in this class, but
+ * subclasses can override this method to return <code>true</code>
+ * if they support mark/reset functionality.
+ *
+ * @return <code>true</code> if mark/reset functionality is
+ * supported, <code>false</code> otherwise
+ */
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ /**
+ * This method reads an unsigned byte from the input stream and returns it
+ * as an int in the range of 0-255. This method also will return -1 if
+ * the end of the stream has been reached.
+ * <p>
+ * This method will block until the byte can be read.
+ *
+ * @return The byte read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public abstract int read() throws IOException;
+
+ /**
+ * This method reads bytes from a stream and stores them into a caller
+ * supplied buffer. This method attempts to completely fill the buffer,
+ * but can return before doing so. The actual number of bytes read is
+ * returned as an int. A -1 is returned to indicate the end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ * <p>
+ * This method operates by calling an overloaded read method like so:
+ * <code>read(b, 0, b.length)</code>
+ *
+ * @param b The buffer into which the bytes read will be stored.
+ *
+ * @return The number of bytes read or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read(byte[] b) throws IOException
+ {
+ return read(b, 0, b.length);
+ }
+
+ /**
+ * This method read bytes from a stream and stores them into a
+ * caller supplied buffer. It starts storing the data at index
+ * <code>off</code> into the buffer and attempts to read
+ * <code>len</code> bytes. This method can return before reading the
+ * number of bytes requested. The actual number of bytes read is
+ * returned as an int. A -1 is returned to indicate the end of the
+ * stream.
+ * <p>
+ * This method will block until some data can be read.
+ * <p>
+ * This method operates by calling the single byte <code>read()</code> method
+ * in a loop until the desired number of bytes are read. The read loop
+ * stops short if the end of the stream is encountered or if an IOException
+ * is encountered on any read operation except the first. If the first
+ * attempt to read a bytes fails, the IOException is allowed to propagate
+ * upward. And subsequent IOException is caught and treated identically
+ * to an end of stream condition. Subclasses can (and should if possible)
+ * override this method to provide a more efficient implementation.
+ *
+ * @param b The array into which the bytes read should be stored
+ * @param off The offset into the array 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.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ if (off < 0 || len < 0 || b.length - off < len)
+ throw new IndexOutOfBoundsException();
+
+ int i, ch;
+
+ for (i = 0; i < len; ++i)
+ try
+ {
+ if ((ch = read()) < 0)
+ return i == 0 ? -1 : i; // EOF
+ b[off + i] = (byte) ch;
+ }
+ catch (IOException ex)
+ {
+ // Only reading the first byte should cause an IOException.
+ if (i == 0)
+ throw ex;
+ return i;
+ }
+
+ return i;
+ }
+
+ /**
+ * This method resets a stream to the point where the
+ * <code>mark()</code> method was called. Any bytes that were read
+ * after the mark point was set will be re-read during subsequent
+ * reads.
+ * <p>
+ * This method always throws an IOException in this class, but subclasses
+ * can override this method if they provide mark/reset functionality.
+ *
+ * @exception IOException Always thrown for this class
+ */
+ public void reset() throws IOException
+ {
+ throw new IOException("mark/reset not supported");
+ }
+
+ /**
+ * This method skips the specified number of bytes in the stream. It
+ * returns the actual number of bytes skipped, which may be less than the
+ * requested amount.
+ * <p>
+ * This method reads and discards bytes into a byte array until the
+ * specified number of bytes were skipped or until either the end of stream
+ * is reached or a read attempt returns a short count. Subclasses can
+ * override this metho to provide a more efficient implementation where
+ * one exists.
+ *
+ * @param n The requested number of bytes to skip
+ *
+ * @return The actual number of bytes skipped.
+ *
+ * @exception IOException If an error occurs
+ */
+ public long skip(long n) throws IOException
+ {
+ // Throw away n bytes by reading them into a temp byte[].
+ // Limit the temp array to 2Kb so we don't grab too much memory.
+ final int buflen = n > 2048 ? 2048 : (int) n;
+ byte[] tmpbuf = new byte[buflen];
+ final long origN = n;
+
+ while (n > 0L)
+ {
+ int numread = read(tmpbuf, 0, n > buflen ? buflen : (int) n);
+ if (numread <= 0)
+ break;
+ n -= numread;
+ }
+
+ return origN - n;
+ }
+}
diff --git a/libjava/classpath/java/io/InputStreamReader.java b/libjava/classpath/java/io/InputStreamReader.java
new file mode 100644
index 000000000..51925a8c5
--- /dev/null
+++ b/libjava/classpath/java/io/InputStreamReader.java
@@ -0,0 +1,509 @@
+/* InputStreamReader.java -- Reader than transforms bytes to chars
+ Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+import gnu.classpath.SystemProperties;
+import gnu.java.nio.charset.EncodingHelper;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * This class reads characters from a byte input stream. The characters
+ * read are converted from bytes in the underlying stream by a
+ * decoding layer. The decoding layer transforms bytes to chars according
+ * to an encoding standard. There are many available encodings to choose
+ * from. The desired encoding can either be specified by name, or if no
+ * encoding is selected, the system default encoding will be used. The
+ * system default encoding name is determined from the system property
+ * <code>file.encoding</code>. The only encodings that are guaranteed to
+ * be availalbe are "8859_1" (the Latin-1 character set) and "UTF8".
+ * Unforunately, Java does not provide a mechanism for listing the
+ * ecodings that are supported in a given implementation.
+ * <p>
+ * Here is a list of standard encoding names that may be available:
+ * <p>
+ * <ul>
+ * <li>8859_1 (ISO-8859-1/Latin-1)</li>
+ * <li>8859_2 (ISO-8859-2/Latin-2)</li>
+ * <li>8859_3 (ISO-8859-3/Latin-3)</li>
+ * <li>8859_4 (ISO-8859-4/Latin-4)</li>
+ * <li>8859_5 (ISO-8859-5/Latin-5)</li>
+ * <li>8859_6 (ISO-8859-6/Latin-6)</li>
+ * <li>8859_7 (ISO-8859-7/Latin-7)</li>
+ * <li>8859_8 (ISO-8859-8/Latin-8)</li>
+ * <li>8859_9 (ISO-8859-9/Latin-9)</li>
+ * <li>ASCII (7-bit ASCII)</li>
+ * <li>UTF8 (UCS Transformation Format-8)</li>
+ * <li>More later</li>
+ * </ul>
+ * <p>
+ * It is recommended that applications do not use
+ * <code>InputStreamReader</code>'s
+ * directly. Rather, for efficiency purposes, an object of this class
+ * should be wrapped by a <code>BufferedReader</code>.
+ * <p>
+ * Due to a deficiency the Java class library design, there is no standard
+ * way for an application to install its own byte-character encoding.
+ *
+ * @see BufferedReader
+ * @see InputStream
+ *
+ * @author Robert Schuster
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Per Bothner (bothner@cygnus.com)
+ * @date April 22, 1998.
+ */
+public class InputStreamReader extends Reader
+{
+ /**
+ * The input stream.
+ */
+ private InputStream in;
+
+ /**
+ * The charset decoder.
+ */
+ private CharsetDecoder decoder;
+
+ /**
+ * End of stream reached.
+ */
+ private boolean isDone = false;
+
+ /**
+ * Need this.
+ */
+ private float maxBytesPerChar;
+
+ /**
+ * Buffer holding surplus loaded bytes (if any)
+ */
+ private ByteBuffer byteBuffer;
+
+ /**
+ * java.io canonical name of the encoding.
+ */
+ private String encoding;
+
+ /**
+ * We might decode to a 2-char UTF-16 surrogate, which won't fit in the
+ * output buffer. In this case we need to save the surrogate char.
+ */
+ private char savedSurrogate;
+ private boolean hasSavedSurrogate = false;
+
+ /**
+ * A byte array to be reused in read(byte[], int, int).
+ */
+ private byte[] bytesCache;
+
+ /**
+ * Locks the bytesCache above in read(byte[], int, int).
+ */
+ private Object cacheLock = new Object();
+
+ /**
+ * This method initializes a new instance of <code>InputStreamReader</code>
+ * to read from the specified stream using the default encoding.
+ *
+ * @param in The <code>InputStream</code> to read from
+ */
+ public InputStreamReader(InputStream in)
+ {
+ if (in == null)
+ throw new NullPointerException();
+ this.in = in;
+ try
+ {
+ encoding = SystemProperties.getProperty("file.encoding");
+ // Don't use NIO if avoidable
+ if(EncodingHelper.isISOLatin1(encoding))
+ {
+ encoding = "ISO8859_1";
+ maxBytesPerChar = 1f;
+ decoder = null;
+ return;
+ }
+ Charset cs = EncodingHelper.getCharset(encoding);
+ decoder = cs.newDecoder();
+ encoding = EncodingHelper.getOldCanonical(cs.name());
+ try {
+ maxBytesPerChar = cs.newEncoder().maxBytesPerChar();
+ } catch(UnsupportedOperationException _){
+ maxBytesPerChar = 1f;
+ }
+ decoder.onMalformedInput(CodingErrorAction.REPLACE);
+ decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ decoder.reset();
+ } catch(RuntimeException e) {
+ encoding = "ISO8859_1";
+ maxBytesPerChar = 1f;
+ decoder = null;
+ } catch(UnsupportedEncodingException e) {
+ encoding = "ISO8859_1";
+ maxBytesPerChar = 1f;
+ decoder = null;
+ }
+ }
+
+ /**
+ * This method initializes a new instance of <code>InputStreamReader</code>
+ * to read from the specified stream using a caller supplied character
+ * encoding scheme. Note that due to a deficiency in the Java language
+ * design, there is no way to determine which encodings are supported.
+ *
+ * @param in The <code>InputStream</code> to read from
+ * @param encoding_name The name of the encoding scheme to use
+ *
+ * @exception UnsupportedEncodingException If the encoding scheme
+ * requested is not available.
+ */
+ public InputStreamReader(InputStream in, String encoding_name)
+ throws UnsupportedEncodingException
+ {
+ if (in == null
+ || encoding_name == null)
+ throw new NullPointerException();
+
+ this.in = in;
+ // Don't use NIO if avoidable
+ if(EncodingHelper.isISOLatin1(encoding_name))
+ {
+ encoding = "ISO8859_1";
+ maxBytesPerChar = 1f;
+ decoder = null;
+ return;
+ }
+ try {
+ Charset cs = EncodingHelper.getCharset(encoding_name);
+ try {
+ maxBytesPerChar = cs.newEncoder().maxBytesPerChar();
+ } catch(UnsupportedOperationException _){
+ maxBytesPerChar = 1f;
+ }
+
+ decoder = cs.newDecoder();
+ decoder.onMalformedInput(CodingErrorAction.REPLACE);
+ decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ decoder.reset();
+
+ // The encoding should be the old name, if such exists.
+ encoding = EncodingHelper.getOldCanonical(cs.name());
+ } catch(RuntimeException e) {
+ encoding = "ISO8859_1";
+ maxBytesPerChar = 1f;
+ decoder = null;
+ }
+ }
+
+ /**
+ * Creates an InputStreamReader that uses a decoder of the given
+ * charset to decode the bytes in the InputStream into
+ * characters.
+ *
+ * @since 1.4
+ */
+ public InputStreamReader(InputStream in, Charset charset) {
+ if (in == null)
+ throw new NullPointerException();
+ this.in = in;
+ decoder = charset.newDecoder();
+
+ try {
+ maxBytesPerChar = charset.newEncoder().maxBytesPerChar();
+ } catch(UnsupportedOperationException _){
+ maxBytesPerChar = 1f;
+ }
+
+ decoder.onMalformedInput(CodingErrorAction.REPLACE);
+ decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ decoder.reset();
+ encoding = EncodingHelper.getOldCanonical(charset.name());
+ }
+
+ /**
+ * Creates an InputStreamReader that uses the given charset decoder
+ * to decode the bytes in the InputStream into characters.
+ *
+ * @since 1.4
+ */
+ public InputStreamReader(InputStream in, CharsetDecoder decoder) {
+ if (in == null)
+ throw new NullPointerException();
+ this.in = in;
+ this.decoder = decoder;
+
+ Charset charset = decoder.charset();
+ try {
+ if (charset == null)
+ maxBytesPerChar = 1f;
+ else
+ maxBytesPerChar = charset.newEncoder().maxBytesPerChar();
+ } catch(UnsupportedOperationException _){
+ maxBytesPerChar = 1f;
+ }
+
+ decoder.onMalformedInput(CodingErrorAction.REPLACE);
+ decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ decoder.reset();
+ if (charset == null)
+ encoding = "US-ASCII";
+ else
+ encoding = EncodingHelper.getOldCanonical(decoder.charset().name());
+ }
+
+ /**
+ * This method closes this stream, as well as the underlying
+ * <code>InputStream</code>.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ synchronized (lock)
+ {
+ // Makes sure all intermediate data is released by the decoder.
+ if (decoder != null)
+ decoder.reset();
+ if (in != null)
+ in.close();
+ in = null;
+ isDone = true;
+ decoder = null;
+ }
+ }
+
+ /**
+ * This method returns the name of the encoding that is currently in use
+ * by this object. If the stream has been closed, this method is allowed
+ * to return <code>null</code>.
+ *
+ * @return The current encoding name
+ */
+ public String getEncoding()
+ {
+ return in != null ? encoding : null;
+ }
+
+ /**
+ * This method checks to see if the stream is ready to be read. It
+ * will return <code>true</code> if is, or <code>false</code> if it is not.
+ * If the stream is not ready to be read, it could (although is not required
+ * to) block on the next read attempt.
+ *
+ * @return <code>true</code> if the stream is ready to be read,
+ * <code>false</code> otherwise
+ *
+ * @exception IOException If an error occurs
+ */
+ public boolean ready() throws IOException
+ {
+ if (in == null)
+ throw new IOException("Reader has been closed");
+
+ return in.available() != 0;
+ }
+
+ /**
+ * This method reads up to <code>length</code> characters from the stream into
+ * the specified array starting at index <code>offset</code> into the
+ * array.
+ *
+ * @param buf The character array to recieve the data read
+ * @param offset The offset into the array to start storing characters
+ * @param length The requested number of characters to read.
+ *
+ * @return The actual number of characters read, or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read(char[] buf, int offset, int length) throws IOException
+ {
+ if (in == null)
+ throw new IOException("Reader has been closed");
+ if (isDone)
+ return -1;
+ if(decoder != null)
+ {
+ int totalBytes = (int)((double) length * maxBytesPerChar);
+ if (byteBuffer != null)
+ totalBytes = Math.max(totalBytes, byteBuffer.remaining());
+ byte[] bytes;
+ // Fetch cached bytes array if available and big enough.
+ synchronized(cacheLock)
+ {
+ bytes = bytesCache;
+ if (bytes == null || bytes.length < totalBytes)
+ bytes = new byte[totalBytes];
+ else
+ bytesCache = null;
+ }
+
+ int remaining = 0;
+ if(byteBuffer != null)
+ {
+ remaining = byteBuffer.remaining();
+ byteBuffer.get(bytes, 0, remaining);
+ }
+ int read;
+ if(totalBytes - remaining > 0)
+ {
+ read = in.read(bytes, remaining, totalBytes - remaining);
+ if(read == -1){
+ read = remaining;
+ isDone = true;
+ } else
+ read += remaining;
+ } else
+ read = remaining;
+ byteBuffer = ByteBuffer.wrap(bytes, 0, read);
+ CharBuffer cb = CharBuffer.wrap(buf, offset, length);
+ int startPos = cb.position();
+
+ if(hasSavedSurrogate){
+ hasSavedSurrogate = false;
+ cb.put(savedSurrogate);
+ read++;
+ }
+
+ CoderResult cr = decoder.decode(byteBuffer, cb, isDone);
+ decoder.reset();
+ // 1 char remains which is the first half of a surrogate pair.
+ if(cr.isOverflow() && cb.hasRemaining()){
+ CharBuffer overflowbuf = CharBuffer.allocate(2);
+ cr = decoder.decode(byteBuffer, overflowbuf, isDone);
+ overflowbuf.flip();
+ if(overflowbuf.hasRemaining())
+ {
+ cb.put(overflowbuf.get());
+ savedSurrogate = overflowbuf.get();
+ hasSavedSurrogate = true;
+ isDone = false;
+ }
+ }
+
+ if(byteBuffer.hasRemaining()) {
+ byteBuffer.compact();
+ byteBuffer.flip();
+ isDone = false;
+ } else
+ byteBuffer = null;
+
+ read = cb.position() - startPos;
+
+ // Put cached bytes array back if we are finished and the cache
+ // is null or smaller than the used bytes array.
+ synchronized (cacheLock)
+ {
+ if (byteBuffer == null
+ && (bytesCache == null || bytesCache.length < bytes.length))
+ bytesCache = bytes;
+ }
+ return (read <= 0) ? -1 : read;
+ }
+ else
+ {
+ byte[] bytes;
+ // Fetch cached bytes array if available and big enough.
+ synchronized (cacheLock)
+ {
+ bytes = bytesCache;
+ if (bytes == null || length < bytes.length)
+ bytes = new byte[length];
+ else
+ bytesCache = null;
+ }
+
+ int read = in.read(bytes);
+ for(int i=0;i<read;i++)
+ buf[offset+i] = (char)(bytes[i]&0xFF);
+
+ // Put back byte array into cache if appropriate.
+ synchronized (cacheLock)
+ {
+ if (bytesCache == null || bytesCache.length < bytes.length)
+ bytesCache = bytes;
+ }
+ return read;
+ }
+ }
+
+ /**
+ * Reads an char from the input stream and returns it
+ * as an int in the range of 0-65535. This method also will return -1 if
+ * the end of the stream has been reached.
+ * <p>
+ * This method will block until the char can be read.
+ *
+ * @return The char read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read() throws IOException
+ {
+ char[] buf = new char[1];
+ int count = read(buf, 0, 1);
+ return count > 0 ? buf[0] : -1;
+ }
+
+ /**
+ * Skips the specified number of chars in the stream. It
+ * returns the actual number of chars skipped, which may be less than the
+ * requested amount.
+ *
+ * @param count The requested number of chars to skip
+ *
+ * @return The actual number of chars skipped.
+ *
+ * @exception IOException If an error occurs
+ */
+ public long skip(long count) throws IOException
+ {
+ if (in == null)
+ throw new IOException("Reader has been closed");
+
+ return super.skip(count);
+ }
+}
diff --git a/libjava/classpath/java/io/InterruptedIOException.java b/libjava/classpath/java/io/InterruptedIOException.java
new file mode 100644
index 000000000..96ec83649
--- /dev/null
+++ b/libjava/classpath/java/io/InterruptedIOException.java
@@ -0,0 +1,94 @@
+/* InterruptedIOException.java -- an I/O operation was interrupted
+ Copyright (C) 1998, 1999, 2001, 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 java.io;
+
+/**
+ * This exception is thrown when a in process I/O operation is interrupted
+ * for some reason. The field bytesTransferred will contain the number of
+ * bytes that were read/written prior to the interruption.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ * @see Thread#interrupt()
+ * @status updated to 1.4
+ */
+public class InterruptedIOException extends IOException
+{
+ /**
+ * Compatible with JDK 1.0+.
+ */
+ private static final long serialVersionUID = 4020568460727500567L;
+
+ /**
+ * The number of bytes read/written prior to the interruption.
+ *
+ * @serial count of bytes successfully transferred
+ */
+ public int bytesTransferred;
+
+ /**
+ * Create an extends without a descriptive error message.
+ */
+ public InterruptedIOException()
+ {
+ }
+
+ /**
+ * Create an exception with a descriptive error message.
+ *
+ * @param message the descriptive error message
+ */
+ public InterruptedIOException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Create an exception with a descriptive error message and count of
+ * bytes transferred.
+ *
+ * @param message the descriptive error message
+ * @param bytesTransferred number of bytes tranferred before interruption
+ */
+ InterruptedIOException(String message, int bytesTransferred)
+ {
+ super(message);
+ this.bytesTransferred = bytesTransferred;
+ }
+} // class InterruptedIOException
diff --git a/libjava/classpath/java/io/InvalidClassException.java b/libjava/classpath/java/io/InvalidClassException.java
new file mode 100644
index 000000000..e31a44f2d
--- /dev/null
+++ b/libjava/classpath/java/io/InvalidClassException.java
@@ -0,0 +1,110 @@
+/* InvalidClassException.java -- deserializing a class failed
+ 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 java.io;
+
+/**
+ * This exception is thrown when there is some sort of problem with a
+ * class during a serialization operation. This could be:<br><ul>
+ * <li>the serial version of the class doesn't match</li>
+ * <li>the class contains unknown datatypes</li>
+ * <li>the class does not have an accessible no-arg constructor</li>
+ * </ul>.
+ *
+ * <p>The field <code>classname</code> will contain the name of the
+ * class that caused the problem if known. The getMessage() method
+ * for this exception will always include the name of that class
+ * if known.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class InvalidClassException extends ObjectStreamException
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = -4333316296251054416L;
+
+ /**
+ * The name of the class which encountered the error.
+ *
+ * @serial the classname causing the error
+ */
+ public String classname;
+
+ /**
+ * Create an exception with a descriptive error message, but a null
+ * classname.
+ *
+ * @param message the descriptive error message
+ */
+ public InvalidClassException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Create an exception with a descriptive error message, and the name of
+ * the class that caused the problem.
+ *
+ * @param classname the name of the faulty class
+ * @param message the descriptive error message
+ */
+ public InvalidClassException(String classname, String message)
+ {
+ super(message);
+ this.classname = classname;
+ }
+
+ /**
+ * Returns the descriptive error message for this exception. It will
+ * include the class name that caused the problem if known, in the format:
+ * <code>[classname][; ][super.getMessage()]</code>.
+ *
+ * @return A descriptive error message, may be null
+ */
+ public String getMessage()
+ {
+ String msg = super.getMessage();
+ if (msg == null)
+ return classname;
+ return (classname == null ? "" : classname + "; ") + msg;
+ }
+}
diff --git a/libjava/classpath/java/io/InvalidObjectException.java b/libjava/classpath/java/io/InvalidObjectException.java
new file mode 100644
index 000000000..deee876db
--- /dev/null
+++ b/libjava/classpath/java/io/InvalidObjectException.java
@@ -0,0 +1,66 @@
+/* InvalidObjectException.java -- deserialization failed verification
+ 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 java.io;
+
+/**
+ * This exception is thrown when an object fails a validation test
+ * during serialization.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class InvalidObjectException extends ObjectStreamException
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = 3233174318281839583L;
+
+ /**
+ * Create an exception with a descriptive error message String. This should
+ * be the cause of the verification failure.
+ *
+ * @param message the descriptive error message
+ */
+ public InvalidObjectException(String message)
+ {
+ super(message);
+ }
+} // class InvalidObjectException
diff --git a/libjava/classpath/java/io/LineNumberInputStream.java b/libjava/classpath/java/io/LineNumberInputStream.java
new file mode 100644
index 000000000..2d8e36202
--- /dev/null
+++ b/libjava/classpath/java/io/LineNumberInputStream.java
@@ -0,0 +1,315 @@
+/* LineNumberInputStream.java -- An input stream which counts line numbers
+ 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 java.io;
+
+/**
+ * This class functions like a standard <code>InputStream</code>
+ * except that it counts line numbers, and canonicalizes newline
+ * characters. As data is read, whenever the byte sequences "\r",
+ * "\n", or "\r\n" are encountered, the running line count is
+ * incremeted by one. Additionally, the whatever line termination
+ * sequence was encountered will be converted to a "\n" byte. Note
+ * that this class numbers lines from 0. When the first line
+ * terminator is encountered, the line number is incremented to 1, and
+ * so on.
+ * <p>
+ * This class counts only line termination characters. If the last line
+ * read from the stream does not end in a line termination sequence, it
+ * will not be counted as a line.
+ * <p>
+ * Note that since this class operates as a filter on an underlying
+ * stream, it has the same mark/reset functionality as the underlying
+ * stream. The <code>mark()</code> and <code>reset()</code> methods
+ * in this class handle line numbers correctly. Calling
+ * <code>reset()</code> resets the line number to the point at which
+ * <code>mark()</code> was called if the subordinate stream supports
+ * that functionality.
+ * <p>
+ * @deprecated This class is deprecated in favor if
+ * <code>LineNumberReader</code> because it operates on ASCII bytes
+ * instead of an encoded character stream. This class is for backward
+ * compatibility only and should not be used in new applications.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public class LineNumberInputStream extends FilterInputStream
+{
+ /** The current line number. */
+ private int lineNumber = 0;
+
+ /** The line number when the stream was marked. */
+ private int markLineNumber = 0;
+
+ /** Flag to indicate a '\r' was just read so that an immediately
+ * subsequent '\n' can be ignored. */
+ private boolean justReadReturnChar = false;
+
+ /**
+ * Create a new <code>LineNumberInputStream</code> that reads from the
+ * specified subordinate <code>InputStream</code>
+ *
+ * @param in The subordinate <code>InputStream</code> to read from
+ */
+ public LineNumberInputStream(InputStream in)
+ {
+ super(in);
+ }
+
+ /**
+ * This method returns the number of bytes that can be read from the
+ * stream before the stream can block. This method is tricky
+ * because the subordinate <code>InputStream</code> might return
+ * only "\r\n" characters, which are replaced by a single "\n"
+ * character by the <code>read()</code> method of this class. So
+ * this method can only guarantee that <code>in.available() /
+ * 2</code> bytes can actually be read before blocking. In
+ * practice, considerably more bytes might be read before blocking
+ * <p>
+ * Note that the stream may not block if additional bytes beyond the count
+ * returned by this method are read.
+ *
+ * @return The number of bytes that can be read before blocking could occur
+ *
+ * @exception IOException If an error occurs
+ */
+ public int available() throws IOException
+ {
+ // We can only guarantee half the characters that might be available
+ // without blocking because "\r\n" is treated as a single character.
+ return in.available() / 2;
+ }
+
+ /**
+ * This method returns the current line number
+ *
+ * @return The current line number
+ */
+ public int getLineNumber()
+ {
+ return lineNumber;
+ }
+
+ /**
+ * This method marks a position in the input to which the stream can
+ * be "reset" byte calling the <code>reset()</code> method. The
+ * parameter <code>readlimit</code> is the number of bytes that can
+ * be read from the stream after setting the mark before the mark
+ * becomes invalid. For example, if <code>mark()</code> is called
+ * with a read limit of 10, then when 11 bytes of data are read from
+ * the stream before the <code>reset()</code> method is called, then
+ * the mark is invalid and the stream object instance is not
+ * required to remember the mark.
+ * <p>
+ * In this class, this method will remember the current line number
+ * as well as the current position in the stream. When the
+ * <code>reset()</code> method is called, the line number will be
+ * restored to the saved line number in addition to the stream
+ * position.
+ * <p>
+ * This method only works if the subordinate stream supports mark/reset
+ * functionality.
+ *
+ * @param readlimit The number of bytes that can be read before the
+ * mark becomes invalid
+ */
+ public void mark(int readlimit)
+ {
+ in.mark(readlimit);
+ markLineNumber = lineNumber;
+ }
+
+ /**
+ * This method reads an unsigned byte from the input stream and returns it
+ * as an int in the range of 0-255. This method will return -1 if the
+ * end of the stream has been reached.
+ * <p>
+ * Note that if a line termination sequence is encountered (ie, "\r",
+ * "\n", or "\r\n") then that line termination sequence is converted to
+ * a single "\n" value which is returned from this method. This means
+ * that it is possible this method reads two bytes from the subordinate
+ * stream instead of just one.
+ * <p>
+ * Note that this method will block until a byte of data is available
+ * to be read.
+ *
+ * @return The byte read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read() throws IOException
+ {
+ // Treat "\r\n" as a single character. A '\r' may have been read by
+ // a previous call to read so we keep an internal flag to avoid having
+ // to read ahead.
+
+ int ch = in.read();
+
+ if (ch == '\n')
+ if (justReadReturnChar)
+ {
+ ch = in.read();
+ justReadReturnChar = false;
+ }
+ else
+ lineNumber++;
+ else if (ch == '\r')
+ {
+ ch = '\n';
+ justReadReturnChar = true;
+ lineNumber++;
+ }
+ else
+ justReadReturnChar = false;
+
+ return ch;
+ }
+
+ /**
+ * This method reads bytes from a stream and stores them into a caller
+ * supplied buffer. It starts storing data at index <code>offset</code> into
+ * the buffer and attemps to read <code>len</code> bytes. This method can
+ * return before reading the number of bytes requested. The actual number
+ * of bytes read is returned as an int. A -1 is returned to indicated the
+ * end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ * <p>
+ * Note that if a line termination sequence is encountered (ie, "\r",
+ * "\n", or "\r\n") then that line termination sequence is converted to
+ * a single "\n" value which is stored in the buffer. Only a single
+ * byte is counted towards the number of bytes read in this case.
+ *
+ * @param b The array into which the bytes read should be stored
+ * @param off The offset into the array 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
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ // This case always succeeds.
+ if (len == 0)
+ return 0;
+
+ // The simplest, though not necessarily the most time efficient thing
+ // to do is simply call read(void) len times. Since this is a deprecated
+ // class, that should be ok.
+ final int origOff = off;
+ while (len-- > 0)
+ {
+ int ch = read();
+ if (ch < 0)
+ break;
+
+ b[off++] = (byte) ch;
+ }
+
+ // This is safe since we already know that some bytes were
+ // actually requested.
+ return off == origOff ? -1 : off - origOff;
+ }
+
+ /**
+ * This method resets a stream to the point where the
+ * <code>mark()</code> method was called. Any bytes that were read
+ * after the mark point was set will be re-read during subsequent
+ * reads.
+ * <p>
+ * In this class, this method will also restore the line number that was
+ * current when the <code>mark()</code> method was called.
+ * <p>
+ * This method only works if the subordinate stream supports mark/reset
+ * functionality.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void reset() throws IOException
+ {
+ in.reset();
+ lineNumber = markLineNumber;
+ justReadReturnChar = false;
+ }
+
+ /**
+ * This method sets the current line number to the specified value.
+ *
+ * @param lineNumber The new line number
+ */
+ public void setLineNumber(int lineNumber)
+ {
+ this.lineNumber = lineNumber;
+ }
+
+ /**
+ * This method skips up to the requested number of bytes in the
+ * input stream. The actual number of bytes skipped is returned. If the
+ * desired number of bytes to skip is negative, no bytes are skipped.
+ *
+ * @param n requested number of bytes to skip.
+ *
+ * @return The actual number of bytes skipped.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public long skip(long n) throws IOException
+ {
+ if (n <= 0)
+ return 0L;
+
+ final long origN = n;
+
+ do
+ {
+ int ch = read();
+ if (ch < 0)
+ break;
+ if (ch == '\n' || ch == '\r')
+ lineNumber++;
+ }
+ while (--n > 0);
+
+ return origN - n;
+ }
+}
diff --git a/libjava/classpath/java/io/LineNumberReader.java b/libjava/classpath/java/io/LineNumberReader.java
new file mode 100644
index 000000000..6ac0b55fe
--- /dev/null
+++ b/libjava/classpath/java/io/LineNumberReader.java
@@ -0,0 +1,416 @@
+/* LineNumberReader.java -- A character input stream which counts line numbers
+ Copyright (C) 1998, 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 java.io;
+
+/**
+ * This class functions like a standard <code>Reader</code> except that it
+ * counts line numbers, and canonicalizes newline characters. As data
+ * is read, whenever the char sequences "\r", "\n", or "\r\n" are encountered,
+ * the running line count is incremeted by one. Additionally, the whatever
+ * line termination sequence was encountered will be converted to a "\n"
+ * char. Note that this class numbers lines from 0. When the first
+ * line terminator is encountered, the line number is incremented to 1, and
+ * so on. Also note that actual "\r" and "\n" characters are looked for.
+ * The system dependent line separator sequence is ignored.
+ * <p>
+ * This class counts only line termination characters. If the last line
+ * read from the stream does not end in a line termination sequence, it
+ * will not be counted as a line.
+ *
+ * @author Per Bothner (bothner@cygnus.com)
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Guilhem Lavaux (guilhem@kaffe.org)
+ * @date December 28, 2003.
+ */
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ *
+ * This implementation has the feature that if '\r' is read, it
+ * does not look for a '\n', but immediately returns '\n'.
+ * On the next read(), if a '\n' is read, it is skipped.
+ * This has the advantage that we do not read (and hang) unnecessarily.
+ *
+ * This implementation is also minimal in the number of fields it uses.
+ */
+public class LineNumberReader extends BufferedReader
+{
+ /** The current line number. */
+ private int lineNumber;
+ /** Whether we already found a new line in the former call. */
+ private boolean matchedNewLine;
+ /** The saved line number when calling mark() */
+ private int savedLineNumber;
+
+ /**
+ * Create a new <code>LineNumberReader</code> that reads from the
+ * specified subordinate <code>Reader</code>. A default 8K char sized
+ * buffer will be used for reads.
+ *
+ * @param in The subordinate <code>Reader</code> to read from
+ */
+ public LineNumberReader(Reader in)
+ {
+ super(in, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * This method initializes a new <code>LineNumberReader</code> to read
+ * from the specified subordinate <code>Reader</code> using the specified
+ * read buffer size.
+ *
+ * @param in The subordinate <code>Reader</code> to read from
+ * @param size The buffer size to use for reading
+ */
+ public LineNumberReader(Reader in, int size)
+ {
+ super(in, size);
+ }
+
+ /**
+ * This method returns the current line number
+ *
+ * @return The current line number
+ */
+ public int getLineNumber()
+ {
+ return lineNumber;
+ }
+
+ /**
+ * This method sets the current line number to the specified value.
+ *
+ * @param lineNumber The new line number
+ */
+ public void setLineNumber(int lineNumber)
+ {
+ this.lineNumber = lineNumber;
+ }
+
+ /**
+ * This method marks a position in the input to which the stream can be
+ * "reset" char calling the <code>reset()</code> method. The parameter
+ * <code>readlimit</code> is the number of chars that can be read from the
+ * stream after setting the mark before the mark becomes invalid. For
+ * example, if <code>mark()</code> is called with a read limit of 10,
+ * then when
+ * 11 chars of data are read from the stream before the <code>reset()</code>
+ * method is called, then the mark is invalid and the stream object
+ * instance is not required to remember the mark.
+ * <p>
+ * In this class, this method will remember the current line number as well
+ * as the current position in the stream. When the <code>reset()</code>
+ * method
+ * is called, the line number will be restored to the saved line number in
+ * addition to the stream position.
+ *
+ * @param readLimit The number of chars that can be read before the
+ * mark becomes invalid
+ *
+ * @exception IOException If an error occurs
+ */
+ public void mark(int readLimit) throws IOException
+ {
+ if (readLimit < 0)
+ throw new IllegalArgumentException("Read-ahead limit is negative");
+
+ synchronized (lock)
+ {
+ // This is basically the same as BufferedReader.mark.
+ // However, if the previous character was a '\r', we need to
+ // save that 'r', in case the next character is a '\n'.
+ if (pos + readLimit > limit)
+ {
+ int saveCR = matchedNewLine ? 1 : 0;
+ char[] old_buffer = buffer;
+ if (readLimit > limit)
+ buffer = new char[saveCR + readLimit];
+ int copy_start = pos - saveCR;
+ savedLineNumber = lineNumber;
+ limit -= copy_start;
+ System.arraycopy(old_buffer, copy_start, buffer, 0, limit);
+ pos = saveCR;
+ }
+ markPos = pos;
+ }
+ }
+
+ /**
+ * This method resets a stream to the point where the <code>mark()</code>
+ * method
+ * was called. Any chars that were read after the mark point was set will
+ * be re-read during subsequent reads.
+ * <p>
+ * In this class, this method will also restore the line number that was
+ * current when the <code>mark()</code> method was called.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void reset() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (markPos < 0)
+ throw new IOException("mark never set or invalidated");
+ lineNumber = savedLineNumber;
+ pos = markPos;
+ matchedNewLine = (markPos > 0 && buffer[markPos-1] == '\r');
+ }
+ }
+
+ /**
+ * This private method fills the input buffer whatever pos is.
+ * Consequently pos should be checked before calling this method.
+ *
+ * @return the number of bytes actually read from the input stream or
+ * -1 if end of stream.
+ * @exception IOException If an error occurs.
+ */
+ private int fill() throws IOException
+ {
+ if (markPos >= 0 && limit == buffer.length)
+ markPos = -1;
+ if (markPos < 0)
+ pos = limit = 0;
+ int count = in.read(buffer, limit, buffer.length - limit);
+ if (count <= 0)
+ return -1;
+ limit += count;
+
+ return count;
+ }
+
+ /**
+ * This method reads an unsigned char from the input stream and returns it
+ * as an int in the range of 0-65535. This method will return -1 if the
+ * end of the stream has been reached.
+ * <p>
+ * Note that if a line termination sequence is encountered (ie, "\r",
+ * "\n", or "\r\n") then that line termination sequence is converted to
+ * a single "\n" value which is returned from this method. This means
+ * that it is possible this method reads two chars from the subordinate
+ * stream instead of just one.
+ * <p>
+ * Note that this method will block until a char of data is available
+ * to be read.
+ *
+ * @return The char read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read() throws IOException
+ {
+ synchronized (lock)
+ {
+ skipRedundantLF();
+ if (pos >= limit && fill() < 0)
+ return -1;
+ char ch = buffer[pos++];
+
+ if ((matchedNewLine = (ch == '\r')) || ch == '\n')
+ {
+ lineNumber++;
+ return '\n';
+ }
+ matchedNewLine = false;
+ return (int) ch;
+ }
+ }
+
+ /**
+ * This method reads chars from a stream and stores them into a caller
+ * supplied buffer. It starts storing data at index <code>offset</code> into
+ * the buffer and attemps to read <code>len</code> chars. This method can
+ * return before reading the number of chars requested. The actual number
+ * of chars read is returned as an int. A -1 is returned to indicated the
+ * end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ * <p>
+ * Note that if a line termination sequence is encountered (ie, "\r",
+ * "\n", or "\r\n") then that line termination sequence is converted to
+ * a single "\n" value which is stored in the buffer. Only a single
+ * char is counted towards the number of chars read in this case.
+ *
+ * @param buf The array into which the chars read should be stored
+ * @param offset The offset into the array to start storing chars
+ * @param count The requested number of chars to read
+ *
+ * @return The actual number of chars read, or -1 if end of stream
+ *
+ * @exception IOException If an error occurs.
+ * @exception NullPointerException If buf is null (in any case).
+ * @exception IndexOutOfBoundsException If buffer parameters (offset and
+ * count) lies outside of the buffer capacity.
+ */
+ public int read(char[] buf, int offset, int count) throws IOException
+ {
+ if (buf == null)
+ throw new NullPointerException();
+
+ if (offset + count > buf.length || offset < 0)
+ throw new IndexOutOfBoundsException();
+
+ if (count <= 0)
+ {
+ if (count < 0)
+ throw new IndexOutOfBoundsException();
+ return 0;
+ }
+
+ synchronized (lock)
+ {
+ if (pos >= limit && fill() < 0)
+ return -1;
+
+ int start_offset = offset;
+ boolean matched = matchedNewLine;
+
+ while (count-- > 0 && pos < limit)
+ {
+ char ch = buffer[pos++];
+ if (ch == '\r')
+ {
+ lineNumber++;
+ matched = true;
+ }
+ else if (ch == '\n' && !matched)
+ lineNumber++;
+ else
+ matched = false;
+
+ buf[offset++] = ch;
+ }
+
+ matchedNewLine = matched;
+ return offset - start_offset;
+ }
+ }
+
+ private void skipRedundantLF() throws IOException
+ {
+ if (pos > 0 && matchedNewLine)
+ {
+ if (pos < limit)
+ { // fast case
+ if (buffer[pos] == '\n')
+ pos++;
+ }
+ else
+ { // check whether the next buffer begins with '\n'.
+ // in that case kill the '\n'.
+ if (fill() <= 0)
+ return;
+ if (buffer[pos] == '\n')
+ pos++;
+ }
+ matchedNewLine = true;
+ }
+ }
+
+ /**
+ * This method reads a line of text from the input stream and returns
+ * it as a <code>String</code>. A line is considered to be terminated
+ * by a "\r", "\n", or "\r\n" sequence, not by the system dependent line
+ * separator.
+ *
+ * @return The line read as a <code>String</code> or <code>null</code>
+ * if end of stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ public String readLine() throws IOException
+ {
+ // BufferedReader.readLine already does this. Shouldn't need to keep
+ // track of newlines (since the read method deals with this for us).
+ // But if the buffer is large, we may not call the read method at all
+ // and super.readLine can't increment lineNumber itself.
+ // Though it may seem kludgy, the safest thing to do is to save off
+ // lineNumber and increment it explicitly when we're done (iff we
+ // ended with a '\n' or '\r' as opposed to EOF).
+ //
+ // Also, we need to undo the special casing done by BufferedReader.readLine
+ // when a '\r' is the last char in the buffer. That situation is marked
+ // by 'pos > limit'.
+ int tmpLineNumber = lineNumber;
+ skipRedundantLF();
+ String str = super.readLine();
+ if (pos > limit)
+ --pos;
+
+ // The only case where you mustn't increment the line number is you are
+ // at the EOS.
+ if (str != null)
+ lineNumber = tmpLineNumber + 1;
+
+ return str;
+ }
+
+ /**
+ * This method skips over characters in the stream. This method will
+ * skip the specified number of characters if possible, but is not required
+ * to skip them all. The actual number of characters skipped is returned.
+ * This method returns 0 if the specified number of chars is less than 1.
+ *
+ * @param count The specified number of chars to skip.
+ *
+ * @return The actual number of chars skipped.
+ *
+ * @exception IOException If an error occurs
+ */
+ public long skip (long count) throws IOException
+ {
+ if (count < 0)
+ throw new IllegalArgumentException("skip() value is negative");
+ if (count == 0)
+ return 0;
+
+ int skipped;
+ char[] buf = new char[1];
+
+ for (skipped = 0; skipped < count; skipped++)
+ {
+ int ch = read(buf, 0, 1);
+
+ if (ch < 0)
+ break;
+ }
+
+ return skipped;
+ }
+}
diff --git a/libjava/classpath/java/io/NotActiveException.java b/libjava/classpath/java/io/NotActiveException.java
new file mode 100644
index 000000000..949ba8eca
--- /dev/null
+++ b/libjava/classpath/java/io/NotActiveException.java
@@ -0,0 +1,72 @@
+/* NotActiveException.java -- thrown when serialization is not active
+ 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 java.io;
+
+/**
+ * This exception is thrown when a problem occurs due to the fact that
+ * serialization is not active.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class NotActiveException extends ObjectStreamException
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = -3893467273049808895L;
+
+ /**
+ * Create an exception without a descriptive error message.
+ */
+ public NotActiveException()
+ {
+ }
+
+ /**
+ * Create an exception with a descriptive error message.
+ *
+ * @param message the descriptive error message
+ */
+ public NotActiveException(String message)
+ {
+ super(message);
+ }
+} // class NotActiveException
diff --git a/libjava/classpath/java/io/NotSerializableException.java b/libjava/classpath/java/io/NotSerializableException.java
new file mode 100644
index 000000000..d49c939e3
--- /dev/null
+++ b/libjava/classpath/java/io/NotSerializableException.java
@@ -0,0 +1,74 @@
+/* NotSerializableException.java -- a Serializable class that isn't
+ 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 java.io;
+
+/**
+ * This exception is thrown when a class implements Serializable because
+ * of a superclass, but should not be serialized. The descriptive message
+ * will consist of the name of the class in question.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class NotSerializableException extends ObjectStreamException
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = 2906642554793891381L;
+
+ /**
+ * Create an exception without a descriptive error message.
+ */
+ public NotSerializableException()
+ {
+ }
+
+ /**
+ * Create an exception with a descriptive error message, which should
+ * be the name of the class.
+ *
+ * @param message the descriptive error message
+ */
+ public NotSerializableException(String message)
+ {
+ super(message);
+ }
+} // class NotSerializableException
diff --git a/libjava/classpath/java/io/ObjectInput.java b/libjava/classpath/java/io/ObjectInput.java
new file mode 100644
index 000000000..f8d51e00d
--- /dev/null
+++ b/libjava/classpath/java/io/ObjectInput.java
@@ -0,0 +1,140 @@
+/* ObjectInput.java -- Read object data from a stream
+ Copyright (C) 1998,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 java.io;
+
+/**
+ * This interface extends the <code>DataInput</code> interface to provide a
+ * facility to read objects as well as primitive types from a stream. It
+ * also has methods that allow input to be done in a manner similar to
+ * <code>InputStream</code>
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ *
+ * @see DataInput
+ */
+public interface ObjectInput extends DataInput
+{
+ /**
+ * This method returns the number of bytes that can be read without
+ * blocking.
+ *
+ * @return The number of bytes available before blocking
+ *
+ * @exception IOException If an error occurs
+ */
+ int available() throws IOException;
+
+ /**
+ * This method reading a byte of data from a stream. It returns that byte
+ * as an <code>int</code>. This method blocks if no data is available
+ * to be read.
+ *
+ * @return The byte of data read
+ *
+ * @exception IOException If an error occurs
+ */
+ int read() throws IOException;
+
+ /**
+ * This method reads raw bytes and stores them them a byte array buffer.
+ * Note that this method will block if no data is available. However,
+ * it will not necessarily block until it fills the entire buffer. That is,
+ * a "short count" is possible.
+ *
+ * @param buf The byte array to receive the data read
+ *
+ * @return The actual number of bytes read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ int read(byte[] buf) throws IOException;
+
+ /**
+ * This method reads raw bytes and stores them in a byte array buffer
+ * <code>buf</code> starting at position <code>offset</code> into the
+ * buffer. A
+ * maximum of <code>len</code> bytes will be read. Note that this method
+ * blocks if no data is available, but will not necessarily block until
+ * it can read <code>len</code> bytes of data. That is, a "short count" is
+ * possible.
+ *
+ * @param buf The byte array to receive the data read
+ * @param offset The offset into <code>buf</code> to start storing data
+ * @param len The maximum number of bytes to read
+ *
+ * @return The actual number of bytes read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ int read(byte[] buf, int offset, int len) throws IOException;
+
+ /**
+ * Reads an object instance and returns it. If the class for the object
+ * being read cannot be found, then a <code>ClassNotFoundException</code>
+ * will be thrown.
+ *
+ * @return The object instance that was read
+ *
+ * @exception ClassNotFoundException If a class for the object cannot be
+ * found
+ * @exception IOException If any other error occurs
+ */
+ Object readObject()
+ throws ClassNotFoundException, IOException;
+
+ /**
+ * This method causes the specified number of bytes to be read and
+ * discarded. It is possible that fewer than the requested number of bytes
+ * will actually be skipped.
+ *
+ * @param numBytes The number of bytes to skip
+ *
+ * @return The actual number of bytes skipped
+ *
+ * @exception IOException If an error occurs
+ */
+ long skip(long numBytes) throws IOException;
+
+ /**
+ * This method closes the input source
+ *
+ * @exception IOException If an error occurs
+ */
+ void close() throws IOException;
+}
diff --git a/libjava/classpath/java/io/ObjectInputStream.java b/libjava/classpath/java/io/ObjectInputStream.java
new file mode 100644
index 000000000..c37f7665f
--- /dev/null
+++ b/libjava/classpath/java/io/ObjectInputStream.java
@@ -0,0 +1,2142 @@
+/* ObjectInputStream.java -- Class used to read serialized objects
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2008
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+import gnu.classpath.Pair;
+import gnu.classpath.VMStackWalker;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeSet;
+
+/**
+ * @author Tom Tromey (tromey@redhat.com)
+ * @author Jeroen Frijters (jeroen@frijters.net)
+ * @author Guilhem Lavaux (guilhem@kaffe.org)
+ * @author Michael Koch (konqueror@gmx.de)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+public class ObjectInputStream extends InputStream
+ implements ObjectInput, ObjectStreamConstants
+{
+ /**
+ * Creates a new <code>ObjectInputStream</code> that will do all of
+ * its reading from <code>in</code>. This method also checks
+ * the stream by reading the header information (stream magic number
+ * and stream version).
+ *
+ * @exception IOException Reading stream header from underlying
+ * stream cannot be completed.
+ *
+ * @exception StreamCorruptedException An invalid stream magic
+ * number or stream version was read from the stream.
+ *
+ * @see #readStreamHeader()
+ */
+ public ObjectInputStream(InputStream in)
+ throws IOException, StreamCorruptedException
+ {
+ if (DEBUG)
+ {
+ String val = System.getProperty("gcj.dumpobjects");
+ if (dump == false && val != null && !val.equals(""))
+ {
+ dump = true;
+ System.out.println ("Serialization debugging enabled");
+ }
+ else if (dump == true && (val == null || val.equals("")))
+ {
+ dump = false;
+ System.out.println ("Serialization debugging disabled");
+ }
+ }
+
+ this.resolveEnabled = false;
+ this.blockDataPosition = 0;
+ this.blockDataBytes = 0;
+ this.blockData = new byte[BUFFER_SIZE];
+ this.blockDataInput = new DataInputStream(this);
+ this.realInputStream = new DataInputStream(in);
+ this.nextOID = baseWireHandle;
+ handles = new HashMap<Integer,Pair<Boolean,Object>>();
+ this.classLookupTable = new Hashtable<Class,ObjectStreamClass>();
+ setBlockDataMode(true);
+ readStreamHeader();
+ }
+
+
+ /**
+ * Returns the next deserialized object read from the underlying stream.
+ *
+ * This method can be overriden by a class by implementing
+ * <code>private void readObject (ObjectInputStream)</code>.
+ *
+ * If an exception is thrown from this method, the stream is left in
+ * an undefined state. This method can also throw Errors and
+ * RuntimeExceptions if caused by existing readResolve() user code.
+ *
+ * @return The object read from the underlying stream.
+ *
+ * @exception ClassNotFoundException The class that an object being
+ * read in belongs to cannot be found.
+ *
+ * @exception IOException Exception from underlying
+ * <code>InputStream</code>.
+ */
+ public final Object readObject()
+ throws ClassNotFoundException, IOException
+ {
+ return readObject(true);
+ }
+
+ /**
+ * <p>
+ * Returns the next deserialized object read from the
+ * underlying stream in an unshared manner. Any object
+ * returned by this method will not be returned by
+ * subsequent calls to either this method or {@link #readObject()}.
+ * </p>
+ * <p>
+ * This behaviour is achieved by:
+ * </p>
+ * <ul>
+ * <li>Marking the handles created by successful calls to this
+ * method, so that future calls to {@link #readObject()} or
+ * {@link #readUnshared()} will throw an {@link ObjectStreamException}
+ * rather than returning the same object reference.</li>
+ * <li>Throwing an {@link ObjectStreamException} if the next
+ * element in the stream is a reference to an earlier object.</li>
+ * </ul>
+ *
+ * @return a reference to the deserialized object.
+ * @throws ClassNotFoundException if the class of the object being
+ * deserialized can not be found.
+ * @throws StreamCorruptedException if information in the stream
+ * is inconsistent.
+ * @throws ObjectStreamException if the next object has already been
+ * returned by an earlier call to this
+ * method or {@link #readObject()}.
+ * @throws OptionalDataException if primitive data occurs next in the stream.
+ * @throws IOException if an I/O error occurs from the stream.
+ * @since 1.4
+ * @see #readObject()
+ */
+ public Object readUnshared()
+ throws IOException, ClassNotFoundException
+ {
+ return readObject(false);
+ }
+
+ /**
+ * Returns the next deserialized object read from the underlying stream.
+ *
+ * This method can be overriden by a class by implementing
+ * <code>private void readObject (ObjectInputStream)</code>.
+ *
+ * If an exception is thrown from this method, the stream is left in
+ * an undefined state. This method can also throw Errors and
+ * RuntimeExceptions if caused by existing readResolve() user code.
+ *
+ * @param shared true if handles created by this call should be shared
+ * with later calls.
+ * @return The object read from the underlying stream.
+ *
+ * @exception ClassNotFoundException The class that an object being
+ * read in belongs to cannot be found.
+ *
+ * @exception IOException Exception from underlying
+ * <code>InputStream</code>.
+ */
+ private final Object readObject(boolean shared)
+ throws ClassNotFoundException, IOException
+ {
+ if (this.useSubclassMethod)
+ return readObjectOverride();
+
+ Object ret_val;
+ boolean old_mode = setBlockDataMode(false);
+ byte marker = this.realInputStream.readByte();
+
+ if (DEBUG)
+ depth += 2;
+
+ if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " ");
+
+ try
+ {
+ ret_val = parseContent(marker, shared);
+ }
+ finally
+ {
+ setBlockDataMode(old_mode);
+ if (DEBUG)
+ depth -= 2;
+ }
+
+ return ret_val;
+ }
+
+ /**
+ * Handles a content block within the stream, which begins with a marker
+ * byte indicating its type.
+ *
+ * @param marker the byte marker.
+ * @param shared true if handles created by this call should be shared
+ * with later calls.
+ * @return an object which represents the parsed content.
+ * @throws ClassNotFoundException if the class of an object being
+ * read in cannot be found.
+ * @throws IOException if invalid data occurs or one is thrown by the
+ * underlying <code>InputStream</code>.
+ */
+ private Object parseContent(byte marker, boolean shared)
+ throws ClassNotFoundException, IOException
+ {
+ Object ret_val;
+ boolean is_consumed = false;
+
+ switch (marker)
+ {
+ case TC_ENDBLOCKDATA:
+ {
+ ret_val = null;
+ is_consumed = true;
+ break;
+ }
+
+ case TC_BLOCKDATA:
+ case TC_BLOCKDATALONG:
+ {
+ if (marker == TC_BLOCKDATALONG)
+ { if(dump) dumpElementln("BLOCKDATALONG"); }
+ else
+ { if(dump) dumpElementln("BLOCKDATA"); }
+ readNextBlock(marker);
+ }
+
+ case TC_NULL:
+ {
+ if(dump) dumpElementln("NULL");
+ ret_val = null;
+ break;
+ }
+
+ case TC_REFERENCE:
+ {
+ if(dump) dumpElement("REFERENCE ");
+ int oid = realInputStream.readInt();
+ if(dump) dumpElementln(Integer.toHexString(oid));
+ ret_val = lookupHandle(oid);
+ if (!shared)
+ throw new
+ InvalidObjectException("References can not be read unshared.");
+ break;
+ }
+
+ case TC_CLASS:
+ {
+ if(dump) dumpElementln("CLASS");
+ ObjectStreamClass osc = (ObjectStreamClass)readObject();
+ Class clazz = osc.forClass();
+ assignNewHandle(clazz,shared);
+ ret_val = clazz;
+ break;
+ }
+
+ case TC_PROXYCLASSDESC:
+ {
+ if(dump) dumpElementln("PROXYCLASS");
+
+/* GCJ LOCAL */
+ // The grammar at this point is
+ // TC_PROXYCLASSDESC newHandle proxyClassDescInfo
+ // i.e. we have to assign the handle immediately after
+ // reading the marker.
+ int handle = assignNewHandle("Dummy proxy",shared);
+/* END GCJ LOCAL */
+
+ int n_intf = this.realInputStream.readInt();
+ String[] intfs = new String[n_intf];
+ for (int i = 0; i < n_intf; i++)
+ {
+ intfs[i] = this.realInputStream.readUTF();
+ }
+
+ boolean oldmode = setBlockDataMode(true);
+ Class cl = resolveProxyClass(intfs);
+ setBlockDataMode(oldmode);
+
+ ObjectStreamClass osc = lookupClass(cl);
+ if (osc.firstNonSerializableParentConstructor == null)
+ {
+ osc.realClassIsSerializable = true;
+ osc.fields = osc.fieldMapping = new ObjectStreamField[0];
+ try
+ {
+ osc.firstNonSerializableParentConstructor =
+ Object.class.getConstructor(new Class[0]);
+ }
+ catch (NoSuchMethodException x)
+ {
+ throw (InternalError)
+ new InternalError("Object ctor missing").initCause(x);
+ }
+ }
+/* GCJ LOCAL */
+ rememberHandle(osc,shared,handle);
+/* END GCJ LOCAL */
+
+ if (!is_consumed)
+ {
+ byte b = this.realInputStream.readByte();
+ if (b != TC_ENDBLOCKDATA)
+ throw new IOException("Data annotated to class was not consumed." + b);
+ }
+ else
+ is_consumed = false;
+ ObjectStreamClass superosc = (ObjectStreamClass)readObject();
+ osc.setSuperclass(superosc);
+ ret_val = osc;
+ break;
+ }
+
+ case TC_CLASSDESC:
+ {
+ ObjectStreamClass osc = readClassDescriptor();
+
+ if (!is_consumed)
+ {
+ byte b = this.realInputStream.readByte();
+ if (b != TC_ENDBLOCKDATA)
+ throw new IOException("Data annotated to class was not consumed." + b);
+ }
+ else
+ is_consumed = false;
+
+ osc.setSuperclass ((ObjectStreamClass)readObject());
+ ret_val = osc;
+ break;
+ }
+
+ case TC_STRING:
+ {
+ if(dump) dumpElement("STRING=");
+ String s = this.realInputStream.readUTF();
+ if(dump) dumpElementln(s);
+ ret_val = processResolution(null, s, assignNewHandle(s,shared),
+ shared);
+ break;
+ }
+
+ case TC_LONGSTRING:
+ {
+ if(dump) dumpElement("STRING=");
+ String s = this.realInputStream.readUTFLong();
+ if(dump) dumpElementln(s);
+ ret_val = processResolution(null, s, assignNewHandle(s,shared),
+ shared);
+ break;
+ }
+
+ case TC_ARRAY:
+ {
+ if(dump) dumpElementln("ARRAY");
+ ObjectStreamClass osc = (ObjectStreamClass)readObject();
+ Class componentType = osc.forClass().getComponentType();
+ if(dump) dumpElement("ARRAY LENGTH=");
+ int length = this.realInputStream.readInt();
+ if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType);
+ Object array = Array.newInstance(componentType, length);
+ int handle = assignNewHandle(array,shared);
+ readArrayElements(array, componentType);
+ if(dump)
+ for (int i = 0, len = Array.getLength(array); i < len; i++)
+ dumpElementln(" ELEMENT[" + i + "]=", Array.get(array, i));
+ ret_val = processResolution(null, array, handle, shared);
+ break;
+ }
+
+ case TC_OBJECT:
+ {
+ if(dump) dumpElementln("OBJECT");
+ ObjectStreamClass osc = (ObjectStreamClass)readObject();
+ Class clazz = osc.forClass();
+
+ if (!osc.realClassIsSerializable)
+ throw new NotSerializableException
+ (clazz + " is not Serializable, and thus cannot be deserialized.");
+
+ if (osc.realClassIsExternalizable)
+ {
+ Externalizable obj = osc.newInstance();
+
+ int handle = assignNewHandle(obj,shared);
+
+ boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0);
+
+ boolean oldmode = this.readDataFromBlock;
+ if (read_from_blocks)
+ setBlockDataMode(true);
+
+ obj.readExternal(this);
+
+ if (read_from_blocks)
+ {
+ setBlockDataMode(oldmode);
+ if (!oldmode)
+ if (this.realInputStream.readByte() != TC_ENDBLOCKDATA)
+ throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method.");
+ }
+
+ ret_val = processResolution(osc, obj, handle,shared);
+ break;
+
+ } // end if (osc.realClassIsExternalizable)
+
+ Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor);
+
+ int handle = assignNewHandle(obj,shared);
+ Object prevObject = this.currentObject;
+ ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
+ TreeSet<ValidatorAndPriority> prevObjectValidators =
+ this.currentObjectValidators;
+
+ this.currentObject = obj;
+ this.currentObjectValidators = null;
+ ObjectStreamClass[] hierarchy = hierarchy(clazz);
+
+ for (int i = 0; i < hierarchy.length; i++)
+ {
+ this.currentObjectStreamClass = hierarchy[i];
+ if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ());
+
+ // XXX: should initialize fields in classes in the hierarchy
+ // that aren't in the stream
+ // should skip over classes in the stream that aren't in the
+ // real classes hierarchy
+
+ Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod;
+ if (readObjectMethod != null)
+ {
+ fieldsAlreadyRead = false;
+ boolean oldmode = setBlockDataMode(true);
+ callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj);
+ setBlockDataMode(oldmode);
+ }
+ else
+ {
+ readFields(obj, currentObjectStreamClass);
+ }
+
+ if (this.currentObjectStreamClass.hasWriteMethod())
+ {
+ if(dump) dumpElement("ENDBLOCKDATA? ");
+ try
+ {
+ /* Read blocks until an end marker */
+ byte writeMarker = this.realInputStream.readByte();
+ while (writeMarker != TC_ENDBLOCKDATA)
+ {
+ parseContent(writeMarker, shared);
+ writeMarker = this.realInputStream.readByte();
+ }
+ if(dump) dumpElementln("yes");
+ }
+ catch (EOFException e)
+ {
+ throw (IOException) new IOException
+ ("No end of block data seen for class with readObject (ObjectInputStream) method.").initCause(e);
+ }
+ }
+ }
+
+ this.currentObject = prevObject;
+ this.currentObjectStreamClass = prevObjectStreamClass;
+ ret_val = processResolution(osc, obj, handle, shared);
+ if (currentObjectValidators != null)
+ invokeValidators();
+ this.currentObjectValidators = prevObjectValidators;
+
+ break;
+ }
+
+ case TC_RESET:
+ if(dump) dumpElementln("RESET");
+ clearHandles();
+ ret_val = readObject();
+ break;
+
+ case TC_EXCEPTION:
+ {
+ if(dump) dumpElement("EXCEPTION=");
+ Exception e = (Exception)readObject();
+ if(dump) dumpElementln(e.toString());
+ clearHandles();
+ throw new WriteAbortedException("Exception thrown during writing of stream", e);
+ }
+
+ case TC_ENUM:
+ {
+ /* TC_ENUM classDesc newHandle enumConstantName */
+ if (dump)
+ dumpElementln("ENUM=");
+ ObjectStreamClass osc = (ObjectStreamClass) readObject();
+ String constantName = (String) readObject();
+ if (dump)
+ dumpElementln("CONSTANT NAME = " + constantName);
+ Class clazz = osc.forClass();
+ Enum instance = Enum.valueOf(clazz, constantName);
+ assignNewHandle(instance,shared);
+ ret_val = instance;
+ break;
+ }
+
+ default:
+ throw new IOException("Unknown marker on stream: " + marker);
+ }
+ return ret_val;
+ }
+
+ /**
+ * This method makes a partial check of types for the fields
+ * contained given in arguments. It checks primitive types of
+ * fields1 against non primitive types of fields2. This method
+ * assumes the two lists has already been sorted according to
+ * the Java specification.
+ *
+ * @param name Name of the class owning the given fields.
+ * @param fields1 First list to check.
+ * @param fields2 Second list to check.
+ * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present
+ * in the non primitive part in fields2.
+ */
+ private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2)
+ throws InvalidClassException
+ {
+ int nonPrimitive = 0;
+
+ for (nonPrimitive = 0;
+ nonPrimitive < fields1.length
+ && fields1[nonPrimitive].isPrimitive(); nonPrimitive++)
+ {
+ }
+
+ if (nonPrimitive == fields1.length)
+ return;
+
+ int i = 0;
+ ObjectStreamField f1;
+ ObjectStreamField f2;
+
+ while (i < fields2.length
+ && nonPrimitive < fields1.length)
+ {
+ f1 = fields1[nonPrimitive];
+ f2 = fields2[i];
+
+ if (!f2.isPrimitive())
+ break;
+
+ int compVal = f1.getName().compareTo (f2.getName());
+
+ if (compVal < 0)
+ {
+ nonPrimitive++;
+ }
+ else if (compVal > 0)
+ {
+ i++;
+ }
+ else
+ {
+ throw new InvalidClassException
+ ("invalid field type for " + f2.getName() +
+ " in class " + name);
+ }
+ }
+ }
+
+ /**
+ * This method reads a class descriptor from the real input stream
+ * and use these data to create a new instance of ObjectStreamClass.
+ * Fields are sorted and ordered for the real read which occurs for
+ * each instance of the described class. Be aware that if you call that
+ * method you must ensure that the stream is synchronized, in the other
+ * case it may be completely desynchronized.
+ *
+ * @return A new instance of ObjectStreamClass containing the freshly
+ * created descriptor.
+ * @throws ClassNotFoundException if the required class to build the
+ * descriptor has not been found in the system.
+ * @throws IOException An input/output error occured.
+ * @throws InvalidClassException If there was a compatibility problem
+ * between the class present in the system and the serialized class.
+ */
+ protected ObjectStreamClass readClassDescriptor()
+ throws ClassNotFoundException, IOException
+ {
+ if(dump) dumpElement("CLASSDESC NAME=");
+ String name = this.realInputStream.readUTF();
+ if(dump) dumpElement(name + "; UID=");
+ long uid = this.realInputStream.readLong ();
+ if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS=");
+ byte flags = this.realInputStream.readByte ();
+ if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT=");
+ short field_count = this.realInputStream.readShort();
+ if(dump) dumpElementln(Short.toString(field_count));
+ ObjectStreamField[] fields = new ObjectStreamField[field_count];
+ ObjectStreamClass osc = new ObjectStreamClass(name, uid,
+ flags, fields);
+ assignNewHandle(osc,true);
+
+ for (int i = 0; i < field_count; i++)
+ {
+ if(dump) dumpElement(" TYPE CODE=");
+ char type_code = (char)this.realInputStream.readByte();
+ if(dump) dumpElement(type_code + "; FIELD NAME=");
+ String field_name = this.realInputStream.readUTF();
+ if(dump) dumpElementln(field_name);
+ String class_name;
+
+ // If the type code is an array or an object we must
+ // decode a String here. In the other case we convert
+ // the type code and pass it to ObjectStreamField.
+ // Type codes are decoded by gnu.java.lang.reflect.TypeSignature.
+ if (type_code == 'L' || type_code == '[')
+ class_name = (String)readObject();
+ else
+ class_name = String.valueOf(type_code);
+
+ fields[i] =
+ new ObjectStreamField(field_name, class_name);
+ }
+
+ /* Now that fields have been read we may resolve the class
+ * (and read annotation if needed). */
+ Class clazz = resolveClass(osc);
+ ClassLoader loader = clazz.getClassLoader();
+ for (int i = 0; i < field_count; i++)
+ {
+ fields[i].resolveType(loader);
+ }
+ boolean oldmode = setBlockDataMode(true);
+ osc.setClass(clazz, lookupClass(clazz.getSuperclass()));
+ classLookupTable.put(clazz, osc);
+ setBlockDataMode(oldmode);
+
+ // find the first non-serializable class in clazz's inheritance hierarchy
+ Class first_nonserial = clazz.getSuperclass();
+ // Maybe it is a primitive class, those don't have a super class,
+ // or Object itself. Otherwise we can keep getting the superclass
+ // till we hit the Object class, or some other non-serializable class.
+
+ if (first_nonserial == null)
+ first_nonserial = clazz;
+ else
+ while (Serializable.class.isAssignableFrom(first_nonserial))
+ first_nonserial = first_nonserial.getSuperclass();
+
+ final Class local_constructor_class = first_nonserial;
+
+ osc.firstNonSerializableParentConstructor =
+ (Constructor)AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ try
+ {
+ Constructor c = local_constructor_class.
+ getDeclaredConstructor(new Class[0]);
+ if (Modifier.isPrivate(c.getModifiers()))
+ return null;
+ return c;
+ }
+ catch (NoSuchMethodException e)
+ {
+ // error will be reported later, in newObject()
+ return null;
+ }
+ }
+ });
+
+ osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz);
+ osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz);
+
+ ObjectStreamField[] stream_fields = osc.fields;
+ ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields;
+ ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)];
+
+ int stream_idx = 0;
+ int real_idx = 0;
+ int map_idx = 0;
+
+ /*
+ * Check that there is no type inconsistencies between the lists.
+ * A special checking must be done for the two groups: primitive types and
+ * not primitive types.
+ */
+ checkTypeConsistency(name, real_fields, stream_fields);
+ checkTypeConsistency(name, stream_fields, real_fields);
+
+
+ while (stream_idx < stream_fields.length
+ || real_idx < real_fields.length)
+ {
+ ObjectStreamField stream_field = null;
+ ObjectStreamField real_field = null;
+
+ if (stream_idx == stream_fields.length)
+ {
+ real_field = real_fields[real_idx++];
+ }
+ else if (real_idx == real_fields.length)
+ {
+ stream_field = stream_fields[stream_idx++];
+ }
+ else
+ {
+ int comp_val =
+ real_fields[real_idx].compareTo (stream_fields[stream_idx]);
+
+ if (comp_val < 0)
+ {
+ real_field = real_fields[real_idx++];
+ }
+ else if (comp_val > 0)
+ {
+ stream_field = stream_fields[stream_idx++];
+ }
+ else
+ {
+ stream_field = stream_fields[stream_idx++];
+ real_field = real_fields[real_idx++];
+ if (stream_field.getType() != real_field.getType())
+ throw new InvalidClassException
+ ("invalid field type for " + real_field.getName() +
+ " in class " + name);
+ }
+ }
+
+ /* If some of stream_fields does not correspond to any of real_fields,
+ * or the opposite, then fieldmapping will go short.
+ */
+ if (map_idx == fieldmapping.length)
+ {
+ ObjectStreamField[] newfieldmapping =
+ new ObjectStreamField[fieldmapping.length + 2];
+ System.arraycopy(fieldmapping, 0,
+ newfieldmapping, 0, fieldmapping.length);
+ fieldmapping = newfieldmapping;
+ }
+ fieldmapping[map_idx++] = stream_field;
+ fieldmapping[map_idx++] = real_field;
+ }
+ osc.fieldMapping = fieldmapping;
+
+ return osc;
+ }
+
+ /**
+ * Reads the current objects non-transient, non-static fields from
+ * the current class from the underlying output stream.
+ *
+ * This method is intended to be called from within a object's
+ * <code>private void readObject (ObjectInputStream)</code>
+ * method.
+ *
+ * @exception ClassNotFoundException The class that an object being
+ * read in belongs to cannot be found.
+ *
+ * @exception NotActiveException This method was called from a
+ * context other than from the current object's and current class's
+ * <code>private void readObject (ObjectInputStream)</code>
+ * method.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code>.
+ */
+ public void defaultReadObject()
+ throws ClassNotFoundException, IOException, NotActiveException
+ {
+ if (this.currentObject == null || this.currentObjectStreamClass == null)
+ throw new NotActiveException("defaultReadObject called by non-active"
+ + " class and/or object");
+
+ if (fieldsAlreadyRead)
+ throw new NotActiveException("defaultReadObject called but fields "
+ + "already read from stream (by "
+ + "defaultReadObject or readFields)");
+
+ boolean oldmode = setBlockDataMode(false);
+ readFields(this.currentObject, this.currentObjectStreamClass);
+ setBlockDataMode(oldmode);
+
+ fieldsAlreadyRead = true;
+ }
+
+
+ /**
+ * Registers a <code>ObjectInputValidation</code> to be carried out
+ * on the object graph currently being deserialized before it is
+ * returned to the original caller of <code>readObject ()</code>.
+ * The order of validation for multiple
+ * <code>ObjectInputValidation</code>s can be controled using
+ * <code>priority</code>. Validators with higher priorities are
+ * called first.
+ *
+ * @see java.io.ObjectInputValidation
+ *
+ * @exception InvalidObjectException <code>validator</code> is
+ * <code>null</code>
+ *
+ * @exception NotActiveException an attempt was made to add a
+ * validator outside of the <code>readObject</code> method of the
+ * object currently being deserialized
+ */
+ public void registerValidation(ObjectInputValidation validator,
+ int priority)
+ throws InvalidObjectException, NotActiveException
+ {
+ if (this.currentObject == null || this.currentObjectStreamClass == null)
+ throw new NotActiveException("registerValidation called by non-active "
+ + "class and/or object");
+
+ if (validator == null)
+ throw new InvalidObjectException("attempt to add a null "
+ + "ObjectInputValidation object");
+
+ if (currentObjectValidators == null)
+ currentObjectValidators = new TreeSet<ValidatorAndPriority>();
+
+ currentObjectValidators.add(new ValidatorAndPriority(validator, priority));
+ }
+
+
+ /**
+ * Called when a class is being deserialized. This is a hook to
+ * allow subclasses to read in information written by the
+ * <code>annotateClass (Class)</code> method of an
+ * <code>ObjectOutputStream</code>.
+ *
+ * This implementation looks up the active call stack for a
+ * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found,
+ * it is used to load the class associated with <code>osc</code>,
+ * otherwise, the default system <code>ClassLoader</code> is used.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code>.
+ *
+ * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class)
+ */
+ protected Class<?> resolveClass(ObjectStreamClass osc)
+ throws ClassNotFoundException, IOException
+ {
+ String name = osc.getName();
+ try
+ {
+ return Class.forName(name, true, currentLoader());
+ }
+ catch(ClassNotFoundException x)
+ {
+ if (name.equals("void"))
+ return Void.TYPE;
+ else if (name.equals("boolean"))
+ return Boolean.TYPE;
+ else if (name.equals("byte"))
+ return Byte.TYPE;
+ else if (name.equals("char"))
+ return Character.TYPE;
+ else if (name.equals("short"))
+ return Short.TYPE;
+ else if (name.equals("int"))
+ return Integer.TYPE;
+ else if (name.equals("long"))
+ return Long.TYPE;
+ else if (name.equals("float"))
+ return Float.TYPE;
+ else if (name.equals("double"))
+ return Double.TYPE;
+ else
+ throw x;
+ }
+ }
+
+ /**
+ * Returns the most recent user defined ClassLoader on the execution stack
+ * or null if none is found.
+ */
+ private ClassLoader currentLoader()
+ {
+ return VMStackWalker.firstNonNullClassLoader();
+ }
+
+ /**
+ * Lookup a class stored in the local hashtable. If it is not
+ * use the global lookup function in ObjectStreamClass to build
+ * the ObjectStreamClass. This method is requested according to
+ * the behaviour detected in the JDK by Kaffe's team.
+ *
+ * @param clazz Class to lookup in the hash table or for which
+ * we must build a descriptor.
+ * @return A valid instance of ObjectStreamClass corresponding
+ * to the specified class.
+ */
+ private ObjectStreamClass lookupClass(Class clazz)
+ {
+ if (clazz == null)
+ return null;
+
+ ObjectStreamClass oclazz;
+ oclazz = classLookupTable.get(clazz);
+ if (oclazz == null)
+ return ObjectStreamClass.lookup(clazz);
+ else
+ return oclazz;
+ }
+
+ /**
+ * Reconstruct class hierarchy the same way {@link
+ * java.io.ObjectStreamClass#hierarchy} does but using lookupClass
+ * instead of ObjectStreamClass.lookup.
+ *
+ * @param clazz This is the class for which we want the hierarchy.
+ *
+ * @return An array of valid {@link java.io.ObjectStreamClass} instances which
+ * represent the class hierarchy for clazz.
+ */
+ private ObjectStreamClass[] hierarchy(Class clazz)
+ {
+ ObjectStreamClass osc = lookupClass(clazz);
+
+ return osc == null ? new ObjectStreamClass[0] : osc.hierarchy();
+ }
+
+ /**
+ * Allows subclasses to resolve objects that are read from the
+ * stream with other objects to be returned in their place. This
+ * method is called the first time each object is encountered.
+ *
+ * This method must be enabled before it will be called in the
+ * serialization process.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code>.
+ *
+ * @see #enableResolveObject(boolean)
+ */
+ protected Object resolveObject(Object obj) throws IOException
+ {
+ return obj;
+ }
+
+
+ protected Class<?> resolveProxyClass(String[] intfs)
+ throws IOException, ClassNotFoundException
+ {
+ ClassLoader cl = currentLoader();
+
+ Class<?>[] clss = new Class<?>[intfs.length];
+ if(cl == null)
+ {
+ for (int i = 0; i < intfs.length; i++)
+ clss[i] = Class.forName(intfs[i]);
+ cl = ClassLoader.getSystemClassLoader();
+ }
+ else
+ for (int i = 0; i < intfs.length; i++)
+ clss[i] = Class.forName(intfs[i], false, cl);
+ try
+ {
+ return Proxy.getProxyClass(cl, clss);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ClassNotFoundException(null, e);
+ }
+ }
+
+ /**
+ * If <code>enable</code> is <code>true</code> and this object is
+ * trusted, then <code>resolveObject (Object)</code> will be called
+ * in subsequent calls to <code>readObject (Object)</code>.
+ * Otherwise, <code>resolveObject (Object)</code> will not be called.
+ *
+ * @exception SecurityException This class is not trusted.
+ */
+ protected boolean enableResolveObject (boolean enable)
+ throws SecurityException
+ {
+ if (enable)
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPermission(new SerializablePermission("enableSubstitution"));
+ }
+
+ boolean old_val = this.resolveEnabled;
+ this.resolveEnabled = enable;
+ return old_val;
+ }
+
+ /**
+ * Reads stream magic and stream version information from the
+ * underlying stream.
+ *
+ * @exception IOException Exception from underlying stream.
+ *
+ * @exception StreamCorruptedException An invalid stream magic
+ * number or stream version was read from the stream.
+ */
+ protected void readStreamHeader()
+ throws IOException, StreamCorruptedException
+ {
+ if(dump) dumpElement("STREAM MAGIC ");
+ if (this.realInputStream.readShort() != STREAM_MAGIC)
+ throw new StreamCorruptedException("Invalid stream magic number");
+
+ if(dump) dumpElementln("STREAM VERSION ");
+ if (this.realInputStream.readShort() != STREAM_VERSION)
+ throw new StreamCorruptedException("Invalid stream version number");
+ }
+
+ public int read() throws IOException
+ {
+ if (this.readDataFromBlock)
+ {
+ if (this.blockDataPosition >= this.blockDataBytes)
+ readNextBlock();
+ return (this.blockData[this.blockDataPosition++] & 0xff);
+ }
+ else
+ return this.realInputStream.read();
+ }
+
+ public int read(byte[] data, int offset, int length) throws IOException
+ {
+ if (this.readDataFromBlock)
+ {
+ int remain = this.blockDataBytes - this.blockDataPosition;
+ if (remain == 0)
+ {
+ readNextBlock();
+ remain = this.blockDataBytes - this.blockDataPosition;
+ }
+ length = Math.min(length, remain);
+ System.arraycopy(this.blockData, this.blockDataPosition,
+ data, offset, length);
+ this.blockDataPosition += length;
+
+ return length;
+ }
+ else
+ return this.realInputStream.read(data, offset, length);
+ }
+
+ public int available() throws IOException
+ {
+ if (this.readDataFromBlock)
+ {
+ if (this.blockDataPosition >= this.blockDataBytes)
+ readNextBlock ();
+
+ return this.blockDataBytes - this.blockDataPosition;
+ }
+ else
+ return this.realInputStream.available();
+ }
+
+ public void close() throws IOException
+ {
+ this.realInputStream.close();
+ }
+
+ public boolean readBoolean() throws IOException
+ {
+ boolean switchmode = true;
+ boolean oldmode = this.readDataFromBlock;
+ if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
+ switchmode = false;
+ if (switchmode)
+ oldmode = setBlockDataMode (true);
+ boolean value = this.dataInputStream.readBoolean ();
+ if (switchmode)
+ setBlockDataMode (oldmode);
+ return value;
+ }
+
+ public byte readByte() throws IOException
+ {
+ boolean switchmode = true;
+ boolean oldmode = this.readDataFromBlock;
+ if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
+ switchmode = false;
+ if (switchmode)
+ oldmode = setBlockDataMode(true);
+ byte value = this.dataInputStream.readByte();
+ if (switchmode)
+ setBlockDataMode(oldmode);
+ return value;
+ }
+
+ public int readUnsignedByte() throws IOException
+ {
+ boolean switchmode = true;
+ boolean oldmode = this.readDataFromBlock;
+ if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1)
+ switchmode = false;
+ if (switchmode)
+ oldmode = setBlockDataMode(true);
+ int value = this.dataInputStream.readUnsignedByte();
+ if (switchmode)
+ setBlockDataMode(oldmode);
+ return value;
+ }
+
+ public short readShort() throws IOException
+ {
+ boolean switchmode = true;
+ boolean oldmode = this.readDataFromBlock;
+ if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
+ switchmode = false;
+ if (switchmode)
+ oldmode = setBlockDataMode(true);
+ short value = this.dataInputStream.readShort();
+ if (switchmode)
+ setBlockDataMode(oldmode);
+ return value;
+ }
+
+ public int readUnsignedShort() throws IOException
+ {
+ boolean switchmode = true;
+ boolean oldmode = this.readDataFromBlock;
+ if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
+ switchmode = false;
+ if (switchmode)
+ oldmode = setBlockDataMode(true);
+ int value = this.dataInputStream.readUnsignedShort();
+ if (switchmode)
+ setBlockDataMode(oldmode);
+ return value;
+ }
+
+ public char readChar() throws IOException
+ {
+ boolean switchmode = true;
+ boolean oldmode = this.readDataFromBlock;
+ if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2)
+ switchmode = false;
+ if (switchmode)
+ oldmode = setBlockDataMode(true);
+ char value = this.dataInputStream.readChar();
+ if (switchmode)
+ setBlockDataMode(oldmode);
+ return value;
+ }
+
+ public int readInt() throws IOException
+ {
+ boolean switchmode = true;
+ boolean oldmode = this.readDataFromBlock;
+ if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
+ switchmode = false;
+ if (switchmode)
+ oldmode = setBlockDataMode(true);
+ int value = this.dataInputStream.readInt();
+ if (switchmode)
+ setBlockDataMode(oldmode);
+ return value;
+ }
+
+ public long readLong() throws IOException
+ {
+ boolean switchmode = true;
+ boolean oldmode = this.readDataFromBlock;
+ if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
+ switchmode = false;
+ if (switchmode)
+ oldmode = setBlockDataMode(true);
+ long value = this.dataInputStream.readLong();
+ if (switchmode)
+ setBlockDataMode(oldmode);
+ return value;
+ }
+
+ public float readFloat() throws IOException
+ {
+ boolean switchmode = true;
+ boolean oldmode = this.readDataFromBlock;
+ if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4)
+ switchmode = false;
+ if (switchmode)
+ oldmode = setBlockDataMode(true);
+ float value = this.dataInputStream.readFloat();
+ if (switchmode)
+ setBlockDataMode(oldmode);
+ return value;
+ }
+
+ public double readDouble() throws IOException
+ {
+ boolean switchmode = true;
+ boolean oldmode = this.readDataFromBlock;
+ if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8)
+ switchmode = false;
+ if (switchmode)
+ oldmode = setBlockDataMode(true);
+ double value = this.dataInputStream.readDouble();
+ if (switchmode)
+ setBlockDataMode(oldmode);
+ return value;
+ }
+
+ public void readFully(byte data[]) throws IOException
+ {
+ this.dataInputStream.readFully(data);
+ }
+
+ public void readFully(byte data[], int offset, int size)
+ throws IOException
+ {
+ this.dataInputStream.readFully(data, offset, size);
+ }
+
+ public int skipBytes(int len) throws IOException
+ {
+ return this.dataInputStream.skipBytes(len);
+ }
+
+ /**
+ * @deprecated
+ * @see java.io.DataInputStream#readLine ()
+ */
+ public String readLine() throws IOException
+ {
+ return this.dataInputStream.readLine();
+ }
+
+ public String readUTF() throws IOException
+ {
+ return this.dataInputStream.readUTF();
+ }
+
+ /**
+ * This class allows a class to specify exactly which fields should
+ * be read, and what values should be read for these fields.
+ *
+ * XXX: finish up comments
+ */
+ public abstract static class GetField
+ {
+ public abstract ObjectStreamClass getObjectStreamClass();
+
+ public abstract boolean defaulted(String name)
+ throws IOException, IllegalArgumentException;
+
+ public abstract boolean get(String name, boolean defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract char get(String name, char defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract byte get(String name, byte defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract short get(String name, short defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract int get(String name, int defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract long get(String name, long defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract float get(String name, float defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract double get(String name, double defvalue)
+ throws IOException, IllegalArgumentException;
+
+ public abstract Object get(String name, Object defvalue)
+ throws IOException, IllegalArgumentException;
+ }
+
+ /**
+ * This method should be called by a method called 'readObject' in the
+ * deserializing class (if present). It cannot (and should not)be called
+ * outside of it. Its goal is to read all fields in the real input stream
+ * and keep them accessible through the {@link GetField} class. Calling
+ * this method will not alter the deserializing object.
+ *
+ * @return A valid freshly created 'GetField' instance to get access to
+ * the deserialized stream.
+ * @throws IOException An input/output exception occured.
+ * @throws ClassNotFoundException
+ * @throws NotActiveException
+ */
+ public GetField readFields()
+ throws IOException, ClassNotFoundException, NotActiveException
+ {
+ if (this.currentObject == null || this.currentObjectStreamClass == null)
+ throw new NotActiveException("readFields called by non-active class and/or object");
+
+ if (prereadFields != null)
+ return prereadFields;
+
+ if (fieldsAlreadyRead)
+ throw new NotActiveException("readFields called but fields already read from"
+ + " stream (by defaultReadObject or readFields)");
+
+ final ObjectStreamClass clazz = this.currentObjectStreamClass;
+ final byte[] prim_field_data = new byte[clazz.primFieldSize];
+ final Object[] objs = new Object[clazz.objectFieldCount];
+
+ // Apparently Block data is not used with GetField as per
+ // empirical evidence against JDK 1.2. Also see Mauve test
+ // java.io.ObjectInputOutput.Test.GetPutField.
+ boolean oldmode = setBlockDataMode(false);
+ readFully(prim_field_data);
+ for (int i = 0; i < objs.length; ++ i)
+ objs[i] = readObject();
+ setBlockDataMode(oldmode);
+
+ prereadFields = new GetField()
+ {
+ public ObjectStreamClass getObjectStreamClass()
+ {
+ return clazz;
+ }
+
+ public boolean defaulted(String name)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField f = clazz.getField(name);
+
+ /* First if we have a serialized field use the descriptor */
+ if (f != null)
+ {
+ /* It is in serialPersistentFields but setClass tells us
+ * it should not be set. This value is defaulted.
+ */
+ if (f.isPersistent() && !f.isToSet())
+ return true;
+
+ return false;
+ }
+
+ /* This is not a serialized field. There should be
+ * a default value only if the field really exists.
+ */
+ try
+ {
+ return (clazz.forClass().getDeclaredField (name) != null);
+ }
+ catch (NoSuchFieldException e)
+ {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public boolean get(String name, boolean defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField(name, Boolean.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ return prim_field_data[field.getOffset()] == 0 ? false : true;
+ }
+
+ public char get(String name, char defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField(name, Character.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset();
+
+ return (char)(((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF));
+ }
+
+ public byte get(String name, byte defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField(name, Byte.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ return prim_field_data[field.getOffset()];
+ }
+
+ public short get(String name, short defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField(name, Short.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset();
+
+ return (short)(((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF));
+ }
+
+ public int get(String name, int defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField(name, Integer.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset();
+
+ return ((prim_field_data[off++] & 0xFF) << 24)
+ | ((prim_field_data[off++] & 0xFF) << 16)
+ | ((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF);
+ }
+
+ public long get(String name, long defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField(name, Long.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset();
+
+ return (long)(((prim_field_data[off++] & 0xFFL) << 56)
+ | ((prim_field_data[off++] & 0xFFL) << 48)
+ | ((prim_field_data[off++] & 0xFFL) << 40)
+ | ((prim_field_data[off++] & 0xFFL) << 32)
+ | ((prim_field_data[off++] & 0xFF) << 24)
+ | ((prim_field_data[off++] & 0xFF) << 16)
+ | ((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF));
+ }
+
+ public float get(String name, float defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField(name, Float.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset();
+
+ return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24)
+ | ((prim_field_data[off++] & 0xFF) << 16)
+ | ((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF));
+ }
+
+ public double get(String name, double defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field = getField(name, Double.TYPE);
+
+ if (field == null)
+ return defvalue;
+
+ int off = field.getOffset();
+
+ return Double.longBitsToDouble
+ ( (long) (((prim_field_data[off++] & 0xFFL) << 56)
+ | ((prim_field_data[off++] & 0xFFL) << 48)
+ | ((prim_field_data[off++] & 0xFFL) << 40)
+ | ((prim_field_data[off++] & 0xFFL) << 32)
+ | ((prim_field_data[off++] & 0xFF) << 24)
+ | ((prim_field_data[off++] & 0xFF) << 16)
+ | ((prim_field_data[off++] & 0xFF) << 8)
+ | (prim_field_data[off] & 0xFF)));
+ }
+
+ public Object get(String name, Object defvalue)
+ throws IOException, IllegalArgumentException
+ {
+ ObjectStreamField field =
+ getField(name, defvalue == null ? null : defvalue.getClass ());
+
+ if (field == null)
+ return defvalue;
+
+ return objs[field.getOffset()];
+ }
+
+ private ObjectStreamField getField(String name, Class type)
+ throws IllegalArgumentException
+ {
+ ObjectStreamField field = clazz.getField(name);
+ boolean illegal = false;
+
+ // XXX This code is horrible and needs to be rewritten!
+ try
+ {
+ try
+ {
+ Class field_type = field.getType();
+
+ if (type == field_type ||
+ (type == null && !field_type.isPrimitive()))
+ {
+ /* See defaulted */
+ return field;
+ }
+
+ illegal = true;
+ throw new IllegalArgumentException
+ ("Field requested is of type "
+ + field_type.getName()
+ + ", but requested type was "
+ + (type == null ? "Object" : type.getName()));
+ }
+ catch (NullPointerException _)
+ {
+ /* Here we catch NullPointerException, because it may
+ only come from the call 'field.getType()'. If field
+ is null, we have to return null and classpath ethic
+ say we must try to avoid 'if (xxx == null)'.
+ */
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw e;
+ }
+
+ return null;
+ }
+ finally
+ {
+ /* If this is an unassigned field we should return
+ * the default value.
+ */
+ if (!illegal && field != null && !field.isToSet() && field.isPersistent())
+ return null;
+
+ /* We do not want to modify transient fields. They should
+ * be left to 0.
+ */
+ try
+ {
+ Field f = clazz.forClass().getDeclaredField(name);
+ if (Modifier.isTransient(f.getModifiers()))
+ throw new IllegalArgumentException
+ ("no such field (non transient) " + name);
+ if (field == null && f.getType() != type)
+ throw new IllegalArgumentException
+ ("Invalid requested type for field " + name);
+ }
+ catch (NoSuchFieldException e)
+ {
+ if (field == null)
+ throw new IllegalArgumentException(e);
+ }
+
+ }
+ }
+ };
+
+ fieldsAlreadyRead = true;
+ return prereadFields;
+ }
+
+ /**
+ * Protected constructor that allows subclasses to override
+ * deserialization. This constructor should be called by subclasses
+ * that wish to override <code>readObject (Object)</code>. This
+ * method does a security check <i>NOTE: currently not
+ * implemented</i>, then sets a flag that informs
+ * <code>readObject (Object)</code> to call the subclasses
+ * <code>readObjectOverride (Object)</code> method.
+ *
+ * @see #readObjectOverride()
+ */
+ protected ObjectInputStream()
+ throws IOException, SecurityException
+ {
+ SecurityManager sec_man = System.getSecurityManager();
+ if (sec_man != null)
+ sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
+ this.useSubclassMethod = true;
+ }
+
+ /**
+ * This method allows subclasses to override the default
+ * de serialization mechanism provided by
+ * <code>ObjectInputStream</code>. To make this method be used for
+ * writing objects, subclasses must invoke the 0-argument
+ * constructor on this class from their constructor.
+ *
+ * @see #ObjectInputStream()
+ */
+ protected Object readObjectOverride()
+ throws ClassNotFoundException, IOException, OptionalDataException
+ {
+ throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride");
+ }
+
+ /**
+ * Assigns the next available handle to <code>obj</code>.
+ *
+ * @param obj The object for which we want a new handle.
+ * @param shared True if the handle should be shared
+ * with later calls.
+ * @return A valid handle for the specified object.
+ */
+ private int assignNewHandle(Object obj, boolean shared)
+ {
+ int handle = this.nextOID;
+ this.nextOID = handle + 1;
+ rememberHandle(obj,shared,handle);
+ return handle;
+ }
+
+ /**
+ * Remember the object associated with the given handle.
+ *
+ * @param obj an object
+ * @param shared true if the reference should be shared
+ * with later calls.
+ * @param handle a handle, must be >= baseWireHandle
+ *
+ * @see #lookupHandle
+ */
+ private void rememberHandle(Object obj, boolean shared,
+ int handle)
+ {
+ handles.put(handle, new Pair<Boolean,Object>(shared, obj));
+ }
+
+ /**
+ * Look up the object associated with a given handle.
+ *
+ * @param handle a handle, must be >= baseWireHandle
+ * @return the object remembered for handle or null if none.
+ * @throws StreamCorruptedException if the handle is invalid.
+ * @throws InvalidObjectException if the reference is not shared.
+ * @see #rememberHandle
+ */
+ private Object lookupHandle(int handle)
+ throws ObjectStreamException
+ {
+ Pair<Boolean,Object> result = handles.get(handle);
+ if (result == null)
+ throw new StreamCorruptedException("The handle, " +
+ Integer.toHexString(handle) +
+ ", is invalid.");
+ if (!result.getLeft())
+ throw new InvalidObjectException("The handle, " +
+ Integer.toHexString(handle) +
+ ", is not shared.");
+ return result.getRight();
+ }
+
+ private Object processResolution(ObjectStreamClass osc, Object obj, int handle,
+ boolean shared)
+ throws IOException
+ {
+ if (osc != null && obj instanceof Serializable)
+ {
+ try
+ {
+ Method m = osc.readResolveMethod;
+ if(m != null)
+ {
+ obj = m.invoke(obj, new Object[] {});
+ }
+ }
+ catch (IllegalAccessException ignore)
+ {
+ }
+ catch (InvocationTargetException exception)
+ {
+ Throwable cause = exception.getCause();
+ if (cause instanceof ObjectStreamException)
+ throw (ObjectStreamException) cause;
+ else if (cause instanceof RuntimeException)
+ throw (RuntimeException) cause;
+ else if (cause instanceof Error)
+ throw (Error) cause;
+ }
+ }
+
+ if (this.resolveEnabled)
+ obj = resolveObject(obj);
+
+ rememberHandle(obj, shared, handle);
+ if (!shared)
+ {
+ if (obj instanceof byte[])
+ return ((byte[]) obj).clone();
+ if (obj instanceof short[])
+ return ((short[]) obj).clone();
+ if (obj instanceof int[])
+ return ((int[]) obj).clone();
+ if (obj instanceof long[])
+ return ((long[]) obj).clone();
+ if (obj instanceof char[])
+ return ((char[]) obj).clone();
+ if (obj instanceof boolean[])
+ return ((boolean[]) obj).clone();
+ if (obj instanceof float[])
+ return ((float[]) obj).clone();
+ if (obj instanceof double[])
+ return ((double[]) obj).clone();
+ if (obj instanceof Object[])
+ return ((Object[]) obj).clone();
+ }
+ return obj;
+ }
+
+ private void clearHandles()
+ {
+ handles.clear();
+ this.nextOID = baseWireHandle;
+ }
+
+ private void readNextBlock() throws IOException
+ {
+ byte marker = this.realInputStream.readByte();
+ while (marker == TC_RESET)
+ {
+ if(dump) dumpElementln("RESET");
+ clearHandles();
+ marker = this.realInputStream.readByte();
+ }
+ readNextBlock(marker);
+ }
+
+ private void readNextBlock(byte marker) throws IOException
+ {
+ if (marker == TC_BLOCKDATA)
+ {
+ if(dump) dumpElement("BLOCK DATA SIZE=");
+ this.blockDataBytes = this.realInputStream.readUnsignedByte();
+ if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
+ }
+ else if (marker == TC_BLOCKDATALONG)
+ {
+ if(dump) dumpElement("BLOCK DATA LONG SIZE=");
+ this.blockDataBytes = this.realInputStream.readInt();
+ if(dump) dumpElementln (Integer.toString(this.blockDataBytes));
+ }
+ else
+ {
+ throw new EOFException("Attempt to read primitive data, but no data block is active.");
+ }
+
+ if (this.blockData.length < this.blockDataBytes)
+ this.blockData = new byte[this.blockDataBytes];
+
+ this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes);
+ this.blockDataPosition = 0;
+ }
+
+ private void readArrayElements (Object array, Class clazz)
+ throws ClassNotFoundException, IOException
+ {
+ if (clazz.isPrimitive())
+ {
+ if (clazz == Boolean.TYPE)
+ {
+ boolean[] cast_array = (boolean[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readBoolean();
+ return;
+ }
+ if (clazz == Byte.TYPE)
+ {
+ byte[] cast_array = (byte[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readByte();
+ return;
+ }
+ if (clazz == Character.TYPE)
+ {
+ char[] cast_array = (char[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readChar();
+ return;
+ }
+ if (clazz == Double.TYPE)
+ {
+ double[] cast_array = (double[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readDouble();
+ return;
+ }
+ if (clazz == Float.TYPE)
+ {
+ float[] cast_array = (float[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readFloat();
+ return;
+ }
+ if (clazz == Integer.TYPE)
+ {
+ int[] cast_array = (int[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readInt();
+ return;
+ }
+ if (clazz == Long.TYPE)
+ {
+ long[] cast_array = (long[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readLong();
+ return;
+ }
+ if (clazz == Short.TYPE)
+ {
+ short[] cast_array = (short[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = this.realInputStream.readShort();
+ return;
+ }
+ }
+ else
+ {
+ Object[] cast_array = (Object[])array;
+ for (int i=0; i < cast_array.length; i++)
+ cast_array[i] = readObject();
+ }
+ }
+
+ private void readFields (Object obj, ObjectStreamClass stream_osc)
+ throws ClassNotFoundException, IOException
+ {
+ ObjectStreamField[] fields = stream_osc.fieldMapping;
+
+ for (int i = 0; i < fields.length; i += 2)
+ {
+ ObjectStreamField stream_field = fields[i];
+ ObjectStreamField real_field = fields[i + 1];
+ boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet());
+ boolean set_value = (real_field != null && real_field.isToSet());
+ String field_name;
+ char type;
+
+ if (stream_field != null)
+ {
+ field_name = stream_field.getName();
+ type = stream_field.getTypeCode();
+ }
+ else
+ {
+ field_name = real_field.getName();
+ type = real_field.getTypeCode();
+ }
+
+ switch(type)
+ {
+ case 'Z':
+ {
+ boolean value =
+ read_value ? this.realInputStream.readBoolean() : false;
+ if (dump && read_value && set_value)
+ dumpElementln(" " + field_name + ": " + value);
+ if (set_value)
+ real_field.setBooleanField(obj, value);
+ break;
+ }
+ case 'B':
+ {
+ byte value =
+ read_value ? this.realInputStream.readByte() : 0;
+ if (dump && read_value && set_value)
+ dumpElementln(" " + field_name + ": " + value);
+ if (set_value)
+ real_field.setByteField(obj, value);
+ break;
+ }
+ case 'C':
+ {
+ char value =
+ read_value ? this.realInputStream.readChar(): 0;
+ if (dump && read_value && set_value)
+ dumpElementln(" " + field_name + ": " + value);
+ if (set_value)
+ real_field.setCharField(obj, value);
+ break;
+ }
+ case 'D':
+ {
+ double value =
+ read_value ? this.realInputStream.readDouble() : 0;
+ if (dump && read_value && set_value)
+ dumpElementln(" " + field_name + ": " + value);
+ if (set_value)
+ real_field.setDoubleField(obj, value);
+ break;
+ }
+ case 'F':
+ {
+ float value =
+ read_value ? this.realInputStream.readFloat() : 0;
+ if (dump && read_value && set_value)
+ dumpElementln(" " + field_name + ": " + value);
+ if (set_value)
+ real_field.setFloatField(obj, value);
+ break;
+ }
+ case 'I':
+ {
+ int value =
+ read_value ? this.realInputStream.readInt() : 0;
+ if (dump && read_value && set_value)
+ dumpElementln(" " + field_name + ": " + value);
+ if (set_value)
+ real_field.setIntField(obj, value);
+ break;
+ }
+ case 'J':
+ {
+ long value =
+ read_value ? this.realInputStream.readLong() : 0;
+ if (dump && read_value && set_value)
+ dumpElementln(" " + field_name + ": " + value);
+ if (set_value)
+ real_field.setLongField(obj, value);
+ break;
+ }
+ case 'S':
+ {
+ short value =
+ read_value ? this.realInputStream.readShort() : 0;
+ if (dump && read_value && set_value)
+ dumpElementln(" " + field_name + ": " + value);
+ if (set_value)
+ real_field.setShortField(obj, value);
+ break;
+ }
+ case 'L':
+ case '[':
+ {
+ Object value =
+ read_value ? readObject() : null;
+ if (set_value)
+ real_field.setObjectField(obj, value);
+ break;
+ }
+ default:
+ throw new InternalError("Invalid type code: " + type);
+ }
+ }
+ }
+
+ // Toggles writing primitive data to block-data buffer.
+ private boolean setBlockDataMode (boolean on)
+ {
+ boolean oldmode = this.readDataFromBlock;
+ this.readDataFromBlock = on;
+
+ if (on)
+ this.dataInputStream = this.blockDataInput;
+ else
+ this.dataInputStream = this.realInputStream;
+ return oldmode;
+ }
+
+ // returns a new instance of REAL_CLASS that has been constructed
+ // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS)
+ private Object newObject (Class real_class, Constructor constructor)
+ throws ClassNotFoundException, IOException
+ {
+ if (constructor == null)
+ throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName());
+ try
+ {
+ return VMObjectInputStream.allocateObject(real_class, constructor.getDeclaringClass(), constructor);
+ }
+ catch (InstantiationException e)
+ {
+ throw (ClassNotFoundException) new ClassNotFoundException
+ ("Instance of " + real_class + " could not be created").initCause(e);
+ }
+ }
+
+ // runs all registered ObjectInputValidations in prioritized order
+ // on OBJ
+ private void invokeValidators() throws InvalidObjectException
+ {
+ try
+ {
+ Iterator<ValidatorAndPriority> it = currentObjectValidators.iterator();
+ while(it.hasNext())
+ {
+ ValidatorAndPriority vap = it.next();
+ ObjectInputValidation validator = vap.validator;
+ validator.validateObject();
+ }
+ }
+ finally
+ {
+ currentObjectValidators = null;
+ }
+ }
+
+ private void callReadMethod (Method readObject, Class klass, Object obj)
+ throws ClassNotFoundException, IOException
+ {
+ try
+ {
+ readObject.invoke(obj, new Object[] { this });
+ }
+ catch (InvocationTargetException x)
+ {
+ /* Rethrow if possible. */
+ Throwable exception = x.getTargetException();
+ if (exception instanceof RuntimeException)
+ throw (RuntimeException) exception;
+ if (exception instanceof IOException)
+ throw (IOException) exception;
+ if (exception instanceof ClassNotFoundException)
+ throw (ClassNotFoundException) exception;
+
+ throw (IOException) new IOException(
+ "Exception thrown from readObject() on " + klass).initCause(x);
+ }
+ catch (Exception x)
+ {
+ throw (IOException) new IOException(
+ "Failure invoking readObject() on " + klass).initCause(x);
+ }
+
+ // Invalidate fields which has been read through readFields.
+ prereadFields = null;
+ }
+
+ private static final int BUFFER_SIZE = 1024;
+
+ private DataInputStream realInputStream;
+ private DataInputStream dataInputStream;
+ private DataInputStream blockDataInput;
+ private int blockDataPosition;
+ private int blockDataBytes;
+ private byte[] blockData;
+ private boolean useSubclassMethod;
+ private int nextOID;
+ private boolean resolveEnabled;
+ private Map<Integer,Pair<Boolean,Object>> handles;
+ private Object currentObject;
+ private ObjectStreamClass currentObjectStreamClass;
+ private TreeSet<ValidatorAndPriority> currentObjectValidators;
+ private boolean readDataFromBlock;
+ private boolean fieldsAlreadyRead;
+ private Hashtable<Class,ObjectStreamClass> classLookupTable;
+ private GetField prereadFields;
+
+ private static boolean dump;
+
+ // The nesting depth for debugging output
+ private int depth = 0;
+
+ private static final boolean DEBUG = false;
+
+ private void dumpElement (String msg)
+ {
+ System.out.print(msg);
+ }
+
+ private void dumpElementln (String msg)
+ {
+ System.out.println(msg);
+ for (int i = 0; i < depth; i++)
+ System.out.print (" ");
+ System.out.print (Thread.currentThread() + ": ");
+ }
+
+ private void dumpElementln (String msg, Object obj)
+ {
+ try
+ {
+ System.out.print(msg);
+ if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
+ System.out.println(obj.getClass());
+ else
+ System.out.println(obj);
+ }
+ catch (Exception _)
+ {
+ }
+ for (int i = 0; i < depth; i++)
+ System.out.print (" ");
+ System.out.print (Thread.currentThread() + ": ");
+ }
+
+ // used to keep a prioritized list of object validators
+ private static final class ValidatorAndPriority implements Comparable
+ {
+ int priority;
+ ObjectInputValidation validator;
+
+ ValidatorAndPriority (ObjectInputValidation validator, int priority)
+ {
+ this.priority = priority;
+ this.validator = validator;
+ }
+
+ public int compareTo (Object o)
+ {
+ ValidatorAndPriority vap = (ValidatorAndPriority)o;
+ return this.priority - vap.priority;
+ }
+ }
+}
diff --git a/libjava/classpath/java/io/ObjectInputValidation.java b/libjava/classpath/java/io/ObjectInputValidation.java
new file mode 100644
index 000000000..fb6de1905
--- /dev/null
+++ b/libjava/classpath/java/io/ObjectInputValidation.java
@@ -0,0 +1,67 @@
+/* ObjectInputValidation.java -- Validate an object
+ Copyright (C) 1998, 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 java.io;
+
+/**
+ * This class allows an object to validate that it is valid after
+ * deserialization has run completely for it and all dependent objects.
+ * This allows an object to determine if it is invalid even if all
+ * state data was correctly deserialized from the stream. It can also
+ * be used to perform re-initialization type activities on an object
+ * after it has been completely deserialized.
+ *
+ * Since this method functions as a type of callback, it must be
+ * registered through <code>ObjectInputStream.registerValidation</code>
+ * in order to be invoked. This is typically done in the
+ * <code>readObject</code> method.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ *
+ * @see ObjectInputStream#registerValidation
+ */
+public interface ObjectInputValidation
+{
+ /**
+ * This method is called to validate an object after serialization
+ * is complete. If the object is invalid an exception is thrown.
+ *
+ * @exception InvalidObjectException If the object is invalid
+ */
+ void validateObject() throws InvalidObjectException;
+}
diff --git a/libjava/classpath/java/io/ObjectOutput.java b/libjava/classpath/java/io/ObjectOutput.java
new file mode 100644
index 000000000..628f8b97b
--- /dev/null
+++ b/libjava/classpath/java/io/ObjectOutput.java
@@ -0,0 +1,110 @@
+/* ObjectOutput.java -- Interface for writing objects to a stream
+ Copyright (C) 1998, 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 java.io;
+
+/**
+ * This interface extends <code>DataOutput</code> to provide the additional
+ * facility of writing object instances to a stream. It also adds some
+ * additional methods to make the interface more
+ * <code>OutputStream</code> like.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ *
+ * @see DataOutput
+ */
+public interface ObjectOutput extends DataOutput
+{
+ /**
+ * This method writes the specified byte to the output stream.
+ *
+ * @param b The byte to write.
+ *
+ * @exception IOException If an error occurs.
+ */
+ void write(int b) throws IOException;
+
+ /**
+ * This method writes all the bytes in the specified byte array to the
+ * output stream.
+ *
+ * @param buf The array of bytes to write.
+ *
+ * @exception IOException If an error occurs.
+ */
+ void write(byte[] buf) throws IOException;
+
+ /**
+ * This method writes <code>len</code> bytes from the specified array
+ * starting at index <code>offset</code> into that array.
+ *
+ * @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;
+
+ /**
+ * This method writes a object instance to a stream. The format of the
+ * data written is determined by the actual implementation of this method
+ *
+ * @param obj The object to write
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeObject(Object obj) throws IOException;
+
+ /**
+ * This method causes any buffered data to be flushed out to the underlying
+ * stream
+ *
+ * @exception IOException If an error occurs
+ */
+ void flush() throws IOException;
+
+ /**
+ * This method closes the underlying stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ void close() throws IOException;
+
+} // interface ObjectOutput
diff --git a/libjava/classpath/java/io/ObjectOutputStream.java b/libjava/classpath/java/io/ObjectOutputStream.java
new file mode 100644
index 000000000..71d2e0b34
--- /dev/null
+++ b/libjava/classpath/java/io/ObjectOutputStream.java
@@ -0,0 +1,1490 @@
+/* ObjectOutputStream.java -- Class used to write serialized objects
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+import gnu.java.io.ObjectIdentityMap2Int;
+import gnu.java.lang.reflect.TypeSignature;
+import gnu.java.security.action.SetAccessibleAction;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+
+/**
+ * An <code>ObjectOutputStream</code> can be used to write objects
+ * as well as primitive data in a platform-independent manner to an
+ * <code>OutputStream</code>.
+ *
+ * The data produced by an <code>ObjectOutputStream</code> can be read
+ * and reconstituted by an <code>ObjectInputStream</code>.
+ *
+ * <code>writeObject (Object)</code> is used to write Objects, the
+ * <code>write&lt;type&gt;</code> methods are used to write primitive
+ * data (as in <code>DataOutputStream</code>). Strings can be written
+ * as objects or as primitive data.
+ *
+ * Not all objects can be written out using an
+ * <code>ObjectOutputStream</code>. Only those objects that are an
+ * instance of <code>java.io.Serializable</code> can be written.
+ *
+ * Using default serialization, information about the class of an
+ * object is written, all of the non-transient, non-static fields of
+ * the object are written, if any of these fields are objects, they are
+ * written out in the same manner.
+ *
+ * An object is only written out the first time it is encountered. If
+ * the object is encountered later, a reference to it is written to
+ * the underlying stream. Thus writing circular object graphs
+ * does not present a problem, nor are relationships between objects
+ * in a graph lost.
+ *
+ * Example usage:
+ * <pre>
+ * Hashtable map = new Hashtable ();
+ * map.put ("one", new Integer (1));
+ * map.put ("two", new Integer (2));
+ *
+ * ObjectOutputStream oos =
+ * new ObjectOutputStream (new FileOutputStream ("numbers"));
+ * oos.writeObject (map);
+ * oos.close ();
+ *
+ * ObjectInputStream ois =
+ * new ObjectInputStream (new FileInputStream ("numbers"));
+ * Hashtable newmap = (Hashtable)ois.readObject ();
+ *
+ * System.out.println (newmap);
+ * </pre>
+ *
+ * The default serialization can be overriden in two ways.
+ *
+ * By defining a method <code>private void
+ * writeObject (ObjectOutputStream)</code>, a class can dictate exactly
+ * how information about itself is written.
+ * <code>defaultWriteObject ()</code> may be called from this method to
+ * carry out default serialization. This method is not
+ * responsible for dealing with fields of super-classes or subclasses.
+ *
+ * By implementing <code>java.io.Externalizable</code>. This gives
+ * the class complete control over the way it is written to the
+ * stream. If this approach is used the burden of writing superclass
+ * and subclass data is transfered to the class implementing
+ * <code>java.io.Externalizable</code>.
+ *
+ * @see java.io.DataOutputStream
+ * @see java.io.Externalizable
+ * @see java.io.ObjectInputStream
+ * @see java.io.Serializable
+ * @author Tom Tromey (tromey@redhat.com)
+ * @author Jeroen Frijters (jeroen@frijters.net)
+ * @author Guilhem Lavaux (guilhem@kaffe.org)
+ * @author Michael Koch (konqueror@gmx.de)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+public class ObjectOutputStream extends OutputStream
+ implements ObjectOutput, ObjectStreamConstants
+{
+ /**
+ * Creates a new <code>ObjectOutputStream</code> that will do all of
+ * its writing onto <code>out</code>. This method also initializes
+ * the stream by writing the header information (stream magic number
+ * and stream version).
+ *
+ * @exception IOException Writing stream header to underlying
+ * stream cannot be completed.
+ *
+ * @see #writeStreamHeader()
+ */
+ public ObjectOutputStream (OutputStream out) throws IOException
+ {
+ realOutput = new DataOutputStream(out);
+ blockData = new byte[ BUFFER_SIZE ];
+ blockDataCount = 0;
+ blockDataOutput = new DataOutputStream(this);
+ setBlockDataMode(true);
+ replacementEnabled = false;
+ isSerializing = false;
+ nextOID = baseWireHandle;
+ OIDLookupTable = new ObjectIdentityMap2Int();
+ protocolVersion = defaultProtocolVersion;
+ useSubclassMethod = false;
+ writeStreamHeader();
+
+ if (DEBUG)
+ {
+ String val = System.getProperty("gcj.dumpobjects");
+ if (val != null && !val.equals(""))
+ dump = true;
+ }
+ }
+
+ /**
+ * Writes a representation of <code>obj</code> to the underlying
+ * output stream by writing out information about its class, then
+ * writing out each of the objects non-transient, non-static
+ * fields. If any of these fields are other objects,
+ * they are written out in the same manner.
+ *
+ * This method can be overriden by a class by implementing
+ * <code>private void writeObject (ObjectOutputStream)</code>.
+ *
+ * If an exception is thrown from this method, the stream is left in
+ * an undefined state.
+ *
+ * @param obj the object to serialize.
+ * @exception NotSerializableException An attempt was made to
+ * serialize an <code>Object</code> that is not serializable.
+ *
+ * @exception InvalidClassException Somebody tried to serialize
+ * an object which is wrongly formatted.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code>.
+ * @see #writeUnshared(Object)
+ */
+ public final void writeObject(Object obj) throws IOException
+ {
+ writeObject(obj, true);
+ }
+
+ /**
+ * Writes an object to the stream in the same manner as
+ * {@link #writeObject(Object)}, but without the use of
+ * references. As a result, the object is always written
+ * to the stream in full. Likewise, if an object is written
+ * by this method and is then later written again by
+ * {@link #writeObject(Object)}, both calls will write out
+ * the object in full, as the later call to
+ * {@link #writeObject(Object)} will know nothing of the
+ * earlier use of {@link #writeUnshared(Object)}.
+ *
+ * @param obj the object to serialize.
+ * @throws NotSerializableException if the object being
+ * serialized does not implement
+ * {@link Serializable}.
+ * @throws InvalidClassException if a problem occurs with
+ * the class of the object being
+ * serialized.
+ * @throws IOException if an I/O error occurs on the underlying
+ * <code>OutputStream</code>.
+ * @since 1.4
+ * @see #writeObject(Object)
+ */
+ public void writeUnshared(Object obj)
+ throws IOException
+ {
+ writeObject(obj, false);
+ }
+
+ /**
+ * Writes a representation of <code>obj</code> to the underlying
+ * output stream by writing out information about its class, then
+ * writing out each of the objects non-transient, non-static
+ * fields. If any of these fields are other objects,
+ * they are written out in the same manner.
+ *
+ * This method can be overriden by a class by implementing
+ * <code>private void writeObject (ObjectOutputStream)</code>.
+ *
+ * If an exception is thrown from this method, the stream is left in
+ * an undefined state.
+ *
+ * @param obj the object to serialize.
+ * @param shared true if the serialized object should be
+ * shared with later calls.
+ * @exception NotSerializableException An attempt was made to
+ * serialize an <code>Object</code> that is not serializable.
+ *
+ * @exception InvalidClassException Somebody tried to serialize
+ * an object which is wrongly formatted.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code>.
+ * @see #writeUnshared(Object)
+ */
+ private final void writeObject(Object obj, boolean shared)
+ throws IOException
+ {
+ if (useSubclassMethod)
+ {
+ if (dump)
+ dumpElementln ("WRITE OVERRIDE: " + obj);
+
+ writeObjectOverride(obj);
+ return;
+ }
+
+ if (dump)
+ dumpElementln ("WRITE: ", obj);
+
+ depth += 2;
+
+ boolean was_serializing = isSerializing;
+ boolean old_mode = setBlockDataMode(false);
+ try
+ {
+ isSerializing = true;
+ boolean replaceDone = false;
+ Object replacedObject = null;
+
+ while (true)
+ {
+ if (obj == null)
+ {
+ realOutput.writeByte(TC_NULL);
+ break;
+ }
+
+ int handle = findHandle(obj);
+ if (handle >= 0 && shared)
+ {
+ realOutput.writeByte(TC_REFERENCE);
+ realOutput.writeInt(handle);
+ break;
+ }
+
+ if (obj instanceof Class)
+ {
+ Class cl = (Class)obj;
+ ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(cl);
+ realOutput.writeByte(TC_CLASS);
+ if (!osc.isProxyClass)
+ {
+ writeObject (osc);
+ }
+ else
+ {System.err.println("1");
+ realOutput.writeByte(TC_PROXYCLASSDESC);
+ Class[] intfs = cl.getInterfaces();
+ realOutput.writeInt(intfs.length);
+ for (int i = 0; i < intfs.length; i++)
+ realOutput.writeUTF(intfs[i].getName());
+
+ boolean oldmode = setBlockDataMode(true);
+ annotateProxyClass(cl);
+ setBlockDataMode(oldmode);
+ realOutput.writeByte(TC_ENDBLOCKDATA);
+
+ writeObject(osc.getSuper());
+ }
+ if (shared)
+ assignNewHandle(obj);
+ break;
+ }
+
+ if (obj instanceof ObjectStreamClass)
+ {
+ writeClassDescriptor((ObjectStreamClass) obj);
+ break;
+ }
+
+ Class clazz = obj.getClass();
+ ObjectStreamClass osc = ObjectStreamClass.lookupForClassObject(clazz);
+ if (osc == null)
+ throw new NotSerializableException(clazz.getName());
+
+ if (osc.isEnum())
+ {
+ /* TC_ENUM classDesc newHandle enumConstantName */
+ realOutput.writeByte(TC_ENUM);
+ writeObject(osc);
+ if (shared)
+ assignNewHandle(obj);
+ writeObject(((Enum) obj).name());
+ break;
+ }
+
+ if ((replacementEnabled || obj instanceof Serializable)
+ && ! replaceDone)
+ {
+ replacedObject = obj;
+
+ if (obj instanceof Serializable)
+ {
+ try
+ {
+ Method m = osc.writeReplaceMethod;
+ if (m != null)
+ obj = m.invoke(obj, new Object[0]);
+ }
+ catch (IllegalAccessException ignore)
+ {
+ }
+ catch (InvocationTargetException ignore)
+ {
+ }
+ }
+
+ if (replacementEnabled)
+ obj = replaceObject(obj);
+
+ replaceDone = true;
+ continue;
+ }
+
+ if (obj instanceof String)
+ {
+ String s = (String)obj;
+ long l = realOutput.getUTFlength(s, 0, 0);
+ if (l <= 65535)
+ {
+ realOutput.writeByte(TC_STRING);
+ if (shared)
+ assignNewHandle(obj);
+ realOutput.writeUTFShort(s, (int)l);
+ }
+ else
+ {
+ realOutput.writeByte(TC_LONGSTRING);
+ if (shared)
+ assignNewHandle(obj);
+ realOutput.writeUTFLong(s, l);
+ }
+ break;
+ }
+
+ if (clazz.isArray ())
+ {
+ realOutput.writeByte(TC_ARRAY);
+ writeObject(osc);
+ if (shared)
+ assignNewHandle(obj);
+ writeArraySizeAndElements(obj, clazz.getComponentType());
+ break;
+ }
+
+ realOutput.writeByte(TC_OBJECT);
+ writeObject(osc);
+
+ if (shared)
+ if (replaceDone)
+ assignNewHandle(replacedObject);
+ else
+ assignNewHandle(obj);
+
+ if (obj instanceof Externalizable)
+ {
+ if (protocolVersion == PROTOCOL_VERSION_2)
+ setBlockDataMode(true);
+
+ ((Externalizable)obj).writeExternal(this);
+
+ if (protocolVersion == PROTOCOL_VERSION_2)
+ {
+ setBlockDataMode(false);
+ realOutput.writeByte(TC_ENDBLOCKDATA);
+ }
+
+ break;
+ }
+
+ if (obj instanceof Serializable)
+ {
+ Object prevObject = this.currentObject;
+ ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass;
+ currentObject = obj;
+ ObjectStreamClass[] hierarchy = osc.hierarchy();
+
+ for (int i = 0; i < hierarchy.length; i++)
+ {
+ currentObjectStreamClass = hierarchy[i];
+
+ fieldsAlreadyWritten = false;
+ if (currentObjectStreamClass.hasWriteMethod())
+ {
+ if (dump)
+ dumpElementln ("WRITE METHOD CALLED FOR: ", obj);
+ setBlockDataMode(true);
+ callWriteMethod(obj, currentObjectStreamClass);
+ setBlockDataMode(false);
+ realOutput.writeByte(TC_ENDBLOCKDATA);
+ if (dump)
+ dumpElementln ("WRITE ENDBLOCKDATA FOR: ", obj);
+ }
+ else
+ {
+ if (dump)
+ dumpElementln ("WRITE FIELDS CALLED FOR: ", obj);
+ writeFields(obj, currentObjectStreamClass);
+ }
+ }
+
+ this.currentObject = prevObject;
+ this.currentObjectStreamClass = prevObjectStreamClass;
+ currentPutField = null;
+ break;
+ }
+
+ throw new NotSerializableException(clazz.getName()
+ + " in "
+ + obj.getClass());
+ } // end pseudo-loop
+ }
+ catch (ObjectStreamException ose)
+ {
+ // Rethrow these are fatal.
+ throw ose;
+ }
+ catch (IOException e)
+ {
+ realOutput.writeByte(TC_EXCEPTION);
+ reset(true);
+
+ setBlockDataMode(false);
+ try
+ {
+ if (DEBUG)
+ {
+ e.printStackTrace(System.out);
+ }
+ writeObject(e);
+ }
+ catch (IOException ioe)
+ {
+ StreamCorruptedException ex =
+ new StreamCorruptedException
+ (ioe + " thrown while exception was being written to stream.");
+ if (DEBUG)
+ {
+ ex.printStackTrace(System.out);
+ }
+ throw ex;
+ }
+
+ reset (true);
+
+ }
+ finally
+ {
+ isSerializing = was_serializing;
+ setBlockDataMode(old_mode);
+ depth -= 2;
+
+ if (dump)
+ dumpElementln ("END: ", obj);
+ }
+ }
+
+ protected void writeClassDescriptor(ObjectStreamClass osc) throws IOException
+ {
+ if (osc.isProxyClass)
+ {
+ realOutput.writeByte(TC_PROXYCLASSDESC);
+ Class[] intfs = osc.forClass().getInterfaces();
+ realOutput.writeInt(intfs.length);
+ for (int i = 0; i < intfs.length; i++)
+ realOutput.writeUTF(intfs[i].getName());
+
+ assignNewHandle(osc);
+
+ boolean oldmode = setBlockDataMode(true);
+ annotateProxyClass(osc.forClass());
+ setBlockDataMode(oldmode);
+ realOutput.writeByte(TC_ENDBLOCKDATA);
+ }
+ else
+ {
+ realOutput.writeByte(TC_CLASSDESC);
+ realOutput.writeUTF(osc.getName());
+ if (osc.isEnum())
+ realOutput.writeLong(0L);
+ else
+ realOutput.writeLong(osc.getSerialVersionUID());
+ assignNewHandle(osc);
+
+ int flags = osc.getFlags();
+
+ if (protocolVersion == PROTOCOL_VERSION_2
+ && osc.isExternalizable())
+ flags |= SC_BLOCK_DATA;
+
+ realOutput.writeByte(flags);
+
+ ObjectStreamField[] fields = osc.fields;
+
+ if (fields == ObjectStreamClass.INVALID_FIELDS)
+ throw new InvalidClassException
+ (osc.getName(), "serialPersistentFields is invalid");
+
+ realOutput.writeShort(fields.length);
+
+ ObjectStreamField field;
+ for (int i = 0; i < fields.length; i++)
+ {
+ field = fields[i];
+ realOutput.writeByte(field.getTypeCode ());
+ realOutput.writeUTF(field.getName ());
+
+ if (! field.isPrimitive())
+ writeObject(field.getTypeString());
+ }
+
+ boolean oldmode = setBlockDataMode(true);
+ annotateClass(osc.forClass());
+ setBlockDataMode(oldmode);
+ realOutput.writeByte(TC_ENDBLOCKDATA);
+ }
+
+ if (osc.isSerializable() || osc.isExternalizable())
+ writeObject(osc.getSuper());
+ else
+ writeObject(null);
+ }
+
+ /**
+ * Writes the current objects non-transient, non-static fields from
+ * the current class to the underlying output stream.
+ *
+ * This method is intended to be called from within a object's
+ * <code>private void writeObject (ObjectOutputStream)</code>
+ * method.
+ *
+ * @exception NotActiveException This method was called from a
+ * context other than from the current object's and current class's
+ * <code>private void writeObject (ObjectOutputStream)</code>
+ * method.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code>.
+ */
+ public void defaultWriteObject()
+ throws IOException, NotActiveException
+ {
+ markFieldsWritten();
+ writeFields(currentObject, currentObjectStreamClass);
+ }
+
+
+ private void markFieldsWritten() throws IOException
+ {
+ if (currentObject == null || currentObjectStreamClass == null)
+ throw new NotActiveException
+ ("defaultWriteObject called by non-active class and/or object");
+
+ if (fieldsAlreadyWritten)
+ throw new IOException
+ ("Only one of writeFields and defaultWriteObject may be called, and it may only be called once");
+
+ fieldsAlreadyWritten = true;
+ }
+
+ /**
+ * Resets stream to state equivalent to the state just after it was
+ * constructed.
+ *
+ * Causes all objects previously written to the stream to be
+ * forgotten. A notification of this reset is also written to the
+ * underlying stream.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code> or reset called while serialization is
+ * in progress.
+ */
+ public void reset() throws IOException
+ {
+ reset(false);
+ }
+
+
+ private void reset(boolean internal) throws IOException
+ {
+ if (!internal)
+ {
+ if (isSerializing)
+ throw new IOException("Reset called while serialization in progress");
+
+ realOutput.writeByte(TC_RESET);
+ }
+
+ clearHandles();
+ }
+
+
+ /**
+ * Informs this <code>ObjectOutputStream</code> to write data
+ * according to the specified protocol. There are currently two
+ * different protocols, specified by <code>PROTOCOL_VERSION_1</code>
+ * and <code>PROTOCOL_VERSION_2</code>. This implementation writes
+ * data using <code>PROTOCOL_VERSION_2</code> by default, as is done
+ * since the JDK 1.2.
+ * <p>
+ * For an explanation of the differences between the two protocols
+ * see the Java Object Serialization Specification.
+ * </p>
+ *
+ * @param version the version to use.
+ *
+ * @throws IllegalArgumentException if <code>version</code> is not a valid
+ * protocol.
+ * @throws IllegalStateException if called after the first the first object
+ * was serialized.
+ * @throws IOException if an I/O error occurs.
+ *
+ * @see ObjectStreamConstants#PROTOCOL_VERSION_1
+ * @see ObjectStreamConstants#PROTOCOL_VERSION_2
+ *
+ * @since 1.2
+ */
+ public void useProtocolVersion(int version) throws IOException
+ {
+ if (version != PROTOCOL_VERSION_1 && version != PROTOCOL_VERSION_2)
+ throw new IllegalArgumentException("Invalid protocol version requested.");
+
+ if (nextOID != baseWireHandle)
+ throw new IllegalStateException("Protocol version cannot be changed "
+ + "after serialization started.");
+
+ protocolVersion = version;
+ }
+
+ /**
+ * An empty hook that allows subclasses to write extra information
+ * about classes to the stream. This method is called the first
+ * time each class is seen, and after all of the standard
+ * information about the class has been written.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code>.
+ *
+ * @see ObjectInputStream#resolveClass(java.io.ObjectStreamClass)
+ */
+ protected void annotateClass(Class<?> cl) throws IOException
+ {
+ }
+
+ protected void annotateProxyClass(Class<?> cl) throws IOException
+ {
+ }
+
+ /**
+ * Allows subclasses to replace objects that are written to the
+ * stream with other objects to be written in their place. This
+ * method is called the first time each object is encountered
+ * (modulo reseting of the stream).
+ *
+ * This method must be enabled before it will be called in the
+ * serialization process.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code>.
+ *
+ * @see #enableReplaceObject(boolean)
+ */
+ protected Object replaceObject(Object obj) throws IOException
+ {
+ return obj;
+ }
+
+
+ /**
+ * If <code>enable</code> is <code>true</code> and this object is
+ * trusted, then <code>replaceObject (Object)</code> will be called
+ * in subsequent calls to <code>writeObject (Object)</code>.
+ * Otherwise, <code>replaceObject (Object)</code> will not be called.
+ *
+ * @exception SecurityException This class is not trusted.
+ */
+ protected boolean enableReplaceObject(boolean enable)
+ throws SecurityException
+ {
+ if (enable)
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPermission(new SerializablePermission("enableSubstitution"));
+ }
+
+ boolean old_val = replacementEnabled;
+ replacementEnabled = enable;
+ return old_val;
+ }
+
+
+ /**
+ * Writes stream magic and stream version information to the
+ * underlying stream.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code>.
+ */
+ protected void writeStreamHeader() throws IOException
+ {
+ realOutput.writeShort(STREAM_MAGIC);
+ realOutput.writeShort(STREAM_VERSION);
+ }
+
+ /**
+ * Protected constructor that allows subclasses to override
+ * serialization. This constructor should be called by subclasses
+ * that wish to override <code>writeObject (Object)</code>. This
+ * method does a security check <i>NOTE: currently not
+ * implemented</i>, then sets a flag that informs
+ * <code>writeObject (Object)</code> to call the subclasses
+ * <code>writeObjectOverride (Object)</code> method.
+ *
+ * @see #writeObjectOverride(Object)
+ */
+ protected ObjectOutputStream() throws IOException, SecurityException
+ {
+ SecurityManager sec_man = System.getSecurityManager ();
+ if (sec_man != null)
+ sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
+ useSubclassMethod = true;
+ }
+
+
+ /**
+ * This method allows subclasses to override the default
+ * serialization mechanism provided by
+ * <code>ObjectOutputStream</code>. To make this method be used for
+ * writing objects, subclasses must invoke the 0-argument
+ * constructor on this class from there constructor.
+ *
+ * @see #ObjectOutputStream()
+ *
+ * @exception NotActiveException Subclass has arranged for this
+ * method to be called, but did not implement this method.
+ */
+ protected void writeObjectOverride(Object obj) throws NotActiveException,
+ IOException
+ {
+ throw new NotActiveException
+ ("Subclass of ObjectOutputStream must implement writeObjectOverride");
+ }
+
+
+ /**
+ * @see DataOutputStream#write(int)
+ */
+ public void write (int data) throws IOException
+ {
+ if (writeDataAsBlocks)
+ {
+ if (blockDataCount == BUFFER_SIZE)
+ drain();
+
+ blockData[ blockDataCount++ ] = (byte)data;
+ }
+ else
+ realOutput.write(data);
+ }
+
+
+ /**
+ * @see DataOutputStream#write(byte[])
+ */
+ public void write(byte[] b) throws IOException
+ {
+ write(b, 0, b.length);
+ }
+
+
+ /**
+ * @see DataOutputStream#write(byte[],int,int)
+ */
+ public void write(byte[] b, int off, int len) throws IOException
+ {
+ if (writeDataAsBlocks)
+ {
+ if (len < 0)
+ throw new IndexOutOfBoundsException();
+
+ if (blockDataCount + len < BUFFER_SIZE)
+ {
+ System.arraycopy(b, off, blockData, blockDataCount, len);
+ blockDataCount += len;
+ }
+ else
+ {
+ drain();
+ writeBlockDataHeader(len);
+ realOutput.write(b, off, len);
+ }
+ }
+ else
+ realOutput.write(b, off, len);
+ }
+
+
+ /**
+ * @see DataOutputStream#flush()
+ */
+ public void flush () throws IOException
+ {
+ drain();
+ realOutput.flush();
+ }
+
+
+ /**
+ * Causes the block-data buffer to be written to the underlying
+ * stream, but does not flush underlying stream.
+ *
+ * @exception IOException Exception from underlying
+ * <code>OutputStream</code>.
+ */
+ protected void drain() throws IOException
+ {
+ if (blockDataCount == 0)
+ return;
+
+ if (writeDataAsBlocks)
+ writeBlockDataHeader(blockDataCount);
+ realOutput.write(blockData, 0, blockDataCount);
+ blockDataCount = 0;
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#close ()
+ */
+ public void close() throws IOException
+ {
+ flush();
+ realOutput.close();
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#writeBoolean (boolean)
+ */
+ public void writeBoolean(boolean data) throws IOException
+ {
+ blockDataOutput.writeBoolean(data);
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#writeByte (int)
+ */
+ public void writeByte(int data) throws IOException
+ {
+ blockDataOutput.writeByte(data);
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#writeShort (int)
+ */
+ public void writeShort (int data) throws IOException
+ {
+ blockDataOutput.writeShort(data);
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#writeChar (int)
+ */
+ public void writeChar(int data) throws IOException
+ {
+ blockDataOutput.writeChar(data);
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#writeInt (int)
+ */
+ public void writeInt(int data) throws IOException
+ {
+ blockDataOutput.writeInt(data);
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#writeLong (long)
+ */
+ public void writeLong(long data) throws IOException
+ {
+ blockDataOutput.writeLong(data);
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#writeFloat (float)
+ */
+ public void writeFloat(float data) throws IOException
+ {
+ blockDataOutput.writeFloat(data);
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#writeDouble (double)
+ */
+ public void writeDouble(double data) throws IOException
+ {
+ blockDataOutput.writeDouble(data);
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#writeBytes (java.lang.String)
+ */
+ public void writeBytes(String data) throws IOException
+ {
+ blockDataOutput.writeBytes(data);
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#writeChars (java.lang.String)
+ */
+ public void writeChars(String data) throws IOException
+ {
+ dataOutput.writeChars(data);
+ }
+
+
+ /**
+ * @see java.io.DataOutputStream#writeUTF (java.lang.String)
+ */
+ public void writeUTF(String data) throws IOException
+ {
+ dataOutput.writeUTF(data);
+ }
+
+
+ /**
+ * This class allows a class to specify exactly which fields should
+ * be written, and what values should be written for these fields.
+ *
+ * XXX: finish up comments
+ */
+ public abstract static class PutField
+ {
+ public abstract void put (String name, boolean value);
+ public abstract void put (String name, byte value);
+ public abstract void put (String name, char value);
+ public abstract void put (String name, double value);
+ public abstract void put (String name, float value);
+ public abstract void put (String name, int value);
+ public abstract void put (String name, long value);
+ public abstract void put (String name, short value);
+ public abstract void put (String name, Object value);
+
+ /**
+ * @deprecated
+ */
+ public abstract void write (ObjectOutput out) throws IOException;
+ }
+
+ public PutField putFields() throws IOException
+ {
+ if (currentPutField != null)
+ return currentPutField;
+
+ currentPutField = new PutField()
+ {
+ private byte[] prim_field_data
+ = new byte[currentObjectStreamClass.primFieldSize];
+ private Object[] objs
+ = new Object[currentObjectStreamClass.objectFieldCount];
+
+ private ObjectStreamField getField (String name)
+ {
+ ObjectStreamField field
+ = currentObjectStreamClass.getField(name);
+
+ if (field == null)
+ throw new IllegalArgumentException("no such serializable field " + name);
+
+ return field;
+ }
+
+ public void put(String name, boolean value)
+ {
+ ObjectStreamField field = getField(name);
+
+ checkType(field, 'Z');
+ prim_field_data[field.getOffset ()] = (byte)(value ? 1 : 0);
+ }
+
+ public void put(String name, byte value)
+ {
+ ObjectStreamField field = getField(name);
+
+ checkType(field, 'B');
+ prim_field_data[field.getOffset()] = value;
+ }
+
+ public void put(String name, char value)
+ {
+ ObjectStreamField field = getField(name);
+
+ checkType(field, 'C');
+ int off = field.getOffset();
+ prim_field_data[off++] = (byte)(value >>> 8);
+ prim_field_data[off] = (byte)value;
+ }
+
+ public void put(String name, double value)
+ {
+ ObjectStreamField field = getField (name);
+
+ checkType(field, 'D');
+ int off = field.getOffset();
+ long l_value = Double.doubleToLongBits (value);
+ prim_field_data[off++] = (byte)(l_value >>> 52);
+ prim_field_data[off++] = (byte)(l_value >>> 48);
+ prim_field_data[off++] = (byte)(l_value >>> 40);
+ prim_field_data[off++] = (byte)(l_value >>> 32);
+ prim_field_data[off++] = (byte)(l_value >>> 24);
+ prim_field_data[off++] = (byte)(l_value >>> 16);
+ prim_field_data[off++] = (byte)(l_value >>> 8);
+ prim_field_data[off] = (byte)l_value;
+ }
+
+ public void put(String name, float value)
+ {
+ ObjectStreamField field = getField(name);
+
+ checkType(field, 'F');
+ int off = field.getOffset();
+ int i_value = Float.floatToIntBits(value);
+ prim_field_data[off++] = (byte)(i_value >>> 24);
+ prim_field_data[off++] = (byte)(i_value >>> 16);
+ prim_field_data[off++] = (byte)(i_value >>> 8);
+ prim_field_data[off] = (byte)i_value;
+ }
+
+ public void put(String name, int value)
+ {
+ ObjectStreamField field = getField(name);
+ checkType(field, 'I');
+ int off = field.getOffset();
+ prim_field_data[off++] = (byte)(value >>> 24);
+ prim_field_data[off++] = (byte)(value >>> 16);
+ prim_field_data[off++] = (byte)(value >>> 8);
+ prim_field_data[off] = (byte)value;
+ }
+
+ public void put(String name, long value)
+ {
+ ObjectStreamField field = getField(name);
+ checkType(field, 'J');
+ int off = field.getOffset();
+ prim_field_data[off++] = (byte)(value >>> 52);
+ prim_field_data[off++] = (byte)(value >>> 48);
+ prim_field_data[off++] = (byte)(value >>> 40);
+ prim_field_data[off++] = (byte)(value >>> 32);
+ prim_field_data[off++] = (byte)(value >>> 24);
+ prim_field_data[off++] = (byte)(value >>> 16);
+ prim_field_data[off++] = (byte)(value >>> 8);
+ prim_field_data[off] = (byte)value;
+ }
+
+ public void put(String name, short value)
+ {
+ ObjectStreamField field = getField(name);
+ checkType(field, 'S');
+ int off = field.getOffset();
+ prim_field_data[off++] = (byte)(value >>> 8);
+ prim_field_data[off] = (byte)value;
+ }
+
+ public void put(String name, Object value)
+ {
+ ObjectStreamField field = getField(name);
+
+ if (value != null &&
+ ! field.getType().isAssignableFrom(value.getClass ()))
+ throw new IllegalArgumentException("Class " + value.getClass() +
+ " cannot be cast to " + field.getType());
+ objs[field.getOffset()] = value;
+ }
+
+ public void write(ObjectOutput out) throws IOException
+ {
+ // Apparently Block data is not used with PutField as per
+ // empirical evidence against JDK 1.2. Also see Mauve test
+ // java.io.ObjectInputOutput.Test.GetPutField.
+ boolean oldmode = setBlockDataMode(false);
+ out.write(prim_field_data);
+ for (int i = 0; i < objs.length; ++ i)
+ out.writeObject(objs[i]);
+ setBlockDataMode(oldmode);
+ }
+
+ private void checkType(ObjectStreamField field, char type)
+ throws IllegalArgumentException
+ {
+ if (TypeSignature.getEncodingOfClass(field.getType()).charAt(0)
+ != type)
+ throw new IllegalArgumentException();
+ }
+ };
+ // end PutFieldImpl
+
+ return currentPutField;
+ }
+
+
+ public void writeFields() throws IOException
+ {
+ if (currentPutField == null)
+ throw new NotActiveException("writeFields can only be called after putFields has been called");
+
+ markFieldsWritten();
+ currentPutField.write(this);
+ }
+
+
+ // write out the block-data buffer, picking the correct header
+ // depending on the size of the buffer
+ private void writeBlockDataHeader(int size) throws IOException
+ {
+ if (size < 256)
+ {
+ realOutput.writeByte(TC_BLOCKDATA);
+ realOutput.write(size);
+ }
+ else
+ {
+ realOutput.writeByte(TC_BLOCKDATALONG);
+ realOutput.writeInt(size);
+ }
+ }
+
+
+ // lookup the handle for OBJ, return null if OBJ doesn't have a
+ // handle yet
+ private int findHandle(Object obj)
+ {
+ return OIDLookupTable.get(obj);
+ }
+
+
+ // assigns the next availible handle to OBJ
+ private int assignNewHandle(Object obj)
+ {
+ OIDLookupTable.put(obj, nextOID);
+ return nextOID++;
+ }
+
+
+ // resets mapping from objects to handles
+ private void clearHandles()
+ {
+ nextOID = baseWireHandle;
+ OIDLookupTable.clear();
+ }
+
+
+ // write out array size followed by each element of the array
+ private void writeArraySizeAndElements(Object array, Class clazz)
+ throws IOException
+ {
+ int length = Array.getLength(array);
+
+ if (clazz.isPrimitive())
+ {
+ if (clazz == Boolean.TYPE)
+ {
+ boolean[] cast_array = (boolean[])array;
+ realOutput.writeInt (length);
+ for (int i = 0; i < length; i++)
+ realOutput.writeBoolean(cast_array[i]);
+ return;
+ }
+ if (clazz == Byte.TYPE)
+ {
+ byte[] cast_array = (byte[])array;
+ realOutput.writeInt(length);
+ realOutput.write(cast_array, 0, length);
+ return;
+ }
+ if (clazz == Character.TYPE)
+ {
+ char[] cast_array = (char[])array;
+ realOutput.writeInt(length);
+ for (int i = 0; i < length; i++)
+ realOutput.writeChar(cast_array[i]);
+ return;
+ }
+ if (clazz == Double.TYPE)
+ {
+ double[] cast_array = (double[])array;
+ realOutput.writeInt(length);
+ for (int i = 0; i < length; i++)
+ realOutput.writeDouble(cast_array[i]);
+ return;
+ }
+ if (clazz == Float.TYPE)
+ {
+ float[] cast_array = (float[])array;
+ realOutput.writeInt(length);
+ for (int i = 0; i < length; i++)
+ realOutput.writeFloat(cast_array[i]);
+ return;
+ }
+ if (clazz == Integer.TYPE)
+ {
+ int[] cast_array = (int[])array;
+ realOutput.writeInt(length);
+ for (int i = 0; i < length; i++)
+ realOutput.writeInt(cast_array[i]);
+ return;
+ }
+ if (clazz == Long.TYPE)
+ {
+ long[] cast_array = (long[])array;
+ realOutput.writeInt (length);
+ for (int i = 0; i < length; i++)
+ realOutput.writeLong(cast_array[i]);
+ return;
+ }
+ if (clazz == Short.TYPE)
+ {
+ short[] cast_array = (short[])array;
+ realOutput.writeInt (length);
+ for (int i = 0; i < length; i++)
+ realOutput.writeShort(cast_array[i]);
+ return;
+ }
+ }
+ else
+ {
+ Object[] cast_array = (Object[])array;
+ realOutput.writeInt(length);
+ for (int i = 0; i < length; i++)
+ writeObject(cast_array[i]);
+ }
+ }
+
+
+/* GCJ LOCAL */
+ // writes out FIELDS of OBJECT for the specified ObjectStreamClass.
+ // FIELDS are already supposed already to be in canonical order, but
+ // under some circumstances (to do with Proxies) this isn't the
+ // case, so we call ensureFieldsSet().
+ private void writeFields(Object obj, ObjectStreamClass osc)
+ throws IOException
+ {
+ osc.ensureFieldsSet(osc.forClass());
+/* END GCJ LOCAL */
+
+ ObjectStreamField[] fields = osc.fields;
+ boolean oldmode = setBlockDataMode(false);
+
+ try
+ {
+ writeFields(obj,fields);
+ }
+ catch (IllegalArgumentException _)
+ {
+ InvalidClassException e = new InvalidClassException
+ ("writing fields of class " + osc.forClass().getName());
+ e.initCause(_);
+ throw e;
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception _)
+ {
+ IOException e = new IOException("Unexpected exception " + _);
+ e.initCause(_);
+ throw(e);
+ }
+
+ setBlockDataMode(oldmode);
+ }
+
+
+ /**
+ * Helper function for writeFields(Object,ObjectStreamClass): write
+ * fields from given fields array. Pass exception on.
+ *
+ * @param obj the object to be written
+ *
+ * @param fields the fields of obj to be written.
+ */
+ private void writeFields(Object obj, ObjectStreamField[] fields)
+ throws
+ IllegalArgumentException, IllegalAccessException, IOException
+ {
+ for (int i = 0; i < fields.length; i++)
+ {
+ ObjectStreamField osf = fields[i];
+ Field field = osf.field;
+
+ if (DEBUG && dump)
+ dumpElementln ("WRITE FIELD: " + osf.getName() + " type=" + osf.getType());
+
+ switch (osf.getTypeCode())
+ {
+ case 'Z': realOutput.writeBoolean(field.getBoolean(obj)); break;
+ case 'B': realOutput.writeByte (field.getByte (obj)); break;
+ case 'S': realOutput.writeShort (field.getShort (obj)); break;
+ case 'C': realOutput.writeChar (field.getChar (obj)); break;
+ case 'I': realOutput.writeInt (field.getInt (obj)); break;
+ case 'F': realOutput.writeFloat (field.getFloat (obj)); break;
+ case 'J': realOutput.writeLong (field.getLong (obj)); break;
+ case 'D': realOutput.writeDouble (field.getDouble (obj)); break;
+ case 'L':
+ case '[': writeObject (field.get (obj)); break;
+ default:
+ throw new IOException("Unexpected type code " + osf.getTypeCode());
+ }
+ }
+ }
+
+
+ // Toggles writing primitive data to block-data buffer.
+ // Package-private to avoid a trampoline constructor.
+ boolean setBlockDataMode(boolean on) throws IOException
+ {
+ if (on == writeDataAsBlocks)
+ return on;
+
+ drain();
+ boolean oldmode = writeDataAsBlocks;
+ writeDataAsBlocks = on;
+
+ if (on)
+ dataOutput = blockDataOutput;
+ else
+ dataOutput = realOutput;
+
+ return oldmode;
+ }
+
+
+ private void callWriteMethod(Object obj, ObjectStreamClass osc)
+ throws IOException
+ {
+ currentPutField = null;
+ try
+ {
+ Object args[] = {this};
+ osc.writeObjectMethod.invoke(obj, args);
+ }
+ catch (InvocationTargetException x)
+ {
+ /* Rethrow if possible. */
+ Throwable exception = x.getTargetException();
+ if (exception instanceof RuntimeException)
+ throw (RuntimeException) exception;
+ if (exception instanceof IOException)
+ throw (IOException) exception;
+
+ IOException ioe
+ = new IOException("Exception thrown from writeObject() on " +
+ osc.forClass().getName() + ": " +
+ exception.getClass().getName());
+ ioe.initCause(exception);
+ throw ioe;
+ }
+ catch (Exception x)
+ {
+ IOException ioe
+ = new IOException("Failure invoking writeObject() on " +
+ osc.forClass().getName() + ": " +
+ x.getClass().getName());
+ ioe.initCause(x);
+ throw ioe;
+ }
+ }
+
+ private void dumpElementln (String msg, Object obj)
+ {
+ try
+ {
+ for (int i = 0; i < depth; i++)
+ System.out.print (" ");
+ System.out.print (Thread.currentThread() + ": ");
+ System.out.print (msg);
+ if (java.lang.reflect.Proxy.isProxyClass(obj.getClass()))
+ System.out.print (obj.getClass());
+ else
+ System.out.print (obj);
+ }
+ catch (Exception _)
+ {
+ }
+ finally
+ {
+ System.out.println ();
+ }
+ }
+
+ private void dumpElementln (String msg)
+ {
+ for (int i = 0; i < depth; i++)
+ System.out.print (" ");
+ System.out.print (Thread.currentThread() + ": ");
+ System.out.println(msg);
+ }
+
+ // this value comes from 1.2 spec, but is used in 1.1 as well
+ private static final int BUFFER_SIZE = 1024;
+
+ private static int defaultProtocolVersion = PROTOCOL_VERSION_2;
+
+ private DataOutputStream dataOutput;
+ private boolean writeDataAsBlocks;
+ private DataOutputStream realOutput;
+ private DataOutputStream blockDataOutput;
+ private byte[] blockData;
+ private int blockDataCount;
+ private Object currentObject;
+ // Package-private to avoid a trampoline.
+ ObjectStreamClass currentObjectStreamClass;
+ private PutField currentPutField;
+ private boolean fieldsAlreadyWritten;
+ private boolean replacementEnabled;
+ private boolean isSerializing;
+ private int nextOID;
+ private ObjectIdentityMap2Int OIDLookupTable;
+ private int protocolVersion;
+ private boolean useSubclassMethod;
+ private SetAccessibleAction setAccessible = new SetAccessibleAction();
+
+ // The nesting depth for debugging output
+ private int depth = 0;
+
+ // Set if we're generating debugging dumps
+ private boolean dump = false;
+
+ private static final boolean DEBUG = false;
+}
diff --git a/libjava/classpath/java/io/ObjectStreamClass.java b/libjava/classpath/java/io/ObjectStreamClass.java
new file mode 100644
index 000000000..b71f54895
--- /dev/null
+++ b/libjava/classpath/java/io/ObjectStreamClass.java
@@ -0,0 +1,1161 @@
+/* ObjectStreamClass.java -- Class used to write class information
+ about serialized objects.
+ Copyright (C) 1998, 1999, 2000, 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 java.io;
+
+import gnu.java.io.NullOutputStream;
+import gnu.java.lang.reflect.TypeSignature;
+import gnu.java.security.action.SetAccessibleAction;
+import gnu.java.security.provider.Gnu;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.security.AccessController;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedAction;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Hashtable;
+
+/**
+ * @author Tom Tromey (tromey@redhat.com)
+ * @author Jeroen Frijters (jeroen@frijters.net)
+ * @author Guilhem Lavaux (guilhem@kaffe.org)
+ * @author Michael Koch (konqueror@gmx.de)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+public class ObjectStreamClass implements Serializable
+{
+ static final ObjectStreamField[] INVALID_FIELDS = new ObjectStreamField[0];
+
+ /**
+ * Returns the <code>ObjectStreamClass</code> for <code>cl</code>.
+ * If <code>cl</code> is null, or is not <code>Serializable</code>,
+ * null is returned. <code>ObjectStreamClass</code>'s are memorized;
+ * later calls to this method with the same class will return the
+ * same <code>ObjectStreamClass</code> object and no recalculation
+ * will be done.
+ *
+ * Warning: If this class contains an invalid serialPersistentField arrays
+ * lookup will not throw anything. However {@link #getFields()} will return
+ * an empty array and {@link java.io.ObjectOutputStream#writeObject} will throw an
+ * {@link java.io.InvalidClassException}.
+ *
+ * @see java.io.Serializable
+ */
+ public static ObjectStreamClass lookup(Class<?> cl)
+ {
+ if (cl == null)
+ return null;
+ if (! (Serializable.class).isAssignableFrom(cl))
+ return null;
+
+ return lookupForClassObject(cl);
+ }
+
+ /**
+ * This lookup for internal use by ObjectOutputStream. Suppose
+ * we have a java.lang.Class object C for class A, though A is not
+ * serializable, but it's okay to serialize C.
+ */
+ static ObjectStreamClass lookupForClassObject(Class cl)
+ {
+ if (cl == null)
+ return null;
+
+ ObjectStreamClass osc = classLookupTable.get(cl);
+
+ if (osc != null)
+ return osc;
+ else
+ {
+ osc = new ObjectStreamClass(cl);
+ classLookupTable.put(cl, osc);
+ return osc;
+ }
+ }
+
+ /**
+ * Returns the name of the class that this
+ * <code>ObjectStreamClass</code> represents.
+ *
+ * @return the name of the class.
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Returns the class that this <code>ObjectStreamClass</code>
+ * represents. Null could be returned if this
+ * <code>ObjectStreamClass</code> was read from an
+ * <code>ObjectInputStream</code> and the class it represents cannot
+ * be found or loaded.
+ *
+ * @see java.io.ObjectInputStream
+ */
+ public Class<?> forClass()
+ {
+ return clazz;
+ }
+
+ /**
+ * Returns the serial version stream-unique identifier for the class
+ * represented by this <code>ObjectStreamClass</code>. This SUID is
+ * either defined by the class as <code>static final long
+ * serialVersionUID</code> or is calculated as specified in
+ * Javasoft's "Object Serialization Specification" XXX: add reference
+ *
+ * @return the serial version UID.
+ */
+ public long getSerialVersionUID()
+ {
+ return uid;
+ }
+
+ /**
+ * Returns the serializable (non-static and non-transient) Fields
+ * of the class represented by this ObjectStreamClass. The Fields
+ * are sorted by name.
+ * If fields were obtained using serialPersistentFields and this array
+ * is faulty then the returned array of this method will be empty.
+ *
+ * @return the fields.
+ */
+ public ObjectStreamField[] getFields()
+ {
+ ObjectStreamField[] copy = new ObjectStreamField[ fields.length ];
+ System.arraycopy(fields, 0, copy, 0, fields.length);
+ return copy;
+ }
+
+ // XXX doc
+ // Can't do binary search since fields is sorted by name and
+ // primitiveness.
+ public ObjectStreamField getField (String name)
+ {
+ for (int i = 0; i < fields.length; i++)
+ if (fields[i].getName().equals(name))
+ return fields[i];
+ return null;
+ }
+
+ /**
+ * Returns a textual representation of this
+ * <code>ObjectStreamClass</code> object including the name of the
+ * class it represents as well as that class's serial version
+ * stream-unique identifier.
+ *
+ * @see #getSerialVersionUID()
+ * @see #getName()
+ */
+ public String toString()
+ {
+ return "java.io.ObjectStreamClass< " + name + ", " + uid + " >";
+ }
+
+ // Returns true iff the class that this ObjectStreamClass represents
+ // has the following method:
+ //
+ // private void writeObject (ObjectOutputStream)
+ //
+ // This method is used by the class to override default
+ // serialization behavior.
+ boolean hasWriteMethod()
+ {
+ return (flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0;
+ }
+
+ // Returns true iff the class that this ObjectStreamClass represents
+ // implements Serializable but does *not* implement Externalizable.
+ boolean isSerializable()
+ {
+ return (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
+ }
+
+
+ // Returns true iff the class that this ObjectStreamClass represents
+ // implements Externalizable.
+ boolean isExternalizable()
+ {
+ return (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
+ }
+
+ // Returns true iff the class that this ObjectStreamClass represents
+ // implements Externalizable.
+ boolean isEnum()
+ {
+ return (flags & ObjectStreamConstants.SC_ENUM) != 0;
+ }
+
+ // Returns the <code>ObjectStreamClass</code> that represents the
+ // class that is the superclass of the class this
+ // <code>ObjectStreamClass</code> represents. If the superclass is
+ // not Serializable, null is returned.
+ ObjectStreamClass getSuper()
+ {
+ return superClass;
+ }
+
+ /**
+ * returns an array of ObjectStreamClasses that represent the super
+ * classes of the class represented by this and the class
+ * represented by this itself in order from most super to this.
+ * ObjectStreamClass[0] is the highest superclass of this that is
+ * serializable.
+ *
+ * The result of consecutive calls this hierarchy() will be the same
+ * array instance.
+ *
+ * @return an array of ObjectStreamClass representing the
+ * super-class hierarchy of serializable classes.
+ */
+ ObjectStreamClass[] hierarchy()
+ {
+ ObjectStreamClass[] result = hierarchy;
+ if (result == null)
+ {
+ int d = 0;
+
+ for(ObjectStreamClass osc = this; osc != null; osc = osc.getSuper())
+ d++;
+
+ result = new ObjectStreamClass[d];
+
+ for (ObjectStreamClass osc = this; osc != null; osc = osc.getSuper())
+ {
+ result[--d] = osc;
+ }
+
+ hierarchy = result;
+ }
+ return result;
+ }
+
+ /**
+ * Cache for hierarchy() result.
+ */
+ private ObjectStreamClass[] hierarchy = null;
+
+ // Returns an integer that consists of bit-flags that indicate
+ // properties of the class represented by this ObjectStreamClass.
+ // The bit-flags that could be present are those defined in
+ // ObjectStreamConstants that begin with `SC_'
+ int getFlags()
+ {
+ return flags;
+ }
+
+
+ ObjectStreamClass(String name, long uid, byte flags,
+ ObjectStreamField[] fields)
+ {
+ this.name = name;
+ this.uid = uid;
+ this.flags = flags;
+ this.fields = fields;
+ }
+
+ /**
+ * This method builds the internal description corresponding to a Java Class.
+ * As the constructor only assign a name to the current ObjectStreamClass instance,
+ * that method sets the serial UID, chose the fields which will be serialized,
+ * and compute the position of the fields in the serialized stream.
+ *
+ * @param cl The Java class which is used as a reference for building the descriptor.
+ * @param superClass The descriptor of the super class for this class descriptor.
+ * @throws InvalidClassException if an incompatibility between computed UID and
+ * already set UID is found.
+ */
+ void setClass(Class cl, ObjectStreamClass superClass) throws InvalidClassException
+ {hierarchy = null;
+ this.clazz = cl;
+
+ cacheMethods();
+
+ long class_uid = getClassUID(cl);
+ if (uid == 0)
+ uid = class_uid;
+ else
+ {
+ // Check that the actual UID of the resolved class matches the UID from
+ // the stream. Mismatches for array classes are ignored.
+ if (!cl.isArray() && uid != class_uid)
+ {
+ String msg = cl +
+ ": Local class not compatible: stream serialVersionUID="
+ + uid + ", local serialVersionUID=" + class_uid;
+ throw new InvalidClassException (msg);
+ }
+ }
+
+ isProxyClass = clazz != null && Proxy.isProxyClass(clazz);
+ this.superClass = superClass;
+ calculateOffsets();
+
+ try
+ {
+ ObjectStreamField[] exportedFields = getSerialPersistentFields (clazz);
+
+ if (exportedFields == null)
+ return;
+
+ ObjectStreamField[] newFieldList = new ObjectStreamField[exportedFields.length + fields.length];
+ int i, j, k;
+
+ /* We now check the import fields against the exported fields.
+ * There should not be contradiction (e.g. int x and String x)
+ * but extra virtual fields can be added to the class.
+ */
+
+ Arrays.sort(exportedFields);
+
+ i = 0; j = 0; k = 0;
+ while (i < fields.length && j < exportedFields.length)
+ {
+ int comp = fields[i].compareTo(exportedFields[j]);
+
+ if (comp < 0)
+ {
+ newFieldList[k] = fields[i];
+ fields[i].setPersistent(false);
+ fields[i].setToSet(false);
+ i++;
+ }
+ else if (comp > 0)
+ {
+ /* field not found in imported fields. We add it
+ * in the list of supported fields.
+ */
+ newFieldList[k] = exportedFields[j];
+ newFieldList[k].setPersistent(true);
+ newFieldList[k].setToSet(false);
+ try
+ {
+ newFieldList[k].lookupField(clazz);
+ newFieldList[k].checkFieldType();
+ }
+ catch (NoSuchFieldException _)
+ {
+ }
+ j++;
+ }
+ else
+ {
+ try
+ {
+ exportedFields[j].lookupField(clazz);
+ exportedFields[j].checkFieldType();
+ }
+ catch (NoSuchFieldException _)
+ {
+ }
+
+ if (!fields[i].getType().equals(exportedFields[j].getType()))
+ throw new InvalidClassException
+ ("serialPersistentFields must be compatible with" +
+ " imported fields (about " + fields[i].getName() + ")");
+ newFieldList[k] = fields[i];
+ fields[i].setPersistent(true);
+ i++;
+ j++;
+ }
+ k++;
+ }
+
+ if (i < fields.length)
+ for (;i<fields.length;i++,k++)
+ {
+ fields[i].setPersistent(false);
+ fields[i].setToSet(false);
+ newFieldList[k] = fields[i];
+ }
+ else
+ if (j < exportedFields.length)
+ for (;j<exportedFields.length;j++,k++)
+ {
+ exportedFields[j].setPersistent(true);
+ exportedFields[j].setToSet(false);
+ newFieldList[k] = exportedFields[j];
+ }
+
+ fields = new ObjectStreamField[k];
+ System.arraycopy(newFieldList, 0, fields, 0, k);
+ }
+ catch (NoSuchFieldException ignore)
+ {
+ return;
+ }
+ catch (IllegalAccessException ignore)
+ {
+ return;
+ }
+ }
+
+ void setSuperclass (ObjectStreamClass osc)
+ {
+ superClass = osc;
+ hierarchy = null;
+ }
+
+ void calculateOffsets()
+ {
+ int i;
+ ObjectStreamField field;
+ primFieldSize = 0;
+ int fcount = fields.length;
+ for (i = 0; i < fcount; ++ i)
+ {
+ field = fields[i];
+
+ if (! field.isPrimitive())
+ break;
+
+ field.setOffset(primFieldSize);
+ switch (field.getTypeCode())
+ {
+ case 'B':
+ case 'Z':
+ ++ primFieldSize;
+ break;
+ case 'C':
+ case 'S':
+ primFieldSize += 2;
+ break;
+ case 'I':
+ case 'F':
+ primFieldSize += 4;
+ break;
+ case 'D':
+ case 'J':
+ primFieldSize += 8;
+ break;
+ }
+ }
+
+ for (objectFieldCount = 0; i < fcount; ++ i)
+ fields[i].setOffset(objectFieldCount++);
+ }
+
+ private Method findMethod(Method[] methods, String name, Class[] params,
+ Class returnType, boolean mustBePrivate)
+ {
+outer:
+ for (int i = 0; i < methods.length; i++)
+ {
+ final Method m = methods[i];
+ int mods = m.getModifiers();
+ if (Modifier.isStatic(mods)
+ || (mustBePrivate && !Modifier.isPrivate(mods)))
+ {
+ continue;
+ }
+
+ if (m.getName().equals(name)
+ && m.getReturnType() == returnType)
+ {
+ Class[] mp = m.getParameterTypes();
+ if (mp.length == params.length)
+ {
+ for (int j = 0; j < mp.length; j++)
+ {
+ if (mp[j] != params[j])
+ {
+ continue outer;
+ }
+ }
+ AccessController.doPrivileged(new SetAccessibleAction(m));
+ return m;
+ }
+ }
+ }
+ return null;
+ }
+
+ private static boolean inSamePackage(Class c1, Class c2)
+ {
+ String name1 = c1.getName();
+ String name2 = c2.getName();
+
+ int id1 = name1.lastIndexOf('.');
+ int id2 = name2.lastIndexOf('.');
+
+ // Handle the default package
+ if (id1 == -1 || id2 == -1)
+ return id1 == id2;
+
+ String package1 = name1.substring(0, id1);
+ String package2 = name2.substring(0, id2);
+
+ return package1.equals(package2);
+ }
+
+ final static Class[] noArgs = new Class[0];
+
+ private static Method findAccessibleMethod(String name, Class from)
+ {
+ for (Class c = from; c != null; c = c.getSuperclass())
+ {
+ try
+ {
+ Method res = c.getDeclaredMethod(name, noArgs);
+ int mods = res.getModifiers();
+
+ if (c == from
+ || Modifier.isProtected(mods)
+ || Modifier.isPublic(mods)
+ || (! Modifier.isPrivate(mods) && inSamePackage(c, from)))
+ {
+ AccessController.doPrivileged(new SetAccessibleAction(res));
+ return res;
+ }
+ }
+ catch (NoSuchMethodException e)
+ {
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Helper routine to check if a class was loaded by boot or
+ * application class loader. Classes for which this is not the case
+ * should not be cached since caching prevent class file garbage
+ * collection.
+ *
+ * @param cl a class
+ *
+ * @return true if cl was loaded by boot or application class loader,
+ * false if cl was loaded by a user class loader.
+ */
+ private static boolean loadedByBootOrApplicationClassLoader(Class cl)
+ {
+ ClassLoader l = cl.getClassLoader();
+ return
+ ( l == null /* boot loader */ )
+ || (l == ClassLoader.getSystemClassLoader() /* application loader */);
+ }
+
+ static Hashtable methodCache = new Hashtable();
+
+ static final Class[] readObjectSignature = { ObjectInputStream.class };
+ static final Class[] writeObjectSignature = { ObjectOutputStream.class };
+
+ private void cacheMethods()
+ {
+ Class cl = forClass();
+ Method[] cached = (Method[]) methodCache.get(cl);
+ if (cached == null)
+ {
+ cached = new Method[4];
+ Method[] methods = cl.getDeclaredMethods();
+
+ cached[0] = findMethod(methods, "readObject",
+ readObjectSignature,
+ Void.TYPE, true);
+ cached[1] = findMethod(methods, "writeObject",
+ writeObjectSignature,
+ Void.TYPE, true);
+
+ // readResolve and writeReplace can be in parent classes, as long as they
+ // are accessible from this class.
+ cached[2] = findAccessibleMethod("readResolve", cl);
+ cached[3] = findAccessibleMethod("writeReplace", cl);
+
+ /* put in cache if classes not loaded by user class loader.
+ * For a user class loader, the cache may otherwise grow
+ * without limit.
+ */
+ if (loadedByBootOrApplicationClassLoader(cl))
+ methodCache.put(cl,cached);
+ }
+ readObjectMethod = cached[0];
+ writeObjectMethod = cached[1];
+ readResolveMethod = cached[2];
+ writeReplaceMethod = cached[3];
+ }
+
+ private ObjectStreamClass(Class cl)
+ {
+ uid = 0;
+ flags = 0;
+ isProxyClass = Proxy.isProxyClass(cl);
+
+ clazz = cl;
+ cacheMethods();
+ name = cl.getName();
+ setFlags(cl);
+ setFields(cl);
+ // to those class nonserializable, its uid field is 0
+ if ( (Serializable.class).isAssignableFrom(cl) && !isProxyClass)
+ uid = getClassUID(cl);
+ superClass = lookup(cl.getSuperclass());
+ }
+
+
+ // Sets bits in flags according to features of CL.
+ private void setFlags(Class cl)
+ {
+ if ((java.io.Externalizable.class).isAssignableFrom(cl))
+ flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
+ else if ((java.io.Serializable.class).isAssignableFrom(cl))
+ // only set this bit if CL is NOT Externalizable
+ flags |= ObjectStreamConstants.SC_SERIALIZABLE;
+
+ if (writeObjectMethod != null)
+ flags |= ObjectStreamConstants.SC_WRITE_METHOD;
+
+ if (cl.isEnum() || cl == Enum.class)
+ flags |= ObjectStreamConstants.SC_ENUM;
+ }
+
+/* GCJ LOCAL */
+ // FIXME: This is a workaround for a fairly obscure bug that happens
+ // when reading a Proxy and then writing it back out again. The
+ // result is that the ObjectStreamClass doesn't have its fields set,
+ // generating a NullPointerException. Rather than this kludge we
+ // should probably fix the real bug, but it would require a fairly
+ // radical reorganization to do so.
+ final void ensureFieldsSet(Class cl)
+ {
+ if (! fieldsSet)
+ setFields(cl);
+ }
+/* END GCJ LOCAL */
+
+
+ // Sets fields to be a sorted array of the serializable fields of
+ // clazz.
+ private void setFields(Class cl)
+ {
+/* GCJ LOCAL */
+ fieldsSet = true;
+/* END GCJ LOCAL */
+
+ SetAccessibleAction setAccessible = new SetAccessibleAction();
+
+ if (!isSerializable() || isExternalizable() || isEnum())
+ {
+ fields = NO_FIELDS;
+ return;
+ }
+
+ try
+ {
+ final Field f =
+ cl.getDeclaredField("serialPersistentFields");
+ setAccessible.setMember(f);
+ AccessController.doPrivileged(setAccessible);
+ int modifiers = f.getModifiers();
+
+ if (Modifier.isStatic(modifiers)
+ && Modifier.isFinal(modifiers)
+ && Modifier.isPrivate(modifiers))
+ {
+ fields = getSerialPersistentFields(cl);
+ if (fields != null)
+ {
+ ObjectStreamField[] fieldsName = new ObjectStreamField[fields.length];
+ System.arraycopy(fields, 0, fieldsName, 0, fields.length);
+
+ Arrays.sort (fieldsName, new Comparator() {
+ public int compare(Object o1, Object o2)
+ {
+ ObjectStreamField f1 = (ObjectStreamField)o1;
+ ObjectStreamField f2 = (ObjectStreamField)o2;
+
+ return f1.getName().compareTo(f2.getName());
+ }
+ });
+
+ for (int i=1; i < fields.length; i++)
+ {
+ if (fieldsName[i-1].getName().equals(fieldsName[i].getName()))
+ {
+ fields = INVALID_FIELDS;
+ return;
+ }
+ }
+
+ Arrays.sort (fields);
+ // Retrieve field reference.
+ for (int i=0; i < fields.length; i++)
+ {
+ try
+ {
+ fields[i].lookupField(cl);
+ }
+ catch (NoSuchFieldException _)
+ {
+ fields[i].setToSet(false);
+ }
+ }
+
+ calculateOffsets();
+ return;
+ }
+ }
+ }
+ catch (NoSuchFieldException ignore)
+ {
+ }
+ catch (IllegalAccessException ignore)
+ {
+ }
+
+ int num_good_fields = 0;
+ Field[] all_fields = cl.getDeclaredFields();
+
+ int modifiers;
+ // set non-serializable fields to null in all_fields
+ for (int i = 0; i < all_fields.length; i++)
+ {
+ modifiers = all_fields[i].getModifiers();
+ if (Modifier.isTransient(modifiers)
+ || Modifier.isStatic(modifiers))
+ all_fields[i] = null;
+ else
+ num_good_fields++;
+ }
+
+ // make a copy of serializable (non-null) fields
+ fields = new ObjectStreamField[ num_good_fields ];
+ for (int from = 0, to = 0; from < all_fields.length; from++)
+ if (all_fields[from] != null)
+ {
+ final Field f = all_fields[from];
+ setAccessible.setMember(f);
+ AccessController.doPrivileged(setAccessible);
+ fields[to] = new ObjectStreamField(all_fields[from]);
+ to++;
+ }
+
+ Arrays.sort(fields);
+ // Make sure we don't have any duplicate field names
+ // (Sun JDK 1.4.1. throws an Internal Error as well)
+ for (int i = 1; i < fields.length; i++)
+ {
+ if(fields[i - 1].getName().equals(fields[i].getName()))
+ throw new InternalError("Duplicate field " +
+ fields[i].getName() + " in class " + cl.getName());
+ }
+ calculateOffsets();
+ }
+
+ static Hashtable uidCache = new Hashtable();
+
+ // Returns the serial version UID defined by class, or if that
+ // isn't present, calculates value of serial version UID.
+ private long getClassUID(Class cl)
+ {
+ long result = 0;
+ Long cache = (Long) uidCache.get(cl);
+ if (cache != null)
+ result = cache.longValue();
+ else
+ {
+ // Note that we can't use Class.isEnum() here, because that returns
+ // false for java.lang.Enum and enum value sub classes.
+ if (Enum.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
+ {
+ // Spec says that enums and dynamic proxies have
+ // a serialVersionUID of 0L.
+ return 0L;
+ }
+ try
+ {
+ result = getClassUIDFromField(cl);
+ }
+ catch (NoSuchFieldException ignore)
+ {
+ try
+ {
+ result = calculateClassUID(cl);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new RuntimeException
+ ("The SHA algorithm was not found to use in computing the Serial Version UID for class "
+ + cl.getName(), e);
+ }
+ catch (IOException ioe)
+ {
+ throw new RuntimeException(ioe);
+ }
+ }
+
+ if (loadedByBootOrApplicationClassLoader(cl))
+ uidCache.put(cl,Long.valueOf(result));
+ }
+ return result;
+ }
+
+ /**
+ * Search for a serialVersionUID field in the given class and read
+ * its value.
+ *
+ * @return the contents of the serialVersionUID field
+ *
+ * @throws NoSuchFieldException if such a field does not exist or is
+ * not static, not final, not of type Long or not accessible.
+ */
+ long getClassUIDFromField(Class cl)
+ throws NoSuchFieldException
+ {
+ long result;
+
+ try
+ {
+ // Use getDeclaredField rather than getField, since serialVersionUID
+ // may not be public AND we only want the serialVersionUID of this
+ // class, not a superclass or interface.
+ final Field suid = cl.getDeclaredField("serialVersionUID");
+ SetAccessibleAction setAccessible = new SetAccessibleAction(suid);
+ AccessController.doPrivileged(setAccessible);
+ int modifiers = suid.getModifiers();
+
+ if (Modifier.isStatic(modifiers)
+ && Modifier.isFinal(modifiers)
+ && suid.getType() == Long.TYPE)
+ result = suid.getLong(null);
+ else
+ throw new NoSuchFieldException();
+ }
+ catch (IllegalAccessException ignore)
+ {
+ throw new NoSuchFieldException();
+ }
+
+ return result;
+ }
+
+ /**
+ * Calculate class serial version UID for a class that does not
+ * define serialVersionUID:
+ *
+ * @param cl a class
+ *
+ * @return the calculated serial varsion UID.
+ *
+ * @throws NoSuchAlgorithmException if SHA algorithm not found
+ *
+ * @throws IOException if writing to the DigestOutputStream causes
+ * an IOException.
+ */
+ long calculateClassUID(Class cl)
+ throws NoSuchAlgorithmException, IOException
+ {
+ long result;
+ MessageDigest md;
+ try
+ {
+ md = MessageDigest.getInstance("SHA");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // If a provider already provides SHA, use it; otherwise, use this.
+ Gnu gnuProvider = new Gnu();
+ Security.addProvider(gnuProvider);
+ md = MessageDigest.getInstance("SHA");
+ }
+
+ DigestOutputStream digest_out =
+ new DigestOutputStream(nullOutputStream, md);
+ DataOutputStream data_out = new DataOutputStream(digest_out);
+
+ data_out.writeUTF(cl.getName());
+
+ int modifiers = cl.getModifiers();
+ // just look at interesting bits
+ modifiers = modifiers & (Modifier.ABSTRACT | Modifier.FINAL
+ | Modifier.INTERFACE | Modifier.PUBLIC);
+ data_out.writeInt(modifiers);
+
+ // Pretend that an array has no interfaces, because when array
+ // serialization was defined (JDK 1.1), arrays didn't have it.
+ if (! cl.isArray())
+ {
+ Class[] interfaces = cl.getInterfaces();
+ Arrays.sort(interfaces, interfaceComparator);
+ for (int i = 0; i < interfaces.length; i++)
+ data_out.writeUTF(interfaces[i].getName());
+ }
+
+ Field field;
+ Field[] fields = cl.getDeclaredFields();
+ Arrays.sort(fields, memberComparator);
+ for (int i = 0; i < fields.length; i++)
+ {
+ field = fields[i];
+ modifiers = field.getModifiers();
+ if (Modifier.isPrivate(modifiers)
+ && (Modifier.isStatic(modifiers)
+ || Modifier.isTransient(modifiers)))
+ continue;
+
+ data_out.writeUTF(field.getName());
+ data_out.writeInt(modifiers);
+ data_out.writeUTF(TypeSignature.getEncodingOfClass (field.getType()));
+ }
+
+ // write class initializer method if present
+ if (VMObjectStreamClass.hasClassInitializer(cl))
+ {
+ data_out.writeUTF("<clinit>");
+ data_out.writeInt(Modifier.STATIC);
+ data_out.writeUTF("()V");
+ }
+
+ Constructor constructor;
+ Constructor[] constructors = cl.getDeclaredConstructors();
+ Arrays.sort (constructors, memberComparator);
+ for (int i = 0; i < constructors.length; i++)
+ {
+ constructor = constructors[i];
+ modifiers = constructor.getModifiers();
+ if (Modifier.isPrivate(modifiers))
+ continue;
+
+ data_out.writeUTF("<init>");
+ data_out.writeInt(modifiers);
+
+ // the replacement of '/' with '.' was needed to make computed
+ // SUID's agree with those computed by JDK
+ data_out.writeUTF
+ (TypeSignature.getEncodingOfConstructor(constructor).replace('/','.'));
+ }
+
+ Method method;
+ Method[] methods = cl.getDeclaredMethods();
+ Arrays.sort(methods, memberComparator);
+ for (int i = 0; i < methods.length; i++)
+ {
+ method = methods[i];
+ modifiers = method.getModifiers();
+ if (Modifier.isPrivate(modifiers))
+ continue;
+
+ data_out.writeUTF(method.getName());
+ data_out.writeInt(modifiers);
+
+ // the replacement of '/' with '.' was needed to make computed
+ // SUID's agree with those computed by JDK
+ data_out.writeUTF
+ (TypeSignature.getEncodingOfMethod(method).replace('/', '.'));
+ }
+
+ data_out.close();
+ byte[] sha = md.digest();
+ result = 0;
+ int len = sha.length < 8 ? sha.length : 8;
+ for (int i = 0; i < len; i++)
+ result += (long) (sha[i] & 0xFF) << (8 * i);
+
+ return result;
+ }
+
+ /**
+ * Returns the value of CLAZZ's private static final field named
+ * `serialPersistentFields'. It performs some sanity checks before
+ * returning the real array. Besides, the returned array is a clean
+ * copy of the original. So it can be modified.
+ *
+ * @param clazz Class to retrieve 'serialPersistentFields' from.
+ * @return The content of 'serialPersistentFields'.
+ */
+ private ObjectStreamField[] getSerialPersistentFields(Class clazz)
+ throws NoSuchFieldException, IllegalAccessException
+ {
+ ObjectStreamField[] fieldsArray = null;
+ ObjectStreamField[] o;
+
+ // Use getDeclaredField rather than getField for the same reason
+ // as above in getDefinedSUID.
+ Field f = clazz.getDeclaredField("serialPersistentFields");
+ f.setAccessible(true);
+
+ int modifiers = f.getModifiers();
+ if (!(Modifier.isStatic(modifiers) &&
+ Modifier.isFinal(modifiers) &&
+ Modifier.isPrivate(modifiers)))
+ return null;
+
+ o = (ObjectStreamField[]) f.get(null);
+
+ if (o == null)
+ return null;
+
+ fieldsArray = new ObjectStreamField[ o.length ];
+ System.arraycopy(o, 0, fieldsArray, 0, o.length);
+
+ return fieldsArray;
+ }
+
+ /**
+ * Returns a new instance of the Class this ObjectStreamClass corresponds
+ * to.
+ * Note that this should only be used for Externalizable classes.
+ *
+ * @return A new instance.
+ */
+ Externalizable newInstance() throws InvalidClassException
+ {
+ synchronized(this)
+ {
+ if (constructor == null)
+ {
+ try
+ {
+ final Constructor c = clazz.getConstructor(new Class[0]);
+
+ AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ c.setAccessible(true);
+ return null;
+ }
+ });
+
+ constructor = c;
+ }
+ catch(NoSuchMethodException x)
+ {
+ throw new InvalidClassException(clazz.getName(),
+ "No public zero-argument constructor");
+ }
+ }
+ }
+
+ try
+ {
+ return (Externalizable)constructor.newInstance();
+ }
+ catch(Exception x)
+ {
+ throw (InvalidClassException)
+ new InvalidClassException(clazz.getName(),
+ "Unable to instantiate").initCause(x);
+ }
+ }
+
+ public static final ObjectStreamField[] NO_FIELDS = {};
+
+ private static Hashtable<Class,ObjectStreamClass> classLookupTable
+ = new Hashtable<Class,ObjectStreamClass>();
+ private static final NullOutputStream nullOutputStream = new NullOutputStream();
+ private static final Comparator interfaceComparator = new InterfaceComparator();
+ private static final Comparator memberComparator = new MemberComparator();
+ private static final
+ Class[] writeMethodArgTypes = { java.io.ObjectOutputStream.class };
+
+ private ObjectStreamClass superClass;
+ private Class<?> clazz;
+ private String name;
+ private long uid;
+ private byte flags;
+
+ // this field is package protected so that ObjectInputStream and
+ // ObjectOutputStream can access it directly
+ ObjectStreamField[] fields;
+
+ // these are accessed by ObjectIn/OutputStream
+ int primFieldSize = -1; // -1 if not yet calculated
+ int objectFieldCount;
+
+ Method readObjectMethod;
+ Method readResolveMethod;
+ Method writeReplaceMethod;
+ Method writeObjectMethod;
+ boolean realClassIsSerializable;
+ boolean realClassIsExternalizable;
+ ObjectStreamField[] fieldMapping;
+ Constructor firstNonSerializableParentConstructor;
+ private Constructor constructor; // default constructor for Externalizable
+
+ boolean isProxyClass = false;
+
+/* GCJ LOCAL */
+ // True after setFields() has been called
+ private boolean fieldsSet = false;
+/* END GCJ LOCAL */
+
+ // This is probably not necessary because this class is special cased already
+ // but it will avoid showing up as a discrepancy when comparing SUIDs.
+ private static final long serialVersionUID = -6120832682080437368L;
+
+
+ // interfaces are compared only by name
+ private static final class InterfaceComparator implements Comparator
+ {
+ public int compare(Object o1, Object o2)
+ {
+ return ((Class) o1).getName().compareTo(((Class) o2).getName());
+ }
+ }
+
+
+ // Members (Methods and Constructors) are compared first by name,
+ // conflicts are resolved by comparing type signatures
+ private static final class MemberComparator implements Comparator
+ {
+ public int compare(Object o1, Object o2)
+ {
+ Member m1 = (Member) o1;
+ Member m2 = (Member) o2;
+
+ int comp = m1.getName().compareTo(m2.getName());
+
+ if (comp == 0)
+ return TypeSignature.getEncodingOfMember(m1).
+ compareTo(TypeSignature.getEncodingOfMember(m2));
+ else
+ return comp;
+ }
+ }
+}
diff --git a/libjava/classpath/java/io/ObjectStreamConstants.java b/libjava/classpath/java/io/ObjectStreamConstants.java
new file mode 100644
index 000000000..8f70196c9
--- /dev/null
+++ b/libjava/classpath/java/io/ObjectStreamConstants.java
@@ -0,0 +1,226 @@
+/* ObjectStreamConstants.java -- Interface containing constant values
+ used in reading and writing serialized objects
+ Copyright (C) 1998, 1999, 2003, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+/**
+ * This interface contains constants that are used in object
+ * serialization. This interface is used by <code>ObjectOutputStream</code>,
+ * <code>ObjectInputStream</code>, and <code>ObjectStreamClass</code>.
+ * The values for these constants are specified by the Java library
+ * specification.
+ *
+ * @since 1.1
+ */
+public interface ObjectStreamConstants
+{
+ /**
+ * The serialization stream protocol version 1. This version was
+ * the default serialization protocol before JDK 1.2.
+ *
+ * @see ObjectOutputStream#useProtocolVersion(int)
+ * @since 1.2
+ */
+ int PROTOCOL_VERSION_1 = 1;
+
+ /**
+ * The serialization stream protocol version 2. This version is
+ * used as the default serialization protocol since JDK 1.2.
+ *
+ * @see ObjectOutputStream#useProtocolVersion(int)
+ * @since 1.2
+ */
+ int PROTOCOL_VERSION_2 = 2;
+
+ /**
+ * The magic number that is written as part of the stream header.
+ */
+ short STREAM_MAGIC = (short)0xaced;
+
+ /**
+ * The stream version number that is written as part of the stream header.
+ * Note that this is different from the protocol version that specifies
+ * the data format for the stream.
+ */
+ short STREAM_VERSION = 5;
+
+ /**
+ * Token value to designate a <code>null</code> reference in the stream.
+ */
+ byte TC_NULL = (byte)112; //0x70
+
+ /**
+ * Token value to designate a reference to an already serialized object.
+ */
+ byte TC_REFERENCE = (byte)113; //0x71
+
+ /**
+ * Token value to designate a class descriptor is next in the stream.
+ */
+ byte TC_CLASSDESC = (byte)114; //0x72
+
+ /**
+ * Token value to designate a new object is next in the stream.
+ */
+ byte TC_OBJECT = (byte)115; //0x73
+
+ /**
+ * Token value to designate a new string is next in the stream.
+ */
+ byte TC_STRING = (byte)116; //0x74
+
+ /**
+ * Token value to designate a new array is next in the stream.
+ */
+ byte TC_ARRAY = (byte)117; //0x75
+
+ /**
+ * Token reference to designate a reference to a class.
+ */
+ byte TC_CLASS = (byte)118; //0x76
+
+ /**
+ * Token value to designate a block of primitive data is next in the stream.
+ * The next byte in the stream holds the size of the block (in bytes).
+ */
+ byte TC_BLOCKDATA = (byte)119; //0x77
+
+ /**
+ * Token value to designate the end of a block of primitve data.
+ */
+ byte TC_ENDBLOCKDATA = (byte)120; //0x78
+
+ /**
+ * Token value to designate a reset of the stream state.
+ */
+ byte TC_RESET = (byte)121; //0x79
+
+ /**
+ * Token value to designate a long block of primitive data is next in the
+ * stream. The next long in the stream holds the size of the block
+ * (in bytes).
+ */
+ byte TC_BLOCKDATALONG = (byte)122; //0x7A
+
+ /**
+ * Token value to designate an exception occured during serialization.
+ */
+ byte TC_EXCEPTION = (byte)123; //0x7B
+
+ /**
+ * Token value to designate a long string is next in the stream.
+ */
+ byte TC_LONGSTRING = (byte)124; //0x7C
+
+ /**
+ * Token value to designate a proxy class descriptor is next in the stream.
+ */
+ byte TC_PROXYCLASSDESC = (byte)125; //0x7D
+
+ /**
+ * Token value to designate an enum constant is next in the stream.
+ *
+ * @since 1.5
+ */
+ byte TC_ENUM = (byte)126; //0x7E
+
+ /**
+ * The first token value.
+ */
+ byte TC_BASE = TC_NULL;
+
+ /**
+ * The last token value.
+ */
+ byte TC_MAX = TC_ENUM;
+
+ /**
+ * The first handle that will be assigned to an object, for later references.
+ */
+ int baseWireHandle = 0x7e0000;
+
+ /**
+ * Flag used in <code>ObjectStreamClass</code> to designate that the class
+ * defines the <code>writeObject</code> method.
+ */
+ byte SC_WRITE_METHOD = 0x01;
+
+ /**
+ * Flag used in <code>ObjectStreamClass</code> to designate that the class
+ * is serializeable.
+ */
+ byte SC_SERIALIZABLE = 0x02;
+
+ /**
+ * Flag used in <code>ObjectStreamClass</code> to designate that the class
+ * is externalizable.
+ */
+ byte SC_EXTERNALIZABLE = 0x04;
+
+ /**
+ * Flag used in <code>ObjectStreamClass</code> to designate that
+ * externalizable data is written in block data mode.
+ *
+ * @since 1.2
+ */
+ byte SC_BLOCK_DATA = 0x08;
+
+ /**
+ * Flag used in <code>ObjectStreamClass</code> to designate that the class
+ * is an enum constant.
+ *
+ * @since 1.5
+ */
+ byte SC_ENUM = 0x10;
+
+ /**
+ * Constant for use with a <code>SecurityManager</code> to check if
+ * substitution of objects is allowed.
+ */
+ SerializablePermission SUBSTITUTION_PERMISSION
+ = new SerializablePermission("enableSubstitution");
+
+ /**
+ * Constant for use with a <code>SecurityManager</code> to check if
+ * overriding of the <code>writeObject</code> and <code>readObject</code>
+ * methods is allowed.
+ */
+ SerializablePermission SUBCLASS_IMPLEMENTATION_PERMISSION
+ = new SerializablePermission("enableSubclassImplementation");
+}
diff --git a/libjava/classpath/java/io/ObjectStreamException.java b/libjava/classpath/java/io/ObjectStreamException.java
new file mode 100644
index 000000000..61d4dd09e
--- /dev/null
+++ b/libjava/classpath/java/io/ObjectStreamException.java
@@ -0,0 +1,74 @@
+/* ObjectStreamException.java -- Superclass of all serialization exceptions
+ Copyright (C) 1998, 2000, 2001, 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 java.io;
+
+/**
+ * This exception is thrown when a problem occurs during serialization.
+ * There are more specific subclasses that give more fine grained
+ * indications of the precise failure.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public abstract class ObjectStreamException extends IOException
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = 7260898174833392607L;
+
+ /**
+ * Create an exception without a descriptive error message.
+ */
+ protected ObjectStreamException()
+ {
+ }
+
+ /**
+ * Create an exception with a descriptive error message.
+ *
+ * @param message the descriptive error message
+ */
+ protected ObjectStreamException(String message)
+ {
+ super(message);
+ }
+} // class ObjectStreamException
diff --git a/libjava/classpath/java/io/ObjectStreamField.java b/libjava/classpath/java/io/ObjectStreamField.java
new file mode 100644
index 000000000..dfb6728a7
--- /dev/null
+++ b/libjava/classpath/java/io/ObjectStreamField.java
@@ -0,0 +1,401 @@
+/* ObjectStreamField.java -- Class used to store name and class of fields
+ Copyright (C) 1998, 1999, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+import gnu.java.lang.reflect.TypeSignature;
+
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * This class intends to describe the field of a class for the serialization
+ * subsystem. Serializable fields in a serializable class can be explicitly
+ * exported using an array of ObjectStreamFields.
+ *
+ * @author Tom Tromey (tromey@redhat.com)
+ * @author Jeroen Frijters (jeroen@frijters.net)
+ * @author Guilhem Lavaux (guilhem@kaffe.org)
+ * @author Michael Koch (konqueror@gmx.de)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+public class ObjectStreamField
+ implements Comparable<Object>
+{
+ private String name;
+ private Class<?> type;
+ private String typename;
+ private int offset = -1; // XXX make sure this is correct
+ private boolean unshared;
+ private boolean persistent = false;
+ private boolean toset = true;
+ Field field;
+
+ ObjectStreamField (Field field)
+ {
+ this (field.getName(), field.getType());
+ this.field = field;
+ }
+
+ /**
+ * This constructor creates an ObjectStreamField instance
+ * which represents a field named <code>name</code> and is
+ * of the type <code>type</code>.
+ *
+ * @param name Name of the field to export.
+ * @param type Type of the field in the concerned class.
+ */
+ public ObjectStreamField (String name, Class<?> type)
+ {
+ this (name, type, false);
+ }
+
+ /**
+ * This constructor creates an ObjectStreamField instance
+ * which represents a field named <code>name</code> and is
+ * of the type <code>type</code>.
+ *
+ * @param name Name of the field to export.
+ * @param type Type of the field in the concerned class.
+ * @param unshared true if field will be unshared, false otherwise.
+ */
+ public ObjectStreamField (String name, Class<?> type, boolean unshared)
+ {
+ if (name == null)
+ throw new NullPointerException();
+
+ this.name = name;
+ this.type = type;
+ this.typename = TypeSignature.getEncodingOfClass(type);
+ this.unshared = unshared;
+ }
+
+ /**
+ * There are many cases you can not get java.lang.Class from typename
+ * if your context class loader cannot load it, then use typename to
+ * construct the field.
+ *
+ * @param name Name of the field to export.
+ * @param typename The coded name of the type for this field.
+ */
+ ObjectStreamField (String name, String typename)
+ {
+ this.name = name;
+ this.typename = typename;
+ }
+
+ void resolveType(ClassLoader loader)
+ {
+ try
+ {
+ type = TypeSignature.getClassForEncoding(typename, true, loader);
+ }
+ catch(ClassNotFoundException e)
+ {
+ }
+ }
+
+ /**
+ * This method returns the name of the field represented by the
+ * ObjectStreamField instance.
+ *
+ * @return A string containing the name of the field.
+ */
+ public String getName ()
+ {
+ return name;
+ }
+
+ /**
+ * This method returns the class representing the type of the
+ * field which is represented by this instance of ObjectStreamField.
+ *
+ * @return A class representing the type of the field.
+ */
+ public Class<?> getType ()
+ {
+ return type;
+ }
+
+ /**
+ * This method returns the char encoded type of the field which
+ * is represented by this instance of ObjectStreamField.
+ *
+ * @return A char representing the type of the field.
+ */
+ public char getTypeCode ()
+ {
+ return typename.charAt (0);
+ }
+
+ /**
+ * This method returns a more explicit type name than
+ * {@link #getTypeCode()} in the case the type is a real
+ * class (and not a primitive).
+ *
+ * @return The name of the type (class name) if it is not a
+ * primitive, in the other case null is returned.
+ */
+ public String getTypeString ()
+ {
+ // use intern()
+ if (isPrimitive())
+ return null;
+ return typename.intern();
+ }
+
+ /**
+ * This method returns the current offset of the field in
+ * the serialization stream relatively to the other fields.
+ * The offset is expressed in bytes.
+ *
+ * @return The offset of the field in bytes.
+ * @see #setOffset(int)
+ */
+ public int getOffset ()
+ {
+ return offset;
+ }
+
+ /**
+ * This method sets the current offset of the field.
+ *
+ * @param off The offset of the field in bytes.
+ * @see #getOffset()
+ */
+ protected void setOffset (int off)
+ {
+ offset = off;
+ }
+
+ /**
+ * This method returns whether the field represented by this object is
+ * unshared or not.
+ *
+ * @return Tells if this field is unshared or not.
+ */
+ public boolean isUnshared ()
+ {
+ return unshared;
+ }
+
+ /**
+ * This method returns true if the type of the field
+ * represented by this instance is a primitive.
+ *
+ * @return true if the type is a primitive, false
+ * in the other case.
+ */
+ public boolean isPrimitive ()
+ {
+ return typename.length() == 1;
+ }
+
+ /**
+ * Compares this object to the given object.
+ *
+ * @param obj the object to compare to.
+ *
+ * @return -1, 0 or 1.
+ */
+ public int compareTo (Object obj)
+ {
+ ObjectStreamField f = (ObjectStreamField) obj;
+ boolean this_is_primitive = isPrimitive ();
+ boolean f_is_primitive = f.isPrimitive ();
+
+ if (this_is_primitive && !f_is_primitive)
+ return -1;
+
+ if (!this_is_primitive && f_is_primitive)
+ return 1;
+
+ return getName ().compareTo (f.getName ());
+ }
+
+ /**
+ * This method is specific to classpath's implementation and so has the default
+ * access. It changes the state of this field to "persistent". It means that
+ * the field should not be changed when the stream is read (if it is not
+ * explicitly specified using serialPersistentFields).
+ *
+ * @param persistent True if the field is persistent, false in the
+ * other cases.
+ * @see #isPersistent()
+ */
+ void setPersistent(boolean persistent)
+ {
+ this.persistent = persistent;
+ }
+
+ /**
+ * This method returns true if the field is marked as persistent.
+ *
+ * @return True if persistent, false in the other cases.
+ * @see #setPersistent(boolean)
+ */
+ boolean isPersistent()
+ {
+ return persistent;
+ }
+
+ /**
+ * This method is specific to classpath's implementation and so
+ * has the default access. It changes the state of this field as
+ * to be set by ObjectInputStream.
+ *
+ * @param toset True if this field should be set, false in the other
+ * cases.
+ * @see #isToSet()
+ */
+ void setToSet(boolean toset)
+ {
+ this.toset = toset;
+ }
+
+ /**
+ * This method returns true if the field is marked as to be
+ * set.
+ *
+ * @return True if it is to be set, false in the other cases.
+ * @see #setToSet(boolean)
+ */
+ boolean isToSet()
+ {
+ return toset;
+ }
+
+ /**
+ * This method searches for its field reference in the specified class
+ * object. It requests privileges. If an error occurs the internal field
+ * reference is not modified.
+ *
+ * @throws NoSuchFieldException if the field name does not exist in this class.
+ * @throws SecurityException if there was an error requesting the privileges.
+ */
+ void lookupField(Class clazz) throws NoSuchFieldException, SecurityException
+ {
+ final Field f = clazz.getDeclaredField(name);
+
+ AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ f.setAccessible(true);
+ return null;
+ }
+ });
+
+ this.field = f;
+ }
+
+ /**
+ * This method check whether the field described by this
+ * instance of ObjectStreamField is compatible with the
+ * actual implementation of this field.
+ *
+ * @throws NullPointerException if this field does not exist
+ * in the real class.
+ * @throws InvalidClassException if the types are incompatible.
+ */
+ void checkFieldType() throws InvalidClassException
+ {
+ Class<?> ftype = field.getType();
+
+ if (!ftype.isAssignableFrom(type))
+ throw new InvalidClassException
+ ("invalid field type for " + name +
+ " in class " + field.getDeclaringClass());
+ }
+
+ /**
+ * Returns a string representing this object.
+ *
+ * @return the string.
+ */
+ public String toString ()
+ {
+ return "ObjectStreamField< " + type + " " + name + " >";
+ }
+
+ final void setBooleanField(Object obj, boolean val)
+ {
+ VMObjectStreamClass.setBooleanNative(field, obj, val);
+ }
+
+ final void setByteField(Object obj, byte val)
+ {
+ VMObjectStreamClass.setByteNative(field, obj, val);
+ }
+
+ final void setCharField(Object obj, char val)
+ {
+ VMObjectStreamClass.setCharNative(field, obj, val);
+ }
+
+ final void setShortField(Object obj, short val)
+ {
+ VMObjectStreamClass.setShortNative(field, obj, val);
+ }
+
+ final void setIntField(Object obj, int val)
+ {
+ VMObjectStreamClass.setIntNative(field, obj, val);
+ }
+
+ final void setLongField(Object obj, long val)
+ {
+ VMObjectStreamClass.setLongNative(field, obj, val);
+ }
+
+ final void setFloatField(Object obj, float val)
+ {
+ VMObjectStreamClass.setFloatNative(field, obj, val);
+ }
+
+ final void setDoubleField(Object obj, double val)
+ {
+ VMObjectStreamClass.setDoubleNative(field, obj, val);
+ }
+
+ final void setObjectField(Object obj, Object val)
+ {
+ VMObjectStreamClass.setObjectNative(field, obj, val);
+ }
+}
diff --git a/libjava/classpath/java/io/OptionalDataException.java b/libjava/classpath/java/io/OptionalDataException.java
new file mode 100644
index 000000000..8d8b1bda0
--- /dev/null
+++ b/libjava/classpath/java/io/OptionalDataException.java
@@ -0,0 +1,91 @@
+/* OptionalDataException.java -- indicates unexpected data in serialized stream
+ Copyright (C) 1998, 2000, 2001, 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 java.io;
+
+/**
+ * This exception is thrown when unexpected data appears in the input
+ * stream from which a serialized object is being read. There are two
+ * cases:<br><ul>
+ * <li>The next stream element is primitive data. <code>eof</code> will
+ * be false, and <code>count</code> is the number of bytes of primitive
+ * data available.</li>
+ * <li>The data consumable by readObject or readExternal has been exhausted.
+ * <code>eof</code> is true, and <code>count</code> is 0.</li>
+ * </ul>
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class OptionalDataException extends ObjectStreamException
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = -8011121865681257820L;
+
+ /**
+ * Whether or not the end of the stream has been reached.
+ *
+ * @serial the end of the buffer was reached
+ */
+ public boolean eof;
+
+ /**
+ * The number of valid bytes that can be read.
+ *
+ * @serial the bytes of the buffer remaining
+ */
+ public int length;
+
+ /**
+ * Create a new OptionalDataException with an eof parameter indicating
+ * whether or not the end of stream is reached and the number of valid
+ * bytes that may be read.
+ *
+ * @param eof 'true' if end of stream reached, 'false' otherwise
+ * @param count The number of valid bytes to be read
+ */
+ OptionalDataException(boolean eof, int count)
+ {
+ this.eof = eof;
+ this.length = count;
+ }
+} // class OptionalDataException
diff --git a/libjava/classpath/java/io/OutputStream.java b/libjava/classpath/java/io/OutputStream.java
new file mode 100644
index 000000000..5ba9478e3
--- /dev/null
+++ b/libjava/classpath/java/io/OutputStream.java
@@ -0,0 +1,140 @@
+/* OutputStream.java -- Base class for byte output streams
+ Copyright (C) 1998, 1999, 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 java.io;
+
+/**
+ * This abstract class forms the base of the hierarchy of classes that
+ * write output as a stream of bytes. It provides a common set of methods
+ * for writing bytes to stream. Subclasses implement and/or extend these
+ * methods to write bytes in a particular manner or to a particular
+ * destination such as a file on disk or network connection.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ */
+public abstract class OutputStream implements Closeable, Flushable
+{
+ /**
+ * This is the default no-argument constructor for this class. This method
+ * does nothing in this class.
+ */
+ public OutputStream ()
+ {
+ }
+
+ /**
+ * This method writes a single byte to the output stream. The byte written
+ * is the low eight bits of the <code>int</code> passed and a argument.
+ * <p>
+ * Subclasses must provide an implementation of this abstract method
+ *
+ * @param b The byte to be written to the output stream, passed as
+ * the low eight bits of an <code>int</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public abstract void write (int b) throws IOException;
+
+ /**
+ * This method all the writes bytes from the passed array to the
+ * output stream. This method is equivalent to <code>write(b, 0,
+ * buf.length)</code> which is exactly how it is implemented in this
+ * class.
+ *
+ * @param b The array of bytes to write
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (byte[] b) throws IOException, NullPointerException
+ {
+ write (b, 0, b.length);
+ }
+
+ /**
+ * This method writes <code>len</code> bytes from the specified array
+ * <code>b</code> starting at index <code>off</code> into the array.
+ * <p>
+ * This method in this class calls the single byte <code>write()</code>
+ * method in a loop until all bytes have been written. Subclasses should
+ * override this method if possible in order to provide a more efficent
+ * implementation.
+ *
+ * @param b The array of bytes to write from
+ * @param off The index into the array to start writing from
+ * @param len The number of bytes to write
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (byte[] b, int off, int len)
+ throws IOException, NullPointerException, IndexOutOfBoundsException
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException ();
+ for (int i = 0; i < len; ++i)
+ write (b[off + i]);
+ }
+
+ /**
+ * This method forces any data that may have been buffered to be written
+ * to the underlying output device. Please note that the host environment
+ * might perform its own buffering unbeknowst to Java. In that case, a
+ * write made (for example, to a disk drive) might be cached in OS
+ * buffers instead of actually being written to disk.
+ * <p>
+ * This method in this class does nothing.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void flush () throws IOException
+ {
+ }
+
+ /**
+ * This method closes the stream. Any internal or native resources
+ * associated with this stream are freed. Any subsequent attempt to
+ * access the stream might throw an exception.
+ * <p>
+ * This method in this class does nothing.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close () throws IOException
+ {
+ }
+}
diff --git a/libjava/classpath/java/io/OutputStreamWriter.java b/libjava/classpath/java/io/OutputStreamWriter.java
new file mode 100644
index 000000000..27067fdb9
--- /dev/null
+++ b/libjava/classpath/java/io/OutputStreamWriter.java
@@ -0,0 +1,429 @@
+/* OutputStreamWriter.java -- Writer that converts chars to bytes
+ Copyright (C) 1998, 1999, 2000, 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 java.io;
+
+import gnu.java.nio.charset.EncodingHelper;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.MalformedInputException;
+
+/**
+ * This class writes characters to an output stream that is byte oriented
+ * It converts the chars that are written to bytes using an encoding layer,
+ * which is specific to a particular encoding standard. The desired
+ * encoding can either be specified by name, or if no encoding is specified,
+ * the system default encoding will be used. The system default encoding
+ * name is determined from the system property <code>file.encoding</code>.
+ * The only encodings that are guaranteed to be available are "8859_1"
+ * (the Latin-1 character set) and "UTF8". Unfortunately, Java does not
+ * provide a mechanism for listing the encodings that are supported in
+ * a given implementation.
+ * <p>
+ * Here is a list of standard encoding names that may be available:
+ * <p>
+ * <ul>
+ * <li>8859_1 (ISO-8859-1/Latin-1)
+ * <li>8859_2 (ISO-8859-2/Latin-2)
+ * <li>8859_3 (ISO-8859-3/Latin-3)
+ * <li>8859_4 (ISO-8859-4/Latin-4)
+ * <li>8859_5 (ISO-8859-5/Latin-5)
+ * <li>8859_6 (ISO-8859-6/Latin-6)
+ * <li>8859_7 (ISO-8859-7/Latin-7)
+ * <li>8859_8 (ISO-8859-8/Latin-8)
+ * <li>8859_9 (ISO-8859-9/Latin-9)
+ * <li>ASCII (7-bit ASCII)
+ * <li>UTF8 (UCS Transformation Format-8)
+ * <li>More Later
+ * </ul>
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Per Bothner (bothner@cygnus.com)
+ * @date April 17, 1998.
+ */
+public class OutputStreamWriter extends Writer
+{
+ /**
+ * The output stream.
+ */
+ private OutputStream out;
+
+ /**
+ * The charset encoder.
+ */
+ private final CharsetEncoder encoder;
+
+ /**
+ * java.io canonical name of the encoding.
+ */
+ private final String encodingName;
+
+ /**
+ * Buffer output before character conversion as it has costly overhead.
+ */
+ private final CharBuffer outputBuffer;
+ private final static int BUFFER_SIZE = 1024;
+
+ /**
+ * This method initializes a new instance of <code>OutputStreamWriter</code>
+ * to write to the specified stream using a caller supplied character
+ * encoding scheme. Note that due to a deficiency in the Java language
+ * design, there is no way to determine which encodings are supported.
+ *
+ * @param out The <code>OutputStream</code> to write to
+ * @param encoding_scheme The name of the encoding scheme to use for
+ * character to byte translation
+ *
+ * @exception UnsupportedEncodingException If the named encoding is
+ * not available.
+ */
+ public OutputStreamWriter (OutputStream out, String encoding_scheme)
+ throws UnsupportedEncodingException
+ {
+ CharsetEncoder encoder;
+ String encodingName;
+ this.out = out;
+ outputBuffer = CharBuffer.allocate(BUFFER_SIZE);
+
+ try
+ {
+ // Don't use NIO if avoidable
+ if(EncodingHelper.isISOLatin1(encoding_scheme))
+ {
+ encodingName = "ISO8859_1";
+ encoder = null;
+ }
+ else
+ {
+ /*
+ * Workaround for encodings with a byte-order-mark.
+ * We only want to write it once per stream.
+ */
+ try
+ {
+ if(encoding_scheme.equalsIgnoreCase("UnicodeBig") ||
+ encoding_scheme.equalsIgnoreCase("UTF-16") ||
+ encoding_scheme.equalsIgnoreCase("UTF16"))
+ {
+ encoding_scheme = "UTF-16BE";
+ out.write((byte)0xFE);
+ out.write((byte)0xFF);
+ }
+ else if(encoding_scheme.equalsIgnoreCase("UnicodeLittle"))
+ {
+ encoding_scheme = "UTF-16LE";
+ out.write((byte)0xFF);
+ out.write((byte)0xFE);
+ }
+ }
+ catch(IOException ioe)
+ {
+ }
+
+ Charset cs = EncodingHelper.getCharset(encoding_scheme);
+ if(cs == null)
+ throw new UnsupportedEncodingException("Encoding "+encoding_scheme+
+ " unknown");
+ encoder = cs.newEncoder();
+ encodingName = EncodingHelper.getOldCanonical(cs.name());
+
+ encoder.onMalformedInput(CodingErrorAction.REPLACE);
+ encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+ }
+ catch(RuntimeException e)
+ {
+ // Default to ISO Latin-1, will happen if this is called, for instance,
+ // before the NIO provider is loadable.
+ encoder = null;
+ encodingName = "ISO8859_1";
+ }
+ this.encoder = encoder;
+ this.encodingName = encodingName;
+ }
+
+ /**
+ * This method initializes a new instance of <code>OutputStreamWriter</code>
+ * to write to the specified stream using the default encoding.
+ *
+ * @param out The <code>OutputStream</code> to write to
+ */
+ public OutputStreamWriter (OutputStream out)
+ {
+ CharsetEncoder encoder;
+ String encodingName;
+ this.out = out;
+ outputBuffer = CharBuffer.allocate(BUFFER_SIZE);
+ try
+ {
+ String encoding = System.getProperty("file.encoding");
+ Charset cs = Charset.forName(encoding);
+ encoder = cs.newEncoder();
+ encodingName = EncodingHelper.getOldCanonical(cs.name());
+ }
+ catch(RuntimeException e)
+ {
+ encoder = null;
+ encodingName = "ISO8859_1";
+ }
+
+ if(encoder != null)
+ {
+ encoder.onMalformedInput(CodingErrorAction.REPLACE);
+ encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+ this.encoder = encoder;
+ this.encodingName = encodingName;
+ }
+
+ /**
+ * This method initializes a new instance of <code>OutputStreamWriter</code>
+ * to write to the specified stream using a given <code>Charset</code>.
+ *
+ * @param out The <code>OutputStream</code> to write to
+ * @param cs The <code>Charset</code> of the encoding to use
+ *
+ * @since 1.5
+ */
+ public OutputStreamWriter(OutputStream out, Charset cs)
+ {
+ this.out = out;
+ encoder = cs.newEncoder();
+ encoder.onMalformedInput(CodingErrorAction.REPLACE);
+ encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ outputBuffer = CharBuffer.allocate(BUFFER_SIZE);
+ encodingName = EncodingHelper.getOldCanonical(cs.name());
+ }
+
+ /**
+ * This method initializes a new instance of <code>OutputStreamWriter</code>
+ * to write to the specified stream using a given
+ * <code>CharsetEncoder</code>.
+ *
+ * @param out The <code>OutputStream</code> to write to
+ * @param enc The <code>CharsetEncoder</code> to encode the output with
+ *
+ * @since 1.5
+ */
+ public OutputStreamWriter(OutputStream out, CharsetEncoder enc)
+ {
+ this.out = out;
+ encoder = enc;
+ outputBuffer = CharBuffer.allocate(BUFFER_SIZE);
+ Charset cs = enc.charset();
+ if (cs == null)
+ encodingName = "US-ASCII";
+ else
+ encodingName = EncodingHelper.getOldCanonical(cs.name());
+ }
+
+ /**
+ * This method closes this stream, and the underlying
+ * <code>OutputStream</code>
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close () throws IOException
+ {
+ if(out == null)
+ return;
+ flush();
+ out.close ();
+ out = null;
+ }
+
+ /**
+ * This method returns the name of the character encoding scheme currently
+ * in use by this stream. If the stream has been closed, then this method
+ * may return <code>null</code>.
+ *
+ * @return The encoding scheme name
+ */
+ public String getEncoding ()
+ {
+ return out != null ? encodingName : null;
+ }
+
+ /**
+ * This method flushes any buffered bytes to the underlying output sink.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void flush () throws IOException
+ {
+ if(out != null){
+ if(outputBuffer != null){
+ char[] buf = new char[outputBuffer.position()];
+ if(buf.length > 0){
+ outputBuffer.flip();
+ outputBuffer.get(buf);
+ writeConvert(buf, 0, buf.length);
+ outputBuffer.clear();
+ }
+ }
+ out.flush ();
+ }
+ }
+
+ /**
+ * This method writes <code>count</code> characters from the specified
+ * array to the output stream starting at position <code>offset</code>
+ * into the array.
+ *
+ * @param buf The array of character to write from
+ * @param offset The offset into the array to start writing chars from
+ * @param count The number of chars to write.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (char[] buf, int offset, int count) throws IOException
+ {
+ if(out == null)
+ throw new IOException("Stream is closed.");
+ if(buf == null)
+ throw new IOException("Buffer is null.");
+
+ if(outputBuffer != null)
+ {
+ if(count >= outputBuffer.remaining())
+ {
+ int r = outputBuffer.remaining();
+ outputBuffer.put(buf, offset, r);
+ writeConvert(outputBuffer.array(), 0, BUFFER_SIZE);
+ outputBuffer.clear();
+ offset += r;
+ count -= r;
+ // if the remaining bytes is larger than the whole buffer,
+ // just don't buffer.
+ if(count >= outputBuffer.remaining()){
+ writeConvert(buf, offset, count);
+ return;
+ }
+ }
+ outputBuffer.put(buf, offset, count);
+ } else writeConvert(buf, offset, count);
+ }
+
+ /**
+ * Converts and writes characters.
+ */
+ private void writeConvert (char[] buf, int offset, int count)
+ throws IOException
+ {
+ if(encoder == null)
+ {
+ byte[] b = new byte[count];
+ for(int i=0;i<count;i++)
+ b[i] = nullConversion(buf[offset+i]);
+ out.write(b);
+ } else {
+ try {
+ ByteBuffer output = encoder.encode(CharBuffer.wrap(buf,offset,count));
+ encoder.reset();
+ if(output.hasArray())
+ out.write(output.array());
+ else
+ {
+ byte[] outbytes = new byte[output.remaining()];
+ output.get(outbytes);
+ out.write(outbytes);
+ }
+ } catch(IllegalStateException e) {
+ throw new IOException("Internal error.");
+ } catch(MalformedInputException e) {
+ throw new IOException("Invalid character sequence.");
+ } catch(CharacterCodingException e) {
+ throw new IOException("Unmappable character.");
+ }
+ }
+ }
+
+ private byte nullConversion(char c) {
+ return (byte)((c <= 0xFF)?c:'?');
+ }
+
+ /**
+ * This method writes <code>count</code> bytes from the specified
+ * <code>String</code> starting at position <code>offset</code> into the
+ * <code>String</code>.
+ *
+ * @param str The <code>String</code> to write chars from
+ * @param offset The position in the <code>String</code> to start
+ * writing chars from
+ * @param count The number of chars to write
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (String str, int offset, int count) throws IOException
+ {
+ if(str == null)
+ throw new IOException("String is null.");
+
+ write(str.toCharArray(), offset, count);
+ }
+
+ /**
+ * This method writes a single character to the output stream.
+ *
+ * @param ch The char to write, passed as an int.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (int ch) throws IOException
+ {
+ // No buffering, no encoding ... just pass through
+ if (encoder == null && outputBuffer == null) {
+ out.write(nullConversion((char)ch));
+ } else {
+ if (outputBuffer != null) {
+ if (outputBuffer.remaining() == 0) {
+ writeConvert(outputBuffer.array(), 0, BUFFER_SIZE);
+ outputBuffer.clear();
+ }
+ outputBuffer.put((char)ch);
+ } else {
+ writeConvert(new char[]{ (char)ch }, 0, 1);
+ }
+ }
+ }
+} // class OutputStreamWriter
diff --git a/libjava/classpath/java/io/PipedInputStream.java b/libjava/classpath/java/io/PipedInputStream.java
new file mode 100644
index 000000000..0171a1b6f
--- /dev/null
+++ b/libjava/classpath/java/io/PipedInputStream.java
@@ -0,0 +1,413 @@
+/* PipedInputStream.java -- Read portion of piped streams.
+ Copyright (C) 1998, 1999, 2000, 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 java.io;
+
+// NOTE: This implementation is very similar to that of PipedReader. If you
+// fix a bug in here, chances are you should make a similar change to the
+// PipedReader code.
+
+/**
+ * An input stream that reads its bytes from an output stream
+ * to which it is connected.
+ * <p>
+ * Data is read and written to an internal buffer. It is highly recommended
+ * that the <code>PipedInputStream</code> and connected
+ * <code>PipedOutputStream</code>
+ * be part of different threads. If they are not, the read and write
+ * operations could deadlock their thread.
+ *
+ * @specnote The JDK implementation appears to have some undocumented
+ * functionality where it keeps track of what thread is writing
+ * to pipe and throws an IOException if that thread susequently
+ * dies. This behaviour seems dubious and unreliable - we don't
+ * implement it.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class PipedInputStream extends InputStream
+{
+ /** PipedOutputStream to which this is connected. Null only if this
+ * InputStream hasn't been connected yet. */
+ PipedOutputStream source;
+
+ /** Set to true if close() has been called on this InputStream. */
+ boolean closed;
+
+
+ /**
+ * The size of the internal buffer used for input/output.
+ */
+ /* The "Constant Field Values" Javadoc of the Sun J2SE 1.4
+ * specifies 1024.
+ */
+ protected static final int PIPE_SIZE = 1024;
+
+
+ /**
+ * This is the internal circular buffer used for storing bytes written
+ * to the pipe and from which bytes are read by this stream
+ */
+ protected byte[] buffer = null;
+
+ /**
+ * The index into buffer where the next byte from the connected
+ * <code>PipedOutputStream</code> will be written. If this variable is
+ * equal to <code>out</code>, then the buffer is full. If set to < 0,
+ * the buffer is empty.
+ */
+ protected int in = -1;
+
+ /**
+ * This index into the buffer where bytes will be read from.
+ */
+ protected int out = 0;
+
+ /** Buffer used to implement single-argument read/receive */
+ private byte[] read_buf = new byte[1];
+
+ /**
+ * Creates a new <code>PipedInputStream</code> that is not connected to a
+ * <code>PipedOutputStream</code>. It must be connected before bytes can
+ * be read from this stream.
+ */
+ public PipedInputStream()
+ {
+ this(PIPE_SIZE);
+ }
+
+ /**
+ * Creates a new <code>PipedInputStream</code> of the given size that is not
+ * connected to a <code>PipedOutputStream</code>.
+ * It must be connected before bytes can be read from this stream.
+ *
+ * @since 1.6
+ * @since IllegalArgumentException If pipeSize <= 0.
+ */
+ public PipedInputStream(int pipeSize) throws IllegalArgumentException
+ {
+ if (pipeSize <= 0)
+ throw new IllegalArgumentException("pipeSize must be > 0");
+
+ this.buffer = new byte[pipeSize];
+ }
+
+ /**
+ * This constructor creates a new <code>PipedInputStream</code> and connects
+ * it to the passed in <code>PipedOutputStream</code>. The stream is then
+ * ready for reading.
+ *
+ * @param source The <code>PipedOutputStream</code> to connect this
+ * stream to
+ *
+ * @exception IOException If <code>source</code> is already connected.
+ */
+ public PipedInputStream(PipedOutputStream source) throws IOException
+ {
+ this();
+ connect(source);
+ }
+
+ /**
+ * This constructor creates a new <code>PipedInputStream</code> of the given
+ * size and connects it to the passed in <code>PipedOutputStream</code>.
+ * The stream is then ready for reading.
+ *
+ * @param source The <code>PipedOutputStream</code> to connect this
+ * stream to
+ *
+ * @since 1.6
+ * @exception IOException If <code>source</code> is already connected.
+ */
+ public PipedInputStream(PipedOutputStream source, int pipeSize)
+ throws IOException
+ {
+ this(pipeSize);
+ connect(source);
+ }
+
+ /**
+ * This method connects this stream to the passed in
+ * <code>PipedOutputStream</code>.
+ * This stream is then ready for reading. If this stream is already
+ * connected or has been previously closed, then an exception is thrown
+ *
+ * @param source The <code>PipedOutputStream</code> to connect this stream to
+ *
+ * @exception IOException If this PipedInputStream or <code>source</code>
+ * has been connected already.
+ */
+ public void connect(PipedOutputStream source) throws IOException
+ {
+ // The JDK (1.3) does not appear to check for a previously closed
+ // connection here.
+
+ if (this.source != null || source.sink != null)
+ throw new IOException ("Already connected");
+
+ source.sink = this;
+ this.source = source;
+ }
+
+ /**
+ * This method receives a byte of input from the source PipedOutputStream.
+ * If the internal circular buffer is full, this method blocks.
+ *
+ * @param val The byte to write to this stream
+ *
+ * @exception IOException if error occurs
+ * @specnote Weird. This method must be some sort of accident.
+ */
+ protected synchronized void receive(int val) throws IOException
+ {
+ read_buf[0] = (byte) (val & 0xff);
+ receive (read_buf, 0, 1);
+ }
+
+ /**
+ * This method is used by the connected <code>PipedOutputStream</code> to
+ * write bytes into the buffer.
+ *
+ * @param buf The array containing bytes to write to this stream
+ * @param offset The offset into the array to start writing from
+ * @param len The number of bytes to write.
+ *
+ * @exception IOException If an error occurs
+ * @specnote This code should be in PipedOutputStream.write, but we
+ * put it here in order to support that bizarre recieve(int)
+ * method.
+ */
+ synchronized void receive(byte[] buf, int offset, int len)
+ throws IOException
+ {
+ if (closed)
+ throw new IOException ("Pipe closed");
+
+ int bufpos = offset;
+ int copylen;
+
+ while (len > 0)
+ {
+ try
+ {
+ while (in == out)
+ {
+ // The pipe is full. Wake up any readers and wait for them.
+ notifyAll();
+ wait();
+ // The pipe could have been closed while we were waiting.
+ if (closed)
+ throw new IOException ("Pipe closed");
+ }
+ }
+ catch (InterruptedException ix)
+ {
+ throw new InterruptedIOException ();
+ }
+
+ if (in < 0) // The pipe is empty.
+ in = 0;
+
+ // Figure out how many bytes from buf can be copied without
+ // overrunning out or going past the length of the buffer.
+ if (in < out)
+ copylen = Math.min (len, out - in);
+ else
+ copylen = Math.min (len, buffer.length - in);
+
+ // Copy bytes until the pipe is filled, wrapping if necessary.
+ System.arraycopy(buf, bufpos, buffer, in, copylen);
+ len -= copylen;
+ bufpos += copylen;
+ in += copylen;
+ if (in == buffer.length)
+ in = 0;
+ }
+ // Notify readers that new data is in the pipe.
+ notifyAll();
+ }
+
+ /**
+ * This method reads one byte from the stream.
+ * -1 is returned to indicated that no bytes can be read
+ * because the end of the stream was reached. If the stream is already
+ * closed, a -1 will again be returned to indicate the end of the stream.
+ *
+ * <p>This method will block if no byte is available to be read.</p>
+ *
+ * @return the value of the read byte value, or -1 of the end of the stream
+ * was reached
+ *
+ * @throws IOException if an error occured
+ */
+ public int read() throws IOException
+ {
+ // Method operates by calling the multibyte overloaded read method
+ // Note that read_buf is an internal instance variable. I allocate it
+ // there to avoid constant reallocation overhead for applications that
+ // call this method in a loop at the cost of some unneeded overhead
+ // if this method is never called.
+
+ int r = read(read_buf, 0, 1);
+ return r != -1 ? (read_buf[0] & 0xff) : -1;
+ }
+
+ /**
+ * This method reads bytes from the stream into a caller supplied buffer.
+ * It starts storing bytes at position <code>offset</code> into the
+ * buffer and
+ * reads a maximum of <code>len</code> bytes. Note that this method
+ * can actually
+ * read fewer than <code>len</code> bytes. The actual number of bytes
+ * read is
+ * returned. A -1 is returned to indicated that no bytes can be read
+ * because the end of the stream was reached - ie close() was called on the
+ * connected PipedOutputStream.
+ * <p>
+ * This method will block if no bytes are available to be read.
+ *
+ * @param buf The buffer into which bytes will be stored
+ * @param offset The index into the buffer at which to start writing.
+ * @param len The maximum number of bytes to read.
+ *
+ * @exception IOException If <code>close()</code> was called on this Piped
+ * InputStream.
+ */
+ public synchronized int read(byte[] buf, int offset, int len)
+ throws IOException
+ {
+ if (source == null)
+ throw new IOException ("Not connected");
+ if (closed)
+ throw new IOException ("Pipe closed");
+
+ // Don't block if nothing was requested.
+ if (len == 0)
+ return 0;
+
+ // If the buffer is empty, wait until there is something in the pipe
+ // to read.
+ try
+ {
+ while (in < 0)
+ {
+ if (source.closed)
+ return -1;
+ wait();
+ }
+ }
+ catch (InterruptedException ix)
+ {
+ throw new InterruptedIOException();
+ }
+
+ int total = 0;
+ int copylen;
+
+ while (true)
+ {
+ // Figure out how many bytes from the pipe can be copied without
+ // overrunning in or going past the length of buf.
+ if (out < in)
+ copylen = Math.min (len, in - out);
+ else
+ copylen = Math.min (len, buffer.length - out);
+
+ System.arraycopy (buffer, out, buf, offset, copylen);
+ offset += copylen;
+ len -= copylen;
+ out += copylen;
+ total += copylen;
+
+ if (out == buffer.length)
+ out = 0;
+
+ if (out == in)
+ {
+ // Pipe is now empty.
+ in = -1;
+ out = 0;
+ }
+
+ // If output buffer is filled or the pipe is empty, we're done.
+ if (len == 0 || in == -1)
+ {
+ // Notify any waiting outputstream that there is now space
+ // to write.
+ notifyAll();
+ return total;
+ }
+ }
+ }
+
+ /**
+ * This method returns the number of bytes that can be read from this stream
+ * before blocking could occur. This is the number of bytes that are
+ * currently unread in the internal circular buffer. Note that once this
+ * many additional bytes are read, the stream may block on a subsequent
+ * read, but it not guaranteed to block.
+ *
+ * @return The number of bytes that can be read before blocking might occur
+ *
+ * @exception IOException If an error occurs
+ */
+ public synchronized int available() throws IOException
+ {
+ // The JDK 1.3 implementation does not appear to check for the closed or
+ // unconnected stream conditions here.
+
+ if (in < 0)
+ return 0;
+ else if (out < in)
+ return in - out;
+ else
+ return (buffer.length - out) + in;
+ }
+
+ /**
+ * This methods closes the stream so that no more data can be read
+ * from it.
+ *
+ * @exception IOException If an error occurs
+ */
+ public synchronized void close() throws IOException
+ {
+ closed = true;
+ // Wake any thread which may be in receive() waiting to write data.
+ notifyAll();
+ }
+}
diff --git a/libjava/classpath/java/io/PipedOutputStream.java b/libjava/classpath/java/io/PipedOutputStream.java
new file mode 100644
index 000000000..839cb1e22
--- /dev/null
+++ b/libjava/classpath/java/io/PipedOutputStream.java
@@ -0,0 +1,181 @@
+/* PipedOutputStream.java -- Write portion of piped streams.
+ Copyright (C) 1998, 2000, 2001, 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 java.io;
+
+// NOTE: This implementation is very similar to that of PipedWriter. If you
+// fix a bug in here, chances are you should make a similar change to the
+// PipedWriter code.
+
+/**
+ * This class writes its bytes to a <code>PipedInputStream</code> to
+ * which it is connected.
+ * <p>
+ * It is highly recommended that a <code>PipedOutputStream</code> and its
+ * connected <code>PipedInputStream</code> be in different threads. If
+ * they are in the same thread, read and write operations could deadlock
+ * the thread.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class PipedOutputStream extends OutputStream
+{
+ /** Target PipedInputStream to which this is connected. Null only if this
+ * OutputStream hasn't been connected yet. */
+ PipedInputStream sink;
+
+ /** Set to true if close() has been called on this OutputStream. */
+ boolean closed;
+
+ /**
+ * Create an unconnected PipedOutputStream. It must be connected
+ * to a <code>PipedInputStream</code> using the <code>connect</code>
+ * method prior to writing any data or an exception will be thrown.
+ */
+ public PipedOutputStream()
+ {
+ }
+
+ /**
+ * Create a new <code>PipedOutputStream</code> instance
+ * to write to the specified <code>PipedInputStream</code>. This stream
+ * is then ready for writing.
+ *
+ * @param sink The <code>PipedInputStream</code> to connect this stream to.
+ *
+ * @exception IOException If <code>sink</code> has already been connected
+ * to a different PipedOutputStream.
+ */
+ public PipedOutputStream(PipedInputStream sink) throws IOException
+ {
+ sink.connect(this);
+ }
+
+ /**
+ * Connects this object to the specified <code>PipedInputStream</code>
+ * object. This stream will then be ready for writing.
+ *
+ * @param sink The <code>PipedInputStream</code> to connect this stream to
+ *
+ * @exception IOException If the stream has not been connected or has
+ * been closed.
+ */
+ public void connect(PipedInputStream sink) throws IOException
+ {
+ if (this.sink != null || sink.source != null)
+ throw new IOException ("Already connected");
+ sink.connect(this);
+ }
+
+ /**
+ * Write a single byte of date to the stream. Note that this method will
+ * block if the <code>PipedInputStream</code> to which this object is
+ * connected has a full buffer.
+ *
+ * @param b The byte of data to be written, passed as an <code>int</code>.
+ *
+ * @exception IOException If the stream has not been connected or has
+ * been closed.
+ */
+ public void write(int b) throws IOException
+ {
+ if (sink == null)
+ throw new IOException ("Not connected");
+ if (closed)
+ throw new IOException ("Pipe closed");
+
+ sink.receive (b);
+ }
+
+ /**
+ * This method writes <code>len</code> bytes of data from the byte array
+ * <code>buf</code> starting at index <code>offset</code> in the array
+ * to the stream. Note that this method will block if the
+ * <code>PipedInputStream</code> to which this object is connected has
+ * a buffer that cannot hold all of the bytes to be written.
+ *
+ * @param buffer The array containing bytes to write to the stream.
+ * @param offset The index into the array to start writing bytes from.
+ * @param len The number of bytes to write.
+ *
+ * @exception IOException If the stream has not been connected or has
+ * been closed.
+ */
+ public void write(byte[] buffer, int offset, int len) throws IOException
+ {
+ if (sink == null)
+ throw new IOException ("Not connected");
+ if (closed)
+ throw new IOException ("Pipe closed");
+
+ sink.receive(buffer, offset, len);
+ }
+
+ /**
+ * This method does nothing.
+ *
+ * @exception IOException If the stream is closed.
+ * @specnote You'd think that this method would block until the sink
+ * had read all available data. Thats not the case - this method
+ * appears to be a no-op?
+ */
+ public void flush() throws IOException
+ {
+ }
+
+ /**
+ * This method closes this stream so that no more data can be written
+ * to it. Any further attempts to write to this stream may throw an
+ * exception
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ // A close call on an unconnected PipedOutputStream has no effect.
+ if (sink != null)
+ {
+ closed = true;
+ // Notify any waiting readers that the stream is now closed.
+ synchronized (sink)
+ {
+ sink.notifyAll();
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/java/io/PipedReader.java b/libjava/classpath/java/io/PipedReader.java
new file mode 100644
index 000000000..4f449ffce
--- /dev/null
+++ b/libjava/classpath/java/io/PipedReader.java
@@ -0,0 +1,364 @@
+/* PipedReader.java -- Read portion of piped character streams.
+ Copyright (C) 1998, 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 java.io;
+
+// NOTE: This implementation is very similar to that of PipedInputStream.
+// If you fix a bug in here, chances are you should make a similar change to
+// the PipedInputStream code.
+
+/**
+ * An input stream that reads characters from a piped writer to which it is
+ * connected.
+ * <p>
+ * Data is read and written to an internal buffer. It is highly recommended
+ * that the <code>PipedReader</code> and connected <code>PipedWriter</code>
+ * be part of different threads. If they are not, there is a possibility
+ * that the read and write operations could deadlock their thread.
+ *
+ * @specnote The JDK implementation appears to have some undocumented
+ * functionality where it keeps track of what thread is writing
+ * to pipe and throws an IOException if that thread susequently
+ * dies. This behaviour seems dubious and unreliable - we don't
+ * implement it.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class PipedReader extends Reader
+{
+ /** PipedWriter to which this is connected. Null only if this
+ * Reader hasn't been connected yet. */
+ PipedWriter source;
+
+ /** Set to true if close() has been called on this Reader. */
+ boolean closed;
+
+ /**
+ * The size of the internal buffer used for input/output.
+ */
+ static final int PIPE_SIZE = 2048;
+
+ /**
+ * This is the internal circular buffer used for storing chars written
+ * to the pipe and from which chars are read by this stream
+ */
+ char[] buffer = new char[PIPE_SIZE];
+
+ /**
+ * The index into buffer where the next char from the connected
+ * <code>PipedWriter</code> will be written. If this variable is
+ * equal to <code>out</code>, then the buffer is full. If set to < 0,
+ * the buffer is empty.
+ */
+ int in = -1;
+
+ /**
+ * This index into the buffer where chars will be read from.
+ */
+ int out = 0;
+
+ /** Buffer used to implement single-argument read/receive */
+ char[] read_buf = new char[1];
+
+ /**
+ * Creates a new <code>PipedReader</code> that is not connected to a
+ * <code>PipedWriter</code>. It must be connected before chars can
+ * be read from this stream.
+ */
+ public PipedReader()
+ {
+ }
+
+ /**
+ * This constructor creates a new <code>PipedReader</code> and connects
+ * it to the passed in <code>PipedWriter</code>. The stream is then
+ * ready for reading.
+ *
+ * @param source The <code>PipedWriter</code> to connect this stream to
+ *
+ * @exception IOException If <code>source</code> is already connected.
+ */
+ public PipedReader(PipedWriter source) throws IOException
+ {
+ connect(source);
+ }
+
+ /**
+ * This method connects this stream to the passed in
+ * <code>PipedWriter</code>.
+ * This stream is then ready for reading. If this stream is already
+ * connected or has been previously closed, then an exception is thrown
+ *
+ * @param source The <code>PipedWriter</code> to connect this stream to
+ *
+ * @exception IOException If this PipedReader or <code>source</code>
+ * has been connected already.
+ */
+ public void connect(PipedWriter source) throws IOException
+ {
+ // The JDK (1.3) does not appear to check for a previously closed
+ // connection here.
+
+ if (this.source != null || source.sink != null)
+ throw new IOException ("Already connected");
+
+ source.sink = this;
+ this.source = source;
+ }
+
+ /**
+ * This method is used by the connected <code>PipedWriter</code> to
+ * write chars into the buffer.
+ *
+ * @param buf The array containing chars to write to this stream
+ * @param offset The offset into the array to start writing from
+ * @param len The number of chars to write.
+ *
+ * @exception IOException If an error occurs
+ * @specnote This code should be in PipedWriter.write, but we
+ * put it here in order to support that bizarre recieve(int)
+ * method.
+ */
+ void receive(char[] buf, int offset, int len)
+ throws IOException
+ {
+ synchronized (lock)
+ {
+ if (closed)
+ throw new IOException ("Pipe closed");
+
+ int bufpos = offset;
+ int copylen;
+
+ while (len > 0)
+ {
+ try
+ {
+ while (in == out)
+ {
+ // The pipe is full. Wake up any readers and wait for them.
+ lock.notifyAll();
+ lock.wait();
+ // The pipe could have been closed while we were waiting.
+ if (closed)
+ throw new IOException ("Pipe closed");
+ }
+ }
+ catch (InterruptedException ix)
+ {
+ throw new InterruptedIOException ();
+ }
+
+ if (in < 0) // The pipe is empty.
+ in = 0;
+
+ // Figure out how many chars from buf can be copied without
+ // overrunning out or going past the length of the buffer.
+ if (in < out)
+ copylen = Math.min (len, out - in);
+ else
+ copylen = Math.min (len, buffer.length - in);
+
+ // Copy chars until the pipe is filled, wrapping if necessary.
+ System.arraycopy(buf, bufpos, buffer, in, copylen);
+ len -= copylen;
+ bufpos += copylen;
+ in += copylen;
+ if (in == buffer.length)
+ in = 0;
+ }
+ // Notify readers that new data is in the pipe.
+ lock.notifyAll();
+ }
+ }
+
+ /**
+ * This method reads chars from the stream into a caller supplied buffer.
+ * It starts storing chars at position <code>offset</code> into the
+ * buffer and
+ * reads a maximum of <code>len</code> chars. Note that this method
+ * can actually
+ * read fewer than <code>len</code> chars. The actual number of chars
+ * read is
+ * returned. A -1 is returned to indicated that no chars can be read
+ * because the end of the stream was reached. If the stream is already
+ * closed, a -1 will again be returned to indicate the end of the stream.
+ * <p>
+ * This method will block if no char is available to be read.
+ */
+ public int read() throws IOException
+ {
+ // Method operates by calling the multichar overloaded read method
+ // Note that read_buf is an internal instance variable. I allocate it
+ // there to avoid constant reallocation overhead for applications that
+ // call this method in a loop at the cost of some unneeded overhead
+ // if this method is never called.
+
+ int r = read(read_buf, 0, 1);
+ return r != -1 ? read_buf[0] : -1;
+ }
+
+ /**
+ * This method reads characters from the stream into a caller supplied
+ * buffer. It starts storing chars at position <code>offset</code> into
+ * the buffer and reads a maximum of <code>len</code> chars. Note that
+ * this method can actually read fewer than <code>len</code> chars.
+ * The actual number of chars read is
+ * returned. A -1 is returned to indicated that no chars can be read
+ * because the end of the stream was reached - ie close() was called on the
+ * connected PipedWriter.
+ * <p>
+ * This method will block if no chars are available to be read.
+ *
+ * @param buf The buffer into which chars will be stored
+ * @param offset The index into the buffer at which to start writing.
+ * @param len The maximum number of chars to read.
+ *
+ * @exception IOException If <code>close()</code> was called on this Piped
+ * Reader.
+ */
+ public int read(char[] buf, int offset, int len)
+ throws IOException
+ {
+ synchronized (lock)
+ {
+ if (source == null)
+ throw new IOException ("Not connected");
+ if (closed)
+ throw new IOException ("Pipe closed");
+
+ // Don't block if nothing was requested.
+ if (len == 0)
+ return 0;
+
+ // If the buffer is empty, wait until there is something in the pipe
+ // to read.
+ try
+ {
+ while (in < 0)
+ {
+ if (source.closed)
+ return -1;
+ lock.wait();
+ }
+ }
+ catch (InterruptedException ix)
+ {
+ throw new InterruptedIOException();
+ }
+
+ int total = 0;
+ int copylen;
+
+ while (true)
+ {
+ // Figure out how many chars from the pipe can be copied without
+ // overrunning in or going past the length of buf.
+ if (out < in)
+ copylen = Math.min (len, in - out);
+ else
+ copylen = Math.min (len, buffer.length - out);
+
+ System.arraycopy (buffer, out, buf, offset, copylen);
+ offset += copylen;
+ len -= copylen;
+ out += copylen;
+ total += copylen;
+
+ if (out == buffer.length)
+ out = 0;
+
+ if (out == in)
+ {
+ // Pipe is now empty.
+ in = -1;
+ out = 0;
+ }
+
+ // If output buffer is filled or the pipe is empty, we're done.
+ if (len == 0 || in == -1)
+ {
+ // Notify any waiting Writer that there is now space
+ // to write.
+ lock.notifyAll();
+ return total;
+ }
+ }
+ }
+ }
+
+ public boolean ready() throws IOException
+ {
+ // The JDK 1.3 implementation does not appear to check for the closed or
+ // unconnected stream conditions here. However, checking for a
+ // closed stream is explicitly required by the JDK 1.2 and 1.3
+ // documentation (for Reader.close()), so we do it.
+
+ synchronized (lock)
+ {
+ if (closed)
+ throw new IOException("Pipe closed");
+
+ if (in < 0)
+ return false;
+
+ int count;
+ if (out < in)
+ count = in - out;
+ else
+ count = (buffer.length - out) - in;
+
+ return (count > 0);
+ }
+ }
+
+ /**
+ * This methods closes the stream so that no more data can be read
+ * from it.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ synchronized (lock)
+ {
+ closed = true;
+ // Wake any thread which may be in receive() waiting to write data.
+ lock.notifyAll();
+ }
+ }
+}
diff --git a/libjava/classpath/java/io/PipedWriter.java b/libjava/classpath/java/io/PipedWriter.java
new file mode 100644
index 000000000..0d48ab0e4
--- /dev/null
+++ b/libjava/classpath/java/io/PipedWriter.java
@@ -0,0 +1,182 @@
+/* PipedWriter.java -- Write portion of piped character streams.
+ Copyright (C) 1998, 2000, 2001, 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 java.io;
+
+// NOTE: This implementation is very similar to that of PipedOutputStream.
+// If you fix a bug in here, chances are you should make a similar change to
+// the PipedOutputStream code.
+
+/**
+ * This class writes its chars to a <code>PipedReader</code> to
+ * which it is connected.
+ * <p>
+ * It is highly recommended that a <code>PipedWriter</code> and its
+ * connected <code>PipedReader</code> be in different threads. If
+ * they are in the same thread, read and write operations could deadlock
+ * the thread.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class PipedWriter extends Writer
+{
+ /** Target PipedReader to which this is connected. Null only if this
+ * Writer hasn't been connected yet. */
+ PipedReader sink;
+
+ /** Set to true if close() has been called on this Writer. */
+ boolean closed;
+
+ /** Buffer used to implement single-argument write */
+ char[] read_buf = new char[1];
+
+ /**
+ * Create an unconnected PipedWriter. It must be connected
+ * to a <code>PipedReader</code> using the <code>connect</code>
+ * method prior to writing any data or an exception will be thrown.
+ */
+ public PipedWriter()
+ {
+ }
+
+ /**
+ * Create a new <code>PipedWriter</code> instance
+ * to write to the specified <code>PipedReader</code>. This stream
+ * is then ready for writing.
+ *
+ * @param sink The <code>PipedReader</code> to connect this stream to.
+ *
+ * @exception IOException If <code>sink</code> has already been connected
+ * to a different PipedWriter.
+ */
+ public PipedWriter(PipedReader sink) throws IOException
+ {
+ sink.connect(this);
+ }
+
+ /**
+ * Connects this object to the specified <code>PipedReader</code>
+ * object. This stream will then be ready for writing.
+ *
+ * @param sink The <code>PipedReader</code> to connect this stream to
+ *
+ * @exception IOException If the stream has not been connected or has
+ * been closed.
+ */
+ public void connect(PipedReader sink) throws IOException
+ {
+ if (this.sink != null || sink.source != null)
+ throw new IOException ("Already connected");
+ sink.connect(this);
+ }
+
+ /**
+ * Write a single char of date to the stream. Note that this method will
+ * block if the <code>PipedReader</code> to which this object is
+ * connected has a full buffer.
+ *
+ * @param b The char of data to be written, passed as an <code>int</code>.
+ *
+ * @exception IOException If the stream has not been connected or has
+ * been closed.
+ */
+ public void write(int b) throws IOException
+ {
+ read_buf[0] = (char) (b & 0xffff);
+ sink.receive (read_buf, 0, 1);
+ }
+
+ /**
+ * This method writes <code>len</code> chars of data from the char array
+ * <code>buf</code> starting at index <code>offset</code> in the array
+ * to the stream. Note that this method will block if the
+ * <code>PipedReader</code> to which this object is connected has
+ * a buffer that cannot hold all of the chars to be written.
+ *
+ * @param buffer The array containing chars to write to the stream.
+ * @param offset The index into the array to start writing chars from.
+ * @param len The number of chars to write.
+ *
+ * @exception IOException If the stream has not been connected or has
+ * been closed.
+ */
+ public void write(char[] buffer, int offset, int len) throws IOException
+ {
+ if (sink == null)
+ throw new IOException ("Not connected");
+ if (closed)
+ throw new IOException ("Pipe closed");
+
+ sink.receive(buffer, offset, len);
+ }
+
+ /**
+ * This method does nothing.
+ *
+ * @exception IOException If the stream is closed.
+ * @specnote You'd think that this method would block until the sink
+ * had read all available data. Thats not the case - this method
+ * appears to be a no-op?
+ */
+ public void flush() throws IOException
+ {
+ if (closed)
+ throw new IOException ("Pipe closed");
+ }
+
+ /**
+ * This method closes this stream so that no more data can be written
+ * to it. Any further attempts to write to this stream may throw an
+ * exception
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ // A close call on an unconnected PipedWriter has no effect.
+ if (sink != null)
+ {
+ closed = true;
+ // Notify any waiting readers that the stream is now closed.
+ synchronized (sink)
+ {
+ sink.notifyAll();
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/java/io/PrintStream.java b/libjava/classpath/java/io/PrintStream.java
new file mode 100644
index 000000000..eaab7c3d4
--- /dev/null
+++ b/libjava/classpath/java/io/PrintStream.java
@@ -0,0 +1,675 @@
+/* PrintStream.java -- OutputStream for printing output
+ Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+import java.util.Locale;
+import java.util.Formatter;
+
+import gnu.classpath.SystemProperties;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Believed complete and correct to 1.3
+ */
+
+/**
+ * This class prints Java primitive values and object to a stream as
+ * text. None of the methods in this class throw an exception. However,
+ * errors can be detected by calling the <code>checkError()</code> method.
+ * Additionally, this stream can be designated as "autoflush" when
+ * created so that any writes are automatically flushed to the underlying
+ * output sink when the current line is terminated.
+ * <p>
+ * This class converts char's into byte's using the system default encoding.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
+ */
+public class PrintStream extends FilterOutputStream implements Appendable
+{
+ /* Notice the implementation is quite similar to OutputStreamWriter.
+ * This leads to some minor duplication, because neither inherits
+ * from the other, and we want to maximize performance. */
+
+ // Line separator string.
+ private static final char[] line_separator
+ = SystemProperties.getProperty("line.separator", "\n").toCharArray();
+
+ /**
+ * Encoding name
+ */
+ private final String encoding;
+
+ /**
+ * This boolean indicates whether or not an error has ever occurred
+ * on this stream.
+ */
+ private boolean error_occurred = false;
+
+ /**
+ * This is <code>true</code> if auto-flush is enabled,
+ * <code>false</code> otherwise
+ */
+ private final boolean auto_flush;
+
+ /**
+ * This method initializes a new <code>PrintStream</code> object to write
+ * to the specified output File. Doesn't autoflush.
+ *
+ * @param file The <code>File</code> to write to.
+ * @throws FileNotFoundException if an error occurs while opening the file.
+ *
+ * @since 1.5
+ */
+ public PrintStream (File file)
+ throws FileNotFoundException
+ {
+ this (new FileOutputStream(file), false);
+ }
+
+ /**
+ * This method initializes a new <code>PrintStream</code> object to write
+ * to the specified output File. Doesn't autoflush.
+ *
+ * @param file The <code>File</code> to write to.
+ * @param encoding The name of the character encoding to use for this
+ * object.
+ * @throws FileNotFoundException If an error occurs while opening the file.
+ * @throws UnsupportedEncodingException If the charset specified by
+ * <code>encoding</code> is invalid.
+ *
+ * @since 1.5
+ */
+ public PrintStream (File file, String encoding)
+ throws FileNotFoundException,UnsupportedEncodingException
+ {
+ this (new FileOutputStream(file), false, encoding);
+ }
+
+ /**
+ * This method initializes a new <code>PrintStream</code> object to write
+ * to the specified output File. Doesn't autoflush.
+ *
+ * @param fileName The name of the <code>File</code> to write to.
+ * @throws FileNotFoundException if an error occurs while opening the file,
+ *
+ * @since 1.5
+ */
+ public PrintStream (String fileName)
+ throws FileNotFoundException
+ {
+ this (new FileOutputStream(new File(fileName)), false);
+ }
+
+ /**
+ * This method initializes a new <code>PrintStream</code> object to write
+ * to the specified output File. Doesn't autoflush.
+ *
+ * @param fileName The name of the <code>File</code> to write to.
+ * @param encoding The name of the character encoding to use for this
+ * object.
+ * @throws FileNotFoundException if an error occurs while opening the file.
+ * @throws UnsupportedEncodingException If the charset specified by
+ * <code>encoding</code> is invalid.
+ *
+ * @since 1.5
+ */
+ public PrintStream (String fileName, String encoding)
+ throws FileNotFoundException,UnsupportedEncodingException
+ {
+ this (new FileOutputStream(new File(fileName)), false, encoding);
+ }
+
+ /**
+ * This method initializes a new <code>PrintStream</code> object to write
+ * to the specified output sink. Doesn't autoflush.
+ *
+ * @param out The <code>OutputStream</code> to write to.
+ */
+ public PrintStream (OutputStream out)
+ {
+ this (out, false);
+ }
+
+ /**
+ * This method initializes a new <code>PrintStream</code> object to write
+ * to the specified output sink. This constructor also allows "auto-flush"
+ * functionality to be specified where the stream will be flushed after
+ * every <code>print</code> or <code>println</code> call, when the
+ * <code>write</code> methods with array arguments are called, or when a
+ * single new-line character is written.
+ * <p>
+ *
+ * @param out The <code>OutputStream</code> to write to.
+ * @param auto_flush <code>true</code> to flush the stream after every
+ * line, <code>false</code> otherwise
+ */
+ public PrintStream (OutputStream out, boolean auto_flush)
+ {
+ super (out);
+ String encoding;
+ try {
+ encoding = SystemProperties.getProperty("file.encoding");
+ } catch (SecurityException e){
+ encoding = "ISO8859_1";
+ } catch (IllegalArgumentException e){
+ encoding = "ISO8859_1";
+ } catch (NullPointerException e){
+ encoding = "ISO8859_1";
+ }
+ this.encoding = encoding;
+ this.auto_flush = auto_flush;
+ }
+
+ /**
+ * This method initializes a new <code>PrintStream</code> object to write
+ * to the specified output sink. This constructor also allows "auto-flush"
+ * functionality to be specified where the stream will be flushed after
+ * every <code>print</code> or <code>println</code> call, when the
+ * <code>write</code> methods with array arguments are called, or when a
+ * single new-line character is written.
+ * <p>
+ *
+ * @param out The <code>OutputStream</code> to write to.
+ * @param auto_flush <code>true</code> to flush the stream after every
+ * line, <code>false</code> otherwise
+ * @param encoding The name of the character encoding to use for this
+ * object.
+ */
+ public PrintStream (OutputStream out, boolean auto_flush, String encoding)
+ throws UnsupportedEncodingException
+ {
+ super (out);
+
+ new String(new byte[]{0}, encoding); // check if encoding is supported
+ this.encoding = encoding;
+ this.auto_flush = auto_flush;
+ }
+
+ /**
+ * This method checks to see if an error has occurred on this stream. Note
+ * that once an error has occurred, this method will continue to report
+ * <code>true</code> forever for this stream. Before checking for an
+ * error condition, this method flushes the stream.
+ *
+ * @return <code>true</code> if an error has occurred,
+ * <code>false</code> otherwise
+ */
+ public boolean checkError ()
+ {
+ flush ();
+ return error_occurred;
+ }
+
+ /**
+ * This method can be called by subclasses to indicate that an error
+ * has occurred and should be reported by <code>checkError</code>.
+ */
+ protected void setError ()
+ {
+ error_occurred = true;
+ }
+
+ /**
+ * This method closes this stream and all underlying streams.
+ */
+ public void close ()
+ {
+ try
+ {
+ flush();
+ out.close();
+ }
+ catch (InterruptedIOException iioe)
+ {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException e)
+ {
+ setError ();
+ }
+ }
+
+ /**
+ * This method flushes any buffered bytes to the underlying stream and
+ * then flushes that stream as well.
+ */
+ public void flush ()
+ {
+ try
+ {
+ out.flush();
+ }
+ catch (InterruptedIOException iioe)
+ {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException e)
+ {
+ setError ();
+ }
+ }
+
+ private synchronized void print (String str, boolean println)
+ {
+ try
+ {
+ writeChars(str, 0, str.length());
+ if (println)
+ writeChars(line_separator, 0, line_separator.length);
+ if (auto_flush)
+ flush();
+ }
+ catch (InterruptedIOException iioe)
+ {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException e)
+ {
+ setError ();
+ }
+ }
+
+ private synchronized void print (char[] chars, int pos, int len,
+ boolean println)
+ {
+ try
+ {
+ writeChars(chars, pos, len);
+ if (println)
+ writeChars(line_separator, 0, line_separator.length);
+ if (auto_flush)
+ flush();
+ }
+ catch (InterruptedIOException iioe)
+ {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException e)
+ {
+ setError ();
+ }
+ }
+
+ private void writeChars(char[] buf, int offset, int count)
+ throws IOException
+ {
+ byte[] bytes = (new String(buf, offset, count)).getBytes(encoding);
+ out.write(bytes, 0, bytes.length);
+ }
+
+ private void writeChars(String str, int offset, int count)
+ throws IOException
+ {
+ byte[] bytes = str.substring(offset, offset+count).getBytes(encoding);
+ out.write(bytes, 0, bytes.length);
+ }
+
+ /**
+ * This methods prints a boolean value to the stream. <code>true</code>
+ * values are printed as "true" and <code>false</code> values are printed
+ * as "false".
+ *
+ * @param bool The <code>boolean</code> value to print
+ */
+ public void print (boolean bool)
+ {
+ print(String.valueOf(bool), false);
+ }
+
+ /**
+ * This method prints an integer to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * @param inum The <code>int</code> value to be printed
+ */
+ public void print (int inum)
+ {
+ print(String.valueOf(inum), false);
+ }
+
+ /**
+ * This method prints a long to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * @param lnum The <code>long</code> value to be printed
+ */
+ public void print (long lnum)
+ {
+ print(String.valueOf(lnum), false);
+ }
+
+ /**
+ * This method prints a float to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * @param fnum The <code>float</code> value to be printed
+ */
+ public void print (float fnum)
+ {
+ print(String.valueOf(fnum), false);
+ }
+
+ /**
+ * This method prints a double to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * @param dnum The <code>double</code> value to be printed
+ */
+ public void print (double dnum)
+ {
+ print(String.valueOf(dnum), false);
+ }
+
+ /**
+ * This method prints an <code>Object</code> to the stream. The actual
+ * value printed is determined by calling the <code>String.valueOf()</code>
+ * method.
+ *
+ * @param obj The <code>Object</code> to print.
+ */
+ public void print (Object obj)
+ {
+ print(obj == null ? "null" : obj.toString(), false);
+ }
+
+ /**
+ * This method prints a <code>String</code> to the stream. The actual
+ * value printed depends on the system default encoding.
+ *
+ * @param str The <code>String</code> to print.
+ */
+ public void print (String str)
+ {
+ print(str == null ? "null" : str, false);
+ }
+
+ /**
+ * This method prints a char to the stream. The actual value printed is
+ * determined by the character encoding in use.
+ *
+ * @param ch The <code>char</code> value to be printed
+ */
+ public synchronized void print (char ch)
+ {
+ print(new char[]{ch}, 0, 1, false);
+ }
+
+ /**
+ * This method prints an array of characters to the stream. The actual
+ * value printed depends on the system default encoding.
+ *
+ * @param charArray The array of characters to print.
+ */
+ public void print (char[] charArray)
+ {
+ print(charArray, 0, charArray.length, false);
+ }
+
+ /**
+ * This method prints a line separator sequence to the stream. The value
+ * printed is determined by the system property <xmp>line.separator</xmp>
+ * and is not necessarily the Unix '\n' newline character.
+ */
+ public void println ()
+ {
+ print(line_separator, 0, line_separator.length, false);
+ }
+
+ /**
+ * This methods prints a boolean value to the stream. <code>true</code>
+ * values are printed as "true" and <code>false</code> values are printed
+ * as "false".
+ * <p>
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param bool The <code>boolean</code> value to print
+ */
+ public void println (boolean bool)
+ {
+ print(String.valueOf(bool), true);
+ }
+
+ /**
+ * This method prints an integer to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ * <p>
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param inum The <code>int</code> value to be printed
+ */
+ public void println (int inum)
+ {
+ print(String.valueOf(inum), true);
+ }
+
+ /**
+ * This method prints a long to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ * <p>
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param lnum The <code>long</code> value to be printed
+ */
+ public void println (long lnum)
+ {
+ print(String.valueOf(lnum), true);
+ }
+
+ /**
+ * This method prints a float to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ * <p>
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param fnum The <code>float</code> value to be printed
+ */
+ public void println (float fnum)
+ {
+ print(String.valueOf(fnum), true);
+ }
+
+ /**
+ * This method prints a double to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ * <p>
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param dnum The <code>double</code> value to be printed
+ */
+ public void println (double dnum)
+ {
+ print(String.valueOf(dnum), true);
+ }
+
+ /**
+ * This method prints an <code>Object</code> to the stream. The actual
+ * value printed is determined by calling the <code>String.valueOf()</code>
+ * method.
+ * <p>
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param obj The <code>Object</code> to print.
+ */
+ public void println (Object obj)
+ {
+ print(obj == null ? "null" : obj.toString(), true);
+ }
+
+ /**
+ * This method prints a <code>String</code> to the stream. The actual
+ * value printed depends on the system default encoding.
+ * <p>
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param str The <code>String</code> to print.
+ */
+ public void println (String str)
+ {
+ print (str == null ? "null" : str, true);
+ }
+
+ /**
+ * This method prints a char to the stream. The actual value printed is
+ * determined by the character encoding in use.
+ * <p>
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param ch The <code>char</code> value to be printed
+ */
+ public synchronized void println (char ch)
+ {
+ print(new char[]{ch}, 0, 1, true);
+ }
+
+ /**
+ * This method prints an array of characters to the stream. The actual
+ * value printed depends on the system default encoding.
+ * <p>
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param charArray The array of characters to print.
+ */
+ public void println (char[] charArray)
+ {
+ print(charArray, 0, charArray.length, true);
+ }
+
+ /**
+ * This method writes a byte of data to the stream. If auto-flush is
+ * enabled, printing a newline character will cause the stream to be
+ * flushed after the character is written.
+ *
+ * @param oneByte The byte to be written
+ */
+ public void write (int oneByte)
+ {
+ try
+ {
+ out.write (oneByte & 0xff);
+
+ if (auto_flush && (oneByte == '\n'))
+ flush ();
+ }
+ catch (InterruptedIOException iioe)
+ {
+ Thread.currentThread ().interrupt ();
+ }
+ catch (IOException e)
+ {
+ setError ();
+ }
+ }
+
+ /**
+ * This method writes <code>len</code> bytes from the specified array
+ * starting at index <code>offset</code> into the array.
+ *
+ * @param buffer The array of bytes to write
+ * @param offset The index into the array to start writing from
+ * @param len The number of bytes to write
+ */
+ public void write (byte[] buffer, int offset, int len)
+ {
+ try
+ {
+ out.write (buffer, offset, len);
+
+ if (auto_flush)
+ flush ();
+ }
+ catch (InterruptedIOException iioe)
+ {
+ Thread.currentThread ().interrupt ();
+ }
+ catch (IOException e)
+ {
+ setError ();
+ }
+ }
+
+ /** @since 1.5 */
+ public PrintStream append(char c)
+ {
+ print(c);
+ return this;
+ }
+
+ /** @since 1.5 */
+ public PrintStream append(CharSequence cs)
+ {
+ print(cs == null ? "null" : cs.toString());
+ return this;
+ }
+
+ /** @since 1.5 */
+ public PrintStream append(CharSequence cs, int start, int end)
+ {
+ print(cs == null ? "null" : cs.subSequence(start, end).toString());
+ return this;
+ }
+
+ /** @since 1.5 */
+ public PrintStream printf(String format, Object... args)
+ {
+ return format(format, args);
+ }
+
+ /** @since 1.5 */
+ public PrintStream printf(Locale locale, String format, Object... args)
+ {
+ return format(locale, format, args);
+ }
+
+ /** @since 1.5 */
+ public PrintStream format(String format, Object... args)
+ {
+ return format(Locale.getDefault(), format, args);
+ }
+
+ /** @since 1.5 */
+ public PrintStream format(Locale locale, String format, Object... args)
+ {
+ Formatter f = new Formatter(this, locale);
+ f.format(format, args);
+ return this;
+ }
+} // class PrintStream
diff --git a/libjava/classpath/java/io/PrintWriter.java b/libjava/classpath/java/io/PrintWriter.java
new file mode 100644
index 000000000..a67a7f8aa
--- /dev/null
+++ b/libjava/classpath/java/io/PrintWriter.java
@@ -0,0 +1,689 @@
+/* PrintWriter.java -- prints primitive values and objects to a stream as text
+ Copyright (C) 1998, 1999, 2000, 2001, 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 java.io;
+
+import java.util.Locale;
+import java.util.Formatter;
+
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ * However, should use native methods for conversion.
+ */
+
+/**
+ * This class prints Java primitive values and objects to a stream as
+ * text. None of the methods in this class throw an exception. However,
+ * errors can be detected by calling the <code>checkError()</code> method.
+ * Additionally, this stream can be designated as "autoflush" when
+ * created so that any writes are automatically flushed to the underlying
+ * output sink whenever one of the <code>println</code> methods is
+ * called. (Note that this differs from the <code>PrintStream</code>
+ * class which also auto-flushes when it encounters a newline character
+ * in the chars written).
+ *
+ * @author Per Bothner (bothner@cygnus.com)
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @date April 17, 1998.
+ */
+public class PrintWriter extends Writer
+{
+ /**
+ * <code>true</code> if auto-flush is enabled, <code>false</code> otherwise
+ */
+ private boolean autoflush;
+
+ /**
+ * This boolean indicates whether or not an error has ever occurred
+ * on this stream.
+ */
+ private boolean error;
+
+ /**
+ * Indicates whether or not the stream has been closed.
+ */
+ private boolean closed;
+
+ /**
+ * This is the underlying <code>Writer</code> we are sending output
+ * to
+ */
+ protected Writer out;
+
+ /**
+ * This method intializes a new <code>PrintWriter</code> object to write
+ * to the specified output sink. The form of the constructor does not
+ * enable auto-flush functionality.
+ *
+ * @param wr The <code>Writer</code> to write to.
+ */
+ public PrintWriter(Writer wr)
+ {
+ super(wr.lock);
+ this.out = wr;
+ }
+
+ /**
+ * This method intializes a new <code>PrintWriter</code> object to write
+ * to the specified output sink. This constructor also allows "auto-flush"
+ * functionality to be specified where the stream will be flushed after
+ * every line is terminated or newline character is written.
+ *
+ * @param wr The <code>Writer</code> to write to.
+ * @param autoflush <code>true</code> to flush the stream after every
+ * line, <code>false</code> otherwise
+ */
+ public PrintWriter(Writer wr, boolean autoflush)
+ {
+ super(wr.lock);
+ this.out = wr;
+ this.autoflush = autoflush;
+ }
+
+ /**
+ * This method initializes a new <code>PrintWriter</code> object to write
+ * to the specified <code>OutputStream</code>. Characters will be converted
+ * to chars using the system default encoding. Auto-flush functionality
+ * will not be enabled.
+ *
+ * @param out The <code>OutputStream</code> to write to
+ */
+ public PrintWriter(OutputStream out)
+ {
+ super();
+ this.out = new OutputStreamWriter(out);
+ this.lock = this.out;
+ }
+
+ /**
+ * This method initializes a new <code>PrintWriter</code> object to write
+ * to the specified <code>OutputStream</code>. Characters will be converted
+ * to chars using the system default encoding. This form of the
+ * constructor allows auto-flush functionality to be enabled if desired
+ *
+ * @param out The <code>OutputStream</code> to write to
+ * @param autoflush <code>true</code> to flush the stream after every
+ * <code>println</code> call, <code>false</code> otherwise.
+ */
+ public PrintWriter(OutputStream out, boolean autoflush)
+ {
+ this(out);
+ this.autoflush = autoflush;
+ }
+
+ /**
+ * This initializes a new PrintWriter object to write to the specified
+ * file. It creates a FileOutputStream object and wraps it in an
+ * OutputStreamWriter using the default encoding.
+ * @param file name of the file to write to
+ * @throws FileNotFoundException if the file cannot be written or created
+ *
+ * @since 1.5
+ */
+ public PrintWriter(String file) throws FileNotFoundException
+ {
+ this(new FileOutputStream(file));
+ }
+
+ /**
+ * This initializes a new PrintWriter object to write to the specified
+ * file. It creates a FileOutputStream object and wraps it in an
+ * OutputStreamWriter using the specified encoding.
+ * @param file name of the file to write to
+ * @param enc the encoding to use
+ * @throws FileNotFoundException if the file cannot be written or created
+ * @throws UnsupportedEncodingException if the encoding is not supported
+ *
+ * @since 1.5
+ */
+ public PrintWriter(String file, String enc)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ this(new OutputStreamWriter(new FileOutputStream(file), enc));
+ }
+
+ /**
+ * This initializes a new PrintWriter object to write to the specified
+ * file. It creates a FileOutputStream object and wraps it in an
+ * OutputStreamWriter using the default encoding.
+ * @param file the file to write to
+ * @throws FileNotFoundException if the file cannot be written or created
+ *
+ * @since 1.5
+ */
+ public PrintWriter(File file) throws FileNotFoundException
+ {
+ this(new FileOutputStream(file));
+ }
+
+ /**
+ * This initializes a new PrintWriter object to write to the specified
+ * file. It creates a FileOutputStream object and wraps it in an
+ * OutputStreamWriter using the specified encoding.
+ * @param file the file to write to
+ * @param enc the encoding to use
+ * @throws FileNotFoundException if the file cannot be written or created
+ * @throws UnsupportedEncodingException if the encoding is not supported
+ *
+ * @since 1.5
+ */
+ public PrintWriter(File file, String enc)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ this(new OutputStreamWriter(new FileOutputStream(file), enc));
+ }
+
+ /**
+ * This method can be called by subclasses to indicate that an error
+ * has occurred and should be reported by <code>checkError</code>.
+ */
+ protected void setError()
+ {
+ error = true;
+ }
+
+ /**
+ * This method checks to see if an error has occurred on this stream. Note
+ * that once an error has occurred, this method will continue to report
+ * <code>true</code> forever for this stream. Before checking for an
+ * error condition, this method flushes the stream.
+ *
+ * @return <code>true</code> if an error has occurred,
+ * <code>false</code> otherwise
+ */
+ public boolean checkError()
+ {
+ if (! closed)
+ flush();
+ return error;
+ }
+
+ /**
+ * This method flushes any buffered chars to the underlying stream and
+ * then flushes that stream as well.
+ */
+ public void flush()
+ {
+ try
+ {
+ out.flush();
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ /**
+ * This method closes this stream and all underlying streams.
+ */
+ public void close()
+ {
+ try
+ {
+ out.close();
+ closed = true;
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ /**
+ * This method prints a <code>String</code> to the stream. The actual
+ * value printed depends on the system default encoding.
+ *
+ * @param str The <code>String</code> to print.
+ */
+ public void print(String str)
+ {
+ write(str == null ? "null" : str);
+ }
+
+ /**
+ * This method prints a char to the stream. The actual value printed is
+ * determined by the character encoding in use.
+ *
+ * @param ch The <code>char</code> value to be printed
+ */
+ public void print(char ch)
+ {
+ write((int) ch);
+ }
+
+ /**
+ * This method prints an array of characters to the stream. The actual
+ * value printed depends on the system default encoding.
+ *
+ * @param charArray The array of characters to print.
+ */
+ public void print(char[] charArray)
+ {
+ write(charArray, 0, charArray.length);
+ }
+
+ /**
+ * This methods prints a boolean value to the stream. <code>true</code>
+ * values are printed as "true" and <code>false</code> values are printed
+ * as "false".
+ *
+ * @param bool The <code>boolean</code> value to print
+ */
+ public void print(boolean bool)
+ {
+ // We purposely call write() and not print() here. This preserves
+ // compatibility with JDK 1.2.
+ write (bool ? "true" : "false");
+ }
+
+ /**
+ * This method prints an integer to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * @param inum The <code>int</code> value to be printed
+ */
+ public void print(int inum)
+ {
+ // We purposely call write() and not print() here. This preserves
+ // compatibility with JDK 1.2.
+ write(Integer.toString(inum));
+ }
+
+ /**
+ * This method prints a long to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * @param lnum The <code>long</code> value to be printed
+ */
+ public void print(long lnum)
+ {
+ // We purposely call write() and not print() here. This preserves
+ // compatibility with JDK 1.2.
+ write(Long.toString(lnum));
+ }
+
+ /**
+ * This method prints a float to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * @param fnum The <code>float</code> value to be printed
+ */
+ public void print(float fnum)
+ {
+ // We purposely call write() and not print() here. This preserves
+ // compatibility with JDK 1.2.
+ write(Float.toString(fnum));
+ }
+
+ /**
+ * This method prints a double to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * @param dnum The <code>double</code> value to be printed
+ */
+ public void print(double dnum)
+ {
+ // We purposely call write() and not print() here. This preserves
+ // compatibility with JDK 1.2.
+ write(Double.toString(dnum));
+ }
+
+ /**
+ * This method prints an <code>Object</code> to the stream. The actual
+ * value printed is determined by calling the <code>String.valueOf()</code>
+ * method.
+ *
+ * @param obj The <code>Object</code> to print.
+ */
+ public void print(Object obj)
+ {
+ // We purposely call write() and not print() here. This preserves
+ // compatibility with JDK 1.2.
+ write(obj == null ? "null" : obj.toString());
+ }
+
+ /**
+ * This is the system dependent line separator
+ */
+ private static final char[] line_separator
+ = System.getProperty("line.separator", "\n").toCharArray();
+
+ /**
+ * This method prints a line separator sequence to the stream. The value
+ * printed is determined by the system property <xmp>line.separator</xmp>
+ * and is not necessarily the Unix '\n' newline character.
+ */
+ public void println()
+ {
+ synchronized (lock)
+ {
+ try
+ {
+ write(line_separator, 0, line_separator.length);
+ if (autoflush)
+ out.flush();
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+ }
+
+ /**
+ * This methods prints a boolean value to the stream. <code>true</code>
+ * values are printed as "true" and <code>false</code> values are printed
+ * as "false".
+ *
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param bool The <code>boolean</code> value to print
+ */
+ public void println(boolean bool)
+ {
+ synchronized (lock)
+ {
+ print(bool);
+ println();
+ }
+ }
+
+ /**
+ * This method prints an integer to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param inum The <code>int</code> value to be printed
+ */
+ public void println(int inum)
+ {
+ synchronized (lock)
+ {
+ print(inum);
+ println();
+ }
+ }
+
+ /**
+ * This method prints a long to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param lnum The <code>long</code> value to be printed
+ */
+ public void println(long lnum)
+ {
+ synchronized (lock)
+ {
+ print(lnum);
+ println();
+ }
+ }
+
+ /**
+ * This method prints a float to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param fnum The <code>float</code> value to be printed
+ */
+ public void println(float fnum)
+ {
+ synchronized (lock)
+ {
+ print(fnum);
+ println();
+ }
+ }
+
+ /**
+ * This method prints a double to the stream. The value printed is
+ * determined using the <code>String.valueOf()</code> method.
+ *
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param dnum The <code>double</code> value to be printed
+ */
+ public void println(double dnum)
+ {
+ synchronized (lock)
+ {
+ print(dnum);
+ println();
+ }
+ }
+
+ /**
+ * This method prints an <code>Object</code> to the stream. The actual
+ * value printed is determined by calling the <code>String.valueOf()</code>
+ * method.
+ *
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param obj The <code>Object</code> to print.
+ */
+ public void println(Object obj)
+ {
+ synchronized (lock)
+ {
+ print(obj);
+ println();
+ }
+ }
+
+ /**
+ * This method prints a <code>String</code> to the stream. The actual
+ * value printed depends on the system default encoding.
+ *
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param str The <code>String</code> to print.
+ */
+ public void println(String str)
+ {
+ synchronized (lock)
+ {
+ print(str);
+ println();
+ }
+ }
+
+ /**
+ * This method prints a char to the stream. The actual value printed is
+ * determined by the character encoding in use.
+ *
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param ch The <code>char</code> value to be printed
+ */
+ public void println(char ch)
+ {
+ synchronized (lock)
+ {
+ print(ch);
+ println();
+ }
+ }
+
+ /**
+ * This method prints an array of characters to the stream. The actual
+ * value printed depends on the system default encoding.
+ *
+ * This method prints a line termination sequence after printing the value.
+ *
+ * @param charArray The array of characters to print.
+ */
+ public void println(char[] charArray)
+ {
+ synchronized (lock)
+ {
+ print(charArray);
+ println();
+ }
+ }
+
+ /**
+ * This method writes a single char to the stream.
+ *
+ * @param ch The char to be written, passed as a int
+ */
+ public void write(int ch)
+ {
+ try
+ {
+ out.write(ch);
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ /**
+ * This method writes <code>count</code> chars from the specified array
+ * starting at index <code>offset</code> into the array.
+ *
+ * @param charArray The array of chars to write
+ * @param offset The index into the array to start writing from
+ * @param count The number of chars to write
+ */
+ public void write(char[] charArray, int offset, int count)
+ {
+ try
+ {
+ out.write(charArray, offset, count);
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ /**
+ * This method writes <code>count</code> chars from the specified
+ * <code>String</code> to the output starting at character position
+ * <code>offset</code> into the <code>String</code>
+ *
+ * @param str The <code>String</code> to write chars from
+ * @param offset The offset into the <code>String</code> to start writing from
+ * @param count The number of chars to write.
+ */
+ public void write(String str, int offset, int count)
+ {
+ try
+ {
+ out.write(str, offset, count);
+ }
+ catch (IOException ex)
+ {
+ error = true;
+ }
+ }
+
+ /**
+ * This method write all the chars in the specified array to the output.
+ *
+ * @param charArray The array of characters to write
+ */
+ public void write(char[] charArray)
+ {
+ write(charArray, 0, charArray.length);
+ }
+
+ /**
+ * This method writes the contents of the specified <code>String</code>
+ * to the underlying stream.
+ *
+ * @param str The <code>String</code> to write
+ */
+ public void write(String str)
+ {
+ write(str, 0, str.length());
+ }
+
+ /** @since 1.5 */
+ public PrintWriter append(char c)
+ {
+ write(c);
+ return this;
+ }
+
+ /** @since 1.5 */
+ public PrintWriter append(CharSequence cs)
+ {
+ write(cs == null ? "null" : cs.toString());
+ return this;
+ }
+
+ /** @since 1.5 */
+ public PrintWriter append(CharSequence cs, int start, int end)
+ {
+ write(cs == null ? "null" : cs.subSequence(start, end).toString());
+ return this;
+ }
+
+ /** @since 1.5 */
+ public PrintWriter printf(String format, Object... args)
+ {
+ return format(format, args);
+ }
+
+ /** @since 1.5 */
+ public PrintWriter printf(Locale locale, String format, Object... args)
+ {
+ return format(locale, format, args);
+ }
+
+ /** @since 1.5 */
+ public PrintWriter format(String format, Object... args)
+ {
+ return format(Locale.getDefault(), format, args);
+ }
+
+ /** @since 1.5 */
+ public PrintWriter format(Locale locale, String format, Object... args)
+ {
+ Formatter f = new Formatter(this, locale);
+ f.format(format, args);
+ return this;
+ }
+}
diff --git a/libjava/classpath/java/io/PushbackInputStream.java b/libjava/classpath/java/io/PushbackInputStream.java
new file mode 100644
index 000000000..62737870c
--- /dev/null
+++ b/libjava/classpath/java/io/PushbackInputStream.java
@@ -0,0 +1,335 @@
+/* PushbackInputStream.java -- An input stream that can unread bytes
+ Copyright (C) 1998, 1999, 2001, 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 java.io;
+
+/**
+ * This subclass of <code>FilterInputStream</code> provides the ability to
+ * unread data from a stream. It maintains an internal buffer of unread
+ * data that is supplied to the next read operation. This is conceptually
+ * similar to mark/reset functionality, except that in this case the
+ * position to reset the stream to does not need to be known in advance.
+ * <p>
+ * The default pushback buffer size one byte, but this can be overridden
+ * by the creator of the stream.
+ * <p>
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public class PushbackInputStream extends FilterInputStream
+{
+ /**
+ * This is the default buffer size
+ */
+ private static final int DEFAULT_BUFFER_SIZE = 1;
+
+ /**
+ * This is the buffer that is used to store the pushed back data
+ */
+ protected byte[] buf;
+
+ /**
+ * This is the position in the buffer from which the next byte will be
+ * read. Bytes are stored in reverse order in the buffer, starting from
+ * <code>buf[buf.length - 1]</code> to <code>buf[0]</code>. Thus when
+ * <code>pos</code> is 0 the buffer is full and <code>buf.length</code> when
+ * it is empty
+ */
+ protected int pos;
+
+ /**
+ * This method initializes a <code>PushbackInputStream</code> to
+ * read from the specified subordinate <code>InputStream</code>
+ * with a default pushback buffer size of 1.
+ *
+ * @param in The subordinate stream to read from
+ */
+ public PushbackInputStream(InputStream in)
+ {
+ this(in, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * This method initializes a <code>PushbackInputStream</code> to
+ * read from the specified subordinate <code>InputStream</code> with
+ * the specified buffer size
+ *
+ * @param in The subordinate <code>InputStream</code> to read from
+ * @param size The pushback buffer size to use
+ */
+ public PushbackInputStream(InputStream in, int size)
+ {
+ super(in);
+ if (size < 0)
+ throw new IllegalArgumentException();
+ buf = new byte[size];
+ pos = buf.length;
+ }
+
+ /**
+ * This method returns the number of bytes that can be read from this
+ * stream before a read can block. A return of 0 indicates that blocking
+ * might (or might not) occur on the very next read attempt.
+ * <p>
+ * This method will return the number of bytes available from the
+ * pushback buffer plus the number of bytes available from the
+ * underlying stream.
+ *
+ * @return The number of bytes that can be read before blocking could occur
+ *
+ * @exception IOException If an error occurs
+ */
+ public int available() throws IOException
+ {
+ try
+ {
+ return (buf.length - pos) + super.available();
+ }
+ catch (NullPointerException npe)
+ {
+ throw new IOException ("Stream closed");
+ }
+ }
+
+ /**
+ * This method closes the stream and releases any associated resources.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public synchronized void close() throws IOException
+ {
+ buf = null;
+ super.close();
+ }
+
+ /**
+ * This method returns <code>false</code> to indicate that it does
+ * not support mark/reset functionality.
+ *
+ * @return This method returns <code>false</code> to indicate that
+ * this class does not support mark/reset functionality
+ */
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ /**
+ * This method always throws an IOException in this class because
+ * mark/reset functionality is not supported.
+ *
+ * @exception IOException Always thrown for this class
+ */
+ public void reset() throws IOException
+ {
+ throw new IOException("Mark not supported in this class");
+ }
+
+ /**
+ * This method reads an unsigned byte from the input stream and returns it
+ * as an int in the range of 0-255. This method also will return -1 if
+ * the end of the stream has been reached. The byte returned will be read
+ * from the pushback buffer, unless the buffer is empty, in which case
+ * the byte will be read from the underlying stream.
+ * <p>
+ * This method will block until the byte can be read.
+ *
+ * @return The byte read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public synchronized int read() throws IOException
+ {
+ if (pos < buf.length)
+ return ((int) buf[pos++]) & 0xFF;
+
+ return super.read();
+ }
+
+ /**
+ * This method read bytes from a stream and stores them into a
+ * caller supplied buffer. It starts storing the data at index
+ * <code>offset</code> into the buffer and attempts to read
+ * <code>len</code> bytes. This method can return before reading the
+ * number of bytes requested. The actual number of bytes read is
+ * returned as an int. A -1 is returned to indicate the end of the
+ * stream.
+ * <p>
+ * This method will block until some data can be read.
+ * <p>
+ * This method first reads bytes from the pushback buffer in order to
+ * satisfy the read request. If the pushback buffer cannot provide all
+ * of the bytes requested, the remaining bytes are read from the
+ * underlying stream.
+ *
+ * @param b The array into which the bytes read should be stored
+ * @param off The offset into the array 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.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public synchronized int read(byte[] b, int off, int len) throws IOException
+ {
+ int numBytes = Math.min(buf.length - pos, len);
+
+ if (numBytes > 0)
+ {
+ System.arraycopy (buf, pos, b, off, numBytes);
+ pos += numBytes;
+ len -= numBytes;
+ off += numBytes;
+ }
+
+ if (len > 0)
+ {
+ len = super.read(b, off, len);
+ if (len == -1) //EOF
+ return numBytes > 0 ? numBytes : -1;
+ numBytes += len;
+ }
+ return numBytes;
+ }
+
+ /**
+ * This method pushes a single byte of data into the pushback buffer.
+ * The byte pushed back is the one that will be returned as the first byte
+ * of the next read.
+ * <p>
+ * If the pushback buffer is full, this method throws an exception.
+ * <p>
+ * The argument to this method is an <code>int</code>. Only the low
+ * eight bits of this value are pushed back.
+ *
+ * @param b The byte to be pushed back, passed as an int
+ *
+ * @exception IOException If the pushback buffer is full.
+ */
+ public synchronized void unread(int b) throws IOException
+ {
+ if (pos <= 0)
+ throw new IOException("Insufficient space in pushback buffer");
+
+ buf[--pos] = (byte) b;
+ }
+
+ /**
+ * This method pushes all of the bytes in the passed byte array into
+ * the pushback bfer. These bytes are pushed in reverse order so that
+ * the next byte read from the stream after this operation will be
+ * <code>b[0]</code> followed by <code>b[1]</code>, etc.
+ * <p>
+ * If the pushback buffer cannot hold all of the requested bytes, an
+ * exception is thrown.
+ *
+ * @param b The byte array to be pushed back
+ *
+ * @exception IOException If the pushback buffer is full
+ */
+ public synchronized void unread(byte[] b) throws IOException
+ {
+ unread(b, 0, b.length);
+ }
+
+ /**
+ * This method pushed back bytes from the passed in array into the
+ * pushback buffer. The bytes from <code>b[offset]</code> to
+ * <code>b[offset + len]</code> are pushed in reverse order so that
+ * the next byte read from the stream after this operation will be
+ * <code>b[offset]</code> followed by <code>b[offset + 1]</code>,
+ * etc.
+ * <p>
+ * If the pushback buffer cannot hold all of the requested bytes, an
+ * exception is thrown.
+ *
+ * @param b The byte array to be pushed back
+ * @param off The index into the array where the bytes to be push start
+ * @param len The number of bytes to be pushed.
+ *
+ * @exception IOException If the pushback buffer is full
+ */
+ public synchronized void unread(byte[] b, int off, int len)
+ throws IOException
+ {
+ if (pos < len)
+ throw new IOException("Insufficient space in pushback buffer");
+
+ // Note the order that these bytes are being added is the opposite
+ // of what would be done if they were added to the buffer one at a time.
+ // See the Java Class Libraries book p. 1390.
+ System.arraycopy(b, off, buf, pos - len, len);
+
+ // Don't put this into the arraycopy above, an exception might be thrown
+ // and in that case we don't want to modify pos.
+ pos -= len;
+ }
+
+ /**
+ * This method skips the specified number of bytes in the stream. It
+ * returns the actual number of bytes skipped, which may be less than the
+ * requested amount.
+ * <p>
+ * This method first discards bytes from the buffer, then calls the
+ * <code>skip</code> method on the underlying <code>InputStream</code> to
+ * skip additional bytes if necessary.
+ *
+ * @param n The requested number of bytes to skip
+ *
+ * @return The actual number of bytes skipped.
+ *
+ * @exception IOException If an error occurs
+ *
+ * @since 1.2
+ */
+ public synchronized long skip(long n) throws IOException
+ {
+ final long origN = n;
+
+ if (n > 0L)
+ {
+ int numread = (int) Math.min((long) (buf.length - pos), n);
+ pos += numread;
+ n -= numread;
+ if (n > 0)
+ n -= super.skip(n);
+ }
+
+ return origN - n;
+ }
+}
diff --git a/libjava/classpath/java/io/PushbackReader.java b/libjava/classpath/java/io/PushbackReader.java
new file mode 100644
index 000000000..43bf826a8
--- /dev/null
+++ b/libjava/classpath/java/io/PushbackReader.java
@@ -0,0 +1,383 @@
+/* PushbackReader.java -- An character stream that can unread chars
+ Copyright (C) 1998, 2000, 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 java.io;
+
+/**
+ * This subclass of <code>FilterReader</code> provides the ability to
+ * unread data from a stream. It maintains an internal buffer of unread
+ * data that is supplied to the next read operation. This is conceptually
+ * similar to mark/reset functionality, except that in this case the
+ * position to reset the stream to does not need to be known in advance.
+ * <p>
+ * The default pushback buffer size one char, but this can be overridden
+ * by the creator of the stream.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public class PushbackReader extends FilterReader
+{
+ /**
+ * This is the default buffer size
+ */
+ private static final int DEFAULT_BUFFER_SIZE = 1;
+
+ /**
+ * This is the buffer that is used to store the pushed back data
+ */
+ private char[] buf;
+
+ /**
+ * This is the position in the buffer from which the next char will be
+ * read. Bytes are stored in reverse order in the buffer, starting from
+ * <code>buf[buf.length - 1]</code> to <code>buf[0]</code>. Thus when
+ * <code>pos</code> is 0 the buffer is full and <code>buf.length</code> when
+ * it is empty
+ */
+ private int pos;
+
+ /**
+ * This method initializes a <code>PushbackReader</code> to read from the
+ * specified subordinate <code>Reader</code> with a default pushback buffer
+ * size of 1.
+ *
+ * @param in The subordinate stream to read from
+ */
+ public PushbackReader(Reader in)
+ {
+ this(in, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * This method initializes a <code>PushbackReader</code> to read from the
+ * specified subordinate <code>Reader</code> with the specified buffer
+ * size
+ *
+ * @param in The subordinate <code>Reader</code> to read from
+ * @param bufsize The pushback buffer size to use
+ */
+ public PushbackReader(Reader in, int bufsize)
+ {
+ super(in);
+
+ if (bufsize < 0)
+ throw new IllegalArgumentException("buffer size must be positive");
+
+ buf = new char[bufsize];
+ pos = bufsize;
+ }
+
+ /**
+ * This method closes the stream and frees any associated resources.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public void close() throws IOException
+ {
+ synchronized (lock)
+ {
+ buf = null;
+ super.close();
+ }
+ }
+
+ /**
+ * This method throws an exception when called since this class does
+ * not support mark/reset.
+ *
+ * @param read_limit Not used.
+ *
+ * @exception IOException Always thrown to indicate mark/reset not supported.
+ */
+ public void mark(int read_limit) throws IOException
+ {
+ throw new IOException("mark not supported in this class");
+ }
+
+ /**
+ * This method returns <code>false</code> to indicate that it does not support
+ * mark/reset functionality.
+ *
+ * @return This method returns <code>false</code> to indicate that this
+ * class does not support mark/reset functionality
+ *
+ */
+ public boolean markSupported()
+ {
+ return(false);
+ }
+
+ /**
+ * This method always throws an IOException in this class because
+ * mark/reset functionality is not supported.
+ *
+ * @exception IOException Always thrown for this class
+ */
+ public void reset() throws IOException
+ {
+ throw new IOException("reset not supported in this class");
+ }
+
+ /**
+ * This method determines whether or not this stream is ready to be read.
+ * If it returns <code>false</code> to indicate that the stream is not
+ * ready, any attempt to read from the stream could (but is not
+ * guaranteed to) block.
+ * <p>
+ * This stream is ready to read if there are either chars waiting to be
+ * read in the pushback buffer or if the underlying stream is ready to
+ * be read.
+ *
+ * @return <code>true</code> if this stream is ready to be read,
+ * <code>false</code> otherwise
+ *
+ * @exception IOException If an error occurs
+ */
+ public boolean ready() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException ("stream closed");
+
+ if (((buf.length - pos) > 0) || super.ready())
+ return(true);
+ else
+ return(false);
+ }
+ }
+
+ // Don't delete this method just because the spec says it shouldn't be there!
+ // See the CVS log for details.
+ /**
+ * This method skips the specified number of chars in the stream. It
+ * returns the actual number of chars skipped, which may be less than the
+ * requested amount.
+ * <p>
+ * This method first discards chars from the buffer, then calls the
+ * <code>skip</code> method on the underlying <code>Reader</code> to
+ * skip additional chars if necessary.
+ *
+ * @param num_chars The requested number of chars to skip
+ *
+ * @return The actual number of chars skipped.
+ *
+ * @exception IOException If an error occurs
+ */
+ public long skip(long num_chars) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (num_chars <= 0)
+ return(0);
+
+ if ((buf.length - pos) >= num_chars)
+ {
+ pos += num_chars;
+ return(num_chars);
+ }
+
+ int chars_discarded = buf.length - pos;
+ pos = buf.length;
+
+ long chars_skipped = in.skip(num_chars - chars_discarded);
+
+ return(chars_discarded + chars_skipped);
+ }
+ }
+
+ /**
+ * This method reads an unsigned char from the input stream and returns it
+ * as an int in the range of 0-65535. This method also will return -1 if
+ * the end of the stream has been reached. The char returned will be read
+ * from the pushback buffer, unless the buffer is empty, in which case
+ * the char will be read from the underlying stream.
+ * <p>
+ * This method will block until the char can be read.
+ *
+ * @return The char read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("stream closed");
+
+ if (pos == buf.length)
+ return(super.read());
+
+ ++pos;
+ return((buf[pos - 1] & 0xFFFF));
+ }
+ }
+
+ /**
+ * This method read chars from a stream and stores them into a caller
+ * supplied buffer. It starts storing the data at index <code>offset</code>
+ * into
+ * the buffer and attempts to read <code>len</code> chars. This method can
+ * return before reading the number of chars requested. The actual number
+ * of chars read is returned as an int. A -1 is returned to indicate the
+ * end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ * <p>
+ * This method first reads chars from the pushback buffer in order to
+ * satisfy the read request. If the pushback buffer cannot provide all
+ * of the chars requested, the remaining chars are read from the
+ * underlying stream.
+ *
+ * @param buffer The array into which the chars read should be stored
+ * @param offset The offset into the array to start storing chars
+ * @param length The requested number of chars to read
+ *
+ * @return The actual number of chars read, or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public synchronized int read(char[] buffer, int offset, int length)
+ throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("stream closed");
+
+ if (offset < 0 || length < 0 || offset + length > buffer.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ int numBytes = Math.min(buf.length - pos, length);
+ if (numBytes > 0)
+ {
+ System.arraycopy (buf, pos, buffer, offset, numBytes);
+ pos += numBytes;
+ return numBytes;
+ }
+
+ return super.read(buffer, offset, length);
+ }
+ }
+
+ /**
+ * This method pushes a single char of data into the pushback buffer.
+ * The char pushed back is the one that will be returned as the first char
+ * of the next read.
+ * <p>
+ * If the pushback buffer is full, this method throws an exception.
+ * <p>
+ * The argument to this method is an <code>int</code>. Only the low eight
+ * bits of this value are pushed back.
+ *
+ * @param b The char to be pushed back, passed as an int
+ *
+ * @exception IOException If the pushback buffer is full.
+ */
+ public void unread(int b) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("stream closed");
+ if (pos == 0)
+ throw new IOException("Pushback buffer is full");
+
+ --pos;
+ buf[pos] = (char)(b & 0xFFFF);
+ }
+ }
+
+ /**
+ * This method pushes all of the chars in the passed char array into
+ * the pushback buffer. These chars are pushed in reverse order so that
+ * the next char read from the stream after this operation will be
+ * <code>buf[0]</code> followed by <code>buf[1]</code>, etc.
+ * <p>
+ * If the pushback buffer cannot hold all of the requested chars, an
+ * exception is thrown.
+ *
+ * @param buf The char array to be pushed back
+ *
+ * @exception IOException If the pushback buffer is full
+ */
+ public synchronized void unread(char[] buf) throws IOException
+ {
+ unread(buf, 0, buf.length);
+ }
+
+ /**
+ * This method pushed back chars from the passed in array into the pushback
+ * buffer. The chars from <code>buf[offset]</code> to
+ * <code>buf[offset + len]</code>
+ * are pushed in reverse order so that the next char read from the stream
+ * after this operation will be <code>buf[offset]</code> followed by
+ * <code>buf[offset + 1]</code>, etc.
+ * <p>
+ * If the pushback buffer cannot hold all of the requested chars, an
+ * exception is thrown.
+ *
+ * @param buffer The char array to be pushed back
+ * @param offset The index into the array where the chars to be push start
+ * @param length The number of chars to be pushed.
+ *
+ * @exception IOException If the pushback buffer is full
+ */
+ public synchronized void unread(char[] buffer, int offset, int length)
+ throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("stream closed");
+ if (pos < length)
+ throw new IOException("Pushback buffer is full");
+
+ // Note the order that these chars are being added is the opposite
+ // of what would be done if they were added to the buffer one at a time.
+ // See the Java Class Libraries book p. 1397.
+ System.arraycopy(buffer, offset, buf, pos - length, length);
+
+ // Don't put this into the arraycopy above, an exception might be thrown
+ // and in that case we don't want to modify pos.
+ pos -= length;
+ }
+ }
+}
diff --git a/libjava/classpath/java/io/RandomAccessFile.java b/libjava/classpath/java/io/RandomAccessFile.java
new file mode 100644
index 000000000..da0c81272
--- /dev/null
+++ b/libjava/classpath/java/io/RandomAccessFile.java
@@ -0,0 +1,1049 @@
+/* RandomAccessFile.java -- Class supporting random file I/O
+ Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+import gnu.java.nio.FileChannelImpl;
+
+import java.nio.channels.FileChannel;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * Status: Believe complete and correct to 1.1.
+ */
+
+/**
+ * This class allows reading and writing of files at random locations.
+ * Most Java I/O classes are either pure sequential input or output. This
+ * class fulfills the need to be able to read the bytes of a file in an
+ * arbitrary order. In addition, this class implements the
+ * <code>DataInput</code> and <code>DataOutput</code> interfaces to allow
+ * the reading and writing of Java primitives.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ */
+public class RandomAccessFile implements DataOutput, DataInput, Closeable
+{
+
+ // The underlying file.
+ private FileChannelImpl ch;
+ private FileDescriptor fd;
+ // The corresponding input and output streams.
+ private DataOutputStream out;
+ private DataInputStream in;
+
+
+ /**
+ * This method initializes a new instance of <code>RandomAccessFile</code>
+ * to read from the specified <code>File</code> object with the specified
+ * access mode. The access mode is either "r" for read only access or "rw"
+ * for read-write access.
+ * <p>
+ * Note that a <code>SecurityManager</code> check is made prior to
+ * opening the file to determine whether or not this file is allowed to
+ * be read or written.
+ *
+ * @param file The <code>File</code> object to read and/or write.
+ * @param mode "r" for read only or "rw" for read-write access to the file
+ *
+ * @exception IllegalArgumentException If <code>mode</code> has an
+ * illegal value
+ * @exception SecurityException If the requested access to the file
+ * is not allowed
+ * @exception FileNotFoundException If the file is a directory, or
+ * any other error occurs
+ */
+ public RandomAccessFile (File file, String mode)
+ throws FileNotFoundException
+ {
+ int fdmode;
+ if (mode.equals("r"))
+ fdmode = FileChannelImpl.READ;
+ else if (mode.equals("rw"))
+ fdmode = FileChannelImpl.READ | FileChannelImpl.WRITE;
+ else if (mode.equals("rws"))
+ {
+ fdmode = (FileChannelImpl.READ | FileChannelImpl.WRITE
+ | FileChannelImpl.SYNC);
+ }
+ else if (mode.equals("rwd"))
+ {
+ fdmode = (FileChannelImpl.READ | FileChannelImpl.WRITE
+ | FileChannelImpl.DSYNC);
+ }
+ else
+ throw new IllegalArgumentException ("invalid mode: " + mode);
+
+ final String fileName = file.getPath();
+
+ // The obligatory SecurityManager stuff
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ {
+ s.checkRead(fileName);
+
+ if ((fdmode & FileChannelImpl.WRITE) != 0)
+ s.checkWrite(fileName);
+ }
+
+ try
+ {
+ ch = FileChannelImpl.create(file, fdmode);
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ throw fnfe;
+ }
+ catch (IOException ioe)
+ {
+ FileNotFoundException fnfe = new FileNotFoundException(file.getPath());
+ fnfe.initCause(ioe);
+ throw fnfe;
+ }
+ fd = new FileDescriptor(ch);
+ if ((fdmode & FileChannelImpl.WRITE) != 0)
+ out = new DataOutputStream (new FileOutputStream (fd));
+ else
+ out = null;
+ in = new DataInputStream (new FileInputStream (fd));
+ }
+
+ /**
+ * This method initializes a new instance of <code>RandomAccessFile</code>
+ * to read from the specified file name with the specified access mode.
+ * The access mode is either "r" for read only access, "rw" for read
+ * write access, "rws" for synchronized read/write access of both
+ * content and metadata, or "rwd" for read/write access
+ * where only content is required to be synchronous.
+ * <p>
+ * Note that a <code>SecurityManager</code> check is made prior to
+ * opening the file to determine whether or not this file is allowed to
+ * be read or written.
+ *
+ * @param fileName The name of the file to read and/or write
+ * @param mode "r", "rw", "rws", or "rwd"
+ *
+ * @exception IllegalArgumentException If <code>mode</code> has an
+ * illegal value
+ * @exception SecurityException If the requested access to the file
+ * is not allowed
+ * @exception FileNotFoundException If the file is a directory or
+ * any other error occurs
+ */
+ public RandomAccessFile (String fileName, String mode)
+ throws FileNotFoundException
+ {
+ this (new File(fileName), mode);
+ }
+
+ /**
+ * This method closes the file and frees up all file related system
+ * resources. Since most operating systems put a limit on how many files
+ * may be opened at any given time, it is a good idea to close all files
+ * when no longer needed to avoid hitting this limit
+ */
+ public void close () throws IOException
+ {
+ ch.close();
+ }
+
+ /**
+ * This method returns a <code>FileDescriptor</code> object that
+ * represents the native file handle for this file.
+ *
+ * @return The <code>FileDescriptor</code> object for this file
+ *
+ * @exception IOException If an error occurs
+ */
+ public final FileDescriptor getFD () throws IOException
+ {
+ synchronized (this)
+ {
+ if (fd == null)
+ fd = new FileDescriptor (ch);
+ return fd;
+ }
+ }
+
+ /**
+ * This method returns the current offset in the file at which the next
+ * read or write will occur
+ *
+ * @return The current file position
+ *
+ * @exception IOException If an error occurs
+ */
+ public long getFilePointer () throws IOException
+ {
+ return ch.position();
+ }
+
+ /**
+ * This method sets the length of the file to the specified length.
+ * If the currently length of the file is longer than the specified
+ * length, then the file is truncated to the specified length (the
+ * file position is set to the end of file in this case). If the
+ * current length of the file is shorter than the specified length,
+ * the file is extended with bytes of an undefined value (the file
+ * position is unchanged in this case).
+ * <p>
+ * The file must be open for write access for this operation to succeed.
+ *
+ * @param newLen The new length of the file
+ *
+ * @exception IOException If an error occurs
+ */
+ public void setLength (long newLen) throws IOException
+ {
+ // FIXME: Extending a file should probably be done by one method call.
+
+ // FileChannel.truncate() can only shrink a file.
+ // To expand it we need to seek forward and write at least one byte.
+ if (newLen < length())
+ ch.truncate (newLen);
+ else if (newLen > length())
+ {
+ long pos = getFilePointer();
+ seek(newLen - 1);
+ write(0);
+ seek(pos);
+ }
+ }
+
+ /**
+ * This method returns the length of the file in bytes
+ *
+ * @return The length of the file
+ *
+ * @exception IOException If an error occurs
+ */
+ public long length () throws IOException
+ {
+ return ch.size();
+ }
+
+ /**
+ * This method reads a single byte of data from the file and returns it
+ * as an integer.
+ *
+ * @return The byte read as an int, or -1 if the end of the file was reached.
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read () throws IOException
+ {
+ return in.read();
+ }
+
+ /**
+ * This method reads bytes from the file into the specified array. The
+ * bytes are stored starting at the beginning of the array and up to
+ * <code>buf.length</code> bytes can be read.
+ *
+ * @param buffer The buffer to read bytes from the file into
+ *
+ * @return The actual number of bytes read or -1 if end of file
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read (byte[] buffer) throws IOException
+ {
+ return in.read (buffer);
+ }
+
+ /**
+ * This methods reads up to <code>len</code> bytes from the file into the
+ * specified array starting at position <code>offset</code> into the array.
+ *
+ * @param buffer The array to read the bytes into
+ * @param offset The index into the array 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 file
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read (byte[] buffer, int offset, int len) throws IOException
+ {
+ return in.read (buffer, offset, 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 <code>false</code> If the byte is non-zero, then
+ * the value returned is <code>true</code>
+ * <p>
+ * This method can read a <code>boolean</code> written by an object
+ * implementing the
+ * <code>writeBoolean()</code> method in the <code>DataOutput</code>
+ * interface.
+ *
+ * @return The <code>boolean</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the
+ * boolean
+ * @exception IOException If any other error occurs
+ */
+ public final boolean readBoolean () throws IOException
+ {
+ return in.readBoolean ();
+ }
+
+ /**
+ * This method reads a Java byte value from an input stream. The value
+ * is in the range of -128 to 127.
+ * <p>
+ * This method can read a <code>byte</code> written by an object
+ * implementing the
+ * <code>writeByte()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>byte</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the byte
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+ public final byte readByte () throws IOException
+ {
+ return in.readByte ();
+ }
+
+ /**
+ * This method reads a Java <code>char</code> value from an input stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single 16-bit Java <code>char</code> The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code> represent
+ * the first
+ * and second byte read from the stream respectively, they will be
+ * transformed to a <code>char</code> in the following manner:
+ * <p>
+ * <code>(char)(((byte1 &amp; 0xFF) &lt;&lt; 8) | (byte2 &amp; 0xFF)</code>
+ * <p>
+ * This method can read a <code>char</code> written by an object
+ * implementing the
+ * <code>writeChar()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>char</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the char
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+ public final char readChar () throws IOException
+ {
+ return in.readChar();
+ }
+
+ /**
+ * This method reads a Java double value from an input stream. It operates
+ * by first reading a <code>logn</code> value from the stream by calling the
+ * <code>readLong()</code> method in this interface, then
+ * converts that <code>long</code>
+ * to a <code>double</code> using the <code>longBitsToDouble</code>
+ * method in the class <code>java.lang.Double</code>
+ * <p>
+ * This method can read a <code>double</code> written by an object
+ * implementing the
+ * <code>writeDouble()</code> method in the <code>DataOutput</code>
+ * interface.
+ *
+ * @return The <code>double</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading
+ * the double
+ * @exception IOException If any other error occurs
+ *
+ * @see java.lang.Double
+ * @see DataOutput
+ */
+ public final double readDouble () throws IOException
+ {
+ return in.readDouble ();
+ }
+
+ /**
+ * This method reads a Java float value from an input stream. It operates
+ * by first reading an <code>int</code> value from the stream by calling the
+ * <code>readInt()</code> method in this interface, then converts
+ * that <code>int</code>
+ * to a <code>float</code> using the <code>intBitsToFloat</code> method in
+ * the class <code>java.lang.Float</code>
+ * <p>
+ * This method can read a <code>float</code> written by an object
+ * implementing the
+ * <code>writeFloat()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>float</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the float
+ * @exception IOException If any other error occurs
+ *
+ * @see java.lang.Float
+ * @see DataOutput
+ */
+ public final float readFloat () throws IOException
+ {
+ return in.readFloat();
+ }
+
+ /**
+ * 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
+ *
+ * @param buffer 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 final void readFully (byte[] buffer) throws IOException
+ {
+ in.readFully(buffer);
+ }
+
+ /**
+ * This method reads raw bytes into the passed array <code>buf</code>
+ * starting
+ * <code>offset</code> bytes into the buffer. The number of bytes read
+ * will be
+ * exactly <code>len</code> 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 <code>len</code> bytes.
+ *
+ * @param buffer The buffer into which to read the data
+ * @param offset The offset into the buffer to start storing data
+ * @param count 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 final void readFully (byte[] buffer, int offset, int count)
+ throws IOException
+ {
+ in.readFully (buffer, offset, count);
+ }
+
+ /**
+ * This method reads a Java <code>int</code> value from an input stream
+ * It operates by reading four bytes from the stream and converting them to
+ * a single Java <code>int</code> The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte4</code>
+ * represent the first
+ * four bytes read from the stream, they will be
+ * transformed to an <code>int</code> in the following manner:
+ * <p>
+ * <code>(int)(((byte1 &amp; 0xFF) &lt;&lt; 24) + ((byte2 &amp; 0xFF) &lt;&lt; 16) +
+ * ((byte3 &amp; 0xFF) &lt;&lt; 8) + (byte4 &amp; 0xFF)))</code>
+ * <p>
+ * The value returned is in the range of 0 to 65535.
+ * <p>
+ * This method can read an <code>int</code> written by an object
+ * implementing the
+ * <code>writeInt()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>int</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the int
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+ public final int readInt () throws IOException
+ {
+ return in.readInt();
+ }
+
+ /**
+ * This method reads the next line of text data from an input stream.
+ * It operates by reading bytes and converting those bytes to
+ * <code>char</code>
+ * values by treating the byte read as the low eight bits of the
+ * <code>char</code>
+ * and using <code>0</code> as the high eight bits. Because of this, it does
+ * not support the full 16-bit Unicode character set.
+ * <p>
+ * 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 <code>String</code>
+ * A line terminator is a byte sequence consisting of either
+ * <code>\r</code> <code>\n</code> or <code>\r\n</code> These
+ * termination charaters are
+ * discarded and are not returned as part of the string.
+ * <p>
+ * This method can read data that was written by an object implementing the
+ * <code>writeLine()</code> method in <code>DataOutput</code>
+ *
+ * @return The line read as a <code>String</code>
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataOutput
+ */
+ public final String readLine () throws IOException
+ {
+ return in.readLine ();
+ }
+
+ /**
+ * 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 <code>long</code> The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte8</code>
+ * represent the first
+ * eight bytes read from the stream, they will be
+ * transformed to an <code>long</code> in the following manner:
+ * <p>
+ * <code>
+ * (long)((((long)byte1 &amp; 0xFF) &lt;&lt; 56) + (((long)byte2 &amp; 0xFF) &lt;&lt; 48) +
+ * (((long)byte3 &amp; 0xFF) &lt;&lt; 40) + (((long)byte4 &amp; 0xFF) &lt;&lt; 32) +
+ * (((long)byte5 &amp; 0xFF) &lt;&lt; 24) + (((long)byte6 &amp; 0xFF) &lt;&lt; 16) +
+ * (((long)byte7 &amp; 0xFF) &lt;&lt; 8) + ((long)byte9 &amp; 0xFF)))</code>
+ * <p>
+ * The value returned is in the range of 0 to 65535.
+ * <p>
+ * This method can read an <code>long</code> written by an object
+ * implementing the
+ * <code>writeLong()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>long</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the long
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+ public final long readLong () throws IOException
+ {
+ return in.readLong();
+ }
+
+ /**
+ * 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 <code>short</code> The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * represent the first
+ * and second byte read from the stream respectively, they will be
+ * transformed to a <code>short</code> in the following manner:
+ * <p>
+ * <code>(short)(((byte1 &amp; 0xFF) &lt;&lt; 8) | (byte2 &amp; 0xFF)</code>
+ * <p>
+ * The value returned is in the range of -32768 to 32767.
+ * <p>
+ * This method can read a <code>short</code> written by an object
+ * implementing the
+ * <code>writeShort()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>short</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+ public final short readShort () throws IOException
+ {
+ return in.readShort();
+ }
+
+ /**
+ * This method reads 8 unsigned bits into a Java <code>int</code> value
+ * from the
+ * stream. The value returned is in the range of 0 to 255.
+ * <p>
+ * This method can read an unsigned byte written by an object implementing
+ * the <code>writeUnsignedByte()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The unsigned bytes value read as a Java <code>int</code>
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+ public final int readUnsignedByte () throws IOException
+ {
+ return in.readUnsignedByte();
+ }
+
+ /**
+ * 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 <code>int</code> The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * represent the first
+ * and second byte read from the stream respectively, they will be
+ * transformed to an <code>int</code> in the following manner:
+ * <p>
+ * <code>(int)(((byte1 &amp; 0xFF) &lt;&lt; 8) + (byte2 &amp; 0xFF))</code>
+ * <p>
+ * The value returned is in the range of 0 to 65535.
+ * <p>
+ * This method can read an unsigned short written by an object implementing
+ * the <code>writeUnsignedShort()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The unsigned short value read as a Java <code>int</code>
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ */
+ public final int readUnsignedShort () throws IOException
+ {
+ return in.readUnsignedShort();
+ }
+
+ /**
+ * This method reads a <code>String</code> from an input stream that
+ * is encoded in
+ * a modified UTF-8 format. This format has a leading two byte sequence
+ * that contains the remaining number of bytes to read. This two byte
+ * sequence is read using the <code>readUnsignedShort()</code> method of this
+ * interface.
+ * <p>
+ * After the number of remaining bytes have been determined, these bytes
+ * are read an transformed into <code>char</code> values.
+ * These <code>char</code> values
+ * are encoded in the stream using either a one, two, or three byte format.
+ * The particular format in use can be determined by examining the first
+ * byte read.
+ * <p>
+ * If the first byte has a high order bit of 0 then
+ * that character consists on only one byte. This character value consists
+ * of seven bits that are at positions 0 through 6 of the byte. As an
+ * example, if <code>byte1</code> is the byte read from the stream, it would
+ * be converted to a <code>char</code> like so:
+ * <p>
+ * <code>(char)byte1</code>
+ * <p>
+ * If the first byte has <code>110</code> as its high order bits, then the
+ * character consists of two bytes. The bits that make up the character
+ * value are in positions 0 through 4 of the first byte and bit positions
+ * 0 through 5 of the second byte. (The second byte should have
+ * 10 as its high order bits). These values are in most significant
+ * byte first (i.e., "big endian") order.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * are the first two bytes
+ * read respectively, and the high order bits of them match the patterns
+ * which indicate a two byte character encoding, then they would be
+ * converted to a Java <code>char</code> like so:
+ * <p>
+ * <code>(char)(((byte1 & 0x1F) << 6) | (byte2 & 0x3F))</code>
+ * <p>
+ * If the first byte has a <code>1110</code> as its high order bits, then the
+ * character consists of three bytes. The bits that make up the character
+ * value are in positions 0 through 3 of the first byte and bit positions
+ * 0 through 5 of the other two bytes. (The second and third bytes should
+ * have <code>10</code> as their high order bits). These values are in most
+ * significant byte first (i.e., "big endian") order.
+ * <p>
+ * As an example, if <code>byte1</code> <code>byte2</code>
+ * and <code>byte3</code> are the
+ * three bytes read, and the high order bits of them match the patterns
+ * which indicate a three byte character encoding, then they would be
+ * converted to a Java <code>char</code> like so:
+ * <p>
+ * <code>(char)(((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) |
+ * (byte3 & 0x3F))</code>
+ * <p>
+ * Note that all characters are encoded in the method that requires the
+ * fewest number of bytes with the exception of the character with the
+ * value of <code>&#92;u0000</code> which is encoded as two bytes. This is
+ * a modification of the UTF standard used to prevent C language style
+ * <code>NUL</code> values from appearing in the byte stream.
+ * <p>
+ * This method can read data that was written by an object implementing the
+ * <code>writeUTF()</code> method in <code>DataOutput</code>
+ *
+ * @return The <code>String</code> read
+ *
+ * @exception EOFException If end of file is reached before reading the
+ * String
+ * @exception UTFDataFormatException If the data is not in UTF-8 format
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+ public final String readUTF () throws IOException
+ {
+ return in.readUTF();
+ }
+
+ /**
+ * This method sets the current file position to the specified offset
+ * from the beginning of the file. Note that some operating systems will
+ * allow the file pointer to be set past the current end of the file.
+ *
+ * @param pos The offset from the beginning of the file at which to set
+ * the file pointer
+ *
+ * @exception IOException If an error occurs
+ */
+ public void seek (long pos) throws IOException
+ {
+ ch.position(pos);
+ }
+
+ /**
+ * This method attempts to skip and discard the specified number of bytes
+ * in the input stream. It may actually skip fewer bytes than requested.
+ * The actual number of bytes skipped is returned. This method will not
+ * skip any bytes if passed a negative number of bytes to skip.
+ *
+ * @param numBytes The requested number of bytes to skip.
+ *
+ * @return The number of bytes actually skipped.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int skipBytes (int numBytes) throws IOException
+ {
+ if (numBytes < 0)
+ throw new IllegalArgumentException ("Can't skip negative bytes: " +
+ numBytes);
+
+ if (numBytes == 0)
+ return 0;
+
+ long oldPos = ch.position();
+ long newPos = oldPos + numBytes;
+ long size = ch.size();
+ if (newPos > size)
+ newPos = size;
+ ch.position(newPos);
+ return (int) (ch.position() - oldPos);
+ }
+
+ /**
+ * This method writes a single byte of data to the file. The file must
+ * be open for read-write in order for this operation to succeed.
+ *
+ * @param oneByte The byte of data to write, passed as an int.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (int oneByte) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.write(oneByte);
+ }
+
+ /**
+ * This method writes all the bytes in the specified array to the file.
+ * The file must be open read-write in order for this operation to succeed.
+ *
+ * @param buffer The array of bytes to write to the file
+ */
+ public void write (byte[] buffer) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.write(buffer);
+ }
+
+ /**
+ * This method writes <code>len</code> bytes to the file from the specified
+ * array starting at index <code>offset</code> into the array.
+ *
+ * @param buffer The array of bytes to write to the file
+ * @param offset The index into the array to start writing file
+ * @param len The number of bytes to write
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write (byte[] buffer, int offset, int len) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.write (buffer, offset, len);
+ }
+
+ /**
+ * This method writes a Java <code>boolean</code> to the underlying output
+ * stream. For a value of <code>true</code>, 1 is written to the stream.
+ * For a value of <code>false</code>, 0 is written.
+ *
+ * @param val The <code>boolean</code> value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public final void writeBoolean (boolean val) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.writeBoolean(val);
+ }
+
+ /**
+ * This method writes a Java <code>byte</code> value to the underlying
+ * output stream.
+ *
+ * @param val The <code>byte</code> to write to the stream, passed
+ * as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs
+ */
+ public final void writeByte (int val) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.writeByte(val);
+ }
+
+ /**
+ * This method writes a Java <code>short</code> to the stream, high byte
+ * first. This method requires two bytes to encode the value.
+ *
+ * @param val The <code>short</code> value to write to the stream,
+ * passed as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs
+ */
+ public final void writeShort (int val) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.writeShort(val);
+ }
+
+ /**
+ * This method writes a single <code>char</code> value to the stream,
+ * high byte first.
+ *
+ * @param val The <code>char</code> value to write, passed as
+ * an <code>int</code>.
+ *
+ * @exception IOException If an error occurs
+ */
+ public final void writeChar (int val) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.writeChar(val);
+ }
+
+ /**
+ * This method writes a Java <code>int</code> to the stream, high bytes
+ * first. This method requires four bytes to encode the value.
+ *
+ * @param val The <code>int</code> value to write to the stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ public final void writeInt (int val) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.writeInt(val);
+ }
+
+ /**
+ * This method writes a Java <code>long</code> to the stream, high bytes
+ * first. This method requires eight bytes to encode the value.
+ *
+ * @param val The <code>long</code> value to write to the stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ public final void writeLong (long val) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.writeLong(val);
+ }
+
+ /**
+ * This method writes a Java <code>float</code> value to the stream. This
+ * value is written by first calling the method
+ * <code>Float.floatToIntBits</code>
+ * to retrieve an <code>int</code> representing the floating point number,
+ * then writing this <code>int</code> value to the stream exactly the same
+ * as the <code>writeInt()</code> method does.
+ *
+ * @param val The floating point number to write to the stream.
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see #writeInt(int)
+ */
+ public final void writeFloat (float val) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.writeFloat(val);
+ }
+
+ /**
+ * This method writes a Java <code>double</code> value to the stream. This
+ * value is written by first calling the method
+ * <code>Double.doubleToLongBits</code>
+ * to retrieve an <code>long</code> representing the floating point number,
+ * then writing this <code>long</code> value to the stream exactly the same
+ * as the <code>writeLong()</code> method does.
+ *
+ * @param val The double precision floating point number to write to the
+ * stream.
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see #writeLong(long)
+ */
+ public final void writeDouble (double val) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.writeDouble(val);
+ }
+
+ /**
+ * This method writes all the bytes in a <code>String</code> out to the
+ * stream. One byte is written for each character in the <code>String</code>.
+ * The high eight bits of each character are discarded.
+ *
+ * @param val The <code>String</code> to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public final void writeBytes (String val) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.writeBytes(val);
+ }
+
+ /**
+ * This method writes all the characters in a <code>String</code> to the
+ * stream. There will be two bytes for each character value. The high
+ * byte of the character will be written first.
+ *
+ * @param val The <code>String</code> to write to the stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ public final void writeChars (String val) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.writeChars(val);
+ }
+
+ /**
+ * This method writes a Java <code>String</code> to the stream in a modified
+ * UTF-8 format. First, two bytes are written to the stream indicating the
+ * number of bytes to follow. Note that this is the number of bytes in the
+ * encoded <code>String</code> not the <code>String</code> length. Next
+ * come the encoded characters. Each character in the <code>String</code>
+ * is encoded as either one, two or three bytes. For characters in the
+ * range of <code>&#92;u0001</code> to <code>&#92;u007F</code>,
+ * one byte is used. The character
+ * value goes into bits 0-7 and bit eight is 0. For characters in the range
+ * of <code>&#92;u0080</code> to <code>&#92;u007FF</code>, two
+ * bytes are used. Bits
+ * 6-10 of the character value are encoded bits 0-4 of the first byte, with
+ * the high bytes having a value of "110". Bits 0-5 of the character value
+ * are stored in bits 0-5 of the second byte, with the high bits set to
+ * "10". This type of encoding is also done for the null character
+ * <code>&#92;u0000</code>. This eliminates any C style NUL character values
+ * in the output. All remaining characters are stored as three bytes.
+ * Bits 12-15 of the character value are stored in bits 0-3 of the first
+ * byte. The high bits of the first bytes are set to "1110". Bits 6-11
+ * of the character value are stored in bits 0-5 of the second byte. The
+ * high bits of the second byte are set to "10". And bits 0-5 of the
+ * character value are stored in bits 0-5 of byte three, with the high bits
+ * of that byte set to "10".
+ *
+ * @param val The <code>String</code> to write to the output in UTF format
+ *
+ * @exception IOException If an error occurs
+ */
+ public final void writeUTF (String val) throws IOException
+ {
+ if (out == null)
+ throw new IOException("Bad file descriptor");
+
+ out.writeUTF(val);
+ }
+
+ /**
+ * This method creates a java.nio.channels.FileChannel.
+ * Nio does not allow one to create a file channel directly.
+ * A file channel must be created by first creating an instance of
+ * Input/Output/RandomAccessFile and invoking the getChannel() method on it.
+ */
+ public final synchronized FileChannel getChannel ()
+ {
+ return ch;
+ }
+}
diff --git a/libjava/classpath/java/io/Reader.java b/libjava/classpath/java/io/Reader.java
new file mode 100644
index 000000000..11a12f812
--- /dev/null
+++ b/libjava/classpath/java/io/Reader.java
@@ -0,0 +1,286 @@
+/* Reader.java -- base class of classes that read input as a stream of chars
+ Copyright (C) 1998, 1999, 2000, 2003, 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 java.io;
+
+import java.nio.CharBuffer;
+
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * This abstract class forms the base of the hierarchy of classes that read
+ * input as a stream of characters. It provides a common set of methods for
+ * reading characters from streams. Subclasses implement and extend these
+ * methods to read characters from a particular input source such as a file
+ * or network connection.
+ *
+ * @author Per Bothner (bothner@cygnus.com)
+ * @date April 21, 1998.
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public abstract class Reader implements Closeable, Readable
+{
+ /**
+ * This is the <code>Object</code> used for synchronizing critical code
+ * sections. Subclasses should use this variable instead of a
+ * synchronized method or an explicit synchronization on <code>this</code>
+ */
+ protected Object lock;
+
+ /**
+ * Unitializes a <code>Reader</code> that will use the object
+ * itself for synchronization of critical code sections.
+ */
+ protected Reader()
+ {
+ this.lock = this;
+ }
+
+ /**
+ * Initializes a <code>Reader</code> that will use the specified
+ * <code>Object</code> for synchronization of critical code sections.
+ *
+ * @param lock The <code>Object</code> to use for synchronization
+ */
+ protected Reader(Object lock)
+ {
+ this.lock = lock;
+ }
+
+ /**
+ * Read chars from a stream and stores them into a caller
+ * supplied buffer. It starts storing the data at index <code>offset</code>
+ * into the buffer and attempts to read <code>len</code> chars. This method
+ * can return before reading the number of chars requested. The actual
+ * number of chars read is returned as an int. A -1 is returned to indicate
+ * the end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ * <p>
+ * This method operates by calling the single char <code>read()</code> method
+ * in a loop until the desired number of chars are read. The read loop
+ * stops short if the end of the stream is encountered or if an IOException
+ * is encountered on any read operation except the first. If the first
+ * attempt to read a chars fails, the IOException is allowed to propagate
+ * upward. And subsequent IOException is caught and treated identically
+ * to an end of stream condition. Subclasses can (and should if possible)
+ * override this method to provide a more efficient implementation.
+ *
+ * @param buf The array into which the chars read should be stored
+ * @param offset The offset into the array to start storing chars
+ * @param count The requested number of chars to read
+ *
+ * @return The actual number of chars read, or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public abstract int read(char buf[], int offset, int count)
+ throws IOException;
+
+ /**
+ * Reads chars from a stream and stores them into a caller
+ * supplied buffer. This method attempts to completely fill the buffer,
+ * but can return before doing so. The actual number of chars read is
+ * returned as an int. A -1 is returned to indicate the end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ * <p>
+ * This method operates by calling an overloaded read method like so:
+ * <code>read(buf, 0, buf.length)</code>
+ *
+ * @param buf The buffer into which the chars read will be stored.
+ *
+ * @return The number of chars read or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read(char buf[]) throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ /**
+ * Reads an char from the input stream and returns it
+ * as an int in the range of 0-65535. This method also will return -1 if
+ * the end of the stream has been reached.
+ * <p>
+ * This method will block until the char can be read.
+ *
+ * @return The char read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read() throws IOException
+ {
+ char[] buf = new char[1];
+ int count = read(buf, 0, 1);
+ return count > 0 ? buf[0] : -1;
+ }
+
+ /** @since 1.5 */
+ public int read(CharBuffer buffer) throws IOException
+ {
+ // We want to call put(), so we don't manipulate the CharBuffer
+ // directly.
+ int rem = buffer.remaining();
+ char[] buf = new char[rem];
+ int result = read(buf, 0, rem);
+ if (result != -1)
+ buffer.put(buf, 0, result);
+ return result;
+ }
+
+ /**
+ * Closes the stream. Any futher attempts to read from the
+ * stream may generate an <code>IOException</code>.
+ *
+ * @exception IOException If an error occurs
+ */
+ public abstract void close() throws IOException;
+
+ /**
+ * Returns a boolean that indicates whether the mark/reset
+ * methods are supported in this class. Those methods can be used to
+ * remember a specific point in the stream and reset the stream to that
+ * point.
+ * <p>
+ * This method always returns <code>false</code> in this class, but
+ * subclasses can override this method to return <code>true</code> if they
+ * support mark/reset functionality.
+ *
+ * @return <code>true</code> if mark/reset functionality is supported,
+ * <code>false</code> otherwise
+ *
+ */
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+ /**
+ * Marks a position in the input to which the stream can be
+ * "reset" by calling the <code>reset()</code> method. The parameter
+ * <code>readlimit</code> is the number of chars that can be read from the
+ * stream after setting the mark before the mark becomes invalid. For
+ * example, if <code>mark()</code> is called with a read limit of 10, then
+ * when 11 chars of data are read from the stream before the
+ * <code>reset()</code> method is called, then the mark is invalid and the
+ * stream object instance is not required to remember the mark.
+ *
+ * @param readLimit The number of chars that can be read before the mark
+ * becomes invalid
+ *
+ * @exception IOException If an error occurs such as mark not being
+ * supported for this class
+ */
+ public void mark(int readLimit) throws IOException
+ {
+ throw new IOException("mark not supported");
+ }
+
+ /**
+ * Resets a stream to the point where the <code>mark()</code>
+ * method was called. Any chars that were read after the mark point was
+ * set will be re-read during subsequent reads.
+ * <p>
+ * This method always throws an IOException in this class, but subclasses
+ * can override this method if they provide mark/reset functionality.
+ *
+ * @exception IOException Always thrown for this class
+ */
+ public void reset() throws IOException
+ {
+ throw new IOException("reset not supported");
+ }
+
+ /**
+ * Determines whether or not this stream is ready to be
+ * read. If it returns <code>false</code> the stream may block if a
+ * read is attempted, but it is not guaranteed to do so.
+ * <p>
+ * This method always returns <code>false</code> in this class
+ *
+ * @return <code>true</code> if the stream is ready to be read,
+ * <code>false</code> otherwise.
+ *
+ * @exception IOException If an error occurs
+ */
+ public boolean ready() throws IOException
+ {
+ return false;
+ }
+
+ /**
+ * Skips the specified number of chars in the stream. It
+ * returns the actual number of chars skipped, which may be less than the
+ * requested amount.
+ * <p>
+ * This method reads and discards chars into a 256 char array until the
+ * specified number of chars were skipped or until either the end of stream
+ * is reached or a read attempt returns a short count. Subclasses can
+ * override this method to provide a more efficient implementation where
+ * one exists.
+ *
+ * @param count The requested number of chars to skip
+ *
+ * @return The actual number of chars skipped.
+ *
+ * @exception IOException If an error occurs
+ */
+ public long skip(long count) throws IOException
+ {
+ if (count <= 0)
+ return 0;
+ int bsize = count > 1024 ? 1024 : (int) count;
+ char[] buffer = new char[bsize];
+ long todo = count;
+ synchronized (lock)
+ {
+ while (todo > 0)
+ {
+ int skipped = read(buffer, 0, bsize > todo ? (int) todo : bsize);
+ if (skipped <= 0)
+ break;
+ todo -= skipped;
+ }
+ }
+ return count - todo;
+ }
+}
diff --git a/libjava/classpath/java/io/SequenceInputStream.java b/libjava/classpath/java/io/SequenceInputStream.java
new file mode 100644
index 000000000..92f032ccf
--- /dev/null
+++ b/libjava/classpath/java/io/SequenceInputStream.java
@@ -0,0 +1,223 @@
+/* SequenceInputStream.java -- Reads multiple input streams in sequence
+ Copyright (C) 1998, 1999, 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 java.io;
+
+import java.util.Enumeration;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * This class merges a sequence of multiple <code>InputStream</code>'s in
+ * order to form a single logical stream that can be read by applications
+ * that expect only one stream.
+ * <p>
+ * The streams passed to the constructor method are read in order until
+ * they return -1 to indicate they are at end of stream. When a stream
+ * reports end of stream, it is closed, then the next stream is read.
+ * When the last stream is closed, the next attempt to read from this
+ * stream will return a -1 to indicate it is at end of stream.
+ * <p>
+ * If this stream is closed prior to all subordinate streams being read
+ * to completion, all subordinate streams are closed.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public class SequenceInputStream extends InputStream
+{
+ /** The handle for the current input stream. */
+ private InputStream in;
+
+ /** Secondary input stream; not used if constructed w/ enumeration. */
+ private InputStream in2;
+
+ /**
+ * The enumeration handle; not used if constructed w/ 2 explicit
+ * input streams.
+ */
+ private Enumeration<? extends InputStream> e;
+
+ /**
+ * This method creates a new <code>SequenceInputStream</code> that obtains
+ * its list of subordinate <code>InputStream</code>s from the specified
+ * <code>Enumeration</code>
+ *
+ * @param e An <code>Enumeration</code> that will return a list of
+ * <code>InputStream</code>s to read in sequence
+ */
+ public SequenceInputStream(Enumeration<? extends InputStream> e)
+ {
+ this.e = e;
+ in = e.nextElement();
+ in2 = null;
+ }
+
+ /**
+ * This method creates a new <code>SequenceInputStream</code> that will read
+ * the two specified subordinate <code>InputStream</code>s in sequence.
+ *
+ * @param s1 The first <code>InputStream</code> to read
+ * @param s2 The second <code>InputStream</code> to read
+ */
+ public SequenceInputStream(InputStream s1, InputStream s2)
+ {
+ in = s1;
+ in2 = s2;
+ }
+
+ /**
+ * This method returns the number of bytes than can be read from the
+ * currently being read subordinate stream before that stream could
+ * block. Note that it is possible more bytes than this can actually
+ * be read without the stream blocking. If a 0 is returned, then the
+ * stream could block on the very next read.
+ *
+ * @return The number of bytes that can be read before blocking could occur
+ *
+ * @exception IOException If an error occurs
+ */
+ public int available() throws IOException
+ {
+ if (in == null)
+ return 0;
+
+ return in.available();
+ }
+
+ /**
+ * Closes this stream. This will cause any remaining unclosed subordinate
+ * <code>InputStream</code>'s to be closed as well. Subsequent attempts to
+ * read from this stream may cause an exception.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ while (in != null)
+ {
+ in.close();
+ in = getNextStream ();
+ }
+ }
+
+ /**
+ * This method reads an unsigned byte from the input stream and returns it
+ * as an int in the range of 0-255. This method also will return -1 if
+ * the end of the stream has been reached. This will only happen when
+ * all of the subordinate streams have been read.
+ * <p>
+ * This method will block until the byte can be read.
+ *
+ * @return The byte read, or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read() throws IOException
+ {
+ int ch = -1;
+
+ while (in != null && (ch = in.read()) < 0)
+ {
+ in.close();
+ in = getNextStream();
+ }
+
+ return ch;
+ }
+
+ /**
+ * This method reads bytes from a stream and stores them into a caller
+ * supplied buffer. It starts storing the data at index <code>offset</code>
+ * into the buffer and attempts to read <code>len</code> bytes. This method
+ * can return before reading the number of bytes requested. The actual number
+ * of bytes read is returned as an int. A -1 is returend to indicate the
+ * end of the stream. This will only happen when all of the subordinate
+ * streams have been read.
+ * <p>
+ * This method will block until at least one byte can be read.
+ *
+ * @param b The array into which bytes read should be stored
+ * @param off The offset into the array 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
+ *
+ * @exception IOException If an error occurs
+ */
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ int ch = -1;
+
+ // The validity of the parameters will be checked by in.read so
+ // don't bother doing it here.
+ while (in != null && (ch = in.read(b, off, len)) < 0)
+ {
+ in.close();
+ in = getNextStream();
+ }
+
+ return ch;
+ }
+
+ /**
+ * This private method is used to get the next <code>InputStream</code> to
+ * read from. Returns null when no more streams are available.
+ */
+ private InputStream getNextStream()
+ {
+ InputStream nextIn = null;
+
+ if (e != null)
+ {
+ if (e.hasMoreElements())
+ nextIn = e.nextElement();
+ }
+ else if (in2 != null)
+ {
+ nextIn = in2;
+ in2 = null;
+ }
+
+ return nextIn;
+ }
+}
diff --git a/libjava/classpath/java/io/Serializable.java b/libjava/classpath/java/io/Serializable.java
new file mode 100644
index 000000000..869fa6de8
--- /dev/null
+++ b/libjava/classpath/java/io/Serializable.java
@@ -0,0 +1,54 @@
+/* Serializable.java -- Interface to indicate a class may be serialized
+ Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * Status: Believed complete
+ */
+
+/**
+ * This interface has no methods. It simply serves to indicate that
+ * the implementing class may be serialized.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public interface Serializable
+{
+} // interface Serializable
diff --git a/libjava/classpath/java/io/SerializablePermission.java b/libjava/classpath/java/io/SerializablePermission.java
new file mode 100644
index 000000000..88846cc35
--- /dev/null
+++ b/libjava/classpath/java/io/SerializablePermission.java
@@ -0,0 +1,112 @@
+/* SerializablePermission.java -- Basic permissions related to serialization.
+ Copyright (C) 1998, 2000, 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 java.io;
+
+import java.security.BasicPermission;
+
+/**
+ * This class models permissions related to serialization. As a subclass
+ * of <code>BasicPermission</code>, this class has permissions that have
+ * a name only. There is no associated action list.
+ * <p>
+ * There are currently two allowable permission names for this class:
+ * <ul>
+ * <li><code>enableSubclassImplementation</code> - Allows a subclass to
+ * override the default serialization behavior of objects.</li>
+ * <li><code>enableSubstitution</code> - Allows substitution of one object
+ * for another during serialization or deserialization.</li>
+ * </ul>
+ *
+ * @see java.security.BasicPermission
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public final class SerializablePermission extends BasicPermission
+{
+ static final long serialVersionUID = 8537212141160296410L;
+
+ /*
+ * Class Variables
+ */
+
+ private static final String[] legal_names = { "enableSubclassImplementation",
+ "enableSubstitution" };
+ /*
+ * Constructors
+ */
+
+ /**
+ * This method initializes a new instance of
+ * <code>SerializablePermission</code>
+ * that has the specified name.
+ *
+ * @param name The name of the permission.
+ *
+ * @exception IllegalArgumentException If the name is not valid for
+ * this class.
+ */
+ public SerializablePermission(String name)
+ {
+ this(name, null);
+ }
+
+ /**
+ * This method initializes a new instance of
+ * <code>SerializablePermission</code>
+ * that has the specified name and action list. Note that the action list
+ * is unused in this class.
+ *
+ * @param name The name of the permission.
+ * @param actions The action list (unused).
+ *
+ * @exception IllegalArgumentException If the name is not valid for
+ * this class.
+ */
+ public SerializablePermission(String name, String actions)
+ {
+ super(name, actions);
+
+ for (int i = 0; i < legal_names.length; i++)
+ if (legal_names[i].equals(name))
+ return;
+
+ throw new IllegalArgumentException("Bad permission name: " + name);
+ }
+
+} // class SerializablePermission
diff --git a/libjava/classpath/java/io/StreamCorruptedException.java b/libjava/classpath/java/io/StreamCorruptedException.java
new file mode 100644
index 000000000..d24d12150
--- /dev/null
+++ b/libjava/classpath/java/io/StreamCorruptedException.java
@@ -0,0 +1,73 @@
+/* StreamCorruptedException.java -- Error in stream during serialization
+ Copyright (C) 1998, 2000, 2001, 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 java.io;
+
+/**
+ * This exception is thrown when there is an error in the data that is
+ * read from a stream during de-serialization.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class StreamCorruptedException extends ObjectStreamException
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = 8983558202217591746L;
+
+ /**
+ * Create an exception without a descriptive error message.
+ */
+ public StreamCorruptedException()
+ {
+ }
+
+ /**
+ * Create an exception with a descriptive error message.
+ *
+ * @param message the descriptive error message
+ */
+ public StreamCorruptedException(String message)
+ {
+ super(message);
+ }
+} // class StreamCorruptedException
diff --git a/libjava/classpath/java/io/StreamTokenizer.java b/libjava/classpath/java/io/StreamTokenizer.java
new file mode 100644
index 000000000..0245fbf51
--- /dev/null
+++ b/libjava/classpath/java/io/StreamTokenizer.java
@@ -0,0 +1,718 @@
+/* StreamTokenizer.java -- parses streams of characters into tokens
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 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 java.io;
+
+import gnu.java.lang.CPStringBuilder;
+
+/**
+ * This class parses streams of characters into tokens. There are a
+ * million-zillion flags that can be set to control the parsing, as
+ * described under the various method headings.
+ *
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @date October 25, 1998.
+ */
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+public class StreamTokenizer
+{
+ /** A constant indicating that the end of the stream has been read. */
+ public static final int TT_EOF = -1;
+
+ /** A constant indicating that the end of the line has been read. */
+ public static final int TT_EOL = '\n';
+
+ /** A constant indicating that a number token has been read. */
+ public static final int TT_NUMBER = -2;
+
+ /** A constant indicating that a word token has been read. */
+ public static final int TT_WORD = -3;
+
+ /** A constant indicating that no tokens have been read yet. */
+ private static final int TT_NONE = -4;
+
+ /**
+ * Contains the type of the token read resulting from a call to nextToken
+ * The rules are as follows:
+ * <ul>
+ * <li>For a token consisting of a single ordinary character, this is the
+ * value of that character.</li>
+ * <li>For a quoted string, this is the value of the quote character</li>
+ * <li>For a word, this is TT_WORD</li>
+ * <li>For a number, this is TT_NUMBER</li>
+ * <li>For the end of the line, this is TT_EOL</li>
+ * <li>For the end of the stream, this is TT_EOF</li>
+ * </ul>
+ */
+ public int ttype = TT_NONE;
+
+ /** The String associated with word and string tokens. */
+ public String sval;
+
+ /** The numeric value associated with number tokens. */
+ public double nval;
+
+ /* Indicates whether end-of-line is recognized as a token. */
+ private boolean eolSignificant = false;
+
+ /* Indicates whether word tokens are automatically made lower case. */
+ private boolean lowerCase = false;
+
+ /* Indicates whether C++ style comments are recognized and skipped. */
+ private boolean slashSlash = false;
+
+ /* Indicates whether C style comments are recognized and skipped. */
+ private boolean slashStar = false;
+
+ /* Attribute tables of each byte from 0x00 to 0xFF. */
+ private boolean[] whitespace = new boolean[256];
+ private boolean[] alphabetic = new boolean[256];
+ private boolean[] numeric = new boolean[256];
+ private boolean[] quote = new boolean[256];
+ private boolean[] comment = new boolean[256];
+
+ /* The Reader associated with this class. */
+ private PushbackReader in;
+
+ /* Indicates if a token has been pushed back. */
+ private boolean pushedBack = false;
+
+ /* Contains the current line number of the reader. */
+ private int lineNumber = 1;
+
+ /**
+ * This method reads bytes from an <code>InputStream</code> and tokenizes
+ * them. For details on how this method operates by default, see
+ * <code>StreamTokenizer(Reader)</code>.
+ *
+ * @param is The <code>InputStream</code> to read from
+ *
+ * @deprecated Since JDK 1.1.
+ */
+ public StreamTokenizer(InputStream is)
+ {
+ this(new InputStreamReader(is));
+ }
+
+ /**
+ * This method initializes a new <code>StreamTokenizer</code> to read
+ * characters from a <code>Reader</code> and parse them. The char values
+ * have their hight bits masked so that the value is treated a character
+ * in the range of 0x0000 to 0x00FF.
+ * <p>
+ * This constructor sets up the parsing table to parse the stream in the
+ * following manner:
+ * <ul>
+ * <li>The values 'A' through 'Z', 'a' through 'z' and 0xA0 through 0xFF
+ * are initialized as alphabetic</li>
+ * <li>The values 0x00 through 0x20 are initialized as whitespace</li>
+ * <li>The values '\'' and '"' are initialized as quote characters</li>
+ * <li>'/' is a comment character</li>
+ * <li>Numbers will be parsed</li>
+ * <li>EOL is not treated as significant</li>
+ * <li>C and C++ (//) comments are not recognized</li>
+ * </ul>
+ *
+ * @param r The <code>Reader</code> to read chars from
+ */
+ public StreamTokenizer(Reader r)
+ {
+ in = new PushbackReader(r);
+
+ whitespaceChars(0x00, 0x20);
+ wordChars('A', 'Z');
+ wordChars('a', 'z');
+ wordChars(0xA0, 0xFF);
+ commentChar('/');
+ quoteChar('\'');
+ quoteChar('"');
+ parseNumbers();
+ }
+
+ /**
+ * This method sets the comment attribute on the specified
+ * character. Other attributes for the character are cleared.
+ *
+ * @param ch The character to set the comment attribute for, passed as an int
+ */
+ public void commentChar(int ch)
+ {
+ if (ch >= 0 && ch <= 255)
+ {
+ comment[ch] = true;
+ whitespace[ch] = false;
+ alphabetic[ch] = false;
+ numeric[ch] = false;
+ quote[ch] = false;
+ }
+ }
+
+ /**
+ * This method sets a flag that indicates whether or not the end of line
+ * sequence terminates and is a token. The defaults to <code>false</code>
+ *
+ * @param flag <code>true</code> if EOF is significant, <code>false</code>
+ * otherwise
+ */
+ public void eolIsSignificant(boolean flag)
+ {
+ eolSignificant = flag;
+ }
+
+ /**
+ * This method returns the current line number. Note that if the
+ * <code>pushBack()</code> method is called, it has no effect on the
+ * line number returned by this method.
+ *
+ * @return The current line number
+ */
+ public int lineno()
+ {
+ return lineNumber;
+ }
+
+ /**
+ * This method sets a flag that indicates whether or not alphabetic
+ * tokens that are returned should be converted to lower case.
+ *
+ * @param flag <code>true</code> to convert to lower case,
+ * <code>false</code> otherwise
+ */
+ public void lowerCaseMode(boolean flag)
+ {
+ lowerCase = flag;
+ }
+
+ private boolean isWhitespace(int ch)
+ {
+ return (ch >= 0 && ch <= 255 && whitespace[ch]);
+ }
+
+ private boolean isAlphabetic(int ch)
+ {
+ return ((ch > 255) || (ch >= 0 && alphabetic[ch]));
+ }
+
+ private boolean isNumeric(int ch)
+ {
+ return (ch >= 0 && ch <= 255 && numeric[ch]);
+ }
+
+ private boolean isQuote(int ch)
+ {
+ return (ch >= 0 && ch <= 255 && quote[ch]);
+ }
+
+ private boolean isComment(int ch)
+ {
+ return (ch >= 0 && ch <= 255 && comment[ch]);
+ }
+
+ /**
+ * This method reads the next token from the stream. It sets the
+ * <code>ttype</code> variable to the appropriate token type and
+ * returns it. It also can set <code>sval</code> or <code>nval</code>
+ * as described below. The parsing strategy is as follows:
+ * <ul>
+ * <li>Skip any whitespace characters.</li>
+ * <li>If a numeric character is encountered, attempt to parse a numeric
+ * value. Leading '-' characters indicate a numeric only if followed by
+ * another non-'-' numeric. The value of the numeric token is terminated
+ * by either the first non-numeric encountered, or the second occurrence of
+ * '-' or '.'. The token type returned is TT_NUMBER and <code>nval</code>
+ * is set to the value parsed.</li>
+ * <li>If an alphabetic character is parsed, all subsequent characters
+ * are read until the first non-alphabetic or non-numeric character is
+ * encountered. The token type returned is TT_WORD and the value parsed
+ * is stored in <code>sval</code>. If lower case mode is set, the token
+ * stored in <code>sval</code> is converted to lower case. The end of line
+ * sequence terminates a word only if EOL signficance has been turned on.
+ * The start of a comment also terminates a word. Any character with a
+ * non-alphabetic and non-numeric attribute (such as white space, a quote,
+ * or a commet) are treated as non-alphabetic and terminate the word.</li>
+ * <li>If a comment character is parsed, then all remaining characters on
+ * the current line are skipped and another token is parsed. Any EOL or
+ * EOF's encountered are not discarded, but rather terminate the comment.</li>
+ * <li>If a quote character is parsed, then all characters up to the
+ * second occurrence of the same quote character are parsed into a
+ * <code>String</code>. This <code>String</code> is stored as
+ * <code>sval</code>, but is not converted to lower case, even if lower case
+ * mode is enabled. The token type returned is the value of the quote
+ * character encountered. Any escape sequences
+ * (\b (backspace), \t (HTAB), \n (linefeed), \f (form feed), \r
+ * (carriage return), \" (double quote), \' (single quote), \\
+ * (backslash), \XXX (octal esacpe)) are converted to the appropriate
+ * char values. Invalid esacape sequences are left in untranslated.
+ * Unicode characters like ('\ u0000') are not recognized. </li>
+ * <li>If the C++ comment sequence "//" is encountered, and the parser
+ * is configured to handle that sequence, then the remainder of the line
+ * is skipped and another token is read exactly as if a character with
+ * the comment attribute was encountered.</li>
+ * <li>If the C comment sequence "/*" is encountered, and the parser
+ * is configured to handle that sequence, then all characters up to and
+ * including the comment terminator sequence are discarded and another
+ * token is parsed.</li>
+ * <li>If all cases above are not met, then the character is an ordinary
+ * character that is parsed as a token by itself. The char encountered
+ * is returned as the token type.</li>
+ * </ul>
+ *
+ * @return The token type
+ * @exception IOException If an I/O error occurs
+ */
+ public int nextToken() throws IOException
+ {
+ if (pushedBack)
+ {
+ pushedBack = false;
+ if (ttype != TT_NONE)
+ return ttype;
+ }
+
+ sval = null;
+ int ch;
+
+ // Skip whitespace. Deal with EOL along the way.
+ while (isWhitespace(ch = in.read()))
+ if (ch == '\n' || ch == '\r')
+ {
+ lineNumber++;
+
+ // Throw away \n if in combination with \r.
+ if (ch == '\r' && (ch = in.read()) != '\n')
+ {
+ if (ch != TT_EOF)
+ in.unread(ch);
+ }
+ if (eolSignificant)
+ return (ttype = TT_EOL);
+ }
+
+ if (ch == '/')
+ if ((ch = in.read()) == '/' && slashSlash)
+ {
+ while ((ch = in.read()) != '\n' && ch != '\r' && ch != TT_EOF)
+ ;
+
+ if (ch != TT_EOF)
+ in.unread(ch);
+ return nextToken(); // Recursive, but not too deep in normal cases
+ }
+ else if (ch == '*' && slashStar)
+ {
+ while (true)
+ {
+ ch = in.read();
+ if (ch == '*')
+ {
+ if ((ch = in.read()) == '/')
+ break;
+ else if (ch != TT_EOF)
+ in.unread(ch);
+ }
+ else if (ch == '\n' || ch == '\r')
+ {
+ lineNumber++;
+ if (ch == '\r' && (ch = in.read()) != '\n')
+ {
+ if (ch != TT_EOF)
+ in.unread(ch);
+ }
+ }
+ else if (ch == TT_EOF)
+ {
+ break;
+ }
+ }
+ return nextToken(); // Recursive, but not too deep in normal cases
+ }
+ else
+ {
+ if (ch != TT_EOF)
+ in.unread(ch);
+ ch = '/';
+ }
+
+ if (ch == TT_EOF)
+ ttype = TT_EOF;
+ else if (isNumeric(ch))
+ {
+ boolean isNegative = false;
+ if (ch == '-')
+ {
+ // Read ahead to see if this is an ordinary '-' rather than numeric.
+ ch = in.read();
+ if (isNumeric(ch) && ch != '-')
+ {
+ isNegative = true;
+ }
+ else
+ {
+ if (ch != TT_EOF)
+ in.unread(ch);
+ return (ttype = '-');
+ }
+ }
+
+ CPStringBuilder tokbuf = new CPStringBuilder();
+ tokbuf.append((char) ch);
+
+ int decCount = 0;
+ while (isNumeric(ch = in.read()) && ch != '-')
+ if (ch == '.' && decCount++ > 0)
+ break;
+ else
+ tokbuf.append((char) ch);
+
+ if (ch != TT_EOF)
+ in.unread(ch);
+ ttype = TT_NUMBER;
+ try
+ {
+ nval = Double.valueOf(tokbuf.toString()).doubleValue();
+ }
+ catch (NumberFormatException _)
+ {
+ nval = 0.0;
+ }
+ if (isNegative)
+ nval = -nval;
+ }
+ else if (isAlphabetic(ch))
+ {
+ CPStringBuilder tokbuf = new CPStringBuilder();
+ tokbuf.append((char) ch);
+ while (isAlphabetic(ch = in.read()) || isNumeric(ch))
+ tokbuf.append((char) ch);
+ if (ch != TT_EOF)
+ in.unread(ch);
+ ttype = TT_WORD;
+ sval = tokbuf.toString();
+ if (lowerCase)
+ sval = sval.toLowerCase();
+ }
+ else if (isComment(ch))
+ {
+ while ((ch = in.read()) != '\n' && ch != '\r' && ch != TT_EOF)
+ ;
+
+ if (ch != TT_EOF)
+ in.unread(ch);
+ return nextToken(); // Recursive, but not too deep in normal cases.
+ }
+ else if (isQuote(ch))
+ {
+ ttype = ch;
+ CPStringBuilder tokbuf = new CPStringBuilder();
+ while ((ch = in.read()) != ttype && ch != '\n' && ch != '\r' &&
+ ch != TT_EOF)
+ {
+ if (ch == '\\')
+ switch (ch = in.read())
+ {
+ case 'a': ch = 0x7;
+ break;
+ case 'b': ch = '\b';
+ break;
+ case 'f': ch = 0xC;
+ break;
+ case 'n': ch = '\n';
+ break;
+ case 'r': ch = '\r';
+ break;
+ case 't': ch = '\t';
+ break;
+ case 'v': ch = 0xB;
+ break;
+ case '\n': ch = '\n';
+ break;
+ case '\r': ch = '\r';
+ break;
+ case '\"':
+ case '\'':
+ case '\\':
+ break;
+ default:
+ int ch1, nextch;
+ if ((nextch = ch1 = ch) >= '0' && ch <= '7')
+ {
+ ch -= '0';
+ if ((nextch = in.read()) >= '0' && nextch <= '7')
+ {
+ ch = ch * 8 + nextch - '0';
+ if ((nextch = in.read()) >= '0' && nextch <= '7' &&
+ ch1 >= '0' && ch1 <= '3')
+ {
+ ch = ch * 8 + nextch - '0';
+ nextch = in.read();
+ }
+ }
+ }
+
+ if (nextch != TT_EOF)
+ in.unread(nextch);
+ }
+
+ tokbuf.append((char) ch);
+ }
+
+ // Throw away matching quote char.
+ if (ch != ttype && ch != TT_EOF)
+ in.unread(ch);
+
+ sval = tokbuf.toString();
+ }
+ else
+ {
+ ttype = ch;
+ }
+
+ return ttype;
+ }
+
+ private void resetChar(int ch)
+ {
+ whitespace[ch] = alphabetic[ch] = numeric[ch] = quote[ch] = comment[ch] =
+ false;
+ }
+
+ /**
+ * This method makes the specified character an ordinary character. This
+ * means that none of the attributes (whitespace, alphabetic, numeric,
+ * quote, or comment) will be set on this character. This character will
+ * parse as its own token.
+ *
+ * @param ch The character to make ordinary, passed as an int
+ */
+ public void ordinaryChar(int ch)
+ {
+ if (ch >= 0 && ch <= 255)
+ resetChar(ch);
+ }
+
+ /**
+ * This method makes all the characters in the specified range, range
+ * terminators included, ordinary. This means the none of the attributes
+ * (whitespace, alphabetic, numeric, quote, or comment) will be set on
+ * any of the characters in the range. This makes each character in this
+ * range parse as its own token.
+ *
+ * @param low The low end of the range of values to set the whitespace
+ * attribute for
+ * @param hi The high end of the range of values to set the whitespace
+ * attribute for
+ */
+ public void ordinaryChars(int low, int hi)
+ {
+ if (low < 0)
+ low = 0;
+ if (hi > 255)
+ hi = 255;
+ for (int i = low; i <= hi; i++)
+ resetChar(i);
+ }
+
+ /**
+ * This method sets the numeric attribute on the characters '0' - '9' and
+ * the characters '.' and '-'.
+ * When this method is used, the result of giving other attributes
+ * (whitespace, quote, or comment) to the numeric characters may
+ * vary depending on the implementation. For example, if
+ * parseNumbers() and then whitespaceChars('1', '1') are called,
+ * this implementation reads "121" as 2, while some other implementation
+ * will read it as 21.
+ */
+ public void parseNumbers()
+ {
+ for (int i = 0; i <= 9; i++)
+ numeric['0' + i] = true;
+
+ numeric['.'] = true;
+ numeric['-'] = true;
+ }
+
+ /**
+ * Puts the current token back into the StreamTokenizer so
+ * <code>nextToken</code> will return the same value on the next call.
+ * May cause the lineno method to return an incorrect value
+ * if lineno is called before the next call to nextToken.
+ */
+ public void pushBack()
+ {
+ pushedBack = true;
+ }
+
+ /**
+ * This method sets the quote attribute on the specified character.
+ * Other attributes for the character are cleared.
+ *
+ * @param ch The character to set the quote attribute for, passed as an int.
+ */
+ public void quoteChar(int ch)
+ {
+ if (ch >= 0 && ch <= 255)
+ {
+ quote[ch] = true;
+ comment[ch] = false;
+ whitespace[ch] = false;
+ alphabetic[ch] = false;
+ numeric[ch] = false;
+ }
+ }
+
+ /**
+ * This method removes all attributes (whitespace, alphabetic, numeric,
+ * quote, and comment) from all characters. It is equivalent to calling
+ * <code>ordinaryChars(0x00, 0xFF)</code>.
+ *
+ * @see #ordinaryChars(int, int)
+ */
+ public void resetSyntax()
+ {
+ ordinaryChars(0x00, 0xFF);
+ }
+
+ /**
+ * This method sets a flag that indicates whether or not "C++" language style
+ * comments ("//" comments through EOL ) are handled by the parser.
+ * If this is <code>true</code> commented out sequences are skipped and
+ * ignored by the parser. This defaults to <code>false</code>.
+ *
+ * @param flag <code>true</code> to recognized and handle "C++" style
+ * comments, <code>false</code> otherwise
+ */
+ public void slashSlashComments(boolean flag)
+ {
+ slashSlash = flag;
+ }
+
+ /**
+ * This method sets a flag that indicates whether or not "C" language style
+ * comments (with nesting not allowed) are handled by the parser.
+ * If this is <code>true</code> commented out sequences are skipped and
+ * ignored by the parser. This defaults to <code>false</code>.
+ *
+ * @param flag <code>true</code> to recognized and handle "C" style comments,
+ * <code>false</code> otherwise
+ */
+ public void slashStarComments(boolean flag)
+ {
+ slashStar = flag;
+ }
+
+ /**
+ * This method returns the current token value as a <code>String</code> in
+ * the form "Token[x], line n", where 'n' is the current line numbers and
+ * 'x' is determined as follows.
+ * <p>
+ * <ul>
+ * <li>If no token has been read, then 'x' is "NOTHING" and 'n' is 0</li>
+ * <li>If <code>ttype</code> is TT_EOF, then 'x' is "EOF"</li>
+ * <li>If <code>ttype</code> is TT_EOL, then 'x' is "EOL"</li>
+ * <li>If <code>ttype</code> is TT_WORD, then 'x' is <code>sval</code></li>
+ * <li>If <code>ttype</code> is TT_NUMBER, then 'x' is "n=strnval" where
+ * 'strnval' is <code>String.valueOf(nval)</code>.</li>
+ * <li>If <code>ttype</code> is a quote character, then 'x' is
+ * <code>sval</code></li>
+ * <li>For all other cases, 'x' is <code>ttype</code></li>
+ * </ul>
+ */
+ public String toString()
+ {
+ String tempstr;
+ if (ttype == TT_EOF)
+ tempstr = "EOF";
+ else if (ttype == TT_EOL)
+ tempstr = "EOL";
+ else if (ttype == TT_WORD)
+ tempstr = sval;
+ else if (ttype == TT_NUMBER)
+ tempstr = "n=" + nval;
+ else if (ttype == TT_NONE)
+ tempstr = "NOTHING";
+ else // must be an ordinary char.
+ tempstr = "\'" + (char) ttype + "\'";
+
+ return "Token[" + tempstr + "], line " + lineno();
+ }
+
+ /**
+ * This method sets the whitespace attribute for all characters in the
+ * specified range, range terminators included.
+ *
+ * @param low The low end of the range of values to set the whitespace
+ * attribute for
+ * @param hi The high end of the range of values to set the whitespace
+ * attribute for
+ */
+ public void whitespaceChars(int low, int hi)
+ {
+ if (low < 0)
+ low = 0;
+ if (hi > 255)
+ hi = 255;
+ for (int i = low; i <= hi; i++)
+ {
+ resetChar(i);
+ whitespace[i] = true;
+ }
+ }
+
+ /**
+ * This method sets the alphabetic attribute for all characters in the
+ * specified range, range terminators included.
+ *
+ * @param low The low end of the range of values to set the alphabetic
+ * attribute for
+ * @param hi The high end of the range of values to set the alphabetic
+ * attribute for
+ */
+ public void wordChars(int low, int hi)
+ {
+ if (low < 0)
+ low = 0;
+ if (hi > 255)
+ hi = 255;
+ for (int i = low; i <= hi; i++)
+ alphabetic[i] = true;
+ }
+}
diff --git a/libjava/classpath/java/io/StringBufferInputStream.java b/libjava/classpath/java/io/StringBufferInputStream.java
new file mode 100644
index 000000000..28405d938
--- /dev/null
+++ b/libjava/classpath/java/io/StringBufferInputStream.java
@@ -0,0 +1,187 @@
+/* StringBufferInputStream.java -- Read an String as a stream
+ Copyright (C) 1998, 1999, 2001, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct. Deprecated in JDK 1.1.
+ */
+
+/**
+ * This class permits a <code>String</code> to be read as an input stream.
+ * The low eight bits of each character in the <code>String</code> are the
+ * bytes that are returned. The high eight bits of each character are
+ * discarded.
+ * <p>
+ * The mark/reset functionality in this class behaves differently than
+ * normal. The <code>mark()</code> method is always ignored and the
+ * <code>reset()</code> method always resets in stream to start reading from
+ * position 0 in the String. Note that since this method does not override
+ * <code>markSupported()</code> in <code>InputStream</code>, calling that
+ * method will return <code>false</code>.
+ * <p>
+ * Note that this class is deprecated because it does not properly handle
+ * 16-bit Java characters. It is provided for backwards compatibility only
+ * and should not be used for new development. The <code>StringReader</code>
+ * class should be used instead.
+ *
+ * @deprecated
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public class StringBufferInputStream extends InputStream
+{
+ /** The String which is the input to this stream. */
+ protected String buffer;
+
+ /** Position of the next byte in buffer to be read. */
+ protected int pos = 0;
+
+ /** The length of the String buffer. */
+ protected int count;
+
+ /**
+ * Create a new <code>StringBufferInputStream</code> that will read bytes
+ * from the passed in <code>String</code>. This stream will read from the
+ * beginning to the end of the <code>String</code>.
+ *
+ * @param s The <code>String</code> this stream will read from.
+ */
+ public StringBufferInputStream(String s)
+ {
+ buffer = s;
+ count = s.length();
+ }
+
+ /**
+ * This method returns the number of bytes available to be read from this
+ * stream. The value returned will be equal to <code>count - pos</code>.
+ *
+ * @return The number of bytes that can be read from this stream before
+ * blocking, which is all of them
+ */
+ public int available()
+ {
+ return count - pos;
+ }
+
+ /**
+ * This method reads one byte from the stream. The <code>pos</code> counter
+ * is advanced to the next byte to be read. The byte read is returned as
+ * an int in the range of 0-255. If the stream position is already at the
+ * end of the buffer, no byte is read and a -1 is returned in order to
+ * indicate the end of the stream.
+ *
+ * @return The byte read, or -1 if end of stream
+ */
+ public int read()
+ {
+ if (pos >= count)
+ return -1; // EOF
+
+ return ((int) buffer.charAt(pos++)) & 0xFF;
+ }
+
+/**
+ * This method reads bytes from the stream and stores them into a caller
+ * supplied buffer. It starts storing the data at index <code>offset</code>
+ * into the buffer and attempts to read <code>len</code> bytes. This method
+ * can return before reading the number of bytes requested if the end of the
+ * stream is encountered first. The actual number of bytes read is
+ * returned. If no bytes can be read because the stream is already at
+ * the end of stream position, a -1 is returned.
+ * <p>
+ * This method does not block.
+ *
+ * @param b The array into which the bytes read should be stored.
+ * @param off The offset into the array 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.
+ */
+ public int read(byte[] b, int off, int len)
+ {
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ if (pos >= count)
+ return -1; // EOF
+
+ int numRead = Math.min(len, count - pos);
+ if (numRead < 0)
+ return 0;
+
+ buffer.getBytes(pos, pos + numRead, b, off);
+ pos += numRead;
+ return numRead;
+ }
+
+ /**
+ * This method sets the read position in the stream to the beginning
+ * setting the <code>pos</code> variable equal to 0. Note that this differs
+ * from the common implementation of the <code>reset()</code> method.
+ */
+ public void reset()
+ {
+ pos = 0;
+ }
+
+ /**
+ * This method attempts to skip the requested number of bytes in the
+ * input stream. It does this by advancing the <code>pos</code> value by the
+ * specified number of bytes. It this would exceed the length of the
+ * buffer, then only enough bytes are skipped to position the stream at
+ * the end of the buffer. The actual number of bytes skipped is returned.
+ *
+ * @param n The requested number of bytes to skip
+ *
+ * @return The actual number of bytes skipped.
+ */
+ public long skip(long n)
+ {
+ if (n < 0)
+ return 0L;
+
+ long actualSkip = Math.min(n, count - pos);
+ pos += actualSkip;
+ return actualSkip;
+ }
+}
diff --git a/libjava/classpath/java/io/StringReader.java b/libjava/classpath/java/io/StringReader.java
new file mode 100644
index 000000000..c4021a8fb
--- /dev/null
+++ b/libjava/classpath/java/io/StringReader.java
@@ -0,0 +1,208 @@
+/* StringReader.java -- permits a String to be read as a character input stream
+ Copyright (C) 1998, 1999, 2000, 2003 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 java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
+ * "The Java Language Specification", ISBN 0-201-63451-1
+ * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct
+ */
+
+/**
+ * This class permits a <code>String</code> to be read as a character
+ * input stream.
+ * <p>
+ * The mark/reset functionality in this class behaves differently than
+ * normal. If no mark has been set, then calling the <code>reset()</code>
+ * method rewinds the read pointer to the beginning of the <code>String</code>.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ * @date October 19, 1998.
+ */
+public class StringReader extends Reader
+{
+ /* A String provided by the creator of the stream. */
+ private String buf;
+
+ /* Position of the next char in buf to be read. */
+ private int pos;
+
+ /* The currently marked position in the stream. */
+ private int markedPos;
+
+ /* The index in buf one greater than the last valid character. */
+ private int count;
+
+ /**
+ * Create a new <code>StringReader</code> that will read chars from the
+ * passed in <code>String</code>. This stream will read from the beginning
+ * to the end of the <code>String</code>.
+ *
+ * @param buffer The <code>String</code> this stream will read from.
+ */
+ public StringReader(String buffer)
+ {
+ super();
+ buf = buffer;
+
+ count = buffer.length();
+ markedPos = pos = 0;
+ }
+
+ public void close()
+ {
+ synchronized (lock)
+ {
+ buf = null;
+ }
+ }
+
+ public void mark(int readAheadLimit) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+
+ // readAheadLimit is ignored per Java Class Lib. book, p. 1692.
+ markedPos = pos;
+ }
+ }
+
+ public boolean markSupported()
+ {
+ return true;
+ }
+
+ public int read() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+
+ if (pos < count)
+ return ((int) buf.charAt(pos++)) & 0xFFFF;
+ return -1;
+ }
+ }
+
+ public int read(char[] b, int off, int len) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+
+ /* Don't need to check pos value, arraycopy will check it. */
+ if (off < 0 || len < 0 || off + len > b.length)
+ throw new ArrayIndexOutOfBoundsException();
+
+ if (pos >= count)
+ return -1;
+
+ int lastChar = Math.min(count, pos + len);
+ buf.getChars(pos, lastChar, b, off);
+ int numChars = lastChar - pos;
+ pos = lastChar;
+ return numChars;
+ }
+ }
+
+ /**
+ * This method determines if the stream is ready to be read. This class
+ * is always ready to read and so always returns <code>true</code>, unless
+ * close() has previously been called in which case an IOException is
+ * thrown.
+ *
+ * @return <code>true</code> to indicate that this object is ready to be read.
+ * @exception IOException If the stream is closed.
+ */
+ public boolean ready() throws IOException
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+
+ return true;
+ }
+
+ /**
+ * Sets the read position in the stream to the previously
+ * marked position or to 0 (i.e., the beginning of the stream) if the mark
+ * has not already been set.
+ */
+ public void reset() throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+
+ pos = markedPos;
+ }
+ }
+
+ /**
+ * This method attempts to skip the requested number of chars in the
+ * input stream. It does this by advancing the <code>pos</code> value by
+ * the specified number of chars. It this would exceed the length of the
+ * buffer, then only enough chars are skipped to position the stream at
+ * the end of the buffer. The actual number of chars skipped is returned.
+ *
+ * @param n The requested number of chars to skip
+ *
+ * @return The actual number of chars skipped.
+ */
+ public long skip(long n) throws IOException
+ {
+ synchronized (lock)
+ {
+ if (buf == null)
+ throw new IOException("Stream closed");
+
+ // Even though the var numChars is a long, in reality it can never
+ // be larger than an int since the result of subtracting 2 positive
+ // ints will always fit in an int. Since we have to return a long
+ // anyway, numChars might as well just be a long.
+ long numChars = Math.min((long) (count - pos), n < 0 ? 0L : n);
+ pos += numChars;
+ return numChars;
+ }
+ }
+}
diff --git a/libjava/classpath/java/io/StringWriter.java b/libjava/classpath/java/io/StringWriter.java
new file mode 100644
index 000000000..85500b5cb
--- /dev/null
+++ b/libjava/classpath/java/io/StringWriter.java
@@ -0,0 +1,212 @@
+/* StringWriter.java -- Writes bytes to a StringBuffer
+ Copyright (C) 1998, 1999, 2000, 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 java.io;
+
+// Wow is this a dumb class. CharArrayWriter can do all this and
+// more. I would redirect all calls to one in fact, but the javadocs say
+// use a StringBuffer so I will comply.
+
+/**
+ * This class writes chars to an internal <code>StringBuffer</code> that
+ * can then be used to retrieve a <code>String</code>.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ */
+public class StringWriter extends Writer
+{
+ /**
+ * This is the default size of the buffer if the user doesn't specify it.
+ * @specnote The JCL Volume 1 says that 16 is the default size.
+ */
+ private static final int DEFAULT_BUFFER_SIZE = 16;
+
+ /**
+ * This method closes the stream. The contents of the internal buffer
+ * can still be retrieved, but future writes are not guaranteed to work.
+ *
+ * @exception IOException If an error orrurs.
+ */
+ public void close () throws IOException
+ {
+ // JCL says this does nothing. This seems to violate the Writer
+ // contract, in that other methods should still throw an
+ // IOException after a close. Still, we just follow JCL.
+ }
+
+ /**
+ * This method flushes any buffered characters to the underlying output.
+ * It does nothing in this class.
+ */
+ public void flush ()
+ {
+ }
+
+ /**
+ * This method returns the <code>StringBuffer</code> object that this
+ * object is writing to. Note that this is the actual internal buffer, so
+ * any operations performed on it will affect this stream object.
+ *
+ * @return The <code>StringBuffer</code> object being written to
+ */
+ public StringBuffer getBuffer ()
+ {
+ return buffer;
+ }
+
+ /**
+ * This method initializes a new <code>StringWriter</code> to write to a
+ * <code>StringBuffer</code> initially sized to a default size of 16
+ * chars.
+ */
+ public StringWriter ()
+ {
+ this (DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * This method initializes a new <code>StringWriter</code> to write to a
+ * <code>StringBuffer</code> with the specified initial size.
+ *
+ * @param size The initial size to make the <code>StringBuffer</code>
+ */
+ public StringWriter (int size)
+ {
+ super ();
+ buffer = new StringBuffer (size);
+ lock = buffer;
+ }
+
+ /**
+ * This method returns the contents of the internal <code>StringBuffer</code>
+ * as a <code>String</code>.
+ *
+ * @return A <code>String</code> representing the chars written to
+ * this stream.
+ */
+ public String toString ()
+ {
+ return buffer.toString();
+ }
+
+ /**
+ * This method writes a single character to the output, storing it in
+ * the internal buffer.
+ *
+ * @param oneChar The <code>char</code> to write, passed as an int.
+ */
+ public void write (int oneChar)
+ {
+ buffer.append((char) (oneChar & 0xFFFF));
+ }
+
+ /**
+ * This method writes <code>len</code> chars from the specified
+ * array starting at index <code>offset</code> in that array to this
+ * stream by appending the chars to the end of the internal buffer.
+ *
+ * @param chars The array of chars to write
+ * @param offset The index into the array to start writing from
+ * @param len The number of chars to write
+ */
+ public void write (char[] chars, int offset, int len)
+ {
+ buffer.append(chars, offset, len);
+ }
+
+ /**
+ * This method writes the characters in the specified <code>String</code>
+ * to the stream by appending them to the end of the internal buffer.
+ *
+ * @param str The <code>String</code> to write to the stream.
+ */
+ public void write (String str)
+ {
+ buffer.append(str);
+ }
+
+ /**
+ * This method writes out <code>len</code> characters of the specified
+ * <code>String</code> to the stream starting at character position
+ * <code>offset</code> into the stream. This is done by appending the
+ * characters to the internal buffer.
+ *
+ * @param str The <code>String</code> to write characters from
+ * @param offset The character position to start writing from
+ * @param len The number of characters to write.
+ */
+ public void write (String str, int offset, int len)
+ {
+// char[] tmpbuf = new char[len];
+// str.getChars(offset, offset+len, tmpbuf, 0);
+// buf.append(tmpbuf, 0, tmpbuf.length);
+ // This implementation assumes that String.substring is more
+ // efficient than using String.getChars and copying the data
+ // twice. For libgcj, this is true. For Classpath, it is not.
+ // FIXME.
+ buffer.append(str.substring(offset, offset + len));
+ }
+
+ /** @since 1.5 */
+ public StringWriter append(char c)
+ {
+ write(c);
+ return this;
+ }
+
+ /** @since 1.5 */
+ public StringWriter append(CharSequence cs)
+ {
+ write(cs == null ? "null" : cs.toString());
+ return this;
+ }
+
+ /** @since 1.5 */
+ public StringWriter append(CharSequence cs, int start, int end)
+ {
+ write(cs == null ? "null" : cs.subSequence(start, end).toString());
+ return this;
+ }
+
+ /**
+ * This is the <code>StringBuffer</code> that we use to store bytes that
+ * are written.
+ */
+ private StringBuffer buffer;
+}
diff --git a/libjava/classpath/java/io/SyncFailedException.java b/libjava/classpath/java/io/SyncFailedException.java
new file mode 100644
index 000000000..c514c44f2
--- /dev/null
+++ b/libjava/classpath/java/io/SyncFailedException.java
@@ -0,0 +1,66 @@
+/* SyncFailedException.java -- a file sync failed
+ Copyright (C) 1998, 1999, 2001, 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 java.io;
+
+/**
+ * Thrown when a file synchronization fails.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ * @see FileDescriptor#sync()
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class SyncFailedException extends IOException
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = -2353342684412443330L;
+
+ /**
+ * Create an exception with a descriptive error message.
+ *
+ * @param message the descriptive error message
+ */
+ public SyncFailedException(String message)
+ {
+ super(message);
+ }
+} // class SyncFailedException
diff --git a/libjava/classpath/java/io/UTFDataFormatException.java b/libjava/classpath/java/io/UTFDataFormatException.java
new file mode 100644
index 000000000..6bb76aebd
--- /dev/null
+++ b/libjava/classpath/java/io/UTFDataFormatException.java
@@ -0,0 +1,74 @@
+/* UTFDataFormatException.java -- thrown on bad format in UTF data
+ Copyright (C) 1998, 1999, 2001, 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 java.io;
+
+/**
+ * When reading a UTF string from an input stream, this exception is thrown
+ * to indicate that the data read is invalid.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Tom Tromey (tromey@cygnus.com)
+ * @see DataInput
+ * @see DataInputStream#readUTF(DataInput)
+ * @status updated to 1.4
+ */
+public class UTFDataFormatException extends IOException
+{
+ /**
+ * Compatible with JDK 1.0+.
+ */
+ private static final long serialVersionUID = 420743449228280612L;
+
+ /**
+ * Create a new UTFDataFormatException without a descriptive error message.
+ */
+ public UTFDataFormatException()
+ {
+ }
+
+ /**
+ * Create a new UTFDataFormatException with a descriptive error message.
+ *
+ * @param message the descriptive error message
+ */
+ public UTFDataFormatException(String message)
+ {
+ super(message);
+ }
+} // class UTFDataFormatException
diff --git a/libjava/classpath/java/io/UnsupportedEncodingException.java b/libjava/classpath/java/io/UnsupportedEncodingException.java
new file mode 100644
index 000000000..597597563
--- /dev/null
+++ b/libjava/classpath/java/io/UnsupportedEncodingException.java
@@ -0,0 +1,73 @@
+/* UnsupportedEncodingException.java -- the requested encoding isn't supported
+ Copyright (C) 1998, 1999, 2001, 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 java.io;
+
+/**
+ * This exception is thrown when the requested character encoding is
+ * not supported.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Per Bothner (bothner@cygnus.com)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class UnsupportedEncodingException extends IOException
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = -4274276298326136670L;
+
+ /**
+ * Create an exception without a descriptive error message.
+ */
+ public UnsupportedEncodingException()
+ {
+ }
+
+ /**
+ * Create an exception with a descriptive error message.
+ *
+ * @param message the descriptive error message
+ */
+ public UnsupportedEncodingException(String message)
+ {
+ super(message);
+ }
+} // class UnsupportedEncodingException
diff --git a/libjava/classpath/java/io/WriteAbortedException.java b/libjava/classpath/java/io/WriteAbortedException.java
new file mode 100644
index 000000000..f051dc975
--- /dev/null
+++ b/libjava/classpath/java/io/WriteAbortedException.java
@@ -0,0 +1,109 @@
+/* WriteAbortedException.java -- wraps an exception thrown while writing
+ Copyright (C) 1998, 2000, 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 java.io;
+
+/**
+ * This exception is thrown when another ObjectStreamException occurs during
+ * a serialization read or write. The stream is reset, and deserialized
+ * objects are discarded.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Eric Blake (ebb9@email.byu.edu)
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public class WriteAbortedException extends ObjectStreamException
+{
+ /**
+ * Compatible with JDK 1.1+.
+ */
+ private static final long serialVersionUID = -3326426625597282442L;
+
+ /**
+ * The cause of this exception. This pre-dates the exception chaining
+ * of Throwable; and although you can change this field, you are wiser
+ * to leave it alone.
+ *
+ * @serial the exception cause
+ */
+ public Exception detail;
+
+ /**
+ * Create a new WriteAbortedException with a specified message and
+ * cause.
+ *
+ * @param msg the message
+ * @param detail the cause
+ */
+ public WriteAbortedException(String msg, Exception detail)
+ {
+ super(msg);
+ initCause(detail);
+ this.detail = detail;
+ }
+
+ /**
+ * This method returns a message indicating what went wrong, in this
+ * format:
+ * <code>super.getMessage() + (detail == null ? "" : "; " + detail)</code>.
+ *
+ * @return the chained message
+ */
+ public String getMessage()
+ {
+ if (detail == this || detail == null)
+ return super.getMessage();
+ return super.getMessage() + "; " + detail;
+ }
+
+ /**
+ * Returns the cause of this exception. Note that this may not be the
+ * original cause, thanks to the <code>detail</code> field being public
+ * and non-final (yuck). However, to avoid violating the contract of
+ * Throwable.getCause(), this returns null if <code>detail == this</code>,
+ * as no exception can be its own cause.
+ *
+ * @return the cause
+ * @since 1.4
+ */
+ public Throwable getCause()
+ {
+ return detail == this ? null : detail;
+ }
+} // class WriteAbortedException
diff --git a/libjava/classpath/java/io/Writer.java b/libjava/classpath/java/io/Writer.java
new file mode 100644
index 000000000..5b3e7073a
--- /dev/null
+++ b/libjava/classpath/java/io/Writer.java
@@ -0,0 +1,211 @@
+/* Writer.java -- Base class for character output streams
+ Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.io;
+
+/* Written using "Java Class Libraries", 2nd edition, plus online
+ * API docs for JDK 1.2 beta from http://www.javasoft.com.
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * This abstract class forms the base of the hierarchy of classes that
+ * write output as a stream of chars. It provides a common set of methods
+ * for writing chars to stream. Subclasses implement and/or extend these
+ * methods to write chars in a particular manner or to a particular
+ * destination such as a file on disk or network connection.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Per Bothner (bothner@cygnus.com)
+ */
+public abstract class Writer implements Appendable, Closeable, Flushable
+{
+ /**
+ * This is the object used to synchronize criticial code sections for
+ * thread safety. Subclasses should use this field instead of using
+ * synchronized methods or explicity synchronizations on <code>this</code>
+ */
+ protected Object lock;
+
+ /**
+ * This is the default no-argument constructor for this class. This method
+ * will set up the class to synchronize criticial sections on itself.
+ */
+ protected Writer()
+ {
+ lock = this;
+ }
+
+ /**
+ * This method initializes a <code>Writer</code> that will synchronize
+ * on the specified <code>Object</code>.
+ *
+ * @param lock The <code>Object</code> to use for synchronizing critical
+ * sections. Must not be null.
+ */
+ protected Writer(Object lock)
+ {
+ if (lock == null)
+ throw new NullPointerException();
+
+ this.lock = lock;
+ }
+
+ /**
+ * This method forces any data that may have been buffered to be written
+ * to the underlying output device. Please note that the host environment
+ * might perform its own buffering unbeknowst to Java. In that case, a
+ * write made (for example, to a disk drive) might be cached in OS
+ * buffers instead of actually being written to disk.
+ *
+ * @exception IOException If an error occurs
+ */
+ public abstract void flush() throws IOException;
+
+ /**
+ * This method closes the stream. Any internal or native resources
+ * associated
+ * with this stream are freed. Any subsequent attempt to access the stream
+ * might throw an exception.
+ * <p>
+ * This method in this class does nothing.
+ *
+ * @exception IOException If an error occurs
+ */
+ public abstract void close() throws IOException;
+
+ /**
+ * This method writes a single char to the output stream.
+ *
+ * @param b The char to be written to the output stream, passed as an int
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write(int b) throws IOException
+ {
+ char[] buf = new char[1];
+
+ buf[0] = (char)b;
+ write(buf, 0, buf.length);
+ }
+
+ /**
+ * This method all the writes char from the passed array to the output
+ * stream. This method is equivalent to
+ * <code>write(buf, 0, buf.length)</code> which
+ * is exactly how it is implemented in this class.
+ *
+ * @param buf The array of char to write
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write(char[] buf) throws IOException
+ {
+ write(buf, 0, buf.length);
+ }
+
+ /**
+ * This method writes <code>len</code> char from the specified array
+ * <code>buf</code> starting at index <code>offset</code> into the array.
+ * <p>
+ * Subclasses must provide an implementation of this abstract method.
+ *
+ * @param buf The array of char to write from
+ * @param offset The index into the array to start writing from
+ * @param len The number of char to write
+ *
+ * @exception IOException If an error occurs
+ */
+ public abstract void write(char[] buf, int offset, int len)
+ throws IOException;
+
+ /**
+ * This method writes all the characters in a <code>String</code> to the
+ * output.
+ *
+ * @param str The <code>String</code> whose chars are to be written.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write(String str) throws IOException
+ {
+ write(str, 0, str.length());
+ }
+
+ /**
+ * This method writes <code>len</code> chars from the <code>String</code>
+ * starting at position <code>offset</code>.
+ *
+ * @param str The <code>String</code> that is to be written
+ * @param offset The character offset into the <code>String</code> to start
+ * writing from
+ * @param len The number of chars to write
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write(String str, int offset, int len) throws IOException
+ {
+ // FIXME - for libgcj re-write using native code to not require
+ // copied buffer.
+ char[] buf = new char[len];
+
+ str.getChars(offset, offset + len, buf, 0);
+ write(buf, 0, len);
+ }
+
+ /** @since 1.5 */
+ public Writer append(char c) throws IOException
+ {
+ write(c);
+ return this;
+ }
+
+ /** @since 1.5 */
+ public Writer append(CharSequence cs) throws IOException
+ {
+ write(cs == null ? "null" : cs.toString());
+ return this;
+ }
+
+ /** @since 1.5 */
+ public Writer append(CharSequence cs, int start, int end) throws IOException
+ {
+ write(cs == null ? "null" : cs.subSequence(start, end).toString());
+ return this;
+ }
+}
diff --git a/libjava/classpath/java/io/package.html b/libjava/classpath/java/io/package.html
new file mode 100644
index 000000000..02e1c5bc3
--- /dev/null
+++ b/libjava/classpath/java/io/package.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in java.io package.
+ 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. -->
+
+<html>
+<head><title>GNU Classpath - java.io</title></head>
+
+<body>
+<p>Classes for manipulating character and byte streams and files.</p>
+
+</body>
+</html>