Add API 31 sources
Test: None
Change-Id: Ie45894f7a232b2a15e2439b2527ca1813f334cc5
diff --git a/java/io/Bits.java b/java/io/Bits.java
new file mode 100644
index 0000000..5563e66
--- /dev/null
+++ b/java/io/Bits.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Utility methods for packing/unpacking primitive values in/out of byte arrays
+ * using big-endian byte ordering.
+ */
+class Bits {
+
+ /*
+ * Methods for unpacking primitive values from byte arrays starting at
+ * given offsets.
+ */
+
+ static boolean getBoolean(byte[] b, int off) {
+ return b[off] != 0;
+ }
+
+ static char getChar(byte[] b, int off) {
+ return (char) ((b[off + 1] & 0xFF) +
+ (b[off] << 8));
+ }
+
+ static short getShort(byte[] b, int off) {
+ return (short) ((b[off + 1] & 0xFF) +
+ (b[off] << 8));
+ }
+
+ static int getInt(byte[] b, int off) {
+ return ((b[off + 3] & 0xFF) ) +
+ ((b[off + 2] & 0xFF) << 8) +
+ ((b[off + 1] & 0xFF) << 16) +
+ ((b[off ] ) << 24);
+ }
+
+ static float getFloat(byte[] b, int off) {
+ return Float.intBitsToFloat(getInt(b, off));
+ }
+
+ static long getLong(byte[] b, int off) {
+ return ((b[off + 7] & 0xFFL) ) +
+ ((b[off + 6] & 0xFFL) << 8) +
+ ((b[off + 5] & 0xFFL) << 16) +
+ ((b[off + 4] & 0xFFL) << 24) +
+ ((b[off + 3] & 0xFFL) << 32) +
+ ((b[off + 2] & 0xFFL) << 40) +
+ ((b[off + 1] & 0xFFL) << 48) +
+ (((long) b[off]) << 56);
+ }
+
+ static double getDouble(byte[] b, int off) {
+ return Double.longBitsToDouble(getLong(b, off));
+ }
+
+ /*
+ * Methods for packing primitive values into byte arrays starting at given
+ * offsets.
+ */
+
+ static void putBoolean(byte[] b, int off, boolean val) {
+ b[off] = (byte) (val ? 1 : 0);
+ }
+
+ static void putChar(byte[] b, int off, char val) {
+ b[off + 1] = (byte) (val );
+ b[off ] = (byte) (val >>> 8);
+ }
+
+ static void putShort(byte[] b, int off, short val) {
+ b[off + 1] = (byte) (val );
+ b[off ] = (byte) (val >>> 8);
+ }
+
+ static void putInt(byte[] b, int off, int val) {
+ b[off + 3] = (byte) (val );
+ b[off + 2] = (byte) (val >>> 8);
+ b[off + 1] = (byte) (val >>> 16);
+ b[off ] = (byte) (val >>> 24);
+ }
+
+ static void putFloat(byte[] b, int off, float val) {
+ putInt(b, off, Float.floatToIntBits(val));
+ }
+
+ static void putLong(byte[] b, int off, long val) {
+ b[off + 7] = (byte) (val );
+ b[off + 6] = (byte) (val >>> 8);
+ b[off + 5] = (byte) (val >>> 16);
+ b[off + 4] = (byte) (val >>> 24);
+ b[off + 3] = (byte) (val >>> 32);
+ b[off + 2] = (byte) (val >>> 40);
+ b[off + 1] = (byte) (val >>> 48);
+ b[off ] = (byte) (val >>> 56);
+ }
+
+ static void putDouble(byte[] b, int off, double val) {
+ putLong(b, off, Double.doubleToLongBits(val));
+ }
+}
diff --git a/java/io/BufferedInputStream.java b/java/io/BufferedInputStream.java
new file mode 100644
index 0000000..e39c20c
--- /dev/null
+++ b/java/io/BufferedInputStream.java
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+/**
+ * A <code>BufferedInputStream</code> adds
+ * functionality to another input stream-namely,
+ * the ability to buffer the input and to
+ * support the <code>mark</code> and <code>reset</code>
+ * methods. When the <code>BufferedInputStream</code>
+ * is created, an internal buffer array is
+ * created. As bytes from the stream are read
+ * or skipped, the internal buffer is refilled
+ * as necessary from the contained input stream,
+ * many bytes at a time. The <code>mark</code>
+ * operation remembers a point in the input
+ * stream and the <code>reset</code> operation
+ * causes all the bytes read since the most
+ * recent <code>mark</code> operation to be
+ * reread before new bytes are taken from
+ * the contained input stream.
+ *
+ * @author Arthur van Hoff
+ * @since JDK1.0
+ */
+public
+class BufferedInputStream extends FilterInputStream {
+
+ // Android-changed: made final
+ private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+ /**
+ * The maximum size of array to allocate.
+ * Some VMs reserve some header words in an array.
+ * Attempts to allocate larger arrays may result in
+ * OutOfMemoryError: Requested array size exceeds VM limit
+ */
+ // Android-changed: made final
+ private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
+
+ /**
+ * The internal buffer array where the data is stored. When necessary,
+ * it may be replaced by another array of
+ * a different size.
+ */
+ protected volatile byte buf[];
+
+ /**
+ * Atomic updater to provide compareAndSet for buf. This is
+ * necessary because closes can be asynchronous. We use nullness
+ * of buf[] as primary indicator that this stream is closed. (The
+ * "in" field is also nulled out on close.)
+ */
+ private static final
+ AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
+ AtomicReferenceFieldUpdater.newUpdater
+ (BufferedInputStream.class, byte[].class, "buf");
+
+ /**
+ * The index one greater than the index of the last valid byte in
+ * the buffer.
+ * This value is always
+ * in the range <code>0</code> through <code>buf.length</code>;
+ * elements <code>buf[0]</code> through <code>buf[count-1]
+ * </code>contain buffered input data obtained
+ * from the underlying input stream.
+ */
+ protected int count;
+
+ /**
+ * The current position in the buffer. This is the index of the next
+ * character to be read from the <code>buf</code> array.
+ * <p>
+ * This value is always in the range <code>0</code>
+ * through <code>count</code>. If it is less
+ * than <code>count</code>, then <code>buf[pos]</code>
+ * is the next byte to be supplied as input;
+ * if it is equal to <code>count</code>, then
+ * the next <code>read</code> or <code>skip</code>
+ * operation will require more bytes to be
+ * read from the contained input stream.
+ *
+ * @see java.io.BufferedInputStream#buf
+ */
+ protected int pos;
+
+ /**
+ * The value of the <code>pos</code> field at the time the last
+ * <code>mark</code> method was called.
+ * <p>
+ * This value is always
+ * in the range <code>-1</code> through <code>pos</code>.
+ * If there is no marked position in the input
+ * stream, this field is <code>-1</code>. If
+ * there is a marked position in the input
+ * stream, then <code>buf[markpos]</code>
+ * is the first byte to be supplied as input
+ * after a <code>reset</code> operation. If
+ * <code>markpos</code> is not <code>-1</code>,
+ * then all bytes from positions <code>buf[markpos]</code>
+ * through <code>buf[pos-1]</code> must remain
+ * in the buffer array (though they may be
+ * moved to another place in the buffer array,
+ * with suitable adjustments to the values
+ * of <code>count</code>, <code>pos</code>,
+ * and <code>markpos</code>); they may not
+ * be discarded unless and until the difference
+ * between <code>pos</code> and <code>markpos</code>
+ * exceeds <code>marklimit</code>.
+ *
+ * @see java.io.BufferedInputStream#mark(int)
+ * @see java.io.BufferedInputStream#pos
+ */
+ protected int markpos = -1;
+
+ /**
+ * The maximum read ahead allowed after a call to the
+ * <code>mark</code> method before subsequent calls to the
+ * <code>reset</code> method fail.
+ * Whenever the difference between <code>pos</code>
+ * and <code>markpos</code> exceeds <code>marklimit</code>,
+ * then the mark may be dropped by setting
+ * <code>markpos</code> to <code>-1</code>.
+ *
+ * @see java.io.BufferedInputStream#mark(int)
+ * @see java.io.BufferedInputStream#reset()
+ */
+ protected int marklimit;
+
+ /**
+ * Check to make sure that underlying input stream has not been
+ * nulled out due to close; if not return it;
+ */
+ private InputStream getInIfOpen() throws IOException {
+ InputStream input = in;
+ if (input == null)
+ throw new IOException("Stream closed");
+ return input;
+ }
+
+ /**
+ * Check to make sure that buffer has not been nulled out due to
+ * close; if not return it;
+ */
+ private byte[] getBufIfOpen() throws IOException {
+ byte[] buffer = buf;
+ if (buffer == null)
+ throw new IOException("Stream closed");
+ return buffer;
+ }
+
+ /**
+ * Creates a <code>BufferedInputStream</code>
+ * and saves its argument, the input stream
+ * <code>in</code>, for later use. An internal
+ * buffer array is created and stored in <code>buf</code>.
+ *
+ * @param in the underlying input stream.
+ */
+ public BufferedInputStream(InputStream in) {
+ this(in, DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * Creates a <code>BufferedInputStream</code>
+ * with the specified buffer size,
+ * and saves its argument, the input stream
+ * <code>in</code>, for later use. An internal
+ * buffer array of length <code>size</code>
+ * is created and stored in <code>buf</code>.
+ *
+ * @param in the underlying input stream.
+ * @param size the buffer size.
+ * @exception IllegalArgumentException if {@code size <= 0}.
+ */
+ public BufferedInputStream(InputStream in, int size) {
+ super(in);
+ if (size <= 0) {
+ throw new IllegalArgumentException("Buffer size <= 0");
+ }
+ buf = new byte[size];
+ }
+
+ /**
+ * Fills the buffer with more data, taking into account
+ * shuffling and other tricks for dealing with marks.
+ * Assumes that it is being called by a synchronized method.
+ * This method also assumes that all data has already been read in,
+ * hence pos > count.
+ */
+ private void fill() throws IOException {
+ byte[] buffer = getBufIfOpen();
+ if (markpos < 0)
+ pos = 0; /* no mark: throw away the buffer */
+ else if (pos >= buffer.length) /* no room left in buffer */
+ if (markpos > 0) { /* can throw away early part of the buffer */
+ int sz = pos - markpos;
+ System.arraycopy(buffer, markpos, buffer, 0, sz);
+ pos = sz;
+ markpos = 0;
+ } else if (buffer.length >= marklimit) {
+ markpos = -1; /* buffer got too big, invalidate mark */
+ pos = 0; /* drop buffer contents */
+ } else if (buffer.length >= MAX_BUFFER_SIZE) {
+ throw new OutOfMemoryError("Required array size too large");
+ } else { /* grow buffer */
+ int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
+ pos * 2 : MAX_BUFFER_SIZE;
+ if (nsz > marklimit)
+ nsz = marklimit;
+ byte nbuf[] = new byte[nsz];
+ System.arraycopy(buffer, 0, nbuf, 0, pos);
+ if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
+ // Can't replace buf if there was an async close.
+ // Note: This would need to be changed if fill()
+ // is ever made accessible to multiple threads.
+ // But for now, the only way CAS can fail is via close.
+ // assert buf == null;
+ throw new IOException("Stream closed");
+ }
+ buffer = nbuf;
+ }
+ count = pos;
+ int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
+ if (n > 0)
+ count = n + pos;
+ }
+
+ /**
+ * See
+ * the general contract of the <code>read</code>
+ * method of <code>InputStream</code>.
+ *
+ * @return the next byte of data, or <code>-1</code> if the end of the
+ * stream is reached.
+ * @exception IOException if this input stream has been closed by
+ * invoking its {@link #close()} method,
+ * or an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public synchronized int read() throws IOException {
+ if (pos >= count) {
+ fill();
+ if (pos >= count)
+ return -1;
+ }
+ return getBufIfOpen()[pos++] & 0xff;
+ }
+
+ /**
+ * Read characters into a portion of an array, reading from the underlying
+ * stream at most once if necessary.
+ */
+ private int read1(byte[] b, int off, int len) throws IOException {
+ int avail = count - pos;
+ if (avail <= 0) {
+ /* If the requested length is at least as large as the buffer, and
+ if there is no mark/reset activity, do not bother to copy the
+ bytes into the local buffer. In this way buffered streams will
+ cascade harmlessly. */
+ if (len >= getBufIfOpen().length && markpos < 0) {
+ return getInIfOpen().read(b, off, len);
+ }
+ fill();
+ avail = count - pos;
+ if (avail <= 0) return -1;
+ }
+ int cnt = (avail < len) ? avail : len;
+ System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
+ pos += cnt;
+ return cnt;
+ }
+
+ /**
+ * Reads bytes from this byte-input stream into the specified byte array,
+ * starting at the given offset.
+ *
+ * <p> This method implements the general contract of the corresponding
+ * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
+ * the <code>{@link InputStream}</code> class. As an additional
+ * convenience, it attempts to read as many bytes as possible by repeatedly
+ * invoking the <code>read</code> method of the underlying stream. This
+ * iterated <code>read</code> continues until one of the following
+ * conditions becomes true: <ul>
+ *
+ * <li> The specified number of bytes have been read,
+ *
+ * <li> The <code>read</code> method of the underlying stream returns
+ * <code>-1</code>, indicating end-of-file, or
+ *
+ * <li> The <code>available</code> method of the underlying stream
+ * returns zero, indicating that further input requests would block.
+ *
+ * </ul> If the first <code>read</code> on the underlying stream returns
+ * <code>-1</code> to indicate end-of-file then this method returns
+ * <code>-1</code>. Otherwise this method returns the number of bytes
+ * actually read.
+ *
+ * <p> Subclasses of this class are encouraged, but not required, to
+ * attempt to read as many bytes as possible in the same fashion.
+ *
+ * @param b destination buffer.
+ * @param off offset at which to start storing bytes.
+ * @param len maximum number of bytes to read.
+ * @return the number of bytes read, or <code>-1</code> if the end of
+ * the stream has been reached.
+ * @exception IOException if this input stream has been closed by
+ * invoking its {@link #close()} method,
+ * or an I/O error occurs.
+ */
+ public synchronized int read(byte b[], int off, int len)
+ throws IOException
+ {
+ getBufIfOpen(); // Check for closed stream
+ if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ int n = 0;
+ for (;;) {
+ int nread = read1(b, off + n, len - n);
+ if (nread <= 0)
+ return (n == 0) ? nread : n;
+ n += nread;
+ if (n >= len)
+ return n;
+ // if not closed but no bytes available, return
+ InputStream input = in;
+ if (input != null && input.available() <= 0)
+ return n;
+ }
+ }
+
+ /**
+ * See the general contract of the <code>skip</code>
+ * method of <code>InputStream</code>.
+ *
+ * @exception IOException if the stream does not support seek,
+ * or if this input stream has been closed by
+ * invoking its {@link #close()} method, or an
+ * I/O error occurs.
+ */
+ public synchronized long skip(long n) throws IOException {
+ getBufIfOpen(); // Check for closed stream
+ if (n <= 0) {
+ return 0;
+ }
+ long avail = count - pos;
+
+ if (avail <= 0) {
+ // If no mark position set then don't keep in buffer
+ if (markpos <0)
+ return getInIfOpen().skip(n);
+
+ // Fill in buffer to save bytes for reset
+ fill();
+ avail = count - pos;
+ if (avail <= 0)
+ return 0;
+ }
+
+ long skipped = (avail < n) ? avail : n;
+ pos += skipped;
+ return skipped;
+ }
+
+ /**
+ * Returns an estimate of the number of bytes that can be read (or
+ * skipped over) from this input stream without blocking by the next
+ * invocation of a method for this input stream. The next invocation might be
+ * the same thread or another thread. A single read or skip of this
+ * many bytes will not block, but may read or skip fewer bytes.
+ * <p>
+ * This method returns the sum of the number of bytes remaining to be read in
+ * the buffer (<code>count - pos</code>) and the result of calling the
+ * {@link java.io.FilterInputStream#in in}.available().
+ *
+ * @return an estimate of the number of bytes that can be read (or skipped
+ * over) from this input stream without blocking.
+ * @exception IOException if this input stream has been closed by
+ * invoking its {@link #close()} method,
+ * or an I/O error occurs.
+ */
+ public synchronized int available() throws IOException {
+ int n = count - pos;
+ int avail = getInIfOpen().available();
+ return n > (Integer.MAX_VALUE - avail)
+ ? Integer.MAX_VALUE
+ : n + avail;
+ }
+
+ /**
+ * See the general contract of the <code>mark</code>
+ * method of <code>InputStream</code>.
+ *
+ * @param readlimit the maximum limit of bytes that can be read before
+ * the mark position becomes invalid.
+ * @see java.io.BufferedInputStream#reset()
+ */
+ public synchronized void mark(int readlimit) {
+ marklimit = readlimit;
+ markpos = pos;
+ }
+
+ /**
+ * See the general contract of the <code>reset</code>
+ * method of <code>InputStream</code>.
+ * <p>
+ * If <code>markpos</code> is <code>-1</code>
+ * (no mark has been set or the mark has been
+ * invalidated), an <code>IOException</code>
+ * is thrown. Otherwise, <code>pos</code> is
+ * set equal to <code>markpos</code>.
+ *
+ * @exception IOException if this stream has not been marked or,
+ * if the mark has been invalidated, or the stream
+ * has been closed by invoking its {@link #close()}
+ * method, or an I/O error occurs.
+ * @see java.io.BufferedInputStream#mark(int)
+ */
+ public synchronized void reset() throws IOException {
+ getBufIfOpen(); // Cause exception if closed
+ if (markpos < 0)
+ throw new IOException("Resetting to invalid mark");
+ pos = markpos;
+ }
+
+ /**
+ * Tests if this input stream supports the <code>mark</code>
+ * and <code>reset</code> methods. The <code>markSupported</code>
+ * method of <code>BufferedInputStream</code> returns
+ * <code>true</code>.
+ *
+ * @return a <code>boolean</code> indicating if this stream type supports
+ * the <code>mark</code> and <code>reset</code> methods.
+ * @see java.io.InputStream#mark(int)
+ * @see java.io.InputStream#reset()
+ */
+ public boolean markSupported() {
+ return true;
+ }
+
+ /**
+ * Closes this input stream and releases any system resources
+ * associated with the stream.
+ * Once the stream has been closed, further read(), available(), reset(),
+ * or skip() invocations will throw an IOException.
+ * Closing a previously closed stream has no effect.
+ *
+ * @exception IOException if an I/O error occurs.
+ */
+ public void close() throws IOException {
+ byte[] buffer;
+ while ( (buffer = buf) != null) {
+ if (bufUpdater.compareAndSet(this, buffer, null)) {
+ InputStream input = in;
+ in = null;
+ if (input != null)
+ input.close();
+ return;
+ }
+ // Else retry in case a new buf was CASed in fill()
+ }
+ }
+}
diff --git a/java/io/BufferedOutputStream.java b/java/io/BufferedOutputStream.java
new file mode 100644
index 0000000..0579704
--- /dev/null
+++ b/java/io/BufferedOutputStream.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * The class implements a buffered output stream. By setting up such
+ * an output stream, an application can write bytes to the underlying
+ * output stream without necessarily causing a call to the underlying
+ * system for each byte written.
+ *
+ * @author Arthur van Hoff
+ * @since JDK1.0
+ */
+public
+class BufferedOutputStream extends FilterOutputStream {
+ /**
+ * The internal buffer where data is stored.
+ */
+ protected byte buf[];
+
+ /**
+ * The number of valid bytes in the buffer. This value is always
+ * in the range <tt>0</tt> through <tt>buf.length</tt>; elements
+ * <tt>buf[0]</tt> through <tt>buf[count-1]</tt> contain valid
+ * byte data.
+ */
+ protected int count;
+
+ /**
+ * Creates a new buffered output stream to write data to the
+ * specified underlying output stream.
+ *
+ * @param out the underlying output stream.
+ */
+ public BufferedOutputStream(OutputStream out) {
+ this(out, 8192);
+ }
+
+ /**
+ * Creates a new buffered output stream to write data to the
+ * specified underlying output stream with the specified buffer
+ * size.
+ *
+ * @param out the underlying output stream.
+ * @param size the buffer size.
+ * @exception IllegalArgumentException if size <= 0.
+ */
+ public BufferedOutputStream(OutputStream out, int size) {
+ super(out);
+ if (size <= 0) {
+ throw new IllegalArgumentException("Buffer size <= 0");
+ }
+ buf = new byte[size];
+ }
+
+ /** Flush the internal buffer */
+ private void flushBuffer() throws IOException {
+ if (count > 0) {
+ out.write(buf, 0, count);
+ count = 0;
+ }
+ }
+
+ /**
+ * Writes the specified byte to this buffered output stream.
+ *
+ * @param b the byte to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ public synchronized void write(int b) throws IOException {
+ if (count >= buf.length) {
+ flushBuffer();
+ }
+ buf[count++] = (byte)b;
+ }
+
+ /**
+ * Writes <code>len</code> bytes from the specified byte array
+ * starting at offset <code>off</code> to this buffered output stream.
+ *
+ * <p> Ordinarily this method stores bytes from the given array into this
+ * stream's buffer, flushing the buffer to the underlying output stream as
+ * needed. If the requested length is at least as large as this stream's
+ * buffer, however, then this method will flush the buffer and write the
+ * bytes directly to the underlying output stream. Thus redundant
+ * <code>BufferedOutputStream</code>s will not copy data unnecessarily.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @exception IOException if an I/O error occurs.
+ */
+ public synchronized void write(byte b[], int off, int len) throws IOException {
+ if (len >= buf.length) {
+ /* If the request length exceeds the size of the output buffer,
+ flush the output buffer and then write the data directly.
+ In this way buffered streams will cascade harmlessly. */
+ flushBuffer();
+ out.write(b, off, len);
+ return;
+ }
+ if (len > buf.length - count) {
+ flushBuffer();
+ }
+ System.arraycopy(b, off, buf, count, len);
+ count += len;
+ }
+
+ /**
+ * Flushes this buffered output stream. This forces any buffered
+ * output bytes to be written out to the underlying output stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ */
+ public synchronized void flush() throws IOException {
+ flushBuffer();
+ out.flush();
+ }
+}
diff --git a/java/io/BufferedReader.java b/java/io/BufferedReader.java
new file mode 100644
index 0000000..fb814b1
--- /dev/null
+++ b/java/io/BufferedReader.java
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * Reads text from a character-input stream, buffering characters so as to
+ * provide for the efficient reading of characters, arrays, and lines.
+ *
+ * <p> The buffer size may be specified, or the default size may be used. The
+ * default is large enough for most purposes.
+ *
+ * <p> In general, each read request made of a Reader causes a corresponding
+ * read request to be made of the underlying character or byte stream. It is
+ * therefore advisable to wrap a BufferedReader around any Reader whose read()
+ * operations may be costly, such as FileReaders and InputStreamReaders. For
+ * example,
+ *
+ * <pre>
+ * BufferedReader in
+ * = new BufferedReader(new FileReader("foo.in"));
+ * </pre>
+ *
+ * will buffer the input from the specified file. Without buffering, each
+ * invocation of read() or readLine() could cause bytes to be read from the
+ * file, converted into characters, and then returned, which can be very
+ * inefficient.
+ *
+ * <p> Programs that use DataInputStreams for textual input can be localized by
+ * replacing each DataInputStream with an appropriate BufferedReader.
+ *
+ * @see FileReader
+ * @see InputStreamReader
+ * @see java.nio.file.Files#newBufferedReader
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class BufferedReader extends Reader {
+
+ private Reader in;
+
+ private char cb[];
+ private int nChars, nextChar;
+
+ private static final int INVALIDATED = -2;
+ private static final int UNMARKED = -1;
+ private int markedChar = UNMARKED;
+ private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
+
+ /** If the next character is a line feed, skip it */
+ private boolean skipLF = false;
+
+ /** The skipLF flag when the mark was set */
+ private boolean markedSkipLF = false;
+
+ private static int defaultCharBufferSize = 8192;
+ private static int defaultExpectedLineLength = 80;
+
+ /**
+ * Creates a buffering character-input stream that uses an input buffer of
+ * the specified size.
+ *
+ * @param in A Reader
+ * @param sz Input-buffer size
+ *
+ * @exception IllegalArgumentException If {@code sz <= 0}
+ */
+ public BufferedReader(Reader in, int sz) {
+ super(in);
+ if (sz <= 0)
+ throw new IllegalArgumentException("Buffer size <= 0");
+ this.in = in;
+ cb = new char[sz];
+ nextChar = nChars = 0;
+ }
+
+ /**
+ * Creates a buffering character-input stream that uses a default-sized
+ * input buffer.
+ *
+ * @param in A Reader
+ */
+ public BufferedReader(Reader in) {
+ this(in, defaultCharBufferSize);
+ }
+
+ /** Checks to make sure that the stream has not been closed */
+ private void ensureOpen() throws IOException {
+ if (in == null)
+ throw new IOException("Stream closed");
+ }
+
+ /**
+ * Fills the input buffer, taking the mark into account if it is valid.
+ */
+ private void fill() throws IOException {
+ int dst;
+ if (markedChar <= UNMARKED) {
+ /* No mark */
+ dst = 0;
+ } else {
+ /* Marked */
+ int delta = nextChar - markedChar;
+ if (delta >= readAheadLimit) {
+ /* Gone past read-ahead limit: Invalidate mark */
+ markedChar = INVALIDATED;
+ readAheadLimit = 0;
+ dst = 0;
+ } else {
+ if (readAheadLimit <= cb.length) {
+ /* Shuffle in the current buffer */
+ System.arraycopy(cb, markedChar, cb, 0, delta);
+ markedChar = 0;
+ dst = delta;
+ } else {
+ /* Reallocate buffer to accommodate read-ahead limit */
+ //
+ // Android-changed: Use the same strategy as BufferedInputStream,
+ // i.e, double the size of the buffer on each fill. Do not directly
+ // size the buffer to the readAheadLimit.
+ //
+ // char ncb[] = new char[readAheadLimit];
+ int nlength = cb.length * 2;
+ if (nlength > readAheadLimit) {
+ nlength = readAheadLimit;
+ }
+ char ncb[] = new char[nlength];
+ System.arraycopy(cb, markedChar, ncb, 0, delta);
+ cb = ncb;
+ markedChar = 0;
+ dst = delta;
+ }
+ nextChar = nChars = delta;
+ }
+ }
+
+ int n;
+ do {
+ n = in.read(cb, dst, cb.length - dst);
+ } while (n == 0);
+ if (n > 0) {
+ nChars = dst + n;
+ nextChar = dst;
+ }
+ }
+
+ /**
+ * Reads a single character.
+ *
+ * @return The character read, as an integer in the range
+ * 0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
+ * end of the stream has been reached
+ * @exception IOException If an I/O error occurs
+ */
+ public int read() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ for (;;) {
+ if (nextChar >= nChars) {
+ fill();
+ if (nextChar >= nChars)
+ return -1;
+ }
+ if (skipLF) {
+ skipLF = false;
+ if (cb[nextChar] == '\n') {
+ nextChar++;
+ continue;
+ }
+ }
+ return cb[nextChar++];
+ }
+ }
+ }
+
+ /**
+ * Reads characters into a portion of an array, reading from the underlying
+ * stream if necessary.
+ */
+ private int read1(char[] cbuf, int off, int len) throws IOException {
+ if (nextChar >= nChars) {
+ /* If the requested length is at least as large as the buffer, and
+ if there is no mark/reset activity, and if line feeds are not
+ being skipped, do not bother to copy the characters into the
+ local buffer. In this way buffered streams will cascade
+ harmlessly. */
+ if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
+ return in.read(cbuf, off, len);
+ }
+ fill();
+ }
+ if (nextChar >= nChars) return -1;
+ if (skipLF) {
+ skipLF = false;
+ if (cb[nextChar] == '\n') {
+ nextChar++;
+ if (nextChar >= nChars)
+ fill();
+ if (nextChar >= nChars)
+ return -1;
+ }
+ }
+ int n = Math.min(len, nChars - nextChar);
+ System.arraycopy(cb, nextChar, cbuf, off, n);
+ nextChar += n;
+ return n;
+ }
+
+ /**
+ * Reads characters into a portion of an array.
+ *
+ * <p> This method implements the general contract of the corresponding
+ * <code>{@link Reader#read(char[], int, int) read}</code> method of the
+ * <code>{@link Reader}</code> class. As an additional convenience, it
+ * attempts to read as many characters as possible by repeatedly invoking
+ * the <code>read</code> method of the underlying stream. This iterated
+ * <code>read</code> continues until one of the following conditions becomes
+ * true: <ul>
+ *
+ * <li> The specified number of characters have been read,
+ *
+ * <li> The <code>read</code> method of the underlying stream returns
+ * <code>-1</code>, indicating end-of-file, or
+ *
+ * <li> The <code>ready</code> method of the underlying stream
+ * returns <code>false</code>, indicating that further input requests
+ * would block.
+ *
+ * </ul> If the first <code>read</code> on the underlying stream returns
+ * <code>-1</code> to indicate end-of-file then this method returns
+ * <code>-1</code>. Otherwise this method returns the number of characters
+ * actually read.
+ *
+ * <p> Subclasses of this class are encouraged, but not required, to
+ * attempt to read as many characters as possible in the same fashion.
+ *
+ * <p> Ordinarily this method takes characters from this stream's character
+ * buffer, filling it from the underlying stream as necessary. If,
+ * however, the buffer is empty, the mark is not valid, and the requested
+ * length is at least as large as the buffer, then this method will read
+ * characters directly from the underlying stream into the given array.
+ * Thus redundant <code>BufferedReader</code>s will not copy data
+ * unnecessarily.
+ *
+ * @param cbuf Destination buffer
+ * @param off Offset at which to start storing characters
+ * @param len Maximum number of characters to read
+ *
+ * @return The number of characters read, or -1 if the end of the
+ * stream has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read(char cbuf[], int off, int len) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+ ((off + len) > cbuf.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ int n = read1(cbuf, off, len);
+ if (n <= 0) return n;
+ while ((n < len) && in.ready()) {
+ int n1 = read1(cbuf, off + n, len - n);
+ if (n1 <= 0) break;
+ n += n1;
+ }
+ return n;
+ }
+ }
+
+ /**
+ * Reads a line of text. A line is considered to be terminated by any one
+ * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
+ * followed immediately by a linefeed.
+ *
+ * @param ignoreLF If true, the next '\n' will be skipped
+ *
+ * @return A String containing the contents of the line, not including
+ * any line-termination characters, or null if the end of the
+ * stream has been reached
+ *
+ * @see java.io.LineNumberReader#readLine()
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ String readLine(boolean ignoreLF) throws IOException {
+ StringBuffer s = null;
+ int startChar;
+
+ synchronized (lock) {
+ ensureOpen();
+ boolean omitLF = ignoreLF || skipLF;
+
+ bufferLoop:
+ for (;;) {
+
+ if (nextChar >= nChars)
+ fill();
+ if (nextChar >= nChars) { /* EOF */
+ if (s != null && s.length() > 0)
+ return s.toString();
+ else
+ return null;
+ }
+ boolean eol = false;
+ char c = 0;
+ int i;
+
+ /* Skip a leftover '\n', if necessary */
+ if (omitLF && (cb[nextChar] == '\n'))
+ nextChar++;
+ skipLF = false;
+ omitLF = false;
+
+ charLoop:
+ for (i = nextChar; i < nChars; i++) {
+ c = cb[i];
+ if ((c == '\n') || (c == '\r')) {
+ eol = true;
+ break charLoop;
+ }
+ }
+
+ startChar = nextChar;
+ nextChar = i;
+
+ if (eol) {
+ String str;
+ if (s == null) {
+ str = new String(cb, startChar, i - startChar);
+ } else {
+ s.append(cb, startChar, i - startChar);
+ str = s.toString();
+ }
+ nextChar++;
+ if (c == '\r') {
+ skipLF = true;
+ }
+ return str;
+ }
+
+ if (s == null)
+ s = new StringBuffer(defaultExpectedLineLength);
+ s.append(cb, startChar, i - startChar);
+ }
+ }
+ }
+
+ /**
+ * Reads a line of text. A line is considered to be terminated by any one
+ * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
+ * followed immediately by a linefeed.
+ *
+ * @return A String containing the contents of the line, not including
+ * any line-termination characters, or null if the end of the
+ * stream has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ *
+ * @see java.nio.file.Files#readAllLines
+ */
+ public String readLine() throws IOException {
+ return readLine(false);
+ }
+
+ /**
+ * Skips characters.
+ *
+ * @param n The number of characters to skip
+ *
+ * @return The number of characters actually skipped
+ *
+ * @exception IllegalArgumentException If <code>n</code> is negative.
+ * @exception IOException If an I/O error occurs
+ */
+ public long skip(long n) throws IOException {
+ if (n < 0L) {
+ throw new IllegalArgumentException("skip value is negative");
+ }
+ synchronized (lock) {
+ ensureOpen();
+ long r = n;
+ while (r > 0) {
+ if (nextChar >= nChars)
+ fill();
+ if (nextChar >= nChars) /* EOF */
+ break;
+ if (skipLF) {
+ skipLF = false;
+ if (cb[nextChar] == '\n') {
+ nextChar++;
+ }
+ }
+ long d = nChars - nextChar;
+ if (r <= d) {
+ nextChar += r;
+ r = 0;
+ break;
+ }
+ else {
+ r -= d;
+ nextChar = nChars;
+ }
+ }
+ return n - r;
+ }
+ }
+
+ /**
+ * Tells whether this stream is ready to be read. A buffered character
+ * stream is ready if the buffer is not empty, or if the underlying
+ * character stream is ready.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public boolean ready() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+
+ /*
+ * If newline needs to be skipped and the next char to be read
+ * is a newline character, then just skip it right away.
+ */
+ if (skipLF) {
+ /* Note that in.ready() will return true if and only if the next
+ * read on the stream will not block.
+ */
+ if (nextChar >= nChars && in.ready()) {
+ fill();
+ }
+ if (nextChar < nChars) {
+ if (cb[nextChar] == '\n')
+ nextChar++;
+ skipLF = false;
+ }
+ }
+ return (nextChar < nChars) || in.ready();
+ }
+ }
+
+ /**
+ * Tells whether this stream supports the mark() operation, which it does.
+ */
+ public boolean markSupported() {
+ return true;
+ }
+
+ /**
+ * Marks the present position in the stream. Subsequent calls to reset()
+ * will attempt to reposition the stream to this point.
+ *
+ * @param readAheadLimit Limit on the number of characters that may be
+ * read while still preserving the mark. An attempt
+ * to reset the stream after reading characters
+ * up to this limit or beyond may fail.
+ * A limit value larger than the size of the input
+ * buffer will cause a new buffer to be allocated
+ * whose size is no smaller than limit.
+ * Therefore large values should be used with care.
+ *
+ * @exception IllegalArgumentException If {@code readAheadLimit < 0}
+ * @exception IOException If an I/O error occurs
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ if (readAheadLimit < 0) {
+ throw new IllegalArgumentException("Read-ahead limit < 0");
+ }
+ synchronized (lock) {
+ ensureOpen();
+ this.readAheadLimit = readAheadLimit;
+ markedChar = nextChar;
+ markedSkipLF = skipLF;
+ }
+ }
+
+ /**
+ * Resets the stream to the most recent mark.
+ *
+ * @exception IOException If the stream has never been marked,
+ * or if the mark has been invalidated
+ */
+ public void reset() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if (markedChar < 0)
+ throw new IOException((markedChar == INVALIDATED)
+ ? "Mark invalid"
+ : "Stream not marked");
+ nextChar = markedChar;
+ skipLF = markedSkipLF;
+ }
+ }
+
+ public void close() throws IOException {
+ synchronized (lock) {
+ if (in == null)
+ return;
+ try {
+ in.close();
+ } finally {
+ in = null;
+ cb = null;
+ }
+ }
+ }
+
+ /**
+ * Returns a {@code Stream}, the elements of which are lines read from
+ * this {@code BufferedReader}. The {@link Stream} is lazily populated,
+ * i.e., read only occurs during the
+ * <a href="../util/stream/package-summary.html#StreamOps">terminal
+ * stream operation</a>.
+ *
+ * <p> The reader must not be operated on during the execution of the
+ * terminal stream operation. Otherwise, the result of the terminal stream
+ * operation is undefined.
+ *
+ * <p> After execution of the terminal stream operation there are no
+ * guarantees that the reader will be at a specific position from which to
+ * read the next character or line.
+ *
+ * <p> If an {@link IOException} is thrown when accessing the underlying
+ * {@code BufferedReader}, it is wrapped in an {@link
+ * UncheckedIOException} which will be thrown from the {@code Stream}
+ * method that caused the read to take place. This method will return a
+ * Stream if invoked on a BufferedReader that is closed. Any operation on
+ * that stream that requires reading from the BufferedReader after it is
+ * closed, will cause an UncheckedIOException to be thrown.
+ *
+ * @return a {@code Stream<String>} providing the lines of text
+ * described by this {@code BufferedReader}
+ *
+ * @since 1.8
+ */
+ public Stream<String> lines() {
+ Iterator<String> iter = new Iterator<String>() {
+ String nextLine = null;
+
+ @Override
+ public boolean hasNext() {
+ if (nextLine != null) {
+ return true;
+ } else {
+ try {
+ nextLine = readLine();
+ return (nextLine != null);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ }
+
+ @Override
+ public String next() {
+ if (nextLine != null || hasNext()) {
+ String line = nextLine;
+ nextLine = null;
+ return line;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+ };
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+ iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
+ }
+}
diff --git a/java/io/BufferedWriter.java b/java/io/BufferedWriter.java
new file mode 100644
index 0000000..a5d810a
--- /dev/null
+++ b/java/io/BufferedWriter.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Writes text to a character-output stream, buffering characters so as to
+ * provide for the efficient writing of single characters, arrays, and strings.
+ *
+ * <p> The buffer size may be specified, or the default size may be accepted.
+ * The default is large enough for most purposes.
+ *
+ * <p> A newLine() method is provided, which uses the platform's own notion of
+ * line separator as defined by the system property <tt>line.separator</tt>.
+ * Not all platforms use the newline character ('\n') to terminate lines.
+ * Calling this method to terminate each output line is therefore preferred to
+ * writing a newline character directly.
+ *
+ * <p> In general, a Writer sends its output immediately to the underlying
+ * character or byte stream. Unless prompt output is required, it is advisable
+ * to wrap a BufferedWriter around any Writer whose write() operations may be
+ * costly, such as FileWriters and OutputStreamWriters. For example,
+ *
+ * <pre>
+ * PrintWriter out
+ * = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
+ * </pre>
+ *
+ * will buffer the PrintWriter's output to the file. Without buffering, each
+ * invocation of a print() method would cause characters to be converted into
+ * bytes that would then be written immediately to the file, which can be very
+ * inefficient.
+ *
+ * @see PrintWriter
+ * @see FileWriter
+ * @see OutputStreamWriter
+ * @see java.nio.file.Files#newBufferedWriter
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class BufferedWriter extends Writer {
+
+ private Writer out;
+
+ private char cb[];
+ private int nChars, nextChar;
+
+ private static int defaultCharBufferSize = 8192;
+
+ /**
+ * Line separator string. This is the value of the line.separator
+ * property at the moment that the stream was created.
+ */
+ private String lineSeparator;
+
+ /**
+ * Creates a buffered character-output stream that uses a default-sized
+ * output buffer.
+ *
+ * @param out A Writer
+ */
+ public BufferedWriter(Writer out) {
+ this(out, defaultCharBufferSize);
+ }
+
+ /**
+ * Creates a new buffered character-output stream that uses an output
+ * buffer of the given size.
+ *
+ * @param out A Writer
+ * @param sz Output-buffer size, a positive integer
+ *
+ * @exception IllegalArgumentException If {@code sz <= 0}
+ */
+ public BufferedWriter(Writer out, int sz) {
+ super(out);
+ if (sz <= 0)
+ throw new IllegalArgumentException("Buffer size <= 0");
+ this.out = out;
+ cb = new char[sz];
+ nChars = sz;
+ nextChar = 0;
+
+ lineSeparator = java.security.AccessController.doPrivileged(
+ new sun.security.action.GetPropertyAction("line.separator"));
+ }
+
+ /** Checks to make sure that the stream has not been closed */
+ private void ensureOpen() throws IOException {
+ if (out == null)
+ throw new IOException("Stream closed");
+ }
+
+ /**
+ * Flushes the output buffer to the underlying character stream, without
+ * flushing the stream itself. This method is non-private only so that it
+ * may be invoked by PrintStream.
+ */
+ void flushBuffer() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if (nextChar == 0)
+ return;
+ out.write(cb, 0, nextChar);
+ nextChar = 0;
+ }
+ }
+
+ /**
+ * Writes a single character.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void write(int c) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if (nextChar >= nChars)
+ flushBuffer();
+ cb[nextChar++] = (char) c;
+ }
+ }
+
+ /**
+ * Our own little min method, to avoid loading java.lang.Math if we've run
+ * out of file descriptors and we're trying to print a stack trace.
+ */
+ private int min(int a, int b) {
+ if (a < b) return a;
+ return b;
+ }
+
+ /**
+ * Writes a portion of an array of characters.
+ *
+ * <p> Ordinarily this method stores characters from the given array into
+ * this stream's buffer, flushing the buffer to the underlying stream as
+ * needed. If the requested length is at least as large as the buffer,
+ * however, then this method will flush the buffer and write the characters
+ * directly to the underlying stream. Thus redundant
+ * <code>BufferedWriter</code>s will not copy data unnecessarily.
+ *
+ * @param cbuf A character array
+ * @param off Offset from which to start reading characters
+ * @param len Number of characters to write
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void write(char cbuf[], int off, int len) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+ ((off + len) > cbuf.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+
+ if (len >= nChars) {
+ /* If the request length exceeds the size of the output buffer,
+ flush the buffer and then write the data directly. In this
+ way buffered streams will cascade harmlessly. */
+ flushBuffer();
+ out.write(cbuf, off, len);
+ return;
+ }
+
+ int b = off, t = off + len;
+ while (b < t) {
+ int d = min(nChars - nextChar, t - b);
+ System.arraycopy(cbuf, b, cb, nextChar, d);
+ b += d;
+ nextChar += d;
+ if (nextChar >= nChars)
+ flushBuffer();
+ }
+ }
+ }
+
+ /**
+ * Writes a portion of a String.
+ *
+ * <p> If the value of the <tt>len</tt> parameter is negative then no
+ * characters are written. This is contrary to the specification of this
+ * method in the {@linkplain java.io.Writer#write(java.lang.String,int,int)
+ * superclass}, which requires that an {@link IndexOutOfBoundsException} be
+ * thrown.
+ *
+ * @param s String to be written
+ * @param off Offset from which to start reading characters
+ * @param len Number of characters to be written
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void write(String s, int off, int len) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+
+ int b = off, t = off + len;
+ while (b < t) {
+ int d = min(nChars - nextChar, t - b);
+ s.getChars(b, b + d, cb, nextChar);
+ b += d;
+ nextChar += d;
+ if (nextChar >= nChars)
+ flushBuffer();
+ }
+ }
+ }
+
+ /**
+ * Writes a line separator. The line separator string is defined by the
+ * system property <tt>line.separator</tt>, and is not necessarily a single
+ * newline ('\n') character.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void newLine() throws IOException {
+ write(lineSeparator);
+ }
+
+ /**
+ * Flushes the stream.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void flush() throws IOException {
+ synchronized (lock) {
+ flushBuffer();
+ out.flush();
+ }
+ }
+
+ @SuppressWarnings("try")
+ public void close() throws IOException {
+ synchronized (lock) {
+ if (out == null) {
+ return;
+ }
+ try (Writer w = out) {
+ flushBuffer();
+ } finally {
+ out = null;
+ cb = null;
+ }
+ }
+ }
+}
diff --git a/java/io/ByteArrayInputStream.java b/java/io/ByteArrayInputStream.java
new file mode 100644
index 0000000..d07f074
--- /dev/null
+++ b/java/io/ByteArrayInputStream.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * A <code>ByteArrayInputStream</code> contains
+ * an internal buffer that contains bytes that
+ * may be read from the stream. An internal
+ * counter keeps track of the next byte to
+ * be supplied by the <code>read</code> method.
+ * <p>
+ * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
+ * this class can be called after the stream has been closed without
+ * generating an <tt>IOException</tt>.
+ *
+ * @author Arthur van Hoff
+ * @see java.io.StringBufferInputStream
+ * @since JDK1.0
+ */
+public
+class ByteArrayInputStream extends InputStream {
+
+ /**
+ * An array of bytes that was provided
+ * by the creator of the stream. Elements <code>buf[0]</code>
+ * through <code>buf[count-1]</code> are the
+ * only bytes that can ever be read from the
+ * stream; element <code>buf[pos]</code> is
+ * the next byte to be read.
+ */
+ protected byte buf[];
+
+ /**
+ * The index of the next character to read from the input stream buffer.
+ * This value should always be nonnegative
+ * and not larger than the value of <code>count</code>.
+ * The next byte to be read from the input stream buffer
+ * will be <code>buf[pos]</code>.
+ */
+ protected int pos;
+
+ /**
+ * The currently marked position in the stream.
+ * ByteArrayInputStream objects are marked at position zero by
+ * default when constructed. They may be marked at another
+ * position within the buffer by the <code>mark()</code> method.
+ * The current buffer position is set to this point by the
+ * <code>reset()</code> method.
+ * <p>
+ * If no mark has been set, then the value of mark is the offset
+ * passed to the constructor (or 0 if the offset was not supplied).
+ *
+ * @since JDK1.1
+ */
+ protected int mark = 0;
+
+ /**
+ * The index one greater than the last valid character in the input
+ * stream buffer.
+ * This value should always be nonnegative
+ * and not larger than the length of <code>buf</code>.
+ * It is one greater than the position of
+ * the last byte within <code>buf</code> that
+ * can ever be read from the input stream buffer.
+ */
+ protected int count;
+
+ /**
+ * Creates a <code>ByteArrayInputStream</code>
+ * so that it uses <code>buf</code> as its
+ * buffer array.
+ * The buffer array is not copied.
+ * The initial value of <code>pos</code>
+ * is <code>0</code> and the initial value
+ * of <code>count</code> is the length of
+ * <code>buf</code>.
+ *
+ * @param buf the input buffer.
+ */
+ public ByteArrayInputStream(byte buf[]) {
+ this.buf = buf;
+ this.pos = 0;
+ this.count = buf.length;
+ }
+
+ /**
+ * Creates <code>ByteArrayInputStream</code>
+ * that uses <code>buf</code> as its
+ * buffer array. The initial value of <code>pos</code>
+ * is <code>offset</code> and the initial value
+ * of <code>count</code> is the minimum of <code>offset+length</code>
+ * and <code>buf.length</code>.
+ * The buffer array is not copied. The buffer's mark is
+ * set to the specified offset.
+ *
+ * @param buf the input buffer.
+ * @param offset the offset in the buffer of the first byte to read.
+ * @param length the maximum number of bytes to read from the buffer.
+ */
+ public ByteArrayInputStream(byte buf[], int offset, int length) {
+ this.buf = buf;
+ this.pos = offset;
+ this.count = Math.min(offset + length, buf.length);
+ this.mark = offset;
+ }
+
+ /**
+ * Reads the next byte of data from this input stream. The value
+ * byte is returned as an <code>int</code> in the range
+ * <code>0</code> to <code>255</code>. If no byte is available
+ * because the end of the stream has been reached, the value
+ * <code>-1</code> is returned.
+ * <p>
+ * This <code>read</code> method
+ * cannot block.
+ *
+ * @return the next byte of data, or <code>-1</code> if the end of the
+ * stream has been reached.
+ */
+ public synchronized int read() {
+ return (pos < count) ? (buf[pos++] & 0xff) : -1;
+ }
+
+ /**
+ * Reads up to <code>len</code> bytes of data into an array of bytes
+ * from this input stream.
+ * If <code>pos</code> equals <code>count</code>,
+ * then <code>-1</code> is returned to indicate
+ * end of file. Otherwise, the number <code>k</code>
+ * of bytes read is equal to the smaller of
+ * <code>len</code> and <code>count-pos</code>.
+ * If <code>k</code> is positive, then bytes
+ * <code>buf[pos]</code> through <code>buf[pos+k-1]</code>
+ * are copied into <code>b[off]</code> through
+ * <code>b[off+k-1]</code> in the manner performed
+ * by <code>System.arraycopy</code>. The
+ * value <code>k</code> is added into <code>pos</code>
+ * and <code>k</code> is returned.
+ * <p>
+ * This <code>read</code> method cannot block.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in the destination array <code>b</code>
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the stream has been reached.
+ * @exception NullPointerException If <code>b</code> is <code>null</code>.
+ * @exception IndexOutOfBoundsException If <code>off</code> is negative,
+ * <code>len</code> is negative, or <code>len</code> is greater than
+ * <code>b.length - off</code>
+ */
+ public synchronized int read(byte b[], int off, int len) {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ if (pos >= count) {
+ return -1;
+ }
+
+ int avail = count - pos;
+ if (len > avail) {
+ len = avail;
+ }
+ if (len <= 0) {
+ return 0;
+ }
+ System.arraycopy(buf, pos, b, off, len);
+ pos += len;
+ return len;
+ }
+
+ /**
+ * Skips <code>n</code> bytes of input from this input stream. Fewer
+ * bytes might be skipped if the end of the input stream is reached.
+ * The actual number <code>k</code>
+ * of bytes to be skipped is equal to the smaller
+ * of <code>n</code> and <code>count-pos</code>.
+ * The value <code>k</code> is added into <code>pos</code>
+ * and <code>k</code> is returned.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the actual number of bytes skipped.
+ */
+ public synchronized long skip(long n) {
+ long k = count - pos;
+ if (n < k) {
+ k = n < 0 ? 0 : n;
+ }
+
+ pos += k;
+ return k;
+ }
+
+ /**
+ * Returns the number of remaining bytes that can be read (or skipped over)
+ * from this input stream.
+ * <p>
+ * The value returned is <code>count - pos</code>,
+ * which is the number of bytes remaining to be read from the input buffer.
+ *
+ * @return the number of remaining bytes that can be read (or skipped
+ * over) from this input stream without blocking.
+ */
+ public synchronized int available() {
+ return count - pos;
+ }
+
+ /**
+ * Tests if this <code>InputStream</code> supports mark/reset. The
+ * <code>markSupported</code> method of <code>ByteArrayInputStream</code>
+ * always returns <code>true</code>.
+ *
+ * @since JDK1.1
+ */
+ public boolean markSupported() {
+ return true;
+ }
+
+ /**
+ * Set the current marked position in the stream.
+ * ByteArrayInputStream objects are marked at position zero by
+ * default when constructed. They may be marked at another
+ * position within the buffer by this method.
+ * <p>
+ * If no mark has been set, then the value of the mark is the
+ * offset passed to the constructor (or 0 if the offset was not
+ * supplied).
+ *
+ * <p> Note: The <code>readAheadLimit</code> for this class
+ * has no meaning.
+ *
+ * @since JDK1.1
+ */
+ public void mark(int readAheadLimit) {
+ mark = pos;
+ }
+
+ /**
+ * Resets the buffer to the marked position. The marked position
+ * is 0 unless another position was marked or an offset was specified
+ * in the constructor.
+ */
+ public synchronized void reset() {
+ pos = mark;
+ }
+
+ /**
+ * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
+ * this class can be called after the stream has been closed without
+ * generating an <tt>IOException</tt>.
+ */
+ public void close() throws IOException {
+ }
+
+}
diff --git a/java/io/ByteArrayOutputStream.annotated.java b/java/io/ByteArrayOutputStream.annotated.java
new file mode 100644
index 0000000..3fdca11
--- /dev/null
+++ b/java/io/ByteArrayOutputStream.annotated.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.io;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ByteArrayOutputStream extends java.io.OutputStream {
+
+public ByteArrayOutputStream() { throw new RuntimeException("Stub!"); }
+
+public ByteArrayOutputStream(int size) { throw new RuntimeException("Stub!"); }
+
+public synchronized void write(int b) { throw new RuntimeException("Stub!"); }
+
+public synchronized void write(byte @libcore.util.NonNull [] b, int off, int len) { throw new RuntimeException("Stub!"); }
+
+public synchronized void writeTo(@libcore.util.NonNull java.io.OutputStream out) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public synchronized void reset() { throw new RuntimeException("Stub!"); }
+
+public synchronized byte @libcore.util.NonNull [] toByteArray() { throw new RuntimeException("Stub!"); }
+
+public synchronized int size() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.String toString(@libcore.util.NonNull java.lang.String charsetName) throws java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
+
+@Deprecated
[email protected] public synchronized java.lang.String toString(int hibyte) { throw new RuntimeException("Stub!"); }
+
+public void close() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+protected byte @libcore.util.NonNull [] buf;
+
+protected int count;
+}
diff --git a/java/io/ByteArrayOutputStream.java b/java/io/ByteArrayOutputStream.java
new file mode 100644
index 0000000..f1d429b
--- /dev/null
+++ b/java/io/ByteArrayOutputStream.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.Arrays;
+
+/**
+ * This class implements an output stream in which the data is
+ * written into a byte array. The buffer automatically grows as data
+ * is written to it.
+ * The data can be retrieved using <code>toByteArray()</code> and
+ * <code>toString()</code>.
+ * <p>
+ * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
+ * this class can be called after the stream has been closed without
+ * generating an <tt>IOException</tt>.
+ *
+ * @author Arthur van Hoff
+ * @since JDK1.0
+ */
+
+public class ByteArrayOutputStream extends OutputStream {
+
+ /**
+ * The buffer where data is stored.
+ */
+ protected byte buf[];
+
+ /**
+ * The number of valid bytes in the buffer.
+ */
+ protected int count;
+
+ /**
+ * Creates a new byte array output stream. The buffer capacity is
+ * initially 32 bytes, though its size increases if necessary.
+ */
+ public ByteArrayOutputStream() {
+ this(32);
+ }
+
+ /**
+ * Creates a new byte array output stream, with a buffer capacity of
+ * the specified size, in bytes.
+ *
+ * @param size the initial size.
+ * @exception IllegalArgumentException if size is negative.
+ */
+ public ByteArrayOutputStream(int size) {
+ if (size < 0) {
+ throw new IllegalArgumentException("Negative initial size: "
+ + size);
+ }
+ buf = new byte[size];
+ }
+
+ /**
+ * Increases the capacity if necessary to ensure that it can hold
+ * at least the number of elements specified by the minimum
+ * capacity argument.
+ *
+ * @param minCapacity the desired minimum capacity
+ * @throws OutOfMemoryError if {@code minCapacity < 0}. This is
+ * interpreted as a request for the unsatisfiably large capacity
+ * {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}.
+ */
+ private void ensureCapacity(int minCapacity) {
+ // overflow-conscious code
+ if (minCapacity - buf.length > 0)
+ grow(minCapacity);
+ }
+
+ /**
+ * The maximum size of array to allocate.
+ * Some VMs reserve some header words in an array.
+ * Attempts to allocate larger arrays may result in
+ * OutOfMemoryError: Requested array size exceeds VM limit
+ */
+ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+ /**
+ * Increases the capacity to ensure that it can hold at least the
+ * number of elements specified by the minimum capacity argument.
+ *
+ * @param minCapacity the desired minimum capacity
+ */
+ private void grow(int minCapacity) {
+ // overflow-conscious code
+ int oldCapacity = buf.length;
+ int newCapacity = oldCapacity << 1;
+ if (newCapacity - minCapacity < 0)
+ newCapacity = minCapacity;
+ if (newCapacity - MAX_ARRAY_SIZE > 0)
+ newCapacity = hugeCapacity(minCapacity);
+ buf = Arrays.copyOf(buf, newCapacity);
+ }
+
+ private static int hugeCapacity(int minCapacity) {
+ if (minCapacity < 0) // overflow
+ throw new OutOfMemoryError();
+ return (minCapacity > MAX_ARRAY_SIZE) ?
+ Integer.MAX_VALUE :
+ MAX_ARRAY_SIZE;
+ }
+
+ /**
+ * Writes the specified byte to this byte array output stream.
+ *
+ * @param b the byte to be written.
+ */
+ public synchronized void write(int b) {
+ ensureCapacity(count + 1);
+ buf[count] = (byte) b;
+ count += 1;
+ }
+
+ /**
+ * Writes <code>len</code> bytes from the specified byte array
+ * starting at offset <code>off</code> to this byte array output stream.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ */
+ public synchronized void write(byte b[], int off, int len) {
+ if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) - b.length > 0)) {
+ throw new IndexOutOfBoundsException();
+ }
+ ensureCapacity(count + len);
+ System.arraycopy(b, off, buf, count, len);
+ count += len;
+ }
+
+ /**
+ * Writes the complete contents of this byte array output stream to
+ * the specified output stream argument, as if by calling the output
+ * stream's write method using <code>out.write(buf, 0, count)</code>.
+ *
+ * @param out the output stream to which to write the data.
+ * @exception IOException if an I/O error occurs.
+ */
+ public synchronized void writeTo(OutputStream out) throws IOException {
+ out.write(buf, 0, count);
+ }
+
+ /**
+ * Resets the <code>count</code> field of this byte array output
+ * stream to zero, so that all currently accumulated output in the
+ * output stream is discarded. The output stream can be used again,
+ * reusing the already allocated buffer space.
+ *
+ * @see java.io.ByteArrayInputStream#count
+ */
+ public synchronized void reset() {
+ count = 0;
+ }
+
+ /**
+ * Creates a newly allocated byte array. Its size is the current
+ * size of this output stream and the valid contents of the buffer
+ * have been copied into it.
+ *
+ * @return the current contents of this output stream, as a byte array.
+ * @see java.io.ByteArrayOutputStream#size()
+ */
+ public synchronized byte toByteArray()[] {
+ return Arrays.copyOf(buf, count);
+ }
+
+ /**
+ * Returns the current size of the buffer.
+ *
+ * @return the value of the <code>count</code> field, which is the number
+ * of valid bytes in this output stream.
+ * @see java.io.ByteArrayOutputStream#count
+ */
+ public synchronized int size() {
+ return count;
+ }
+
+ /**
+ * Converts the buffer's contents into a string decoding bytes using the
+ * platform's default character set. The length of the new <tt>String</tt>
+ * is a function of the character set, and hence may not be equal to the
+ * size of the buffer.
+ *
+ * <p> This method always replaces malformed-input and unmappable-character
+ * sequences with the default replacement string for the platform's
+ * default character set. The {@linkplain java.nio.charset.CharsetDecoder}
+ * class should be used when more control over the decoding process is
+ * required.
+ *
+ * @return String decoded from the buffer's contents.
+ * @since JDK1.1
+ */
+ public synchronized String toString() {
+ return new String(buf, 0, count);
+ }
+
+ /**
+ * Converts the buffer's contents into a string by decoding the bytes using
+ * the named {@link java.nio.charset.Charset charset}. The length of the new
+ * <tt>String</tt> is a function of the charset, and hence may not be equal
+ * to the length of the byte array.
+ *
+ * <p> This method always replaces malformed-input and unmappable-character
+ * sequences with this charset's default replacement string. The {@link
+ * java.nio.charset.CharsetDecoder} class should be used when more control
+ * over the decoding process is required.
+ *
+ * @param charsetName the name of a supported
+ * {@link java.nio.charset.Charset charset}
+ * @return String decoded from the buffer's contents.
+ * @exception UnsupportedEncodingException
+ * If the named charset is not supported
+ * @since JDK1.1
+ */
+ public synchronized String toString(String charsetName)
+ throws UnsupportedEncodingException
+ {
+ return new String(buf, 0, count, charsetName);
+ }
+
+ /**
+ * Creates a newly allocated string. Its size is the current size of
+ * the output stream and the valid contents of the buffer have been
+ * copied into it. Each character <i>c</i> in the resulting string is
+ * constructed from the corresponding element <i>b</i> in the byte
+ * array such that:
+ * <blockquote><pre>
+ * c == (char)(((hibyte & 0xff) << 8) | (b & 0xff))
+ * </pre></blockquote>
+ *
+ * @deprecated This method does not properly convert bytes into characters.
+ * As of JDK 1.1, the preferred way to do this is via the
+ * <code>toString(String enc)</code> method, which takes an encoding-name
+ * argument, or the <code>toString()</code> method, which uses the
+ * platform's default character encoding.
+ *
+ * @param hibyte the high byte of each resulting Unicode character.
+ * @return the current contents of the output stream, as a string.
+ * @see java.io.ByteArrayOutputStream#size()
+ * @see java.io.ByteArrayOutputStream#toString(String)
+ * @see java.io.ByteArrayOutputStream#toString()
+ */
+ @Deprecated
+ public synchronized String toString(int hibyte) {
+ return new String(buf, hibyte, 0, count);
+ }
+
+ /**
+ * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
+ * this class can be called after the stream has been closed without
+ * generating an <tt>IOException</tt>.
+ */
+ public void close() throws IOException {
+ }
+
+}
diff --git a/java/io/CharArrayReader.java b/java/io/CharArrayReader.java
new file mode 100644
index 0000000..4140976
--- /dev/null
+++ b/java/io/CharArrayReader.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This class implements a character buffer that can be used as a
+ * character-input stream.
+ *
+ * @author Herb Jellinek
+ * @since JDK1.1
+ */
+public class CharArrayReader extends Reader {
+ /** The character buffer. */
+ protected char buf[];
+
+ /** The current buffer position. */
+ protected int pos;
+
+ /** The position of mark in buffer. */
+ protected int markedPos = 0;
+
+ /**
+ * The index of the end of this buffer. There is not valid
+ * data at or beyond this index.
+ */
+ protected int count;
+
+ /**
+ * Creates a CharArrayReader from the specified array of chars.
+ * @param buf Input buffer (not copied)
+ */
+ public CharArrayReader(char buf[]) {
+ this.buf = buf;
+ this.pos = 0;
+ this.count = buf.length;
+ }
+
+ /**
+ * Creates a CharArrayReader from the specified array of chars.
+ *
+ * <p> The resulting reader will start reading at the given
+ * <tt>offset</tt>. The total number of <tt>char</tt> values that can be
+ * read from this reader will be either <tt>length</tt> or
+ * <tt>buf.length-offset</tt>, whichever is smaller.
+ *
+ * @throws IllegalArgumentException
+ * If <tt>offset</tt> is negative or greater than
+ * <tt>buf.length</tt>, or if <tt>length</tt> is negative, or if
+ * the sum of these two values is negative.
+ *
+ * @param buf Input buffer (not copied)
+ * @param offset Offset of the first char to read
+ * @param length Number of chars to read
+ */
+ public CharArrayReader(char buf[], int offset, int length) {
+ if ((offset < 0) || (offset > buf.length) || (length < 0) ||
+ ((offset + length) < 0)) {
+ throw new IllegalArgumentException();
+ }
+ this.buf = buf;
+ this.pos = offset;
+ this.count = Math.min(offset + length, buf.length);
+ this.markedPos = offset;
+ }
+
+ /** Checks to make sure that the stream has not been closed */
+ private void ensureOpen() throws IOException {
+ if (buf == null)
+ throw new IOException("Stream closed");
+ }
+
+ /**
+ * Reads a single character.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if (pos >= count)
+ return -1;
+ else
+ return buf[pos++];
+ }
+ }
+
+ /**
+ * Reads characters into a portion of an array.
+ * @param b Destination buffer
+ * @param off Offset at which to start storing characters
+ * @param len Maximum number of characters to read
+ * @return The actual number of characters read, or -1 if
+ * the end of the stream has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read(char b[], int off, int len) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) > b.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ if (pos >= count) {
+ return -1;
+ }
+ // BEGIN Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+ int avail = count - pos;
+ if (len > avail) {
+ len = avail;
+ }
+ // END Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+ if (len <= 0) {
+ return 0;
+ }
+ System.arraycopy(buf, pos, b, off, len);
+ pos += len;
+ return len;
+ }
+ }
+
+ /**
+ * Skips characters. Returns the number of characters that were skipped.
+ *
+ * <p>The <code>n</code> parameter may be negative, even though the
+ * <code>skip</code> method of the {@link Reader} superclass throws
+ * an exception in this case. If <code>n</code> is negative, then
+ * this method does nothing and returns <code>0</code>.
+ *
+ * @param n The number of characters to skip
+ * @return The number of characters actually skipped
+ * @exception IOException If the stream is closed, or an I/O error occurs
+ */
+ public long skip(long n) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ // BEGIN Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+ long avail = count - pos;
+ if (n > avail) {
+ n = avail;
+ }
+ // END Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+ if (n < 0) {
+ return 0;
+ }
+ pos += n;
+ return n;
+ }
+ }
+
+ /**
+ * Tells whether this stream is ready to be read. Character-array readers
+ * are always ready to be read.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public boolean ready() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ return (count - pos) > 0;
+ }
+ }
+
+ /**
+ * Tells whether this stream supports the mark() operation, which it does.
+ */
+ public boolean markSupported() {
+ return true;
+ }
+
+ /**
+ * Marks the present position in the stream. Subsequent calls to reset()
+ * will reposition the stream to this point.
+ *
+ * @param readAheadLimit Limit on the number of characters that may be
+ * read while still preserving the mark. Because
+ * the stream's input comes from a character array,
+ * there is no actual limit; hence this argument is
+ * ignored.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ markedPos = pos;
+ }
+ }
+
+ /**
+ * Resets the stream to the most recent mark, or to the beginning if it has
+ * never been marked.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void reset() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ pos = markedPos;
+ }
+ }
+
+ /**
+ * Closes the stream and releases any system resources associated with
+ * it. Once the stream has been closed, further read(), ready(),
+ * mark(), reset(), or skip() invocations will throw an IOException.
+ * Closing a previously closed stream has no effect.
+ */
+ public void close() {
+ buf = null;
+ }
+}
diff --git a/java/io/CharArrayWriter.java b/java/io/CharArrayWriter.java
new file mode 100644
index 0000000..56a5821
--- /dev/null
+++ b/java/io/CharArrayWriter.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.Arrays;
+
+/**
+ * This class implements a character buffer that can be used as an Writer.
+ * The buffer automatically grows when data is written to the stream. The data
+ * can be retrieved using toCharArray() and toString().
+ * <P>
+ * Note: Invoking close() on this class has no effect, and methods
+ * of this class can be called after the stream has closed
+ * without generating an IOException.
+ *
+ * @author Herb Jellinek
+ * @since JDK1.1
+ */
+public
+class CharArrayWriter extends Writer {
+ /**
+ * The buffer where data is stored.
+ */
+ protected char buf[];
+
+ /**
+ * The number of chars in the buffer.
+ */
+ protected int count;
+
+ /**
+ * Creates a new CharArrayWriter.
+ */
+ public CharArrayWriter() {
+ this(32);
+ }
+
+ /**
+ * Creates a new CharArrayWriter with the specified initial size.
+ *
+ * @param initialSize an int specifying the initial buffer size.
+ * @exception IllegalArgumentException if initialSize is negative
+ */
+ public CharArrayWriter(int initialSize) {
+ if (initialSize < 0) {
+ throw new IllegalArgumentException("Negative initial size: "
+ + initialSize);
+ }
+ buf = new char[initialSize];
+ }
+
+ /**
+ * Writes a character to the buffer.
+ */
+ public void write(int c) {
+ synchronized (lock) {
+ int newcount = count + 1;
+ if (newcount > buf.length) {
+ buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
+ }
+ buf[count] = (char)c;
+ count = newcount;
+ }
+ }
+
+ /**
+ * Writes characters to the buffer.
+ * @param c the data to be written
+ * @param off the start offset in the data
+ * @param len the number of chars that are written
+ */
+ public void write(char c[], int off, int len) {
+ if ((off < 0) || (off > c.length) || (len < 0) ||
+ ((off + len) > c.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+ synchronized (lock) {
+ int newcount = count + len;
+ if (newcount > buf.length) {
+ buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
+ }
+ System.arraycopy(c, off, buf, count, len);
+ count = newcount;
+ }
+ }
+
+ /**
+ * Write a portion of a string to the buffer.
+ * @param str String to be written from
+ * @param off Offset from which to start reading characters
+ * @param len Number of characters to be written
+ */
+ public void write(String str, int off, int len) {
+ synchronized (lock) {
+ int newcount = count + len;
+ if (newcount > buf.length) {
+ buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
+ }
+ str.getChars(off, off + len, buf, count);
+ count = newcount;
+ }
+ }
+
+ /**
+ * Writes the contents of the buffer to another character stream.
+ *
+ * @param out the output stream to write to
+ * @throws IOException If an I/O error occurs.
+ */
+ public void writeTo(Writer out) throws IOException {
+ synchronized (lock) {
+ out.write(buf, 0, count);
+ }
+ }
+
+ /**
+ * Appends the specified character sequence to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(csq.toString()) </pre>
+ *
+ * <p> Depending on the specification of <tt>toString</tt> for the
+ * character sequence <tt>csq</tt>, the entire sequence may not be
+ * appended. For instance, invoking the <tt>toString</tt> method of a
+ * character buffer will return a subsequence whose content depends upon
+ * the buffer's position and limit.
+ *
+ * @param csq
+ * The character sequence to append. If <tt>csq</tt> is
+ * <tt>null</tt>, then the four characters <tt>"null"</tt> are
+ * appended to this writer.
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public CharArrayWriter append(CharSequence csq) {
+ String s = (csq == null ? "null" : csq.toString());
+ write(s, 0, s.length());
+ return this;
+ }
+
+ /**
+ * Appends a subsequence of the specified character sequence to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(csq, start,
+ * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+ * exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(csq.subSequence(start, end).toString()) </pre>
+ *
+ * @param csq
+ * The character sequence from which a subsequence will be
+ * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
+ * will be appended as if <tt>csq</tt> contained the four
+ * characters <tt>"null"</tt>.
+ *
+ * @param start
+ * The index of the first character in the subsequence
+ *
+ * @param end
+ * The index of the character following the last character in the
+ * subsequence
+ *
+ * @return This writer
+ *
+ * @throws IndexOutOfBoundsException
+ * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+ * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+ * <tt>csq.length()</tt>
+ *
+ * @since 1.5
+ */
+ public CharArrayWriter append(CharSequence csq, int start, int end) {
+ String s = (csq == null ? "null" : csq).subSequence(start, end).toString();
+ write(s, 0, s.length());
+ return this;
+ }
+
+ /**
+ * Appends the specified character to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(c) </pre>
+ *
+ * @param c
+ * The 16-bit character to append
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public CharArrayWriter append(char c) {
+ write(c);
+ return this;
+ }
+
+ /**
+ * Resets the buffer so that you can use it again without
+ * throwing away the already allocated buffer.
+ */
+ public void reset() {
+ count = 0;
+ }
+
+ /**
+ * Returns a copy of the input data.
+ *
+ * @return an array of chars copied from the input data.
+ */
+ public char toCharArray()[] {
+ synchronized (lock) {
+ return Arrays.copyOf(buf, count);
+ }
+ }
+
+ /**
+ * Returns the current size of the buffer.
+ *
+ * @return an int representing the current size of the buffer.
+ */
+ public int size() {
+ return count;
+ }
+
+ /**
+ * Converts input data to a string.
+ * @return the string.
+ */
+ public String toString() {
+ synchronized (lock) {
+ return new String(buf, 0, count);
+ }
+ }
+
+ /**
+ * Flush the stream.
+ */
+ public void flush() { }
+
+ /**
+ * Close the stream. This method does not release the buffer, since its
+ * contents might still be required. Note: Invoking this method in this class
+ * will have no effect.
+ */
+ public void close() { }
+
+}
diff --git a/java/io/CharConversionException.java b/java/io/CharConversionException.java
new file mode 100644
index 0000000..ba79fe3
--- /dev/null
+++ b/java/io/CharConversionException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.io;
+
+/**
+ * Base class for character conversion exceptions.
+ *
+ * @author Asmus Freytag
+ * @since JDK1.1
+ */
+public class CharConversionException
+ extends java.io.IOException
+{
+ private static final long serialVersionUID = -8680016352018427031L;
+
+ /**
+ * This provides no detailed message.
+ */
+ public CharConversionException() {
+ }
+ /**
+ * This provides a detailed message.
+ *
+ * @param s the detailed message associated with the exception.
+ */
+ public CharConversionException(String s) {
+ super(s);
+ }
+}
diff --git a/java/io/Closeable.java b/java/io/Closeable.java
new file mode 100644
index 0000000..b4a1c81
--- /dev/null
+++ b/java/io/Closeable.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.IOException;
+
+/**
+ * A {@code Closeable} is a source or destination of data that can be closed.
+ * The close method is invoked to release resources that the object is
+ * holding (such as open files).
+ *
+ * @since 1.5
+ */
+public interface Closeable extends AutoCloseable {
+
+ /**
+ * Closes this stream and releases any system resources associated
+ * with it. If the stream is already closed then invoking this
+ * method has no effect.
+ *
+ * <p> As noted in {@link AutoCloseable#close()}, cases where the
+ * close may fail require careful attention. It is strongly advised
+ * to relinquish the underlying resources and to internally
+ * <em>mark</em> the {@code Closeable} as closed, prior to throwing
+ * the {@code IOException}.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ public void close() throws IOException;
+}
diff --git a/java/io/Console.java b/java/io/Console.java
new file mode 100644
index 0000000..b25759c
--- /dev/null
+++ b/java/io/Console.java
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.*;
+import java.nio.charset.Charset;
+import sun.nio.cs.StreamDecoder;
+import sun.nio.cs.StreamEncoder;
+
+/**
+ * Methods to access the character-based console device, if any, associated
+ * with the current Java virtual machine.
+ *
+ * <p> Whether a virtual machine has a console is dependent upon the
+ * underlying platform and also upon the manner in which the virtual
+ * machine is invoked. If the virtual machine is started from an
+ * interactive command line without redirecting the standard input and
+ * output streams then its console will exist and will typically be
+ * connected to the keyboard and display from which the virtual machine
+ * was launched. If the virtual machine is started automatically, for
+ * example by a background job scheduler, then it will typically not
+ * have a console.
+ * <p>
+ * If this virtual machine has a console then it is represented by a
+ * unique instance of this class which can be obtained by invoking the
+ * {@link java.lang.System#console()} method. If no console device is
+ * available then an invocation of that method will return <tt>null</tt>.
+ * <p>
+ * Read and write operations are synchronized to guarantee the atomic
+ * completion of critical operations; therefore invoking methods
+ * {@link #readLine()}, {@link #readPassword()}, {@link #format format()},
+ * {@link #printf printf()} as well as the read, format and write operations
+ * on the objects returned by {@link #reader()} and {@link #writer()} may
+ * block in multithreaded scenarios.
+ * <p>
+ * Invoking <tt>close()</tt> on the objects returned by the {@link #reader()}
+ * and the {@link #writer()} will not close the underlying stream of those
+ * objects.
+ * <p>
+ * The console-read methods return <tt>null</tt> when the end of the
+ * console input stream is reached, for example by typing control-D on
+ * Unix or control-Z on Windows. Subsequent read operations will succeed
+ * if additional characters are later entered on the console's input
+ * device.
+ * <p>
+ * Unless otherwise specified, passing a <tt>null</tt> argument to any method
+ * in this class will cause a {@link NullPointerException} to be thrown.
+ * <p>
+ * <b>Security note:</b>
+ * If an application needs to read a password or other secure data, it should
+ * use {@link #readPassword()} or {@link #readPassword(String, Object...)} and
+ * manually zero the returned character array after processing to minimize the
+ * lifetime of sensitive data in memory.
+ *
+ * <blockquote><pre>{@code
+ * Console cons;
+ * char[] passwd;
+ * if ((cons = System.console()) != null &&
+ * (passwd = cons.readPassword("[%s]", "Password:")) != null) {
+ * ...
+ * java.util.Arrays.fill(passwd, ' ');
+ * }
+ * }</pre></blockquote>
+ *
+ * @author Xueming Shen
+ * @since 1.6
+ */
+
+public final class Console implements Flushable
+{
+ /**
+ * Retrieves the unique {@link java.io.PrintWriter PrintWriter} object
+ * associated with this console.
+ *
+ * @return The printwriter associated with this console
+ */
+ public PrintWriter writer() {
+ return pw;
+ }
+
+ /**
+ * Retrieves the unique {@link java.io.Reader Reader} object associated
+ * with this console.
+ * <p>
+ * This method is intended to be used by sophisticated applications, for
+ * example, a {@link java.util.Scanner} object which utilizes the rich
+ * parsing/scanning functionality provided by the <tt>Scanner</tt>:
+ * <blockquote><pre>
+ * Console con = System.console();
+ * if (con != null) {
+ * Scanner sc = new Scanner(con.reader());
+ * ...
+ * }
+ * </pre></blockquote>
+ * <p>
+ * For simple applications requiring only line-oriented reading, use
+ * <tt>{@link #readLine}</tt>.
+ * <p>
+ * The bulk read operations {@link java.io.Reader#read(char[]) read(char[]) },
+ * {@link java.io.Reader#read(char[], int, int) read(char[], int, int) } and
+ * {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)}
+ * on the returned object will not read in characters beyond the line
+ * bound for each invocation, even if the destination buffer has space for
+ * more characters. The {@code Reader}'s {@code read} methods may block if a
+ * line bound has not been entered or reached on the console's input device.
+ * A line bound is considered to be any one of a line feed (<tt>'\n'</tt>),
+ * a carriage return (<tt>'\r'</tt>), a carriage return followed immediately
+ * by a linefeed, or an end of stream.
+ *
+ * @return The reader associated with this console
+ */
+ public Reader reader() {
+ return reader;
+ }
+
+ /**
+ * Writes a formatted string to this console's output stream using
+ * the specified format string and arguments.
+ *
+ * @param fmt
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The number of arguments is
+ * variable and may be zero. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ * The behaviour on a
+ * <tt>null</tt> argument depends on the <a
+ * href="../util/Formatter.html#syntax">conversion</a>.
+ *
+ * @throws IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a> section
+ * of the formatter class specification.
+ *
+ * @return This console
+ */
+ public Console format(String fmt, Object ...args) {
+ formatter.format(fmt, args).flush();
+ return this;
+ }
+
+ /**
+ * A convenience method to write a formatted string to this console's
+ * output stream using the specified format string and arguments.
+ *
+ * <p> An invocation of this method of the form <tt>con.printf(format,
+ * args)</tt> behaves in exactly the same way as the invocation of
+ * <pre>con.format(format, args)</pre>.
+ *
+ * @param format
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>.
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The number of arguments is
+ * variable and may be zero. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ * The behaviour on a
+ * <tt>null</tt> argument depends on the <a
+ * href="../util/Formatter.html#syntax">conversion</a>.
+ *
+ * @throws IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a> section of the
+ * formatter class specification.
+ *
+ * @return This console
+ */
+ public Console printf(String format, Object ... args) {
+ return format(format, args);
+ }
+
+ /**
+ * Provides a formatted prompt, then reads a single line of text from the
+ * console.
+ *
+ * @param fmt
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>.
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ *
+ * @throws IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a> section
+ * of the formatter class specification.
+ *
+ * @throws IOError
+ * If an I/O error occurs.
+ *
+ * @return A string containing the line read from the console, not
+ * including any line-termination characters, or <tt>null</tt>
+ * if an end of stream has been reached.
+ */
+ public String readLine(String fmt, Object ... args) {
+ String line = null;
+ synchronized (writeLock) {
+ synchronized(readLock) {
+ if (fmt.length() != 0)
+ pw.format(fmt, args);
+ try {
+ char[] ca = readline(false);
+ if (ca != null)
+ line = new String(ca);
+ } catch (IOException x) {
+ throw new IOError(x);
+ }
+ }
+ }
+ return line;
+ }
+
+ /**
+ * Reads a single line of text from the console.
+ *
+ * @throws IOError
+ * If an I/O error occurs.
+ *
+ * @return A string containing the line read from the console, not
+ * including any line-termination characters, or <tt>null</tt>
+ * if an end of stream has been reached.
+ */
+ public String readLine() {
+ return readLine("");
+ }
+
+ /**
+ * Provides a formatted prompt, then reads a password or passphrase from
+ * the console with echoing disabled.
+ *
+ * @param fmt
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>
+ * for the prompt text.
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ *
+ * @throws IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a>
+ * section of the formatter class specification.
+ *
+ * @throws IOError
+ * If an I/O error occurs.
+ *
+ * @return A character array containing the password or passphrase read
+ * from the console, not including any line-termination characters,
+ * or <tt>null</tt> if an end of stream has been reached.
+ */
+ public char[] readPassword(String fmt, Object ... args) {
+ char[] passwd = null;
+ synchronized (writeLock) {
+ synchronized(readLock) {
+ try {
+ echoOff = echo(false);
+ } catch (IOException x) {
+ throw new IOError(x);
+ }
+ IOError ioe = null;
+ try {
+ if (fmt.length() != 0)
+ pw.format(fmt, args);
+ passwd = readline(true);
+ } catch (IOException x) {
+ ioe = new IOError(x);
+ } finally {
+ try {
+ echoOff = echo(true);
+ } catch (IOException x) {
+ if (ioe == null)
+ ioe = new IOError(x);
+ else
+ ioe.addSuppressed(x);
+ }
+ if (ioe != null)
+ throw ioe;
+ }
+ pw.println();
+ }
+ }
+ return passwd;
+ }
+
+ /**
+ * Reads a password or passphrase from the console with echoing disabled
+ *
+ * @throws IOError
+ * If an I/O error occurs.
+ *
+ * @return A character array containing the password or passphrase read
+ * from the console, not including any line-termination characters,
+ * or <tt>null</tt> if an end of stream has been reached.
+ */
+ public char[] readPassword() {
+ return readPassword("");
+ }
+
+ /**
+ * Flushes the console and forces any buffered output to be written
+ * immediately .
+ */
+ public void flush() {
+ pw.flush();
+ }
+
+ private Object readLock;
+ private Object writeLock;
+ private Reader reader;
+ private Writer out;
+ private PrintWriter pw;
+ private Formatter formatter;
+ private Charset cs;
+ private char[] rcb;
+ private static native String encoding();
+ private static native boolean echo(boolean on) throws IOException;
+ private static boolean echoOff;
+
+ private char[] readline(boolean zeroOut) throws IOException {
+ int len = reader.read(rcb, 0, rcb.length);
+ if (len < 0)
+ return null; //EOL
+ if (rcb[len-1] == '\r')
+ len--; //remove CR at end;
+ else if (rcb[len-1] == '\n') {
+ len--; //remove LF at end;
+ if (len > 0 && rcb[len-1] == '\r')
+ len--; //remove the CR, if there is one
+ }
+ char[] b = new char[len];
+ if (len > 0) {
+ System.arraycopy(rcb, 0, b, 0, len);
+ if (zeroOut) {
+ Arrays.fill(rcb, 0, len, ' ');
+ }
+ }
+ return b;
+ }
+
+ private char[] grow() {
+ assert Thread.holdsLock(readLock);
+ char[] t = new char[rcb.length * 2];
+ System.arraycopy(rcb, 0, t, 0, rcb.length);
+ rcb = t;
+ return rcb;
+ }
+
+ class LineReader extends Reader {
+ private Reader in;
+ private char[] cb;
+ private int nChars, nextChar;
+ boolean leftoverLF;
+ LineReader(Reader in) {
+ this.in = in;
+ cb = new char[1024];
+ nextChar = nChars = 0;
+ leftoverLF = false;
+ }
+ public void close () {}
+ public boolean ready() throws IOException {
+ //in.ready synchronizes on readLock already
+ return in.ready();
+ }
+
+ public int read(char cbuf[], int offset, int length)
+ throws IOException
+ {
+ int off = offset;
+ int end = offset + length;
+ if (offset < 0 || offset > cbuf.length || length < 0 ||
+ end < 0 || end > cbuf.length) {
+ throw new IndexOutOfBoundsException();
+ }
+ synchronized(readLock) {
+ boolean eof = false;
+ char c = 0;
+ for (;;) {
+ if (nextChar >= nChars) { //fill
+ int n = 0;
+ do {
+ n = in.read(cb, 0, cb.length);
+ } while (n == 0);
+ if (n > 0) {
+ nChars = n;
+ nextChar = 0;
+ if (n < cb.length &&
+ cb[n-1] != '\n' && cb[n-1] != '\r') {
+ /*
+ * we're in canonical mode so each "fill" should
+ * come back with an eol. if there no lf or nl at
+ * the end of returned bytes we reached an eof.
+ */
+ eof = true;
+ }
+ } else { /*EOF*/
+ if (off - offset == 0)
+ return -1;
+ return off - offset;
+ }
+ }
+ if (leftoverLF && cbuf == rcb && cb[nextChar] == '\n') {
+ /*
+ * if invoked by our readline, skip the leftover, otherwise
+ * return the LF.
+ */
+ nextChar++;
+ }
+ leftoverLF = false;
+ while (nextChar < nChars) {
+ c = cbuf[off++] = cb[nextChar];
+ cb[nextChar++] = 0;
+ if (c == '\n') {
+ return off - offset;
+ } else if (c == '\r') {
+ if (off == end) {
+ /* no space left even the next is LF, so return
+ * whatever we have if the invoker is not our
+ * readLine()
+ */
+ if (cbuf == rcb) {
+ cbuf = grow();
+ end = cbuf.length;
+ } else {
+ leftoverLF = true;
+ return off - offset;
+ }
+ }
+ if (nextChar == nChars && in.ready()) {
+ /*
+ * we have a CR and we reached the end of
+ * the read in buffer, fill to make sure we
+ * don't miss a LF, if there is one, it's possible
+ * that it got cut off during last round reading
+ * simply because the read in buffer was full.
+ */
+ nChars = in.read(cb, 0, cb.length);
+ nextChar = 0;
+ }
+ if (nextChar < nChars && cb[nextChar] == '\n') {
+ cbuf[off++] = '\n';
+ nextChar++;
+ }
+ return off - offset;
+ } else if (off == end) {
+ if (cbuf == rcb) {
+ cbuf = grow();
+ end = cbuf.length;
+ } else {
+ return off - offset;
+ }
+ }
+ }
+ if (eof)
+ return off - offset;
+ }
+ }
+ }
+ }
+
+ // Android-removed: SharedSecrets setup and also the shutdown hook.
+ // The hook is a no-op (but causes trouble when it's turned on).
+
+ // Android-changed: Use @hide rather than sun.misc.SharedSecrets to expose console().
+ /** @hide */
+ public static Console console() {
+ if (istty()) {
+ if (cons == null)
+ cons = new Console();
+ return cons;
+ }
+ return null;
+ }
+ private static Console cons;
+ private native static boolean istty();
+ private Console() {
+ // BEGIN Android-changed: Support custom in/out streams for testing.
+ this(new FileInputStream(FileDescriptor.in), new FileOutputStream(FileDescriptor.out));
+ }
+
+ // Constructor for tests
+ private Console(InputStream inStream, OutputStream outStream) {
+ // END Android-changed: Support custom in/out streams for testing.
+ readLock = new Object();
+ writeLock = new Object();
+ String csname = encoding();
+ if (csname != null) {
+ try {
+ cs = Charset.forName(csname);
+ } catch (Exception x) {}
+ }
+ if (cs == null)
+ cs = Charset.defaultCharset();
+ out = StreamEncoder.forOutputStreamWriter(
+ outStream,
+ writeLock,
+ cs);
+ pw = new PrintWriter(out, true) { public void close() {} };
+ formatter = new Formatter(out);
+ reader = new LineReader(StreamDecoder.forInputStreamReader(
+ inStream,
+ readLock,
+ cs));
+ rcb = new char[1024];
+ }
+}
diff --git a/java/io/DataInput.java b/java/io/DataInput.java
new file mode 100644
index 0000000..3e0f0dd
--- /dev/null
+++ b/java/io/DataInput.java
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * The {@code DataInput} interface provides
+ * for reading bytes from a binary stream and
+ * reconstructing from them data in any of
+ * the Java primitive types. There is also
+ * a
+ * facility for reconstructing a {@code String}
+ * from data in
+ * <a href="#modified-utf-8">modified UTF-8</a>
+ * format.
+ * <p>
+ * It is generally true of all the reading
+ * routines in this interface that if end of
+ * file is reached before the desired number
+ * of bytes has been read, an {@code EOFException}
+ * (which is a kind of {@code IOException})
+ * is thrown. If any byte cannot be read for
+ * any reason other than end of file, an {@code IOException}
+ * other than {@code EOFException} is
+ * thrown. In particular, an {@code IOException}
+ * may be thrown if the input stream has been
+ * closed.
+ *
+ * <h3><a name="modified-utf-8">Modified UTF-8</a></h3>
+ * <p>
+ * Implementations of the DataInput and DataOutput interfaces represent
+ * Unicode strings in a format that is a slight modification of UTF-8.
+ * (For information regarding the standard UTF-8 format, see section
+ * <i>3.9 Unicode Encoding Forms</i> of <i>The Unicode Standard, Version
+ * 4.0</i>).
+ * Note that in the following table, the most significant bit appears in the
+ * far left-hand column.
+ *
+ * <blockquote>
+ * <table border="1" cellspacing="0" cellpadding="8"
+ * summary="Bit values and bytes">
+ * <tr>
+ * <th colspan="9"><span style="font-weight:normal">
+ * All characters in the range {@code '\u005Cu0001'} to
+ * {@code '\u005Cu007F'} are represented by a single byte:</span></th>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <th colspan="8" id="bit_a">Bit Values</th>
+ * </tr>
+ * <tr>
+ * <th id="byte1_a">Byte 1</th>
+ * <td><center>0</center>
+ * <td colspan="7"><center>bits 6-0</center>
+ * </tr>
+ * <tr>
+ * <th colspan="9"><span style="font-weight:normal">
+ * The null character {@code '\u005Cu0000'} and characters
+ * in the range {@code '\u005Cu0080'} to {@code '\u005Cu07FF'} are
+ * represented by a pair of bytes:</span></th>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <th colspan="8" id="bit_b">Bit Values</th>
+ * </tr>
+ * <tr>
+ * <th id="byte1_b">Byte 1</th>
+ * <td><center>1</center>
+ * <td><center>1</center>
+ * <td><center>0</center>
+ * <td colspan="5"><center>bits 10-6</center>
+ * </tr>
+ * <tr>
+ * <th id="byte2_a">Byte 2</th>
+ * <td><center>1</center>
+ * <td><center>0</center>
+ * <td colspan="6"><center>bits 5-0</center>
+ * </tr>
+ * <tr>
+ * <th colspan="9"><span style="font-weight:normal">
+ * {@code char} values in the range {@code '\u005Cu0800'}
+ * to {@code '\u005CuFFFF'} are represented by three bytes:</span></th>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <th colspan="8"id="bit_c">Bit Values</th>
+ * </tr>
+ * <tr>
+ * <th id="byte1_c">Byte 1</th>
+ * <td><center>1</center>
+ * <td><center>1</center>
+ * <td><center>1</center>
+ * <td><center>0</center>
+ * <td colspan="4"><center>bits 15-12</center>
+ * </tr>
+ * <tr>
+ * <th id="byte2_b">Byte 2</th>
+ * <td><center>1</center>
+ * <td><center>0</center>
+ * <td colspan="6"><center>bits 11-6</center>
+ * </tr>
+ * <tr>
+ * <th id="byte3">Byte 3</th>
+ * <td><center>1</center>
+ * <td><center>0</center>
+ * <td colspan="6"><center>bits 5-0</center>
+ * </tr>
+ * </table>
+ * </blockquote>
+ * <p>
+ * The differences between this format and the
+ * standard UTF-8 format are the following:
+ * <ul>
+ * <li>The null byte {@code '\u005Cu0000'} is encoded in 2-byte format
+ * rather than 1-byte, so that the encoded strings never have
+ * embedded nulls.
+ * <li>Only the 1-byte, 2-byte, and 3-byte formats are used.
+ * <li><a href="../lang/Character.html#unicode">Supplementary characters</a>
+ * are represented in the form of surrogate pairs.
+ * </ul>
+ * @author Frank Yellin
+ * @see java.io.DataInputStream
+ * @see java.io.DataOutput
+ * @since JDK1.0
+ */
+public
+interface DataInput {
+ /**
+ * Reads some bytes from an input
+ * stream and stores them into the buffer
+ * array {@code b}. The number of bytes
+ * read is equal
+ * to the length of {@code b}.
+ * <p>
+ * This method blocks until one of the
+ * following conditions occurs:
+ * <ul>
+ * <li>{@code b.length}
+ * bytes of input data are available, in which
+ * case a normal return is made.
+ *
+ * <li>End of
+ * file is detected, in which case an {@code EOFException}
+ * is thrown.
+ *
+ * <li>An I/O error occurs, in
+ * which case an {@code IOException} other
+ * than {@code EOFException} is thrown.
+ * </ul>
+ * <p>
+ * If {@code b} is {@code null},
+ * a {@code NullPointerException} is thrown.
+ * If {@code b.length} is zero, then
+ * no bytes are read. Otherwise, the first
+ * byte read is stored into element {@code b[0]},
+ * the next one into {@code b[1]}, and
+ * so on.
+ * If an exception is thrown from
+ * this method, then it may be that some but
+ * not all bytes of {@code b} have been
+ * updated with data from the input stream.
+ *
+ * @param b the buffer into which the data is read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ void readFully(byte b[]) throws IOException;
+
+ /**
+ *
+ * Reads {@code len}
+ * bytes from
+ * an input stream.
+ * <p>
+ * This method
+ * blocks until one of the following conditions
+ * occurs:
+ * <ul>
+ * <li>{@code len} bytes
+ * of input data are available, in which case
+ * a normal return is made.
+ *
+ * <li>End of file
+ * is detected, in which case an {@code EOFException}
+ * is thrown.
+ *
+ * <li>An I/O error occurs, in
+ * which case an {@code IOException} other
+ * than {@code EOFException} is thrown.
+ * </ul>
+ * <p>
+ * If {@code b} is {@code null},
+ * a {@code NullPointerException} is thrown.
+ * If {@code off} is negative, or {@code len}
+ * is negative, or {@code off+len} is
+ * greater than the length of the array {@code b},
+ * then an {@code IndexOutOfBoundsException}
+ * is thrown.
+ * If {@code len} is zero,
+ * then no bytes are read. Otherwise, the first
+ * byte read is stored into element {@code b[off]},
+ * the next one into {@code b[off+1]},
+ * and so on. The number of bytes read is,
+ * at most, equal to {@code len}.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off an int specifying the offset into the data.
+ * @param len an int specifying the number of bytes to read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ void readFully(byte b[], int off, int len) throws IOException;
+
+ /**
+ * Makes an attempt to skip over
+ * {@code n} bytes
+ * of data from the input
+ * stream, discarding the skipped bytes. However,
+ * it may skip
+ * over some smaller number of
+ * bytes, possibly zero. This may result from
+ * any of a
+ * number of conditions; reaching
+ * end of file before {@code n} bytes
+ * have been skipped is
+ * only one possibility.
+ * This method never throws an {@code EOFException}.
+ * The actual
+ * number of bytes skipped is returned.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the number of bytes actually skipped.
+ * @exception IOException if an I/O error occurs.
+ */
+ int skipBytes(int n) throws IOException;
+
+ /**
+ * Reads one input byte and returns
+ * {@code true} if that byte is nonzero,
+ * {@code false} if that byte is zero.
+ * This method is suitable for reading
+ * the byte written by the {@code writeBoolean}
+ * method of interface {@code DataOutput}.
+ *
+ * @return the {@code boolean} value read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ boolean readBoolean() throws IOException;
+
+ /**
+ * Reads and returns one input byte.
+ * The byte is treated as a signed value in
+ * the range {@code -128} through {@code 127},
+ * inclusive.
+ * This method is suitable for
+ * reading the byte written by the {@code writeByte}
+ * method of interface {@code DataOutput}.
+ *
+ * @return the 8-bit value read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ byte readByte() throws IOException;
+
+ /**
+ * Reads one input byte, zero-extends
+ * it to type {@code int}, and returns
+ * the result, which is therefore in the range
+ * {@code 0}
+ * through {@code 255}.
+ * This method is suitable for reading
+ * the byte written by the {@code writeByte}
+ * method of interface {@code DataOutput}
+ * if the argument to {@code writeByte}
+ * was intended to be a value in the range
+ * {@code 0} through {@code 255}.
+ *
+ * @return the unsigned 8-bit value read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ int readUnsignedByte() throws IOException;
+
+ /**
+ * Reads two input bytes and returns
+ * a {@code short} value. Let {@code a}
+ * be the first byte read and {@code b}
+ * be the second byte. The value
+ * returned
+ * is:
+ * <pre>{@code (short)((a << 8) | (b & 0xff))
+ * }</pre>
+ * This method
+ * is suitable for reading the bytes written
+ * by the {@code writeShort} method of
+ * interface {@code DataOutput}.
+ *
+ * @return the 16-bit value read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ short readShort() throws IOException;
+
+ /**
+ * Reads two input bytes and returns
+ * an {@code int} value in the range {@code 0}
+ * through {@code 65535}. Let {@code a}
+ * be the first byte read and
+ * {@code b}
+ * be the second byte. The value returned is:
+ * <pre>{@code (((a & 0xff) << 8) | (b & 0xff))
+ * }</pre>
+ * This method is suitable for reading the bytes
+ * written by the {@code writeShort} method
+ * of interface {@code DataOutput} if
+ * the argument to {@code writeShort}
+ * was intended to be a value in the range
+ * {@code 0} through {@code 65535}.
+ *
+ * @return the unsigned 16-bit value read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ int readUnsignedShort() throws IOException;
+
+ /**
+ * Reads two input bytes and returns a {@code char} value.
+ * Let {@code a}
+ * be the first byte read and {@code b}
+ * be the second byte. The value
+ * returned is:
+ * <pre>{@code (char)((a << 8) | (b & 0xff))
+ * }</pre>
+ * This method
+ * is suitable for reading bytes written by
+ * the {@code writeChar} method of interface
+ * {@code DataOutput}.
+ *
+ * @return the {@code char} value read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ char readChar() throws IOException;
+
+ /**
+ * Reads four input bytes and returns an
+ * {@code int} value. Let {@code a-d}
+ * be the first through fourth bytes read. The value returned is:
+ * <pre>{@code
+ * (((a & 0xff) << 24) | ((b & 0xff) << 16) |
+ * ((c & 0xff) << 8) | (d & 0xff))
+ * }</pre>
+ * This method is suitable
+ * for reading bytes written by the {@code writeInt}
+ * method of interface {@code DataOutput}.
+ *
+ * @return the {@code int} value read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ int readInt() throws IOException;
+
+ /**
+ * Reads eight input bytes and returns
+ * a {@code long} value. Let {@code a-h}
+ * be the first through eighth bytes read.
+ * The value returned is:
+ * <pre>{@code
+ * (((long)(a & 0xff) << 56) |
+ * ((long)(b & 0xff) << 48) |
+ * ((long)(c & 0xff) << 40) |
+ * ((long)(d & 0xff) << 32) |
+ * ((long)(e & 0xff) << 24) |
+ * ((long)(f & 0xff) << 16) |
+ * ((long)(g & 0xff) << 8) |
+ * ((long)(h & 0xff)))
+ * }</pre>
+ * <p>
+ * This method is suitable
+ * for reading bytes written by the {@code writeLong}
+ * method of interface {@code DataOutput}.
+ *
+ * @return the {@code long} value read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ long readLong() throws IOException;
+
+ /**
+ * Reads four input bytes and returns
+ * a {@code float} value. It does this
+ * by first constructing an {@code int}
+ * value in exactly the manner
+ * of the {@code readInt}
+ * method, then converting this {@code int}
+ * value to a {@code float} in
+ * exactly the manner of the method {@code Float.intBitsToFloat}.
+ * This method is suitable for reading
+ * bytes written by the {@code writeFloat}
+ * method of interface {@code DataOutput}.
+ *
+ * @return the {@code float} value read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ float readFloat() throws IOException;
+
+ /**
+ * Reads eight input bytes and returns
+ * a {@code double} value. It does this
+ * by first constructing a {@code long}
+ * value in exactly the manner
+ * of the {@code readLong}
+ * method, then converting this {@code long}
+ * value to a {@code double} in exactly
+ * the manner of the method {@code Double.longBitsToDouble}.
+ * This method is suitable for reading
+ * bytes written by the {@code writeDouble}
+ * method of interface {@code DataOutput}.
+ *
+ * @return the {@code double} value read.
+ * @exception EOFException if this stream reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ double readDouble() throws IOException;
+
+ /**
+ * Reads the next line of text from the input stream.
+ * It reads successive bytes, converting
+ * each byte separately into a character,
+ * until it encounters a line terminator or
+ * end of
+ * file; the characters read are then
+ * returned as a {@code String}. Note
+ * that because this
+ * method processes bytes,
+ * it does not support input of the full Unicode
+ * character set.
+ * <p>
+ * If end of file is encountered
+ * before even one byte can be read, then {@code null}
+ * is returned. Otherwise, each byte that is
+ * read is converted to type {@code char}
+ * by zero-extension. If the character {@code '\n'}
+ * is encountered, it is discarded and reading
+ * ceases. If the character {@code '\r'}
+ * is encountered, it is discarded and, if
+ * the following byte converts  to the
+ * character {@code '\n'}, then that is
+ * discarded also; reading then ceases. If
+ * end of file is encountered before either
+ * of the characters {@code '\n'} and
+ * {@code '\r'} is encountered, reading
+ * ceases. Once reading has ceased, a {@code String}
+ * is returned that contains all the characters
+ * read and not discarded, taken in order.
+ * Note that every character in this string
+ * will have a value less than {@code \u005Cu0100},
+ * that is, {@code (char)256}.
+ *
+ * @return the next line of text from the input stream,
+ * or {@code null} if the end of file is
+ * encountered before a byte can be read.
+ * @exception IOException if an I/O error occurs.
+ */
+ String readLine() throws IOException;
+
+ /**
+ * Reads in a string that has been encoded using a
+ * <a href="#modified-utf-8">modified UTF-8</a>
+ * format.
+ * The general contract of {@code readUTF}
+ * is that it reads a representation of a Unicode
+ * character string encoded in modified
+ * UTF-8 format; this string of characters
+ * is then returned as a {@code String}.
+ * <p>
+ * First, two bytes are read and used to
+ * construct an unsigned 16-bit integer in
+ * exactly the manner of the {@code readUnsignedShort}
+ * method . This integer value is called the
+ * <i>UTF length</i> and specifies the number
+ * of additional bytes to be read. These bytes
+ * are then converted to characters by considering
+ * them in groups. The length of each group
+ * is computed from the value of the first
+ * byte of the group. The byte following a
+ * group, if any, is the first byte of the
+ * next group.
+ * <p>
+ * If the first byte of a group
+ * matches the bit pattern {@code 0xxxxxxx}
+ * (where {@code x} means "may be {@code 0}
+ * or {@code 1}"), then the group consists
+ * of just that byte. The byte is zero-extended
+ * to form a character.
+ * <p>
+ * If the first byte
+ * of a group matches the bit pattern {@code 110xxxxx},
+ * then the group consists of that byte {@code a}
+ * and a second byte {@code b}. If there
+ * is no byte {@code b} (because byte
+ * {@code a} was the last of the bytes
+ * to be read), or if byte {@code b} does
+ * not match the bit pattern {@code 10xxxxxx},
+ * then a {@code UTFDataFormatException}
+ * is thrown. Otherwise, the group is converted
+ * to the character:
+ * <pre>{@code (char)(((a & 0x1F) << 6) | (b & 0x3F))
+ * }</pre>
+ * If the first byte of a group
+ * matches the bit pattern {@code 1110xxxx},
+ * then the group consists of that byte {@code a}
+ * and two more bytes {@code b} and {@code c}.
+ * If there is no byte {@code c} (because
+ * byte {@code a} was one of the last
+ * two of the bytes to be read), or either
+ * byte {@code b} or byte {@code c}
+ * does not match the bit pattern {@code 10xxxxxx},
+ * then a {@code UTFDataFormatException}
+ * is thrown. Otherwise, the group is converted
+ * to the character:
+ * <pre>{@code
+ * (char)(((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F))
+ * }</pre>
+ * If the first byte of a group matches the
+ * pattern {@code 1111xxxx} or the pattern
+ * {@code 10xxxxxx}, then a {@code UTFDataFormatException}
+ * is thrown.
+ * <p>
+ * If end of file is encountered
+ * at any time during this entire process,
+ * then an {@code EOFException} is thrown.
+ * <p>
+ * After every group has been converted to
+ * a character by this process, the characters
+ * are gathered, in the same order in which
+ * their corresponding groups were read from
+ * the input stream, to form a {@code String},
+ * which is returned.
+ * <p>
+ * The {@code writeUTF}
+ * method of interface {@code DataOutput}
+ * may be used to write data that is suitable
+ * for reading by this method.
+ * @return a Unicode string.
+ * @exception EOFException if this stream reaches the end
+ * before reading all the bytes.
+ * @exception IOException if an I/O error occurs.
+ * @exception UTFDataFormatException if the bytes do not represent a
+ * valid modified UTF-8 encoding of a string.
+ */
+ String readUTF() throws IOException;
+}
diff --git a/java/io/DataInputStream.java b/java/io/DataInputStream.java
new file mode 100644
index 0000000..19d4067
--- /dev/null
+++ b/java/io/DataInputStream.java
@@ -0,0 +1,660 @@
+/*
+ * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.nio.ByteOrder;
+import libcore.io.Memory;
+
+/**
+ * A data input stream lets an application read primitive Java data
+ * types from an underlying input stream in a machine-independent
+ * way. An application uses a data output stream to write data that
+ * can later be read by a data input stream.
+ * <p>
+ * DataInputStream is not necessarily safe for multithreaded access.
+ * Thread safety is optional and is the responsibility of users of
+ * methods in this class.
+ *
+ * @author Arthur van Hoff
+ * @see java.io.DataOutputStream
+ * @since JDK1.0
+ */
+public
+class DataInputStream extends FilterInputStream implements DataInput {
+
+ /**
+ * Creates a DataInputStream that uses the specified
+ * underlying InputStream.
+ *
+ * @param in the specified input stream
+ */
+ public DataInputStream(InputStream in) {
+ super(in);
+ }
+
+ /**
+ * working arrays initialized on demand by readUTF
+ */
+ private byte bytearr[] = new byte[80];
+ private char chararr[] = new char[80];
+
+ /**
+ * Reads some number of bytes from the contained input stream and
+ * stores them into the buffer array <code>b</code>. The number of
+ * bytes actually read is returned as an integer. This method blocks
+ * until input data is available, end of file is detected, or an
+ * exception is thrown.
+ *
+ * <p>If <code>b</code> is null, a <code>NullPointerException</code> is
+ * thrown. If the length of <code>b</code> is zero, then no bytes are
+ * read and <code>0</code> is returned; otherwise, there is an attempt
+ * to read at least one byte. If no byte is available because the
+ * stream is at end of file, the value <code>-1</code> is returned;
+ * otherwise, at least one byte is read and stored into <code>b</code>.
+ *
+ * <p>The first byte read is stored into element <code>b[0]</code>, the
+ * next one into <code>b[1]</code>, and so on. The number of bytes read
+ * is, at most, equal to the length of <code>b</code>. Let <code>k</code>
+ * be the number of bytes actually read; these bytes will be stored in
+ * elements <code>b[0]</code> through <code>b[k-1]</code>, leaving
+ * elements <code>b[k]</code> through <code>b[b.length-1]</code>
+ * unaffected.
+ *
+ * <p>The <code>read(b)</code> method has the same effect as:
+ * <blockquote><pre>
+ * read(b, 0, b.length)
+ * </pre></blockquote>
+ *
+ * @param b the buffer into which the data is read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end
+ * of the stream has been reached.
+ * @exception IOException if the first byte cannot be read for any reason
+ * other than end of file, the stream has been closed and the underlying
+ * input stream does not support reading after close, or another I/O
+ * error occurs.
+ * @see java.io.FilterInputStream#in
+ * @see java.io.InputStream#read(byte[], int, int)
+ */
+ public final int read(byte b[]) throws IOException {
+ return in.read(b, 0, b.length);
+ }
+
+ /**
+ * Reads up to <code>len</code> bytes of data from the contained
+ * input stream into an array of bytes. An attempt is made to read
+ * as many as <code>len</code> bytes, but a smaller number may be read,
+ * possibly zero. The number of bytes actually read is returned as an
+ * integer.
+ *
+ * <p> This method blocks until input data is available, end of file is
+ * detected, or an exception is thrown.
+ *
+ * <p> If <code>len</code> is zero, then no bytes are read and
+ * <code>0</code> is returned; otherwise, there is an attempt to read at
+ * least one byte. If no byte is available because the stream is at end of
+ * file, the value <code>-1</code> is returned; otherwise, at least one
+ * byte is read and stored into <code>b</code>.
+ *
+ * <p> The first byte read is stored into element <code>b[off]</code>, the
+ * next one into <code>b[off+1]</code>, and so on. The number of bytes read
+ * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
+ * bytes actually read; these bytes will be stored in elements
+ * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
+ * leaving elements <code>b[off+</code><i>k</i><code>]</code> through
+ * <code>b[off+len-1]</code> unaffected.
+ *
+ * <p> In every case, elements <code>b[0]</code> through
+ * <code>b[off]</code> and elements <code>b[off+len]</code> through
+ * <code>b[b.length-1]</code> are unaffected.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in the destination array <code>b</code>
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end
+ * of the stream has been reached.
+ * @exception NullPointerException If <code>b</code> is <code>null</code>.
+ * @exception IndexOutOfBoundsException If <code>off</code> is negative,
+ * <code>len</code> is negative, or <code>len</code> is greater than
+ * <code>b.length - off</code>
+ * @exception IOException if the first byte cannot be read for any reason
+ * other than end of file, the stream has been closed and the underlying
+ * input stream does not support reading after close, or another I/O
+ * error occurs.
+ * @see java.io.FilterInputStream#in
+ * @see java.io.InputStream#read(byte[], int, int)
+ */
+ public final int read(byte b[], int off, int len) throws IOException {
+ return in.read(b, off, len);
+ }
+
+ /**
+ * See the general contract of the <code>readFully</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @param b the buffer into which the data is read.
+ * @exception EOFException if this input stream reaches the end before
+ * reading all the bytes.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public final void readFully(byte b[]) throws IOException {
+ readFully(b, 0, b.length);
+ }
+
+ /**
+ * See the general contract of the <code>readFully</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset of the data.
+ * @param len the number of bytes to read.
+ * @exception EOFException if this input stream reaches the end before
+ * reading all the bytes.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public final void readFully(byte b[], int off, int len) throws IOException {
+ if (len < 0)
+ throw new IndexOutOfBoundsException();
+ int n = 0;
+ while (n < len) {
+ int count = in.read(b, off + n, len - n);
+ if (count < 0)
+ throw new EOFException();
+ n += count;
+ }
+ }
+
+ /**
+ * See the general contract of the <code>skipBytes</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes for this operation are read from the contained
+ * input stream.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the actual number of bytes skipped.
+ * @exception IOException if the contained input stream does not support
+ * seek, or the stream has been closed and
+ * the contained input stream does not support
+ * reading after close, or another I/O error occurs.
+ */
+ public final int skipBytes(int n) throws IOException {
+ int total = 0;
+ int cur = 0;
+
+ while ((total<n) && ((cur = (int) in.skip(n-total)) > 0)) {
+ total += cur;
+ }
+
+ return total;
+ }
+
+ /**
+ * See the general contract of the <code>readBoolean</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes for this operation are read from the contained
+ * input stream.
+ *
+ * @return the <code>boolean</code> value read.
+ * @exception EOFException if this input stream has reached the end.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public final boolean readBoolean() throws IOException {
+ int ch = in.read();
+ if (ch < 0)
+ throw new EOFException();
+ return (ch != 0);
+ }
+
+ /**
+ * See the general contract of the <code>readByte</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next byte of this input stream as a signed 8-bit
+ * <code>byte</code>.
+ * @exception EOFException if this input stream has reached the end.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public final byte readByte() throws IOException {
+ int ch = in.read();
+ if (ch < 0)
+ throw new EOFException();
+ return (byte)(ch);
+ }
+
+ /**
+ * See the general contract of the <code>readUnsignedByte</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next byte of this input stream, interpreted as an
+ * unsigned 8-bit number.
+ * @exception EOFException if this input stream has reached the end.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public final int readUnsignedByte() throws IOException {
+ int ch = in.read();
+ if (ch < 0)
+ throw new EOFException();
+ return ch;
+ }
+
+ /**
+ * See the general contract of the <code>readShort</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next two bytes of this input stream, interpreted as a
+ * signed 16-bit number.
+ * @exception EOFException if this input stream reaches the end before
+ * reading two bytes.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public final short readShort() throws IOException {
+ // b/30268192
+ // Android-changed: Use read(byte[], int, int) instead of read().
+ readFully(readBuffer, 0, 2);
+ return Memory.peekShort(readBuffer, 0, ByteOrder.BIG_ENDIAN);
+ }
+
+ /**
+ * See the general contract of the <code>readUnsignedShort</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next two bytes of this input stream, interpreted as an
+ * unsigned 16-bit integer.
+ * @exception EOFException if this input stream reaches the end before
+ * reading two bytes.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public final int readUnsignedShort() throws IOException {
+ // b/30268192
+ // Android-changed: Use read(byte[], int, int) instead of read().
+ readFully(readBuffer, 0, 2);
+ return Memory.peekShort(readBuffer, 0, ByteOrder.BIG_ENDIAN) & 0xffff;
+ }
+
+ /**
+ * See the general contract of the <code>readChar</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next two bytes of this input stream, interpreted as a
+ * <code>char</code>.
+ * @exception EOFException if this input stream reaches the end before
+ * reading two bytes.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public final char readChar() throws IOException {
+ // b/30268192
+ // Android-changed: Use read(byte[], int, int) instead of read().
+ readFully(readBuffer, 0, 2);
+ return (char)Memory.peekShort(readBuffer, 0, ByteOrder.BIG_ENDIAN);
+ }
+
+ /**
+ * See the general contract of the <code>readInt</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next four bytes of this input stream, interpreted as an
+ * <code>int</code>.
+ * @exception EOFException if this input stream reaches the end before
+ * reading four bytes.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public final int readInt() throws IOException {
+ // b/30268192
+ // Android-changed: Use read(byte[], int, int) instead of read().
+ readFully(readBuffer, 0, 4);
+ return Memory.peekInt(readBuffer, 0, ByteOrder.BIG_ENDIAN);
+ }
+
+ private byte readBuffer[] = new byte[8];
+
+ /**
+ * See the general contract of the <code>readLong</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next eight bytes of this input stream, interpreted as a
+ * <code>long</code>.
+ * @exception EOFException if this input stream reaches the end before
+ * reading eight bytes.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public final long readLong() throws IOException {
+ readFully(readBuffer, 0, 8);
+ return (((long)readBuffer[0] << 56) +
+ ((long)(readBuffer[1] & 255) << 48) +
+ ((long)(readBuffer[2] & 255) << 40) +
+ ((long)(readBuffer[3] & 255) << 32) +
+ ((long)(readBuffer[4] & 255) << 24) +
+ ((readBuffer[5] & 255) << 16) +
+ ((readBuffer[6] & 255) << 8) +
+ ((readBuffer[7] & 255) << 0));
+ }
+
+ /**
+ * See the general contract of the <code>readFloat</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next four bytes of this input stream, interpreted as a
+ * <code>float</code>.
+ * @exception EOFException if this input stream reaches the end before
+ * reading four bytes.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.DataInputStream#readInt()
+ * @see java.lang.Float#intBitsToFloat(int)
+ */
+ public final float readFloat() throws IOException {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ /**
+ * See the general contract of the <code>readDouble</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return the next eight bytes of this input stream, interpreted as a
+ * <code>double</code>.
+ * @exception EOFException if this input stream reaches the end before
+ * reading eight bytes.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @see java.io.DataInputStream#readLong()
+ * @see java.lang.Double#longBitsToDouble(long)
+ */
+ public final double readDouble() throws IOException {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ private char lineBuffer[];
+
+ /**
+ * See the general contract of the <code>readLine</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @deprecated This method does not properly convert bytes to characters.
+ * As of JDK 1.1, the preferred way to read lines of text is via the
+ * <code>BufferedReader.readLine()</code> method. Programs that use the
+ * <code>DataInputStream</code> class to read lines can be converted to use
+ * the <code>BufferedReader</code> class by replacing code of the form:
+ * <blockquote><pre>
+ * DataInputStream d = new DataInputStream(in);
+ * </pre></blockquote>
+ * with:
+ * <blockquote><pre>
+ * BufferedReader d
+ * = new BufferedReader(new InputStreamReader(in));
+ * </pre></blockquote>
+ *
+ * @return the next line of text from this input stream.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.BufferedReader#readLine()
+ * @see java.io.FilterInputStream#in
+ */
+ @Deprecated
+ public final String readLine() throws IOException {
+ char buf[] = lineBuffer;
+
+ if (buf == null) {
+ buf = lineBuffer = new char[128];
+ }
+
+ int room = buf.length;
+ int offset = 0;
+ int c;
+
+loop: while (true) {
+ switch (c = in.read()) {
+ case -1:
+ case '\n':
+ break loop;
+
+ case '\r':
+ int c2 = in.read();
+ if ((c2 != '\n') && (c2 != -1)) {
+ if (!(in instanceof PushbackInputStream)) {
+ this.in = new PushbackInputStream(in);
+ }
+ ((PushbackInputStream)in).unread(c2);
+ }
+ break loop;
+
+ default:
+ if (--room < 0) {
+ buf = new char[offset + 128];
+ room = buf.length - offset - 1;
+ System.arraycopy(lineBuffer, 0, buf, 0, offset);
+ lineBuffer = buf;
+ }
+ buf[offset++] = (char) c;
+ break;
+ }
+ }
+ if ((c == -1) && (offset == 0)) {
+ return null;
+ }
+ return String.copyValueOf(buf, 0, offset);
+ }
+
+ /**
+ * See the general contract of the <code>readUTF</code>
+ * method of <code>DataInput</code>.
+ * <p>
+ * Bytes
+ * for this operation are read from the contained
+ * input stream.
+ *
+ * @return a Unicode string.
+ * @exception EOFException if this input stream reaches the end before
+ * reading all the bytes.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @exception UTFDataFormatException if the bytes do not represent a valid
+ * modified UTF-8 encoding of a string.
+ * @see java.io.DataInputStream#readUTF(java.io.DataInput)
+ */
+ public final String readUTF() throws IOException {
+ return readUTF(this);
+ }
+
+ /**
+ * Reads from the
+ * stream <code>in</code> a representation
+ * of a Unicode character string encoded in
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> format;
+ * this string of characters is then returned as a <code>String</code>.
+ * The details of the modified UTF-8 representation
+ * are exactly the same as for the <code>readUTF</code>
+ * method of <code>DataInput</code>.
+ *
+ * @param in a data input stream.
+ * @return a Unicode string.
+ * @exception EOFException if the input stream reaches the end
+ * before all the bytes.
+ * @exception IOException the stream has been closed and the contained
+ * input stream does not support reading after close, or
+ * another I/O error occurs.
+ * @exception UTFDataFormatException if the bytes do not represent a
+ * valid modified UTF-8 encoding of a Unicode string.
+ * @see java.io.DataInputStream#readUnsignedShort()
+ */
+ public final static String readUTF(DataInput in) throws IOException {
+ int utflen = in.readUnsignedShort();
+ byte[] bytearr = null;
+ char[] chararr = null;
+ if (in instanceof DataInputStream) {
+ DataInputStream dis = (DataInputStream)in;
+ if (dis.bytearr.length < utflen){
+ dis.bytearr = new byte[utflen*2];
+ dis.chararr = new char[utflen*2];
+ }
+ chararr = dis.chararr;
+ bytearr = dis.bytearr;
+ } else {
+ bytearr = new byte[utflen];
+ chararr = new char[utflen];
+ }
+
+ int c, char2, char3;
+ int count = 0;
+ int chararr_count=0;
+
+ in.readFully(bytearr, 0, utflen);
+
+ while (count < utflen) {
+ c = (int) bytearr[count] & 0xff;
+ if (c > 127) break;
+ count++;
+ chararr[chararr_count++]=(char)c;
+ }
+
+ while (count < utflen) {
+ c = (int) bytearr[count] & 0xff;
+ switch (c >> 4) {
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ /* 0xxxxxxx*/
+ count++;
+ chararr[chararr_count++]=(char)c;
+ break;
+ case 12: case 13:
+ /* 110x xxxx 10xx xxxx*/
+ count += 2;
+ if (count > utflen)
+ throw new UTFDataFormatException(
+ "malformed input: partial character at end");
+ char2 = (int) bytearr[count-1];
+ if ((char2 & 0xC0) != 0x80)
+ throw new UTFDataFormatException(
+ "malformed input around byte " + count);
+ chararr[chararr_count++]=(char)(((c & 0x1F) << 6) |
+ (char2 & 0x3F));
+ break;
+ case 14:
+ /* 1110 xxxx 10xx xxxx 10xx xxxx */
+ count += 3;
+ if (count > utflen)
+ throw new UTFDataFormatException(
+ "malformed input: partial character at end");
+ char2 = (int) bytearr[count-2];
+ char3 = (int) bytearr[count-1];
+ if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+ throw new UTFDataFormatException(
+ "malformed input around byte " + (count-1));
+ chararr[chararr_count++]=(char)(((c & 0x0F) << 12) |
+ ((char2 & 0x3F) << 6) |
+ ((char3 & 0x3F) << 0));
+ break;
+ default:
+ /* 10xx xxxx, 1111 xxxx */
+ throw new UTFDataFormatException(
+ "malformed input around byte " + count);
+ }
+ }
+ // The number of chars produced may be less than utflen
+ return new String(chararr, 0, chararr_count);
+ }
+}
diff --git a/java/io/DataOutput.java b/java/io/DataOutput.java
new file mode 100644
index 0000000..c6692a6
--- /dev/null
+++ b/java/io/DataOutput.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * The <code>DataOutput</code> interface provides
+ * for converting data from any of the Java
+ * primitive types to a series of bytes and
+ * writing these bytes to a binary stream.
+ * There is also a facility for converting
+ * a <code>String</code> into
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+ * format and writing the resulting series
+ * of bytes.
+ * <p>
+ * For all the methods in this interface that
+ * write bytes, it is generally true that if
+ * a byte cannot be written for any reason,
+ * an <code>IOException</code> is thrown.
+ *
+ * @author Frank Yellin
+ * @see java.io.DataInput
+ * @see java.io.DataOutputStream
+ * @since JDK1.0
+ */
+public
+interface DataOutput {
+ /**
+ * Writes to the output stream the eight
+ * low-order bits of the argument <code>b</code>.
+ * The 24 high-order bits of <code>b</code>
+ * are ignored.
+ *
+ * @param b the byte to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void write(int b) throws IOException;
+
+ /**
+ * Writes to the output stream all the bytes in array <code>b</code>.
+ * If <code>b</code> is <code>null</code>,
+ * a <code>NullPointerException</code> is thrown.
+ * If <code>b.length</code> is zero, then
+ * no bytes are written. Otherwise, the byte
+ * <code>b[0]</code> is written first, then
+ * <code>b[1]</code>, and so on; the last byte
+ * written is <code>b[b.length-1]</code>.
+ *
+ * @param b the data.
+ * @throws IOException if an I/O error occurs.
+ */
+ void write(byte b[]) throws IOException;
+
+ /**
+ * Writes <code>len</code> bytes from array
+ * <code>b</code>, in order, to
+ * the output stream. If <code>b</code>
+ * is <code>null</code>, a <code>NullPointerException</code>
+ * is thrown. If <code>off</code> is negative,
+ * or <code>len</code> is negative, or <code>off+len</code>
+ * is greater than the length of the array
+ * <code>b</code>, then an <code>IndexOutOfBoundsException</code>
+ * is thrown. If <code>len</code> is zero,
+ * then no bytes are written. Otherwise, the
+ * byte <code>b[off]</code> is written first,
+ * then <code>b[off+1]</code>, and so on; the
+ * last byte written is <code>b[off+len-1]</code>.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @throws IOException if an I/O error occurs.
+ */
+ void write(byte b[], int off, int len) throws IOException;
+
+ /**
+ * Writes a <code>boolean</code> value to this output stream.
+ * If the argument <code>v</code>
+ * is <code>true</code>, the value <code>(byte)1</code>
+ * is written; if <code>v</code> is <code>false</code>,
+ * the value <code>(byte)0</code> is written.
+ * The byte written by this method may
+ * be read by the <code>readBoolean</code>
+ * method of interface <code>DataInput</code>,
+ * which will then return a <code>boolean</code>
+ * equal to <code>v</code>.
+ *
+ * @param v the boolean to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void writeBoolean(boolean v) throws IOException;
+
+ /**
+ * Writes to the output stream the eight low-
+ * order bits of the argument <code>v</code>.
+ * The 24 high-order bits of <code>v</code>
+ * are ignored. (This means that <code>writeByte</code>
+ * does exactly the same thing as <code>write</code>
+ * for an integer argument.) The byte written
+ * by this method may be read by the <code>readByte</code>
+ * method of interface <code>DataInput</code>,
+ * which will then return a <code>byte</code>
+ * equal to <code>(byte)v</code>.
+ *
+ * @param v the byte value to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void writeByte(int v) throws IOException;
+
+ /**
+ * Writes two bytes to the output
+ * stream to represent the value of the argument.
+ * The byte values to be written, in the order
+ * shown, are:
+ * <pre>{@code
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }</pre> <p>
+ * The bytes written by this method may be
+ * read by the <code>readShort</code> method
+ * of interface <code>DataInput</code> , which
+ * will then return a <code>short</code> equal
+ * to <code>(short)v</code>.
+ *
+ * @param v the <code>short</code> value to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void writeShort(int v) throws IOException;
+
+ /**
+ * Writes a <code>char</code> value, which
+ * is comprised of two bytes, to the
+ * output stream.
+ * The byte values to be written, in the order
+ * shown, are:
+ * <pre>{@code
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }</pre><p>
+ * The bytes written by this method may be
+ * read by the <code>readChar</code> method
+ * of interface <code>DataInput</code> , which
+ * will then return a <code>char</code> equal
+ * to <code>(char)v</code>.
+ *
+ * @param v the <code>char</code> value to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void writeChar(int v) throws IOException;
+
+ /**
+ * Writes an <code>int</code> value, which is
+ * comprised of four bytes, to the output stream.
+ * The byte values to be written, in the order
+ * shown, are:
+ * <pre>{@code
+ * (byte)(0xff & (v >> 24))
+ * (byte)(0xff & (v >> 16))
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }</pre><p>
+ * The bytes written by this method may be read
+ * by the <code>readInt</code> method of interface
+ * <code>DataInput</code> , which will then
+ * return an <code>int</code> equal to <code>v</code>.
+ *
+ * @param v the <code>int</code> value to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void writeInt(int v) throws IOException;
+
+ /**
+ * Writes a <code>long</code> value, which is
+ * comprised of eight bytes, to the output stream.
+ * The byte values to be written, in the order
+ * shown, are:
+ * <pre>{@code
+ * (byte)(0xff & (v >> 56))
+ * (byte)(0xff & (v >> 48))
+ * (byte)(0xff & (v >> 40))
+ * (byte)(0xff & (v >> 32))
+ * (byte)(0xff & (v >> 24))
+ * (byte)(0xff & (v >> 16))
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }</pre><p>
+ * The bytes written by this method may be
+ * read by the <code>readLong</code> method
+ * of interface <code>DataInput</code> , which
+ * will then return a <code>long</code> equal
+ * to <code>v</code>.
+ *
+ * @param v the <code>long</code> value to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void writeLong(long v) throws IOException;
+
+ /**
+ * Writes a <code>float</code> value,
+ * which is comprised of four bytes, to the output stream.
+ * It does this as if it first converts this
+ * <code>float</code> value to an <code>int</code>
+ * in exactly the manner of the <code>Float.floatToIntBits</code>
+ * method and then writes the <code>int</code>
+ * value in exactly the manner of the <code>writeInt</code>
+ * method. The bytes written by this method
+ * may be read by the <code>readFloat</code>
+ * method of interface <code>DataInput</code>,
+ * which will then return a <code>float</code>
+ * equal to <code>v</code>.
+ *
+ * @param v the <code>float</code> value to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void writeFloat(float v) throws IOException;
+
+ /**
+ * Writes a <code>double</code> value,
+ * which is comprised of eight bytes, to the output stream.
+ * It does this as if it first converts this
+ * <code>double</code> value to a <code>long</code>
+ * in exactly the manner of the <code>Double.doubleToLongBits</code>
+ * method and then writes the <code>long</code>
+ * value in exactly the manner of the <code>writeLong</code>
+ * method. The bytes written by this method
+ * may be read by the <code>readDouble</code>
+ * method of interface <code>DataInput</code>,
+ * which will then return a <code>double</code>
+ * equal to <code>v</code>.
+ *
+ * @param v the <code>double</code> value to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void writeDouble(double v) throws IOException;
+
+ /**
+ * Writes a string to the output stream.
+ * For every character in the string
+ * <code>s</code>, taken in order, one byte
+ * is written to the output stream. If
+ * <code>s</code> is <code>null</code>, a <code>NullPointerException</code>
+ * is thrown.<p> If <code>s.length</code>
+ * is zero, then no bytes are written. Otherwise,
+ * the character <code>s[0]</code> is written
+ * first, then <code>s[1]</code>, and so on;
+ * the last character written is <code>s[s.length-1]</code>.
+ * For each character, one byte is written,
+ * the low-order byte, in exactly the manner
+ * of the <code>writeByte</code> method . The
+ * high-order eight bits of each character
+ * in the string are ignored.
+ *
+ * @param s the string of bytes to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void writeBytes(String s) throws IOException;
+
+ /**
+ * Writes every character in the string <code>s</code>,
+ * to the output stream, in order,
+ * two bytes per character. If <code>s</code>
+ * is <code>null</code>, a <code>NullPointerException</code>
+ * is thrown. If <code>s.length</code>
+ * is zero, then no characters are written.
+ * Otherwise, the character <code>s[0]</code>
+ * is written first, then <code>s[1]</code>,
+ * and so on; the last character written is
+ * <code>s[s.length-1]</code>. For each character,
+ * two bytes are actually written, high-order
+ * byte first, in exactly the manner of the
+ * <code>writeChar</code> method.
+ *
+ * @param s the string value to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void writeChars(String s) throws IOException;
+
+ /**
+ * Writes two bytes of length information
+ * to the output stream, followed
+ * by the
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+ * representation
+ * of every character in the string <code>s</code>.
+ * If <code>s</code> is <code>null</code>,
+ * a <code>NullPointerException</code> is thrown.
+ * Each character in the string <code>s</code>
+ * is converted to a group of one, two, or
+ * three bytes, depending on the value of the
+ * character.<p>
+ * If a character <code>c</code>
+ * is in the range <code>\u0001</code> through
+ * <code>\u007f</code>, it is represented
+ * by one byte:
+ * <pre>(byte)c </pre> <p>
+ * If a character <code>c</code> is <code>\u0000</code>
+ * or is in the range <code>\u0080</code>
+ * through <code>\u07ff</code>, then it is
+ * represented by two bytes, to be written
+ * in the order shown: <pre>{@code
+ * (byte)(0xc0 | (0x1f & (c >> 6)))
+ * (byte)(0x80 | (0x3f & c))
+ * }</pre> <p> If a character
+ * <code>c</code> is in the range <code>\u0800</code>
+ * through <code>uffff</code>, then it is
+ * represented by three bytes, to be written
+ * in the order shown: <pre>{@code
+ * (byte)(0xe0 | (0x0f & (c >> 12)))
+ * (byte)(0x80 | (0x3f & (c >> 6)))
+ * (byte)(0x80 | (0x3f & c))
+ * }</pre> <p> First,
+ * the total number of bytes needed to represent
+ * all the characters of <code>s</code> is
+ * calculated. If this number is larger than
+ * <code>65535</code>, then a <code>UTFDataFormatException</code>
+ * is thrown. Otherwise, this length is written
+ * to the output stream in exactly the manner
+ * of the <code>writeShort</code> method;
+ * after this, the one-, two-, or three-byte
+ * representation of each character in the
+ * string <code>s</code> is written.<p> The
+ * bytes written by this method may be read
+ * by the <code>readUTF</code> method of interface
+ * <code>DataInput</code> , which will then
+ * return a <code>String</code> equal to <code>s</code>.
+ *
+ * @param s the string value to be written.
+ * @throws IOException if an I/O error occurs.
+ */
+ void writeUTF(String s) throws IOException;
+}
diff --git a/java/io/DataOutputStream.java b/java/io/DataOutputStream.java
new file mode 100644
index 0000000..99fafed
--- /dev/null
+++ b/java/io/DataOutputStream.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * A data output stream lets an application write primitive Java data
+ * types to an output stream in a portable way. An application can
+ * then use a data input stream to read the data back in.
+ *
+ * @author unascribed
+ * @see java.io.DataInputStream
+ * @since JDK1.0
+ */
+public
+class DataOutputStream extends FilterOutputStream implements DataOutput {
+ /**
+ * The number of bytes written to the data output stream so far.
+ * If this counter overflows, it will be wrapped to Integer.MAX_VALUE.
+ */
+ protected int written;
+
+ /**
+ * bytearr is initialized on demand by writeUTF
+ */
+ private byte[] bytearr = null;
+
+ /**
+ * Creates a new data output stream to write data to the specified
+ * underlying output stream. The counter <code>written</code> is
+ * set to zero.
+ *
+ * @param out the underlying output stream, to be saved for later
+ * use.
+ * @see java.io.FilterOutputStream#out
+ */
+ public DataOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ /**
+ * Increases the written counter by the specified value
+ * until it reaches Integer.MAX_VALUE.
+ */
+ private void incCount(int value) {
+ int temp = written + value;
+ if (temp < 0) {
+ temp = Integer.MAX_VALUE;
+ }
+ written = temp;
+ }
+
+ /**
+ * Writes the specified byte (the low eight bits of the argument
+ * <code>b</code>) to the underlying output stream. If no exception
+ * is thrown, the counter <code>written</code> is incremented by
+ * <code>1</code>.
+ * <p>
+ * Implements the <code>write</code> method of <code>OutputStream</code>.
+ *
+ * @param b the <code>byte</code> to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ */
+ public synchronized void write(int b) throws IOException {
+ out.write(b);
+ incCount(1);
+ }
+
+ /**
+ * Writes <code>len</code> bytes from the specified byte array
+ * starting at offset <code>off</code> to the underlying output stream.
+ * If no exception is thrown, the counter <code>written</code> is
+ * incremented by <code>len</code>.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ */
+ public synchronized void write(byte b[], int off, int len)
+ throws IOException
+ {
+ out.write(b, off, len);
+ incCount(len);
+ }
+
+ /**
+ * Flushes this data output stream. This forces any buffered output
+ * bytes to be written out to the stream.
+ * <p>
+ * The <code>flush</code> method of <code>DataOutputStream</code>
+ * calls the <code>flush</code> method of its underlying output stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ * @see java.io.OutputStream#flush()
+ */
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ /**
+ * Writes a <code>boolean</code> to the underlying output stream as
+ * a 1-byte value. The value <code>true</code> is written out as the
+ * value <code>(byte)1</code>; the value <code>false</code> is
+ * written out as the value <code>(byte)0</code>. If no exception is
+ * thrown, the counter <code>written</code> is incremented by
+ * <code>1</code>.
+ *
+ * @param v a <code>boolean</code> value to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ */
+ public final void writeBoolean(boolean v) throws IOException {
+ out.write(v ? 1 : 0);
+ incCount(1);
+ }
+
+ /**
+ * Writes out a <code>byte</code> to the underlying output stream as
+ * a 1-byte value. If no exception is thrown, the counter
+ * <code>written</code> is incremented by <code>1</code>.
+ *
+ * @param v a <code>byte</code> value to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ */
+ public final void writeByte(int v) throws IOException {
+ out.write(v);
+ incCount(1);
+ }
+
+ /**
+ * Writes a <code>short</code> to the underlying output stream as two
+ * bytes, high byte first. If no exception is thrown, the counter
+ * <code>written</code> is incremented by <code>2</code>.
+ *
+ * @param v a <code>short</code> to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ */
+ public final void writeShort(int v) throws IOException {
+ out.write((v >>> 8) & 0xFF);
+ out.write((v >>> 0) & 0xFF);
+ incCount(2);
+ }
+
+ /**
+ * Writes a <code>char</code> to the underlying output stream as a
+ * 2-byte value, high byte first. If no exception is thrown, the
+ * counter <code>written</code> is incremented by <code>2</code>.
+ *
+ * @param v a <code>char</code> value to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ */
+ public final void writeChar(int v) throws IOException {
+ out.write((v >>> 8) & 0xFF);
+ out.write((v >>> 0) & 0xFF);
+ incCount(2);
+ }
+
+ /**
+ * Writes an <code>int</code> to the underlying output stream as four
+ * bytes, high byte first. If no exception is thrown, the counter
+ * <code>written</code> is incremented by <code>4</code>.
+ *
+ * @param v an <code>int</code> to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ */
+ public final void writeInt(int v) throws IOException {
+ out.write((v >>> 24) & 0xFF);
+ out.write((v >>> 16) & 0xFF);
+ out.write((v >>> 8) & 0xFF);
+ out.write((v >>> 0) & 0xFF);
+ incCount(4);
+ }
+
+ private byte writeBuffer[] = new byte[8];
+
+ /**
+ * Writes a <code>long</code> to the underlying output stream as eight
+ * bytes, high byte first. In no exception is thrown, the counter
+ * <code>written</code> is incremented by <code>8</code>.
+ *
+ * @param v a <code>long</code> to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ */
+ public final void writeLong(long v) throws IOException {
+ writeBuffer[0] = (byte)(v >>> 56);
+ writeBuffer[1] = (byte)(v >>> 48);
+ writeBuffer[2] = (byte)(v >>> 40);
+ writeBuffer[3] = (byte)(v >>> 32);
+ writeBuffer[4] = (byte)(v >>> 24);
+ writeBuffer[5] = (byte)(v >>> 16);
+ writeBuffer[6] = (byte)(v >>> 8);
+ writeBuffer[7] = (byte)(v >>> 0);
+ out.write(writeBuffer, 0, 8);
+ incCount(8);
+ }
+
+ /**
+ * Converts the float argument to an <code>int</code> using the
+ * <code>floatToIntBits</code> method in class <code>Float</code>,
+ * and then writes that <code>int</code> value to the underlying
+ * output stream as a 4-byte quantity, high byte first. If no
+ * exception is thrown, the counter <code>written</code> is
+ * incremented by <code>4</code>.
+ *
+ * @param v a <code>float</code> value to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ * @see java.lang.Float#floatToIntBits(float)
+ */
+ public final void writeFloat(float v) throws IOException {
+ writeInt(Float.floatToIntBits(v));
+ }
+
+ /**
+ * Converts the double argument to a <code>long</code> using the
+ * <code>doubleToLongBits</code> method in class <code>Double</code>,
+ * and then writes that <code>long</code> value to the underlying
+ * output stream as an 8-byte quantity, high byte first. If no
+ * exception is thrown, the counter <code>written</code> is
+ * incremented by <code>8</code>.
+ *
+ * @param v a <code>double</code> value to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ * @see java.lang.Double#doubleToLongBits(double)
+ */
+ public final void writeDouble(double v) throws IOException {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ /**
+ * Writes out the string to the underlying output stream as a
+ * sequence of bytes. Each character in the string is written out, in
+ * sequence, by discarding its high eight bits. If no exception is
+ * thrown, the counter <code>written</code> is incremented by the
+ * length of <code>s</code>.
+ *
+ * @param s a string of bytes to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ */
+ public final void writeBytes(String s) throws IOException {
+ int len = s.length();
+ for (int i = 0 ; i < len ; i++) {
+ out.write((byte)s.charAt(i));
+ }
+ incCount(len);
+ }
+
+ /**
+ * Writes a string to the underlying output stream as a sequence of
+ * characters. Each character is written to the data output stream as
+ * if by the <code>writeChar</code> method. If no exception is
+ * thrown, the counter <code>written</code> is incremented by twice
+ * the length of <code>s</code>.
+ *
+ * @param s a <code>String</code> value to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.DataOutputStream#writeChar(int)
+ * @see java.io.FilterOutputStream#out
+ */
+ public final void writeChars(String s) throws IOException {
+ int len = s.length();
+ for (int i = 0 ; i < len ; i++) {
+ int v = s.charAt(i);
+ out.write((v >>> 8) & 0xFF);
+ out.write((v >>> 0) & 0xFF);
+ }
+ incCount(len * 2);
+ }
+
+ /**
+ * Writes a string to the underlying output stream using
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+ * encoding in a machine-independent manner.
+ * <p>
+ * First, two bytes are written to the output stream as if by the
+ * <code>writeShort</code> method giving the number of bytes to
+ * follow. This value is the number of bytes actually written out,
+ * not the length of the string. Following the length, each character
+ * of the string is output, in sequence, using the modified UTF-8 encoding
+ * for the character. If no exception is thrown, the counter
+ * <code>written</code> is incremented by the total number of
+ * bytes written to the output stream. This will be at least two
+ * plus the length of <code>str</code>, and at most two plus
+ * thrice the length of <code>str</code>.
+ *
+ * @param str a string to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final void writeUTF(String str) throws IOException {
+ writeUTF(str, this);
+ }
+
+ /**
+ * Writes a string to the specified DataOutput using
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+ * encoding in a machine-independent manner.
+ * <p>
+ * First, two bytes are written to out as if by the <code>writeShort</code>
+ * method giving the number of bytes to follow. This value is the number of
+ * bytes actually written out, not the length of the string. Following the
+ * length, each character of the string is output, in sequence, using the
+ * modified UTF-8 encoding for the character. If no exception is thrown, the
+ * counter <code>written</code> is incremented by the total number of
+ * bytes written to the output stream. This will be at least two
+ * plus the length of <code>str</code>, and at most two plus
+ * thrice the length of <code>str</code>.
+ *
+ * @param str a string to be written.
+ * @param out destination to write to
+ * @return The number of bytes written out.
+ * @exception IOException if an I/O error occurs.
+ */
+ static int writeUTF(String str, DataOutput out) throws IOException {
+ int strlen = str.length();
+ int utflen = 0;
+ int c, count = 0;
+
+ /* use charAt instead of copying String to char array */
+ for (int i = 0; i < strlen; i++) {
+ c = str.charAt(i);
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ utflen++;
+ } else if (c > 0x07FF) {
+ utflen += 3;
+ } else {
+ utflen += 2;
+ }
+ }
+
+ if (utflen > 65535)
+ throw new UTFDataFormatException(
+ "encoded string too long: " + utflen + " bytes");
+
+ byte[] bytearr = null;
+ if (out instanceof DataOutputStream) {
+ DataOutputStream dos = (DataOutputStream)out;
+ if(dos.bytearr == null || (dos.bytearr.length < (utflen+2)))
+ dos.bytearr = new byte[(utflen*2) + 2];
+ bytearr = dos.bytearr;
+ } else {
+ bytearr = new byte[utflen+2];
+ }
+
+ bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
+ bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
+
+ int i=0;
+ for (i=0; i<strlen; i++) {
+ c = str.charAt(i);
+ if (!((c >= 0x0001) && (c <= 0x007F))) break;
+ bytearr[count++] = (byte) c;
+ }
+
+ for (;i < strlen; i++){
+ c = str.charAt(i);
+ if ((c >= 0x0001) && (c <= 0x007F)) {
+ bytearr[count++] = (byte) c;
+
+ } else if (c > 0x07FF) {
+ bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
+ bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
+ bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
+ } else {
+ bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
+ bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
+ }
+ }
+ out.write(bytearr, 0, utflen+2);
+ return utflen + 2;
+ }
+
+ /**
+ * Returns the current value of the counter <code>written</code>,
+ * the number of bytes written to this data output stream so far.
+ * If the counter overflows, it will be wrapped to Integer.MAX_VALUE.
+ *
+ * @return the value of the <code>written</code> field.
+ * @see java.io.DataOutputStream#written
+ */
+ public final int size() {
+ return written;
+ }
+}
diff --git a/java/io/DefaultFileSystem.java b/java/io/DefaultFileSystem.java
new file mode 100644
index 0000000..8e8cf08
--- /dev/null
+++ b/java/io/DefaultFileSystem.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ *
+ * @since 1.8
+ */
+class DefaultFileSystem {
+
+ /**
+ * Return the FileSystem object for Unix-based platform.
+ */
+ public static FileSystem getFileSystem() {
+ return new UnixFileSystem();
+ }
+}
diff --git a/java/io/DeleteOnExitHook.java b/java/io/DeleteOnExitHook.java
new file mode 100644
index 0000000..e988f9b
--- /dev/null
+++ b/java/io/DeleteOnExitHook.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.io;
+
+import java.util.*;
+import java.io.File;
+
+/**
+ * This class holds a set of filenames to be deleted on VM exit through a shutdown hook.
+ * A set is used both to prevent double-insertion of the same file as well as offer
+ * quick removal.
+ */
+
+class DeleteOnExitHook {
+ private static LinkedHashSet<String> files = new LinkedHashSet<>();
+ static {
+ // BEGIN Android-changed: Use Runtime.addShutdownHook() rather than SharedSecrets.
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ public void run() {
+ runHooks();
+ }
+ });
+ // END Android-changed: Use Runtime.addShutdownHook() rather than SharedSecrets.
+ }
+
+ private DeleteOnExitHook() {}
+
+ static synchronized void add(String file) {
+ if(files == null) {
+ // DeleteOnExitHook is running. Too late to add a file
+ throw new IllegalStateException("Shutdown in progress");
+ }
+
+ files.add(file);
+ }
+
+ static void runHooks() {
+ LinkedHashSet<String> theFiles;
+
+ synchronized (DeleteOnExitHook.class) {
+ theFiles = files;
+ files = null;
+ }
+
+ ArrayList<String> toBeDeleted = new ArrayList<>(theFiles);
+
+ // reverse the list to maintain previous jdk deletion order.
+ // Last in first deleted.
+ Collections.reverse(toBeDeleted);
+ for (String filename : toBeDeleted) {
+ (new File(filename)).delete();
+ }
+ }
+}
diff --git a/java/io/EOFException.java b/java/io/EOFException.java
new file mode 100644
index 0000000..536669f
--- /dev/null
+++ b/java/io/EOFException.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that an end of file or end of stream has been reached
+ * unexpectedly during input.
+ * <p>
+ * This exception is mainly used by data input streams to signal end of
+ * stream. Note that many other input operations return a special value on
+ * end of stream rather than throwing an exception.
+ *
+ * @author Frank Yellin
+ * @see java.io.DataInputStream
+ * @see java.io.IOException
+ * @since JDK1.0
+ */
+public
+class EOFException extends IOException {
+ private static final long serialVersionUID = 6433858223774886977L;
+
+ /**
+ * Constructs an <code>EOFException</code> with <code>null</code>
+ * as its error detail message.
+ */
+ public EOFException() {
+ super();
+ }
+
+ /**
+ * Constructs an <code>EOFException</code> with the specified detail
+ * message. The string <code>s</code> may later be retrieved by the
+ * <code>{@link java.lang.Throwable#getMessage}</code> method of class
+ * <code>java.lang.Throwable</code>.
+ *
+ * @param s the detail message.
+ */
+ public EOFException(String s) {
+ super(s);
+ }
+}
diff --git a/java/io/ExpiringCache.java b/java/io/ExpiringCache.java
new file mode 100644
index 0000000..d0edb11
--- /dev/null
+++ b/java/io/ExpiringCache.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ */
+
+package java.io;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.LinkedHashMap;
+import java.util.Set;
+
+class ExpiringCache {
+ private long millisUntilExpiration;
+ private Map<String,Entry> map;
+ // Clear out old entries every few queries
+ private int queryCount;
+ private int queryOverflow = 300;
+ private int MAX_ENTRIES = 200;
+
+ static class Entry {
+ private long timestamp;
+ private String val;
+
+ Entry(long timestamp, String val) {
+ this.timestamp = timestamp;
+ this.val = val;
+ }
+
+ long timestamp() { return timestamp; }
+ void setTimestamp(long timestamp) { this.timestamp = timestamp; }
+
+ String val() { return val; }
+ void setVal(String val) { this.val = val; }
+ }
+
+ ExpiringCache() {
+ this(30000);
+ }
+
+ @SuppressWarnings("serial")
+ ExpiringCache(long millisUntilExpiration) {
+ this.millisUntilExpiration = millisUntilExpiration;
+ map = new LinkedHashMap<String,Entry>() {
+ // Android-changed: Qualified ExpiringCache.Entry to distinguish from Map.Entry.
+ // There seems to be a compiler difference between javac and jack here;
+ // Map.Entry<String,Entry> doesn't work on jack since the latter "Entry" gets
+ // interpreted as referring to Map.Entry rather than ExpiringCache.Entry.
+ // protected boolean removeEldestEntry(Map.Entry<String,Entry> eldest) {
+ protected boolean removeEldestEntry(Map.Entry<String,ExpiringCache.Entry> eldest) {
+ return size() > MAX_ENTRIES;
+ }
+ };
+ }
+
+ synchronized String get(String key) {
+ if (++queryCount >= queryOverflow) {
+ cleanup();
+ }
+ Entry entry = entryFor(key);
+ if (entry != null) {
+ return entry.val();
+ }
+ return null;
+ }
+
+ synchronized void put(String key, String val) {
+ if (++queryCount >= queryOverflow) {
+ cleanup();
+ }
+ Entry entry = entryFor(key);
+ if (entry != null) {
+ entry.setTimestamp(System.currentTimeMillis());
+ entry.setVal(val);
+ } else {
+ map.put(key, new Entry(System.currentTimeMillis(), val));
+ }
+ }
+
+ synchronized void clear() {
+ map.clear();
+ }
+
+ private Entry entryFor(String key) {
+ Entry entry = map.get(key);
+ if (entry != null) {
+ long delta = System.currentTimeMillis() - entry.timestamp();
+ if (delta < 0 || delta >= millisUntilExpiration) {
+ map.remove(key);
+ entry = null;
+ }
+ }
+ return entry;
+ }
+
+ private void cleanup() {
+ Set<String> keySet = map.keySet();
+ // Avoid ConcurrentModificationExceptions
+ String[] keys = new String[keySet.size()];
+ int i = 0;
+ for (String key: keySet) {
+ keys[i++] = key;
+ }
+ for (int j = 0; j < keys.length; j++) {
+ entryFor(keys[j]);
+ }
+ queryCount = 0;
+ }
+}
diff --git a/java/io/Externalizable.java b/java/io/Externalizable.java
new file mode 100644
index 0000000..f9e88fe
--- /dev/null
+++ b/java/io/Externalizable.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.ObjectOutput;
+import java.io.ObjectInput;
+
+/**
+ * Only the identity of the class of an Externalizable instance is
+ * written in the serialization stream and it is the responsibility
+ * of the class to save and restore the contents of its instances.
+ *
+ * The writeExternal and readExternal methods of the Externalizable
+ * interface are implemented by a class to give the class complete
+ * control over the format and contents of the stream for an object
+ * and its supertypes. These methods must explicitly
+ * coordinate with the supertype to save its state. These methods supersede
+ * customized implementations of writeObject and readObject methods.<br>
+ *
+ * Object Serialization uses the Serializable and Externalizable
+ * interfaces. Object persistence mechanisms can use them as well. Each
+ * object to be stored is tested for the Externalizable interface. If
+ * the object supports Externalizable, the writeExternal method is called. If the
+ * object does not support Externalizable and does implement
+ * Serializable, the object is saved using
+ * ObjectOutputStream. <br> When an Externalizable object is
+ * reconstructed, an instance is created using the public no-arg
+ * constructor, then the readExternal method called. Serializable
+ * objects are restored by reading them from an ObjectInputStream.<br>
+ *
+ * An Externalizable instance can designate a substitution object via
+ * the writeReplace and readResolve methods documented in the Serializable
+ * interface.<br>
+ *
+ * @author unascribed
+ * @see java.io.ObjectOutputStream
+ * @see java.io.ObjectInputStream
+ * @see java.io.ObjectOutput
+ * @see java.io.ObjectInput
+ * @see java.io.Serializable
+ * @since JDK1.1
+ */
+public interface Externalizable extends java.io.Serializable {
+ /**
+ * The object implements the writeExternal method to save its contents
+ * by calling the methods of DataOutput for its primitive values or
+ * calling the writeObject method of ObjectOutput for objects, strings,
+ * and arrays.
+ *
+ * @serialData Overriding methods should use this tag to describe
+ * the data layout of this Externalizable object.
+ * List the sequence of element types and, if possible,
+ * relate the element to a public/protected field and/or
+ * method of this Externalizable class.
+ *
+ * @param out the stream to write the object to
+ * @exception IOException Includes any I/O exceptions that may occur
+ */
+ void writeExternal(ObjectOutput out) throws IOException;
+
+ /**
+ * The object implements the readExternal method to restore its
+ * contents by calling the methods of DataInput for primitive
+ * types and readObject for objects, strings and arrays. The
+ * readExternal method must read the values in the same sequence
+ * and with the same types as were written by writeExternal.
+ *
+ * @param in the stream to read data from in order to restore the object
+ * @exception IOException if I/O errors occur
+ * @exception ClassNotFoundException If the class for an object being
+ * restored cannot be found.
+ */
+ void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
+}
diff --git a/java/io/File.annotated.java b/java/io/File.annotated.java
new file mode 100644
index 0000000..497c434
--- /dev/null
+++ b/java/io/File.annotated.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.io;
+
+import java.nio.file.Path;
+import java.net.URI;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.FileSystems;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class File implements java.io.Serializable, java.lang.Comparable<java.io.File> {
+
+public File(@libcore.util.NonNull java.lang.String pathname) { throw new RuntimeException("Stub!"); }
+
+public File(@libcore.util.Nullable java.lang.String parent, @libcore.util.NonNull java.lang.String child) { throw new RuntimeException("Stub!"); }
+
+public File(@libcore.util.Nullable java.io.File parent, @libcore.util.NonNull java.lang.String child) { throw new RuntimeException("Stub!"); }
+
+public File(@libcore.util.NonNull java.net.URI uri) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getParent() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.File getParentFile() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getPath() { throw new RuntimeException("Stub!"); }
+
+public boolean isAbsolute() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getAbsolutePath() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.File getAbsoluteFile() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getCanonicalPath() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.File getCanonicalFile() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+@Deprecated
[email protected] public java.net.URL toURL() throws java.net.MalformedURLException { throw new RuntimeException("Stub!"); }
+
[email protected] public java.net.URI toURI() { throw new RuntimeException("Stub!"); }
+
+public boolean canRead() { throw new RuntimeException("Stub!"); }
+
+public boolean canWrite() { throw new RuntimeException("Stub!"); }
+
+public boolean exists() { throw new RuntimeException("Stub!"); }
+
+public boolean isDirectory() { throw new RuntimeException("Stub!"); }
+
+public boolean isFile() { throw new RuntimeException("Stub!"); }
+
+public boolean isHidden() { throw new RuntimeException("Stub!"); }
+
+public long lastModified() { throw new RuntimeException("Stub!"); }
+
+public long length() { throw new RuntimeException("Stub!"); }
+
+public boolean createNewFile() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public boolean delete() { throw new RuntimeException("Stub!"); }
+
+public void deleteOnExit() { throw new RuntimeException("Stub!"); }
+
+public [email protected] String @libcore.util.Nullable [] list() { throw new RuntimeException("Stub!"); }
+
+public [email protected] String @libcore.util.Nullable [] list(@libcore.util.Nullable java.io.FilenameFilter filter) { throw new RuntimeException("Stub!"); }
+
+public [email protected] File @libcore.util.Nullable [] listFiles() { throw new RuntimeException("Stub!"); }
+
+public [email protected] File @libcore.util.Nullable [] listFiles(@libcore.util.Nullable java.io.FilenameFilter filter) { throw new RuntimeException("Stub!"); }
+
+public [email protected] File @libcore.util.Nullable [] listFiles(@libcore.util.Nullable java.io.FileFilter filter) { throw new RuntimeException("Stub!"); }
+
+public boolean mkdir() { throw new RuntimeException("Stub!"); }
+
+public boolean mkdirs() { throw new RuntimeException("Stub!"); }
+
+public boolean renameTo(@libcore.util.NonNull java.io.File dest) { throw new RuntimeException("Stub!"); }
+
+public boolean setLastModified(long time) { throw new RuntimeException("Stub!"); }
+
+public boolean setReadOnly() { throw new RuntimeException("Stub!"); }
+
+public boolean setWritable(boolean writable, boolean ownerOnly) { throw new RuntimeException("Stub!"); }
+
+public boolean setWritable(boolean writable) { throw new RuntimeException("Stub!"); }
+
+public boolean setReadable(boolean readable, boolean ownerOnly) { throw new RuntimeException("Stub!"); }
+
+public boolean setReadable(boolean readable) { throw new RuntimeException("Stub!"); }
+
+public boolean setExecutable(boolean executable, boolean ownerOnly) { throw new RuntimeException("Stub!"); }
+
+public boolean setExecutable(boolean executable) { throw new RuntimeException("Stub!"); }
+
+public boolean canExecute() { throw new RuntimeException("Stub!"); }
+
+public static [email protected] File @libcore.util.NonNull [] listRoots() { throw new RuntimeException("Stub!"); }
+
+public long getTotalSpace() { throw new RuntimeException("Stub!"); }
+
+public long getFreeSpace() { throw new RuntimeException("Stub!"); }
+
+public long getUsableSpace() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.io.File createTempFile(@libcore.util.NonNull java.lang.String prefix, @libcore.util.Nullable java.lang.String suffix, @libcore.util.Nullable java.io.File directory) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.io.File createTempFile(@libcore.util.NonNull java.lang.String prefix, @libcore.util.Nullable java.lang.String suffix) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public int compareTo(@libcore.util.NonNull java.io.File pathname) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.nio.file.Path toPath() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.lang.String pathSeparator;
+static { pathSeparator = null; }
+
+public static final char pathSeparatorChar;
+static { pathSeparatorChar = 0; }
+
[email protected] public static final java.lang.String separator;
+static { separator = null; }
+
+public static final char separatorChar;
+static { separatorChar = 0; }
+}
diff --git a/java/io/File.java b/java/io/File.java
new file mode 100644
index 0000000..0037534
--- /dev/null
+++ b/java/io/File.java
@@ -0,0 +1,2224 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.net.URI;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.ArrayList;
+import java.security.AccessController;
+import java.nio.file.Path;
+import java.nio.file.FileSystems;
+import sun.security.action.GetPropertyAction;
+
+// Android-added: Info about UTF-8 usage in filenames.
+/**
+ * An abstract representation of file and directory pathnames.
+ *
+ * <p> User interfaces and operating systems use system-dependent <em>pathname
+ * strings</em> to name files and directories. This class presents an
+ * abstract, system-independent view of hierarchical pathnames. An
+ * <em>abstract pathname</em> has two components:
+ *
+ * <ol>
+ * <li> An optional system-dependent <em>prefix</em> string,
+ * such as a disk-drive specifier, <code>"/"</code> for the UNIX root
+ * directory, or <code>"\\\\"</code> for a Microsoft Windows UNC pathname, and
+ * <li> A sequence of zero or more string <em>names</em>.
+ * </ol>
+ *
+ * The first name in an abstract pathname may be a directory name or, in the
+ * case of Microsoft Windows UNC pathnames, a hostname. Each subsequent name
+ * in an abstract pathname denotes a directory; the last name may denote
+ * either a directory or a file. The <em>empty</em> abstract pathname has no
+ * prefix and an empty name sequence.
+ *
+ * <p> The conversion of a pathname string to or from an abstract pathname is
+ * inherently system-dependent. When an abstract pathname is converted into a
+ * pathname string, each name is separated from the next by a single copy of
+ * the default <em>separator character</em>. The default name-separator
+ * character is defined by the system property <code>file.separator</code>, and
+ * is made available in the public static fields <code>{@link
+ * #separator}</code> and <code>{@link #separatorChar}</code> of this class.
+ * When a pathname string is converted into an abstract pathname, the names
+ * within it may be separated by the default name-separator character or by any
+ * other name-separator character that is supported by the underlying system.
+ *
+ * <p> A pathname, whether abstract or in string form, may be either
+ * <em>absolute</em> or <em>relative</em>. An absolute pathname is complete in
+ * that no other information is required in order to locate the file that it
+ * denotes. A relative pathname, in contrast, must be interpreted in terms of
+ * information taken from some other pathname. By default the classes in the
+ * <code>java.io</code> package always resolve relative pathnames against the
+ * current user directory. This directory is named by the system property
+ * <code>user.dir</code>, and is typically the directory in which the Java
+ * virtual machine was invoked.
+ *
+ * <p> The <em>parent</em> of an abstract pathname may be obtained by invoking
+ * the {@link #getParent} method of this class and consists of the pathname's
+ * prefix and each name in the pathname's name sequence except for the last.
+ * Each directory's absolute pathname is an ancestor of any <tt>File</tt>
+ * object with an absolute abstract pathname which begins with the directory's
+ * absolute pathname. For example, the directory denoted by the abstract
+ * pathname <tt>"/usr"</tt> is an ancestor of the directory denoted by the
+ * pathname <tt>"/usr/local/bin"</tt>.
+ *
+ * <p> The prefix concept is used to handle root directories on UNIX platforms,
+ * and drive specifiers, root directories and UNC pathnames on Microsoft Windows platforms,
+ * as follows:
+ *
+ * <ul>
+ *
+ * <li> For UNIX platforms, the prefix of an absolute pathname is always
+ * <code>"/"</code>. Relative pathnames have no prefix. The abstract pathname
+ * denoting the root directory has the prefix <code>"/"</code> and an empty
+ * name sequence.
+ *
+ * <li> For Microsoft Windows platforms, the prefix of a pathname that contains a drive
+ * specifier consists of the drive letter followed by <code>":"</code> and
+ * possibly followed by <code>"\\"</code> if the pathname is absolute. The
+ * prefix of a UNC pathname is <code>"\\\\"</code>; the hostname and the share
+ * name are the first two names in the name sequence. A relative pathname that
+ * does not specify a drive has no prefix.
+ *
+ * </ul>
+ *
+ * <p> Instances of this class may or may not denote an actual file-system
+ * object such as a file or a directory. If it does denote such an object
+ * then that object resides in a <i>partition</i>. A partition is an
+ * operating system-specific portion of storage for a file system. A single
+ * storage device (e.g. a physical disk-drive, flash memory, CD-ROM) may
+ * contain multiple partitions. The object, if any, will reside on the
+ * partition <a name="partName">named</a> by some ancestor of the absolute
+ * form of this pathname.
+ *
+ * <p> A file system may implement restrictions to certain operations on the
+ * actual file-system object, such as reading, writing, and executing. These
+ * restrictions are collectively known as <i>access permissions</i>. The file
+ * system may have multiple sets of access permissions on a single object.
+ * For example, one set may apply to the object's <i>owner</i>, and another
+ * may apply to all other users. The access permissions on an object may
+ * cause some methods in this class to fail.
+ *
+ * <p> Instances of the <code>File</code> class are immutable; that is, once
+ * created, the abstract pathname represented by a <code>File</code> object
+ * will never change.
+ *
+ * <h3>Interoperability with {@code java.nio.file} package</h3>
+ *
+ * <p> The <a href="../../java/nio/file/package-summary.html">{@code java.nio.file}</a>
+ * package defines interfaces and classes for the Java virtual machine to access
+ * files, file attributes, and file systems. This API may be used to overcome
+ * many of the limitations of the {@code java.io.File} class.
+ * The {@link #toPath toPath} method may be used to obtain a {@link
+ * Path} that uses the abstract path represented by a {@code File} object to
+ * locate a file. The resulting {@code Path} may be used with the {@link
+ * java.nio.file.Files} class to provide more efficient and extensive access to
+ * additional file operations, file attributes, and I/O exceptions to help
+ * diagnose errors when an operation on a file fails.
+ *
+ * <p>On Android strings are converted to UTF-8 byte sequences when sending filenames to
+ * the operating system, and byte sequences returned by the operating system (from the
+ * various {@code list} methods) are converted to strings by decoding them as UTF-8
+ * byte sequences.
+ *
+ * @author unascribed
+ * @since JDK1.0
+ */
+
+public class File
+ implements Serializable, Comparable<File>
+{
+
+ /**
+ * The FileSystem object representing the platform's local file system.
+ */
+ private static final FileSystem fs = DefaultFileSystem.getFileSystem();
+
+ /**
+ * This abstract pathname's normalized pathname string. A normalized
+ * pathname string uses the default name-separator character and does not
+ * contain any duplicate or redundant separators.
+ *
+ * @serial
+ */
+ private final String path;
+
+ /**
+ * Enum type that indicates the status of a file path.
+ */
+ private static enum PathStatus { INVALID, CHECKED };
+
+ /**
+ * The flag indicating whether the file path is invalid.
+ */
+ private transient PathStatus status = null;
+
+ /**
+ * Check if the file has an invalid path. Currently, the inspection of
+ * a file path is very limited, and it only covers Nul character check.
+ * Returning true means the path is definitely invalid/garbage. But
+ * returning false does not guarantee that the path is valid.
+ *
+ * @return true if the file path is invalid.
+ */
+ final boolean isInvalid() {
+ if (status == null) {
+ status = (this.path.indexOf('\u0000') < 0) ? PathStatus.CHECKED
+ : PathStatus.INVALID;
+ }
+ return status == PathStatus.INVALID;
+ }
+
+ /**
+ * The length of this abstract pathname's prefix, or zero if it has no
+ * prefix.
+ */
+ private final transient int prefixLength;
+
+ /**
+ * Returns the length of this abstract pathname's prefix.
+ * For use by FileSystem classes.
+ */
+ int getPrefixLength() {
+ return prefixLength;
+ }
+
+ /**
+ * The system-dependent default name-separator character. This field is
+ * initialized to contain the first character of the value of the system
+ * property <code>file.separator</code>. On UNIX systems the value of this
+ * field is <code>'/'</code>; on Microsoft Windows systems it is <code>'\\'</code>.
+ *
+ * @see java.lang.System#getProperty(java.lang.String)
+ */
+ public static final char separatorChar = fs.getSeparator();
+
+ /**
+ * The system-dependent default name-separator character, represented as a
+ * string for convenience. This string contains a single character, namely
+ * <code>{@link #separatorChar}</code>.
+ */
+ public static final String separator = "" + separatorChar;
+
+ /**
+ * The system-dependent path-separator character. This field is
+ * initialized to contain the first character of the value of the system
+ * property <code>path.separator</code>. This character is used to
+ * separate filenames in a sequence of files given as a <em>path list</em>.
+ * On UNIX systems, this character is <code>':'</code>; on Microsoft Windows systems it
+ * is <code>';'</code>.
+ *
+ * @see java.lang.System#getProperty(java.lang.String)
+ */
+ public static final char pathSeparatorChar = fs.getPathSeparator();
+
+ /**
+ * The system-dependent path-separator character, represented as a string
+ * for convenience. This string contains a single character, namely
+ * <code>{@link #pathSeparatorChar}</code>.
+ */
+ public static final String pathSeparator = "" + pathSeparatorChar;
+
+
+ /* -- Constructors -- */
+
+ /**
+ * Internal constructor for already-normalized pathname strings.
+ */
+ private File(String pathname, int prefixLength) {
+ this.path = pathname;
+ this.prefixLength = prefixLength;
+ }
+
+ /**
+ * Internal constructor for already-normalized pathname strings.
+ * The parameter order is used to disambiguate this method from the
+ * public(File, String) constructor.
+ */
+ private File(String child, File parent) {
+ assert parent.path != null;
+ assert (!parent.path.equals(""));
+ this.path = fs.resolve(parent.path, child);
+ this.prefixLength = parent.prefixLength;
+ }
+
+ /**
+ * Creates a new <code>File</code> instance by converting the given
+ * pathname string into an abstract pathname. If the given string is
+ * the empty string, then the result is the empty abstract pathname.
+ *
+ * @param pathname A pathname string
+ * @throws NullPointerException
+ * If the <code>pathname</code> argument is <code>null</code>
+ */
+ public File(String pathname) {
+ if (pathname == null) {
+ throw new NullPointerException();
+ }
+ this.path = fs.normalize(pathname);
+ this.prefixLength = fs.prefixLength(this.path);
+ }
+
+ /* Note: The two-argument File constructors do not interpret an empty
+ parent abstract pathname as the current user directory. An empty parent
+ instead causes the child to be resolved against the system-dependent
+ directory defined by the FileSystem.getDefaultParent method. On Unix
+ this default is "/", while on Microsoft Windows it is "\\". This is required for
+ compatibility with the original behavior of this class. */
+
+ /**
+ * Creates a new <code>File</code> instance from a parent pathname string
+ * and a child pathname string.
+ *
+ * <p> If <code>parent</code> is <code>null</code> then the new
+ * <code>File</code> instance is created as if by invoking the
+ * single-argument <code>File</code> constructor on the given
+ * <code>child</code> pathname string.
+ *
+ * <p> Otherwise the <code>parent</code> pathname string is taken to denote
+ * a directory, and the <code>child</code> pathname string is taken to
+ * denote either a directory or a file. If the <code>child</code> pathname
+ * string is absolute then it is converted into a relative pathname in a
+ * system-dependent way. If <code>parent</code> is the empty string then
+ * the new <code>File</code> instance is created by converting
+ * <code>child</code> into an abstract pathname and resolving the result
+ * against a system-dependent default directory. Otherwise each pathname
+ * string is converted into an abstract pathname and the child abstract
+ * pathname is resolved against the parent.
+ *
+ * @param parent The parent pathname string
+ * @param child The child pathname string
+ * @throws NullPointerException
+ * If <code>child</code> is <code>null</code>
+ */
+ public File(String parent, String child) {
+ if (child == null) {
+ throw new NullPointerException();
+ }
+ // BEGIN Android-changed: b/25859957, app-compat; don't substitute empty parent.
+ if (parent != null && !parent.isEmpty()) {
+ this.path = fs.resolve(fs.normalize(parent),
+ fs.normalize(child));
+ // END Android-changed: b/25859957, app-compat; don't substitute empty parent.
+ } else {
+ this.path = fs.normalize(child);
+ }
+ this.prefixLength = fs.prefixLength(this.path);
+ }
+
+ /**
+ * Creates a new <code>File</code> instance from a parent abstract
+ * pathname and a child pathname string.
+ *
+ * <p> If <code>parent</code> is <code>null</code> then the new
+ * <code>File</code> instance is created as if by invoking the
+ * single-argument <code>File</code> constructor on the given
+ * <code>child</code> pathname string.
+ *
+ * <p> Otherwise the <code>parent</code> abstract pathname is taken to
+ * denote a directory, and the <code>child</code> pathname string is taken
+ * to denote either a directory or a file. If the <code>child</code>
+ * pathname string is absolute then it is converted into a relative
+ * pathname in a system-dependent way. If <code>parent</code> is the empty
+ * abstract pathname then the new <code>File</code> instance is created by
+ * converting <code>child</code> into an abstract pathname and resolving
+ * the result against a system-dependent default directory. Otherwise each
+ * pathname string is converted into an abstract pathname and the child
+ * abstract pathname is resolved against the parent.
+ *
+ * @param parent The parent abstract pathname
+ * @param child The child pathname string
+ * @throws NullPointerException
+ * If <code>child</code> is <code>null</code>
+ */
+ public File(File parent, String child) {
+ if (child == null) {
+ throw new NullPointerException();
+ }
+ if (parent != null) {
+ if (parent.path.equals("")) {
+ this.path = fs.resolve(fs.getDefaultParent(),
+ fs.normalize(child));
+ } else {
+ this.path = fs.resolve(parent.path,
+ fs.normalize(child));
+ }
+ } else {
+ this.path = fs.normalize(child);
+ }
+ this.prefixLength = fs.prefixLength(this.path);
+ }
+
+ /**
+ * Creates a new <tt>File</tt> instance by converting the given
+ * <tt>file:</tt> URI into an abstract pathname.
+ *
+ * <p> The exact form of a <tt>file:</tt> URI is system-dependent, hence
+ * the transformation performed by this constructor is also
+ * system-dependent.
+ *
+ * <p> For a given abstract pathname <i>f</i> it is guaranteed that
+ *
+ * <blockquote><tt>
+ * new File(</tt><i> f</i><tt>.{@link #toURI() toURI}()).equals(</tt><i> f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}())
+ * </tt></blockquote>
+ *
+ * so long as the original abstract pathname, the URI, and the new abstract
+ * pathname are all created in (possibly different invocations of) the same
+ * Java virtual machine. This relationship typically does not hold,
+ * however, when a <tt>file:</tt> URI that is created in a virtual machine
+ * on one operating system is converted into an abstract pathname in a
+ * virtual machine on a different operating system.
+ *
+ * @param uri
+ * An absolute, hierarchical URI with a scheme equal to
+ * <tt>"file"</tt>, a non-empty path component, and undefined
+ * authority, query, and fragment components
+ *
+ * @throws NullPointerException
+ * If <tt>uri</tt> is <tt>null</tt>
+ *
+ * @throws IllegalArgumentException
+ * If the preconditions on the parameter do not hold
+ *
+ * @see #toURI()
+ * @see java.net.URI
+ * @since 1.4
+ */
+ public File(URI uri) {
+
+ // Check our many preconditions
+ if (!uri.isAbsolute())
+ throw new IllegalArgumentException("URI is not absolute");
+ if (uri.isOpaque())
+ throw new IllegalArgumentException("URI is not hierarchical");
+ String scheme = uri.getScheme();
+ if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
+ throw new IllegalArgumentException("URI scheme is not \"file\"");
+ if (uri.getAuthority() != null)
+ throw new IllegalArgumentException("URI has an authority component");
+ if (uri.getFragment() != null)
+ throw new IllegalArgumentException("URI has a fragment component");
+ if (uri.getQuery() != null)
+ throw new IllegalArgumentException("URI has a query component");
+ String p = uri.getPath();
+ if (p.equals(""))
+ throw new IllegalArgumentException("URI path component is empty");
+
+ // Okay, now initialize
+ p = fs.fromURIPath(p);
+ if (File.separatorChar != '/')
+ p = p.replace('/', File.separatorChar);
+ this.path = fs.normalize(p);
+ this.prefixLength = fs.prefixLength(this.path);
+ }
+
+
+ /* -- Path-component accessors -- */
+
+ /**
+ * Returns the name of the file or directory denoted by this abstract
+ * pathname. This is just the last name in the pathname's name
+ * sequence. If the pathname's name sequence is empty, then the empty
+ * string is returned.
+ *
+ * @return The name of the file or directory denoted by this abstract
+ * pathname, or the empty string if this pathname's name sequence
+ * is empty
+ */
+ public String getName() {
+ int index = path.lastIndexOf(separatorChar);
+ if (index < prefixLength) return path.substring(prefixLength);
+ return path.substring(index + 1);
+ }
+
+ /**
+ * Returns the pathname string of this abstract pathname's parent, or
+ * <code>null</code> if this pathname does not name a parent directory.
+ *
+ * <p> The <em>parent</em> of an abstract pathname consists of the
+ * pathname's prefix, if any, and each name in the pathname's name
+ * sequence except for the last. If the name sequence is empty then
+ * the pathname does not name a parent directory.
+ *
+ * @return The pathname string of the parent directory named by this
+ * abstract pathname, or <code>null</code> if this pathname
+ * does not name a parent
+ */
+ public String getParent() {
+ int index = path.lastIndexOf(separatorChar);
+ if (index < prefixLength) {
+ if ((prefixLength > 0) && (path.length() > prefixLength))
+ return path.substring(0, prefixLength);
+ return null;
+ }
+ return path.substring(0, index);
+ }
+
+ /**
+ * Returns the abstract pathname of this abstract pathname's parent,
+ * or <code>null</code> if this pathname does not name a parent
+ * directory.
+ *
+ * <p> The <em>parent</em> of an abstract pathname consists of the
+ * pathname's prefix, if any, and each name in the pathname's name
+ * sequence except for the last. If the name sequence is empty then
+ * the pathname does not name a parent directory.
+ *
+ * @return The abstract pathname of the parent directory named by this
+ * abstract pathname, or <code>null</code> if this pathname
+ * does not name a parent
+ *
+ * @since 1.2
+ */
+ public File getParentFile() {
+ String p = this.getParent();
+ if (p == null) return null;
+ return new File(p, this.prefixLength);
+ }
+
+ /**
+ * Converts this abstract pathname into a pathname string. The resulting
+ * string uses the {@link #separator default name-separator character} to
+ * separate the names in the name sequence.
+ *
+ * @return The string form of this abstract pathname
+ */
+ public String getPath() {
+ return path;
+ }
+
+
+ /* -- Path operations -- */
+
+ // Android-changed: Android-specific path information.
+ /**
+ * Tests whether this abstract pathname is absolute. The definition of
+ * absolute pathname is system dependent. On Android, absolute paths start with
+ * the character '/'.
+ *
+ * @return <code>true</code> if this abstract pathname is absolute,
+ * <code>false</code> otherwise
+ */
+ public boolean isAbsolute() {
+ return fs.isAbsolute(this);
+ }
+
+ // Android-changed: Android-specific path information.
+ /**
+ * Returns the absolute path of this file. An absolute path is a path that starts at a root
+ * of the file system. On Android, there is only one root: {@code /}.
+ *
+ * <p>A common use for absolute paths is when passing paths to a {@code Process} as
+ * command-line arguments, to remove the requirement implied by relative paths, that the
+ * child must have the same working directory as its parent.
+ *
+ * @return The absolute pathname string denoting the same file or
+ * directory as this abstract pathname
+ *
+ * @see java.io.File#isAbsolute()
+ */
+ public String getAbsolutePath() {
+ return fs.resolve(this);
+ }
+
+ /**
+ * Returns the absolute form of this abstract pathname. Equivalent to
+ * <code>new File(this.{@link #getAbsolutePath})</code>.
+ *
+ * @return The absolute abstract pathname denoting the same file or
+ * directory as this abstract pathname
+ *
+ * @throws SecurityException
+ * If a required system property value cannot be accessed.
+ *
+ * @since 1.2
+ */
+ public File getAbsoluteFile() {
+ String absPath = getAbsolutePath();
+ return new File(absPath, fs.prefixLength(absPath));
+ }
+
+ /**
+ * Returns the canonical pathname string of this abstract pathname.
+ *
+ * <p> A canonical pathname is both absolute and unique. The precise
+ * definition of canonical form is system-dependent. This method first
+ * converts this pathname to absolute form if necessary, as if by invoking the
+ * {@link #getAbsolutePath} method, and then maps it to its unique form in a
+ * system-dependent way. This typically involves removing redundant names
+ * such as <tt>"."</tt> and <tt>".."</tt> from the pathname, resolving
+ * symbolic links (on UNIX platforms), and converting drive letters to a
+ * standard case (on Microsoft Windows platforms).
+ *
+ * <p> Every pathname that denotes an existing file or directory has a
+ * unique canonical form. Every pathname that denotes a nonexistent file
+ * or directory also has a unique canonical form. The canonical form of
+ * the pathname of a nonexistent file or directory may be different from
+ * the canonical form of the same pathname after the file or directory is
+ * created. Similarly, the canonical form of the pathname of an existing
+ * file or directory may be different from the canonical form of the same
+ * pathname after the file or directory is deleted.
+ *
+ * @return The canonical pathname string denoting the same file or
+ * directory as this abstract pathname
+ *
+ * @throws IOException
+ * If an I/O error occurs, which is possible because the
+ * construction of the canonical pathname may require
+ * filesystem queries
+ *
+ * @throws SecurityException
+ * If a required system property value cannot be accessed, or
+ * if a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkRead}</code> method denies
+ * read access to the file
+ *
+ * @since JDK1.1
+ * @see Path#toRealPath
+ */
+ public String getCanonicalPath() throws IOException {
+ if (isInvalid()) {
+ throw new IOException("Invalid file path");
+ }
+ return fs.canonicalize(fs.resolve(this));
+ }
+
+ /**
+ * Returns the canonical form of this abstract pathname. Equivalent to
+ * <code>new File(this.{@link #getCanonicalPath})</code>.
+ *
+ * @return The canonical pathname string denoting the same file or
+ * directory as this abstract pathname
+ *
+ * @throws IOException
+ * If an I/O error occurs, which is possible because the
+ * construction of the canonical pathname may require
+ * filesystem queries
+ *
+ * @throws SecurityException
+ * If a required system property value cannot be accessed, or
+ * if a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkRead}</code> method denies
+ * read access to the file
+ *
+ * @since 1.2
+ * @see Path#toRealPath
+ */
+ public File getCanonicalFile() throws IOException {
+ String canonPath = getCanonicalPath();
+ return new File(canonPath, fs.prefixLength(canonPath));
+ }
+
+ private static String slashify(String path, boolean isDirectory) {
+ String p = path;
+ if (File.separatorChar != '/')
+ p = p.replace(File.separatorChar, '/');
+ if (!p.startsWith("/"))
+ p = "/" + p;
+ if (!p.endsWith("/") && isDirectory)
+ p = p + "/";
+ return p;
+ }
+
+ /**
+ * Converts this abstract pathname into a <code>file:</code> URL. The
+ * exact form of the URL is system-dependent. If it can be determined that
+ * the file denoted by this abstract pathname is a directory, then the
+ * resulting URL will end with a slash.
+ *
+ * @return A URL object representing the equivalent file URL
+ *
+ * @throws MalformedURLException
+ * If the path cannot be parsed as a URL
+ *
+ * @see #toURI()
+ * @see java.net.URI
+ * @see java.net.URI#toURL()
+ * @see java.net.URL
+ * @since 1.2
+ *
+ * @deprecated This method does not automatically escape characters that
+ * are illegal in URLs. It is recommended that new code convert an
+ * abstract pathname into a URL by first converting it into a URI, via the
+ * {@link #toURI() toURI} method, and then converting the URI into a URL
+ * via the {@link java.net.URI#toURL() URI.toURL} method.
+ */
+ @Deprecated
+ public URL toURL() throws MalformedURLException {
+ if (isInvalid()) {
+ throw new MalformedURLException("Invalid file path");
+ }
+ // Android-changed: Fix for new File("").toURL().
+ // return new URL("file", "", slashify(getAbsolutePath(), isDirectory()));
+ return new URL("file", "", slashify(getAbsolutePath(),
+ getAbsoluteFile().isDirectory()));
+ }
+
+ /**
+ * Constructs a <tt>file:</tt> URI that represents this abstract pathname.
+ *
+ * <p> The exact form of the URI is system-dependent. If it can be
+ * determined that the file denoted by this abstract pathname is a
+ * directory, then the resulting URI will end with a slash.
+ *
+ * <p> For a given abstract pathname <i>f</i>, it is guaranteed that
+ *
+ * <blockquote><tt>
+ * new {@link #File(java.net.URI) File}(</tt><i> f</i><tt>.toURI()).equals(</tt><i> f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}())
+ * </tt></blockquote>
+ *
+ * so long as the original abstract pathname, the URI, and the new abstract
+ * pathname are all created in (possibly different invocations of) the same
+ * Java virtual machine. Due to the system-dependent nature of abstract
+ * pathnames, however, this relationship typically does not hold when a
+ * <tt>file:</tt> URI that is created in a virtual machine on one operating
+ * system is converted into an abstract pathname in a virtual machine on a
+ * different operating system.
+ *
+ * <p> Note that when this abstract pathname represents a UNC pathname then
+ * all components of the UNC (including the server name component) are encoded
+ * in the {@code URI} path. The authority component is undefined, meaning
+ * that it is represented as {@code null}. The {@link Path} class defines the
+ * {@link Path#toUri toUri} method to encode the server name in the authority
+ * component of the resulting {@code URI}. The {@link #toPath toPath} method
+ * may be used to obtain a {@code Path} representing this abstract pathname.
+ *
+ * @return An absolute, hierarchical URI with a scheme equal to
+ * <tt>"file"</tt>, a path representing this abstract pathname,
+ * and undefined authority, query, and fragment components
+ * @throws SecurityException If a required system property value cannot
+ * be accessed.
+ *
+ * @see #File(java.net.URI)
+ * @see java.net.URI
+ * @see java.net.URI#toURL()
+ * @since 1.4
+ */
+ public URI toURI() {
+ try {
+ File f = getAbsoluteFile();
+ String sp = slashify(f.getPath(), f.isDirectory());
+ if (sp.startsWith("//"))
+ sp = "//" + sp;
+ return new URI("file", null, sp, null);
+ } catch (URISyntaxException x) {
+ throw new Error(x); // Can't happen
+ }
+ }
+
+
+ /* -- Attribute accessors -- */
+
+ // Android-changed: Removed inapplicable javadoc comment about special privileges.
+ /**
+ * Tests whether the application can read the file denoted by this
+ * abstract pathname.
+ *
+ * @return <code>true</code> if and only if the file specified by this
+ * abstract pathname exists <em>and</em> can be read by the
+ * application; <code>false</code> otherwise
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+ * method denies read access to the file
+ */
+ public boolean canRead() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return fs.checkAccess(this, FileSystem.ACCESS_READ);
+ }
+
+ // Android-changed: Removed inapplicable javadoc comment about special privileges.
+ /**
+ * Tests whether the application can modify the file denoted by this
+ * abstract pathname.
+ *
+ * @return <code>true</code> if and only if the file system actually
+ * contains a file denoted by this abstract pathname <em>and</em>
+ * the application is allowed to write to the file;
+ * <code>false</code> otherwise.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method denies write access to the file
+ */
+ public boolean canWrite() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkWrite(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return fs.checkAccess(this, FileSystem.ACCESS_WRITE);
+ }
+
+ /**
+ * Tests whether the file or directory denoted by this abstract pathname
+ * exists.
+ *
+ * @return <code>true</code> if and only if the file or directory denoted
+ * by this abstract pathname exists; <code>false</code> otherwise
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+ * method denies read access to the file or directory
+ */
+ public boolean exists() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+
+ // Android-changed: b/25878034 work around SELinux stat64 denial.
+ return fs.checkAccess(this, FileSystem.ACCESS_OK);
+ }
+
+ /**
+ * Tests whether the file denoted by this abstract pathname is a
+ * directory.
+ *
+ * <p> Where it is required to distinguish an I/O exception from the case
+ * that the file is not a directory, or where several attributes of the
+ * same file are required at the same time, then the {@link
+ * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
+ * Files.readAttributes} method may be used.
+ *
+ * @return <code>true</code> if and only if the file denoted by this
+ * abstract pathname exists <em>and</em> is a directory;
+ * <code>false</code> otherwise
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+ * method denies read access to the file
+ */
+ public boolean isDirectory() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return ((fs.getBooleanAttributes(this) & FileSystem.BA_DIRECTORY)
+ != 0);
+ }
+
+ /**
+ * Tests whether the file denoted by this abstract pathname is a normal
+ * file. A file is <em>normal</em> if it is not a directory and, in
+ * addition, satisfies other system-dependent criteria. Any non-directory
+ * file created by a Java application is guaranteed to be a normal file.
+ *
+ * <p> Where it is required to distinguish an I/O exception from the case
+ * that the file is not a normal file, or where several attributes of the
+ * same file are required at the same time, then the {@link
+ * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
+ * Files.readAttributes} method may be used.
+ *
+ * @return <code>true</code> if and only if the file denoted by this
+ * abstract pathname exists <em>and</em> is a normal file;
+ * <code>false</code> otherwise
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+ * method denies read access to the file
+ */
+ public boolean isFile() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return ((fs.getBooleanAttributes(this) & FileSystem.BA_REGULAR) != 0);
+ }
+
+ /**
+ * Tests whether the file named by this abstract pathname is a hidden
+ * file. The exact definition of <em>hidden</em> is system-dependent. On
+ * UNIX systems, a file is considered to be hidden if its name begins with
+ * a period character (<code>'.'</code>). On Microsoft Windows systems, a file is
+ * considered to be hidden if it has been marked as such in the filesystem.
+ *
+ * @return <code>true</code> if and only if the file denoted by this
+ * abstract pathname is hidden according to the conventions of the
+ * underlying platform
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+ * method denies read access to the file
+ *
+ * @since 1.2
+ */
+ public boolean isHidden() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return ((fs.getBooleanAttributes(this) & FileSystem.BA_HIDDEN) != 0);
+ }
+
+ /**
+ * Returns the time that the file denoted by this abstract pathname was
+ * last modified.
+ *
+ * <p> Where it is required to distinguish an I/O exception from the case
+ * where {@code 0L} is returned, or where several attributes of the
+ * same file are required at the same time, or where the time of last
+ * access or the creation time are required, then the {@link
+ * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
+ * Files.readAttributes} method may be used.
+ *
+ * @return A <code>long</code> value representing the time the file was
+ * last modified, measured in milliseconds since the epoch
+ * (00:00:00 GMT, January 1, 1970), or <code>0L</code> if the
+ * file does not exist or if an I/O error occurs
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+ * method denies read access to the file
+ */
+ public long lastModified() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(path);
+ }
+ if (isInvalid()) {
+ return 0L;
+ }
+ return fs.getLastModifiedTime(this);
+ }
+
+ /**
+ * Returns the length of the file denoted by this abstract pathname.
+ * The return value is unspecified if this pathname denotes a directory.
+ *
+ * <p> Where it is required to distinguish an I/O exception from the case
+ * that {@code 0L} is returned, or where several attributes of the same file
+ * are required at the same time, then the {@link
+ * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
+ * Files.readAttributes} method may be used.
+ *
+ * @return The length, in bytes, of the file denoted by this abstract
+ * pathname, or <code>0L</code> if the file does not exist. Some
+ * operating systems may return <code>0L</code> for pathnames
+ * denoting system-dependent entities such as devices or pipes.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+ * method denies read access to the file
+ */
+ public long length() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(path);
+ }
+ if (isInvalid()) {
+ return 0L;
+ }
+ return fs.getLength(this);
+ }
+
+
+ /* -- File operations -- */
+
+ /**
+ * Atomically creates a new, empty file named by this abstract pathname if
+ * and only if a file with this name does not yet exist. The check for the
+ * existence of the file and the creation of the file if it does not exist
+ * are a single operation that is atomic with respect to all other
+ * filesystem activities that might affect the file.
+ * <P>
+ * Note: this method should <i>not</i> be used for file-locking, as
+ * the resulting protocol cannot be made to work reliably. The
+ * {@link java.nio.channels.FileLock FileLock}
+ * facility should be used instead.
+ *
+ * @return <code>true</code> if the named file does not exist and was
+ * successfully created; <code>false</code> if the named file
+ * already exists
+ *
+ * @throws IOException
+ * If an I/O error occurred
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method denies write access to the file
+ *
+ * @since 1.2
+ */
+ public boolean createNewFile() throws IOException {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) security.checkWrite(path);
+ if (isInvalid()) {
+ throw new IOException("Invalid file path");
+ }
+ return fs.createFileExclusively(path);
+ }
+
+ /**
+ * Deletes the file or directory denoted by this abstract pathname. If
+ * this pathname denotes a directory, then the directory must be empty in
+ * order to be deleted.
+ *
+ * <p> Note that the {@link java.nio.file.Files} class defines the {@link
+ * java.nio.file.Files#delete(Path) delete} method to throw an {@link IOException}
+ * when a file cannot be deleted. This is useful for error reporting and to
+ * diagnose why a file cannot be deleted.
+ *
+ * @return <code>true</code> if and only if the file or directory is
+ * successfully deleted; <code>false</code> otherwise
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkDelete}</code> method denies
+ * delete access to the file
+ */
+ public boolean delete() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkDelete(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return fs.delete(this);
+ }
+
+ // Android-added: Additional information about Android behaviour.
+ /**
+ * Requests that the file or directory denoted by this abstract
+ * pathname be deleted when the virtual machine terminates.
+ * Files (or directories) are deleted in the reverse order that
+ * they are registered. Invoking this method to delete a file or
+ * directory that is already registered for deletion has no effect.
+ * Deletion will be attempted only for normal termination of the
+ * virtual machine, as defined by the Java Language Specification.
+ *
+ * <p> Once deletion has been requested, it is not possible to cancel the
+ * request. This method should therefore be used with care.
+ *
+ * <P>
+ * Note: this method should <i>not</i> be used for file-locking, as
+ * the resulting protocol cannot be made to work reliably. The
+ * {@link java.nio.channels.FileLock FileLock}
+ * facility should be used instead.
+ *
+ * <p><i>Note that on Android, the application lifecycle does not include VM termination,
+ * so calling this method will not ensure that files are deleted</i>. Instead, you should
+ * use the most appropriate out of:
+ * <ul>
+ * <li>Use a {@code finally} clause to manually invoke {@link #delete}.
+ * <li>Maintain your own set of files to delete, and process it at an appropriate point
+ * in your application's lifecycle.
+ * <li>Use the Unix trick of deleting the file as soon as all readers and writers have
+ * opened it. No new readers/writers will be able to access the file, but all existing
+ * ones will still have access until the last one closes the file.
+ * </ul>
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkDelete}</code> method denies
+ * delete access to the file
+ *
+ * @see #delete
+ *
+ * @since 1.2
+ */
+ public void deleteOnExit() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkDelete(path);
+ }
+ if (isInvalid()) {
+ return;
+ }
+ DeleteOnExitHook.add(path);
+ }
+
+ /**
+ * Returns an array of strings naming the files and directories in the
+ * directory denoted by this abstract pathname.
+ *
+ * <p> If this abstract pathname does not denote a directory, then this
+ * method returns {@code null}. Otherwise an array of strings is
+ * returned, one for each file or directory in the directory. Names
+ * denoting the directory itself and the directory's parent directory are
+ * not included in the result. Each string is a file name rather than a
+ * complete path.
+ *
+ * <p> There is no guarantee that the name strings in the resulting array
+ * will appear in any specific order; they are not, in particular,
+ * guaranteed to appear in alphabetical order.
+ *
+ * <p> Note that the {@link java.nio.file.Files} class defines the {@link
+ * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method to
+ * open a directory and iterate over the names of the files in the directory.
+ * This may use less resources when working with very large directories, and
+ * may be more responsive when working with remote directories.
+ *
+ * @return An array of strings naming the files and directories in the
+ * directory denoted by this abstract pathname. The array will be
+ * empty if the directory is empty. Returns {@code null} if
+ * this abstract pathname does not denote a directory, or if an
+ * I/O error occurs.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its {@link
+ * SecurityManager#checkRead(String)} method denies read access to
+ * the directory
+ */
+ public String[] list() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(path);
+ }
+ if (isInvalid()) {
+ return null;
+ }
+ return fs.list(this);
+ }
+
+ /**
+ * Returns an array of strings naming the files and directories in the
+ * directory denoted by this abstract pathname that satisfy the specified
+ * filter. The behavior of this method is the same as that of the
+ * {@link #list()} method, except that the strings in the returned array
+ * must satisfy the filter. If the given {@code filter} is {@code null}
+ * then all names are accepted. Otherwise, a name satisfies the filter if
+ * and only if the value {@code true} results when the {@link
+ * FilenameFilter#accept FilenameFilter.accept(File, String)} method
+ * of the filter is invoked on this abstract pathname and the name of a
+ * file or directory in the directory that it denotes.
+ *
+ * @param filter
+ * A filename filter
+ *
+ * @return An array of strings naming the files and directories in the
+ * directory denoted by this abstract pathname that were accepted
+ * by the given {@code filter}. The array will be empty if the
+ * directory is empty or if no names were accepted by the filter.
+ * Returns {@code null} if this abstract pathname does not denote
+ * a directory, or if an I/O error occurs.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its {@link
+ * SecurityManager#checkRead(String)} method denies read access to
+ * the directory
+ *
+ * @see java.nio.file.Files#newDirectoryStream(Path,String)
+ */
+ public String[] list(FilenameFilter filter) {
+ String names[] = list();
+ if ((names == null) || (filter == null)) {
+ return names;
+ }
+ List<String> v = new ArrayList<>();
+ for (int i = 0 ; i < names.length ; i++) {
+ if (filter.accept(this, names[i])) {
+ v.add(names[i]);
+ }
+ }
+ return v.toArray(new String[v.size()]);
+ }
+
+ /**
+ * Returns an array of abstract pathnames denoting the files in the
+ * directory denoted by this abstract pathname.
+ *
+ * <p> If this abstract pathname does not denote a directory, then this
+ * method returns {@code null}. Otherwise an array of {@code File} objects
+ * is returned, one for each file or directory in the directory. Pathnames
+ * denoting the directory itself and the directory's parent directory are
+ * not included in the result. Each resulting abstract pathname is
+ * constructed from this abstract pathname using the {@link #File(File,
+ * String) File(File, String)} constructor. Therefore if this
+ * pathname is absolute then each resulting pathname is absolute; if this
+ * pathname is relative then each resulting pathname will be relative to
+ * the same directory.
+ *
+ * <p> There is no guarantee that the name strings in the resulting array
+ * will appear in any specific order; they are not, in particular,
+ * guaranteed to appear in alphabetical order.
+ *
+ * <p> Note that the {@link java.nio.file.Files} class defines the {@link
+ * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method
+ * to open a directory and iterate over the names of the files in the
+ * directory. This may use less resources when working with very large
+ * directories.
+ *
+ * @return An array of abstract pathnames denoting the files and
+ * directories in the directory denoted by this abstract pathname.
+ * The array will be empty if the directory is empty. Returns
+ * {@code null} if this abstract pathname does not denote a
+ * directory, or if an I/O error occurs.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its {@link
+ * SecurityManager#checkRead(String)} method denies read access to
+ * the directory
+ *
+ * @since 1.2
+ */
+ public File[] listFiles() {
+ String[] ss = list();
+ if (ss == null) return null;
+ int n = ss.length;
+ File[] fs = new File[n];
+ for (int i = 0; i < n; i++) {
+ fs[i] = new File(ss[i], this);
+ }
+ return fs;
+ }
+
+ /**
+ * Returns an array of abstract pathnames denoting the files and
+ * directories in the directory denoted by this abstract pathname that
+ * satisfy the specified filter. The behavior of this method is the same
+ * as that of the {@link #listFiles()} method, except that the pathnames in
+ * the returned array must satisfy the filter. If the given {@code filter}
+ * is {@code null} then all pathnames are accepted. Otherwise, a pathname
+ * satisfies the filter if and only if the value {@code true} results when
+ * the {@link FilenameFilter#accept
+ * FilenameFilter.accept(File, String)} method of the filter is
+ * invoked on this abstract pathname and the name of a file or directory in
+ * the directory that it denotes.
+ *
+ * @param filter
+ * A filename filter
+ *
+ * @return An array of abstract pathnames denoting the files and
+ * directories in the directory denoted by this abstract pathname.
+ * The array will be empty if the directory is empty. Returns
+ * {@code null} if this abstract pathname does not denote a
+ * directory, or if an I/O error occurs.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its {@link
+ * SecurityManager#checkRead(String)} method denies read access to
+ * the directory
+ *
+ * @since 1.2
+ * @see java.nio.file.Files#newDirectoryStream(Path,String)
+ */
+ public File[] listFiles(FilenameFilter filter) {
+ String ss[] = list();
+ if (ss == null) return null;
+ ArrayList<File> files = new ArrayList<>();
+ for (String s : ss)
+ if ((filter == null) || filter.accept(this, s))
+ files.add(new File(s, this));
+ return files.toArray(new File[files.size()]);
+ }
+
+ /**
+ * Returns an array of abstract pathnames denoting the files and
+ * directories in the directory denoted by this abstract pathname that
+ * satisfy the specified filter. The behavior of this method is the same
+ * as that of the {@link #listFiles()} method, except that the pathnames in
+ * the returned array must satisfy the filter. If the given {@code filter}
+ * is {@code null} then all pathnames are accepted. Otherwise, a pathname
+ * satisfies the filter if and only if the value {@code true} results when
+ * the {@link FileFilter#accept FileFilter.accept(File)} method of the
+ * filter is invoked on the pathname.
+ *
+ * @param filter
+ * A file filter
+ *
+ * @return An array of abstract pathnames denoting the files and
+ * directories in the directory denoted by this abstract pathname.
+ * The array will be empty if the directory is empty. Returns
+ * {@code null} if this abstract pathname does not denote a
+ * directory, or if an I/O error occurs.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its {@link
+ * SecurityManager#checkRead(String)} method denies read access to
+ * the directory
+ *
+ * @since 1.2
+ * @see java.nio.file.Files#newDirectoryStream(Path,java.nio.file.DirectoryStream.Filter)
+ */
+ public File[] listFiles(FileFilter filter) {
+ String ss[] = list();
+ if (ss == null) return null;
+ ArrayList<File> files = new ArrayList<>();
+ for (String s : ss) {
+ File f = new File(s, this);
+ if ((filter == null) || filter.accept(f))
+ files.add(f);
+ }
+ return files.toArray(new File[files.size()]);
+ }
+
+ /**
+ * Creates the directory named by this abstract pathname.
+ *
+ * @return <code>true</code> if and only if the directory was
+ * created; <code>false</code> otherwise
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method does not permit the named directory to be created
+ */
+ public boolean mkdir() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkWrite(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return fs.createDirectory(this);
+ }
+
+ /**
+ * Creates the directory named by this abstract pathname, including any
+ * necessary but nonexistent parent directories. Note that if this
+ * operation fails it may have succeeded in creating some of the necessary
+ * parent directories.
+ *
+ * @return <code>true</code> if and only if the directory was created,
+ * along with all necessary parent directories; <code>false</code>
+ * otherwise
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+ * method does not permit verification of the existence of the
+ * named directory and all necessary parent directories; or if
+ * the <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method does not permit the named directory and all necessary
+ * parent directories to be created
+ */
+ public boolean mkdirs() {
+ if (exists()) {
+ return false;
+ }
+ if (mkdir()) {
+ return true;
+ }
+ File canonFile = null;
+ try {
+ canonFile = getCanonicalFile();
+ } catch (IOException e) {
+ return false;
+ }
+
+ File parent = canonFile.getParentFile();
+ return (parent != null && (parent.mkdirs() || parent.exists()) &&
+ canonFile.mkdir());
+ }
+
+ // Android-changed: Replaced generic platform info with Android specific one.
+ /**
+ * Renames the file denoted by this abstract pathname.
+ *
+ * <p>Many failures are possible. Some of the more likely failures include:
+ * <ul>
+ * <li>Write permission is required on the directories containing both the source and
+ * destination paths.
+ * <li>Search permission is required for all parents of both paths.
+ * <li>Both paths be on the same mount point. On Android, applications are most likely to hit
+ * this restriction when attempting to copy between internal storage and an SD card.
+ * </ul>
+ *
+ * <p>The return value should always be checked to make sure
+ * that the rename operation was successful.
+ *
+ * <p> Note that the {@link java.nio.file.Files} class defines the {@link
+ * java.nio.file.Files#move move} method to move or rename a file in a
+ * platform independent manner.
+ *
+ * @param dest The new abstract pathname for the named file
+ *
+ * @return <code>true</code> if and only if the renaming succeeded;
+ * <code>false</code> otherwise
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method denies write access to either the old or new pathnames
+ *
+ * @throws NullPointerException
+ * If parameter <code>dest</code> is <code>null</code>
+ */
+ public boolean renameTo(File dest) {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkWrite(path);
+ security.checkWrite(dest.path);
+ }
+ if (dest == null) {
+ throw new NullPointerException();
+ }
+ if (this.isInvalid() || dest.isInvalid()) {
+ return false;
+ }
+ return fs.rename(this, dest);
+ }
+
+ /**
+ * Sets the last-modified time of the file or directory named by this
+ * abstract pathname.
+ *
+ * <p> All platforms support file-modification times to the nearest second,
+ * but some provide more precision. The argument will be truncated to fit
+ * the supported precision. If the operation succeeds and no intervening
+ * operations on the file take place, then the next invocation of the
+ * <code>{@link #lastModified}</code> method will return the (possibly
+ * truncated) <code>time</code> argument that was passed to this method.
+ *
+ * @param time The new last-modified time, measured in milliseconds since
+ * the epoch (00:00:00 GMT, January 1, 1970)
+ *
+ * @return <code>true</code> if and only if the operation succeeded;
+ * <code>false</code> otherwise
+ *
+ * @throws IllegalArgumentException If the argument is negative
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method denies write access to the named file
+ *
+ * @since 1.2
+ */
+ public boolean setLastModified(long time) {
+ if (time < 0) throw new IllegalArgumentException("Negative time");
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkWrite(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return fs.setLastModifiedTime(this, time);
+ }
+
+ // Android-changed: Removed inapplicable javadoc comment about special privileges.
+ /**
+ * Marks the file or directory named by this abstract pathname so that
+ * only read operations are allowed. After invoking this method the file
+ * or directory will not change until it is either deleted or marked
+ * to allow write access. Whether or not a read-only file or
+ * directory may be deleted depends upon the underlying system.
+ *
+ * @return <code>true</code> if and only if the operation succeeded;
+ * <code>false</code> otherwise
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method denies write access to the named file
+ *
+ * @since 1.2
+ */
+ public boolean setReadOnly() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkWrite(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return fs.setReadOnly(this);
+ }
+
+ // Android-changed: Removed inapplicable javadoc comment about special privileges.
+ /**
+ * Sets the owner's or everybody's write permission for this abstract
+ * pathname.
+ *
+ * <p> The {@link java.nio.file.Files} class defines methods that operate on
+ * file attributes including file permissions. This may be used when finer
+ * manipulation of file permissions is required.
+ *
+ * @param writable
+ * If <code>true</code>, sets the access permission to allow write
+ * operations; if <code>false</code> to disallow write operations
+ *
+ * @param ownerOnly
+ * If <code>true</code>, the write permission applies only to the
+ * owner's write permission; otherwise, it applies to everybody. If
+ * the underlying file system can not distinguish the owner's write
+ * permission from that of others, then the permission will apply to
+ * everybody, regardless of this value.
+ *
+ * @return <code>true</code> if and only if the operation succeeded. The
+ * operation will fail if the user does not have permission to change
+ * the access permissions of this abstract pathname.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method denies write access to the named file
+ *
+ * @since 1.6
+ */
+ public boolean setWritable(boolean writable, boolean ownerOnly) {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkWrite(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return fs.setPermission(this, FileSystem.ACCESS_WRITE, writable, ownerOnly);
+ }
+
+ // Android-changed: Removed inapplicable javadoc comment about special privileges.
+ /**
+ * A convenience method to set the owner's write permission for this abstract
+ * pathname.
+ *
+ * <p> An invocation of this method of the form <tt>file.setWritable(arg)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * file.setWritable(arg, true) </pre>
+ *
+ * @param writable
+ * If <code>true</code>, sets the access permission to allow write
+ * operations; if <code>false</code> to disallow write operations
+ *
+ * @return <code>true</code> if and only if the operation succeeded. The
+ * operation will fail if the user does not have permission to
+ * change the access permissions of this abstract pathname.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method denies write access to the file
+ *
+ * @since 1.6
+ */
+ public boolean setWritable(boolean writable) {
+ return setWritable(writable, true);
+ }
+
+ // Android-changed: Removed inapplicable javadoc comment about special privileges.
+ /**
+ * Sets the owner's or everybody's read permission for this abstract
+ * pathname.
+ *
+ * <p> The {@link java.nio.file.Files} class defines methods that operate on
+ * file attributes including file permissions. This may be used when finer
+ * manipulation of file permissions is required.
+ *
+ * @param readable
+ * If <code>true</code>, sets the access permission to allow read
+ * operations; if <code>false</code> to disallow read operations
+ *
+ * @param ownerOnly
+ * If <code>true</code>, the read permission applies only to the
+ * owner's read permission; otherwise, it applies to everybody. If
+ * the underlying file system can not distinguish the owner's read
+ * permission from that of others, then the permission will apply to
+ * everybody, regardless of this value.
+ *
+ * @return <code>true</code> if and only if the operation succeeded. The
+ * operation will fail if the user does not have permission to
+ * change the access permissions of this abstract pathname. If
+ * <code>readable</code> is <code>false</code> and the underlying
+ * file system does not implement a read permission, then the
+ * operation will fail.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method denies write access to the file
+ *
+ * @since 1.6
+ */
+ public boolean setReadable(boolean readable, boolean ownerOnly) {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkWrite(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return fs.setPermission(this, FileSystem.ACCESS_READ, readable, ownerOnly);
+ }
+
+ // Android-changed: Removed inapplicable javadoc comment about special privileges.
+ /**
+ * A convenience method to set the owner's read permission for this abstract
+ * pathname.
+ *
+ * <p>An invocation of this method of the form <tt>file.setReadable(arg)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * file.setReadable(arg, true) </pre>
+ *
+ * @param readable
+ * If <code>true</code>, sets the access permission to allow read
+ * operations; if <code>false</code> to disallow read operations
+ *
+ * @return <code>true</code> if and only if the operation succeeded. The
+ * operation will fail if the user does not have permission to
+ * change the access permissions of this abstract pathname. If
+ * <code>readable</code> is <code>false</code> and the underlying
+ * file system does not implement a read permission, then the
+ * operation will fail.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method denies write access to the file
+ *
+ * @since 1.6
+ */
+ public boolean setReadable(boolean readable) {
+ return setReadable(readable, true);
+ }
+
+ // Android-changed: Removed inapplicable javadoc comment about special privileges.
+ /**
+ * Sets the owner's or everybody's execute permission for this abstract
+ * pathname.
+ *
+ * <p> The {@link java.nio.file.Files} class defines methods that operate on
+ * file attributes including file permissions. This may be used when finer
+ * manipulation of file permissions is required.
+ *
+ * @param executable
+ * If <code>true</code>, sets the access permission to allow execute
+ * operations; if <code>false</code> to disallow execute operations
+ *
+ * @param ownerOnly
+ * If <code>true</code>, the execute permission applies only to the
+ * owner's execute permission; otherwise, it applies to everybody.
+ * If the underlying file system can not distinguish the owner's
+ * execute permission from that of others, then the permission will
+ * apply to everybody, regardless of this value.
+ *
+ * @return <code>true</code> if and only if the operation succeeded. The
+ * operation will fail if the user does not have permission to
+ * change the access permissions of this abstract pathname. If
+ * <code>executable</code> is <code>false</code> and the underlying
+ * file system does not implement an execute permission, then the
+ * operation will fail.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method denies write access to the file
+ *
+ * @since 1.6
+ */
+ public boolean setExecutable(boolean executable, boolean ownerOnly) {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkWrite(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return fs.setPermission(this, FileSystem.ACCESS_EXECUTE, executable, ownerOnly);
+ }
+
+ // Android-changed: Removed inapplicable javadoc comment about special privileges.
+ /**
+ * A convenience method to set the owner's execute permission for this
+ * abstract pathname.
+ *
+ * <p>An invocation of this method of the form <tt>file.setExcutable(arg)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * file.setExecutable(arg, true) </pre>
+ *
+ * @param executable
+ * If <code>true</code>, sets the access permission to allow execute
+ * operations; if <code>false</code> to disallow execute operations
+ *
+ * @return <code>true</code> if and only if the operation succeeded. The
+ * operation will fail if the user does not have permission to
+ * change the access permissions of this abstract pathname. If
+ * <code>executable</code> is <code>false</code> and the underlying
+ * file system does not implement an execute permission, then the
+ * operation will fail.
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method denies write access to the file
+ *
+ * @since 1.6
+ */
+ public boolean setExecutable(boolean executable) {
+ return setExecutable(executable, true);
+ }
+
+ // Android-changed: Removed inapplicable javadoc comment about special privileges.
+ /**
+ * Tests whether the application can execute the file denoted by this
+ * abstract pathname.
+ *
+ * @return <code>true</code> if and only if the abstract pathname exists
+ * <em>and</em> the application is allowed to execute the file
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkExec(java.lang.String)}</code>
+ * method denies execute access to the file
+ *
+ * @since 1.6
+ */
+ public boolean canExecute() {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkExec(path);
+ }
+ if (isInvalid()) {
+ return false;
+ }
+ return fs.checkAccess(this, FileSystem.ACCESS_EXECUTE);
+ }
+
+
+ /* -- Filesystem interface -- */
+
+ // Android-changed: Replaced generic platform info with Android specific one.
+ /**
+ * Returns the file system roots. On Android and other Unix systems, there is
+ * a single root, {@code /}.
+ */
+ public static File[] listRoots() {
+ return fs.listRoots();
+ }
+
+
+ /* -- Disk usage -- */
+
+ /**
+ * Returns the size of the partition <a href="#partName">named</a> by this
+ * abstract pathname.
+ *
+ * @return The size, in bytes, of the partition or <tt>0L</tt> if this
+ * abstract pathname does not name a partition
+ *
+ * @throws SecurityException
+ * If a security manager has been installed and it denies
+ * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
+ * or its {@link SecurityManager#checkRead(String)} method denies
+ * read access to the file named by this abstract pathname
+ *
+ * @since 1.6
+ */
+ public long getTotalSpace() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+ sm.checkRead(path);
+ }
+ if (isInvalid()) {
+ return 0L;
+ }
+ return fs.getSpace(this, FileSystem.SPACE_TOTAL);
+ }
+
+ /**
+ * Returns the number of unallocated bytes in the partition <a
+ * href="#partName">named</a> by this abstract path name.
+ *
+ * <p> The returned number of unallocated bytes is a hint, but not
+ * a guarantee, that it is possible to use most or any of these
+ * bytes. The number of unallocated bytes is most likely to be
+ * accurate immediately after this call. It is likely to be made
+ * inaccurate by any external I/O operations including those made
+ * on the system outside of this virtual machine. This method
+ * makes no guarantee that write operations to this file system
+ * will succeed.
+ *
+ * @return The number of unallocated bytes on the partition or <tt>0L</tt>
+ * if the abstract pathname does not name a partition. This
+ * value will be less than or equal to the total file system size
+ * returned by {@link #getTotalSpace}.
+ *
+ * @throws SecurityException
+ * If a security manager has been installed and it denies
+ * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
+ * or its {@link SecurityManager#checkRead(String)} method denies
+ * read access to the file named by this abstract pathname
+ *
+ * @since 1.6
+ */
+ public long getFreeSpace() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+ sm.checkRead(path);
+ }
+ if (isInvalid()) {
+ return 0L;
+ }
+ return fs.getSpace(this, FileSystem.SPACE_FREE);
+ }
+
+ // Android-added: Replaced generic platform info with Android specific one.
+ /**
+ * Returns the number of bytes available to this virtual machine on the
+ * partition <a href="#partName">named</a> by this abstract pathname. When
+ * possible, this method checks for write permissions and other operating
+ * system restrictions and will therefore usually provide a more accurate
+ * estimate of how much new data can actually be written than {@link
+ * #getFreeSpace}.
+ *
+ * <p> The returned number of available bytes is a hint, but not a
+ * guarantee, that it is possible to use most or any of these bytes. The
+ * number of unallocated bytes is most likely to be accurate immediately
+ * after this call. It is likely to be made inaccurate by any external
+ * I/O operations including those made on the system outside of this
+ * virtual machine. This method makes no guarantee that write operations
+ * to this file system will succeed.
+ *
+ * <p> On Android (and other Unix-based systems), this method returns the number of free bytes
+ * available to non-root users, regardless of whether you're actually running as root,
+ * and regardless of any quota or other restrictions that might apply to the user.
+ * (The {@code getFreeSpace} method returns the number of bytes potentially available to root.)
+ *
+ * @return The number of available bytes on the partition or <tt>0L</tt>
+ * if the abstract pathname does not name a partition. On
+ * systems where this information is not available, this method
+ * will be equivalent to a call to {@link #getFreeSpace}.
+ *
+ * @throws SecurityException
+ * If a security manager has been installed and it denies
+ * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
+ * or its {@link SecurityManager#checkRead(String)} method denies
+ * read access to the file named by this abstract pathname
+ *
+ * @since 1.6
+ */
+ public long getUsableSpace() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+ sm.checkRead(path);
+ }
+ if (isInvalid()) {
+ return 0L;
+ }
+ return fs.getSpace(this, FileSystem.SPACE_USABLE);
+ }
+
+ /* -- Temporary files -- */
+
+ private static class TempDirectory {
+ private TempDirectory() { }
+
+ // Android-changed: Don't cache java.io.tmpdir value temporary directory location.
+ /*
+ private static final File tmpdir = new File(AccessController
+ .doPrivileged(new GetPropertyAction("java.io.tmpdir")));
+ static File location() {
+ return tmpdir;
+ }
+ */
+
+ // file name generation
+ // private static final SecureRandom random = new SecureRandom();
+ static File generateFile(String prefix, String suffix, File dir)
+ throws IOException
+ {
+ // Android-changed: Use Math.randomIntInternal.
+ // This (pseudo) random number is initialized post-fork.
+
+ long n = Math.randomLongInternal();
+ if (n == Long.MIN_VALUE) {
+ n = 0; // corner case
+ } else {
+ n = Math.abs(n);
+ }
+
+ // Android-changed: Reject invalid file prefixes.
+ // Use only the file name from the supplied prefix
+ // prefix = (new File(prefix)).getName();
+
+ String name = prefix + Long.toString(n) + suffix;
+ File f = new File(dir, name);
+ if (!name.equals(f.getName()) || f.isInvalid()) {
+ if (System.getSecurityManager() != null)
+ throw new IOException("Unable to create temporary file");
+ else
+ throw new IOException("Unable to create temporary file, " + f);
+ }
+ return f;
+ }
+ }
+
+ /**
+ * <p> Creates a new empty file in the specified directory, using the
+ * given prefix and suffix strings to generate its name. If this method
+ * returns successfully then it is guaranteed that:
+ *
+ * <ol>
+ * <li> The file denoted by the returned abstract pathname did not exist
+ * before this method was invoked, and
+ * <li> Neither this method nor any of its variants will return the same
+ * abstract pathname again in the current invocation of the virtual
+ * machine.
+ * </ol>
+ *
+ * This method provides only part of a temporary-file facility. To arrange
+ * for a file created by this method to be deleted automatically, use the
+ * <code>{@link #deleteOnExit}</code> method.
+ *
+ * <p> The <code>prefix</code> argument must be at least three characters
+ * long. It is recommended that the prefix be a short, meaningful string
+ * such as <code>"hjb"</code> or <code>"mail"</code>. The
+ * <code>suffix</code> argument may be <code>null</code>, in which case the
+ * suffix <code>".tmp"</code> will be used.
+ *
+ * <p> To create the new file, the prefix and the suffix may first be
+ * adjusted to fit the limitations of the underlying platform. If the
+ * prefix is too long then it will be truncated, but its first three
+ * characters will always be preserved. If the suffix is too long then it
+ * too will be truncated, but if it begins with a period character
+ * (<code>'.'</code>) then the period and the first three characters
+ * following it will always be preserved. Once these adjustments have been
+ * made the name of the new file will be generated by concatenating the
+ * prefix, five or more internally-generated characters, and the suffix.
+ *
+ * <p> If the <code>directory</code> argument is <code>null</code> then the
+ * system-dependent default temporary-file directory will be used. The
+ * default temporary-file directory is specified by the system property
+ * <code>java.io.tmpdir</code>. On UNIX systems the default value of this
+ * property is typically <code>"/tmp"</code> or <code>"/var/tmp"</code>; on
+ * Microsoft Windows systems it is typically <code>"C:\\WINNT\\TEMP"</code>. A different
+ * value may be given to this system property when the Java virtual machine
+ * is invoked, but programmatic changes to this property are not guaranteed
+ * to have any effect upon the temporary directory used by this method.
+ *
+ * @param prefix The prefix string to be used in generating the file's
+ * name; must be at least three characters long
+ *
+ * @param suffix The suffix string to be used in generating the file's
+ * name; may be <code>null</code>, in which case the
+ * suffix <code>".tmp"</code> will be used
+ *
+ * @param directory The directory in which the file is to be created, or
+ * <code>null</code> if the default temporary-file
+ * directory is to be used
+ *
+ * @return An abstract pathname denoting a newly-created empty file
+ *
+ * @throws IllegalArgumentException
+ * If the <code>prefix</code> argument contains fewer than three
+ * characters
+ *
+ * @throws IOException If a file could not be created
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method does not allow a file to be created
+ *
+ * @since 1.2
+ */
+ public static File createTempFile(String prefix, String suffix,
+ File directory)
+ throws IOException
+ {
+ if (prefix.length() < 3)
+ throw new IllegalArgumentException("Prefix string too short");
+ if (suffix == null)
+ suffix = ".tmp";
+
+ // Android-changed: Handle java.io.tmpdir changes.
+ File tmpdir = (directory != null) ? directory
+ : new File(System.getProperty("java.io.tmpdir", "."));
+ //SecurityManager sm = System.getSecurityManager();
+ File f;
+ do {
+ f = TempDirectory.generateFile(prefix, suffix, tmpdir);
+
+ // Android-changed: sm is always null on Android.
+ /*
+ if (sm != null) {
+ try {
+ sm.checkWrite(f.getPath());
+ } catch (SecurityException se) {
+ // don't reveal temporary directory location
+ if (directory == null)
+ throw new SecurityException("Unable to create temporary file");
+ throw se;
+ }
+ }
+ */
+ } while ((fs.getBooleanAttributes(f) & FileSystem.BA_EXISTS) != 0);
+
+ if (!fs.createFileExclusively(f.getPath()))
+ throw new IOException("Unable to create temporary file");
+
+ return f;
+ }
+
+ /**
+ * Creates an empty file in the default temporary-file directory, using
+ * the given prefix and suffix to generate its name. Invoking this method
+ * is equivalent to invoking <code>{@link #createTempFile(java.lang.String,
+ * java.lang.String, java.io.File)
+ * createTempFile(prefix, suffix, null)}</code>.
+ *
+ * <p> The {@link
+ * java.nio.file.Files#createTempFile(String,String,java.nio.file.attribute.FileAttribute[])
+ * Files.createTempFile} method provides an alternative method to create an
+ * empty file in the temporary-file directory. Files created by that method
+ * may have more restrictive access permissions to files created by this
+ * method and so may be more suited to security-sensitive applications.
+ *
+ * @param prefix The prefix string to be used in generating the file's
+ * name; must be at least three characters long
+ *
+ * @param suffix The suffix string to be used in generating the file's
+ * name; may be <code>null</code>, in which case the
+ * suffix <code>".tmp"</code> will be used
+ *
+ * @return An abstract pathname denoting a newly-created empty file
+ *
+ * @throws IllegalArgumentException
+ * If the <code>prefix</code> argument contains fewer than three
+ * characters
+ *
+ * @throws IOException If a file could not be created
+ *
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method does not allow a file to be created
+ *
+ * @since 1.2
+ * @see java.nio.file.Files#createTempDirectory(String,FileAttribute[])
+ */
+ public static File createTempFile(String prefix, String suffix)
+ throws IOException
+ {
+ return createTempFile(prefix, suffix, null);
+ }
+
+ /* -- Basic infrastructure -- */
+
+ /**
+ * Compares two abstract pathnames lexicographically. The ordering
+ * defined by this method depends upon the underlying system. On UNIX
+ * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows
+ * systems it is not.
+ *
+ * @param pathname The abstract pathname to be compared to this abstract
+ * pathname
+ *
+ * @return Zero if the argument is equal to this abstract pathname, a
+ * value less than zero if this abstract pathname is
+ * lexicographically less than the argument, or a value greater
+ * than zero if this abstract pathname is lexicographically
+ * greater than the argument
+ *
+ * @since 1.2
+ */
+ public int compareTo(File pathname) {
+ return fs.compare(this, pathname);
+ }
+
+ /**
+ * Tests this abstract pathname for equality with the given object.
+ * Returns <code>true</code> if and only if the argument is not
+ * <code>null</code> and is an abstract pathname that denotes the same file
+ * or directory as this abstract pathname. Whether or not two abstract
+ * pathnames are equal depends upon the underlying system. On UNIX
+ * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows
+ * systems it is not.
+ *
+ * @param obj The object to be compared with this abstract pathname
+ *
+ * @return <code>true</code> if and only if the objects are the same;
+ * <code>false</code> otherwise
+ */
+ public boolean equals(Object obj) {
+ if ((obj != null) && (obj instanceof File)) {
+ return compareTo((File)obj) == 0;
+ }
+ return false;
+ }
+
+ /**
+ * Computes a hash code for this abstract pathname. Because equality of
+ * abstract pathnames is inherently system-dependent, so is the computation
+ * of their hash codes. On UNIX systems, the hash code of an abstract
+ * pathname is equal to the exclusive <em>or</em> of the hash code
+ * of its pathname string and the decimal value
+ * <code>1234321</code>. On Microsoft Windows systems, the hash
+ * code is equal to the exclusive <em>or</em> of the hash code of
+ * its pathname string converted to lower case and the decimal
+ * value <code>1234321</code>. Locale is not taken into account on
+ * lowercasing the pathname string.
+ *
+ * @return A hash code for this abstract pathname
+ */
+ public int hashCode() {
+ return fs.hashCode(this);
+ }
+
+ /**
+ * Returns the pathname string of this abstract pathname. This is just the
+ * string returned by the <code>{@link #getPath}</code> method.
+ *
+ * @return The string form of this abstract pathname
+ */
+ public String toString() {
+ return getPath();
+ }
+
+ /**
+ * WriteObject is called to save this filename.
+ * The separator character is saved also so it can be replaced
+ * in case the path is reconstituted on a different host type.
+ * <p>
+ * @serialData Default fields followed by separator character.
+ */
+ private synchronized void writeObject(java.io.ObjectOutputStream s)
+ throws IOException
+ {
+ s.defaultWriteObject();
+ s.writeChar(separatorChar); // Add the separator character
+ }
+
+ /**
+ * readObject is called to restore this filename.
+ * The original separator character is read. If it is different
+ * than the separator character on this system, then the old separator
+ * is replaced by the local separator.
+ */
+ private synchronized void readObject(java.io.ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ ObjectInputStream.GetField fields = s.readFields();
+ String pathField = (String)fields.get("path", null);
+ char sep = s.readChar(); // read the previous separator char
+ if (sep != separatorChar)
+ pathField = pathField.replace(sep, separatorChar);
+ String path = fs.normalize(pathField);
+ UNSAFE.putObject(this, PATH_OFFSET, path);
+ UNSAFE.putIntVolatile(this, PREFIX_LENGTH_OFFSET, fs.prefixLength(path));
+ }
+
+ private static final long PATH_OFFSET;
+ private static final long PREFIX_LENGTH_OFFSET;
+ private static final sun.misc.Unsafe UNSAFE;
+ static {
+ try {
+ sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+ PATH_OFFSET = unsafe.objectFieldOffset(
+ File.class.getDeclaredField("path"));
+ PREFIX_LENGTH_OFFSET = unsafe.objectFieldOffset(
+ File.class.getDeclaredField("prefixLength"));
+ UNSAFE = unsafe;
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }
+ }
+
+
+ /** use serialVersionUID from JDK 1.0.2 for interoperability */
+ private static final long serialVersionUID = 301077366599181567L;
+
+ // -- Integration with java.nio.file --
+
+ private volatile transient Path filePath;
+
+ /**
+ * Returns a {@link Path java.nio.file.Path} object constructed from the
+ * this abstract path. The resulting {@code Path} is associated with the
+ * {@link java.nio.file.FileSystems#getDefault default-filesystem}.
+ *
+ * <p> The first invocation of this method works as if invoking it were
+ * equivalent to evaluating the expression:
+ * <blockquote><pre>
+ * {@link java.nio.file.FileSystems#getDefault FileSystems.getDefault}().{@link
+ * java.nio.file.FileSystem#getPath getPath}(this.{@link #getPath getPath}());
+ * </pre></blockquote>
+ * Subsequent invocations of this method return the same {@code Path}.
+ *
+ * <p> If this abstract pathname is the empty abstract pathname then this
+ * method returns a {@code Path} that may be used to access the current
+ * user directory.
+ *
+ * @return a {@code Path} constructed from this abstract path
+ *
+ * @throws java.nio.file.InvalidPathException
+ * if a {@code Path} object cannot be constructed from the abstract
+ * path (see {@link java.nio.file.FileSystem#getPath FileSystem.getPath})
+ *
+ * @since 1.7
+ * @see Path#toFile
+ */
+ public Path toPath() {
+ Path result = filePath;
+ if (result == null) {
+ synchronized (this) {
+ result = filePath;
+ if (result == null) {
+ result = FileSystems.getDefault().getPath(path);
+ filePath = result;
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/java/io/FileDescriptor.annotated.java b/java/io/FileDescriptor.annotated.java
new file mode 100644
index 0000000..cc16cd6
--- /dev/null
+++ b/java/io/FileDescriptor.annotated.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.io;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class FileDescriptor {
+
+public FileDescriptor() { throw new RuntimeException("Stub!"); }
+
+public boolean valid() { throw new RuntimeException("Stub!"); }
+
+public native void sync() throws java.io.SyncFailedException;
+
[email protected](client = android.annotation.SystemApi.Client.MODULE_LIBRARIES)
[email protected](status = libcore.api.CorePlatformApi.Status.STABLE)
+public int getInt$() { throw new RuntimeException("Stub!"); }
+
[email protected](client = android.annotation.SystemApi.Client.MODULE_LIBRARIES)
[email protected](status = libcore.api.CorePlatformApi.Status.STABLE)
+public void setInt$(int fd) { throw new RuntimeException("Stub!"); }
+
+public long getOwnerId$() { throw new RuntimeException("Stub!"); }
+
+public void setOwnerId$(long newOwnerId) { throw new RuntimeException("Stub!"); }
+
+public java.io.FileDescriptor release$() { throw new RuntimeException("Stub!"); }
+
+public boolean isSocket$() { throw new RuntimeException("Stub!"); }
+
+public static final long NO_OWNER = 0L; // 0x0L
+
+public static final java.io.FileDescriptor err;
+static { err = null; }
+
+public static final java.io.FileDescriptor in;
+static { in = null; }
+
+public static final java.io.FileDescriptor out;
+static { out = null; }
+}
+
diff --git a/java/io/FileDescriptor.java b/java/io/FileDescriptor.java
new file mode 100644
index 0000000..90b97b5
--- /dev/null
+++ b/java/io/FileDescriptor.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import static android.system.OsConstants.F_DUPFD_CLOEXEC;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Instances of the file descriptor class serve as an opaque handle
+ * to the underlying machine-specific structure representing an open
+ * file, an open socket, or another source or sink of bytes. The
+ * main practical use for a file descriptor is to create a
+ * <code>FileInputStream</code> or <code>FileOutputStream</code> to
+ * contain it.
+ * <p>
+ * Applications should not create their own file descriptors.
+ *
+ * @author Pavani Diwanji
+ * @see java.io.FileInputStream
+ * @see java.io.FileOutputStream
+ * @since JDK1.0
+ */
+public final class FileDescriptor {
+ // Android-changed: Removed parent reference counting.
+ // The creator is responsible for closing the file descriptor.
+
+ // Android-changed: Renamed fd to descriptor.
+ // Renaming is to avoid issues with JNI/reflection fetching the descriptor value.
+ private int descriptor;
+
+ // Android-added: Track fd owner to guard against accidental closure. http://b/110100358
+ // The owner on the libc side is an pointer-sized value that can be set to an arbitrary
+ // value (with 0 meaning 'unowned'). libcore chooses to use System.identityHashCode.
+ private long ownerId = NO_OWNER;
+
+ // Android-added: value of ownerId indicating that a FileDescriptor is unowned.
+ /** @hide */
+ public static final long NO_OWNER = 0L;
+
+ // Android-added: lock for release$.
+ private final Object releaseLock = new Object();
+
+ /**
+ * Constructs an (invalid) FileDescriptor
+ * object.
+ */
+ public /**/ FileDescriptor() {
+ descriptor = -1;
+ }
+
+ private /* */ FileDescriptor(int descriptor) {
+ this.descriptor = descriptor;
+ }
+
+ /**
+ * A handle to the standard input stream. Usually, this file
+ * descriptor is not used directly, but rather via the input stream
+ * known as <code>System.in</code>.
+ *
+ * @see java.lang.System#in
+ */
+ public static final FileDescriptor in = new FileDescriptor(0);
+
+ /**
+ * A handle to the standard output stream. Usually, this file
+ * descriptor is not used directly, but rather via the output stream
+ * known as <code>System.out</code>.
+ * @see java.lang.System#out
+ */
+ public static final FileDescriptor out = new FileDescriptor(1);
+
+ /**
+ * A handle to the standard error stream. Usually, this file
+ * descriptor is not used directly, but rather via the output stream
+ * known as <code>System.err</code>.
+ *
+ * @see java.lang.System#err
+ */
+ public static final FileDescriptor err = new FileDescriptor(2);
+
+ /**
+ * Tests if this file descriptor object is valid.
+ *
+ * @return <code>true</code> if the file descriptor object represents a
+ * valid, open file, socket, or other active I/O connection;
+ * <code>false</code> otherwise.
+ */
+ public boolean valid() {
+ return descriptor != -1;
+ }
+
+ /**
+ * Force all system buffers to synchronize with the underlying
+ * device. This method returns after all modified data and
+ * attributes of this FileDescriptor have been written to the
+ * relevant device(s). In particular, if this FileDescriptor
+ * refers to a physical storage medium, such as a file in a file
+ * system, sync will not return until all in-memory modified copies
+ * of buffers associated with this FileDescriptor have been
+ * written to the physical medium.
+ *
+ * sync is meant to be used by code that requires physical
+ * storage (such as a file) to be in a known state For
+ * example, a class that provided a simple transaction facility
+ * might use sync to ensure that all changes to a file caused
+ * by a given transaction were recorded on a storage medium.
+ *
+ * sync only affects buffers downstream of this FileDescriptor. If
+ * any in-memory buffering is being done by the application (for
+ * example, by a BufferedOutputStream object), those buffers must
+ * be flushed into the FileDescriptor (for example, by invoking
+ * OutputStream.flush) before that data will be affected by sync.
+ *
+ * @exception SyncFailedException
+ * Thrown when the buffers cannot be flushed,
+ * or because the system cannot guarantee that all the
+ * buffers have been synchronized with physical media.
+ * @since JDK1.1
+ */
+ public native void sync() throws SyncFailedException;
+
+ // Android-removed: initIDs not used to allow compile-time initialization.
+ /* This routine initializes JNI field offsets for the class */
+ //private static native void initIDs();
+
+ // Android-added: Needed for framework to access descriptor value.
+ /**
+ * Returns the int descriptor. It's highly unlikely you should be calling this. Please discuss
+ * your needs with a libcore maintainer before using this method.
+ * @hide internal use only
+ */
+ public final int getInt$() {
+ return descriptor;
+ }
+
+ // Android-added: Needed for framework to access descriptor value.
+ /**
+ * Sets the int descriptor. It's highly unlikely you should be calling this. Please discuss
+ * your needs with a libcore maintainer before using this method.
+ * @hide internal use only
+ */
+ public final void setInt$(int fd) {
+ this.descriptor = fd;
+ }
+
+ // BEGIN Android-added: Method to clone standard file descriptors.
+ // Required as a consequence of RuntimeInit#redirectLogStreams. Cloning is used in
+ // ZygoteHooks.onEndPreload().
+ /**
+ * Clones the current native file descriptor and uses this for this FileDescriptor instance.
+ *
+ * This method does not close the current native file descriptor.
+ *
+ * @hide internal use only
+ */
+ public void cloneForFork() {
+ try {
+ int newDescriptor = Os.fcntlInt(this, F_DUPFD_CLOEXEC, 0);
+ this.descriptor = newDescriptor;
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ // END Android-added: Method to clone standard file descriptors.
+
+ // BEGIN Android-added: Methods to enable ownership enforcement of Unix file descriptors.
+ /**
+ * Returns the owner ID of this FileDescriptor. It's highly unlikely you should be calling this.
+ * Please discuss your needs with a libcore maintainer before using this method.
+ * @hide internal use only
+ */
+ public long getOwnerId$() {
+ return this.ownerId;
+ }
+
+ /**
+ * Sets the owner ID of this FileDescriptor. The owner ID does not need to be unique, but it is
+ * assumed that clashes are rare. See bionic/include/android/fdsan.h for more details.
+ *
+ * It's highly unlikely you should be calling this.
+ * Please discuss your needs with a libcore maintainer before using this method.
+ * @param owner the owner ID of the Object that is responsible for closing this FileDescriptor
+ * @hide internal use only
+ */
+ public void setOwnerId$(long newOwnerId) {
+ this.ownerId = newOwnerId;
+ }
+
+ /**
+ * Returns a copy of this FileDescriptor, and sets this to an invalid state.
+ *
+ * The returned instance is not necessarily {@code valid()}, if the original FileDescriptor
+ * was invalid, or if another thread concurrently calls {@code release$()}.
+ *
+ * @hide internal use only
+ */
+ public FileDescriptor release$() {
+ FileDescriptor result = new FileDescriptor();
+ synchronized (releaseLock) {
+ result.descriptor = this.descriptor;
+ result.ownerId = this.ownerId;
+ this.descriptor = -1;
+ this.ownerId = FileDescriptor.NO_OWNER;
+ }
+
+ return result;
+ }
+ // END Android-added: Methods to enable ownership enforcement of Unix file descriptors.
+
+ // Android-added: Needed for framework to test if it's a socket.
+ /**
+ * @hide internal use only
+ */
+ public boolean isSocket$() {
+ return isSocket(descriptor);
+ }
+
+ private static native boolean isSocket(int descriptor);
+ // Set up JavaIOFileDescriptorAccess in SharedSecrets
+ static {
+ sun.misc.SharedSecrets.setJavaIOFileDescriptorAccess(
+ new sun.misc.JavaIOFileDescriptorAccess() {
+ public void set(FileDescriptor obj, int fd) {
+ obj.descriptor = fd;
+ }
+
+ public int get(FileDescriptor obj) {
+ return obj.descriptor;
+ }
+
+ public void setHandle(FileDescriptor obj, long handle) {
+ throw new UnsupportedOperationException();
+ }
+
+ public long getHandle(FileDescriptor obj) {
+ throw new UnsupportedOperationException();
+ }
+ }
+ );
+ }
+// Android-removed: Removed method required for parents reference counting.
+}
diff --git a/java/io/FileFilter.java b/java/io/FileFilter.java
new file mode 100644
index 0000000..f973d77
--- /dev/null
+++ b/java/io/FileFilter.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * A filter for abstract pathnames.
+ *
+ * <p> Instances of this interface may be passed to the <code>{@link
+ * File#listFiles(java.io.FileFilter) listFiles(FileFilter)}</code> method
+ * of the <code>{@link java.io.File}</code> class.
+ *
+ * @since 1.2
+ */
+@FunctionalInterface
+public interface FileFilter {
+
+ /**
+ * Tests whether or not the specified abstract pathname should be
+ * included in a pathname list.
+ *
+ * @param pathname The abstract pathname to be tested
+ * @return <code>true</code> if and only if <code>pathname</code>
+ * should be included
+ */
+ boolean accept(File pathname);
+}
diff --git a/java/io/FileInputStream.annotated.java b/java/io/FileInputStream.annotated.java
new file mode 100644
index 0000000..ac26aeb
--- /dev/null
+++ b/java/io/FileInputStream.annotated.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.io;
+
+import java.nio.channels.FileChannel;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class FileInputStream extends java.io.InputStream {
+
+public FileInputStream(java.lang.String name) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
+
+public FileInputStream(java.io.File file) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
+
+public FileInputStream(java.io.FileDescriptor fdObj) { throw new RuntimeException("Stub!"); }
+
[email protected](client = android.annotation.SystemApi.Client.MODULE_LIBRARIES)
[email protected](status = libcore.api.CorePlatformApi.Status.STABLE)
+public FileInputStream(java.io.FileDescriptor fdObj, boolean isFdOwner) { throw new RuntimeException("Stub!"); }
+
+public int read() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public int read(byte[] b) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public int read(byte[] b, int off, int len) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public long skip(long n) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public int available() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void close() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public final java.io.FileDescriptor getFD() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.nio.channels.FileChannel getChannel() { throw new RuntimeException("Stub!"); }
+
+protected void finalize() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/io/FileInputStream.java b/java/io/FileInputStream.java
new file mode 100644
index 0000000..9ce75ff
--- /dev/null
+++ b/java/io/FileInputStream.java
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import static android.system.OsConstants.O_RDONLY;
+
+import java.nio.channels.FileChannel;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.BlockGuard;
+import dalvik.system.CloseGuard;
+import sun.nio.ch.FileChannelImpl;
+import libcore.io.IoBridge;
+import libcore.io.IoTracker;
+import libcore.io.IoUtils;
+
+
+/**
+ * A <code>FileInputStream</code> obtains input bytes
+ * from a file in a file system. What files
+ * are available depends on the host environment.
+ *
+ * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
+ * such as image data. For reading streams of characters, consider using
+ * <code>FileReader</code>.
+ *
+ * @author Arthur van Hoff
+ * @see java.io.File
+ * @see java.io.FileDescriptor
+ * @see java.io.FileOutputStream
+ * @see java.nio.file.Files#newInputStream
+ * @since JDK1.0
+ */
+public
+class FileInputStream extends InputStream
+{
+ /* File Descriptor - handle to the open file */
+ // Android-added: @ReachabilitySensitive
+ @ReachabilitySensitive
+ private final FileDescriptor fd;
+
+ /**
+ * The path of the referenced file
+ * (null if the stream is created with a file descriptor)
+ */
+ private final String path;
+
+ private FileChannel channel = null;
+
+ private final Object closeLock = new Object();
+ private volatile boolean closed = false;
+
+ // Android-added: Field for tracking whether the stream owns the underlying FileDescriptor.
+ private final boolean isFdOwner;
+
+ // Android-added: CloseGuard support.
+ @ReachabilitySensitive
+ private final CloseGuard guard = CloseGuard.get();
+
+ // Android-added: Tracking of unbuffered I/O.
+ private final IoTracker tracker = new IoTracker();
+
+ /**
+ * Creates a <code>FileInputStream</code> by
+ * opening a connection to an actual file,
+ * the file named by the path name <code>name</code>
+ * in the file system. A new <code>FileDescriptor</code>
+ * object is created to represent this file
+ * connection.
+ * <p>
+ * First, if there is a security
+ * manager, its <code>checkRead</code> method
+ * is called with the <code>name</code> argument
+ * as its argument.
+ * <p>
+ * If the named file does not exist, is a directory rather than a regular
+ * file, or for some other reason cannot be opened for reading then a
+ * <code>FileNotFoundException</code> is thrown.
+ *
+ * @param name the system-dependent file name.
+ * @exception FileNotFoundException if the file does not exist,
+ * is a directory rather than a regular file,
+ * or for some other reason cannot be opened for
+ * reading.
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkRead</code> method denies read access
+ * to the file.
+ * @see java.lang.SecurityManager#checkRead(java.lang.String)
+ */
+ public FileInputStream(String name) throws FileNotFoundException {
+ this(name != null ? new File(name) : null);
+ }
+
+ /**
+ * Creates a <code>FileInputStream</code> by
+ * opening a connection to an actual file,
+ * the file named by the <code>File</code>
+ * object <code>file</code> in the file system.
+ * A new <code>FileDescriptor</code> object
+ * is created to represent this file connection.
+ * <p>
+ * First, if there is a security manager,
+ * its <code>checkRead</code> method is called
+ * with the path represented by the <code>file</code>
+ * argument as its argument.
+ * <p>
+ * If the named file does not exist, is a directory rather than a regular
+ * file, or for some other reason cannot be opened for reading then a
+ * <code>FileNotFoundException</code> is thrown.
+ *
+ * @param file the file to be opened for reading.
+ * @exception FileNotFoundException if the file does not exist,
+ * is a directory rather than a regular file,
+ * or for some other reason cannot be opened for
+ * reading.
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkRead</code> method denies read access to the file.
+ * @see java.io.File#getPath()
+ * @see java.lang.SecurityManager#checkRead(java.lang.String)
+ */
+ public FileInputStream(File file) throws FileNotFoundException {
+ String name = (file != null ? file.getPath() : null);
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(name);
+ }
+ if (name == null) {
+ throw new NullPointerException();
+ }
+ if (file.isInvalid()) {
+ throw new FileNotFoundException("Invalid file path");
+ }
+ // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+ // http://b/112107427
+ // fd = new FileDescriptor();
+ fd = IoBridge.open(name, O_RDONLY);
+ // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+
+ // Android-changed: Tracking mechanism for FileDescriptor sharing.
+ // fd.attach(this);
+ isFdOwner = true;
+
+ path = name;
+
+ // Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+ // open(name);
+
+ // Android-added: File descriptor ownership tracking.
+ IoUtils.setFdOwner(this.fd, this);
+
+ // Android-added: CloseGuard support.
+ guard.open("close");
+ }
+
+ // Android-removed: Documentation around SecurityException. Not thrown on Android.
+ /**
+ * Creates a <code>FileInputStream</code> by using the file descriptor
+ * <code>fdObj</code>, which represents an existing connection to an
+ * actual file in the file system.
+ * <p>
+ * If there is a security manager, its <code>checkRead</code> method is
+ * called with the file descriptor <code>fdObj</code> as its argument to
+ * see if it's ok to read the file descriptor. If read access is denied
+ * to the file descriptor a <code>SecurityException</code> is thrown.
+ * <p>
+ * If <code>fdObj</code> is null then a <code>NullPointerException</code>
+ * is thrown.
+ * <p>
+ * This constructor does not throw an exception if <code>fdObj</code>
+ * is {@link java.io.FileDescriptor#valid() invalid}.
+ * However, if the methods are invoked on the resulting stream to attempt
+ * I/O on the stream, an <code>IOException</code> is thrown.
+ *
+ * @param fdObj the file descriptor to be opened for reading.
+ */
+ public FileInputStream(FileDescriptor fdObj) {
+ // Android-changed: Delegate to added hidden constructor.
+ this(fdObj, false /* isFdOwner */);
+ }
+
+ // Android-added: Internal/hidden constructor for specifying FileDescriptor ownership.
+ // Android-removed: SecurityManager calls.
+ /** @hide */
+ public FileInputStream(FileDescriptor fdObj, boolean isFdOwner) {
+ if (fdObj == null) {
+ // Android-changed: Improved NullPointerException message.
+ throw new NullPointerException("fdObj == null");
+ }
+ fd = fdObj;
+ path = null;
+
+ // Android-changed: FileDescriptor ownership tracking mechanism.
+ /*
+ /*
+ * FileDescriptor is being shared by streams.
+ * Register this stream with FileDescriptor tracker.
+ *
+ fd.attach(this);
+ */
+ this.isFdOwner = isFdOwner;
+ if (isFdOwner) {
+ IoUtils.setFdOwner(this.fd, this);
+ }
+ }
+
+ // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+ // http://b/112107427
+ /*
+ /**
+ * Opens the specified file for reading.
+ * @param name the name of the file
+ *
+ private native void open0(String name) throws FileNotFoundException;
+
+ // wrap native call to allow instrumentation
+ /**
+ * Opens the specified file for reading.
+ * @param name the name of the file
+ *
+ private void open(String name) throws FileNotFoundException {
+ open0(name);
+ }
+ */
+ // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+
+ /**
+ * Reads a byte of data from this input stream. This method blocks
+ * if no input is yet available.
+ *
+ * @return the next byte of data, or <code>-1</code> if the end of the
+ * file is reached.
+ * @exception IOException if an I/O error occurs.
+ */
+ public int read() throws IOException {
+ // Android-changed: Read methods delegate to read(byte[], int, int) to share Android logic.
+ byte[] b = new byte[1];
+ return (read(b, 0, 1) != -1) ? b[0] & 0xff : -1;
+ }
+
+ // Android-removed: Read methods delegate to read(byte[], int, int) to share Android logic.
+ // private native int read0() throws IOException;
+
+ // Android-removed: Read methods delegate to read(byte[], int, int) to share Android logic.
+ /*
+ /**
+ * Reads a subarray as a sequence of bytes.
+ * @param b the data to be written
+ * @param off the start offset in the data
+ * @param len the number of bytes that are written
+ * @exception IOException If an I/O error has occurred.
+ *
+ private native int readBytes(byte b[], int off, int len) throws IOException;
+ */
+
+ /**
+ * Reads up to <code>b.length</code> bytes of data from this input
+ * stream into an array of bytes. This method blocks until some input
+ * is available.
+ *
+ * @param b the buffer into which the data is read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the file has been reached.
+ * @exception IOException if an I/O error occurs.
+ */
+ public int read(byte b[]) throws IOException {
+ // Android-changed: Read methods delegate to read(byte[], int, int) to share Android logic.
+ return read(b, 0, b.length);
+ }
+
+ /**
+ * Reads up to <code>len</code> bytes of data from this input stream
+ * into an array of bytes. If <code>len</code> is not zero, the method
+ * blocks until some input is available; otherwise, no
+ * bytes are read and <code>0</code> is returned.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in the destination array <code>b</code>
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the file has been reached.
+ * @exception NullPointerException If <code>b</code> is <code>null</code>.
+ * @exception IndexOutOfBoundsException If <code>off</code> is negative,
+ * <code>len</code> is negative, or <code>len</code> is greater than
+ * <code>b.length - off</code>
+ * @exception IOException if an I/O error occurs.
+ */
+ public int read(byte b[], int off, int len) throws IOException {
+ // Android-added: close() check before I/O.
+ if (closed && len > 0) {
+ throw new IOException("Stream Closed");
+ }
+
+ // Android-added: Tracking of unbuffered I/O.
+ tracker.trackIo(len);
+
+ // Android-changed: Use IoBridge instead of calling native method.
+ return IoBridge.read(fd, b, off, len);
+ }
+
+ /**
+ * Skips over and discards <code>n</code> bytes of data from the
+ * input stream.
+ *
+ * <p>The <code>skip</code> method may, for a variety of
+ * reasons, end up skipping over some smaller number of bytes,
+ * possibly <code>0</code>. If <code>n</code> is negative, the method
+ * will try to skip backwards. In case the backing file does not support
+ * backward skip at its current position, an <code>IOException</code> is
+ * thrown. The actual number of bytes skipped is returned. If it skips
+ * forwards, it returns a positive value. If it skips backwards, it
+ * returns a negative value.
+ *
+ * <p>This method may skip more bytes than what are remaining in the
+ * backing file. This produces no exception and the number of bytes skipped
+ * may include some number of bytes that were beyond the EOF of the
+ * backing file. Attempting to read from the stream after skipping past
+ * the end will result in -1 indicating the end of the file.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the actual number of bytes skipped.
+ * @exception IOException if n is negative, if the stream does not
+ * support seek, or if an I/O error occurs.
+ */
+ // BEGIN Android-changed: skip(long) implementation changed from bare native.
+ public long skip(long n) throws IOException {
+ // Android-added: close() check before I/O.
+ if (closed) {
+ throw new IOException("Stream Closed");
+ }
+
+ try {
+ // Android-added: BlockGuard support.
+ BlockGuard.getThreadPolicy().onReadFromDisk();
+ return skip0(n);
+ } catch(UseManualSkipException e) {
+ return super.skip(n);
+ }
+ }
+
+ private native long skip0(long n) throws IOException, UseManualSkipException;
+
+ /*
+ * Used to force manual skip when FileInputStream operates on pipe
+ */
+ private static class UseManualSkipException extends Exception {
+ }
+ // END Android-changed: skip(long) implementation changed from bare native.
+
+ /**
+ * Returns an estimate of the number of remaining bytes that can be read (or
+ * skipped over) from this input stream without blocking by the next
+ * invocation of a method for this input stream. Returns 0 when the file
+ * position is beyond EOF. The next invocation might be the same thread
+ * or another thread. A single read or skip of this many bytes will not
+ * block, but may read or skip fewer bytes.
+ *
+ * <p> In some cases, a non-blocking read (or skip) may appear to be
+ * blocked when it is merely slow, for example when reading large
+ * files over slow networks.
+ *
+ * @return an estimate of the number of remaining bytes that can be read
+ * (or skipped over) from this input stream without blocking.
+ * @exception IOException if this file input stream has been closed by calling
+ * {@code close} or an I/O error occurs.
+ */
+ // BEGIN Android-changed: available() implementation changed from bare native.
+ public int available() throws IOException {
+ // Android-added: close() check before I/O.
+ if (closed) {
+ throw new IOException("Stream Closed");
+ }
+
+ return available0();
+ }
+
+ private native int available0() throws IOException;
+ // END Android-changed: available() implementation changed from bare native.
+
+ /**
+ * Closes this file input stream and releases any system resources
+ * associated with the stream.
+ *
+ * <p> If this stream has an associated channel then the channel is closed
+ * as well.
+ *
+ * @exception IOException if an I/O error occurs.
+ *
+ * @revised 1.4
+ * @spec JSR-51
+ */
+ public void close() throws IOException {
+ synchronized (closeLock) {
+ if (closed) {
+ return;
+ }
+ closed = true;
+ }
+
+ // Android-added: CloseGuard support.
+ guard.close();
+
+ if (channel != null) {
+ channel.close();
+ }
+
+ // BEGIN Android-changed: Close handling / notification of blocked threads.
+ if (isFdOwner) {
+ IoBridge.closeAndSignalBlockedThreads(fd);
+ }
+ // END Android-changed: Close handling / notification of blocked threads.
+ }
+
+ /**
+ * Returns the <code>FileDescriptor</code>
+ * object that represents the connection to
+ * the actual file in the file system being
+ * used by this <code>FileInputStream</code>.
+ *
+ * @return the file descriptor object associated with this stream.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FileDescriptor
+ */
+ public final FileDescriptor getFD() throws IOException {
+ if (fd != null) {
+ return fd;
+ }
+ throw new IOException();
+ }
+
+ /**
+ * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
+ * object associated with this file input stream.
+ *
+ * <p> The initial {@link java.nio.channels.FileChannel#position()
+ * position} of the returned channel will be equal to the
+ * number of bytes read from the file so far. Reading bytes from this
+ * stream will increment the channel's position. Changing the channel's
+ * position, either explicitly or by reading, will change this stream's
+ * file position.
+ *
+ * @return the file channel associated with this file input stream
+ *
+ * @since 1.4
+ * @spec JSR-51
+ */
+ public FileChannel getChannel() {
+ synchronized (this) {
+ if (channel == null) {
+ channel = FileChannelImpl.open(fd, path, true, false, this);
+ }
+ return channel;
+ }
+ }
+
+ // BEGIN Android-removed: Unused code.
+ /*
+ private static native void initIDs();
+
+ private native void close0() throws IOException;
+
+ static {
+ initIDs();
+ }
+ */
+ // END Android-removed: Unused code.
+
+ /**
+ * Ensures that the <code>close</code> method of this file input stream is
+ * called when there are no more references to it.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FileInputStream#close()
+ */
+ protected void finalize() throws IOException {
+ // Android-added: CloseGuard support.
+ if (guard != null) {
+ guard.warnIfOpen();
+ }
+
+ if ((fd != null) && (fd != FileDescriptor.in)) {
+ // Android-removed: Obsoleted comment about shared FileDescriptor handling.
+ close();
+ }
+ }
+}
diff --git a/java/io/FileNotFoundException.java b/java/io/FileNotFoundException.java
new file mode 100644
index 0000000..278fa1d
--- /dev/null
+++ b/java/io/FileNotFoundException.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Signals that an attempt to open the file denoted by a specified pathname
+ * has failed.
+ *
+ * <p> This exception will be thrown by the {@link FileInputStream}, {@link
+ * FileOutputStream}, and {@link RandomAccessFile} constructors when a file
+ * with the specified pathname does not exist. It will also be thrown by these
+ * constructors if the file does exist but for some reason is inaccessible, for
+ * example when an attempt is made to open a read-only file for writing.
+ *
+ * @author unascribed
+ * @since JDK1.0
+ */
+
+public class FileNotFoundException extends IOException {
+ private static final long serialVersionUID = -897856973823710492L;
+
+ /**
+ * Constructs a <code>FileNotFoundException</code> with
+ * <code>null</code> as its error detail message.
+ */
+ public FileNotFoundException() {
+ super();
+ }
+
+ /**
+ * Constructs a <code>FileNotFoundException</code> with the
+ * specified detail message. The string <code>s</code> can be
+ * retrieved later by the
+ * <code>{@link java.lang.Throwable#getMessage}</code>
+ * method of class <code>java.lang.Throwable</code>.
+ *
+ * @param s the detail message.
+ */
+ public FileNotFoundException(String s) {
+ super(s);
+ }
+
+ /**
+ * Constructs a <code>FileNotFoundException</code> with a detail message
+ * consisting of the given pathname string followed by the given reason
+ * string. If the <code>reason</code> argument is <code>null</code> then
+ * it will be omitted. This private constructor is invoked only by native
+ * I/O methods.
+ *
+ * @since 1.2
+ */
+ private FileNotFoundException(String path, String reason) {
+ super(path + ((reason == null)
+ ? ""
+ : " (" + reason + ")"));
+ }
+
+}
diff --git a/java/io/FileOutputStream.java b/java/io/FileOutputStream.java
new file mode 100644
index 0000000..66f4c05
--- /dev/null
+++ b/java/io/FileOutputStream.java
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_TRUNC;
+import static android.system.OsConstants.O_WRONLY;
+
+import java.nio.channels.FileChannel;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.BlockGuard;
+import dalvik.system.CloseGuard;
+import sun.nio.ch.FileChannelImpl;
+import libcore.io.IoBridge;
+import libcore.io.IoTracker;
+import libcore.io.IoUtils;
+
+/**
+ * A file output stream is an output stream for writing data to a
+ * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not
+ * a file is available or may be created depends upon the underlying
+ * platform. Some platforms, in particular, allow a file to be opened
+ * for writing by only one <tt>FileOutputStream</tt> (or other
+ * file-writing object) at a time. In such situations the constructors in
+ * this class will fail if the file involved is already open.
+ *
+ * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes
+ * such as image data. For writing streams of characters, consider using
+ * <code>FileWriter</code>.
+ *
+ * @author Arthur van Hoff
+ * @see java.io.File
+ * @see java.io.FileDescriptor
+ * @see java.io.FileInputStream
+ * @see java.nio.file.Files#newOutputStream
+ * @since JDK1.0
+ */
+public
+class FileOutputStream extends OutputStream
+{
+ /**
+ * The system dependent file descriptor.
+ */
+ // Android-added: @ReachabilitySensitive
+ @ReachabilitySensitive
+ private final FileDescriptor fd;
+
+ /**
+ * True if the file is opened for append.
+ */
+ private final boolean append;
+
+ /**
+ * The associated channel, initialized lazily.
+ */
+ private FileChannel channel;
+
+ /**
+ * The path of the referenced file
+ * (null if the stream is created with a file descriptor)
+ */
+ private final String path;
+
+ private final Object closeLock = new Object();
+ private volatile boolean closed = false;
+
+ // Android-added: CloseGuard support: Log if the stream is not closed.
+ @ReachabilitySensitive
+ private final CloseGuard guard = CloseGuard.get();
+
+ // Android-added: Field for tracking whether the stream owns the underlying FileDescriptor.
+ private final boolean isFdOwner;
+
+ // Android-added: Tracking of unbuffered I/O.
+ private final IoTracker tracker = new IoTracker();
+
+ /**
+ * Creates a file output stream to write to the file with the
+ * specified name. A new <code>FileDescriptor</code> object is
+ * created to represent this file connection.
+ * <p>
+ * First, if there is a security manager, its <code>checkWrite</code>
+ * method is called with <code>name</code> as its argument.
+ * <p>
+ * If the file exists but is a directory rather than a regular file, does
+ * not exist but cannot be created, or cannot be opened for any other
+ * reason then a <code>FileNotFoundException</code> is thrown.
+ *
+ * @param name the system-dependent filename
+ * @exception FileNotFoundException if the file exists but is a directory
+ * rather than a regular file, does not exist but cannot
+ * be created, or cannot be opened for any other reason
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkWrite</code> method denies write access
+ * to the file.
+ * @see java.lang.SecurityManager#checkWrite(java.lang.String)
+ */
+ public FileOutputStream(String name) throws FileNotFoundException {
+ this(name != null ? new File(name) : null, false);
+ }
+
+ /**
+ * Creates a file output stream to write to the file with the specified
+ * name. If the second argument is <code>true</code>, then
+ * bytes will be written to the end of the file rather than the beginning.
+ * A new <code>FileDescriptor</code> object is created to represent this
+ * file connection.
+ * <p>
+ * First, if there is a security manager, its <code>checkWrite</code>
+ * method is called with <code>name</code> as its argument.
+ * <p>
+ * If the file exists but is a directory rather than a regular file, does
+ * not exist but cannot be created, or cannot be opened for any other
+ * reason then a <code>FileNotFoundException</code> is thrown.
+ *
+ * @param name the system-dependent file name
+ * @param append if <code>true</code>, then bytes will be written
+ * to the end of the file rather than the beginning
+ * @exception FileNotFoundException if the file exists but is a directory
+ * rather than a regular file, does not exist but cannot
+ * be created, or cannot be opened for any other reason.
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkWrite</code> method denies write access
+ * to the file.
+ * @see java.lang.SecurityManager#checkWrite(java.lang.String)
+ * @since JDK1.1
+ */
+ public FileOutputStream(String name, boolean append)
+ throws FileNotFoundException
+ {
+ this(name != null ? new File(name) : null, append);
+ }
+
+ /**
+ * Creates a file output stream to write to the file represented by
+ * the specified <code>File</code> object. A new
+ * <code>FileDescriptor</code> object is created to represent this
+ * file connection.
+ * <p>
+ * First, if there is a security manager, its <code>checkWrite</code>
+ * method is called with the path represented by the <code>file</code>
+ * argument as its argument.
+ * <p>
+ * If the file exists but is a directory rather than a regular file, does
+ * not exist but cannot be created, or cannot be opened for any other
+ * reason then a <code>FileNotFoundException</code> is thrown.
+ *
+ * @param file the file to be opened for writing.
+ * @exception FileNotFoundException if the file exists but is a directory
+ * rather than a regular file, does not exist but cannot
+ * be created, or cannot be opened for any other reason
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkWrite</code> method denies write access
+ * to the file.
+ * @see java.io.File#getPath()
+ * @see java.lang.SecurityException
+ * @see java.lang.SecurityManager#checkWrite(java.lang.String)
+ */
+ public FileOutputStream(File file) throws FileNotFoundException {
+ this(file, false);
+ }
+
+ /**
+ * Creates a file output stream to write to the file represented by
+ * the specified <code>File</code> object. If the second argument is
+ * <code>true</code>, then bytes will be written to the end of the file
+ * rather than the beginning. A new <code>FileDescriptor</code> object is
+ * created to represent this file connection.
+ * <p>
+ * First, if there is a security manager, its <code>checkWrite</code>
+ * method is called with the path represented by the <code>file</code>
+ * argument as its argument.
+ * <p>
+ * If the file exists but is a directory rather than a regular file, does
+ * not exist but cannot be created, or cannot be opened for any other
+ * reason then a <code>FileNotFoundException</code> is thrown.
+ *
+ * @param file the file to be opened for writing.
+ * @param append if <code>true</code>, then bytes will be written
+ * to the end of the file rather than the beginning
+ * @exception FileNotFoundException if the file exists but is a directory
+ * rather than a regular file, does not exist but cannot
+ * be created, or cannot be opened for any other reason
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkWrite</code> method denies write access
+ * to the file.
+ * @see java.io.File#getPath()
+ * @see java.lang.SecurityException
+ * @see java.lang.SecurityManager#checkWrite(java.lang.String)
+ * @since 1.4
+ */
+ public FileOutputStream(File file, boolean append)
+ throws FileNotFoundException
+ {
+ String name = (file != null ? file.getPath() : null);
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkWrite(name);
+ }
+ if (name == null) {
+ throw new NullPointerException();
+ }
+ if (file.isInvalid()) {
+ throw new FileNotFoundException("Invalid file path");
+ }
+ // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+ // http://b/111268862
+ // this.fd = new FileDescriptor();
+ int flags = O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC);
+ this.fd = IoBridge.open(name, flags);
+ // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+
+ // Android-changed: Tracking mechanism for FileDescriptor sharing.
+ // fd.attach(this);
+ this.isFdOwner = true;
+
+ this.append = append;
+ this.path = name;
+
+ // Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+ // open(name, append);
+
+ // Android-added: File descriptor ownership tracking.
+ IoUtils.setFdOwner(this.fd, this);
+
+ // Android-added: CloseGuard support.
+ guard.open("close");
+ }
+
+ // Android-removed: Documentation around SecurityException. Not thrown on Android.
+ /**
+ * Creates a file output stream to write to the specified file
+ * descriptor, which represents an existing connection to an actual
+ * file in the file system.
+ * <p>
+ * First, if there is a security manager, its <code>checkWrite</code>
+ * method is called with the file descriptor <code>fdObj</code>
+ * argument as its argument.
+ * <p>
+ * If <code>fdObj</code> is null then a <code>NullPointerException</code>
+ * is thrown.
+ * <p>
+ * This constructor does not throw an exception if <code>fdObj</code>
+ * is {@link java.io.FileDescriptor#valid() invalid}.
+ * However, if the methods are invoked on the resulting stream to attempt
+ * I/O on the stream, an <code>IOException</code> is thrown.
+ *
+ * @param fdObj the file descriptor to be opened for writing
+ */
+ public FileOutputStream(FileDescriptor fdObj) {
+ // Android-changed: Delegate to added hidden constructor.
+ this(fdObj, false /* isOwner */);
+ }
+
+ // Android-added: Internal/hidden constructor for specifying FileDescriptor ownership.
+ // Android-removed: SecurityManager calls.
+ /**
+ * Internal constructor for {@code FileOutputStream} objects where the file descriptor
+ * is owned by this tream.
+ *
+ * @hide
+ */
+ public FileOutputStream(FileDescriptor fdObj, boolean isFdOwner) {
+ if (fdObj == null) {
+ // Android-changed: Improved NullPointerException message.
+ throw new NullPointerException("fdObj == null");
+ }
+
+ this.fd = fdObj;
+ this.append = false;
+ this.path = null;
+
+ // Android-changed: FileDescriptor ownership tracking mechanism.
+ // fd.attach(this);
+ this.isFdOwner = isFdOwner;
+ if (isFdOwner) {
+ IoUtils.setFdOwner(this.fd, this);
+ }
+ }
+
+ // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+ // http://b/112107427
+ /*
+ /**
+ * Opens a file, with the specified name, for overwriting or appending.
+ * @param name name of file to be opened
+ * @param append whether the file is to be opened in append mode
+ *
+ private native void open0(String name, boolean append)
+ throws FileNotFoundException;
+
+ // wrap native call to allow instrumentation
+ /**
+ * Opens a file, with the specified name, for overwriting or appending.
+ * @param name name of file to be opened
+ * @param append whether the file is to be opened in append mode
+ *
+ private void open(String name, boolean append)
+ throws FileNotFoundException {
+ open0(name, append);
+ }
+ */
+ // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+
+ // Android-removed: write(int, boolean), use IoBridge instead.
+ /*
+ /**
+ * Writes the specified byte to this file output stream.
+ *
+ * @param b the byte to be written.
+ * @param append {@code true} if the write operation first
+ * advances the position to the end of file
+ *
+ private native void write(int b, boolean append) throws IOException;
+ */
+
+ /**
+ * Writes the specified byte to this file output stream. Implements
+ * the <code>write</code> method of <code>OutputStream</code>.
+ *
+ * @param b the byte to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ public void write(int b) throws IOException {
+ // Android-changed: Write methods delegate to write(byte[],int,int) to share Android logic.
+ write(new byte[] { (byte) b }, 0, 1);
+ }
+
+ // Android-removed: Write methods delegate to write(byte[],int,int) to share Android logic.
+ /*
+ /**
+ * Writes a sub array as a sequence of bytes.
+ * @param b the data to be written
+ * @param off the start offset in the data
+ * @param len the number of bytes that are written
+ * @param append {@code true} to first advance the position to the
+ * end of file
+ * @exception IOException If an I/O error has occurred.
+ *
+ private native void writeBytes(byte b[], int off, int len, boolean append)
+ throws IOException;
+ */
+
+ /**
+ * Writes <code>b.length</code> bytes from the specified byte array
+ * to this file output stream.
+ *
+ * @param b the data.
+ * @exception IOException if an I/O error occurs.
+ */
+ public void write(byte b[]) throws IOException {
+ // Android-changed: Write methods delegate to write(byte[],int,int) to share Android logic.
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Writes <code>len</code> bytes from the specified byte array
+ * starting at offset <code>off</code> to this file output stream.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @exception IOException if an I/O error occurs.
+ */
+ public void write(byte b[], int off, int len) throws IOException {
+ // Android-added: close() check before I/O.
+ if (closed && len > 0) {
+ throw new IOException("Stream Closed");
+ }
+
+ // Android-added: Tracking of unbuffered I/O.
+ tracker.trackIo(len);
+
+ // Android-changed: Use IoBridge instead of calling native method.
+ IoBridge.write(fd, b, off, len);
+ }
+
+ /**
+ * Closes this file output stream and releases any system resources
+ * associated with this stream. This file output stream may no longer
+ * be used for writing bytes.
+ *
+ * <p> If this stream has an associated channel then the channel is closed
+ * as well.
+ *
+ * @exception IOException if an I/O error occurs.
+ *
+ * @revised 1.4
+ * @spec JSR-51
+ */
+ public void close() throws IOException {
+ synchronized (closeLock) {
+ if (closed) {
+ return;
+ }
+ closed = true;
+ }
+
+ // Android-added: CloseGuard support.
+ guard.close();
+
+ if (channel != null) {
+ channel.close();
+ }
+
+ // BEGIN Android-changed: Close handling / notification of blocked threads.
+ if (isFdOwner) {
+ IoBridge.closeAndSignalBlockedThreads(fd);
+ }
+ // END Android-changed: Close handling / notification of blocked threads.
+ }
+
+ /**
+ * Returns the file descriptor associated with this stream.
+ *
+ * @return the <code>FileDescriptor</code> object that represents
+ * the connection to the file in the file system being used
+ * by this <code>FileOutputStream</code> object.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FileDescriptor
+ */
+ // Android-added: @ReachabilitySensitive
+ @ReachabilitySensitive
+ public final FileDescriptor getFD() throws IOException {
+ if (fd != null) {
+ return fd;
+ }
+ throw new IOException();
+ }
+
+ /**
+ * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
+ * object associated with this file output stream.
+ *
+ * <p> The initial {@link java.nio.channels.FileChannel#position()
+ * position} of the returned channel will be equal to the
+ * number of bytes written to the file so far unless this stream is in
+ * append mode, in which case it will be equal to the size of the file.
+ * Writing bytes to this stream will increment the channel's position
+ * accordingly. Changing the channel's position, either explicitly or by
+ * writing, will change this stream's file position.
+ *
+ * @return the file channel associated with this file output stream
+ *
+ * @since 1.4
+ * @spec JSR-51
+ */
+ public FileChannel getChannel() {
+ synchronized (this) {
+ if (channel == null) {
+ channel = FileChannelImpl.open(fd, path, false, true, append, this);
+ }
+ return channel;
+ }
+ }
+
+ /**
+ * Cleans up the connection to the file, and ensures that the
+ * <code>close</code> method of this file output stream is
+ * called when there are no more references to this stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FileInputStream#close()
+ */
+ protected void finalize() throws IOException {
+ // Android-added: CloseGuard support.
+ if (guard != null) {
+ guard.warnIfOpen();
+ }
+
+ if (fd != null) {
+ if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
+ flush();
+ } else {
+ // Android-removed: Obsoleted comment about shared FileDescriptor handling.
+ close();
+ }
+ }
+ }
+
+ // BEGIN Android-removed: Unused code.
+ /*
+ private native void close0() throws IOException;
+
+ private static native void initIDs();
+
+ static {
+ initIDs();
+ }
+ */
+ // END Android-removed: Unused code.
+
+}
diff --git a/java/io/FilePermission.java b/java/io/FilePermission.java
new file mode 100644
index 0000000..bb69075
--- /dev/null
+++ b/java/io/FilePermission.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.security.*;
+
+// Android-changed: Stubbed the implementation. Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class FilePermission extends Permission implements Serializable {
+
+ public FilePermission(String path, String actions) { super(path); }
+
+ public boolean implies(Permission p) { return true; }
+ public String getActions() { return null; }
+}
diff --git a/java/io/FileReader.java b/java/io/FileReader.java
new file mode 100644
index 0000000..acc3a19
--- /dev/null
+++ b/java/io/FileReader.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Convenience class for reading character files. The constructors of this
+ * class assume that the default character encoding and the default byte-buffer
+ * size are appropriate. To specify these values yourself, construct an
+ * InputStreamReader on a FileInputStream.
+ *
+ * <p><code>FileReader</code> is meant for reading streams of characters.
+ * For reading streams of raw bytes, consider using a
+ * <code>FileInputStream</code>.
+ *
+ * @see InputStreamReader
+ * @see FileInputStream
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+public class FileReader extends InputStreamReader {
+
+ /**
+ * Creates a new <tt>FileReader</tt>, given the name of the
+ * file to read from.
+ *
+ * @param fileName the name of the file to read from
+ * @exception FileNotFoundException if the named file does not exist,
+ * is a directory rather than a regular file,
+ * or for some other reason cannot be opened for
+ * reading.
+ */
+ public FileReader(String fileName) throws FileNotFoundException {
+ super(new FileInputStream(fileName));
+ }
+
+ /**
+ * Creates a new <tt>FileReader</tt>, given the <tt>File</tt>
+ * to read from.
+ *
+ * @param file the <tt>File</tt> to read from
+ * @exception FileNotFoundException if the file does not exist,
+ * is a directory rather than a regular file,
+ * or for some other reason cannot be opened for
+ * reading.
+ */
+ public FileReader(File file) throws FileNotFoundException {
+ super(new FileInputStream(file));
+ }
+
+ /**
+ * Creates a new <tt>FileReader</tt>, given the
+ * <tt>FileDescriptor</tt> to read from.
+ *
+ * @param fd the FileDescriptor to read from
+ */
+ public FileReader(FileDescriptor fd) {
+ super(new FileInputStream(fd));
+ }
+
+}
diff --git a/java/io/FileSystem.java b/java/io/FileSystem.java
new file mode 100644
index 0000000..ffa640c
--- /dev/null
+++ b/java/io/FileSystem.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.lang.annotation.Native;
+
+/**
+ * Package-private abstract class for the local filesystem abstraction.
+ */
+
+abstract class FileSystem {
+
+ /* -- Normalization and construction -- */
+
+ /**
+ * Return the local filesystem's name-separator character.
+ */
+ public abstract char getSeparator();
+
+ /**
+ * Return the local filesystem's path-separator character.
+ */
+ public abstract char getPathSeparator();
+
+ /**
+ * Convert the given pathname string to normal form. If the string is
+ * already in normal form then it is simply returned.
+ */
+ public abstract String normalize(String path);
+
+ /**
+ * Compute the length of this pathname string's prefix. The pathname
+ * string must be in normal form.
+ */
+ public abstract int prefixLength(String path);
+
+ /**
+ * Resolve the child pathname string against the parent.
+ * Both strings must be in normal form, and the result
+ * will be in normal form.
+ */
+ public abstract String resolve(String parent, String child);
+
+ /**
+ * Return the parent pathname string to be used when the parent-directory
+ * argument in one of the two-argument File constructors is the empty
+ * pathname.
+ */
+ public abstract String getDefaultParent();
+
+ /**
+ * Post-process the given URI path string if necessary. This is used on
+ * win32, e.g., to transform "/c:/foo" into "c:/foo". The path string
+ * still has slash separators; code in the File class will translate them
+ * after this method returns.
+ */
+ public abstract String fromURIPath(String path);
+
+
+ /* -- Path operations -- */
+
+ /**
+ * Tell whether or not the given abstract pathname is absolute.
+ */
+ public abstract boolean isAbsolute(File f);
+
+ /**
+ * Resolve the given abstract pathname into absolute form. Invoked by the
+ * getAbsolutePath and getCanonicalPath methods in the File class.
+ */
+ public abstract String resolve(File f);
+
+ public abstract String canonicalize(String path) throws IOException;
+
+
+ /* -- Attribute accessors -- */
+
+ /* Constants for simple boolean attributes */
+ @Native public static final int BA_EXISTS = 0x01;
+ @Native public static final int BA_REGULAR = 0x02;
+ @Native public static final int BA_DIRECTORY = 0x04;
+ @Native public static final int BA_HIDDEN = 0x08;
+
+ /**
+ * Return the simple boolean attributes for the file or directory denoted
+ * by the given abstract pathname, or zero if it does not exist or some
+ * other I/O error occurs.
+ */
+ public abstract int getBooleanAttributes(File f);
+
+ @Native public static final int ACCESS_READ = 0x04;
+ @Native public static final int ACCESS_WRITE = 0x02;
+ @Native public static final int ACCESS_EXECUTE = 0x01;
+ // Android-added: b/25878034, to support File.exists() reimplementation.
+ public static final int ACCESS_OK = 0x08;
+
+ /**
+ * Check whether the file or directory denoted by the given abstract
+ * pathname may be accessed by this process. The second argument specifies
+ * which access, ACCESS_READ, ACCESS_WRITE or ACCESS_EXECUTE, to check.
+ * Return false if access is denied or an I/O error occurs
+ */
+ public abstract boolean checkAccess(File f, int access);
+ /**
+ * Set on or off the access permission (to owner only or to all) to the file
+ * or directory denoted by the given abstract pathname, based on the parameters
+ * enable, access and oweronly.
+ */
+ public abstract boolean setPermission(File f, int access, boolean enable, boolean owneronly);
+
+ /**
+ * Return the time at which the file or directory denoted by the given
+ * abstract pathname was last modified, or zero if it does not exist or
+ * some other I/O error occurs.
+ */
+ public abstract long getLastModifiedTime(File f);
+
+ /**
+ * Return the length in bytes of the file denoted by the given abstract
+ * pathname, or zero if it does not exist, is a directory, or some other
+ * I/O error occurs.
+ */
+ public abstract long getLength(File f);
+
+
+ /* -- File operations -- */
+
+ /**
+ * Create a new empty file with the given pathname. Return
+ * <code>true</code> if the file was created and <code>false</code> if a
+ * file or directory with the given pathname already exists. Throw an
+ * IOException if an I/O error occurs.
+ */
+ public abstract boolean createFileExclusively(String pathname)
+ throws IOException;
+
+ /**
+ * Delete the file or directory denoted by the given abstract pathname,
+ * returning <code>true</code> if and only if the operation succeeds.
+ */
+ public abstract boolean delete(File f);
+
+ /**
+ * List the elements of the directory denoted by the given abstract
+ * pathname. Return an array of strings naming the elements of the
+ * directory if successful; otherwise, return <code>null</code>.
+ */
+ public abstract String[] list(File f);
+
+ /**
+ * Create a new directory denoted by the given abstract pathname,
+ * returning <code>true</code> if and only if the operation succeeds.
+ */
+ public abstract boolean createDirectory(File f);
+
+ /**
+ * Rename the file or directory denoted by the first abstract pathname to
+ * the second abstract pathname, returning <code>true</code> if and only if
+ * the operation succeeds.
+ */
+ public abstract boolean rename(File f1, File f2);
+
+ /**
+ * Set the last-modified time of the file or directory denoted by the
+ * given abstract pathname, returning <code>true</code> if and only if the
+ * operation succeeds.
+ */
+ public abstract boolean setLastModifiedTime(File f, long time);
+
+ /**
+ * Mark the file or directory denoted by the given abstract pathname as
+ * read-only, returning <code>true</code> if and only if the operation
+ * succeeds.
+ */
+ public abstract boolean setReadOnly(File f);
+
+
+ /* -- Filesystem interface -- */
+
+ /**
+ * List the available filesystem roots.
+ */
+ public abstract File[] listRoots();
+
+ /* -- Disk usage -- */
+ @Native public static final int SPACE_TOTAL = 0;
+ @Native public static final int SPACE_FREE = 1;
+ @Native public static final int SPACE_USABLE = 2;
+
+ public abstract long getSpace(File f, int t);
+
+ /* -- Basic infrastructure -- */
+
+ /**
+ * Compare two abstract pathnames lexicographically.
+ */
+ public abstract int compare(File f1, File f2);
+
+ /**
+ * Compute the hash code of an abstract pathname.
+ */
+ public abstract int hashCode(File f);
+
+ // Flags for enabling/disabling performance optimizations for file
+ // name canonicalization
+ // Android-changed: Disabled caches for security reasons (b/62301183)
+ //static boolean useCanonCaches = true;
+ //static boolean useCanonPrefixCache = true;
+ static boolean useCanonCaches = false;
+ static boolean useCanonPrefixCache = false;
+
+ private static boolean getBooleanProperty(String prop, boolean defaultVal) {
+ String val = System.getProperty(prop);
+ if (val == null) return defaultVal;
+ if (val.equalsIgnoreCase("true")) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ static {
+ useCanonCaches = getBooleanProperty("sun.io.useCanonCaches",
+ useCanonCaches);
+ useCanonPrefixCache = getBooleanProperty("sun.io.useCanonPrefixCache",
+ useCanonPrefixCache);
+ }
+}
diff --git a/java/io/FileWriter.java b/java/io/FileWriter.java
new file mode 100644
index 0000000..7475ea4
--- /dev/null
+++ b/java/io/FileWriter.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Convenience class for writing character files. The constructors of this
+ * class assume that the default character encoding and the default byte-buffer
+ * size are acceptable. To specify these values yourself, construct an
+ * OutputStreamWriter on a FileOutputStream.
+ *
+ * <p>Whether or not a file is available or may be created depends upon the
+ * underlying platform. Some platforms, in particular, allow a file to be
+ * opened for writing by only one <tt>FileWriter</tt> (or other file-writing
+ * object) at a time. In such situations the constructors in this class
+ * will fail if the file involved is already open.
+ *
+ * <p><code>FileWriter</code> is meant for writing streams of characters.
+ * For writing streams of raw bytes, consider using a
+ * <code>FileOutputStream</code>.
+ *
+ * @see OutputStreamWriter
+ * @see FileOutputStream
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class FileWriter extends OutputStreamWriter {
+
+ /**
+ * Constructs a FileWriter object given a file name.
+ *
+ * @param fileName String The system-dependent filename.
+ * @throws IOException if the named file exists but is a directory rather
+ * than a regular file, does not exist but cannot be
+ * created, or cannot be opened for any other reason
+ */
+ public FileWriter(String fileName) throws IOException {
+ super(new FileOutputStream(fileName));
+ }
+
+ /**
+ * Constructs a FileWriter object given a file name with a boolean
+ * indicating whether or not to append the data written.
+ *
+ * @param fileName String The system-dependent filename.
+ * @param append boolean if <code>true</code>, then data will be written
+ * to the end of the file rather than the beginning.
+ * @throws IOException if the named file exists but is a directory rather
+ * than a regular file, does not exist but cannot be
+ * created, or cannot be opened for any other reason
+ */
+ public FileWriter(String fileName, boolean append) throws IOException {
+ super(new FileOutputStream(fileName, append));
+ }
+
+ /**
+ * Constructs a FileWriter object given a File object.
+ *
+ * @param file a File object to write to.
+ * @throws IOException if the file exists but is a directory rather than
+ * a regular file, does not exist but cannot be created,
+ * or cannot be opened for any other reason
+ */
+ public FileWriter(File file) throws IOException {
+ super(new FileOutputStream(file));
+ }
+
+ /**
+ * Constructs a FileWriter object given a File object. If the second
+ * argument is <code>true</code>, then bytes will be written to the end
+ * of the file rather than the beginning.
+ *
+ * @param file a File object to write to
+ * @param append if <code>true</code>, then bytes will be written
+ * to the end of the file rather than the beginning
+ * @throws IOException if the file exists but is a directory rather than
+ * a regular file, does not exist but cannot be created,
+ * or cannot be opened for any other reason
+ * @since 1.4
+ */
+ public FileWriter(File file, boolean append) throws IOException {
+ super(new FileOutputStream(file, append));
+ }
+
+ /**
+ * Constructs a FileWriter object associated with a file descriptor.
+ *
+ * @param fd FileDescriptor object to write to.
+ */
+ public FileWriter(FileDescriptor fd) {
+ super(new FileOutputStream(fd));
+ }
+
+}
diff --git a/java/io/FilenameFilter.java b/java/io/FilenameFilter.java
new file mode 100644
index 0000000..25d866b
--- /dev/null
+++ b/java/io/FilenameFilter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+// Android-changed: Removed @see tag (target does not exist on Android):
+// @see java.awt.FileDialog#setFilenameFilter(java.io.FilenameFilter)
+/**
+ * Instances of classes that implement this interface are used to
+ * filter filenames. These instances are used to filter directory
+ * listings in the <code>list</code> method of class
+ * <code>File</code>, and by the Abstract Window Toolkit's file
+ * dialog component.
+ *
+ * @author Arthur van Hoff
+ * @author Jonathan Payne
+ * @see java.io.File
+ * @see java.io.File#list(java.io.FilenameFilter)
+ * @since JDK1.0
+ */
+@FunctionalInterface
+public interface FilenameFilter {
+ /**
+ * Tests if a specified file should be included in a file list.
+ *
+ * @param dir the directory in which the file was found.
+ * @param name the name of the file.
+ * @return <code>true</code> if and only if the name should be
+ * included in the file list; <code>false</code> otherwise.
+ */
+ boolean accept(File dir, String name);
+}
diff --git a/java/io/FilterInputStream.java b/java/io/FilterInputStream.java
new file mode 100644
index 0000000..10beaea
--- /dev/null
+++ b/java/io/FilterInputStream.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * A <code>FilterInputStream</code> contains
+ * some other input stream, which it uses as
+ * its basic source of data, possibly transforming
+ * the data along the way or providing additional
+ * functionality. The class <code>FilterInputStream</code>
+ * itself simply overrides all methods of
+ * <code>InputStream</code> with versions that
+ * pass all requests to the contained input
+ * stream. Subclasses of <code>FilterInputStream</code>
+ * may further override some of these methods
+ * and may also provide additional methods
+ * and fields.
+ *
+ * @author Jonathan Payne
+ * @since JDK1.0
+ */
+public
+class FilterInputStream extends InputStream {
+ /**
+ * The input stream to be filtered.
+ */
+ protected volatile InputStream in;
+
+ /**
+ * Creates a <code>FilterInputStream</code>
+ * by assigning the argument <code>in</code>
+ * to the field <code>this.in</code> so as
+ * to remember it for later use.
+ *
+ * @param in the underlying input stream, or <code>null</code> if
+ * this instance is to be created without an underlying stream.
+ */
+ protected FilterInputStream(InputStream in) {
+ this.in = in;
+ }
+
+ /**
+ * Reads the next byte of data from this input stream. The value
+ * byte is returned as an <code>int</code> in the range
+ * <code>0</code> to <code>255</code>. If no byte is available
+ * because the end of the stream has been reached, the value
+ * <code>-1</code> is returned. This method blocks until input data
+ * is available, the end of the stream is detected, or an exception
+ * is thrown.
+ * <p>
+ * This method
+ * simply performs <code>in.read()</code> and returns the result.
+ *
+ * @return the next byte of data, or <code>-1</code> if the end of the
+ * stream is reached.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public int read() throws IOException {
+ return in.read();
+ }
+
+ /**
+ * Reads up to <code>byte.length</code> bytes of data from this
+ * input stream into an array of bytes. This method blocks until some
+ * input is available.
+ * <p>
+ * This method simply performs the call
+ * <code>read(b, 0, b.length)</code> and returns
+ * the result. It is important that it does
+ * <i>not</i> do <code>in.read(b)</code> instead;
+ * certain subclasses of <code>FilterInputStream</code>
+ * depend on the implementation strategy actually
+ * used.
+ *
+ * @param b the buffer into which the data is read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the stream has been reached.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#read(byte[], int, int)
+ */
+ public int read(byte b[]) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ /**
+ * Reads up to <code>len</code> bytes of data from this input stream
+ * into an array of bytes. If <code>len</code> is not zero, the method
+ * blocks until some input is available; otherwise, no
+ * bytes are read and <code>0</code> is returned.
+ * <p>
+ * This method simply performs <code>in.read(b, off, len)</code>
+ * and returns the result.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in the destination array <code>b</code>
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the stream has been reached.
+ * @exception NullPointerException If <code>b</code> is <code>null</code>.
+ * @exception IndexOutOfBoundsException If <code>off</code> is negative,
+ * <code>len</code> is negative, or <code>len</code> is greater than
+ * <code>b.length - off</code>
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public int read(byte b[], int off, int len) throws IOException {
+ return in.read(b, off, len);
+ }
+
+ /**
+ * Skips over and discards <code>n</code> bytes of data from the
+ * input stream. The <code>skip</code> method may, for a variety of
+ * reasons, end up skipping over some smaller number of bytes,
+ * possibly <code>0</code>. The actual number of bytes skipped is
+ * returned.
+ * <p>
+ * This method simply performs <code>in.skip(n)</code>.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the actual number of bytes skipped.
+ * @exception IOException if the stream does not support seek,
+ * or if some other I/O error occurs.
+ */
+ public long skip(long n) throws IOException {
+ return in.skip(n);
+ }
+
+ /**
+ * Returns an estimate of the number of bytes that can be read (or
+ * skipped over) from this input stream without blocking by the next
+ * caller of a method for this input stream. The next caller might be
+ * the same thread or another thread. A single read or skip of this
+ * many bytes will not block, but may read or skip fewer bytes.
+ * <p>
+ * This method returns the result of {@link #in in}.available().
+ *
+ * @return an estimate of the number of bytes that can be read (or skipped
+ * over) from this input stream without blocking.
+ * @exception IOException if an I/O error occurs.
+ */
+ public int available() throws IOException {
+ return in.available();
+ }
+
+ /**
+ * Closes this input stream and releases any system resources
+ * associated with the stream.
+ * This
+ * method simply performs <code>in.close()</code>.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public void close() throws IOException {
+ in.close();
+ }
+
+ /**
+ * Marks the current position in this input stream. A subsequent
+ * call to the <code>reset</code> method repositions this stream at
+ * the last marked position so that subsequent reads re-read the same bytes.
+ * <p>
+ * The <code>readlimit</code> argument tells this input stream to
+ * allow that many bytes to be read before the mark position gets
+ * invalidated.
+ * <p>
+ * This method simply performs <code>in.mark(readlimit)</code>.
+ *
+ * @param readlimit the maximum limit of bytes that can be read before
+ * the mark position becomes invalid.
+ * @see java.io.FilterInputStream#in
+ * @see java.io.FilterInputStream#reset()
+ */
+ public synchronized void mark(int readlimit) {
+ in.mark(readlimit);
+ }
+
+ /**
+ * Repositions this stream to the position at the time the
+ * <code>mark</code> method was last called on this input stream.
+ * <p>
+ * This method
+ * simply performs <code>in.reset()</code>.
+ * <p>
+ * Stream marks are intended to be used in
+ * situations where you need to read ahead a little to see what's in
+ * the stream. Often this is most easily done by invoking some
+ * general parser. If the stream is of the type handled by the
+ * parse, it just chugs along happily. If the stream is not of
+ * that type, the parser should toss an exception when it fails.
+ * If this happens within readlimit bytes, it allows the outer
+ * code to reset the stream and try another parser.
+ *
+ * @exception IOException if the stream has not been marked or if the
+ * mark has been invalidated.
+ * @see java.io.FilterInputStream#in
+ * @see java.io.FilterInputStream#mark(int)
+ */
+ public synchronized void reset() throws IOException {
+ in.reset();
+ }
+
+ /**
+ * Tests if this input stream supports the <code>mark</code>
+ * and <code>reset</code> methods.
+ * This method
+ * simply performs <code>in.markSupported()</code>.
+ *
+ * @return <code>true</code> if this stream type supports the
+ * <code>mark</code> and <code>reset</code> method;
+ * <code>false</code> otherwise.
+ * @see java.io.FilterInputStream#in
+ * @see java.io.InputStream#mark(int)
+ * @see java.io.InputStream#reset()
+ */
+ public boolean markSupported() {
+ return in.markSupported();
+ }
+}
diff --git a/java/io/FilterOutputStream.java b/java/io/FilterOutputStream.java
new file mode 100644
index 0000000..89f5ef5
--- /dev/null
+++ b/java/io/FilterOutputStream.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This class is the superclass of all classes that filter output
+ * streams. These streams sit on top of an already existing output
+ * stream (the <i>underlying</i> output stream) which it uses as its
+ * basic sink of data, but possibly transforming the data along the
+ * way or providing additional functionality.
+ * <p>
+ * The class <code>FilterOutputStream</code> itself simply overrides
+ * all methods of <code>OutputStream</code> with versions that pass
+ * all requests to the underlying output stream. Subclasses of
+ * <code>FilterOutputStream</code> may further override some of these
+ * methods as well as provide additional methods and fields.
+ *
+ * @author Jonathan Payne
+ * @since JDK1.0
+ */
+public
+class FilterOutputStream extends OutputStream {
+ /**
+ * The underlying output stream to be filtered.
+ */
+ protected OutputStream out;
+
+ // Android-added: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
+ /**
+ * Whether the stream is closed; implicitly initialized to false.
+ */
+ private boolean closed;
+
+ /**
+ * Creates an output stream filter built on top of the specified
+ * underlying output stream.
+ *
+ * @param out the underlying output stream to be assigned to
+ * the field <tt>this.out</tt> for later use, or
+ * <code>null</code> if this instance is to be
+ * created without an underlying stream.
+ */
+ public FilterOutputStream(OutputStream out) {
+ this.out = out;
+ }
+
+ /**
+ * Writes the specified <code>byte</code> to this output stream.
+ * <p>
+ * The <code>write</code> method of <code>FilterOutputStream</code>
+ * calls the <code>write</code> method of its underlying output stream,
+ * that is, it performs <tt>out.write(b)</tt>.
+ * <p>
+ * Implements the abstract <tt>write</tt> method of <tt>OutputStream</tt>.
+ *
+ * @param b the <code>byte</code>.
+ * @exception IOException if an I/O error occurs.
+ */
+ public void write(int b) throws IOException {
+ out.write(b);
+ }
+
+ /**
+ * Writes <code>b.length</code> bytes to this output stream.
+ * <p>
+ * The <code>write</code> method of <code>FilterOutputStream</code>
+ * calls its <code>write</code> method of three arguments with the
+ * arguments <code>b</code>, <code>0</code>, and
+ * <code>b.length</code>.
+ * <p>
+ * Note that this method does not call the one-argument
+ * <code>write</code> method of its underlying stream with the single
+ * argument <code>b</code>.
+ *
+ * @param b the data to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#write(byte[], int, int)
+ */
+ public void write(byte b[]) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Writes <code>len</code> bytes from the specified
+ * <code>byte</code> array starting at offset <code>off</code> to
+ * this output stream.
+ * <p>
+ * The <code>write</code> method of <code>FilterOutputStream</code>
+ * calls the <code>write</code> method of one argument on each
+ * <code>byte</code> to output.
+ * <p>
+ * Note that this method does not call the <code>write</code> method
+ * of its underlying input stream with the same arguments. Subclasses
+ * of <code>FilterOutputStream</code> should provide a more efficient
+ * implementation of this method.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#write(int)
+ */
+ public void write(byte b[], int off, int len) throws IOException {
+ if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
+ throw new IndexOutOfBoundsException();
+
+ for (int i = 0 ; i < len ; i++) {
+ write(b[off + i]);
+ }
+ }
+
+ /**
+ * Flushes this output stream and forces any buffered output bytes
+ * to be written out to the stream.
+ * <p>
+ * The <code>flush</code> method of <code>FilterOutputStream</code>
+ * calls the <code>flush</code> method of its underlying output stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#out
+ */
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ /**
+ * Closes this output stream and releases any system resources
+ * associated with the stream.
+ * <p>
+ * When not already closed, the {@code close} method of {@code
+ * FilterOutputStream} calls its {@code flush} method, and then
+ * calls the {@code close} method of its underlying output stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterOutputStream#flush()
+ * @see java.io.FilterOutputStream#out
+ */
+ // BEGIN Android-changed: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
+ /*
+ @SuppressWarnings("try")
+ public void close() throws IOException {
+ try (OutputStream ostream = out) {
+ flush();
+ }
+ }
+ */
+ @Override
+ public void close() throws IOException {
+ if (closed) {
+ return;
+ }
+ closed = true;
+
+ Throwable flushException = null;
+ try {
+ flush();
+ } catch (Throwable e) {
+ flushException = e;
+ throw e;
+ } finally {
+ if (flushException == null) {
+ out.close();
+ } else {
+ try {
+ out.close();
+ } catch (Throwable closeException) {
+ // evaluate possible precedence of flushException over closeException
+ if ((flushException instanceof ThreadDeath) &&
+ !(closeException instanceof ThreadDeath)) {
+ flushException.addSuppressed(closeException);
+ throw (ThreadDeath) flushException;
+ }
+
+ if (flushException != closeException) {
+ closeException.addSuppressed(flushException);
+ }
+
+ throw closeException;
+ }
+ }
+ }
+ }
+ // END Android-changed: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
+}
diff --git a/java/io/FilterReader.java b/java/io/FilterReader.java
new file mode 100644
index 0000000..0826230
--- /dev/null
+++ b/java/io/FilterReader.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Abstract class for reading filtered character streams.
+ * The abstract class <code>FilterReader</code> itself
+ * provides default methods that pass all requests to
+ * the contained stream. Subclasses of <code>FilterReader</code>
+ * should override some of these methods and may also provide
+ * additional methods and fields.
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public abstract class FilterReader extends Reader {
+
+ /**
+ * The underlying character-input stream.
+ */
+ protected Reader in;
+
+ /**
+ * Creates a new filtered reader.
+ *
+ * @param in a Reader object providing the underlying stream.
+ * @throws NullPointerException if <code>in</code> is <code>null</code>
+ */
+ protected FilterReader(Reader in) {
+ super(in);
+ this.in = in;
+ }
+
+ /**
+ * Reads a single character.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read() throws IOException {
+ return in.read();
+ }
+
+ /**
+ * Reads characters into a portion of an array.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read(char cbuf[], int off, int len) throws IOException {
+ return in.read(cbuf, off, len);
+ }
+
+ /**
+ * Skips characters.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public long skip(long n) throws IOException {
+ return in.skip(n);
+ }
+
+ /**
+ * Tells whether this stream is ready to be read.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public boolean ready() throws IOException {
+ return in.ready();
+ }
+
+ /**
+ * Tells whether this stream supports the mark() operation.
+ */
+ public boolean markSupported() {
+ return in.markSupported();
+ }
+
+ /**
+ * Marks the present position in the stream.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ in.mark(readAheadLimit);
+ }
+
+ /**
+ * Resets the stream.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void reset() throws IOException {
+ in.reset();
+ }
+
+ public void close() throws IOException {
+ in.close();
+ }
+
+}
diff --git a/java/io/FilterWriter.java b/java/io/FilterWriter.java
new file mode 100644
index 0000000..fb307d5
--- /dev/null
+++ b/java/io/FilterWriter.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Abstract class for writing filtered character streams.
+ * The abstract class <code>FilterWriter</code> itself
+ * provides default methods that pass all requests to the
+ * contained stream. Subclasses of <code>FilterWriter</code>
+ * should override some of these methods and may also
+ * provide additional methods and fields.
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public abstract class FilterWriter extends Writer {
+
+ /**
+ * The underlying character-output stream.
+ */
+ protected Writer out;
+
+ /**
+ * Create a new filtered writer.
+ *
+ * @param out a Writer object to provide the underlying stream.
+ * @throws NullPointerException if <code>out</code> is <code>null</code>
+ */
+ protected FilterWriter(Writer out) {
+ super(out);
+ this.out = out;
+ }
+
+ /**
+ * Writes a single character.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void write(int c) throws IOException {
+ out.write(c);
+ }
+
+ /**
+ * Writes a portion of an array of characters.
+ *
+ * @param cbuf Buffer of characters to be written
+ * @param off Offset from which to start reading characters
+ * @param len Number of characters to be written
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void write(char cbuf[], int off, int len) throws IOException {
+ out.write(cbuf, off, len);
+ }
+
+ /**
+ * Writes a portion of a string.
+ *
+ * @param str String to be written
+ * @param off Offset from which to start reading characters
+ * @param len Number of characters to be written
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void write(String str, int off, int len) throws IOException {
+ out.write(str, off, len);
+ }
+
+ /**
+ * Flushes the stream.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ public void close() throws IOException {
+ out.close();
+ }
+
+}
diff --git a/java/io/Flushable.java b/java/io/Flushable.java
new file mode 100644
index 0000000..fe90fbd
--- /dev/null
+++ b/java/io/Flushable.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.IOException;
+
+/**
+ * A <tt>Flushable</tt> is a destination of data that can be flushed. The
+ * flush method is invoked to write any buffered output to the underlying
+ * stream.
+ *
+ * @since 1.5
+ */
+public interface Flushable {
+
+ /**
+ * Flushes this stream by writing any buffered output to the underlying
+ * stream.
+ *
+ * @throws IOException If an I/O error occurs
+ */
+ void flush() throws IOException;
+}
diff --git a/java/io/IOError.java b/java/io/IOError.java
new file mode 100644
index 0000000..f9626cd
--- /dev/null
+++ b/java/io/IOError.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Thrown when a serious I/O error has occurred.
+ *
+ * @author Xueming Shen
+ * @since 1.6
+ */
+public class IOError extends Error {
+ /**
+ * Constructs a new instance of IOError with the specified cause. The
+ * IOError is created with the detail message of
+ * <tt>(cause==null ? null : cause.toString())</tt> (which typically
+ * contains the class and detail message of cause).
+ *
+ * @param cause
+ * The cause of this error, or <tt>null</tt> if the cause
+ * is not known
+ */
+ public IOError(Throwable cause) {
+ super(cause);
+ }
+
+ private static final long serialVersionUID = 67100927991680413L;
+}
diff --git a/java/io/IOException.java b/java/io/IOException.java
new file mode 100644
index 0000000..745b579
--- /dev/null
+++ b/java/io/IOException.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that an I/O exception of some sort has occurred. This
+ * class is the general class of exceptions produced by failed or
+ * interrupted I/O operations.
+ *
+ * @author unascribed
+ * @see java.io.InputStream
+ * @see java.io.OutputStream
+ * @since JDK1.0
+ */
+public
+class IOException extends Exception {
+ static final long serialVersionUID = 7818375828146090155L;
+
+ /**
+ * Constructs an {@code IOException} with {@code null}
+ * as its error detail message.
+ */
+ public IOException() {
+ super();
+ }
+
+ /**
+ * Constructs an {@code IOException} with the specified detail message.
+ *
+ * @param message
+ * The detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method)
+ */
+ public IOException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs an {@code IOException} with the specified detail message
+ * and cause.
+ *
+ * <p> Note that the detail message associated with {@code cause} is
+ * <i>not</i> automatically incorporated into this exception's detail
+ * message.
+ *
+ * @param message
+ * The detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method)
+ *
+ * @param cause
+ * The cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is permitted,
+ * and indicates that the cause is nonexistent or unknown.)
+ *
+ * @since 1.6
+ */
+ public IOException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructs an {@code IOException} with the specified cause and a
+ * detail message of {@code (cause==null ? null : cause.toString())}
+ * (which typically contains the class and detail message of {@code cause}).
+ * This constructor is useful for IO exceptions that are little more
+ * than wrappers for other throwables.
+ *
+ * @param cause
+ * The cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is permitted,
+ * and indicates that the cause is nonexistent or unknown.)
+ *
+ * @since 1.6
+ */
+ public IOException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/java/io/InputStream.java b/java/io/InputStream.java
new file mode 100644
index 0000000..6c46a40
--- /dev/null
+++ b/java/io/InputStream.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This abstract class is the superclass of all classes representing
+ * an input stream of bytes.
+ *
+ * <p> Applications that need to define a subclass of <code>InputStream</code>
+ * must always provide a method that returns the next byte of input.
+ *
+ * @author Arthur van Hoff
+ * @see java.io.BufferedInputStream
+ * @see java.io.ByteArrayInputStream
+ * @see java.io.DataInputStream
+ * @see java.io.FilterInputStream
+ * @see java.io.InputStream#read()
+ * @see java.io.OutputStream
+ * @see java.io.PushbackInputStream
+ * @since JDK1.0
+ */
+public abstract class InputStream implements Closeable {
+
+ // MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to
+ // use when skipping.
+ private static final int MAX_SKIP_BUFFER_SIZE = 2048;
+
+ /**
+ * Reads the next byte of data from the input stream. The value byte is
+ * returned as an <code>int</code> in the range <code>0</code> to
+ * <code>255</code>. If no byte is available because the end of the stream
+ * has been reached, the value <code>-1</code> is returned. This method
+ * blocks until input data is available, the end of the stream is detected,
+ * or an exception is thrown.
+ *
+ * <p> A subclass must provide an implementation of this method.
+ *
+ * @return the next byte of data, or <code>-1</code> if the end of the
+ * stream is reached.
+ * @exception IOException if an I/O error occurs.
+ */
+ public abstract int read() throws IOException;
+
+ /**
+ * Reads some number of bytes from the input stream and stores them into
+ * the buffer array <code>b</code>. The number of bytes actually read is
+ * returned as an integer. This method blocks until input data is
+ * available, end of file is detected, or an exception is thrown.
+ *
+ * <p> If the length of <code>b</code> is zero, then no bytes are read and
+ * <code>0</code> is returned; otherwise, there is an attempt to read at
+ * least one byte. If no byte is available because the stream is at the
+ * end of the file, the value <code>-1</code> is returned; otherwise, at
+ * least one byte is read and stored into <code>b</code>.
+ *
+ * <p> The first byte read is stored into element <code>b[0]</code>, the
+ * next one into <code>b[1]</code>, and so on. The number of bytes read is,
+ * at most, equal to the length of <code>b</code>. Let <i>k</i> be the
+ * number of bytes actually read; these bytes will be stored in elements
+ * <code>b[0]</code> through <code>b[</code><i>k</i><code>-1]</code>,
+ * leaving elements <code>b[</code><i>k</i><code>]</code> through
+ * <code>b[b.length-1]</code> unaffected.
+ *
+ * <p> The <code>read(b)</code> method for class <code>InputStream</code>
+ * has the same effect as: <pre><code> read(b, 0, b.length) </code></pre>
+ *
+ * @param b the buffer into which the data is read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the stream has been reached.
+ * @exception IOException If the first byte cannot be read for any reason
+ * other than the end of the file, if the input stream has been closed, or
+ * if some other I/O error occurs.
+ * @exception NullPointerException if <code>b</code> is <code>null</code>.
+ * @see java.io.InputStream#read(byte[], int, int)
+ */
+ public int read(byte b[]) throws IOException {
+ return read(b, 0, b.length);
+ }
+
+ /**
+ * Reads up to <code>len</code> bytes of data from the input stream into
+ * an array of bytes. An attempt is made to read as many as
+ * <code>len</code> bytes, but a smaller number may be read.
+ * The number of bytes actually read is returned as an integer.
+ *
+ * <p> This method blocks until input data is available, end of file is
+ * detected, or an exception is thrown.
+ *
+ * <p> If <code>len</code> is zero, then no bytes are read and
+ * <code>0</code> is returned; otherwise, there is an attempt to read at
+ * least one byte. If no byte is available because the stream is at end of
+ * file, the value <code>-1</code> is returned; otherwise, at least one
+ * byte is read and stored into <code>b</code>.
+ *
+ * <p> The first byte read is stored into element <code>b[off]</code>, the
+ * next one into <code>b[off+1]</code>, and so on. The number of bytes read
+ * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
+ * bytes actually read; these bytes will be stored in elements
+ * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
+ * leaving elements <code>b[off+</code><i>k</i><code>]</code> through
+ * <code>b[off+len-1]</code> unaffected.
+ *
+ * <p> In every case, elements <code>b[0]</code> through
+ * <code>b[off]</code> and elements <code>b[off+len]</code> through
+ * <code>b[b.length-1]</code> are unaffected.
+ *
+ * <p> The <code>read(b,</code> <code>off,</code> <code>len)</code> method
+ * for class <code>InputStream</code> simply calls the method
+ * <code>read()</code> repeatedly. If the first such call results in an
+ * <code>IOException</code>, that exception is returned from the call to
+ * the <code>read(b,</code> <code>off,</code> <code>len)</code> method. If
+ * any subsequent call to <code>read()</code> results in a
+ * <code>IOException</code>, the exception is caught and treated as if it
+ * were end of file; the bytes read up to that point are stored into
+ * <code>b</code> and the number of bytes read before the exception
+ * occurred is returned. The default implementation of this method blocks
+ * until the requested amount of input data <code>len</code> has been read,
+ * end of file is detected, or an exception is thrown. Subclasses are encouraged
+ * to provide a more efficient implementation of this method.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in array <code>b</code>
+ * at which the data is written.
+ * @param len the maximum number of bytes to read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the stream has been reached.
+ * @exception IOException If the first byte cannot be read for any reason
+ * other than end of file, or if the input stream has been closed, or if
+ * some other I/O error occurs.
+ * @exception NullPointerException If <code>b</code> is <code>null</code>.
+ * @exception IndexOutOfBoundsException If <code>off</code> is negative,
+ * <code>len</code> is negative, or <code>len</code> is greater than
+ * <code>b.length - off</code>
+ * @see java.io.InputStream#read()
+ */
+ public int read(byte b[], int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ int c = read();
+ if (c == -1) {
+ return -1;
+ }
+ b[off] = (byte)c;
+
+ int i = 1;
+ try {
+ for (; i < len ; i++) {
+ c = read();
+ if (c == -1) {
+ break;
+ }
+ b[off + i] = (byte)c;
+ }
+ } catch (IOException ee) {
+ }
+ return i;
+ }
+
+ /**
+ * Skips over and discards <code>n</code> bytes of data from this input
+ * stream. The <code>skip</code> method may, for a variety of reasons, end
+ * up skipping over some smaller number of bytes, possibly <code>0</code>.
+ * This may result from any of a number of conditions; reaching end of file
+ * before <code>n</code> bytes have been skipped is only one possibility.
+ * The actual number of bytes skipped is returned. If {@code n} is
+ * negative, the {@code skip} method for class {@code InputStream} always
+ * returns 0, and no bytes are skipped. Subclasses may handle the negative
+ * value differently.
+ *
+ * <p> The <code>skip</code> method of this class creates a
+ * byte array and then repeatedly reads into it until <code>n</code> bytes
+ * have been read or the end of the stream has been reached. Subclasses are
+ * encouraged to provide a more efficient implementation of this method.
+ * For instance, the implementation may depend on the ability to seek.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the actual number of bytes skipped.
+ * @exception IOException if the stream does not support seek,
+ * or if some other I/O error occurs.
+ */
+ public long skip(long n) throws IOException {
+
+ long remaining = n;
+ int nr;
+
+ if (n <= 0) {
+ return 0;
+ }
+
+ int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
+ byte[] skipBuffer = new byte[size];
+ while (remaining > 0) {
+ nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
+ if (nr < 0) {
+ break;
+ }
+ remaining -= nr;
+ }
+
+ return n - remaining;
+ }
+
+ /**
+ * Returns an estimate of the number of bytes that can be read (or
+ * skipped over) from this input stream without blocking by the next
+ * invocation of a method for this input stream. The next invocation
+ * might be the same thread or another thread. A single read or skip of this
+ * many bytes will not block, but may read or skip fewer bytes.
+ *
+ * <p> Note that while some implementations of {@code InputStream} will return
+ * the total number of bytes in the stream, many will not. It is
+ * never correct to use the return value of this method to allocate
+ * a buffer intended to hold all data in this stream.
+ *
+ * <p> A subclass' implementation of this method may choose to throw an
+ * {@link IOException} if this input stream has been closed by
+ * invoking the {@link #close()} method.
+ *
+ * <p> The {@code available} method for class {@code InputStream} always
+ * returns {@code 0}.
+ *
+ * <p> This method should be overridden by subclasses.
+ *
+ * @return an estimate of the number of bytes that can be read (or skipped
+ * over) from this input stream without blocking or {@code 0} when
+ * it reaches the end of the input stream.
+ * @exception IOException if an I/O error occurs.
+ */
+ public int available() throws IOException {
+ return 0;
+ }
+
+ /**
+ * Closes this input stream and releases any system resources associated
+ * with the stream.
+ *
+ * <p> The <code>close</code> method of <code>InputStream</code> does
+ * nothing.
+ *
+ * @exception IOException if an I/O error occurs.
+ */
+ public void close() throws IOException {}
+
+ /**
+ * Marks the current position in this input stream. A subsequent call to
+ * the <code>reset</code> method repositions this stream at the last marked
+ * position so that subsequent reads re-read the same bytes.
+ *
+ * <p> The <code>readlimit</code> arguments tells this input stream to
+ * allow that many bytes to be read before the mark position gets
+ * invalidated.
+ *
+ * <p> The general contract of <code>mark</code> is that, if the method
+ * <code>markSupported</code> returns <code>true</code>, the stream somehow
+ * remembers all the bytes read after the call to <code>mark</code> and
+ * stands ready to supply those same bytes again if and whenever the method
+ * <code>reset</code> is called. However, the stream is not required to
+ * remember any data at all if more than <code>readlimit</code> bytes are
+ * read from the stream before <code>reset</code> is called.
+ *
+ * <p> Marking a closed stream should not have any effect on the stream.
+ *
+ * <p> The <code>mark</code> method of <code>InputStream</code> does
+ * nothing.
+ *
+ * @param readlimit the maximum limit of bytes that can be read before
+ * the mark position becomes invalid.
+ * @see java.io.InputStream#reset()
+ */
+ public synchronized void mark(int readlimit) {}
+
+ /**
+ * Repositions this stream to the position at the time the
+ * <code>mark</code> method was last called on this input stream.
+ *
+ * <p> The general contract of <code>reset</code> is:
+ *
+ * <ul>
+ * <li> If the method <code>markSupported</code> returns
+ * <code>true</code>, then:
+ *
+ * <ul><li> If the method <code>mark</code> has not been called since
+ * the stream was created, or the number of bytes read from the stream
+ * since <code>mark</code> was last called is larger than the argument
+ * to <code>mark</code> at that last call, then an
+ * <code>IOException</code> might be thrown.
+ *
+ * <li> If such an <code>IOException</code> is not thrown, then the
+ * stream is reset to a state such that all the bytes read since the
+ * most recent call to <code>mark</code> (or since the start of the
+ * file, if <code>mark</code> has not been called) will be resupplied
+ * to subsequent callers of the <code>read</code> method, followed by
+ * any bytes that otherwise would have been the next input data as of
+ * the time of the call to <code>reset</code>. </ul>
+ *
+ * <li> If the method <code>markSupported</code> returns
+ * <code>false</code>, then:
+ *
+ * <ul><li> The call to <code>reset</code> may throw an
+ * <code>IOException</code>.
+ *
+ * <li> If an <code>IOException</code> is not thrown, then the stream
+ * is reset to a fixed state that depends on the particular type of the
+ * input stream and how it was created. The bytes that will be supplied
+ * to subsequent callers of the <code>read</code> method depend on the
+ * particular type of the input stream. </ul></ul>
+ *
+ * <p>The method <code>reset</code> for class <code>InputStream</code>
+ * does nothing except throw an <code>IOException</code>.
+ *
+ * @exception IOException if this stream has not been marked or if the
+ * mark has been invalidated.
+ * @see java.io.InputStream#mark(int)
+ * @see java.io.IOException
+ */
+ public synchronized void reset() throws IOException {
+ throw new IOException("mark/reset not supported");
+ }
+
+ /**
+ * Tests if this input stream supports the <code>mark</code> and
+ * <code>reset</code> methods. Whether or not <code>mark</code> and
+ * <code>reset</code> are supported is an invariant property of a
+ * particular input stream instance. The <code>markSupported</code> method
+ * of <code>InputStream</code> returns <code>false</code>.
+ *
+ * @return <code>true</code> if this stream instance supports the mark
+ * and reset methods; <code>false</code> otherwise.
+ * @see java.io.InputStream#mark(int)
+ * @see java.io.InputStream#reset()
+ */
+ public boolean markSupported() {
+ return false;
+ }
+
+}
diff --git a/java/io/InputStreamReader.java b/java/io/InputStreamReader.java
new file mode 100644
index 0000000..e131dca
--- /dev/null
+++ b/java/io/InputStreamReader.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import sun.nio.cs.StreamDecoder;
+
+
+/**
+ * An InputStreamReader is a bridge from byte streams to character streams: It
+ * reads bytes and decodes them into characters using a specified {@link
+ * java.nio.charset.Charset charset}. The charset that it uses
+ * may be specified by name or may be given explicitly, or the platform's
+ * default charset may be accepted.
+ *
+ * <p> Each invocation of one of an InputStreamReader's read() methods may
+ * cause one or more bytes to be read from the underlying byte-input stream.
+ * To enable the efficient conversion of bytes to characters, more bytes may
+ * be read ahead from the underlying stream than are necessary to satisfy the
+ * current read operation.
+ *
+ * <p> For top efficiency, consider wrapping an InputStreamReader within a
+ * BufferedReader. For example:
+ *
+ * <pre>
+ * BufferedReader in
+ * = new BufferedReader(new InputStreamReader(System.in));
+ * </pre>
+ *
+ * @see BufferedReader
+ * @see InputStream
+ * @see java.nio.charset.Charset
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class InputStreamReader extends Reader {
+
+ private final StreamDecoder sd;
+
+ /**
+ * Creates an InputStreamReader that uses the default charset.
+ *
+ * @param in An InputStream
+ */
+ public InputStreamReader(InputStream in) {
+ super(in);
+ try {
+ sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
+ } catch (UnsupportedEncodingException e) {
+ // The default encoding should always be available
+ throw new Error(e);
+ }
+ }
+
+ /**
+ * Creates an InputStreamReader that uses the named charset.
+ *
+ * @param in
+ * An InputStream
+ *
+ * @param charsetName
+ * The name of a supported
+ * {@link java.nio.charset.Charset charset}
+ *
+ * @exception UnsupportedEncodingException
+ * If the named charset is not supported
+ */
+ public InputStreamReader(InputStream in, String charsetName)
+ throws UnsupportedEncodingException
+ {
+ super(in);
+ if (charsetName == null)
+ throw new NullPointerException("charsetName");
+ sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
+ }
+
+ /**
+ * Creates an InputStreamReader that uses the given charset.
+ *
+ * @param in An InputStream
+ * @param cs A charset
+ *
+ * @since 1.4
+ * @spec JSR-51
+ */
+ public InputStreamReader(InputStream in, Charset cs) {
+ super(in);
+ if (cs == null)
+ throw new NullPointerException("charset");
+ sd = StreamDecoder.forInputStreamReader(in, this, cs);
+ }
+
+ /**
+ * Creates an InputStreamReader that uses the given charset decoder.
+ *
+ * @param in An InputStream
+ * @param dec A charset decoder
+ *
+ * @since 1.4
+ * @spec JSR-51
+ */
+ public InputStreamReader(InputStream in, CharsetDecoder dec) {
+ super(in);
+ if (dec == null)
+ throw new NullPointerException("charset decoder");
+ sd = StreamDecoder.forInputStreamReader(in, this, dec);
+ }
+
+ /**
+ * Returns the name of the character encoding being used by this stream.
+ *
+ * <p> If the encoding has an historical name then that name is returned;
+ * otherwise the encoding's canonical name is returned.
+ *
+ * <p> If this instance was created with the {@link
+ * #InputStreamReader(InputStream, String)} constructor then the returned
+ * name, being unique for the encoding, may differ from the name passed to
+ * the constructor. This method will return <code>null</code> if the
+ * stream has been closed.
+ * </p>
+ * @return The historical name of this encoding, or
+ * <code>null</code> if the stream has been closed
+ *
+ * @see java.nio.charset.Charset
+ *
+ * @revised 1.4
+ * @spec JSR-51
+ */
+ public String getEncoding() {
+ return sd.getEncoding();
+ }
+
+ /**
+ * Reads a single character.
+ *
+ * @return The character read, or -1 if the end of the stream has been
+ * reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read() throws IOException {
+ return sd.read();
+ }
+
+ /**
+ * Reads characters into a portion of an array.
+ *
+ * @param cbuf Destination buffer
+ * @param offset Offset at which to start storing characters
+ * @param length Maximum number of characters to read
+ *
+ * @return The number of characters read, or -1 if the end of the
+ * stream has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read(char cbuf[], int offset, int length) throws IOException {
+ return sd.read(cbuf, offset, length);
+ }
+
+ /**
+ * Tells whether this stream is ready to be read. An InputStreamReader is
+ * ready if its input buffer is not empty, or if bytes are available to be
+ * read from the underlying byte stream.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public boolean ready() throws IOException {
+ return sd.ready();
+ }
+
+ public void close() throws IOException {
+ sd.close();
+ }
+}
diff --git a/java/io/InterruptedIOException.java b/java/io/InterruptedIOException.java
new file mode 100644
index 0000000..29b7c29
--- /dev/null
+++ b/java/io/InterruptedIOException.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that an I/O operation has been interrupted. An
+ * <code>InterruptedIOException</code> is thrown to indicate that an
+ * input or output transfer has been terminated because the thread
+ * performing it was interrupted. The field {@link #bytesTransferred}
+ * indicates how many bytes were successfully transferred before
+ * the interruption occurred.
+ *
+ * @author unascribed
+ * @see java.io.InputStream
+ * @see java.io.OutputStream
+ * @see java.lang.Thread#interrupt()
+ * @since JDK1.0
+ */
+public
+class InterruptedIOException extends IOException {
+ private static final long serialVersionUID = 4020568460727500567L;
+
+ /**
+ * Constructs an <code>InterruptedIOException</code> with
+ * <code>null</code> as its error detail message.
+ */
+ public InterruptedIOException() {
+ super();
+ }
+
+ /**
+ * Constructs an <code>InterruptedIOException</code> with the
+ * specified detail message. The string <code>s</code> can be
+ * retrieved later by the
+ * <code>{@link java.lang.Throwable#getMessage}</code>
+ * method of class <code>java.lang.Throwable</code>.
+ *
+ * @param s the detail message.
+ */
+ public InterruptedIOException(String s) {
+ super(s);
+ }
+
+ /**
+ * Reports how many bytes had been transferred as part of the I/O
+ * operation before it was interrupted.
+ *
+ * @serial
+ */
+ public int bytesTransferred = 0;
+
+ // Android-added: Additional constructor for internal use.
+ /** @hide */
+ public InterruptedIOException(Throwable cause) {
+ super(cause);
+ }
+
+ // Android-added: Additional constructor for internal use.
+ /**
+ * Constructs a new instance with given detail message and cause.
+ *
+ * @hide internal use only
+ */
+ public InterruptedIOException(String detailMessage, Throwable cause) {
+ super(detailMessage, cause);
+ }
+}
diff --git a/java/io/InvalidClassException.java b/java/io/InvalidClassException.java
new file mode 100644
index 0000000..77f0a5a
--- /dev/null
+++ b/java/io/InvalidClassException.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Thrown when the Serialization runtime detects one of the following
+ * problems with a Class.
+ * <UL>
+ * <LI> The serial version of the class does not match that of the class
+ * descriptor read from the stream
+ * <LI> The class contains unknown datatypes
+ * <LI> The class does not have an accessible no-arg constructor
+ * </UL>
+ *
+ * @author unascribed
+ * @since JDK1.1
+ */
+public class InvalidClassException extends ObjectStreamException {
+
+ private static final long serialVersionUID = -4333316296251054416L;
+
+ /**
+ * Name of the invalid class.
+ *
+ * @serial Name of the invalid class.
+ */
+ public String classname;
+
+ /**
+ * Report an InvalidClassException for the reason specified.
+ *
+ * @param reason String describing the reason for the exception.
+ */
+ public InvalidClassException(String reason) {
+ super(reason);
+ }
+
+ /**
+ * Constructs an InvalidClassException object.
+ *
+ * @param cname a String naming the invalid class.
+ * @param reason a String describing the reason for the exception.
+ */
+ public InvalidClassException(String cname, String reason) {
+ super(reason);
+ classname = cname;
+ }
+
+ /**
+ * Produce the message and include the classname, if present.
+ */
+ public String getMessage() {
+ if (classname == null)
+ return super.getMessage();
+ else
+ return classname + "; " + super.getMessage();
+ }
+}
diff --git a/java/io/InvalidObjectException.java b/java/io/InvalidObjectException.java
new file mode 100644
index 0000000..fbe1108
--- /dev/null
+++ b/java/io/InvalidObjectException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Indicates that one or more deserialized objects failed validation
+ * tests. The argument should provide the reason for the failure.
+ *
+ * @see ObjectInputValidation
+ * @since JDK1.1
+ *
+ * @author unascribed
+ * @since JDK1.1
+ */
+public class InvalidObjectException extends ObjectStreamException {
+
+ private static final long serialVersionUID = 3233174318281839583L;
+
+ /**
+ * Constructs an <code>InvalidObjectException</code>.
+ * @param reason Detailed message explaining the reason for the failure.
+ *
+ * @see ObjectInputValidation
+ */
+ public InvalidObjectException(String reason) {
+ super(reason);
+ }
+}
diff --git a/java/io/LineNumberInputStream.java b/java/io/LineNumberInputStream.java
new file mode 100644
index 0000000..1f37a98
--- /dev/null
+++ b/java/io/LineNumberInputStream.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This class is an input stream filter that provides the added
+ * functionality of keeping track of the current line number.
+ * <p>
+ * A line is a sequence of bytes ending with a carriage return
+ * character ({@code '\u005Cr'}), a newline character
+ * ({@code '\u005Cn'}), or a carriage return character followed
+ * immediately by a linefeed character. In all three cases, the line
+ * terminating character(s) are returned as a single newline character.
+ * <p>
+ * The line number begins at {@code 0}, and is incremented by
+ * {@code 1} when a {@code read} returns a newline character.
+ *
+ * @author Arthur van Hoff
+ * @see java.io.LineNumberReader
+ * @since JDK1.0
+ * @deprecated This class incorrectly assumes that bytes adequately represent
+ * characters. As of JDK 1.1, the preferred way to operate on
+ * character streams is via the new character-stream classes, which
+ * include a class for counting line numbers.
+ */
+@Deprecated
+public
+class LineNumberInputStream extends FilterInputStream {
+ int pushBack = -1;
+ int lineNumber;
+ int markLineNumber;
+ int markPushBack = -1;
+
+ /**
+ * Constructs a newline number input stream that reads its input
+ * from the specified input stream.
+ *
+ * @param in the underlying input stream.
+ */
+ public LineNumberInputStream(InputStream in) {
+ super(in);
+ }
+
+ /**
+ * Reads the next byte of data from this input stream. The value
+ * byte is returned as an {@code int} in the range
+ * {@code 0} to {@code 255}. If no byte is available
+ * because the end of the stream has been reached, the value
+ * {@code -1} is returned. This method blocks until input data
+ * is available, the end of the stream is detected, or an exception
+ * is thrown.
+ * <p>
+ * The {@code read} method of
+ * {@code LineNumberInputStream} calls the {@code read}
+ * method of the underlying input stream. It checks for carriage
+ * returns and newline characters in the input, and modifies the
+ * current line number as appropriate. A carriage-return character or
+ * a carriage return followed by a newline character are both
+ * converted into a single newline character.
+ *
+ * @return the next byte of data, or {@code -1} if the end of this
+ * stream is reached.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ * @see java.io.LineNumberInputStream#getLineNumber()
+ */
+ @SuppressWarnings("fallthrough")
+ public int read() throws IOException {
+ int c = pushBack;
+
+ if (c != -1) {
+ pushBack = -1;
+ } else {
+ c = in.read();
+ }
+
+ switch (c) {
+ case '\r':
+ pushBack = in.read();
+ if (pushBack == '\n') {
+ pushBack = -1;
+ }
+ case '\n':
+ lineNumber++;
+ return '\n';
+ }
+ return c;
+ }
+
+ /**
+ * Reads up to {@code len} bytes of data from this input stream
+ * into an array of bytes. This method blocks until some input is available.
+ * <p>
+ * The {@code read} method of
+ * {@code LineNumberInputStream} repeatedly calls the
+ * {@code read} method of zero arguments to fill in the byte array.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset of the data.
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * {@code -1} if there is no more data because the end of
+ * this stream has been reached.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.LineNumberInputStream#read()
+ */
+ public int read(byte b[], int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) > b.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ int c = read();
+ if (c == -1) {
+ return -1;
+ }
+ b[off] = (byte)c;
+
+ int i = 1;
+ try {
+ for (; i < len ; i++) {
+ c = read();
+ if (c == -1) {
+ break;
+ }
+ if (b != null) {
+ b[off + i] = (byte)c;
+ }
+ }
+ } catch (IOException ee) {
+ }
+ return i;
+ }
+
+ /**
+ * Skips over and discards {@code n} bytes of data from this
+ * input stream. The {@code skip} method may, for a variety of
+ * reasons, end up skipping over some smaller number of bytes,
+ * possibly {@code 0}. The actual number of bytes skipped is
+ * returned. If {@code n} is negative, no bytes are skipped.
+ * <p>
+ * The {@code skip} method of {@code LineNumberInputStream} creates
+ * a byte array and then repeatedly reads into it until
+ * {@code n} bytes have been read or the end of the stream has
+ * been reached.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the actual number of bytes skipped.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public long skip(long n) throws IOException {
+ int chunk = 2048;
+ long remaining = n;
+ byte data[];
+ int nr;
+
+ if (n <= 0) {
+ return 0;
+ }
+
+ data = new byte[chunk];
+ while (remaining > 0) {
+ nr = read(data, 0, (int) Math.min(chunk, remaining));
+ if (nr < 0) {
+ break;
+ }
+ remaining -= nr;
+ }
+
+ return n - remaining;
+ }
+
+ /**
+ * Sets the line number to the specified argument.
+ *
+ * @param lineNumber the new line number.
+ * @see #getLineNumber
+ */
+ public void setLineNumber(int lineNumber) {
+ this.lineNumber = lineNumber;
+ }
+
+ /**
+ * Returns the current line number.
+ *
+ * @return the current line number.
+ * @see #setLineNumber
+ */
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+
+ /**
+ * Returns the number of bytes that can be read from this input
+ * stream without blocking.
+ * <p>
+ * Note that if the underlying input stream is able to supply
+ * <i>k</i> input characters without blocking, the
+ * {@code LineNumberInputStream} can guarantee only to provide
+ * <i>k</i>/2 characters without blocking, because the
+ * <i>k</i> characters from the underlying input stream might
+ * consist of <i>k</i>/2 pairs of {@code '\u005Cr'} and
+ * {@code '\u005Cn'}, which are converted to just
+ * <i>k</i>/2 {@code '\u005Cn'} characters.
+ *
+ * @return the number of bytes that can be read from this input stream
+ * without blocking.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ public int available() throws IOException {
+ return (pushBack == -1) ? super.available()/2 : super.available()/2 + 1;
+ }
+
+ /**
+ * Marks the current position in this input stream. A subsequent
+ * call to the {@code reset} method repositions this stream at
+ * the last marked position so that subsequent reads re-read the same bytes.
+ * <p>
+ * The {@code mark} method of
+ * {@code LineNumberInputStream} remembers the current line
+ * number in a private variable, and then calls the {@code mark}
+ * method of the underlying input stream.
+ *
+ * @param readlimit the maximum limit of bytes that can be read before
+ * the mark position becomes invalid.
+ * @see java.io.FilterInputStream#in
+ * @see java.io.LineNumberInputStream#reset()
+ */
+ public void mark(int readlimit) {
+ markLineNumber = lineNumber;
+ markPushBack = pushBack;
+ in.mark(readlimit);
+ }
+
+ /**
+ * Repositions this stream to the position at the time the
+ * {@code mark} method was last called on this input stream.
+ * <p>
+ * The {@code reset} method of
+ * {@code LineNumberInputStream} resets the line number to be
+ * the line number at the time the {@code mark} method was
+ * called, and then calls the {@code reset} method of the
+ * underlying input stream.
+ * <p>
+ * Stream marks are intended to be used in
+ * situations where you need to read ahead a little to see what's in
+ * the stream. Often this is most easily done by invoking some
+ * general parser. If the stream is of the type handled by the
+ * parser, it just chugs along happily. If the stream is not of
+ * that type, the parser should toss an exception when it fails,
+ * which, if it happens within readlimit bytes, allows the outer
+ * code to reset the stream and try another parser.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ * @see java.io.LineNumberInputStream#mark(int)
+ */
+ public void reset() throws IOException {
+ lineNumber = markLineNumber;
+ pushBack = markPushBack;
+ in.reset();
+ }
+}
diff --git a/java/io/LineNumberReader.java b/java/io/LineNumberReader.java
new file mode 100644
index 0000000..29884fd
--- /dev/null
+++ b/java/io/LineNumberReader.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * A buffered character-input stream that keeps track of line numbers. This
+ * class defines methods {@link #setLineNumber(int)} and {@link
+ * #getLineNumber()} for setting and getting the current line number
+ * respectively.
+ *
+ * <p> By default, line numbering begins at 0. This number increments at every
+ * <a href="#lt">line terminator</a> as the data is read, and can be changed
+ * with a call to <tt>setLineNumber(int)</tt>. Note however, that
+ * <tt>setLineNumber(int)</tt> does not actually change the current position in
+ * the stream; it only changes the value that will be returned by
+ * <tt>getLineNumber()</tt>.
+ *
+ * <p> A line is considered to be <a name="lt">terminated</a> by any one of a
+ * line feed ('\n'), a carriage return ('\r'), or a carriage return followed
+ * immediately by a linefeed.
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class LineNumberReader extends BufferedReader {
+
+ /** The current line number */
+ private int lineNumber = 0;
+
+ /** The line number of the mark, if any */
+ private int markedLineNumber; // Defaults to 0
+
+ /** If the next character is a line feed, skip it */
+ private boolean skipLF;
+
+ /** The skipLF flag when the mark was set */
+ private boolean markedSkipLF;
+
+ /**
+ * Create a new line-numbering reader, using the default input-buffer
+ * size.
+ *
+ * @param in
+ * A Reader object to provide the underlying stream
+ */
+ public LineNumberReader(Reader in) {
+ super(in);
+ }
+
+ /**
+ * Create a new line-numbering reader, reading characters into a buffer of
+ * the given size.
+ *
+ * @param in
+ * A Reader object to provide the underlying stream
+ *
+ * @param sz
+ * An int specifying the size of the buffer
+ */
+ public LineNumberReader(Reader in, int sz) {
+ super(in, sz);
+ }
+
+ /**
+ * Set the current line number.
+ *
+ * @param lineNumber
+ * An int specifying the line number
+ *
+ * @see #getLineNumber
+ */
+ public void setLineNumber(int lineNumber) {
+ this.lineNumber = lineNumber;
+ }
+
+ /**
+ * Get the current line number.
+ *
+ * @return The current line number
+ *
+ * @see #setLineNumber
+ */
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ /**
+ * Read a single character. <a href="#lt">Line terminators</a> are
+ * compressed into single newline ('\n') characters. Whenever a line
+ * terminator is read the current line number is incremented.
+ *
+ * @return The character read, or -1 if the end of the stream has been
+ * reached
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ @SuppressWarnings("fallthrough")
+ public int read() throws IOException {
+ synchronized (lock) {
+ int c = super.read();
+ if (skipLF) {
+ if (c == '\n')
+ c = super.read();
+ skipLF = false;
+ }
+ switch (c) {
+ case '\r':
+ skipLF = true;
+ case '\n': /* Fall through */
+ lineNumber++;
+ return '\n';
+ }
+ return c;
+ }
+ }
+
+ /**
+ * Read characters into a portion of an array. Whenever a <a
+ * href="#lt">line terminator</a> is read the current line number is
+ * incremented.
+ *
+ * @param cbuf
+ * Destination buffer
+ *
+ * @param off
+ * Offset at which to start storing characters
+ *
+ * @param len
+ * Maximum number of characters to read
+ *
+ * @return The number of bytes read, or -1 if the end of the stream has
+ * already been reached
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ @SuppressWarnings("fallthrough")
+ public int read(char cbuf[], int off, int len) throws IOException {
+ synchronized (lock) {
+ int n = super.read(cbuf, off, len);
+
+ for (int i = off; i < off + n; i++) {
+ int c = cbuf[i];
+ if (skipLF) {
+ skipLF = false;
+ if (c == '\n')
+ continue;
+ }
+ switch (c) {
+ case '\r':
+ skipLF = true;
+ case '\n': /* Fall through */
+ lineNumber++;
+ break;
+ }
+ }
+
+ return n;
+ }
+ }
+
+ /**
+ * Read a line of text. Whenever a <a href="#lt">line terminator</a> is
+ * read the current line number is incremented.
+ *
+ * @return A String containing the contents of the line, not including
+ * any <a href="#lt">line termination characters</a>, or
+ * <tt>null</tt> if the end of the stream has been reached
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public String readLine() throws IOException {
+ synchronized (lock) {
+ String l = super.readLine(skipLF);
+ skipLF = false;
+ if (l != null)
+ lineNumber++;
+ return l;
+ }
+ }
+
+ /** Maximum skip-buffer size */
+ private static final int maxSkipBufferSize = 8192;
+
+ /** Skip buffer, null until allocated */
+ private char skipBuffer[] = null;
+
+ /**
+ * Skip characters.
+ *
+ * @param n
+ * The number of characters to skip
+ *
+ * @return The number of characters actually skipped
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @throws IllegalArgumentException
+ * If <tt>n</tt> is negative
+ */
+ public long skip(long n) throws IOException {
+ if (n < 0)
+ throw new IllegalArgumentException("skip() value is negative");
+ int nn = (int) Math.min(n, maxSkipBufferSize);
+ synchronized (lock) {
+ if ((skipBuffer == null) || (skipBuffer.length < nn))
+ skipBuffer = new char[nn];
+ long r = n;
+ while (r > 0) {
+ int nc = read(skipBuffer, 0, (int) Math.min(r, nn));
+ if (nc == -1)
+ break;
+ r -= nc;
+ }
+ return n - r;
+ }
+ }
+
+ /**
+ * Mark the present position in the stream. Subsequent calls to reset()
+ * will attempt to reposition the stream to this point, and will also reset
+ * the line number appropriately.
+ *
+ * @param readAheadLimit
+ * Limit on the number of characters that may be read while still
+ * preserving the mark. After reading this many characters,
+ * attempting to reset the stream may fail.
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ synchronized (lock) {
+ super.mark(readAheadLimit);
+ markedLineNumber = lineNumber;
+ markedSkipLF = skipLF;
+ }
+ }
+
+ /**
+ * Reset the stream to the most recent mark.
+ *
+ * @throws IOException
+ * If the stream has not been marked, or if the mark has been
+ * invalidated
+ */
+ public void reset() throws IOException {
+ synchronized (lock) {
+ super.reset();
+ lineNumber = markedLineNumber;
+ skipLF = markedSkipLF;
+ }
+ }
+
+}
diff --git a/java/io/NotActiveException.java b/java/io/NotActiveException.java
new file mode 100644
index 0000000..13291e6
--- /dev/null
+++ b/java/io/NotActiveException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Thrown when serialization or deserialization is not active.
+ *
+ * @author unascribed
+ * @since JDK1.1
+ */
+public class NotActiveException extends ObjectStreamException {
+
+ private static final long serialVersionUID = -3893467273049808895L;
+
+ /**
+ * Constructor to create a new NotActiveException with the reason given.
+ *
+ * @param reason a String describing the reason for the exception.
+ */
+ public NotActiveException(String reason) {
+ super(reason);
+ }
+
+ /**
+ * Constructor to create a new NotActiveException without a reason.
+ */
+ public NotActiveException() {
+ super();
+ }
+}
diff --git a/java/io/NotSerializableException.java b/java/io/NotSerializableException.java
new file mode 100644
index 0000000..70e4f57
--- /dev/null
+++ b/java/io/NotSerializableException.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Thrown when an instance is required to have a Serializable interface.
+ * The serialization runtime or the class of the instance can throw
+ * this exception. The argument should be the name of the class.
+ *
+ * @author unascribed
+ * @since JDK1.1
+ */
+public class NotSerializableException extends ObjectStreamException {
+
+ private static final long serialVersionUID = 2906642554793891381L;
+
+ /**
+ * Constructs a NotSerializableException object with message string.
+ *
+ * @param classname Class of the instance being serialized/deserialized.
+ */
+ public NotSerializableException(String classname) {
+ super(classname);
+ }
+
+ /**
+ * Constructs a NotSerializableException object.
+ */
+ public NotSerializableException() {
+ super();
+ }
+}
diff --git a/java/io/ObjectInput.java b/java/io/ObjectInput.java
new file mode 100644
index 0000000..bc7c26b
--- /dev/null
+++ b/java/io/ObjectInput.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * ObjectInput extends the DataInput interface to include the reading of
+ * objects. DataInput includes methods for the input of primitive types,
+ * ObjectInput extends that interface to include objects, arrays, and Strings.
+ *
+ * @author unascribed
+ * @see java.io.InputStream
+ * @see java.io.ObjectOutputStream
+ * @see java.io.ObjectInputStream
+ * @since JDK1.1
+ */
+public interface ObjectInput extends DataInput, AutoCloseable {
+ /**
+ * Read and return an object. The class that implements this interface
+ * defines where the object is "read" from.
+ *
+ * @return the object read from the stream
+ * @exception java.lang.ClassNotFoundException If the class of a serialized
+ * object cannot be found.
+ * @exception IOException If any of the usual Input/Output
+ * related exceptions occur.
+ */
+ public Object readObject()
+ throws ClassNotFoundException, IOException;
+
+ /**
+ * Reads a byte of data. This method will block if no input is
+ * available.
+ * @return the byte read, or -1 if the end of the
+ * stream is reached.
+ * @exception IOException If an I/O error has occurred.
+ */
+ public int read() throws IOException;
+
+ /**
+ * Reads into an array of bytes. This method will
+ * block until some input is available.
+ * @param b the buffer into which the data is read
+ * @return the actual number of bytes read, -1 is
+ * returned when the end of the stream is reached.
+ * @exception IOException If an I/O error has occurred.
+ */
+ public int read(byte b[]) throws IOException;
+
+ /**
+ * Reads into an array of bytes. This method will
+ * block until some input is available.
+ * @param b the buffer into which the data is read
+ * @param off the start offset of the data
+ * @param len the maximum number of bytes read
+ * @return the actual number of bytes read, -1 is
+ * returned when the end of the stream is reached.
+ * @exception IOException If an I/O error has occurred.
+ */
+ public int read(byte b[], int off, int len) throws IOException;
+
+ /**
+ * Skips n bytes of input.
+ * @param n the number of bytes to be skipped
+ * @return the actual number of bytes skipped.
+ * @exception IOException If an I/O error has occurred.
+ */
+ public long skip(long n) throws IOException;
+
+ /**
+ * Returns the number of bytes that can be read
+ * without blocking.
+ * @return the number of available bytes.
+ * @exception IOException If an I/O error has occurred.
+ */
+ public int available() throws IOException;
+
+ /**
+ * Closes the input stream. Must be called
+ * to release any resources associated with
+ * the stream.
+ * @exception IOException If an I/O error has occurred.
+ */
+ public void close() throws IOException;
+}
diff --git a/java/io/ObjectInputStream.java b/java/io/ObjectInputStream.java
new file mode 100644
index 0000000..8369a59
--- /dev/null
+++ b/java/io/ObjectInputStream.java
@@ -0,0 +1,3716 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.ObjectStreamClass.WeakClassKey;
+import java.lang.ref.ReferenceQueue;
+import java.lang.reflect.Array;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import static java.io.ObjectStreamClass.processQueue;
+import sun.reflect.misc.ReflectUtil;
+import dalvik.system.VMStack;
+
+/**
+ * An ObjectInputStream deserializes primitive data and objects previously
+ * written using an ObjectOutputStream.
+ *
+ * <p>ObjectOutputStream and ObjectInputStream can provide an application with
+ * persistent storage for graphs of objects when used with a FileOutputStream
+ * and FileInputStream respectively. ObjectInputStream is used to recover
+ * those objects previously serialized. Other uses include passing objects
+ * between hosts using a socket stream or for marshaling and unmarshaling
+ * arguments and parameters in a remote communication system.
+ *
+ * <p>ObjectInputStream ensures that the types of all objects in the graph
+ * created from the stream match the classes present in the Java Virtual
+ * Machine. Classes are loaded as required using the standard mechanisms.
+ *
+ * <p>Only objects that support the java.io.Serializable or
+ * java.io.Externalizable interface can be read from streams.
+ *
+ * <p>The method <code>readObject</code> is used to read an object from the
+ * stream. Java's safe casting should be used to get the desired type. In
+ * Java, strings and arrays are objects and are treated as objects during
+ * serialization. When read they need to be cast to the expected type.
+ *
+ * <p>Primitive data types can be read from the stream using the appropriate
+ * method on DataInput.
+ *
+ * <p>The default deserialization mechanism for objects restores the contents
+ * of each field to the value and type it had when it was written. Fields
+ * declared as transient or static are ignored by the deserialization process.
+ * References to other objects cause those objects to be read from the stream
+ * as necessary. Graphs of objects are restored correctly using a reference
+ * sharing mechanism. New objects are always allocated when deserializing,
+ * which prevents existing objects from being overwritten.
+ *
+ * <p>Reading an object is analogous to running the constructors of a new
+ * object. Memory is allocated for the object and initialized to zero (NULL).
+ * No-arg constructors are invoked for the non-serializable classes and then
+ * the fields of the serializable classes are restored from the stream starting
+ * with the serializable class closest to java.lang.object and finishing with
+ * the object's most specific class.
+ *
+ * <p>For example to read from a stream as written by the example in
+ * ObjectOutputStream:
+ * <br>
+ * <pre>
+ * FileInputStream fis = new FileInputStream("t.tmp");
+ * ObjectInputStream ois = new ObjectInputStream(fis);
+ *
+ * int i = ois.readInt();
+ * String today = (String) ois.readObject();
+ * Date date = (Date) ois.readObject();
+ *
+ * ois.close();
+ * </pre>
+ *
+ * <p>Classes control how they are serialized by implementing either the
+ * java.io.Serializable or java.io.Externalizable interfaces.
+ *
+ * <p>Implementing the Serializable interface allows object serialization to
+ * save and restore the entire state of the object and it allows classes to
+ * evolve between the time the stream is written and the time it is read. It
+ * automatically traverses references between objects, saving and restoring
+ * entire graphs.
+ *
+ * <p>Serializable classes that require special handling during the
+ * serialization and deserialization process should implement the following
+ * methods:
+ *
+ * <pre>
+ * private void writeObject(java.io.ObjectOutputStream stream)
+ * throws IOException;
+ * private void readObject(java.io.ObjectInputStream stream)
+ * throws IOException, ClassNotFoundException;
+ * private void readObjectNoData()
+ * throws ObjectStreamException;
+ * </pre>
+ *
+ * <p>The readObject method is responsible for reading and restoring the state
+ * of the object for its particular class using data written to the stream by
+ * the corresponding writeObject method. The method does not need to concern
+ * itself with the state belonging to its superclasses or subclasses. State is
+ * restored by reading data from the ObjectInputStream for the individual
+ * fields and making assignments to the appropriate fields of the object.
+ * Reading primitive data types is supported by DataInput.
+ *
+ * <p>Any attempt to read object data which exceeds the boundaries of the
+ * custom data written by the corresponding writeObject method will cause an
+ * OptionalDataException to be thrown with an eof field value of true.
+ * Non-object reads which exceed the end of the allotted data will reflect the
+ * end of data in the same way that they would indicate the end of the stream:
+ * bytewise reads will return -1 as the byte read or number of bytes read, and
+ * primitive reads will throw EOFExceptions. If there is no corresponding
+ * writeObject method, then the end of default serialized data marks the end of
+ * the allotted data.
+ *
+ * <p>Primitive and object read calls issued from within a readExternal method
+ * behave in the same manner--if the stream is already positioned at the end of
+ * data written by the corresponding writeExternal method, object reads will
+ * throw OptionalDataExceptions with eof set to true, bytewise reads will
+ * return -1, and primitive reads will throw EOFExceptions. Note that this
+ * behavior does not hold for streams written with the old
+ * <code>ObjectStreamConstants.PROTOCOL_VERSION_1</code> protocol, in which the
+ * end of data written by writeExternal methods is not demarcated, and hence
+ * cannot be detected.
+ *
+ * <p>The readObjectNoData method is responsible for initializing the state of
+ * the object for its particular class in the event that the serialization
+ * stream does not list the given class as a superclass of the object being
+ * deserialized. This may occur in cases where the receiving party uses a
+ * different version of the deserialized instance's class than the sending
+ * party, and the receiver's version extends classes that are not extended by
+ * the sender's version. This may also occur if the serialization stream has
+ * been tampered; hence, readObjectNoData is useful for initializing
+ * deserialized objects properly despite a "hostile" or incomplete source
+ * stream.
+ *
+ * <p>Serialization does not read or assign values to the fields of any object
+ * that does not implement the java.io.Serializable interface. Subclasses of
+ * Objects that are not serializable can be serializable. In this case the
+ * non-serializable class must have a no-arg constructor to allow its fields to
+ * be initialized. In this case it is the responsibility of the subclass to
+ * save and restore the state of the non-serializable class. It is frequently
+ * the case that the fields of that class are accessible (public, package, or
+ * protected) or that there are get and set methods that can be used to restore
+ * the state.
+ *
+ * <p>Any exception that occurs while deserializing an object will be caught by
+ * the ObjectInputStream and abort the reading process.
+ *
+ * <p>Implementing the Externalizable interface allows the object to assume
+ * complete control over the contents and format of the object's serialized
+ * form. The methods of the Externalizable interface, writeExternal and
+ * readExternal, are called to save and restore the objects state. When
+ * implemented by a class they can write and read their own state using all of
+ * the methods of ObjectOutput and ObjectInput. It is the responsibility of
+ * the objects to handle any versioning that occurs.
+ *
+ * <p>Enum constants are deserialized differently than ordinary serializable or
+ * externalizable objects. The serialized form of an enum constant consists
+ * solely of its name; field values of the constant are not transmitted. To
+ * deserialize an enum constant, ObjectInputStream reads the constant name from
+ * the stream; the deserialized constant is then obtained by calling the static
+ * method <code>Enum.valueOf(Class, String)</code> with the enum constant's
+ * base type and the received constant name as arguments. Like other
+ * serializable or externalizable objects, enum constants can function as the
+ * targets of back references appearing subsequently in the serialization
+ * stream. The process by which enum constants are deserialized cannot be
+ * customized: any class-specific readObject, readObjectNoData, and readResolve
+ * methods defined by enum types are ignored during deserialization.
+ * Similarly, any serialPersistentFields or serialVersionUID field declarations
+ * are also ignored--all enum types have a fixed serialVersionUID of 0L.
+ *
+ * @author Mike Warres
+ * @author Roger Riggs
+ * @see java.io.DataInput
+ * @see java.io.ObjectOutputStream
+ * @see java.io.Serializable
+ * @see <a href="../../../platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
+ * @since JDK1.1
+ */
+public class ObjectInputStream
+ extends InputStream implements ObjectInput, ObjectStreamConstants
+{
+ /** handle value representing null */
+ private static final int NULL_HANDLE = -1;
+
+ /** marker for unshared objects in internal handle table */
+ private static final Object unsharedMarker = new Object();
+
+ /** table mapping primitive type names to corresponding class objects */
+ private static final HashMap<String, Class<?>> primClasses
+ = new HashMap<>(8, 1.0F);
+ static {
+ primClasses.put("boolean", boolean.class);
+ primClasses.put("byte", byte.class);
+ primClasses.put("char", char.class);
+ primClasses.put("short", short.class);
+ primClasses.put("int", int.class);
+ primClasses.put("long", long.class);
+ primClasses.put("float", float.class);
+ primClasses.put("double", double.class);
+ primClasses.put("void", void.class);
+ }
+
+ private static class Caches {
+ /** cache of subclass security audit results */
+ static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
+ new ConcurrentHashMap<>();
+
+ /** queue for WeakReferences to audited subclasses */
+ static final ReferenceQueue<Class<?>> subclassAuditsQueue =
+ new ReferenceQueue<>();
+ }
+
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ /*
+ static {
+ /* Setup access so sun.misc can invoke package private functions. *
+ sun.misc.SharedSecrets.setJavaOISAccess(new JavaOISAccess() {
+ public void setObjectInputFilter(ObjectInputStream stream, ObjectInputFilter filter) {
+ stream.setInternalObjectInputFilter(filter);
+ }
+
+ public ObjectInputFilter getObjectInputFilter(ObjectInputStream stream) {
+ return stream.getInternalObjectInputFilter();
+ }
+ });
+ }
+
+ /*
+ * Separate class to defer initialization of logging until needed.
+ *
+ private static class Logging {
+
+ /*
+ * Logger for ObjectInputFilter results.
+ * Setup the filter logger if it is set to INFO or WARNING.
+ * (Assuming it will not change).
+ *
+ private static final PlatformLogger traceLogger;
+ private static final PlatformLogger infoLogger;
+ static {
+ PlatformLogger filterLog = PlatformLogger.getLogger("java.io.serialization");
+ infoLogger = (filterLog != null &&
+ filterLog.isLoggable(PlatformLogger.Level.INFO)) ? filterLog : null;
+ traceLogger = (filterLog != null &&
+ filterLog.isLoggable(PlatformLogger.Level.FINER)) ? filterLog : null;
+ }
+ }
+ */
+
+ /** filter stream for handling block data conversion */
+ private final BlockDataInputStream bin;
+ /** validation callback list */
+ private final ValidationList vlist;
+ /** recursion depth */
+ // Android-changed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // private long depth;
+ private int depth;
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // /** Total number of references to any type of object, class, enum, proxy, etc. */
+ // private long totalObjectRefs;
+ /** whether stream is closed */
+ private boolean closed;
+
+ /** wire handle -> obj/exception map */
+ private final HandleTable handles;
+ /** scratch field for passing handle values up/down call stack */
+ private int passHandle = NULL_HANDLE;
+ /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
+ private boolean defaultDataEnd = false;
+
+ /** buffer for reading primitive field values */
+ private byte[] primVals;
+
+ /** if true, invoke readObjectOverride() instead of readObject() */
+ private final boolean enableOverride;
+ /** if true, invoke resolveObject() */
+ private boolean enableResolve;
+
+ /**
+ * Context during upcalls to class-defined readObject methods; holds
+ * object currently being deserialized and descriptor for current class.
+ * Null when not during readObject upcall.
+ */
+ private SerialCallbackContext curContext;
+
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ /**
+ * Filter of class descriptors and classes read from the stream;
+ * may be null.
+ *
+ private ObjectInputFilter serialFilter;
+ */
+
+ /**
+ * Creates an ObjectInputStream that reads from the specified InputStream.
+ * A serialization stream header is read from the stream and verified.
+ * This constructor will block until the corresponding ObjectOutputStream
+ * has written and flushed the header.
+ *
+ * <p>If a security manager is installed, this constructor will check for
+ * the "enableSubclassImplementation" SerializablePermission when invoked
+ * directly or indirectly by the constructor of a subclass which overrides
+ * the ObjectInputStream.readFields or ObjectInputStream.readUnshared
+ * methods.
+ *
+ * @param in input stream to read from
+ * @throws StreamCorruptedException if the stream header is incorrect
+ * @throws IOException if an I/O error occurs while reading stream header
+ * @throws SecurityException if untrusted subclass illegally overrides
+ * security-sensitive methods
+ * @throws NullPointerException if <code>in</code> is <code>null</code>
+ * @see ObjectInputStream#ObjectInputStream()
+ * @see ObjectInputStream#readFields()
+ * @see ObjectOutputStream#ObjectOutputStream(OutputStream)
+ */
+ public ObjectInputStream(InputStream in) throws IOException {
+ verifySubclass();
+ bin = new BlockDataInputStream(in);
+ handles = new HandleTable(10);
+ vlist = new ValidationList();
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // serialFilter = ObjectInputFilter.Config.getSerialFilter();
+ enableOverride = false;
+ readStreamHeader();
+ bin.setBlockDataMode(true);
+ }
+
+ /**
+ * Provide a way for subclasses that are completely reimplementing
+ * ObjectInputStream to not have to allocate private data just used by this
+ * implementation of ObjectInputStream.
+ *
+ * <p>If there is a security manager installed, this method first calls the
+ * security manager's <code>checkPermission</code> method with the
+ * <code>SerializablePermission("enableSubclassImplementation")</code>
+ * permission to ensure it's ok to enable subclassing.
+ *
+ * @throws SecurityException if a security manager exists and its
+ * <code>checkPermission</code> method denies enabling
+ * subclassing.
+ * @throws IOException if an I/O error occurs while creating this stream
+ * @see SecurityManager#checkPermission
+ * @see java.io.SerializablePermission
+ */
+ protected ObjectInputStream() throws IOException, SecurityException {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
+ }
+ bin = null;
+ handles = null;
+ vlist = null;
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // serialFilter = ObjectInputFilter.Config.getSerialFilter();
+ enableOverride = true;
+ }
+
+ /**
+ * Read an object from the ObjectInputStream. The class of the object, the
+ * signature of the class, and the values of the non-transient and
+ * non-static fields of the class and all of its supertypes are read.
+ * Default deserializing for a class can be overridden using the writeObject
+ * and readObject methods. Objects referenced by this object are read
+ * transitively so that a complete equivalent graph of objects is
+ * reconstructed by readObject.
+ *
+ * <p>The root object is completely restored when all of its fields and the
+ * objects it references are completely restored. At this point the object
+ * validation callbacks are executed in order based on their registered
+ * priorities. The callbacks are registered by objects (in the readObject
+ * special methods) as they are individually restored.
+ *
+ * <p>Exceptions are thrown for problems with the InputStream and for
+ * classes that should not be deserialized. All exceptions are fatal to
+ * the InputStream and leave it in an indeterminate state; it is up to the
+ * caller to ignore or recover the stream state.
+ *
+ * @throws ClassNotFoundException Class of a serialized object cannot be
+ * found.
+ * @throws InvalidClassException Something is wrong with a class used by
+ * serialization.
+ * @throws StreamCorruptedException Control information in the
+ * stream is inconsistent.
+ * @throws OptionalDataException Primitive data was found in the
+ * stream instead of objects.
+ * @throws IOException Any of the usual Input/Output related exceptions.
+ */
+ public final Object readObject()
+ throws IOException, ClassNotFoundException
+ {
+ if (enableOverride) {
+ return readObjectOverride();
+ }
+
+ // if nested read, passHandle contains handle of enclosing object
+ int outerHandle = passHandle;
+ try {
+ Object obj = readObject0(false);
+ handles.markDependency(outerHandle, passHandle);
+ ClassNotFoundException ex = handles.lookupException(passHandle);
+ if (ex != null) {
+ throw ex;
+ }
+ if (depth == 0) {
+ vlist.doCallbacks();
+ }
+ return obj;
+ } finally {
+ passHandle = outerHandle;
+ if (closed && depth == 0) {
+ clear();
+ }
+ }
+ }
+
+ /**
+ * This method is called by trusted subclasses of ObjectOutputStream that
+ * constructed ObjectOutputStream using the protected no-arg constructor.
+ * The subclass is expected to provide an override method with the modifier
+ * "final".
+ *
+ * @return the Object read from the stream.
+ * @throws ClassNotFoundException Class definition of a serialized object
+ * cannot be found.
+ * @throws OptionalDataException Primitive data was found in the stream
+ * instead of objects.
+ * @throws IOException if I/O errors occurred while reading from the
+ * underlying stream
+ * @see #ObjectInputStream()
+ * @see #readObject()
+ * @since 1.2
+ */
+ protected Object readObjectOverride()
+ throws IOException, ClassNotFoundException
+ {
+ return null;
+ }
+
+ /**
+ * Reads an "unshared" object from the ObjectInputStream. This method is
+ * identical to readObject, except that it prevents subsequent calls to
+ * readObject and readUnshared from returning additional references to the
+ * deserialized instance obtained via this call. Specifically:
+ * <ul>
+ * <li>If readUnshared is called to deserialize a back-reference (the
+ * stream representation of an object which has been written
+ * previously to the stream), an ObjectStreamException will be
+ * thrown.
+ *
+ * <li>If readUnshared returns successfully, then any subsequent attempts
+ * to deserialize back-references to the stream handle deserialized
+ * by readUnshared will cause an ObjectStreamException to be thrown.
+ * </ul>
+ * Deserializing an object via readUnshared invalidates the stream handle
+ * associated with the returned object. Note that this in itself does not
+ * always guarantee that the reference returned by readUnshared is unique;
+ * the deserialized object may define a readResolve method which returns an
+ * object visible to other parties, or readUnshared may return a Class
+ * object or enum constant obtainable elsewhere in the stream or through
+ * external means. If the deserialized object defines a readResolve method
+ * and the invocation of that method returns an array, then readUnshared
+ * returns a shallow clone of that array; this guarantees that the returned
+ * array object is unique and cannot be obtained a second time from an
+ * invocation of readObject or readUnshared on the ObjectInputStream,
+ * even if the underlying data stream has been manipulated.
+ *
+ * <p>ObjectInputStream subclasses which override this method can only be
+ * constructed in security contexts possessing the
+ * "enableSubclassImplementation" SerializablePermission; any attempt to
+ * instantiate such a subclass without this permission will cause a
+ * SecurityException to be thrown.
+ *
+ * @return reference to deserialized object
+ * @throws ClassNotFoundException if class of an object to deserialize
+ * cannot be found
+ * @throws StreamCorruptedException if control information in the stream
+ * is inconsistent
+ * @throws ObjectStreamException if object to deserialize has already
+ * appeared in stream
+ * @throws OptionalDataException if primitive data is next in stream
+ * @throws IOException if an I/O error occurs during deserialization
+ * @since 1.4
+ */
+ public Object readUnshared() throws IOException, ClassNotFoundException {
+ // if nested read, passHandle contains handle of enclosing object
+ int outerHandle = passHandle;
+ try {
+ Object obj = readObject0(true);
+ handles.markDependency(outerHandle, passHandle);
+ ClassNotFoundException ex = handles.lookupException(passHandle);
+ if (ex != null) {
+ throw ex;
+ }
+ if (depth == 0) {
+ vlist.doCallbacks();
+ }
+ return obj;
+ } finally {
+ passHandle = outerHandle;
+ if (closed && depth == 0) {
+ clear();
+ }
+ }
+ }
+
+ /**
+ * Read the non-static and non-transient fields of the current class from
+ * this stream. This may only be called from the readObject method of the
+ * class being deserialized. It will throw the NotActiveException if it is
+ * called otherwise.
+ *
+ * @throws ClassNotFoundException if the class of a serialized object
+ * could not be found.
+ * @throws IOException if an I/O error occurs.
+ * @throws NotActiveException if the stream is not currently reading
+ * objects.
+ */
+ public void defaultReadObject()
+ throws IOException, ClassNotFoundException
+ {
+ SerialCallbackContext ctx = curContext;
+ if (ctx == null) {
+ throw new NotActiveException("not in call to readObject");
+ }
+ Object curObj = ctx.getObj();
+ ObjectStreamClass curDesc = ctx.getDesc();
+ bin.setBlockDataMode(false);
+ defaultReadFields(curObj, curDesc);
+ bin.setBlockDataMode(true);
+ if (!curDesc.hasWriteObjectData()) {
+ /*
+ * Fix for 4360508: since stream does not contain terminating
+ * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
+ * knows to simulate end-of-custom-data behavior.
+ */
+ defaultDataEnd = true;
+ }
+ ClassNotFoundException ex = handles.lookupException(passHandle);
+ if (ex != null) {
+ throw ex;
+ }
+ }
+
+ /**
+ * Reads the persistent fields from the stream and makes them available by
+ * name.
+ *
+ * @return the <code>GetField</code> object representing the persistent
+ * fields of the object being deserialized
+ * @throws ClassNotFoundException if the class of a serialized object
+ * could not be found.
+ * @throws IOException if an I/O error occurs.
+ * @throws NotActiveException if the stream is not currently reading
+ * objects.
+ * @since 1.2
+ */
+ public ObjectInputStream.GetField readFields()
+ throws IOException, ClassNotFoundException
+ {
+ SerialCallbackContext ctx = curContext;
+ if (ctx == null) {
+ throw new NotActiveException("not in call to readObject");
+ }
+ Object curObj = ctx.getObj();
+ ObjectStreamClass curDesc = ctx.getDesc();
+ bin.setBlockDataMode(false);
+ GetFieldImpl getField = new GetFieldImpl(curDesc);
+ getField.readFields();
+ bin.setBlockDataMode(true);
+ if (!curDesc.hasWriteObjectData()) {
+ /*
+ * Fix for 4360508: since stream does not contain terminating
+ * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
+ * knows to simulate end-of-custom-data behavior.
+ */
+ defaultDataEnd = true;
+ }
+
+ return getField;
+ }
+
+ /**
+ * Register an object to be validated before the graph is returned. While
+ * similar to resolveObject these validations are called after the entire
+ * graph has been reconstituted. Typically, a readObject method will
+ * register the object with the stream so that when all of the objects are
+ * restored a final set of validations can be performed.
+ *
+ * @param obj the object to receive the validation callback.
+ * @param prio controls the order of callbacks;zero is a good default.
+ * Use higher numbers to be called back earlier, lower numbers for
+ * later callbacks. Within a priority, callbacks are processed in
+ * no particular order.
+ * @throws NotActiveException The stream is not currently reading objects
+ * so it is invalid to register a callback.
+ * @throws InvalidObjectException The validation object is null.
+ */
+ public void registerValidation(ObjectInputValidation obj, int prio)
+ throws NotActiveException, InvalidObjectException
+ {
+ if (depth == 0) {
+ throw new NotActiveException("stream inactive");
+ }
+ vlist.register(obj, prio);
+ }
+
+ /**
+ * Load the local class equivalent of the specified stream class
+ * description. Subclasses may implement this method to allow classes to
+ * be fetched from an alternate source.
+ *
+ * <p>The corresponding method in <code>ObjectOutputStream</code> is
+ * <code>annotateClass</code>. This method will be invoked only once for
+ * each unique class in the stream. This method can be implemented by
+ * subclasses to use an alternate loading mechanism but must return a
+ * <code>Class</code> object. Once returned, if the class is not an array
+ * class, its serialVersionUID is compared to the serialVersionUID of the
+ * serialized class, and if there is a mismatch, the deserialization fails
+ * and an {@link InvalidClassException} is thrown.
+ *
+ * <p>The default implementation of this method in
+ * <code>ObjectInputStream</code> returns the result of calling
+ * <pre>
+ * Class.forName(desc.getName(), false, loader)
+ * </pre>
+ * where <code>loader</code> is determined as follows: if there is a
+ * method on the current thread's stack whose declaring class was
+ * defined by a user-defined class loader (and was not a generated to
+ * implement reflective invocations), then <code>loader</code> is class
+ * loader corresponding to the closest such method to the currently
+ * executing frame; otherwise, <code>loader</code> is
+ * <code>null</code>. If this call results in a
+ * <code>ClassNotFoundException</code> and the name of the passed
+ * <code>ObjectStreamClass</code> instance is the Java language keyword
+ * for a primitive type or void, then the <code>Class</code> object
+ * representing that primitive type or void will be returned
+ * (e.g., an <code>ObjectStreamClass</code> with the name
+ * <code>"int"</code> will be resolved to <code>Integer.TYPE</code>).
+ * Otherwise, the <code>ClassNotFoundException</code> will be thrown to
+ * the caller of this method.
+ *
+ * @param desc an instance of class <code>ObjectStreamClass</code>
+ * @return a <code>Class</code> object corresponding to <code>desc</code>
+ * @throws IOException any of the usual Input/Output exceptions.
+ * @throws ClassNotFoundException if class of a serialized object cannot
+ * be found.
+ */
+ protected Class<?> resolveClass(ObjectStreamClass desc)
+ throws IOException, ClassNotFoundException
+ {
+ String name = desc.getName();
+ try {
+ return Class.forName(name, false, latestUserDefinedLoader());
+ } catch (ClassNotFoundException ex) {
+ Class<?> cl = primClasses.get(name);
+ if (cl != null) {
+ return cl;
+ } else {
+ throw ex;
+ }
+ }
+ }
+
+ /**
+ * Returns a proxy class that implements the interfaces named in a proxy
+ * class descriptor; subclasses may implement this method to read custom
+ * data from the stream along with the descriptors for dynamic proxy
+ * classes, allowing them to use an alternate loading mechanism for the
+ * interfaces and the proxy class.
+ *
+ * <p>This method is called exactly once for each unique proxy class
+ * descriptor in the stream.
+ *
+ * <p>The corresponding method in <code>ObjectOutputStream</code> is
+ * <code>annotateProxyClass</code>. For a given subclass of
+ * <code>ObjectInputStream</code> that overrides this method, the
+ * <code>annotateProxyClass</code> method in the corresponding subclass of
+ * <code>ObjectOutputStream</code> must write any data or objects read by
+ * this method.
+ *
+ * <p>The default implementation of this method in
+ * <code>ObjectInputStream</code> returns the result of calling
+ * <code>Proxy.getProxyClass</code> with the list of <code>Class</code>
+ * objects for the interfaces that are named in the <code>interfaces</code>
+ * parameter. The <code>Class</code> object for each interface name
+ * <code>i</code> is the value returned by calling
+ * <pre>
+ * Class.forName(i, false, loader)
+ * </pre>
+ * where <code>loader</code> is that of the first non-<code>null</code>
+ * class loader up the execution stack, or <code>null</code> if no
+ * non-<code>null</code> class loaders are on the stack (the same class
+ * loader choice used by the <code>resolveClass</code> method). Unless any
+ * of the resolved interfaces are non-public, this same value of
+ * <code>loader</code> is also the class loader passed to
+ * <code>Proxy.getProxyClass</code>; if non-public interfaces are present,
+ * their class loader is passed instead (if more than one non-public
+ * interface class loader is encountered, an
+ * <code>IllegalAccessError</code> is thrown).
+ * If <code>Proxy.getProxyClass</code> throws an
+ * <code>IllegalArgumentException</code>, <code>resolveProxyClass</code>
+ * will throw a <code>ClassNotFoundException</code> containing the
+ * <code>IllegalArgumentException</code>.
+ *
+ * @param interfaces the list of interface names that were
+ * deserialized in the proxy class descriptor
+ * @return a proxy class for the specified interfaces
+ * @throws IOException any exception thrown by the underlying
+ * <code>InputStream</code>
+ * @throws ClassNotFoundException if the proxy class or any of the
+ * named interfaces could not be found
+ * @see ObjectOutputStream#annotateProxyClass(Class)
+ * @since 1.3
+ */
+ protected Class<?> resolveProxyClass(String[] interfaces)
+ throws IOException, ClassNotFoundException
+ {
+ ClassLoader latestLoader = latestUserDefinedLoader();
+ ClassLoader nonPublicLoader = null;
+ boolean hasNonPublicInterface = false;
+
+ // define proxy in class loader of non-public interface(s), if any
+ Class<?>[] classObjs = new Class<?>[interfaces.length];
+ for (int i = 0; i < interfaces.length; i++) {
+ Class<?> cl = Class.forName(interfaces[i], false, latestLoader);
+ if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
+ if (hasNonPublicInterface) {
+ if (nonPublicLoader != cl.getClassLoader()) {
+ throw new IllegalAccessError(
+ "conflicting non-public interface class loaders");
+ }
+ } else {
+ nonPublicLoader = cl.getClassLoader();
+ hasNonPublicInterface = true;
+ }
+ }
+ classObjs[i] = cl;
+ }
+ try {
+ return Proxy.getProxyClass(
+ hasNonPublicInterface ? nonPublicLoader : latestLoader,
+ classObjs);
+ } catch (IllegalArgumentException e) {
+ throw new ClassNotFoundException(null, e);
+ }
+ }
+
+ /**
+ * This method will allow trusted subclasses of ObjectInputStream to
+ * substitute one object for another during deserialization. Replacing
+ * objects is disabled until enableResolveObject is called. The
+ * enableResolveObject method checks that the stream requesting to resolve
+ * object can be trusted. Every reference to serializable objects is passed
+ * to resolveObject. To insure that the private state of objects is not
+ * unintentionally exposed only trusted streams may use resolveObject.
+ *
+ * <p>This method is called after an object has been read but before it is
+ * returned from readObject. The default resolveObject method just returns
+ * the same object.
+ *
+ * <p>When a subclass is replacing objects it must insure that the
+ * substituted object is compatible with every field where the reference
+ * will be stored. Objects whose type is not a subclass of the type of the
+ * field or array element abort the serialization by raising an exception
+ * and the object is not be stored.
+ *
+ * <p>This method is called only once when each object is first
+ * encountered. All subsequent references to the object will be redirected
+ * to the new object.
+ *
+ * @param obj object to be substituted
+ * @return the substituted object
+ * @throws IOException Any of the usual Input/Output exceptions.
+ */
+ protected Object resolveObject(Object obj) throws IOException {
+ return obj;
+ }
+
+ /**
+ * Enable the stream to allow objects read from the stream to be replaced.
+ * When enabled, the resolveObject method is called for every object being
+ * deserialized.
+ *
+ * <p>If <i>enable</i> is true, and there is a security manager installed,
+ * this method first calls the security manager's
+ * <code>checkPermission</code> method with the
+ * <code>SerializablePermission("enableSubstitution")</code> permission to
+ * ensure it's ok to enable the stream to allow objects read from the
+ * stream to be replaced.
+ *
+ * @param enable true for enabling use of <code>resolveObject</code> for
+ * every object being deserialized
+ * @return the previous setting before this method was invoked
+ * @throws SecurityException if a security manager exists and its
+ * <code>checkPermission</code> method denies enabling the stream
+ * to allow objects read from the stream to be replaced.
+ * @see SecurityManager#checkPermission
+ * @see java.io.SerializablePermission
+ */
+ protected boolean enableResolveObject(boolean enable)
+ throws SecurityException
+ {
+ if (enable == enableResolve) {
+ return enable;
+ }
+ if (enable) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(SUBSTITUTION_PERMISSION);
+ }
+ }
+ enableResolve = enable;
+ return !enableResolve;
+ }
+
+ /**
+ * The readStreamHeader method is provided to allow subclasses to read and
+ * verify their own stream headers. It reads and verifies the magic number
+ * and version number.
+ *
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @throws StreamCorruptedException if control information in the stream
+ * is inconsistent
+ */
+ protected void readStreamHeader()
+ throws IOException, StreamCorruptedException
+ {
+ short s0 = bin.readShort();
+ short s1 = bin.readShort();
+ if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
+ throw new StreamCorruptedException(
+ String.format("invalid stream header: %04X%04X", s0, s1));
+ }
+ }
+
+ /**
+ * Read a class descriptor from the serialization stream. This method is
+ * called when the ObjectInputStream expects a class descriptor as the next
+ * item in the serialization stream. Subclasses of ObjectInputStream may
+ * override this method to read in class descriptors that have been written
+ * in non-standard formats (by subclasses of ObjectOutputStream which have
+ * overridden the <code>writeClassDescriptor</code> method). By default,
+ * this method reads class descriptors according to the format defined in
+ * the Object Serialization specification.
+ *
+ * @return the class descriptor read
+ * @throws IOException If an I/O error has occurred.
+ * @throws ClassNotFoundException If the Class of a serialized object used
+ * in the class descriptor representation cannot be found
+ * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass)
+ * @since 1.3
+ */
+ protected ObjectStreamClass readClassDescriptor()
+ throws IOException, ClassNotFoundException
+ {
+ ObjectStreamClass desc = new ObjectStreamClass();
+ desc.readNonProxy(this);
+ return desc;
+ }
+
+ /**
+ * Reads a byte of data. This method will block if no input is available.
+ *
+ * @return the byte read, or -1 if the end of the stream is reached.
+ * @throws IOException If an I/O error has occurred.
+ */
+ public int read() throws IOException {
+ return bin.read();
+ }
+
+ /**
+ * Reads into an array of bytes. This method will block until some input
+ * is available. Consider using java.io.DataInputStream.readFully to read
+ * exactly 'length' bytes.
+ *
+ * @param buf the buffer into which the data is read
+ * @param off the start offset of the data
+ * @param len the maximum number of bytes read
+ * @return the actual number of bytes read, -1 is returned when the end of
+ * the stream is reached.
+ * @throws IOException If an I/O error has occurred.
+ * @see java.io.DataInputStream#readFully(byte[],int,int)
+ */
+ public int read(byte[] buf, int off, int len) throws IOException {
+ if (buf == null) {
+ throw new NullPointerException();
+ }
+ int endoff = off + len;
+ if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ return bin.read(buf, off, len, false);
+ }
+
+ /**
+ * Returns the number of bytes that can be read without blocking.
+ *
+ * @return the number of available bytes.
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ */
+ public int available() throws IOException {
+ return bin.available();
+ }
+
+ /**
+ * Closes the input stream. Must be called to release any resources
+ * associated with the stream.
+ *
+ * @throws IOException If an I/O error has occurred.
+ */
+ public void close() throws IOException {
+ /*
+ * Even if stream already closed, propagate redundant close to
+ * underlying stream to stay consistent with previous implementations.
+ */
+ closed = true;
+ if (depth == 0) {
+ clear();
+ }
+ bin.close();
+ }
+
+ /**
+ * Reads in a boolean.
+ *
+ * @return the boolean read.
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public boolean readBoolean() throws IOException {
+ return bin.readBoolean();
+ }
+
+ /**
+ * Reads an 8 bit byte.
+ *
+ * @return the 8 bit byte read.
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public byte readByte() throws IOException {
+ return bin.readByte();
+ }
+
+ /**
+ * Reads an unsigned 8 bit byte.
+ *
+ * @return the 8 bit byte read.
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public int readUnsignedByte() throws IOException {
+ return bin.readUnsignedByte();
+ }
+
+ /**
+ * Reads a 16 bit char.
+ *
+ * @return the 16 bit char read.
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public char readChar() throws IOException {
+ return bin.readChar();
+ }
+
+ /**
+ * Reads a 16 bit short.
+ *
+ * @return the 16 bit short read.
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public short readShort() throws IOException {
+ return bin.readShort();
+ }
+
+ /**
+ * Reads an unsigned 16 bit short.
+ *
+ * @return the 16 bit short read.
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public int readUnsignedShort() throws IOException {
+ return bin.readUnsignedShort();
+ }
+
+ /**
+ * Reads a 32 bit int.
+ *
+ * @return the 32 bit integer read.
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public int readInt() throws IOException {
+ return bin.readInt();
+ }
+
+ /**
+ * Reads a 64 bit long.
+ *
+ * @return the read 64 bit long.
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public long readLong() throws IOException {
+ return bin.readLong();
+ }
+
+ /**
+ * Reads a 32 bit float.
+ *
+ * @return the 32 bit float read.
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public float readFloat() throws IOException {
+ return bin.readFloat();
+ }
+
+ /**
+ * Reads a 64 bit double.
+ *
+ * @return the 64 bit double read.
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public double readDouble() throws IOException {
+ return bin.readDouble();
+ }
+
+ /**
+ * Reads bytes, blocking until all bytes are read.
+ *
+ * @param buf the buffer into which the data is read
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public void readFully(byte[] buf) throws IOException {
+ bin.readFully(buf, 0, buf.length, false);
+ }
+
+ /**
+ * Reads bytes, blocking until all bytes are read.
+ *
+ * @param buf the buffer into which the data is read
+ * @param off the start offset of the data
+ * @param len the maximum number of bytes to read
+ * @throws EOFException If end of file is reached.
+ * @throws IOException If other I/O error has occurred.
+ */
+ public void readFully(byte[] buf, int off, int len) throws IOException {
+ int endoff = off + len;
+ if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ bin.readFully(buf, off, len, false);
+ }
+
+ /**
+ * Skips bytes.
+ *
+ * @param len the number of bytes to be skipped
+ * @return the actual number of bytes skipped.
+ * @throws IOException If an I/O error has occurred.
+ */
+ public int skipBytes(int len) throws IOException {
+ return bin.skipBytes(len);
+ }
+
+ /**
+ * Reads in a line that has been terminated by a \n, \r, \r\n or EOF.
+ *
+ * @return a String copy of the line.
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @deprecated This method does not properly convert bytes to characters.
+ * see DataInputStream for the details and alternatives.
+ */
+ @Deprecated
+ public String readLine() throws IOException {
+ return bin.readLine();
+ }
+
+ /**
+ * Reads a String in
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+ * format.
+ *
+ * @return the String.
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @throws UTFDataFormatException if read bytes do not represent a valid
+ * modified UTF-8 encoding of a string
+ */
+ public String readUTF() throws IOException {
+ return bin.readUTF();
+ }
+
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // Removed ObjectInputFilter related methods.
+
+ /**
+ * Provide access to the persistent fields read from the input stream.
+ */
+ public static abstract class GetField {
+
+ /**
+ * Get the ObjectStreamClass that describes the fields in the stream.
+ *
+ * @return the descriptor class that describes the serializable fields
+ */
+ public abstract ObjectStreamClass getObjectStreamClass();
+
+ /**
+ * Return true if the named field is defaulted and has no value in this
+ * stream.
+ *
+ * @param name the name of the field
+ * @return true, if and only if the named field is defaulted
+ * @throws IOException if there are I/O errors while reading from
+ * the underlying <code>InputStream</code>
+ * @throws IllegalArgumentException if <code>name</code> does not
+ * correspond to a serializable field
+ */
+ public abstract boolean defaulted(String name) throws IOException;
+
+ /**
+ * Get the value of the named boolean field from the persistent field.
+ *
+ * @param name the name of the field
+ * @param val the default value to use if <code>name</code> does not
+ * have a value
+ * @return the value of the named <code>boolean</code> field
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @throws IllegalArgumentException if type of <code>name</code> is
+ * not serializable or if the field type is incorrect
+ */
+ public abstract boolean get(String name, boolean val)
+ throws IOException;
+
+ /**
+ * Get the value of the named byte field from the persistent field.
+ *
+ * @param name the name of the field
+ * @param val the default value to use if <code>name</code> does not
+ * have a value
+ * @return the value of the named <code>byte</code> field
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @throws IllegalArgumentException if type of <code>name</code> is
+ * not serializable or if the field type is incorrect
+ */
+ public abstract byte get(String name, byte val) throws IOException;
+
+ /**
+ * Get the value of the named char field from the persistent field.
+ *
+ * @param name the name of the field
+ * @param val the default value to use if <code>name</code> does not
+ * have a value
+ * @return the value of the named <code>char</code> field
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @throws IllegalArgumentException if type of <code>name</code> is
+ * not serializable or if the field type is incorrect
+ */
+ public abstract char get(String name, char val) throws IOException;
+
+ /**
+ * Get the value of the named short field from the persistent field.
+ *
+ * @param name the name of the field
+ * @param val the default value to use if <code>name</code> does not
+ * have a value
+ * @return the value of the named <code>short</code> field
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @throws IllegalArgumentException if type of <code>name</code> is
+ * not serializable or if the field type is incorrect
+ */
+ public abstract short get(String name, short val) throws IOException;
+
+ /**
+ * Get the value of the named int field from the persistent field.
+ *
+ * @param name the name of the field
+ * @param val the default value to use if <code>name</code> does not
+ * have a value
+ * @return the value of the named <code>int</code> field
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @throws IllegalArgumentException if type of <code>name</code> is
+ * not serializable or if the field type is incorrect
+ */
+ public abstract int get(String name, int val) throws IOException;
+
+ /**
+ * Get the value of the named long field from the persistent field.
+ *
+ * @param name the name of the field
+ * @param val the default value to use if <code>name</code> does not
+ * have a value
+ * @return the value of the named <code>long</code> field
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @throws IllegalArgumentException if type of <code>name</code> is
+ * not serializable or if the field type is incorrect
+ */
+ public abstract long get(String name, long val) throws IOException;
+
+ /**
+ * Get the value of the named float field from the persistent field.
+ *
+ * @param name the name of the field
+ * @param val the default value to use if <code>name</code> does not
+ * have a value
+ * @return the value of the named <code>float</code> field
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @throws IllegalArgumentException if type of <code>name</code> is
+ * not serializable or if the field type is incorrect
+ */
+ public abstract float get(String name, float val) throws IOException;
+
+ /**
+ * Get the value of the named double field from the persistent field.
+ *
+ * @param name the name of the field
+ * @param val the default value to use if <code>name</code> does not
+ * have a value
+ * @return the value of the named <code>double</code> field
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @throws IllegalArgumentException if type of <code>name</code> is
+ * not serializable or if the field type is incorrect
+ */
+ public abstract double get(String name, double val) throws IOException;
+
+ /**
+ * Get the value of the named Object field from the persistent field.
+ *
+ * @param name the name of the field
+ * @param val the default value to use if <code>name</code> does not
+ * have a value
+ * @return the value of the named <code>Object</code> field
+ * @throws IOException if there are I/O errors while reading from the
+ * underlying <code>InputStream</code>
+ * @throws IllegalArgumentException if type of <code>name</code> is
+ * not serializable or if the field type is incorrect
+ */
+ public abstract Object get(String name, Object val) throws IOException;
+ }
+
+ /**
+ * Verifies that this (possibly subclass) instance can be constructed
+ * without violating security constraints: the subclass must not override
+ * security-sensitive non-final methods, or else the
+ * "enableSubclassImplementation" SerializablePermission is checked.
+ */
+ private void verifySubclass() {
+ Class<?> cl = getClass();
+ if (cl == ObjectInputStream.class) {
+ return;
+ }
+ SecurityManager sm = System.getSecurityManager();
+ if (sm == null) {
+ return;
+ }
+ processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
+ WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
+ Boolean result = Caches.subclassAudits.get(key);
+ if (result == null) {
+ result = Boolean.valueOf(auditSubclass(cl));
+ Caches.subclassAudits.putIfAbsent(key, result);
+ }
+ if (result.booleanValue()) {
+ return;
+ }
+ sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
+ }
+
+ /**
+ * Performs reflective checks on given subclass to verify that it doesn't
+ * override security-sensitive non-final methods. Returns true if subclass
+ * is "safe", false otherwise.
+ */
+ private static boolean auditSubclass(final Class<?> subcl) {
+ Boolean result = AccessController.doPrivileged(
+ new PrivilegedAction<Boolean>() {
+ public Boolean run() {
+ for (Class<?> cl = subcl;
+ cl != ObjectInputStream.class;
+ cl = cl.getSuperclass())
+ {
+ try {
+ cl.getDeclaredMethod(
+ "readUnshared", (Class[]) null);
+ return Boolean.FALSE;
+ } catch (NoSuchMethodException ex) {
+ }
+ try {
+ cl.getDeclaredMethod("readFields", (Class[]) null);
+ return Boolean.FALSE;
+ } catch (NoSuchMethodException ex) {
+ }
+ }
+ return Boolean.TRUE;
+ }
+ }
+ );
+ return result.booleanValue();
+ }
+
+ /**
+ * Clears internal data structures.
+ */
+ private void clear() {
+ handles.clear();
+ vlist.clear();
+ }
+
+ /**
+ * Underlying readObject implementation.
+ */
+ private Object readObject0(boolean unshared) throws IOException {
+ boolean oldMode = bin.getBlockDataMode();
+ if (oldMode) {
+ int remain = bin.currentBlockRemaining();
+ if (remain > 0) {
+ throw new OptionalDataException(remain);
+ } else if (defaultDataEnd) {
+ /*
+ * Fix for 4360508: stream is currently at the end of a field
+ * value block written via default serialization; since there
+ * is no terminating TC_ENDBLOCKDATA tag, simulate
+ * end-of-custom-data behavior explicitly.
+ */
+ throw new OptionalDataException(true);
+ }
+ bin.setBlockDataMode(false);
+ }
+
+ byte tc;
+ while ((tc = bin.peekByte()) == TC_RESET) {
+ bin.readByte();
+ handleReset();
+ }
+
+ depth++;
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // totalObjectRefs++;
+ try {
+ switch (tc) {
+ case TC_NULL:
+ return readNull();
+
+ case TC_REFERENCE:
+ return readHandle(unshared);
+
+ case TC_CLASS:
+ return readClass(unshared);
+
+ case TC_CLASSDESC:
+ case TC_PROXYCLASSDESC:
+ return readClassDesc(unshared);
+
+ case TC_STRING:
+ case TC_LONGSTRING:
+ return checkResolve(readString(unshared));
+
+ case TC_ARRAY:
+ return checkResolve(readArray(unshared));
+
+ case TC_ENUM:
+ return checkResolve(readEnum(unshared));
+
+ case TC_OBJECT:
+ return checkResolve(readOrdinaryObject(unshared));
+
+ case TC_EXCEPTION:
+ IOException ex = readFatalException();
+ throw new WriteAbortedException("writing aborted", ex);
+
+ case TC_BLOCKDATA:
+ case TC_BLOCKDATALONG:
+ if (oldMode) {
+ bin.setBlockDataMode(true);
+ bin.peek(); // force header read
+ throw new OptionalDataException(
+ bin.currentBlockRemaining());
+ } else {
+ throw new StreamCorruptedException(
+ "unexpected block data");
+ }
+
+ case TC_ENDBLOCKDATA:
+ if (oldMode) {
+ throw new OptionalDataException(true);
+ } else {
+ throw new StreamCorruptedException(
+ "unexpected end of block data");
+ }
+
+ default:
+ throw new StreamCorruptedException(
+ String.format("invalid type code: %02X", tc));
+ }
+ } finally {
+ depth--;
+ bin.setBlockDataMode(oldMode);
+ }
+ }
+
+ /**
+ * If resolveObject has been enabled and given object does not have an
+ * exception associated with it, calls resolveObject to determine
+ * replacement for object, and updates handle table accordingly. Returns
+ * replacement object, or echoes provided object if no replacement
+ * occurred. Expects that passHandle is set to given object's handle prior
+ * to calling this method.
+ */
+ private Object checkResolve(Object obj) throws IOException {
+ if (!enableResolve || handles.lookupException(passHandle) != null) {
+ return obj;
+ }
+ Object rep = resolveObject(obj);
+ if (rep != obj) {
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ /*
+ // The type of the original object has been filtered but resolveObject
+ // may have replaced it; filter the replacement's type
+ if (rep != null) {
+ if (rep.getClass().isArray()) {
+ filterCheck(rep.getClass(), Array.getLength(rep));
+ } else {
+ filterCheck(rep.getClass(), -1);
+ }
+ }
+ */
+ handles.setObject(passHandle, rep);
+ }
+ return rep;
+ }
+
+ /**
+ * Reads string without allowing it to be replaced in stream. Called from
+ * within ObjectStreamClass.read().
+ */
+ String readTypeString() throws IOException {
+ int oldHandle = passHandle;
+ try {
+ byte tc = bin.peekByte();
+ switch (tc) {
+ case TC_NULL:
+ return (String) readNull();
+
+ case TC_REFERENCE:
+ return (String) readHandle(false);
+
+ case TC_STRING:
+ case TC_LONGSTRING:
+ return readString(false);
+
+ default:
+ throw new StreamCorruptedException(
+ String.format("invalid type code: %02X", tc));
+ }
+ } finally {
+ passHandle = oldHandle;
+ }
+ }
+
+ /**
+ * Reads in null code, sets passHandle to NULL_HANDLE and returns null.
+ */
+ private Object readNull() throws IOException {
+ if (bin.readByte() != TC_NULL) {
+ throw new InternalError();
+ }
+ passHandle = NULL_HANDLE;
+ return null;
+ }
+
+ /**
+ * Reads in object handle, sets passHandle to the read handle, and returns
+ * object associated with the handle.
+ */
+ private Object readHandle(boolean unshared) throws IOException {
+ if (bin.readByte() != TC_REFERENCE) {
+ throw new InternalError();
+ }
+ passHandle = bin.readInt() - baseWireHandle;
+ if (passHandle < 0 || passHandle >= handles.size()) {
+ throw new StreamCorruptedException(
+ String.format("invalid handle value: %08X", passHandle +
+ baseWireHandle));
+ }
+ if (unshared) {
+ // REMIND: what type of exception to throw here?
+ throw new InvalidObjectException(
+ "cannot read back reference as unshared");
+ }
+
+ Object obj = handles.lookupObject(passHandle);
+ if (obj == unsharedMarker) {
+ // REMIND: what type of exception to throw here?
+ throw new InvalidObjectException(
+ "cannot read back reference to unshared object");
+ }
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // filterCheck(null, -1); // just a check for number of references, depth, no class
+ return obj;
+ }
+
+ /**
+ * Reads in and returns class object. Sets passHandle to class object's
+ * assigned handle. Returns null if class is unresolvable (in which case a
+ * ClassNotFoundException will be associated with the class' handle in the
+ * handle table).
+ */
+ private Class<?> readClass(boolean unshared) throws IOException {
+ if (bin.readByte() != TC_CLASS) {
+ throw new InternalError();
+ }
+ ObjectStreamClass desc = readClassDesc(false);
+ Class<?> cl = desc.forClass();
+ passHandle = handles.assign(unshared ? unsharedMarker : cl);
+
+ ClassNotFoundException resolveEx = desc.getResolveException();
+ if (resolveEx != null) {
+ handles.markException(passHandle, resolveEx);
+ }
+
+ handles.finish(passHandle);
+ return cl;
+ }
+
+ /**
+ * Reads in and returns (possibly null) class descriptor. Sets passHandle
+ * to class descriptor's assigned handle. If class descriptor cannot be
+ * resolved to a class in the local VM, a ClassNotFoundException is
+ * associated with the class descriptor's handle.
+ */
+ private ObjectStreamClass readClassDesc(boolean unshared)
+ throws IOException
+ {
+ byte tc = bin.peekByte();
+ ObjectStreamClass descriptor;
+ switch (tc) {
+ case TC_NULL:
+ descriptor = (ObjectStreamClass) readNull();
+ break;
+ case TC_REFERENCE:
+ descriptor = (ObjectStreamClass) readHandle(unshared);
+ break;
+ case TC_PROXYCLASSDESC:
+ descriptor = readProxyDesc(unshared);
+ break;
+ case TC_CLASSDESC:
+ descriptor = readNonProxyDesc(unshared);
+ break;
+ default:
+ throw new StreamCorruptedException(
+ String.format("invalid type code: %02X", tc));
+ }
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // if (descriptor != null) {
+ // validateDescriptor(descriptor);
+ // }
+ return descriptor;
+ }
+
+ private boolean isCustomSubclass() {
+ // Return true if this class is a custom subclass of ObjectInputStream
+ return getClass().getClassLoader()
+ != ObjectInputStream.class.getClassLoader();
+ }
+
+ /**
+ * Reads in and returns class descriptor for a dynamic proxy class. Sets
+ * passHandle to proxy class descriptor's assigned handle. If proxy class
+ * descriptor cannot be resolved to a class in the local VM, a
+ * ClassNotFoundException is associated with the descriptor's handle.
+ */
+ private ObjectStreamClass readProxyDesc(boolean unshared)
+ throws IOException
+ {
+ if (bin.readByte() != TC_PROXYCLASSDESC) {
+ throw new InternalError();
+ }
+
+ ObjectStreamClass desc = new ObjectStreamClass();
+ int descHandle = handles.assign(unshared ? unsharedMarker : desc);
+ passHandle = NULL_HANDLE;
+
+ int numIfaces = bin.readInt();
+ String[] ifaces = new String[numIfaces];
+ for (int i = 0; i < numIfaces; i++) {
+ ifaces[i] = bin.readUTF();
+ }
+
+ Class<?> cl = null;
+ ClassNotFoundException resolveEx = null;
+ bin.setBlockDataMode(true);
+ try {
+ if ((cl = resolveProxyClass(ifaces)) == null) {
+ resolveEx = new ClassNotFoundException("null class");
+ } else if (!Proxy.isProxyClass(cl)) {
+ throw new InvalidClassException("Not a proxy");
+ } else {
+ // ReflectUtil.checkProxyPackageAccess makes a test
+ // equivalent to isCustomSubclass so there's no need
+ // to condition this call to isCustomSubclass == true here.
+ ReflectUtil.checkProxyPackageAccess(
+ getClass().getClassLoader(),
+ cl.getInterfaces());
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // // Filter the interfaces
+ // for (Class<?> clazz : cl.getInterfaces()) {
+ // filterCheck(clazz, -1);
+ // }
+ }
+ } catch (ClassNotFoundException ex) {
+ resolveEx = ex;
+ }
+ skipCustomData();
+
+ desc.initProxy(cl, resolveEx, readClassDesc(false));
+
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // // Call filterCheck on the definition
+ // filterCheck(desc.forClass(), -1);
+
+ handles.finish(descHandle);
+ passHandle = descHandle;
+ return desc;
+ }
+
+ /**
+ * Reads in and returns class descriptor for a class that is not a dynamic
+ * proxy class. Sets passHandle to class descriptor's assigned handle. If
+ * class descriptor cannot be resolved to a class in the local VM, a
+ * ClassNotFoundException is associated with the descriptor's handle.
+ */
+ private ObjectStreamClass readNonProxyDesc(boolean unshared)
+ throws IOException
+ {
+ if (bin.readByte() != TC_CLASSDESC) {
+ throw new InternalError();
+ }
+
+ ObjectStreamClass desc = new ObjectStreamClass();
+ int descHandle = handles.assign(unshared ? unsharedMarker : desc);
+ passHandle = NULL_HANDLE;
+
+ ObjectStreamClass readDesc = null;
+ try {
+ readDesc = readClassDescriptor();
+ } catch (ClassNotFoundException ex) {
+ throw (IOException) new InvalidClassException(
+ "failed to read class descriptor").initCause(ex);
+ }
+
+ Class<?> cl = null;
+ ClassNotFoundException resolveEx = null;
+ bin.setBlockDataMode(true);
+ final boolean checksRequired = isCustomSubclass();
+ try {
+ if ((cl = resolveClass(readDesc)) == null) {
+ resolveEx = new ClassNotFoundException("null class");
+ } else if (checksRequired) {
+ ReflectUtil.checkPackageAccess(cl);
+ }
+ } catch (ClassNotFoundException ex) {
+ resolveEx = ex;
+ }
+ skipCustomData();
+
+ desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
+
+ // Android-removed: ObjectInputFilter unsupported - removed filterCheck() call.
+ // // Call filterCheck on the definition
+ // filterCheck(desc.forClass(), -1);
+
+ handles.finish(descHandle);
+ passHandle = descHandle;
+
+ return desc;
+ }
+
+ /**
+ * Reads in and returns new string. Sets passHandle to new string's
+ * assigned handle.
+ */
+ private String readString(boolean unshared) throws IOException {
+ String str;
+ byte tc = bin.readByte();
+ switch (tc) {
+ case TC_STRING:
+ str = bin.readUTF();
+ break;
+
+ case TC_LONGSTRING:
+ str = bin.readLongUTF();
+ break;
+
+ default:
+ throw new StreamCorruptedException(
+ String.format("invalid type code: %02X", tc));
+ }
+ passHandle = handles.assign(unshared ? unsharedMarker : str);
+ handles.finish(passHandle);
+ return str;
+ }
+
+ /**
+ * Reads in and returns array object, or null if array class is
+ * unresolvable. Sets passHandle to array's assigned handle.
+ */
+ private Object readArray(boolean unshared) throws IOException {
+ if (bin.readByte() != TC_ARRAY) {
+ throw new InternalError();
+ }
+
+ ObjectStreamClass desc = readClassDesc(false);
+ int len = bin.readInt();
+
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // filterCheck(desc.forClass(), len);
+
+ Object array = null;
+ Class<?> cl, ccl = null;
+ if ((cl = desc.forClass()) != null) {
+ ccl = cl.getComponentType();
+ array = Array.newInstance(ccl, len);
+ }
+
+ int arrayHandle = handles.assign(unshared ? unsharedMarker : array);
+ ClassNotFoundException resolveEx = desc.getResolveException();
+ if (resolveEx != null) {
+ handles.markException(arrayHandle, resolveEx);
+ }
+
+ if (ccl == null) {
+ for (int i = 0; i < len; i++) {
+ readObject0(false);
+ }
+ } else if (ccl.isPrimitive()) {
+ if (ccl == Integer.TYPE) {
+ bin.readInts((int[]) array, 0, len);
+ } else if (ccl == Byte.TYPE) {
+ bin.readFully((byte[]) array, 0, len, true);
+ } else if (ccl == Long.TYPE) {
+ bin.readLongs((long[]) array, 0, len);
+ } else if (ccl == Float.TYPE) {
+ bin.readFloats((float[]) array, 0, len);
+ } else if (ccl == Double.TYPE) {
+ bin.readDoubles((double[]) array, 0, len);
+ } else if (ccl == Short.TYPE) {
+ bin.readShorts((short[]) array, 0, len);
+ } else if (ccl == Character.TYPE) {
+ bin.readChars((char[]) array, 0, len);
+ } else if (ccl == Boolean.TYPE) {
+ bin.readBooleans((boolean[]) array, 0, len);
+ } else {
+ throw new InternalError();
+ }
+ } else {
+ Object[] oa = (Object[]) array;
+ for (int i = 0; i < len; i++) {
+ oa[i] = readObject0(false);
+ handles.markDependency(arrayHandle, passHandle);
+ }
+ }
+
+ handles.finish(arrayHandle);
+ passHandle = arrayHandle;
+ return array;
+ }
+
+ /**
+ * Reads in and returns enum constant, or null if enum type is
+ * unresolvable. Sets passHandle to enum constant's assigned handle.
+ */
+ private Enum<?> readEnum(boolean unshared) throws IOException {
+ if (bin.readByte() != TC_ENUM) {
+ throw new InternalError();
+ }
+
+ ObjectStreamClass desc = readClassDesc(false);
+ if (!desc.isEnum()) {
+ throw new InvalidClassException("non-enum class: " + desc);
+ }
+
+ int enumHandle = handles.assign(unshared ? unsharedMarker : null);
+ ClassNotFoundException resolveEx = desc.getResolveException();
+ if (resolveEx != null) {
+ handles.markException(enumHandle, resolveEx);
+ }
+
+ String name = readString(false);
+ Enum<?> result = null;
+ Class<?> cl = desc.forClass();
+ if (cl != null) {
+ try {
+ @SuppressWarnings("unchecked")
+ Enum<?> en = Enum.valueOf((Class)cl, name);
+ result = en;
+ } catch (IllegalArgumentException ex) {
+ throw (IOException) new InvalidObjectException(
+ "enum constant " + name + " does not exist in " +
+ cl).initCause(ex);
+ }
+ if (!unshared) {
+ handles.setObject(enumHandle, result);
+ }
+ }
+
+ handles.finish(enumHandle);
+ passHandle = enumHandle;
+ return result;
+ }
+
+ /**
+ * Reads and returns "ordinary" (i.e., not a String, Class,
+ * ObjectStreamClass, array, or enum constant) object, or null if object's
+ * class is unresolvable (in which case a ClassNotFoundException will be
+ * associated with object's handle). Sets passHandle to object's assigned
+ * handle.
+ */
+ private Object readOrdinaryObject(boolean unshared)
+ throws IOException
+ {
+ if (bin.readByte() != TC_OBJECT) {
+ throw new InternalError();
+ }
+
+ ObjectStreamClass desc = readClassDesc(false);
+ desc.checkDeserialize();
+
+ Class<?> cl = desc.forClass();
+ if (cl == String.class || cl == Class.class
+ || cl == ObjectStreamClass.class) {
+ throw new InvalidClassException("invalid class descriptor");
+ }
+
+ Object obj;
+ try {
+ obj = desc.isInstantiable() ? desc.newInstance() : null;
+ } catch (Exception ex) {
+ throw (IOException) new InvalidClassException(
+ desc.forClass().getName(),
+ "unable to create instance").initCause(ex);
+ }
+
+ passHandle = handles.assign(unshared ? unsharedMarker : obj);
+ ClassNotFoundException resolveEx = desc.getResolveException();
+ if (resolveEx != null) {
+ handles.markException(passHandle, resolveEx);
+ }
+
+ if (desc.isExternalizable()) {
+ readExternalData((Externalizable) obj, desc);
+ } else {
+ readSerialData(obj, desc);
+ }
+
+ handles.finish(passHandle);
+
+ if (obj != null &&
+ handles.lookupException(passHandle) == null &&
+ desc.hasReadResolveMethod())
+ {
+ Object rep = desc.invokeReadResolve(obj);
+ if (unshared && rep.getClass().isArray()) {
+ rep = cloneArray(rep);
+ }
+ if (rep != obj) {
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ /*
+ // Filter the replacement object
+ if (rep != null) {
+ if (rep.getClass().isArray()) {
+ filterCheck(rep.getClass(), Array.getLength(rep));
+ } else {
+ filterCheck(rep.getClass(), -1);
+ }
+ }
+ */
+ handles.setObject(passHandle, obj = rep);
+ }
+ }
+
+ return obj;
+ }
+
+ /**
+ * If obj is non-null, reads externalizable data by invoking readExternal()
+ * method of obj; otherwise, attempts to skip over externalizable data.
+ * Expects that passHandle is set to obj's handle before this method is
+ * called.
+ */
+ private void readExternalData(Externalizable obj, ObjectStreamClass desc)
+ throws IOException
+ {
+ SerialCallbackContext oldContext = curContext;
+ if (oldContext != null)
+ oldContext.check();
+ curContext = null;
+ try {
+ boolean blocked = desc.hasBlockExternalData();
+ if (blocked) {
+ bin.setBlockDataMode(true);
+ }
+ if (obj != null) {
+ try {
+ obj.readExternal(this);
+ } catch (ClassNotFoundException ex) {
+ /*
+ * In most cases, the handle table has already propagated
+ * a CNFException to passHandle at this point; this mark
+ * call is included to address cases where the readExternal
+ * method has cons'ed and thrown a new CNFException of its
+ * own.
+ */
+ handles.markException(passHandle, ex);
+ }
+ }
+ if (blocked) {
+ skipCustomData();
+ }
+ } finally {
+ if (oldContext != null)
+ oldContext.check();
+ curContext = oldContext;
+ }
+ /*
+ * At this point, if the externalizable data was not written in
+ * block-data form and either the externalizable class doesn't exist
+ * locally (i.e., obj == null) or readExternal() just threw a
+ * CNFException, then the stream is probably in an inconsistent state,
+ * since some (or all) of the externalizable data may not have been
+ * consumed. Since there's no "correct" action to take in this case,
+ * we mimic the behavior of past serialization implementations and
+ * blindly hope that the stream is in sync; if it isn't and additional
+ * externalizable data remains in the stream, a subsequent read will
+ * most likely throw a StreamCorruptedException.
+ */
+ }
+
+ /**
+ * Reads (or attempts to skip, if obj is null or is tagged with a
+ * ClassNotFoundException) instance data for each serializable class of
+ * object in stream, from superclass to subclass. Expects that passHandle
+ * is set to obj's handle before this method is called.
+ */
+ private void readSerialData(Object obj, ObjectStreamClass desc)
+ throws IOException
+ {
+ ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
+ for (int i = 0; i < slots.length; i++) {
+ ObjectStreamClass slotDesc = slots[i].desc;
+
+ if (slots[i].hasData) {
+ if (obj == null || handles.lookupException(passHandle) != null) {
+ defaultReadFields(null, slotDesc); // skip field values
+ } else if (slotDesc.hasReadObjectMethod()) {
+ // BEGIN Android-changed: ThreadDeath cannot cause corruption on Android.
+ // Android does not support Thread.stop() or Thread.stop(Throwable) so this
+ // does not need to protect against state corruption that can occur when a
+ // ThreadDeath Error is thrown in the middle of the finally block.
+ SerialCallbackContext oldContext = curContext;
+ if (oldContext != null)
+ oldContext.check();
+ try {
+ curContext = new SerialCallbackContext(obj, slotDesc);
+
+ bin.setBlockDataMode(true);
+ slotDesc.invokeReadObject(obj, this);
+ } catch (ClassNotFoundException ex) {
+ /*
+ * In most cases, the handle table has already
+ * propagated a CNFException to passHandle at this
+ * point; this mark call is included to address cases
+ * where the custom readObject method has cons'ed and
+ * thrown a new CNFException of its own.
+ */
+ handles.markException(passHandle, ex);
+ } finally {
+ curContext.setUsed();
+ if (oldContext!= null)
+ oldContext.check();
+ curContext = oldContext;
+ // END Android-changed: ThreadDeath cannot cause corruption on Android.
+ }
+
+ /*
+ * defaultDataEnd may have been set indirectly by custom
+ * readObject() method when calling defaultReadObject() or
+ * readFields(); clear it to restore normal read behavior.
+ */
+ defaultDataEnd = false;
+ } else {
+ defaultReadFields(obj, slotDesc);
+ }
+
+ if (slotDesc.hasWriteObjectData()) {
+ skipCustomData();
+ } else {
+ bin.setBlockDataMode(false);
+ }
+ } else {
+ if (obj != null &&
+ slotDesc.hasReadObjectNoDataMethod() &&
+ handles.lookupException(passHandle) == null)
+ {
+ slotDesc.invokeReadObjectNoData(obj);
+ }
+ }
+ }
+ }
+
+ /**
+ * Skips over all block data and objects until TC_ENDBLOCKDATA is
+ * encountered.
+ */
+ private void skipCustomData() throws IOException {
+ int oldHandle = passHandle;
+ for (;;) {
+ if (bin.getBlockDataMode()) {
+ bin.skipBlockData();
+ bin.setBlockDataMode(false);
+ }
+ switch (bin.peekByte()) {
+ case TC_BLOCKDATA:
+ case TC_BLOCKDATALONG:
+ bin.setBlockDataMode(true);
+ break;
+
+ case TC_ENDBLOCKDATA:
+ bin.readByte();
+ passHandle = oldHandle;
+ return;
+
+ default:
+ readObject0(false);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Reads in values of serializable fields declared by given class
+ * descriptor. If obj is non-null, sets field values in obj. Expects that
+ * passHandle is set to obj's handle before this method is called.
+ */
+ private void defaultReadFields(Object obj, ObjectStreamClass desc)
+ throws IOException
+ {
+ Class<?> cl = desc.forClass();
+ if (cl != null && obj != null && !cl.isInstance(obj)) {
+ throw new ClassCastException();
+ }
+
+ int primDataSize = desc.getPrimDataSize();
+ if (primVals == null || primVals.length < primDataSize) {
+ primVals = new byte[primDataSize];
+ }
+ bin.readFully(primVals, 0, primDataSize, false);
+ if (obj != null) {
+ desc.setPrimFieldValues(obj, primVals);
+ }
+
+ int objHandle = passHandle;
+ ObjectStreamField[] fields = desc.getFields(false);
+ Object[] objVals = new Object[desc.getNumObjFields()];
+ int numPrimFields = fields.length - objVals.length;
+ for (int i = 0; i < objVals.length; i++) {
+ ObjectStreamField f = fields[numPrimFields + i];
+ objVals[i] = readObject0(f.isUnshared());
+ if (f.getField() != null) {
+ handles.markDependency(objHandle, passHandle);
+ }
+ }
+ if (obj != null) {
+ desc.setObjFieldValues(obj, objVals);
+ }
+ passHandle = objHandle;
+ }
+
+ /**
+ * Reads in and returns IOException that caused serialization to abort.
+ * All stream state is discarded prior to reading in fatal exception. Sets
+ * passHandle to fatal exception's handle.
+ */
+ private IOException readFatalException() throws IOException {
+ if (bin.readByte() != TC_EXCEPTION) {
+ throw new InternalError();
+ }
+ clear();
+ // BEGIN Android-changed: Fix SerializationStressTest#test_2_writeReplace.
+ IOException e = (IOException) readObject0(false);
+ // If we want to continue reading from same stream after fatal exception, we
+ // need to clear internal data structures.
+ clear();
+ return e;
+ // END Android-changed: Fix SerializationStressTest#test_2_writeReplace.
+ }
+
+ /**
+ * If recursion depth is 0, clears internal data structures; otherwise,
+ * throws a StreamCorruptedException. This method is called when a
+ * TC_RESET typecode is encountered.
+ */
+ private void handleReset() throws StreamCorruptedException {
+ if (depth > 0) {
+ throw new StreamCorruptedException(
+ "unexpected reset; recursion depth: " + depth);
+ }
+ clear();
+ }
+
+ /**
+ * Converts specified span of bytes into float values.
+ */
+ // REMIND: remove once hotspot inlines Float.intBitsToFloat
+ private static native void bytesToFloats(byte[] src, int srcpos,
+ float[] dst, int dstpos,
+ int nfloats);
+
+ /**
+ * Converts specified span of bytes into double values.
+ */
+ // REMIND: remove once hotspot inlines Double.longBitsToDouble
+ private static native void bytesToDoubles(byte[] src, int srcpos,
+ double[] dst, int dstpos,
+ int ndoubles);
+
+ /**
+ * Returns the first non-null class loader (not counting class loaders of
+ * generated reflection implementation classes) up the execution stack, or
+ * null if only code from the null class loader is on the stack. This
+ * method is also called via reflection by the following RMI-IIOP class:
+ *
+ * com.sun.corba.se.internal.util.JDKClassLoader
+ *
+ * This method should not be removed or its signature changed without
+ * corresponding modifications to the above class.
+ */
+ private static ClassLoader latestUserDefinedLoader() {
+ // Android-changed: Use VMStack on Android.
+ return VMStack.getClosestUserClassLoader();
+ }
+
+ /**
+ * Default GetField implementation.
+ */
+ private class GetFieldImpl extends GetField {
+
+ /** class descriptor describing serializable fields */
+ private final ObjectStreamClass desc;
+ /** primitive field values */
+ private final byte[] primVals;
+ /** object field values */
+ private final Object[] objVals;
+ /** object field value handles */
+ private final int[] objHandles;
+
+ /**
+ * Creates GetFieldImpl object for reading fields defined in given
+ * class descriptor.
+ */
+ GetFieldImpl(ObjectStreamClass desc) {
+ this.desc = desc;
+ primVals = new byte[desc.getPrimDataSize()];
+ objVals = new Object[desc.getNumObjFields()];
+ objHandles = new int[objVals.length];
+ }
+
+ public ObjectStreamClass getObjectStreamClass() {
+ return desc;
+ }
+
+ public boolean defaulted(String name) throws IOException {
+ return (getFieldOffset(name, null) < 0);
+ }
+
+ public boolean get(String name, boolean val) throws IOException {
+ int off = getFieldOffset(name, Boolean.TYPE);
+ return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
+ }
+
+ public byte get(String name, byte val) throws IOException {
+ int off = getFieldOffset(name, Byte.TYPE);
+ return (off >= 0) ? primVals[off] : val;
+ }
+
+ public char get(String name, char val) throws IOException {
+ int off = getFieldOffset(name, Character.TYPE);
+ return (off >= 0) ? Bits.getChar(primVals, off) : val;
+ }
+
+ public short get(String name, short val) throws IOException {
+ int off = getFieldOffset(name, Short.TYPE);
+ return (off >= 0) ? Bits.getShort(primVals, off) : val;
+ }
+
+ public int get(String name, int val) throws IOException {
+ int off = getFieldOffset(name, Integer.TYPE);
+ return (off >= 0) ? Bits.getInt(primVals, off) : val;
+ }
+
+ public float get(String name, float val) throws IOException {
+ int off = getFieldOffset(name, Float.TYPE);
+ return (off >= 0) ? Bits.getFloat(primVals, off) : val;
+ }
+
+ public long get(String name, long val) throws IOException {
+ int off = getFieldOffset(name, Long.TYPE);
+ return (off >= 0) ? Bits.getLong(primVals, off) : val;
+ }
+
+ public double get(String name, double val) throws IOException {
+ int off = getFieldOffset(name, Double.TYPE);
+ return (off >= 0) ? Bits.getDouble(primVals, off) : val;
+ }
+
+ public Object get(String name, Object val) throws IOException {
+ int off = getFieldOffset(name, Object.class);
+ if (off >= 0) {
+ int objHandle = objHandles[off];
+ handles.markDependency(passHandle, objHandle);
+ return (handles.lookupException(objHandle) == null) ?
+ objVals[off] : null;
+ } else {
+ return val;
+ }
+ }
+
+ /**
+ * Reads primitive and object field values from stream.
+ */
+ void readFields() throws IOException {
+ bin.readFully(primVals, 0, primVals.length, false);
+
+ int oldHandle = passHandle;
+ ObjectStreamField[] fields = desc.getFields(false);
+ int numPrimFields = fields.length - objVals.length;
+ for (int i = 0; i < objVals.length; i++) {
+ objVals[i] =
+ readObject0(fields[numPrimFields + i].isUnshared());
+ objHandles[i] = passHandle;
+ }
+ passHandle = oldHandle;
+ }
+
+ /**
+ * Returns offset of field with given name and type. A specified type
+ * of null matches all types, Object.class matches all non-primitive
+ * types, and any other non-null type matches assignable types only.
+ * If no matching field is found in the (incoming) class
+ * descriptor but a matching field is present in the associated local
+ * class descriptor, returns -1. Throws IllegalArgumentException if
+ * neither incoming nor local class descriptor contains a match.
+ */
+ private int getFieldOffset(String name, Class<?> type) {
+ ObjectStreamField field = desc.getField(name, type);
+ if (field != null) {
+ return field.getOffset();
+ } else if (desc.getLocalDesc().getField(name, type) != null) {
+ return -1;
+ } else {
+ throw new IllegalArgumentException("no such field " + name +
+ " with type " + type);
+ }
+ }
+ }
+
+ /**
+ * Prioritized list of callbacks to be performed once object graph has been
+ * completely deserialized.
+ */
+ private static class ValidationList {
+
+ private static class Callback {
+ final ObjectInputValidation obj;
+ final int priority;
+ Callback next;
+ final AccessControlContext acc;
+
+ Callback(ObjectInputValidation obj, int priority, Callback next,
+ AccessControlContext acc)
+ {
+ this.obj = obj;
+ this.priority = priority;
+ this.next = next;
+ this.acc = acc;
+ }
+ }
+
+ /** linked list of callbacks */
+ private Callback list;
+
+ /**
+ * Creates new (empty) ValidationList.
+ */
+ ValidationList() {
+ }
+
+ /**
+ * Registers callback. Throws InvalidObjectException if callback
+ * object is null.
+ */
+ void register(ObjectInputValidation obj, int priority)
+ throws InvalidObjectException
+ {
+ if (obj == null) {
+ throw new InvalidObjectException("null callback");
+ }
+
+ Callback prev = null, cur = list;
+ while (cur != null && priority < cur.priority) {
+ prev = cur;
+ cur = cur.next;
+ }
+ AccessControlContext acc = AccessController.getContext();
+ if (prev != null) {
+ prev.next = new Callback(obj, priority, cur, acc);
+ } else {
+ list = new Callback(obj, priority, list, acc);
+ }
+ }
+
+ /**
+ * Invokes all registered callbacks and clears the callback list.
+ * Callbacks with higher priorities are called first; those with equal
+ * priorities may be called in any order. If any of the callbacks
+ * throws an InvalidObjectException, the callback process is terminated
+ * and the exception propagated upwards.
+ */
+ void doCallbacks() throws InvalidObjectException {
+ try {
+ while (list != null) {
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Void>()
+ {
+ public Void run() throws InvalidObjectException {
+ list.obj.validateObject();
+ return null;
+ }
+ }, list.acc);
+ list = list.next;
+ }
+ } catch (PrivilegedActionException ex) {
+ list = null;
+ throw (InvalidObjectException) ex.getException();
+ }
+ }
+
+ /**
+ * Resets the callback list to its initial (empty) state.
+ */
+ public void clear() {
+ list = null;
+ }
+ }
+
+ // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+ // Removed FilterValues class.
+
+ /**
+ * Input stream supporting single-byte peek operations.
+ */
+ private static class PeekInputStream extends InputStream {
+
+ /** underlying stream */
+ private final InputStream in;
+ /** peeked byte */
+ private int peekb = -1;
+ /** total bytes read from the stream */
+ private long totalBytesRead = 0;
+
+ /**
+ * Creates new PeekInputStream on top of given underlying stream.
+ */
+ PeekInputStream(InputStream in) {
+ this.in = in;
+ }
+
+ /**
+ * Peeks at next byte value in stream. Similar to read(), except
+ * that it does not consume the read value.
+ */
+ int peek() throws IOException {
+ if (peekb >= 0) {
+ return peekb;
+ }
+ peekb = in.read();
+ totalBytesRead += peekb >= 0 ? 1 : 0;
+ return peekb;
+ }
+
+ public int read() throws IOException {
+ if (peekb >= 0) {
+ int v = peekb;
+ peekb = -1;
+ return v;
+ } else {
+ int nbytes = in.read();
+ totalBytesRead += nbytes >= 0 ? 1 : 0;
+ return nbytes;
+ }
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ int nbytes;
+ if (len == 0) {
+ return 0;
+ } else if (peekb < 0) {
+ nbytes = in.read(b, off, len);
+ totalBytesRead += nbytes >= 0 ? nbytes : 0;
+ return nbytes;
+ } else {
+ b[off++] = (byte) peekb;
+ len--;
+ peekb = -1;
+ nbytes = in.read(b, off, len);
+ totalBytesRead += nbytes >= 0 ? nbytes : 0;
+ return (nbytes >= 0) ? (nbytes + 1) : 1;
+ }
+ }
+
+ void readFully(byte[] b, int off, int len) throws IOException {
+ int n = 0;
+ while (n < len) {
+ int count = read(b, off + n, len - n);
+ if (count < 0) {
+ throw new EOFException();
+ }
+ n += count;
+ }
+ }
+
+ public long skip(long n) throws IOException {
+ if (n <= 0) {
+ return 0;
+ }
+ int skipped = 0;
+ if (peekb >= 0) {
+ peekb = -1;
+ skipped++;
+ n--;
+ }
+ n = skipped + in.skip(n);
+ totalBytesRead += n;
+ return n;
+ }
+
+ public int available() throws IOException {
+ return in.available() + ((peekb >= 0) ? 1 : 0);
+ }
+
+ public void close() throws IOException {
+ in.close();
+ }
+
+ public long getBytesRead() {
+ return totalBytesRead;
+ }
+ }
+
+ /**
+ * Input stream with two modes: in default mode, inputs data written in the
+ * same format as DataOutputStream; in "block data" mode, inputs data
+ * bracketed by block data markers (see object serialization specification
+ * for details). Buffering depends on block data mode: when in default
+ * mode, no data is buffered in advance; when in block data mode, all data
+ * for the current data block is read in at once (and buffered).
+ */
+ private class BlockDataInputStream
+ extends InputStream implements DataInput
+ {
+ /** maximum data block length */
+ private static final int MAX_BLOCK_SIZE = 1024;
+ /** maximum data block header length */
+ private static final int MAX_HEADER_SIZE = 5;
+ /** (tunable) length of char buffer (for reading strings) */
+ private static final int CHAR_BUF_SIZE = 256;
+ /** readBlockHeader() return value indicating header read may block */
+ private static final int HEADER_BLOCKED = -2;
+
+ /** buffer for reading general/block data */
+ private final byte[] buf = new byte[MAX_BLOCK_SIZE];
+ /** buffer for reading block data headers */
+ private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
+ /** char buffer for fast string reads */
+ private final char[] cbuf = new char[CHAR_BUF_SIZE];
+
+ /** block data mode */
+ private boolean blkmode = false;
+
+ // block data state fields; values meaningful only when blkmode true
+ /** current offset into buf */
+ private int pos = 0;
+ /** end offset of valid data in buf, or -1 if no more block data */
+ private int end = -1;
+ /** number of bytes in current block yet to be read from stream */
+ private int unread = 0;
+
+ /** underlying stream (wrapped in peekable filter stream) */
+ private final PeekInputStream in;
+ /** loopback stream (for data reads that span data blocks) */
+ private final DataInputStream din;
+
+ /**
+ * Creates new BlockDataInputStream on top of given underlying stream.
+ * Block data mode is turned off by default.
+ */
+ BlockDataInputStream(InputStream in) {
+ this.in = new PeekInputStream(in);
+ din = new DataInputStream(this);
+ }
+
+ /**
+ * Sets block data mode to the given mode (true == on, false == off)
+ * and returns the previous mode value. If the new mode is the same as
+ * the old mode, no action is taken. Throws IllegalStateException if
+ * block data mode is being switched from on to off while unconsumed
+ * block data is still present in the stream.
+ */
+ boolean setBlockDataMode(boolean newmode) throws IOException {
+ if (blkmode == newmode) {
+ return blkmode;
+ }
+ if (newmode) {
+ pos = 0;
+ end = 0;
+ unread = 0;
+ } else if (pos < end) {
+ throw new IllegalStateException("unread block data");
+ }
+ blkmode = newmode;
+ return !blkmode;
+ }
+
+ /**
+ * Returns true if the stream is currently in block data mode, false
+ * otherwise.
+ */
+ boolean getBlockDataMode() {
+ return blkmode;
+ }
+
+ /**
+ * If in block data mode, skips to the end of the current group of data
+ * blocks (but does not unset block data mode). If not in block data
+ * mode, throws an IllegalStateException.
+ */
+ void skipBlockData() throws IOException {
+ if (!blkmode) {
+ throw new IllegalStateException("not in block data mode");
+ }
+ while (end >= 0) {
+ refill();
+ }
+ }
+
+ /**
+ * Attempts to read in the next block data header (if any). If
+ * canBlock is false and a full header cannot be read without possibly
+ * blocking, returns HEADER_BLOCKED, else if the next element in the
+ * stream is a block data header, returns the block data length
+ * specified by the header, else returns -1.
+ */
+ private int readBlockHeader(boolean canBlock) throws IOException {
+ if (defaultDataEnd) {
+ /*
+ * Fix for 4360508: stream is currently at the end of a field
+ * value block written via default serialization; since there
+ * is no terminating TC_ENDBLOCKDATA tag, simulate
+ * end-of-custom-data behavior explicitly.
+ */
+ return -1;
+ }
+ try {
+ for (;;) {
+ int avail = canBlock ? Integer.MAX_VALUE : in.available();
+ if (avail == 0) {
+ return HEADER_BLOCKED;
+ }
+
+ int tc = in.peek();
+ switch (tc) {
+ case TC_BLOCKDATA:
+ if (avail < 2) {
+ return HEADER_BLOCKED;
+ }
+ in.readFully(hbuf, 0, 2);
+ return hbuf[1] & 0xFF;
+
+ case TC_BLOCKDATALONG:
+ if (avail < 5) {
+ return HEADER_BLOCKED;
+ }
+ in.readFully(hbuf, 0, 5);
+ int len = Bits.getInt(hbuf, 1);
+ if (len < 0) {
+ throw new StreamCorruptedException(
+ "illegal block data header length: " +
+ len);
+ }
+ return len;
+
+ /*
+ * TC_RESETs may occur in between data blocks.
+ * Unfortunately, this case must be parsed at a lower
+ * level than other typecodes, since primitive data
+ * reads may span data blocks separated by a TC_RESET.
+ */
+ case TC_RESET:
+ in.read();
+ handleReset();
+ break;
+
+ default:
+ if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
+ throw new StreamCorruptedException(
+ String.format("invalid type code: %02X",
+ tc));
+ }
+ return -1;
+ }
+ }
+ } catch (EOFException ex) {
+ throw new StreamCorruptedException(
+ "unexpected EOF while reading block data header");
+ }
+ }
+
+ /**
+ * Refills internal buffer buf with block data. Any data in buf at the
+ * time of the call is considered consumed. Sets the pos, end, and
+ * unread fields to reflect the new amount of available block data; if
+ * the next element in the stream is not a data block, sets pos and
+ * unread to 0 and end to -1.
+ */
+ private void refill() throws IOException {
+ try {
+ do {
+ pos = 0;
+ if (unread > 0) {
+ int n =
+ in.read(buf, 0, Math.min(unread, MAX_BLOCK_SIZE));
+ if (n >= 0) {
+ end = n;
+ unread -= n;
+ } else {
+ throw new StreamCorruptedException(
+ "unexpected EOF in middle of data block");
+ }
+ } else {
+ int n = readBlockHeader(true);
+ if (n >= 0) {
+ end = 0;
+ unread = n;
+ } else {
+ end = -1;
+ unread = 0;
+ }
+ }
+ } while (pos == end);
+ } catch (IOException ex) {
+ pos = 0;
+ end = -1;
+ unread = 0;
+ throw ex;
+ }
+ }
+
+ /**
+ * If in block data mode, returns the number of unconsumed bytes
+ * remaining in the current data block. If not in block data mode,
+ * throws an IllegalStateException.
+ */
+ int currentBlockRemaining() {
+ if (blkmode) {
+ return (end >= 0) ? (end - pos) + unread : 0;
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * Peeks at (but does not consume) and returns the next byte value in
+ * the stream, or -1 if the end of the stream/block data (if in block
+ * data mode) has been reached.
+ */
+ int peek() throws IOException {
+ if (blkmode) {
+ if (pos == end) {
+ refill();
+ }
+ return (end >= 0) ? (buf[pos] & 0xFF) : -1;
+ } else {
+ return in.peek();
+ }
+ }
+
+ /**
+ * Peeks at (but does not consume) and returns the next byte value in
+ * the stream, or throws EOFException if end of stream/block data has
+ * been reached.
+ */
+ byte peekByte() throws IOException {
+ int val = peek();
+ if (val < 0) {
+ throw new EOFException();
+ }
+ return (byte) val;
+ }
+
+
+ /* ----------------- generic input stream methods ------------------ */
+ /*
+ * The following methods are equivalent to their counterparts in
+ * InputStream, except that they interpret data block boundaries and
+ * read the requested data from within data blocks when in block data
+ * mode.
+ */
+
+ public int read() throws IOException {
+ if (blkmode) {
+ if (pos == end) {
+ refill();
+ }
+ return (end >= 0) ? (buf[pos++] & 0xFF) : -1;
+ } else {
+ return in.read();
+ }
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ return read(b, off, len, false);
+ }
+
+ public long skip(long len) throws IOException {
+ long remain = len;
+ while (remain > 0) {
+ if (blkmode) {
+ if (pos == end) {
+ refill();
+ }
+ if (end < 0) {
+ break;
+ }
+ int nread = (int) Math.min(remain, end - pos);
+ remain -= nread;
+ pos += nread;
+ } else {
+ int nread = (int) Math.min(remain, MAX_BLOCK_SIZE);
+ if ((nread = in.read(buf, 0, nread)) < 0) {
+ break;
+ }
+ remain -= nread;
+ }
+ }
+ return len - remain;
+ }
+
+ public int available() throws IOException {
+ if (blkmode) {
+ if ((pos == end) && (unread == 0)) {
+ int n;
+ while ((n = readBlockHeader(false)) == 0) ;
+ switch (n) {
+ case HEADER_BLOCKED:
+ break;
+
+ case -1:
+ pos = 0;
+ end = -1;
+ break;
+
+ default:
+ pos = 0;
+ end = 0;
+ unread = n;
+ break;
+ }
+ }
+ // avoid unnecessary call to in.available() if possible
+ int unreadAvail = (unread > 0) ?
+ Math.min(in.available(), unread) : 0;
+ return (end >= 0) ? (end - pos) + unreadAvail : 0;
+ } else {
+ return in.available();
+ }
+ }
+
+ public void close() throws IOException {
+ if (blkmode) {
+ pos = 0;
+ end = -1;
+ unread = 0;
+ }
+ in.close();
+ }
+
+ /**
+ * Attempts to read len bytes into byte array b at offset off. Returns
+ * the number of bytes read, or -1 if the end of stream/block data has
+ * been reached. If copy is true, reads values into an intermediate
+ * buffer before copying them to b (to avoid exposing a reference to
+ * b).
+ */
+ int read(byte[] b, int off, int len, boolean copy) throws IOException {
+ if (len == 0) {
+ return 0;
+ } else if (blkmode) {
+ if (pos == end) {
+ refill();
+ }
+ if (end < 0) {
+ return -1;
+ }
+ int nread = Math.min(len, end - pos);
+ System.arraycopy(buf, pos, b, off, nread);
+ pos += nread;
+ return nread;
+ } else if (copy) {
+ int nread = in.read(buf, 0, Math.min(len, MAX_BLOCK_SIZE));
+ if (nread > 0) {
+ System.arraycopy(buf, 0, b, off, nread);
+ }
+ return nread;
+ } else {
+ return in.read(b, off, len);
+ }
+ }
+
+ /* ----------------- primitive data input methods ------------------ */
+ /*
+ * The following methods are equivalent to their counterparts in
+ * DataInputStream, except that they interpret data block boundaries
+ * and read the requested data from within data blocks when in block
+ * data mode.
+ */
+
+ public void readFully(byte[] b) throws IOException {
+ readFully(b, 0, b.length, false);
+ }
+
+ public void readFully(byte[] b, int off, int len) throws IOException {
+ readFully(b, off, len, false);
+ }
+
+ public void readFully(byte[] b, int off, int len, boolean copy)
+ throws IOException
+ {
+ while (len > 0) {
+ int n = read(b, off, len, copy);
+ if (n < 0) {
+ throw new EOFException();
+ }
+ off += n;
+ len -= n;
+ }
+ }
+
+ public int skipBytes(int n) throws IOException {
+ return din.skipBytes(n);
+ }
+
+ public boolean readBoolean() throws IOException {
+ int v = read();
+ if (v < 0) {
+ throw new EOFException();
+ }
+ return (v != 0);
+ }
+
+ public byte readByte() throws IOException {
+ int v = read();
+ if (v < 0) {
+ throw new EOFException();
+ }
+ return (byte) v;
+ }
+
+ public int readUnsignedByte() throws IOException {
+ int v = read();
+ if (v < 0) {
+ throw new EOFException();
+ }
+ return v;
+ }
+
+ public char readChar() throws IOException {
+ if (!blkmode) {
+ pos = 0;
+ in.readFully(buf, 0, 2);
+ } else if (end - pos < 2) {
+ return din.readChar();
+ }
+ char v = Bits.getChar(buf, pos);
+ pos += 2;
+ return v;
+ }
+
+ public short readShort() throws IOException {
+ if (!blkmode) {
+ pos = 0;
+ in.readFully(buf, 0, 2);
+ } else if (end - pos < 2) {
+ return din.readShort();
+ }
+ short v = Bits.getShort(buf, pos);
+ pos += 2;
+ return v;
+ }
+
+ public int readUnsignedShort() throws IOException {
+ if (!blkmode) {
+ pos = 0;
+ in.readFully(buf, 0, 2);
+ } else if (end - pos < 2) {
+ return din.readUnsignedShort();
+ }
+ int v = Bits.getShort(buf, pos) & 0xFFFF;
+ pos += 2;
+ return v;
+ }
+
+ public int readInt() throws IOException {
+ if (!blkmode) {
+ pos = 0;
+ in.readFully(buf, 0, 4);
+ } else if (end - pos < 4) {
+ return din.readInt();
+ }
+ int v = Bits.getInt(buf, pos);
+ pos += 4;
+ return v;
+ }
+
+ public float readFloat() throws IOException {
+ if (!blkmode) {
+ pos = 0;
+ in.readFully(buf, 0, 4);
+ } else if (end - pos < 4) {
+ return din.readFloat();
+ }
+ float v = Bits.getFloat(buf, pos);
+ pos += 4;
+ return v;
+ }
+
+ public long readLong() throws IOException {
+ if (!blkmode) {
+ pos = 0;
+ in.readFully(buf, 0, 8);
+ } else if (end - pos < 8) {
+ return din.readLong();
+ }
+ long v = Bits.getLong(buf, pos);
+ pos += 8;
+ return v;
+ }
+
+ public double readDouble() throws IOException {
+ if (!blkmode) {
+ pos = 0;
+ in.readFully(buf, 0, 8);
+ } else if (end - pos < 8) {
+ return din.readDouble();
+ }
+ double v = Bits.getDouble(buf, pos);
+ pos += 8;
+ return v;
+ }
+
+ public String readUTF() throws IOException {
+ return readUTFBody(readUnsignedShort());
+ }
+
+ @SuppressWarnings("deprecation")
+ public String readLine() throws IOException {
+ return din.readLine(); // deprecated, not worth optimizing
+ }
+
+ /* -------------- primitive data array input methods --------------- */
+ /*
+ * The following methods read in spans of primitive data values.
+ * Though equivalent to calling the corresponding primitive read
+ * methods repeatedly, these methods are optimized for reading groups
+ * of primitive data values more efficiently.
+ */
+
+ void readBooleans(boolean[] v, int off, int len) throws IOException {
+ int stop, endoff = off + len;
+ while (off < endoff) {
+ if (!blkmode) {
+ int span = Math.min(endoff - off, MAX_BLOCK_SIZE);
+ in.readFully(buf, 0, span);
+ stop = off + span;
+ pos = 0;
+ } else if (end - pos < 1) {
+ v[off++] = din.readBoolean();
+ continue;
+ } else {
+ stop = Math.min(endoff, off + end - pos);
+ }
+
+ while (off < stop) {
+ v[off++] = Bits.getBoolean(buf, pos++);
+ }
+ }
+ }
+
+ void readChars(char[] v, int off, int len) throws IOException {
+ int stop, endoff = off + len;
+ while (off < endoff) {
+ if (!blkmode) {
+ int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
+ in.readFully(buf, 0, span << 1);
+ stop = off + span;
+ pos = 0;
+ } else if (end - pos < 2) {
+ v[off++] = din.readChar();
+ continue;
+ } else {
+ stop = Math.min(endoff, off + ((end - pos) >> 1));
+ }
+
+ while (off < stop) {
+ v[off++] = Bits.getChar(buf, pos);
+ pos += 2;
+ }
+ }
+ }
+
+ void readShorts(short[] v, int off, int len) throws IOException {
+ int stop, endoff = off + len;
+ while (off < endoff) {
+ if (!blkmode) {
+ int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
+ in.readFully(buf, 0, span << 1);
+ stop = off + span;
+ pos = 0;
+ } else if (end - pos < 2) {
+ v[off++] = din.readShort();
+ continue;
+ } else {
+ stop = Math.min(endoff, off + ((end - pos) >> 1));
+ }
+
+ while (off < stop) {
+ v[off++] = Bits.getShort(buf, pos);
+ pos += 2;
+ }
+ }
+ }
+
+ void readInts(int[] v, int off, int len) throws IOException {
+ int stop, endoff = off + len;
+ while (off < endoff) {
+ if (!blkmode) {
+ int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
+ in.readFully(buf, 0, span << 2);
+ stop = off + span;
+ pos = 0;
+ } else if (end - pos < 4) {
+ v[off++] = din.readInt();
+ continue;
+ } else {
+ stop = Math.min(endoff, off + ((end - pos) >> 2));
+ }
+
+ while (off < stop) {
+ v[off++] = Bits.getInt(buf, pos);
+ pos += 4;
+ }
+ }
+ }
+
+ void readFloats(float[] v, int off, int len) throws IOException {
+ int span, endoff = off + len;
+ while (off < endoff) {
+ if (!blkmode) {
+ span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
+ in.readFully(buf, 0, span << 2);
+ pos = 0;
+ } else if (end - pos < 4) {
+ v[off++] = din.readFloat();
+ continue;
+ } else {
+ span = Math.min(endoff - off, ((end - pos) >> 2));
+ }
+
+ bytesToFloats(buf, pos, v, off, span);
+ off += span;
+ pos += span << 2;
+ }
+ }
+
+ void readLongs(long[] v, int off, int len) throws IOException {
+ int stop, endoff = off + len;
+ while (off < endoff) {
+ if (!blkmode) {
+ int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
+ in.readFully(buf, 0, span << 3);
+ stop = off + span;
+ pos = 0;
+ } else if (end - pos < 8) {
+ v[off++] = din.readLong();
+ continue;
+ } else {
+ stop = Math.min(endoff, off + ((end - pos) >> 3));
+ }
+
+ while (off < stop) {
+ v[off++] = Bits.getLong(buf, pos);
+ pos += 8;
+ }
+ }
+ }
+
+ void readDoubles(double[] v, int off, int len) throws IOException {
+ int span, endoff = off + len;
+ while (off < endoff) {
+ if (!blkmode) {
+ span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
+ in.readFully(buf, 0, span << 3);
+ pos = 0;
+ } else if (end - pos < 8) {
+ v[off++] = din.readDouble();
+ continue;
+ } else {
+ span = Math.min(endoff - off, ((end - pos) >> 3));
+ }
+
+ bytesToDoubles(buf, pos, v, off, span);
+ off += span;
+ pos += span << 3;
+ }
+ }
+
+ /**
+ * Reads in string written in "long" UTF format. "Long" UTF format is
+ * identical to standard UTF, except that it uses an 8 byte header
+ * (instead of the standard 2 bytes) to convey the UTF encoding length.
+ */
+ String readLongUTF() throws IOException {
+ return readUTFBody(readLong());
+ }
+
+ /**
+ * Reads in the "body" (i.e., the UTF representation minus the 2-byte
+ * or 8-byte length header) of a UTF encoding, which occupies the next
+ * utflen bytes.
+ */
+ private String readUTFBody(long utflen) throws IOException {
+ StringBuilder sbuf = new StringBuilder();
+ if (!blkmode) {
+ end = pos = 0;
+ }
+
+ while (utflen > 0) {
+ int avail = end - pos;
+ if (avail >= 3 || (long) avail == utflen) {
+ utflen -= readUTFSpan(sbuf, utflen);
+ } else {
+ if (blkmode) {
+ // near block boundary, read one byte at a time
+ utflen -= readUTFChar(sbuf, utflen);
+ } else {
+ // shift and refill buffer manually
+ if (avail > 0) {
+ System.arraycopy(buf, pos, buf, 0, avail);
+ }
+ pos = 0;
+ end = (int) Math.min(MAX_BLOCK_SIZE, utflen);
+ in.readFully(buf, avail, end - avail);
+ }
+ }
+ }
+
+ return sbuf.toString();
+ }
+
+ /**
+ * Reads span of UTF-encoded characters out of internal buffer
+ * (starting at offset pos and ending at or before offset end),
+ * consuming no more than utflen bytes. Appends read characters to
+ * sbuf. Returns the number of bytes consumed.
+ */
+ private long readUTFSpan(StringBuilder sbuf, long utflen)
+ throws IOException
+ {
+ int cpos = 0;
+ int start = pos;
+ int avail = Math.min(end - pos, CHAR_BUF_SIZE);
+ // stop short of last char unless all of utf bytes in buffer
+ int stop = pos + ((utflen > avail) ? avail - 2 : (int) utflen);
+ boolean outOfBounds = false;
+
+ try {
+ while (pos < stop) {
+ int b1, b2, b3;
+ b1 = buf[pos++] & 0xFF;
+ switch (b1 >> 4) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7: // 1 byte format: 0xxxxxxx
+ cbuf[cpos++] = (char) b1;
+ break;
+
+ case 12:
+ case 13: // 2 byte format: 110xxxxx 10xxxxxx
+ b2 = buf[pos++];
+ if ((b2 & 0xC0) != 0x80) {
+ throw new UTFDataFormatException();
+ }
+ cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) |
+ ((b2 & 0x3F) << 0));
+ break;
+
+ case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
+ b3 = buf[pos + 1];
+ b2 = buf[pos + 0];
+ pos += 2;
+ if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
+ throw new UTFDataFormatException();
+ }
+ cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) |
+ ((b2 & 0x3F) << 6) |
+ ((b3 & 0x3F) << 0));
+ break;
+
+ default: // 10xx xxxx, 1111 xxxx
+ throw new UTFDataFormatException();
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ outOfBounds = true;
+ } finally {
+ if (outOfBounds || (pos - start) > utflen) {
+ /*
+ * Fix for 4450867: if a malformed utf char causes the
+ * conversion loop to scan past the expected end of the utf
+ * string, only consume the expected number of utf bytes.
+ */
+ pos = start + (int) utflen;
+ throw new UTFDataFormatException();
+ }
+ }
+
+ sbuf.append(cbuf, 0, cpos);
+ return pos - start;
+ }
+
+ /**
+ * Reads in single UTF-encoded character one byte at a time, appends
+ * the character to sbuf, and returns the number of bytes consumed.
+ * This method is used when reading in UTF strings written in block
+ * data mode to handle UTF-encoded characters which (potentially)
+ * straddle block-data boundaries.
+ */
+ private int readUTFChar(StringBuilder sbuf, long utflen)
+ throws IOException
+ {
+ int b1, b2, b3;
+ b1 = readByte() & 0xFF;
+ switch (b1 >> 4) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7: // 1 byte format: 0xxxxxxx
+ sbuf.append((char) b1);
+ return 1;
+
+ case 12:
+ case 13: // 2 byte format: 110xxxxx 10xxxxxx
+ if (utflen < 2) {
+ throw new UTFDataFormatException();
+ }
+ b2 = readByte();
+ if ((b2 & 0xC0) != 0x80) {
+ throw new UTFDataFormatException();
+ }
+ sbuf.append((char) (((b1 & 0x1F) << 6) |
+ ((b2 & 0x3F) << 0)));
+ return 2;
+
+ case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
+ if (utflen < 3) {
+ if (utflen == 2) {
+ readByte(); // consume remaining byte
+ }
+ throw new UTFDataFormatException();
+ }
+ b2 = readByte();
+ b3 = readByte();
+ if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
+ throw new UTFDataFormatException();
+ }
+ sbuf.append((char) (((b1 & 0x0F) << 12) |
+ ((b2 & 0x3F) << 6) |
+ ((b3 & 0x3F) << 0)));
+ return 3;
+
+ default: // 10xx xxxx, 1111 xxxx
+ throw new UTFDataFormatException();
+ }
+ }
+
+ /**
+ * Returns the number of bytes read from the input stream.
+ * @return the number of bytes read from the input stream
+ */
+ long getBytesRead() {
+ return in.getBytesRead();
+ }
+ }
+
+ /**
+ * Unsynchronized table which tracks wire handle to object mappings, as
+ * well as ClassNotFoundExceptions associated with deserialized objects.
+ * This class implements an exception-propagation algorithm for
+ * determining which objects should have ClassNotFoundExceptions associated
+ * with them, taking into account cycles and discontinuities (e.g., skipped
+ * fields) in the object graph.
+ *
+ * <p>General use of the table is as follows: during deserialization, a
+ * given object is first assigned a handle by calling the assign method.
+ * This method leaves the assigned handle in an "open" state, wherein
+ * dependencies on the exception status of other handles can be registered
+ * by calling the markDependency method, or an exception can be directly
+ * associated with the handle by calling markException. When a handle is
+ * tagged with an exception, the HandleTable assumes responsibility for
+ * propagating the exception to any other objects which depend
+ * (transitively) on the exception-tagged object.
+ *
+ * <p>Once all exception information/dependencies for the handle have been
+ * registered, the handle should be "closed" by calling the finish method
+ * on it. The act of finishing a handle allows the exception propagation
+ * algorithm to aggressively prune dependency links, lessening the
+ * performance/memory impact of exception tracking.
+ *
+ * <p>Note that the exception propagation algorithm used depends on handles
+ * being assigned/finished in LIFO order; however, for simplicity as well
+ * as memory conservation, it does not enforce this constraint.
+ */
+ // REMIND: add full description of exception propagation algorithm?
+ private static class HandleTable {
+
+ /* status codes indicating whether object has associated exception */
+ private static final byte STATUS_OK = 1;
+ private static final byte STATUS_UNKNOWN = 2;
+ private static final byte STATUS_EXCEPTION = 3;
+
+ /** array mapping handle -> object status */
+ byte[] status;
+ /** array mapping handle -> object/exception (depending on status) */
+ Object[] entries;
+ /** array mapping handle -> list of dependent handles (if any) */
+ HandleList[] deps;
+ /** lowest unresolved dependency */
+ int lowDep = -1;
+ /** number of handles in table */
+ int size = 0;
+
+ /**
+ * Creates handle table with the given initial capacity.
+ */
+ HandleTable(int initialCapacity) {
+ status = new byte[initialCapacity];
+ entries = new Object[initialCapacity];
+ deps = new HandleList[initialCapacity];
+ }
+
+ /**
+ * Assigns next available handle to given object, and returns assigned
+ * handle. Once object has been completely deserialized (and all
+ * dependencies on other objects identified), the handle should be
+ * "closed" by passing it to finish().
+ */
+ int assign(Object obj) {
+ if (size >= entries.length) {
+ grow();
+ }
+ status[size] = STATUS_UNKNOWN;
+ entries[size] = obj;
+ return size++;
+ }
+
+ /**
+ * Registers a dependency (in exception status) of one handle on
+ * another. The dependent handle must be "open" (i.e., assigned, but
+ * not finished yet). No action is taken if either dependent or target
+ * handle is NULL_HANDLE.
+ */
+ void markDependency(int dependent, int target) {
+ if (dependent == NULL_HANDLE || target == NULL_HANDLE) {
+ return;
+ }
+ switch (status[dependent]) {
+
+ case STATUS_UNKNOWN:
+ switch (status[target]) {
+ case STATUS_OK:
+ // ignore dependencies on objs with no exception
+ break;
+
+ case STATUS_EXCEPTION:
+ // eagerly propagate exception
+ markException(dependent,
+ (ClassNotFoundException) entries[target]);
+ break;
+
+ case STATUS_UNKNOWN:
+ // add to dependency list of target
+ if (deps[target] == null) {
+ deps[target] = new HandleList();
+ }
+ deps[target].add(dependent);
+
+ // remember lowest unresolved target seen
+ if (lowDep < 0 || lowDep > target) {
+ lowDep = target;
+ }
+ break;
+
+ default:
+ throw new InternalError();
+ }
+ break;
+
+ case STATUS_EXCEPTION:
+ break;
+
+ default:
+ throw new InternalError();
+ }
+ }
+
+ /**
+ * Associates a ClassNotFoundException (if one not already associated)
+ * with the currently active handle and propagates it to other
+ * referencing objects as appropriate. The specified handle must be
+ * "open" (i.e., assigned, but not finished yet).
+ */
+ void markException(int handle, ClassNotFoundException ex) {
+ switch (status[handle]) {
+ case STATUS_UNKNOWN:
+ status[handle] = STATUS_EXCEPTION;
+ entries[handle] = ex;
+
+ // propagate exception to dependents
+ HandleList dlist = deps[handle];
+ if (dlist != null) {
+ int ndeps = dlist.size();
+ for (int i = 0; i < ndeps; i++) {
+ markException(dlist.get(i), ex);
+ }
+ deps[handle] = null;
+ }
+ break;
+
+ case STATUS_EXCEPTION:
+ break;
+
+ default:
+ throw new InternalError();
+ }
+ }
+
+ /**
+ * Marks given handle as finished, meaning that no new dependencies
+ * will be marked for handle. Calls to the assign and finish methods
+ * must occur in LIFO order.
+ */
+ void finish(int handle) {
+ int end;
+ if (lowDep < 0) {
+ // no pending unknowns, only resolve current handle
+ end = handle + 1;
+ } else if (lowDep >= handle) {
+ // pending unknowns now clearable, resolve all upward handles
+ end = size;
+ lowDep = -1;
+ } else {
+ // unresolved backrefs present, can't resolve anything yet
+ return;
+ }
+
+ // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
+ for (int i = handle; i < end; i++) {
+ switch (status[i]) {
+ case STATUS_UNKNOWN:
+ status[i] = STATUS_OK;
+ deps[i] = null;
+ break;
+
+ case STATUS_OK:
+ case STATUS_EXCEPTION:
+ break;
+
+ default:
+ throw new InternalError();
+ }
+ }
+ }
+
+ /**
+ * Assigns a new object to the given handle. The object previously
+ * associated with the handle is forgotten. This method has no effect
+ * if the given handle already has an exception associated with it.
+ * This method may be called at any time after the handle is assigned.
+ */
+ void setObject(int handle, Object obj) {
+ switch (status[handle]) {
+ case STATUS_UNKNOWN:
+ case STATUS_OK:
+ entries[handle] = obj;
+ break;
+
+ case STATUS_EXCEPTION:
+ break;
+
+ default:
+ throw new InternalError();
+ }
+ }
+
+ /**
+ * Looks up and returns object associated with the given handle.
+ * Returns null if the given handle is NULL_HANDLE, or if it has an
+ * associated ClassNotFoundException.
+ */
+ Object lookupObject(int handle) {
+ return (handle != NULL_HANDLE &&
+ status[handle] != STATUS_EXCEPTION) ?
+ entries[handle] : null;
+ }
+
+ /**
+ * Looks up and returns ClassNotFoundException associated with the
+ * given handle. Returns null if the given handle is NULL_HANDLE, or
+ * if there is no ClassNotFoundException associated with the handle.
+ */
+ ClassNotFoundException lookupException(int handle) {
+ return (handle != NULL_HANDLE &&
+ status[handle] == STATUS_EXCEPTION) ?
+ (ClassNotFoundException) entries[handle] : null;
+ }
+
+ /**
+ * Resets table to its initial state.
+ */
+ void clear() {
+ Arrays.fill(status, 0, size, (byte) 0);
+ Arrays.fill(entries, 0, size, null);
+ Arrays.fill(deps, 0, size, null);
+ lowDep = -1;
+ size = 0;
+ }
+
+ /**
+ * Returns number of handles registered in table.
+ */
+ int size() {
+ return size;
+ }
+
+ /**
+ * Expands capacity of internal arrays.
+ */
+ private void grow() {
+ int newCapacity = (entries.length << 1) + 1;
+
+ byte[] newStatus = new byte[newCapacity];
+ Object[] newEntries = new Object[newCapacity];
+ HandleList[] newDeps = new HandleList[newCapacity];
+
+ System.arraycopy(status, 0, newStatus, 0, size);
+ System.arraycopy(entries, 0, newEntries, 0, size);
+ System.arraycopy(deps, 0, newDeps, 0, size);
+
+ status = newStatus;
+ entries = newEntries;
+ deps = newDeps;
+ }
+
+ /**
+ * Simple growable list of (integer) handles.
+ */
+ private static class HandleList {
+ private int[] list = new int[4];
+ private int size = 0;
+
+ public HandleList() {
+ }
+
+ public void add(int handle) {
+ if (size >= list.length) {
+ int[] newList = new int[list.length << 1];
+ System.arraycopy(list, 0, newList, 0, list.length);
+ list = newList;
+ }
+ list[size++] = handle;
+ }
+
+ public int get(int index) {
+ if (index >= size) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return list[index];
+ }
+
+ public int size() {
+ return size;
+ }
+ }
+ }
+
+ /**
+ * Method for cloning arrays in case of using unsharing reading
+ */
+ private static Object cloneArray(Object array) {
+ if (array instanceof Object[]) {
+ return ((Object[]) array).clone();
+ } else if (array instanceof boolean[]) {
+ return ((boolean[]) array).clone();
+ } else if (array instanceof byte[]) {
+ return ((byte[]) array).clone();
+ } else if (array instanceof char[]) {
+ return ((char[]) array).clone();
+ } else if (array instanceof double[]) {
+ return ((double[]) array).clone();
+ } else if (array instanceof float[]) {
+ return ((float[]) array).clone();
+ } else if (array instanceof int[]) {
+ return ((int[]) array).clone();
+ } else if (array instanceof long[]) {
+ return ((long[]) array).clone();
+ } else if (array instanceof short[]) {
+ return ((short[]) array).clone();
+ } else {
+ throw new AssertionError();
+ }
+ }
+
+ // Android-removed: Logic related to ObjectStreamClassValidator, unused on Android
+ /*
+ private void validateDescriptor(ObjectStreamClass descriptor) {
+ ObjectStreamClassValidator validating = validator;
+ if (validating != null) {
+ validating.validateDescriptor(descriptor);
+ }
+ }
+
+ // controlled access to ObjectStreamClassValidator
+ private volatile ObjectStreamClassValidator validator;
+
+ private static void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator) {
+ ois.validator = validator;
+ }
+ static {
+ SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::setValidator);
+ }
+ */
+}
diff --git a/java/io/ObjectInputValidation.java b/java/io/ObjectInputValidation.java
new file mode 100644
index 0000000..dc6f842
--- /dev/null
+++ b/java/io/ObjectInputValidation.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Callback interface to allow validation of objects within a graph.
+ * Allows an object to be called when a complete graph of objects has
+ * been deserialized.
+ *
+ * @author unascribed
+ * @see ObjectInputStream
+ * @see ObjectInputStream#registerValidation(java.io.ObjectInputValidation, int)
+ * @since JDK1.1
+ */
+public interface ObjectInputValidation {
+ /**
+ * Validates the object.
+ *
+ * @exception InvalidObjectException If the object cannot validate itself.
+ */
+ public void validateObject() throws InvalidObjectException;
+}
diff --git a/java/io/ObjectOutput.java b/java/io/ObjectOutput.java
new file mode 100644
index 0000000..7c2cbeb
--- /dev/null
+++ b/java/io/ObjectOutput.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * ObjectOutput extends the DataOutput interface to include writing of objects.
+ * DataOutput includes methods for output of primitive types, ObjectOutput
+ * extends that interface to include objects, arrays, and Strings.
+ *
+ * @author unascribed
+ * @see java.io.InputStream
+ * @see java.io.ObjectOutputStream
+ * @see java.io.ObjectInputStream
+ * @since JDK1.1
+ */
+public interface ObjectOutput extends DataOutput, AutoCloseable {
+ /**
+ * Write an object to the underlying storage or stream. The
+ * class that implements this interface defines how the object is
+ * written.
+ *
+ * @param obj the object to be written
+ * @exception IOException Any of the usual Input/Output related exceptions.
+ */
+ public void writeObject(Object obj)
+ throws IOException;
+
+ /**
+ * Writes a byte. This method will block until the byte is actually
+ * written.
+ * @param b the byte
+ * @exception IOException If an I/O error has occurred.
+ */
+ public void write(int b) throws IOException;
+
+ /**
+ * Writes an array of bytes. This method will block until the bytes
+ * are actually written.
+ * @param b the data to be written
+ * @exception IOException If an I/O error has occurred.
+ */
+ public void write(byte b[]) throws IOException;
+
+ /**
+ * Writes a sub array of bytes.
+ * @param b the data to be written
+ * @param off the start offset in the data
+ * @param len the number of bytes that are written
+ * @exception IOException If an I/O error has occurred.
+ */
+ public void write(byte b[], int off, int len) throws IOException;
+
+ /**
+ * Flushes the stream. This will write any buffered
+ * output bytes.
+ * @exception IOException If an I/O error has occurred.
+ */
+ public void flush() throws IOException;
+
+ /**
+ * Closes the stream. This method must be called
+ * to release any resources associated with the
+ * stream.
+ * @exception IOException If an I/O error has occurred.
+ */
+ public void close() throws IOException;
+}
diff --git a/java/io/ObjectOutputStream.java b/java/io/ObjectOutputStream.java
new file mode 100644
index 0000000..1f7f901
--- /dev/null
+++ b/java/io/ObjectOutputStream.java
@@ -0,0 +1,2574 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.ObjectStreamClass.WeakClassKey;
+import java.lang.ref.ReferenceQueue;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import static java.io.ObjectStreamClass.processQueue;
+import java.io.SerialCallbackContext;
+import sun.reflect.misc.ReflectUtil;
+
+/**
+ * An ObjectOutputStream writes primitive data types and graphs of Java objects
+ * to an OutputStream. The objects can be read (reconstituted) using an
+ * ObjectInputStream. Persistent storage of objects can be accomplished by
+ * using a file for the stream. If the stream is a network socket stream, the
+ * objects can be reconstituted on another host or in another process.
+ *
+ * <p>Only objects that support the java.io.Serializable interface can be
+ * written to streams. The class of each serializable object is encoded
+ * including the class name and signature of the class, the values of the
+ * object's fields and arrays, and the closure of any other objects referenced
+ * from the initial objects.
+ *
+ * <p>The method writeObject is used to write an object to the stream. Any
+ * object, including Strings and arrays, is written with writeObject. Multiple
+ * objects or primitives can be written to the stream. The objects must be
+ * read back from the corresponding ObjectInputstream with the same types and
+ * in the same order as they were written.
+ *
+ * <p>Primitive data types can also be written to the stream using the
+ * appropriate methods from DataOutput. Strings can also be written using the
+ * writeUTF method.
+ *
+ * <p>The default serialization mechanism for an object writes the class of the
+ * object, the class signature, and the values of all non-transient and
+ * non-static fields. References to other objects (except in transient or
+ * static fields) cause those objects to be written also. Multiple references
+ * to a single object are encoded using a reference sharing mechanism so that
+ * graphs of objects can be restored to the same shape as when the original was
+ * written.
+ *
+ * <p>For example to write an object that can be read by the example in
+ * ObjectInputStream:
+ * <br>
+ * <pre>
+ * FileOutputStream fos = new FileOutputStream("t.tmp");
+ * ObjectOutputStream oos = new ObjectOutputStream(fos);
+ *
+ * oos.writeInt(12345);
+ * oos.writeObject("Today");
+ * oos.writeObject(new Date());
+ *
+ * oos.close();
+ * </pre>
+ *
+ * <p>Classes that require special handling during the serialization and
+ * deserialization process must implement special methods with these exact
+ * signatures:
+ * <br>
+ * <pre>
+ * private void readObject(java.io.ObjectInputStream stream)
+ * throws IOException, ClassNotFoundException;
+ * private void writeObject(java.io.ObjectOutputStream stream)
+ * throws IOException
+ * private void readObjectNoData()
+ * throws ObjectStreamException;
+ * </pre>
+ *
+ * <p>The writeObject method is responsible for writing the state of the object
+ * for its particular class so that the corresponding readObject method can
+ * restore it. The method does not need to concern itself with the state
+ * belonging to the object's superclasses or subclasses. State is saved by
+ * writing the individual fields to the ObjectOutputStream using the
+ * writeObject method or by using the methods for primitive data types
+ * supported by DataOutput.
+ *
+ * <p>Serialization does not write out the fields of any object that does not
+ * implement the java.io.Serializable interface. Subclasses of Objects that
+ * are not serializable can be serializable. In this case the non-serializable
+ * class must have a no-arg constructor to allow its fields to be initialized.
+ * In this case it is the responsibility of the subclass to save and restore
+ * the state of the non-serializable class. It is frequently the case that the
+ * fields of that class are accessible (public, package, or protected) or that
+ * there are get and set methods that can be used to restore the state.
+ *
+ * <p>Serialization of an object can be prevented by implementing writeObject
+ * and readObject methods that throw the NotSerializableException. The
+ * exception will be caught by the ObjectOutputStream and abort the
+ * serialization process.
+ *
+ * <p>Implementing the Externalizable interface allows the object to assume
+ * complete control over the contents and format of the object's serialized
+ * form. The methods of the Externalizable interface, writeExternal and
+ * readExternal, are called to save and restore the objects state. When
+ * implemented by a class they can write and read their own state using all of
+ * the methods of ObjectOutput and ObjectInput. It is the responsibility of
+ * the objects to handle any versioning that occurs.
+ *
+ * <p>Enum constants are serialized differently than ordinary serializable or
+ * externalizable objects. The serialized form of an enum constant consists
+ * solely of its name; field values of the constant are not transmitted. To
+ * serialize an enum constant, ObjectOutputStream writes the string returned by
+ * the constant's name method. Like other serializable or externalizable
+ * objects, enum constants can function as the targets of back references
+ * appearing subsequently in the serialization stream. The process by which
+ * enum constants are serialized cannot be customized; any class-specific
+ * writeObject and writeReplace methods defined by enum types are ignored
+ * during serialization. Similarly, any serialPersistentFields or
+ * serialVersionUID field declarations are also ignored--all enum types have a
+ * fixed serialVersionUID of 0L.
+ *
+ * <p>Primitive data, excluding serializable fields and externalizable data, is
+ * written to the ObjectOutputStream in block-data records. A block data record
+ * is composed of a header and data. The block data header consists of a marker
+ * and the number of bytes to follow the header. Consecutive primitive data
+ * writes are merged into one block-data record. The blocking factor used for
+ * a block-data record will be 1024 bytes. Each block-data record will be
+ * filled up to 1024 bytes, or be written whenever there is a termination of
+ * block-data mode. Calls to the ObjectOutputStream methods writeObject,
+ * defaultWriteObject and writeFields initially terminate any existing
+ * block-data record.
+ *
+ * @author Mike Warres
+ * @author Roger Riggs
+ * @see java.io.DataOutput
+ * @see java.io.ObjectInputStream
+ * @see java.io.Serializable
+ * @see java.io.Externalizable
+ * @see <a href="../../../platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a>
+ * @since JDK1.1
+ */
+public class ObjectOutputStream
+ extends OutputStream implements ObjectOutput, ObjectStreamConstants
+{
+
+ private static class Caches {
+ /** cache of subclass security audit results */
+ static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
+ new ConcurrentHashMap<>();
+
+ /** queue for WeakReferences to audited subclasses */
+ static final ReferenceQueue<Class<?>> subclassAuditsQueue =
+ new ReferenceQueue<>();
+ }
+
+ /** filter stream for handling block data conversion */
+ private final BlockDataOutputStream bout;
+ /** obj -> wire handle map */
+ private final HandleTable handles;
+ /** obj -> replacement obj map */
+ private final ReplaceTable subs;
+ /** stream protocol version */
+ private int protocol = PROTOCOL_VERSION_2;
+ /** recursion depth */
+ private int depth;
+
+ /** buffer for writing primitive field values */
+ private byte[] primVals;
+
+ /** if true, invoke writeObjectOverride() instead of writeObject() */
+ private final boolean enableOverride;
+ /** if true, invoke replaceObject() */
+ private boolean enableReplace;
+
+ // values below valid only during upcalls to writeObject()/writeExternal()
+ /**
+ * Context during upcalls to class-defined writeObject methods; holds
+ * object currently being serialized and descriptor for current class.
+ * Null when not during writeObject upcall.
+ */
+ private SerialCallbackContext curContext;
+ /** current PutField object */
+ private PutFieldImpl curPut;
+
+ /** custom storage for debug trace info */
+ private final DebugTraceInfoStack debugInfoStack;
+
+ /**
+ * value of "sun.io.serialization.extendedDebugInfo" property,
+ * as true or false for extended information about exception's place
+ */
+ // BEGIN Android-changed: Do not support extendedDebugInfo on Android.
+ /*
+ private static final boolean extendedDebugInfo =
+ java.security.AccessController.doPrivileged(
+ new sun.security.action.GetBooleanAction(
+ "sun.io.serialization.extendedDebugInfo")).booleanValue();
+ */
+ private static final boolean extendedDebugInfo = false;
+ // END Android-changed: Do not support extendedDebugInfo on Android.
+
+ /**
+ * Creates an ObjectOutputStream that writes to the specified OutputStream.
+ * This constructor writes the serialization stream header to the
+ * underlying stream; callers may wish to flush the stream immediately to
+ * ensure that constructors for receiving ObjectInputStreams will not block
+ * when reading the header.
+ *
+ * <p>If a security manager is installed, this constructor will check for
+ * the "enableSubclassImplementation" SerializablePermission when invoked
+ * directly or indirectly by the constructor of a subclass which overrides
+ * the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared
+ * methods.
+ *
+ * @param out output stream to write to
+ * @throws IOException if an I/O error occurs while writing stream header
+ * @throws SecurityException if untrusted subclass illegally overrides
+ * security-sensitive methods
+ * @throws NullPointerException if <code>out</code> is <code>null</code>
+ * @since 1.4
+ * @see ObjectOutputStream#ObjectOutputStream()
+ * @see ObjectOutputStream#putFields()
+ * @see ObjectInputStream#ObjectInputStream(InputStream)
+ */
+ public ObjectOutputStream(OutputStream out) throws IOException {
+ verifySubclass();
+ bout = new BlockDataOutputStream(out);
+ handles = new HandleTable(10, (float) 3.00);
+ subs = new ReplaceTable(10, (float) 3.00);
+ enableOverride = false;
+ writeStreamHeader();
+ bout.setBlockDataMode(true);
+ if (extendedDebugInfo) {
+ debugInfoStack = new DebugTraceInfoStack();
+ } else {
+ debugInfoStack = null;
+ }
+ }
+
+ /**
+ * Provide a way for subclasses that are completely reimplementing
+ * ObjectOutputStream to not have to allocate private data just used by
+ * this implementation of ObjectOutputStream.
+ *
+ * <p>If there is a security manager installed, this method first calls the
+ * security manager's <code>checkPermission</code> method with a
+ * <code>SerializablePermission("enableSubclassImplementation")</code>
+ * permission to ensure it's ok to enable subclassing.
+ *
+ * @throws SecurityException if a security manager exists and its
+ * <code>checkPermission</code> method denies enabling
+ * subclassing.
+ * @throws IOException if an I/O error occurs while creating this stream
+ * @see SecurityManager#checkPermission
+ * @see java.io.SerializablePermission
+ */
+ protected ObjectOutputStream() throws IOException, SecurityException {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
+ }
+ bout = null;
+ handles = null;
+ subs = null;
+ enableOverride = true;
+ debugInfoStack = null;
+ }
+
+ /**
+ * Specify stream protocol version to use when writing the stream.
+ *
+ * <p>This routine provides a hook to enable the current version of
+ * Serialization to write in a format that is backwards compatible to a
+ * previous version of the stream format.
+ *
+ * <p>Every effort will be made to avoid introducing additional
+ * backwards incompatibilities; however, sometimes there is no
+ * other alternative.
+ *
+ * @param version use ProtocolVersion from java.io.ObjectStreamConstants.
+ * @throws IllegalStateException if called after any objects
+ * have been serialized.
+ * @throws IllegalArgumentException if invalid version is passed in.
+ * @throws IOException if I/O errors occur
+ * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
+ * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2
+ * @since 1.2
+ */
+ public void useProtocolVersion(int version) throws IOException {
+ if (handles.size() != 0) {
+ // REMIND: implement better check for pristine stream?
+ throw new IllegalStateException("stream non-empty");
+ }
+ switch (version) {
+ case PROTOCOL_VERSION_1:
+ case PROTOCOL_VERSION_2:
+ protocol = version;
+ break;
+
+ default:
+ throw new IllegalArgumentException(
+ "unknown version: " + version);
+ }
+ }
+
+ /**
+ * Write the specified object to the ObjectOutputStream. The class of the
+ * object, the signature of the class, and the values of the non-transient
+ * and non-static fields of the class and all of its supertypes are
+ * written. Default serialization for a class can be overridden using the
+ * writeObject and the readObject methods. Objects referenced by this
+ * object are written transitively so that a complete equivalent graph of
+ * objects can be reconstructed by an ObjectInputStream.
+ *
+ * <p>Exceptions are thrown for problems with the OutputStream and for
+ * classes that should not be serialized. All exceptions are fatal to the
+ * OutputStream, which is left in an indeterminate state, and it is up to
+ * the caller to ignore or recover the stream state.
+ *
+ * @throws InvalidClassException Something is wrong with a class used by
+ * serialization.
+ * @throws NotSerializableException Some object to be serialized does not
+ * implement the java.io.Serializable interface.
+ * @throws IOException Any exception thrown by the underlying
+ * OutputStream.
+ */
+ public final void writeObject(Object obj) throws IOException {
+ if (enableOverride) {
+ writeObjectOverride(obj);
+ return;
+ }
+ try {
+ writeObject0(obj, false);
+ } catch (IOException ex) {
+ if (depth == 0) {
+ // BEGIN Android-changed: Ignore secondary exceptions during writeObject().
+ // writeFatalException(ex);
+ try {
+ writeFatalException(ex);
+
+ } catch (IOException ex2) {
+ // If writing the exception to the output stream causes another exception there
+ // is no need to propagate the second exception or generate a third exception,
+ // both of which might obscure details of the root cause.
+ }
+ // END Android-changed: Ignore secondary exceptions during writeObject().
+ }
+ throw ex;
+ }
+ }
+
+ /**
+ * Method used by subclasses to override the default writeObject method.
+ * This method is called by trusted subclasses of ObjectInputStream that
+ * constructed ObjectInputStream using the protected no-arg constructor.
+ * The subclass is expected to provide an override method with the modifier
+ * "final".
+ *
+ * @param obj object to be written to the underlying stream
+ * @throws IOException if there are I/O errors while writing to the
+ * underlying stream
+ * @see #ObjectOutputStream()
+ * @see #writeObject(Object)
+ * @since 1.2
+ */
+ protected void writeObjectOverride(Object obj) throws IOException {
+ // BEGIN Android-added: Let writeObjectOverride throw IOException if !enableOverride.
+ if (!enableOverride) {
+ // Subclasses must override.
+ throw new IOException();
+ }
+ // END Android-added: Let writeObjectOverride throw IOException if !enableOverride.
+ }
+
+ /**
+ * Writes an "unshared" object to the ObjectOutputStream. This method is
+ * identical to writeObject, except that it always writes the given object
+ * as a new, unique object in the stream (as opposed to a back-reference
+ * pointing to a previously serialized instance). Specifically:
+ * <ul>
+ * <li>An object written via writeUnshared is always serialized in the
+ * same manner as a newly appearing object (an object that has not
+ * been written to the stream yet), regardless of whether or not the
+ * object has been written previously.
+ *
+ * <li>If writeObject is used to write an object that has been previously
+ * written with writeUnshared, the previous writeUnshared operation
+ * is treated as if it were a write of a separate object. In other
+ * words, ObjectOutputStream will never generate back-references to
+ * object data written by calls to writeUnshared.
+ * </ul>
+ * While writing an object via writeUnshared does not in itself guarantee a
+ * unique reference to the object when it is deserialized, it allows a
+ * single object to be defined multiple times in a stream, so that multiple
+ * calls to readUnshared by the receiver will not conflict. Note that the
+ * rules described above only apply to the base-level object written with
+ * writeUnshared, and not to any transitively referenced sub-objects in the
+ * object graph to be serialized.
+ *
+ * <p>ObjectOutputStream subclasses which override this method can only be
+ * constructed in security contexts possessing the
+ * "enableSubclassImplementation" SerializablePermission; any attempt to
+ * instantiate such a subclass without this permission will cause a
+ * SecurityException to be thrown.
+ *
+ * @param obj object to write to stream
+ * @throws NotSerializableException if an object in the graph to be
+ * serialized does not implement the Serializable interface
+ * @throws InvalidClassException if a problem exists with the class of an
+ * object to be serialized
+ * @throws IOException if an I/O error occurs during serialization
+ * @since 1.4
+ */
+ public void writeUnshared(Object obj) throws IOException {
+ try {
+ writeObject0(obj, true);
+ } catch (IOException ex) {
+ if (depth == 0) {
+ writeFatalException(ex);
+ }
+ throw ex;
+ }
+ }
+
+ /**
+ * Write the non-static and non-transient fields of the current class to
+ * this stream. This may only be called from the writeObject method of the
+ * class being serialized. It will throw the NotActiveException if it is
+ * called otherwise.
+ *
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * <code>OutputStream</code>
+ */
+ public void defaultWriteObject() throws IOException {
+ SerialCallbackContext ctx = curContext;
+ if (ctx == null) {
+ throw new NotActiveException("not in call to writeObject");
+ }
+ Object curObj = ctx.getObj();
+ ObjectStreamClass curDesc = ctx.getDesc();
+ bout.setBlockDataMode(false);
+ defaultWriteFields(curObj, curDesc);
+ bout.setBlockDataMode(true);
+ }
+
+ /**
+ * Retrieve the object used to buffer persistent fields to be written to
+ * the stream. The fields will be written to the stream when writeFields
+ * method is called.
+ *
+ * @return an instance of the class Putfield that holds the serializable
+ * fields
+ * @throws IOException if I/O errors occur
+ * @since 1.2
+ */
+ public ObjectOutputStream.PutField putFields() throws IOException {
+ if (curPut == null) {
+ SerialCallbackContext ctx = curContext;
+ if (ctx == null) {
+ throw new NotActiveException("not in call to writeObject");
+ }
+ Object curObj = ctx.getObj();
+ ObjectStreamClass curDesc = ctx.getDesc();
+ curPut = new PutFieldImpl(curDesc);
+ }
+ return curPut;
+ }
+
+ /**
+ * Write the buffered fields to the stream.
+ *
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ * @throws NotActiveException Called when a classes writeObject method was
+ * not called to write the state of the object.
+ * @since 1.2
+ */
+ public void writeFields() throws IOException {
+ if (curPut == null) {
+ throw new NotActiveException("no current PutField object");
+ }
+ bout.setBlockDataMode(false);
+ curPut.writeFields();
+ bout.setBlockDataMode(true);
+ }
+
+ /**
+ * Reset will disregard the state of any objects already written to the
+ * stream. The state is reset to be the same as a new ObjectOutputStream.
+ * The current point in the stream is marked as reset so the corresponding
+ * ObjectInputStream will be reset at the same point. Objects previously
+ * written to the stream will not be referred to as already being in the
+ * stream. They will be written to the stream again.
+ *
+ * @throws IOException if reset() is invoked while serializing an object.
+ */
+ public void reset() throws IOException {
+ if (depth != 0) {
+ throw new IOException("stream active");
+ }
+ bout.setBlockDataMode(false);
+ bout.writeByte(TC_RESET);
+ clear();
+ bout.setBlockDataMode(true);
+ }
+
+ /**
+ * Subclasses may implement this method to allow class data to be stored in
+ * the stream. By default this method does nothing. The corresponding
+ * method in ObjectInputStream is resolveClass. This method is called
+ * exactly once for each unique class in the stream. The class name and
+ * signature will have already been written to the stream. This method may
+ * make free use of the ObjectOutputStream to save any representation of
+ * the class it deems suitable (for example, the bytes of the class file).
+ * The resolveClass method in the corresponding subclass of
+ * ObjectInputStream must read and use any data or objects written by
+ * annotateClass.
+ *
+ * @param cl the class to annotate custom data for
+ * @throws IOException Any exception thrown by the underlying
+ * OutputStream.
+ */
+ protected void annotateClass(Class<?> cl) throws IOException {
+ }
+
+ /**
+ * Subclasses may implement this method to store custom data in the stream
+ * along with descriptors for dynamic proxy classes.
+ *
+ * <p>This method is called exactly once for each unique proxy class
+ * descriptor in the stream. The default implementation of this method in
+ * <code>ObjectOutputStream</code> does nothing.
+ *
+ * <p>The corresponding method in <code>ObjectInputStream</code> is
+ * <code>resolveProxyClass</code>. For a given subclass of
+ * <code>ObjectOutputStream</code> that overrides this method, the
+ * <code>resolveProxyClass</code> method in the corresponding subclass of
+ * <code>ObjectInputStream</code> must read any data or objects written by
+ * <code>annotateProxyClass</code>.
+ *
+ * @param cl the proxy class to annotate custom data for
+ * @throws IOException any exception thrown by the underlying
+ * <code>OutputStream</code>
+ * @see ObjectInputStream#resolveProxyClass(String[])
+ * @since 1.3
+ */
+ protected void annotateProxyClass(Class<?> cl) throws IOException {
+ }
+
+ /**
+ * This method will allow trusted subclasses of ObjectOutputStream to
+ * substitute one object for another during serialization. Replacing
+ * objects is disabled until enableReplaceObject is called. The
+ * enableReplaceObject method checks that the stream requesting to do
+ * replacement can be trusted. The first occurrence of each object written
+ * into the serialization stream is passed to replaceObject. Subsequent
+ * references to the object are replaced by the object returned by the
+ * original call to replaceObject. To ensure that the private state of
+ * objects is not unintentionally exposed, only trusted streams may use
+ * replaceObject.
+ *
+ * <p>The ObjectOutputStream.writeObject method takes a parameter of type
+ * Object (as opposed to type Serializable) to allow for cases where
+ * non-serializable objects are replaced by serializable ones.
+ *
+ * <p>When a subclass is replacing objects it must insure that either a
+ * complementary substitution must be made during deserialization or that
+ * the substituted object is compatible with every field where the
+ * reference will be stored. Objects whose type is not a subclass of the
+ * type of the field or array element abort the serialization by raising an
+ * exception and the object is not be stored.
+ *
+ * <p>This method is called only once when each object is first
+ * encountered. All subsequent references to the object will be redirected
+ * to the new object. This method should return the object to be
+ * substituted or the original object.
+ *
+ * <p>Null can be returned as the object to be substituted, but may cause
+ * NullReferenceException in classes that contain references to the
+ * original object since they may be expecting an object instead of
+ * null.
+ *
+ * @param obj the object to be replaced
+ * @return the alternate object that replaced the specified one
+ * @throws IOException Any exception thrown by the underlying
+ * OutputStream.
+ */
+ protected Object replaceObject(Object obj) throws IOException {
+ return obj;
+ }
+
+ /**
+ * Enable the stream to do replacement of objects in the stream. When
+ * enabled, the replaceObject method is called for every object being
+ * serialized.
+ *
+ * <p>If <code>enable</code> is true, and there is a security manager
+ * installed, this method first calls the security manager's
+ * <code>checkPermission</code> method with a
+ * <code>SerializablePermission("enableSubstitution")</code> permission to
+ * ensure it's ok to enable the stream to do replacement of objects in the
+ * stream.
+ *
+ * @param enable boolean parameter to enable replacement of objects
+ * @return the previous setting before this method was invoked
+ * @throws SecurityException if a security manager exists and its
+ * <code>checkPermission</code> method denies enabling the stream
+ * to do replacement of objects in the stream.
+ * @see SecurityManager#checkPermission
+ * @see java.io.SerializablePermission
+ */
+ protected boolean enableReplaceObject(boolean enable)
+ throws SecurityException
+ {
+ if (enable == enableReplace) {
+ return enable;
+ }
+ if (enable) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(SUBSTITUTION_PERMISSION);
+ }
+ }
+ enableReplace = enable;
+ return !enableReplace;
+ }
+
+ /**
+ * The writeStreamHeader method is provided so subclasses can append or
+ * prepend their own header to the stream. It writes the magic number and
+ * version to the stream.
+ *
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ protected void writeStreamHeader() throws IOException {
+ bout.writeShort(STREAM_MAGIC);
+ bout.writeShort(STREAM_VERSION);
+ }
+
+ /**
+ * Write the specified class descriptor to the ObjectOutputStream. Class
+ * descriptors are used to identify the classes of objects written to the
+ * stream. Subclasses of ObjectOutputStream may override this method to
+ * customize the way in which class descriptors are written to the
+ * serialization stream. The corresponding method in ObjectInputStream,
+ * <code>readClassDescriptor</code>, should then be overridden to
+ * reconstitute the class descriptor from its custom stream representation.
+ * By default, this method writes class descriptors according to the format
+ * defined in the Object Serialization specification.
+ *
+ * <p>Note that this method will only be called if the ObjectOutputStream
+ * is not using the old serialization stream format (set by calling
+ * ObjectOutputStream's <code>useProtocolVersion</code> method). If this
+ * serialization stream is using the old format
+ * (<code>PROTOCOL_VERSION_1</code>), the class descriptor will be written
+ * internally in a manner that cannot be overridden or customized.
+ *
+ * @param desc class descriptor to write to the stream
+ * @throws IOException If an I/O error has occurred.
+ * @see java.io.ObjectInputStream#readClassDescriptor()
+ * @see #useProtocolVersion(int)
+ * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
+ * @since 1.3
+ */
+ protected void writeClassDescriptor(ObjectStreamClass desc)
+ throws IOException
+ {
+ desc.writeNonProxy(this);
+ }
+
+ /**
+ * Writes a byte. This method will block until the byte is actually
+ * written.
+ *
+ * @param val the byte to be written to the stream
+ * @throws IOException If an I/O error has occurred.
+ */
+ public void write(int val) throws IOException {
+ bout.write(val);
+ }
+
+ /**
+ * Writes an array of bytes. This method will block until the bytes are
+ * actually written.
+ *
+ * @param buf the data to be written
+ * @throws IOException If an I/O error has occurred.
+ */
+ public void write(byte[] buf) throws IOException {
+ bout.write(buf, 0, buf.length, false);
+ }
+
+ /**
+ * Writes a sub array of bytes.
+ *
+ * @param buf the data to be written
+ * @param off the start offset in the data
+ * @param len the number of bytes that are written
+ * @throws IOException If an I/O error has occurred.
+ */
+ public void write(byte[] buf, int off, int len) throws IOException {
+ if (buf == null) {
+ throw new NullPointerException();
+ }
+ int endoff = off + len;
+ if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ bout.write(buf, off, len, false);
+ }
+
+ /**
+ * Flushes the stream. This will write any buffered output bytes and flush
+ * through to the underlying stream.
+ *
+ * @throws IOException If an I/O error has occurred.
+ */
+ public void flush() throws IOException {
+ bout.flush();
+ }
+
+ /**
+ * Drain any buffered data in ObjectOutputStream. Similar to flush but
+ * does not propagate the flush to the underlying stream.
+ *
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ protected void drain() throws IOException {
+ bout.drain();
+ }
+
+ /**
+ * Closes the stream. This method must be called to release any resources
+ * associated with the stream.
+ *
+ * @throws IOException If an I/O error has occurred.
+ */
+ public void close() throws IOException {
+ flush();
+ // Android-removed: Don't clear() during close(), keep the handle table. http://b/28159133
+ // clear();
+ bout.close();
+ }
+
+ /**
+ * Writes a boolean.
+ *
+ * @param val the boolean to be written
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ public void writeBoolean(boolean val) throws IOException {
+ bout.writeBoolean(val);
+ }
+
+ /**
+ * Writes an 8 bit byte.
+ *
+ * @param val the byte value to be written
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ public void writeByte(int val) throws IOException {
+ bout.writeByte(val);
+ }
+
+ /**
+ * Writes a 16 bit short.
+ *
+ * @param val the short value to be written
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ public void writeShort(int val) throws IOException {
+ bout.writeShort(val);
+ }
+
+ /**
+ * Writes a 16 bit char.
+ *
+ * @param val the char value to be written
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ public void writeChar(int val) throws IOException {
+ bout.writeChar(val);
+ }
+
+ /**
+ * Writes a 32 bit int.
+ *
+ * @param val the integer value to be written
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ public void writeInt(int val) throws IOException {
+ bout.writeInt(val);
+ }
+
+ /**
+ * Writes a 64 bit long.
+ *
+ * @param val the long value to be written
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ public void writeLong(long val) throws IOException {
+ bout.writeLong(val);
+ }
+
+ /**
+ * Writes a 32 bit float.
+ *
+ * @param val the float value to be written
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ public void writeFloat(float val) throws IOException {
+ bout.writeFloat(val);
+ }
+
+ /**
+ * Writes a 64 bit double.
+ *
+ * @param val the double value to be written
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ public void writeDouble(double val) throws IOException {
+ bout.writeDouble(val);
+ }
+
+ /**
+ * Writes a String as a sequence of bytes.
+ *
+ * @param str the String of bytes to be written
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ public void writeBytes(String str) throws IOException {
+ bout.writeBytes(str);
+ }
+
+ /**
+ * Writes a String as a sequence of chars.
+ *
+ * @param str the String of chars to be written
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ public void writeChars(String str) throws IOException {
+ bout.writeChars(str);
+ }
+
+ /**
+ * Primitive data write of this String in
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+ * format. Note that there is a
+ * significant difference between writing a String into the stream as
+ * primitive data or as an Object. A String instance written by writeObject
+ * is written into the stream as a String initially. Future writeObject()
+ * calls write references to the string into the stream.
+ *
+ * @param str the String to be written
+ * @throws IOException if I/O errors occur while writing to the underlying
+ * stream
+ */
+ public void writeUTF(String str) throws IOException {
+ bout.writeUTF(str);
+ }
+
+ /**
+ * Provide programmatic access to the persistent fields to be written
+ * to ObjectOutput.
+ *
+ * @since 1.2
+ */
+ public static abstract class PutField {
+
+ /**
+ * Put the value of the named boolean field into the persistent field.
+ *
+ * @param name the name of the serializable field
+ * @param val the value to assign to the field
+ * @throws IllegalArgumentException if <code>name</code> does not
+ * match the name of a serializable field for the class whose fields
+ * are being written, or if the type of the named field is not
+ * <code>boolean</code>
+ */
+ public abstract void put(String name, boolean val);
+
+ /**
+ * Put the value of the named byte field into the persistent field.
+ *
+ * @param name the name of the serializable field
+ * @param val the value to assign to the field
+ * @throws IllegalArgumentException if <code>name</code> does not
+ * match the name of a serializable field for the class whose fields
+ * are being written, or if the type of the named field is not
+ * <code>byte</code>
+ */
+ public abstract void put(String name, byte val);
+
+ /**
+ * Put the value of the named char field into the persistent field.
+ *
+ * @param name the name of the serializable field
+ * @param val the value to assign to the field
+ * @throws IllegalArgumentException if <code>name</code> does not
+ * match the name of a serializable field for the class whose fields
+ * are being written, or if the type of the named field is not
+ * <code>char</code>
+ */
+ public abstract void put(String name, char val);
+
+ /**
+ * Put the value of the named short field into the persistent field.
+ *
+ * @param name the name of the serializable field
+ * @param val the value to assign to the field
+ * @throws IllegalArgumentException if <code>name</code> does not
+ * match the name of a serializable field for the class whose fields
+ * are being written, or if the type of the named field is not
+ * <code>short</code>
+ */
+ public abstract void put(String name, short val);
+
+ /**
+ * Put the value of the named int field into the persistent field.
+ *
+ * @param name the name of the serializable field
+ * @param val the value to assign to the field
+ * @throws IllegalArgumentException if <code>name</code> does not
+ * match the name of a serializable field for the class whose fields
+ * are being written, or if the type of the named field is not
+ * <code>int</code>
+ */
+ public abstract void put(String name, int val);
+
+ /**
+ * Put the value of the named long field into the persistent field.
+ *
+ * @param name the name of the serializable field
+ * @param val the value to assign to the field
+ * @throws IllegalArgumentException if <code>name</code> does not
+ * match the name of a serializable field for the class whose fields
+ * are being written, or if the type of the named field is not
+ * <code>long</code>
+ */
+ public abstract void put(String name, long val);
+
+ /**
+ * Put the value of the named float field into the persistent field.
+ *
+ * @param name the name of the serializable field
+ * @param val the value to assign to the field
+ * @throws IllegalArgumentException if <code>name</code> does not
+ * match the name of a serializable field for the class whose fields
+ * are being written, or if the type of the named field is not
+ * <code>float</code>
+ */
+ public abstract void put(String name, float val);
+
+ /**
+ * Put the value of the named double field into the persistent field.
+ *
+ * @param name the name of the serializable field
+ * @param val the value to assign to the field
+ * @throws IllegalArgumentException if <code>name</code> does not
+ * match the name of a serializable field for the class whose fields
+ * are being written, or if the type of the named field is not
+ * <code>double</code>
+ */
+ public abstract void put(String name, double val);
+
+ /**
+ * Put the value of the named Object field into the persistent field.
+ *
+ * @param name the name of the serializable field
+ * @param val the value to assign to the field
+ * (which may be <code>null</code>)
+ * @throws IllegalArgumentException if <code>name</code> does not
+ * match the name of a serializable field for the class whose fields
+ * are being written, or if the type of the named field is not a
+ * reference type
+ */
+ public abstract void put(String name, Object val);
+
+ /**
+ * Write the data and fields to the specified ObjectOutput stream,
+ * which must be the same stream that produced this
+ * <code>PutField</code> object.
+ *
+ * @param out the stream to write the data and fields to
+ * @throws IOException if I/O errors occur while writing to the
+ * underlying stream
+ * @throws IllegalArgumentException if the specified stream is not
+ * the same stream that produced this <code>PutField</code>
+ * object
+ * @deprecated This method does not write the values contained by this
+ * <code>PutField</code> object in a proper format, and may
+ * result in corruption of the serialization stream. The
+ * correct way to write <code>PutField</code> data is by
+ * calling the {@link java.io.ObjectOutputStream#writeFields()}
+ * method.
+ */
+ @Deprecated
+ public abstract void write(ObjectOutput out) throws IOException;
+ }
+
+
+ /**
+ * Returns protocol version in use.
+ */
+ int getProtocolVersion() {
+ return protocol;
+ }
+
+ /**
+ * Writes string without allowing it to be replaced in stream. Used by
+ * ObjectStreamClass to write class descriptor type strings.
+ */
+ void writeTypeString(String str) throws IOException {
+ int handle;
+ if (str == null) {
+ writeNull();
+ } else if ((handle = handles.lookup(str)) != -1) {
+ writeHandle(handle);
+ } else {
+ writeString(str, false);
+ }
+ }
+
+ /**
+ * Verifies that this (possibly subclass) instance can be constructed
+ * without violating security constraints: the subclass must not override
+ * security-sensitive non-final methods, or else the
+ * "enableSubclassImplementation" SerializablePermission is checked.
+ */
+ private void verifySubclass() {
+ Class<?> cl = getClass();
+ if (cl == ObjectOutputStream.class) {
+ return;
+ }
+ SecurityManager sm = System.getSecurityManager();
+ if (sm == null) {
+ return;
+ }
+ processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
+ WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
+ Boolean result = Caches.subclassAudits.get(key);
+ if (result == null) {
+ result = Boolean.valueOf(auditSubclass(cl));
+ Caches.subclassAudits.putIfAbsent(key, result);
+ }
+ if (result.booleanValue()) {
+ return;
+ }
+ sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
+ }
+
+ /**
+ * Performs reflective checks on given subclass to verify that it doesn't
+ * override security-sensitive non-final methods. Returns true if subclass
+ * is "safe", false otherwise.
+ */
+ private static boolean auditSubclass(final Class<?> subcl) {
+ Boolean result = AccessController.doPrivileged(
+ new PrivilegedAction<Boolean>() {
+ public Boolean run() {
+ for (Class<?> cl = subcl;
+ cl != ObjectOutputStream.class;
+ cl = cl.getSuperclass())
+ {
+ try {
+ cl.getDeclaredMethod(
+ "writeUnshared", new Class<?>[] { Object.class });
+ return Boolean.FALSE;
+ } catch (NoSuchMethodException ex) {
+ }
+ try {
+ cl.getDeclaredMethod("putFields", (Class<?>[]) null);
+ return Boolean.FALSE;
+ } catch (NoSuchMethodException ex) {
+ }
+ }
+ return Boolean.TRUE;
+ }
+ }
+ );
+ return result.booleanValue();
+ }
+
+ /**
+ * Clears internal data structures.
+ */
+ private void clear() {
+ subs.clear();
+ handles.clear();
+ }
+
+ /**
+ * Underlying writeObject/writeUnshared implementation.
+ */
+ private void writeObject0(Object obj, boolean unshared)
+ throws IOException
+ {
+ boolean oldMode = bout.setBlockDataMode(false);
+ depth++;
+ try {
+ // handle previously written and non-replaceable objects
+ int h;
+ if ((obj = subs.lookup(obj)) == null) {
+ writeNull();
+ return;
+ } else if (!unshared && (h = handles.lookup(obj)) != -1) {
+ writeHandle(h);
+ return;
+ // BEGIN Android-changed: Make Class and ObjectStreamClass replaceable.
+ /*
+ } else if (obj instanceof Class) {
+ writeClass((Class) obj, unshared);
+ return;
+ } else if (obj instanceof ObjectStreamClass) {
+ writeClassDesc((ObjectStreamClass) obj, unshared);
+ return;
+ */
+ // END Android-changed: Make Class and ObjectStreamClass replaceable.
+ }
+
+ // check for replacement object
+ Object orig = obj;
+ Class<?> cl = obj.getClass();
+ ObjectStreamClass desc;
+
+ // BEGIN Android-changed: Make only one call to writeReplace.
+ /*
+ for (;;) {
+ // REMIND: skip this check for strings/arrays?
+ Class<?> repCl;
+ desc = ObjectStreamClass.lookup(cl, true);
+ if (!desc.hasWriteReplaceMethod() ||
+ (obj = desc.invokeWriteReplace(obj)) == null ||
+ (repCl = obj.getClass()) == cl)
+ {
+ break;
+ }
+ cl = repCl;
+ desc = ObjectStreamClass.lookup(cl, true);
+ break;
+ }
+ */
+ // Do only one replace pass
+
+ Class repCl;
+ desc = ObjectStreamClass.lookup(cl, true);
+ if (desc.hasWriteReplaceMethod() &&
+ (obj = desc.invokeWriteReplace(obj)) != null &&
+ (repCl = obj.getClass()) != cl)
+ {
+ cl = repCl;
+ desc = ObjectStreamClass.lookup(cl, true);
+ }
+ // END Android-changed: Make only one call to writeReplace.
+
+ if (enableReplace) {
+ Object rep = replaceObject(obj);
+ if (rep != obj && rep != null) {
+ cl = rep.getClass();
+ desc = ObjectStreamClass.lookup(cl, true);
+ }
+ obj = rep;
+ }
+
+ // if object replaced, run through original checks a second time
+ if (obj != orig) {
+ subs.assign(orig, obj);
+ if (obj == null) {
+ writeNull();
+ return;
+ } else if (!unshared && (h = handles.lookup(obj)) != -1) {
+ writeHandle(h);
+ return;
+// BEGIN Android-changed: Make Class and ObjectStreamClass replaceable.
+/*
+ } else if (obj instanceof Class) {
+ writeClass((Class) obj, unshared);
+ return;
+ } else if (obj instanceof ObjectStreamClass) {
+ writeClassDesc((ObjectStreamClass) obj, unshared);
+ return;
+*/
+// END Android-changed: Make Class and ObjectStreamClass replaceable.
+ }
+ }
+
+ // remaining cases
+ // BEGIN Android-changed: Make Class and ObjectStreamClass replaceable.
+ if (obj instanceof Class) {
+ writeClass((Class) obj, unshared);
+ } else if (obj instanceof ObjectStreamClass) {
+ writeClassDesc((ObjectStreamClass) obj, unshared);
+ // END Android-changed: Make Class and ObjectStreamClass replaceable.
+ } else if (obj instanceof String) {
+ writeString((String) obj, unshared);
+ } else if (cl.isArray()) {
+ writeArray(obj, desc, unshared);
+ } else if (obj instanceof Enum) {
+ writeEnum((Enum<?>) obj, desc, unshared);
+ } else if (obj instanceof Serializable) {
+ writeOrdinaryObject(obj, desc, unshared);
+ } else {
+ if (extendedDebugInfo) {
+ throw new NotSerializableException(
+ cl.getName() + "\n" + debugInfoStack.toString());
+ } else {
+ throw new NotSerializableException(cl.getName());
+ }
+ }
+ } finally {
+ depth--;
+ bout.setBlockDataMode(oldMode);
+ }
+ }
+
+ /**
+ * Writes null code to stream.
+ */
+ private void writeNull() throws IOException {
+ bout.writeByte(TC_NULL);
+ }
+
+ /**
+ * Writes given object handle to stream.
+ */
+ private void writeHandle(int handle) throws IOException {
+ bout.writeByte(TC_REFERENCE);
+ bout.writeInt(baseWireHandle + handle);
+ }
+
+ /**
+ * Writes representation of given class to stream.
+ */
+ private void writeClass(Class<?> cl, boolean unshared) throws IOException {
+ bout.writeByte(TC_CLASS);
+ writeClassDesc(ObjectStreamClass.lookup(cl, true), false);
+ handles.assign(unshared ? null : cl);
+ }
+
+ /**
+ * Writes representation of given class descriptor to stream.
+ */
+ private void writeClassDesc(ObjectStreamClass desc, boolean unshared)
+ throws IOException
+ {
+ int handle;
+ if (desc == null) {
+ writeNull();
+ } else if (!unshared && (handle = handles.lookup(desc)) != -1) {
+ writeHandle(handle);
+ } else if (desc.isProxy()) {
+ writeProxyDesc(desc, unshared);
+ } else {
+ writeNonProxyDesc(desc, unshared);
+ }
+ }
+
+ private boolean isCustomSubclass() {
+ // Return true if this class is a custom subclass of ObjectOutputStream
+ return getClass().getClassLoader()
+ != ObjectOutputStream.class.getClassLoader();
+ }
+
+ /**
+ * Writes class descriptor representing a dynamic proxy class to stream.
+ */
+ private void writeProxyDesc(ObjectStreamClass desc, boolean unshared)
+ throws IOException
+ {
+ bout.writeByte(TC_PROXYCLASSDESC);
+ handles.assign(unshared ? null : desc);
+
+ Class<?> cl = desc.forClass();
+ Class<?>[] ifaces = cl.getInterfaces();
+ bout.writeInt(ifaces.length);
+ for (int i = 0; i < ifaces.length; i++) {
+ bout.writeUTF(ifaces[i].getName());
+ }
+
+ bout.setBlockDataMode(true);
+ if (cl != null && isCustomSubclass()) {
+ ReflectUtil.checkPackageAccess(cl);
+ }
+ annotateProxyClass(cl);
+ bout.setBlockDataMode(false);
+ bout.writeByte(TC_ENDBLOCKDATA);
+
+ writeClassDesc(desc.getSuperDesc(), false);
+ }
+
+ /**
+ * Writes class descriptor representing a standard (i.e., not a dynamic
+ * proxy) class to stream.
+ */
+ private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
+ throws IOException
+ {
+ bout.writeByte(TC_CLASSDESC);
+ handles.assign(unshared ? null : desc);
+
+ if (protocol == PROTOCOL_VERSION_1) {
+ // do not invoke class descriptor write hook with old protocol
+ desc.writeNonProxy(this);
+ } else {
+ writeClassDescriptor(desc);
+ }
+
+ Class<?> cl = desc.forClass();
+ bout.setBlockDataMode(true);
+ if (cl != null && isCustomSubclass()) {
+ ReflectUtil.checkPackageAccess(cl);
+ }
+ annotateClass(cl);
+ bout.setBlockDataMode(false);
+ bout.writeByte(TC_ENDBLOCKDATA);
+
+ writeClassDesc(desc.getSuperDesc(), false);
+ }
+
+ /**
+ * Writes given string to stream, using standard or long UTF format
+ * depending on string length.
+ */
+ private void writeString(String str, boolean unshared) throws IOException {
+ handles.assign(unshared ? null : str);
+ long utflen = bout.getUTFLength(str);
+ if (utflen <= 0xFFFF) {
+ bout.writeByte(TC_STRING);
+ bout.writeUTF(str, utflen);
+ } else {
+ bout.writeByte(TC_LONGSTRING);
+ bout.writeLongUTF(str, utflen);
+ }
+ }
+
+ /**
+ * Writes given array object to stream.
+ */
+ private void writeArray(Object array,
+ ObjectStreamClass desc,
+ boolean unshared)
+ throws IOException
+ {
+ bout.writeByte(TC_ARRAY);
+ writeClassDesc(desc, false);
+ handles.assign(unshared ? null : array);
+
+ Class<?> ccl = desc.forClass().getComponentType();
+ if (ccl.isPrimitive()) {
+ if (ccl == Integer.TYPE) {
+ int[] ia = (int[]) array;
+ bout.writeInt(ia.length);
+ bout.writeInts(ia, 0, ia.length);
+ } else if (ccl == Byte.TYPE) {
+ byte[] ba = (byte[]) array;
+ bout.writeInt(ba.length);
+ bout.write(ba, 0, ba.length, true);
+ } else if (ccl == Long.TYPE) {
+ long[] ja = (long[]) array;
+ bout.writeInt(ja.length);
+ bout.writeLongs(ja, 0, ja.length);
+ } else if (ccl == Float.TYPE) {
+ float[] fa = (float[]) array;
+ bout.writeInt(fa.length);
+ bout.writeFloats(fa, 0, fa.length);
+ } else if (ccl == Double.TYPE) {
+ double[] da = (double[]) array;
+ bout.writeInt(da.length);
+ bout.writeDoubles(da, 0, da.length);
+ } else if (ccl == Short.TYPE) {
+ short[] sa = (short[]) array;
+ bout.writeInt(sa.length);
+ bout.writeShorts(sa, 0, sa.length);
+ } else if (ccl == Character.TYPE) {
+ char[] ca = (char[]) array;
+ bout.writeInt(ca.length);
+ bout.writeChars(ca, 0, ca.length);
+ } else if (ccl == Boolean.TYPE) {
+ boolean[] za = (boolean[]) array;
+ bout.writeInt(za.length);
+ bout.writeBooleans(za, 0, za.length);
+ } else {
+ throw new InternalError();
+ }
+ } else {
+ Object[] objs = (Object[]) array;
+ int len = objs.length;
+ bout.writeInt(len);
+ if (extendedDebugInfo) {
+ debugInfoStack.push(
+ "array (class \"" + array.getClass().getName() +
+ "\", size: " + len + ")");
+ }
+ try {
+ for (int i = 0; i < len; i++) {
+ if (extendedDebugInfo) {
+ debugInfoStack.push(
+ "element of array (index: " + i + ")");
+ }
+ try {
+ writeObject0(objs[i], false);
+ } finally {
+ if (extendedDebugInfo) {
+ debugInfoStack.pop();
+ }
+ }
+ }
+ } finally {
+ if (extendedDebugInfo) {
+ debugInfoStack.pop();
+ }
+ }
+ }
+ }
+
+ /**
+ * Writes given enum constant to stream.
+ */
+ private void writeEnum(Enum<?> en,
+ ObjectStreamClass desc,
+ boolean unshared)
+ throws IOException
+ {
+ bout.writeByte(TC_ENUM);
+ ObjectStreamClass sdesc = desc.getSuperDesc();
+ writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false);
+ handles.assign(unshared ? null : en);
+ writeString(en.name(), false);
+ }
+
+ /**
+ * Writes representation of a "ordinary" (i.e., not a String, Class,
+ * ObjectStreamClass, array, or enum constant) serializable object to the
+ * stream.
+ */
+ private void writeOrdinaryObject(Object obj,
+ ObjectStreamClass desc,
+ boolean unshared)
+ throws IOException
+ {
+ if (extendedDebugInfo) {
+ debugInfoStack.push(
+ (depth == 1 ? "root " : "") + "object (class \"" +
+ obj.getClass().getName() + "\", " + obj.toString() + ")");
+ }
+ try {
+ desc.checkSerialize();
+
+ bout.writeByte(TC_OBJECT);
+ writeClassDesc(desc, false);
+ handles.assign(unshared ? null : obj);
+ if (desc.isExternalizable() && !desc.isProxy()) {
+ writeExternalData((Externalizable) obj);
+ } else {
+ writeSerialData(obj, desc);
+ }
+ } finally {
+ if (extendedDebugInfo) {
+ debugInfoStack.pop();
+ }
+ }
+ }
+
+ /**
+ * Writes externalizable data of given object by invoking its
+ * writeExternal() method.
+ */
+ private void writeExternalData(Externalizable obj) throws IOException {
+ PutFieldImpl oldPut = curPut;
+ curPut = null;
+
+ if (extendedDebugInfo) {
+ debugInfoStack.push("writeExternal data");
+ }
+ SerialCallbackContext oldContext = curContext;
+ try {
+ curContext = null;
+ if (protocol == PROTOCOL_VERSION_1) {
+ obj.writeExternal(this);
+ } else {
+ bout.setBlockDataMode(true);
+ obj.writeExternal(this);
+ bout.setBlockDataMode(false);
+ bout.writeByte(TC_ENDBLOCKDATA);
+ }
+ } finally {
+ curContext = oldContext;
+ if (extendedDebugInfo) {
+ debugInfoStack.pop();
+ }
+ }
+
+ curPut = oldPut;
+ }
+
+ /**
+ * Writes instance data for each serializable class of given object, from
+ * superclass to subclass.
+ */
+ private void writeSerialData(Object obj, ObjectStreamClass desc)
+ throws IOException
+ {
+ ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
+ for (int i = 0; i < slots.length; i++) {
+ ObjectStreamClass slotDesc = slots[i].desc;
+ if (slotDesc.hasWriteObjectMethod()) {
+ PutFieldImpl oldPut = curPut;
+ curPut = null;
+ SerialCallbackContext oldContext = curContext;
+
+ if (extendedDebugInfo) {
+ debugInfoStack.push(
+ "custom writeObject data (class \"" +
+ slotDesc.getName() + "\")");
+ }
+ try {
+ curContext = new SerialCallbackContext(obj, slotDesc);
+ bout.setBlockDataMode(true);
+ slotDesc.invokeWriteObject(obj, this);
+ bout.setBlockDataMode(false);
+ bout.writeByte(TC_ENDBLOCKDATA);
+ } finally {
+ curContext.setUsed();
+ curContext = oldContext;
+ if (extendedDebugInfo) {
+ debugInfoStack.pop();
+ }
+ }
+
+ curPut = oldPut;
+ } else {
+ defaultWriteFields(obj, slotDesc);
+ }
+ }
+ }
+
+ /**
+ * Fetches and writes values of serializable fields of given object to
+ * stream. The given class descriptor specifies which field values to
+ * write, and in which order they should be written.
+ */
+ private void defaultWriteFields(Object obj, ObjectStreamClass desc)
+ throws IOException
+ {
+ Class<?> cl = desc.forClass();
+ if (cl != null && obj != null && !cl.isInstance(obj)) {
+ throw new ClassCastException();
+ }
+
+ desc.checkDefaultSerialize();
+
+ int primDataSize = desc.getPrimDataSize();
+ if (primVals == null || primVals.length < primDataSize) {
+ primVals = new byte[primDataSize];
+ }
+ desc.getPrimFieldValues(obj, primVals);
+ bout.write(primVals, 0, primDataSize, false);
+
+ ObjectStreamField[] fields = desc.getFields(false);
+ Object[] objVals = new Object[desc.getNumObjFields()];
+ int numPrimFields = fields.length - objVals.length;
+ desc.getObjFieldValues(obj, objVals);
+ for (int i = 0; i < objVals.length; i++) {
+ if (extendedDebugInfo) {
+ debugInfoStack.push(
+ "field (class \"" + desc.getName() + "\", name: \"" +
+ fields[numPrimFields + i].getName() + "\", type: \"" +
+ fields[numPrimFields + i].getType() + "\")");
+ }
+ try {
+ writeObject0(objVals[i],
+ fields[numPrimFields + i].isUnshared());
+ } finally {
+ if (extendedDebugInfo) {
+ debugInfoStack.pop();
+ }
+ }
+ }
+ }
+
+ /**
+ * Attempts to write to stream fatal IOException that has caused
+ * serialization to abort.
+ */
+ private void writeFatalException(IOException ex) throws IOException {
+ /*
+ * Note: the serialization specification states that if a second
+ * IOException occurs while attempting to serialize the original fatal
+ * exception to the stream, then a StreamCorruptedException should be
+ * thrown (section 2.1). However, due to a bug in previous
+ * implementations of serialization, StreamCorruptedExceptions were
+ * rarely (if ever) actually thrown--the "root" exceptions from
+ * underlying streams were thrown instead. This historical behavior is
+ * followed here for consistency.
+ */
+ clear();
+ boolean oldMode = bout.setBlockDataMode(false);
+ try {
+ bout.writeByte(TC_EXCEPTION);
+ writeObject0(ex, false);
+ clear();
+ } finally {
+ bout.setBlockDataMode(oldMode);
+ }
+ }
+
+ /**
+ * Converts specified span of float values into byte values.
+ */
+ // REMIND: remove once hotspot inlines Float.floatToIntBits
+ private static native void floatsToBytes(float[] src, int srcpos,
+ byte[] dst, int dstpos,
+ int nfloats);
+
+ /**
+ * Converts specified span of double values into byte values.
+ */
+ // REMIND: remove once hotspot inlines Double.doubleToLongBits
+ private static native void doublesToBytes(double[] src, int srcpos,
+ byte[] dst, int dstpos,
+ int ndoubles);
+
+ /**
+ * Default PutField implementation.
+ */
+ private class PutFieldImpl extends PutField {
+
+ /** class descriptor describing serializable fields */
+ private final ObjectStreamClass desc;
+ /** primitive field values */
+ private final byte[] primVals;
+ /** object field values */
+ private final Object[] objVals;
+
+ /**
+ * Creates PutFieldImpl object for writing fields defined in given
+ * class descriptor.
+ */
+ PutFieldImpl(ObjectStreamClass desc) {
+ this.desc = desc;
+ primVals = new byte[desc.getPrimDataSize()];
+ objVals = new Object[desc.getNumObjFields()];
+ }
+
+ public void put(String name, boolean val) {
+ Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val);
+ }
+
+ public void put(String name, byte val) {
+ primVals[getFieldOffset(name, Byte.TYPE)] = val;
+ }
+
+ public void put(String name, char val) {
+ Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val);
+ }
+
+ public void put(String name, short val) {
+ Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val);
+ }
+
+ public void put(String name, int val) {
+ Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val);
+ }
+
+ public void put(String name, float val) {
+ Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val);
+ }
+
+ public void put(String name, long val) {
+ Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val);
+ }
+
+ public void put(String name, double val) {
+ Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val);
+ }
+
+ public void put(String name, Object val) {
+ objVals[getFieldOffset(name, Object.class)] = val;
+ }
+
+ // deprecated in ObjectOutputStream.PutField
+ public void write(ObjectOutput out) throws IOException {
+ /*
+ * Applications should *not* use this method to write PutField
+ * data, as it will lead to stream corruption if the PutField
+ * object writes any primitive data (since block data mode is not
+ * unset/set properly, as is done in OOS.writeFields()). This
+ * broken implementation is being retained solely for behavioral
+ * compatibility, in order to support applications which use
+ * OOS.PutField.write() for writing only non-primitive data.
+ *
+ * Serialization of unshared objects is not implemented here since
+ * it is not necessary for backwards compatibility; also, unshared
+ * semantics may not be supported by the given ObjectOutput
+ * instance. Applications which write unshared objects using the
+ * PutField API must use OOS.writeFields().
+ */
+ if (ObjectOutputStream.this != out) {
+ throw new IllegalArgumentException("wrong stream");
+ }
+ out.write(primVals, 0, primVals.length);
+
+ ObjectStreamField[] fields = desc.getFields(false);
+ int numPrimFields = fields.length - objVals.length;
+ // REMIND: warn if numPrimFields > 0?
+ for (int i = 0; i < objVals.length; i++) {
+ if (fields[numPrimFields + i].isUnshared()) {
+ throw new IOException("cannot write unshared object");
+ }
+ out.writeObject(objVals[i]);
+ }
+ }
+
+ /**
+ * Writes buffered primitive data and object fields to stream.
+ */
+ void writeFields() throws IOException {
+ bout.write(primVals, 0, primVals.length, false);
+
+ ObjectStreamField[] fields = desc.getFields(false);
+ int numPrimFields = fields.length - objVals.length;
+ for (int i = 0; i < objVals.length; i++) {
+ if (extendedDebugInfo) {
+ debugInfoStack.push(
+ "field (class \"" + desc.getName() + "\", name: \"" +
+ fields[numPrimFields + i].getName() + "\", type: \"" +
+ fields[numPrimFields + i].getType() + "\")");
+ }
+ try {
+ writeObject0(objVals[i],
+ fields[numPrimFields + i].isUnshared());
+ } finally {
+ if (extendedDebugInfo) {
+ debugInfoStack.pop();
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns offset of field with given name and type. A specified type
+ * of null matches all types, Object.class matches all non-primitive
+ * types, and any other non-null type matches assignable types only.
+ * Throws IllegalArgumentException if no matching field found.
+ */
+ private int getFieldOffset(String name, Class<?> type) {
+ ObjectStreamField field = desc.getField(name, type);
+ if (field == null) {
+ throw new IllegalArgumentException("no such field " + name +
+ " with type " + type);
+ }
+ return field.getOffset();
+ }
+ }
+
+ /**
+ * Buffered output stream with two modes: in default mode, outputs data in
+ * same format as DataOutputStream; in "block data" mode, outputs data
+ * bracketed by block data markers (see object serialization specification
+ * for details).
+ */
+ private static class BlockDataOutputStream
+ extends OutputStream implements DataOutput
+ {
+ /** maximum data block length */
+ private static final int MAX_BLOCK_SIZE = 1024;
+ /** maximum data block header length */
+ private static final int MAX_HEADER_SIZE = 5;
+ /** (tunable) length of char buffer (for writing strings) */
+ private static final int CHAR_BUF_SIZE = 256;
+
+ /** buffer for writing general/block data */
+ private final byte[] buf = new byte[MAX_BLOCK_SIZE];
+ /** buffer for writing block data headers */
+ private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
+ /** char buffer for fast string writes */
+ private final char[] cbuf = new char[CHAR_BUF_SIZE];
+
+ /** block data mode */
+ private boolean blkmode = false;
+ /** current offset into buf */
+ private int pos = 0;
+
+ /** underlying output stream */
+ private final OutputStream out;
+ /** loopback stream (for data writes that span data blocks) */
+ private final DataOutputStream dout;
+
+ // BEGIN Android-added: Warning if writing to a closed ObjectOutputStream.
+ /**
+ * Indicates that this stream was closed and that a warning must be logged once if an
+ * attempt is made to write to it and the underlying stream does not throw an exception.
+ *
+ * <p>This will be set back to false when a warning is logged to ensure that the log is not
+ * flooded with warnings.
+ *
+ * http://b/28159133
+ */
+ private boolean warnOnceWhenWriting;
+ // END Android-added: Warning if writing to a closed ObjectOutputStream.
+
+ /**
+ * Creates new BlockDataOutputStream on top of given underlying stream.
+ * Block data mode is turned off by default.
+ */
+ BlockDataOutputStream(OutputStream out) {
+ this.out = out;
+ dout = new DataOutputStream(this);
+ }
+
+ /**
+ * Sets block data mode to the given mode (true == on, false == off)
+ * and returns the previous mode value. If the new mode is the same as
+ * the old mode, no action is taken. If the new mode differs from the
+ * old mode, any buffered data is flushed before switching to the new
+ * mode.
+ */
+ boolean setBlockDataMode(boolean mode) throws IOException {
+ if (blkmode == mode) {
+ return blkmode;
+ }
+ drain();
+ blkmode = mode;
+ return !blkmode;
+ }
+
+ /**
+ * Returns true if the stream is currently in block data mode, false
+ * otherwise.
+ */
+ boolean getBlockDataMode() {
+ return blkmode;
+ }
+
+ // BEGIN Android-added: Warning about writing to closed ObjectOutputStream.
+ /**
+ * Warns if the stream has been closed.
+ *
+ * <p>This is called after data has been written to the underlying stream in order to allow
+ * the underlying stream to detect and fail if an attempt is made to write to a closed
+ * stream. That ensures that this will only log a warning if the underlying stream does not
+ * so it will not log unnecessary warnings.
+ */
+ private void warnIfClosed() {
+ if (warnOnceWhenWriting) {
+ System.logW("The app is relying on undefined behavior. Attempting to write to a"
+ + " closed ObjectOutputStream could produce corrupt output in a future"
+ + " release of Android.", new IOException("Stream Closed"));
+ // Set back to false so no more messages are logged unless the stream is closed
+ // again.
+ warnOnceWhenWriting = false;
+ }
+ }
+ // END Android-added: Warning about writing to closed ObjectOutputStream.
+
+ /* ----------------- generic output stream methods ----------------- */
+ /*
+ * The following methods are equivalent to their counterparts in
+ * OutputStream, except that they partition written data into data
+ * blocks when in block data mode.
+ */
+
+ public void write(int b) throws IOException {
+ if (pos >= MAX_BLOCK_SIZE) {
+ drain();
+ }
+ buf[pos++] = (byte) b;
+ }
+
+ public void write(byte[] b) throws IOException {
+ write(b, 0, b.length, false);
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ write(b, off, len, false);
+ }
+
+ public void flush() throws IOException {
+ drain();
+ out.flush();
+ }
+
+ public void close() throws IOException {
+ flush();
+ out.close();
+ // Android-added: Warning about writing to closed ObjectOutputStream.
+ warnOnceWhenWriting = true;
+ }
+
+ /**
+ * Writes specified span of byte values from given array. If copy is
+ * true, copies the values to an intermediate buffer before writing
+ * them to underlying stream (to avoid exposing a reference to the
+ * original byte array).
+ */
+ void write(byte[] b, int off, int len, boolean copy)
+ throws IOException
+ {
+ if (!(copy || blkmode)) { // write directly
+ drain();
+ out.write(b, off, len);
+ // Android-added: Warning about writing to closed ObjectOutputStream.
+ warnIfClosed();
+ return;
+ }
+
+ while (len > 0) {
+ if (pos >= MAX_BLOCK_SIZE) {
+ drain();
+ }
+ if (len >= MAX_BLOCK_SIZE && !copy && pos == 0) {
+ // avoid unnecessary copy
+ writeBlockHeader(MAX_BLOCK_SIZE);
+ out.write(b, off, MAX_BLOCK_SIZE);
+ off += MAX_BLOCK_SIZE;
+ len -= MAX_BLOCK_SIZE;
+ } else {
+ int wlen = Math.min(len, MAX_BLOCK_SIZE - pos);
+ System.arraycopy(b, off, buf, pos, wlen);
+ pos += wlen;
+ off += wlen;
+ len -= wlen;
+ }
+ }
+ // Android-added: Warning about writing to closed ObjectOutputStream.
+ warnIfClosed();
+ }
+
+ /**
+ * Writes all buffered data from this stream to the underlying stream,
+ * but does not flush underlying stream.
+ */
+ void drain() throws IOException {
+ if (pos == 0) {
+ return;
+ }
+ if (blkmode) {
+ writeBlockHeader(pos);
+ }
+ out.write(buf, 0, pos);
+ pos = 0;
+ // Android-added: Warning about writing to closed ObjectOutputStream.
+ warnIfClosed();
+ }
+
+ /**
+ * Writes block data header. Data blocks shorter than 256 bytes are
+ * prefixed with a 2-byte header; all others start with a 5-byte
+ * header.
+ */
+ private void writeBlockHeader(int len) throws IOException {
+ if (len <= 0xFF) {
+ hbuf[0] = TC_BLOCKDATA;
+ hbuf[1] = (byte) len;
+ out.write(hbuf, 0, 2);
+ } else {
+ hbuf[0] = TC_BLOCKDATALONG;
+ Bits.putInt(hbuf, 1, len);
+ out.write(hbuf, 0, 5);
+ }
+ // Android-added: Warning about writing to closed ObjectOutputStream.
+ warnIfClosed();
+ }
+
+
+ /* ----------------- primitive data output methods ----------------- */
+ /*
+ * The following methods are equivalent to their counterparts in
+ * DataOutputStream, except that they partition written data into data
+ * blocks when in block data mode.
+ */
+
+ public void writeBoolean(boolean v) throws IOException {
+ if (pos >= MAX_BLOCK_SIZE) {
+ drain();
+ }
+ Bits.putBoolean(buf, pos++, v);
+ }
+
+ public void writeByte(int v) throws IOException {
+ if (pos >= MAX_BLOCK_SIZE) {
+ drain();
+ }
+ buf[pos++] = (byte) v;
+ }
+
+ public void writeChar(int v) throws IOException {
+ if (pos + 2 <= MAX_BLOCK_SIZE) {
+ Bits.putChar(buf, pos, (char) v);
+ pos += 2;
+ } else {
+ dout.writeChar(v);
+ }
+ }
+
+ public void writeShort(int v) throws IOException {
+ if (pos + 2 <= MAX_BLOCK_SIZE) {
+ Bits.putShort(buf, pos, (short) v);
+ pos += 2;
+ } else {
+ dout.writeShort(v);
+ }
+ }
+
+ public void writeInt(int v) throws IOException {
+ if (pos + 4 <= MAX_BLOCK_SIZE) {
+ Bits.putInt(buf, pos, v);
+ pos += 4;
+ } else {
+ dout.writeInt(v);
+ }
+ }
+
+ public void writeFloat(float v) throws IOException {
+ if (pos + 4 <= MAX_BLOCK_SIZE) {
+ Bits.putFloat(buf, pos, v);
+ pos += 4;
+ } else {
+ dout.writeFloat(v);
+ }
+ }
+
+ public void writeLong(long v) throws IOException {
+ if (pos + 8 <= MAX_BLOCK_SIZE) {
+ Bits.putLong(buf, pos, v);
+ pos += 8;
+ } else {
+ dout.writeLong(v);
+ }
+ }
+
+ public void writeDouble(double v) throws IOException {
+ if (pos + 8 <= MAX_BLOCK_SIZE) {
+ Bits.putDouble(buf, pos, v);
+ pos += 8;
+ } else {
+ dout.writeDouble(v);
+ }
+ }
+
+ public void writeBytes(String s) throws IOException {
+ int endoff = s.length();
+ int cpos = 0;
+ int csize = 0;
+ for (int off = 0; off < endoff; ) {
+ if (cpos >= csize) {
+ cpos = 0;
+ csize = Math.min(endoff - off, CHAR_BUF_SIZE);
+ s.getChars(off, off + csize, cbuf, 0);
+ }
+ if (pos >= MAX_BLOCK_SIZE) {
+ drain();
+ }
+ int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos);
+ int stop = pos + n;
+ while (pos < stop) {
+ buf[pos++] = (byte) cbuf[cpos++];
+ }
+ off += n;
+ }
+ }
+
+ public void writeChars(String s) throws IOException {
+ int endoff = s.length();
+ for (int off = 0; off < endoff; ) {
+ int csize = Math.min(endoff - off, CHAR_BUF_SIZE);
+ s.getChars(off, off + csize, cbuf, 0);
+ writeChars(cbuf, 0, csize);
+ off += csize;
+ }
+ }
+
+ public void writeUTF(String s) throws IOException {
+ writeUTF(s, getUTFLength(s));
+ }
+
+
+ /* -------------- primitive data array output methods -------------- */
+ /*
+ * The following methods write out spans of primitive data values.
+ * Though equivalent to calling the corresponding primitive write
+ * methods repeatedly, these methods are optimized for writing groups
+ * of primitive data values more efficiently.
+ */
+
+ void writeBooleans(boolean[] v, int off, int len) throws IOException {
+ int endoff = off + len;
+ while (off < endoff) {
+ if (pos >= MAX_BLOCK_SIZE) {
+ drain();
+ }
+ int stop = Math.min(endoff, off + (MAX_BLOCK_SIZE - pos));
+ while (off < stop) {
+ Bits.putBoolean(buf, pos++, v[off++]);
+ }
+ }
+ }
+
+ void writeChars(char[] v, int off, int len) throws IOException {
+ int limit = MAX_BLOCK_SIZE - 2;
+ int endoff = off + len;
+ while (off < endoff) {
+ if (pos <= limit) {
+ int avail = (MAX_BLOCK_SIZE - pos) >> 1;
+ int stop = Math.min(endoff, off + avail);
+ while (off < stop) {
+ Bits.putChar(buf, pos, v[off++]);
+ pos += 2;
+ }
+ } else {
+ dout.writeChar(v[off++]);
+ }
+ }
+ }
+
+ void writeShorts(short[] v, int off, int len) throws IOException {
+ int limit = MAX_BLOCK_SIZE - 2;
+ int endoff = off + len;
+ while (off < endoff) {
+ if (pos <= limit) {
+ int avail = (MAX_BLOCK_SIZE - pos) >> 1;
+ int stop = Math.min(endoff, off + avail);
+ while (off < stop) {
+ Bits.putShort(buf, pos, v[off++]);
+ pos += 2;
+ }
+ } else {
+ dout.writeShort(v[off++]);
+ }
+ }
+ }
+
+ void writeInts(int[] v, int off, int len) throws IOException {
+ int limit = MAX_BLOCK_SIZE - 4;
+ int endoff = off + len;
+ while (off < endoff) {
+ if (pos <= limit) {
+ int avail = (MAX_BLOCK_SIZE - pos) >> 2;
+ int stop = Math.min(endoff, off + avail);
+ while (off < stop) {
+ Bits.putInt(buf, pos, v[off++]);
+ pos += 4;
+ }
+ } else {
+ dout.writeInt(v[off++]);
+ }
+ }
+ }
+
+ void writeFloats(float[] v, int off, int len) throws IOException {
+ int limit = MAX_BLOCK_SIZE - 4;
+ int endoff = off + len;
+ while (off < endoff) {
+ if (pos <= limit) {
+ int avail = (MAX_BLOCK_SIZE - pos) >> 2;
+ int chunklen = Math.min(endoff - off, avail);
+ floatsToBytes(v, off, buf, pos, chunklen);
+ off += chunklen;
+ pos += chunklen << 2;
+ } else {
+ dout.writeFloat(v[off++]);
+ }
+ }
+ }
+
+ void writeLongs(long[] v, int off, int len) throws IOException {
+ int limit = MAX_BLOCK_SIZE - 8;
+ int endoff = off + len;
+ while (off < endoff) {
+ if (pos <= limit) {
+ int avail = (MAX_BLOCK_SIZE - pos) >> 3;
+ int stop = Math.min(endoff, off + avail);
+ while (off < stop) {
+ Bits.putLong(buf, pos, v[off++]);
+ pos += 8;
+ }
+ } else {
+ dout.writeLong(v[off++]);
+ }
+ }
+ }
+
+ void writeDoubles(double[] v, int off, int len) throws IOException {
+ int limit = MAX_BLOCK_SIZE - 8;
+ int endoff = off + len;
+ while (off < endoff) {
+ if (pos <= limit) {
+ int avail = (MAX_BLOCK_SIZE - pos) >> 3;
+ int chunklen = Math.min(endoff - off, avail);
+ doublesToBytes(v, off, buf, pos, chunklen);
+ off += chunklen;
+ pos += chunklen << 3;
+ } else {
+ dout.writeDouble(v[off++]);
+ }
+ }
+ }
+
+ /**
+ * Returns the length in bytes of the UTF encoding of the given string.
+ */
+ long getUTFLength(String s) {
+ int len = s.length();
+ long utflen = 0;
+ for (int off = 0; off < len; ) {
+ int csize = Math.min(len - off, CHAR_BUF_SIZE);
+ s.getChars(off, off + csize, cbuf, 0);
+ for (int cpos = 0; cpos < csize; cpos++) {
+ char c = cbuf[cpos];
+ if (c >= 0x0001 && c <= 0x007F) {
+ utflen++;
+ } else if (c > 0x07FF) {
+ utflen += 3;
+ } else {
+ utflen += 2;
+ }
+ }
+ off += csize;
+ }
+ return utflen;
+ }
+
+ /**
+ * Writes the given string in UTF format. This method is used in
+ * situations where the UTF encoding length of the string is already
+ * known; specifying it explicitly avoids a prescan of the string to
+ * determine its UTF length.
+ */
+ void writeUTF(String s, long utflen) throws IOException {
+ if (utflen > 0xFFFFL) {
+ throw new UTFDataFormatException();
+ }
+ writeShort((int) utflen);
+ if (utflen == (long) s.length()) {
+ writeBytes(s);
+ } else {
+ writeUTFBody(s);
+ }
+ }
+
+ /**
+ * Writes given string in "long" UTF format. "Long" UTF format is
+ * identical to standard UTF, except that it uses an 8 byte header
+ * (instead of the standard 2 bytes) to convey the UTF encoding length.
+ */
+ void writeLongUTF(String s) throws IOException {
+ writeLongUTF(s, getUTFLength(s));
+ }
+
+ /**
+ * Writes given string in "long" UTF format, where the UTF encoding
+ * length of the string is already known.
+ */
+ void writeLongUTF(String s, long utflen) throws IOException {
+ writeLong(utflen);
+ if (utflen == (long) s.length()) {
+ writeBytes(s);
+ } else {
+ writeUTFBody(s);
+ }
+ }
+
+ /**
+ * Writes the "body" (i.e., the UTF representation minus the 2-byte or
+ * 8-byte length header) of the UTF encoding for the given string.
+ */
+ private void writeUTFBody(String s) throws IOException {
+ int limit = MAX_BLOCK_SIZE - 3;
+ int len = s.length();
+ for (int off = 0; off < len; ) {
+ int csize = Math.min(len - off, CHAR_BUF_SIZE);
+ s.getChars(off, off + csize, cbuf, 0);
+ for (int cpos = 0; cpos < csize; cpos++) {
+ char c = cbuf[cpos];
+ if (pos <= limit) {
+ if (c <= 0x007F && c != 0) {
+ buf[pos++] = (byte) c;
+ } else if (c > 0x07FF) {
+ buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F));
+ buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F));
+ buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F));
+ pos += 3;
+ } else {
+ buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F));
+ buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F));
+ pos += 2;
+ }
+ } else { // write one byte at a time to normalize block
+ if (c <= 0x007F && c != 0) {
+ write(c);
+ } else if (c > 0x07FF) {
+ write(0xE0 | ((c >> 12) & 0x0F));
+ write(0x80 | ((c >> 6) & 0x3F));
+ write(0x80 | ((c >> 0) & 0x3F));
+ } else {
+ write(0xC0 | ((c >> 6) & 0x1F));
+ write(0x80 | ((c >> 0) & 0x3F));
+ }
+ }
+ }
+ off += csize;
+ }
+ }
+ }
+
+ /**
+ * Lightweight identity hash table which maps objects to integer handles,
+ * assigned in ascending order.
+ */
+ private static class HandleTable {
+
+ /* number of mappings in table/next available handle */
+ private int size;
+ /* size threshold determining when to expand hash spine */
+ private int threshold;
+ /* factor for computing size threshold */
+ private final float loadFactor;
+ /* maps hash value -> candidate handle value */
+ private int[] spine;
+ /* maps handle value -> next candidate handle value */
+ private int[] next;
+ /* maps handle value -> associated object */
+ private Object[] objs;
+
+ /**
+ * Creates new HandleTable with given capacity and load factor.
+ */
+ HandleTable(int initialCapacity, float loadFactor) {
+ this.loadFactor = loadFactor;
+ spine = new int[initialCapacity];
+ next = new int[initialCapacity];
+ objs = new Object[initialCapacity];
+ threshold = (int) (initialCapacity * loadFactor);
+ clear();
+ }
+
+ /**
+ * Assigns next available handle to given object, and returns handle
+ * value. Handles are assigned in ascending order starting at 0.
+ */
+ int assign(Object obj) {
+ if (size >= next.length) {
+ growEntries();
+ }
+ if (size >= threshold) {
+ growSpine();
+ }
+ insert(obj, size);
+ return size++;
+ }
+
+ /**
+ * Looks up and returns handle associated with given object, or -1 if
+ * no mapping found.
+ */
+ int lookup(Object obj) {
+ if (size == 0) {
+ return -1;
+ }
+ int index = hash(obj) % spine.length;
+ for (int i = spine[index]; i >= 0; i = next[i]) {
+ if (objs[i] == obj) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Resets table to its initial (empty) state.
+ */
+ void clear() {
+ Arrays.fill(spine, -1);
+ Arrays.fill(objs, 0, size, null);
+ size = 0;
+ }
+
+ /**
+ * Returns the number of mappings currently in table.
+ */
+ int size() {
+ return size;
+ }
+
+ /**
+ * Inserts mapping object -> handle mapping into table. Assumes table
+ * is large enough to accommodate new mapping.
+ */
+ private void insert(Object obj, int handle) {
+ int index = hash(obj) % spine.length;
+ objs[handle] = obj;
+ next[handle] = spine[index];
+ spine[index] = handle;
+ }
+
+ /**
+ * Expands the hash "spine" -- equivalent to increasing the number of
+ * buckets in a conventional hash table.
+ */
+ private void growSpine() {
+ spine = new int[(spine.length << 1) + 1];
+ threshold = (int) (spine.length * loadFactor);
+ Arrays.fill(spine, -1);
+ for (int i = 0; i < size; i++) {
+ insert(objs[i], i);
+ }
+ }
+
+ /**
+ * Increases hash table capacity by lengthening entry arrays.
+ */
+ private void growEntries() {
+ int newLength = (next.length << 1) + 1;
+ int[] newNext = new int[newLength];
+ System.arraycopy(next, 0, newNext, 0, size);
+ next = newNext;
+
+ Object[] newObjs = new Object[newLength];
+ System.arraycopy(objs, 0, newObjs, 0, size);
+ objs = newObjs;
+ }
+
+ /**
+ * Returns hash value for given object.
+ */
+ private int hash(Object obj) {
+ return System.identityHashCode(obj) & 0x7FFFFFFF;
+ }
+ }
+
+ /**
+ * Lightweight identity hash table which maps objects to replacement
+ * objects.
+ */
+ private static class ReplaceTable {
+
+ /* maps object -> index */
+ private final HandleTable htab;
+ /* maps index -> replacement object */
+ private Object[] reps;
+
+ /**
+ * Creates new ReplaceTable with given capacity and load factor.
+ */
+ ReplaceTable(int initialCapacity, float loadFactor) {
+ htab = new HandleTable(initialCapacity, loadFactor);
+ reps = new Object[initialCapacity];
+ }
+
+ /**
+ * Enters mapping from object to replacement object.
+ */
+ void assign(Object obj, Object rep) {
+ int index = htab.assign(obj);
+ while (index >= reps.length) {
+ grow();
+ }
+ reps[index] = rep;
+ }
+
+ /**
+ * Looks up and returns replacement for given object. If no
+ * replacement is found, returns the lookup object itself.
+ */
+ Object lookup(Object obj) {
+ int index = htab.lookup(obj);
+ return (index >= 0) ? reps[index] : obj;
+ }
+
+ /**
+ * Resets table to its initial (empty) state.
+ */
+ void clear() {
+ Arrays.fill(reps, 0, htab.size(), null);
+ htab.clear();
+ }
+
+ /**
+ * Returns the number of mappings currently in table.
+ */
+ int size() {
+ return htab.size();
+ }
+
+ /**
+ * Increases table capacity.
+ */
+ private void grow() {
+ Object[] newReps = new Object[(reps.length << 1) + 1];
+ System.arraycopy(reps, 0, newReps, 0, reps.length);
+ reps = newReps;
+ }
+ }
+
+ /**
+ * Stack to keep debug information about the state of the
+ * serialization process, for embedding in exception messages.
+ */
+ private static class DebugTraceInfoStack {
+ private final List<String> stack;
+
+ DebugTraceInfoStack() {
+ stack = new ArrayList<>();
+ }
+
+ /**
+ * Removes all of the elements from enclosed list.
+ */
+ void clear() {
+ stack.clear();
+ }
+
+ /**
+ * Removes the object at the top of enclosed list.
+ */
+ void pop() {
+ stack.remove(stack.size()-1);
+ }
+
+ /**
+ * Pushes a String onto the top of enclosed list.
+ */
+ void push(String entry) {
+ stack.add("\t- " + entry);
+ }
+
+ /**
+ * Returns a string representation of this object
+ */
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ if (!stack.isEmpty()) {
+ for(int i = stack.size(); i > 0; i-- ) {
+ buffer.append(stack.get(i-1) + ((i != 1) ? "\n" : ""));
+ }
+ }
+ return buffer.toString();
+ }
+ }
+
+}
diff --git a/java/io/ObjectStreamClass.java b/java/io/ObjectStreamClass.java
new file mode 100644
index 0000000..9a1a48f
--- /dev/null
+++ b/java/io/ObjectStreamClass.java
@@ -0,0 +1,2498 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+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.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+import sun.reflect.misc.ReflectUtil;
+import dalvik.system.VMRuntime;
+
+/**
+ * Serialization's descriptor for classes. It contains the name and
+ * serialVersionUID of the class. The ObjectStreamClass for a specific class
+ * loaded in this Java VM can be found/created using the lookup method.
+ *
+ * <p>The algorithm to compute the SerialVersionUID is described in
+ * <a href="../../../platform/serialization/spec/class.html#4100">Object
+ * Serialization Specification, Section 4.6, Stream Unique Identifiers</a>.
+ *
+ * @author Mike Warres
+ * @author Roger Riggs
+ * @see ObjectStreamField
+ * @see <a href="../../../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a>
+ * @since JDK1.1
+ */
+public class ObjectStreamClass implements Serializable {
+
+ /** serialPersistentFields value indicating no serializable fields */
+ public static final ObjectStreamField[] NO_FIELDS =
+ new ObjectStreamField[0];
+
+ private static final long serialVersionUID = -6120832682080437368L;
+ private static final ObjectStreamField[] serialPersistentFields =
+ NO_FIELDS;
+
+ // BEGIN Android-removed: ReflectionFactory not used on Android.
+ /*
+ /** reflection factory for obtaining serialization constructors *
+ private static final ReflectionFactory reflFactory =
+ AccessController.doPrivileged(
+ new ReflectionFactory.GetReflectionFactoryAction());
+ */
+ // END Android-removed: ReflectionFactory not used on Android.
+
+ private static class Caches {
+ /** cache mapping local classes -> descriptors */
+ static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs =
+ new ConcurrentHashMap<>();
+
+ /** cache mapping field group/local desc pairs -> field reflectors */
+ static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors =
+ new ConcurrentHashMap<>();
+
+ /** queue for WeakReferences to local classes */
+ private static final ReferenceQueue<Class<?>> localDescsQueue =
+ new ReferenceQueue<>();
+ /** queue for WeakReferences to field reflectors keys */
+ private static final ReferenceQueue<Class<?>> reflectorsQueue =
+ new ReferenceQueue<>();
+ }
+
+ /** class associated with this descriptor (if any) */
+ private Class<?> cl;
+ /** name of class represented by this descriptor */
+ private String name;
+ /** serialVersionUID of represented class (null if not computed yet) */
+ private volatile Long suid;
+
+ /** true if represents dynamic proxy class */
+ private boolean isProxy;
+ /** true if represents enum type */
+ private boolean isEnum;
+ /** true if represented class implements Serializable */
+ private boolean serializable;
+ /** true if represented class implements Externalizable */
+ private boolean externalizable;
+ /** true if desc has data written by class-defined writeObject method */
+ private boolean hasWriteObjectData;
+ /**
+ * true if desc has externalizable data written in block data format; this
+ * must be true by default to accommodate ObjectInputStream subclasses which
+ * override readClassDescriptor() to return class descriptors obtained from
+ * ObjectStreamClass.lookup() (see 4461737)
+ */
+ private boolean hasBlockExternalData = true;
+
+ /**
+ * Contains information about InvalidClassException instances to be thrown
+ * when attempting operations on an invalid class. Note that instances of
+ * this class are immutable and are potentially shared among
+ * ObjectStreamClass instances.
+ */
+ private static class ExceptionInfo {
+ private final String className;
+ private final String message;
+
+ ExceptionInfo(String cn, String msg) {
+ className = cn;
+ message = msg;
+ }
+
+ /**
+ * Returns (does not throw) an InvalidClassException instance created
+ * from the information in this object, suitable for being thrown by
+ * the caller.
+ */
+ InvalidClassException newInvalidClassException() {
+ return new InvalidClassException(className, message);
+ }
+ }
+
+ /** exception (if any) thrown while attempting to resolve class */
+ private ClassNotFoundException resolveEx;
+ /** exception (if any) to throw if non-enum deserialization attempted */
+ private ExceptionInfo deserializeEx;
+ /** exception (if any) to throw if non-enum serialization attempted */
+ private ExceptionInfo serializeEx;
+ /** exception (if any) to throw if default serialization attempted */
+ private ExceptionInfo defaultSerializeEx;
+
+ /** serializable fields */
+ private ObjectStreamField[] fields;
+ /** aggregate marshalled size of primitive fields */
+ private int primDataSize;
+ /** number of non-primitive fields */
+ private int numObjFields;
+ /** reflector for setting/getting serializable field values */
+ private FieldReflector fieldRefl;
+ /** data layout of serialized objects described by this class desc */
+ private volatile ClassDataSlot[] dataLayout;
+
+ /** serialization-appropriate constructor, or null if none */
+ private Constructor<?> cons;
+ /** class-defined writeObject method, or null if none */
+ private Method writeObjectMethod;
+ /** class-defined readObject method, or null if none */
+ private Method readObjectMethod;
+ /** class-defined readObjectNoData method, or null if none */
+ private Method readObjectNoDataMethod;
+ /** class-defined writeReplace method, or null if none */
+ private Method writeReplaceMethod;
+ /** class-defined readResolve method, or null if none */
+ private Method readResolveMethod;
+
+ /** local class descriptor for represented class (may point to self) */
+ private ObjectStreamClass localDesc;
+ /** superclass descriptor appearing in stream */
+ private ObjectStreamClass superDesc;
+
+ /** true if, and only if, the object has been correctly initialized */
+ private boolean initialized;
+
+ // BEGIN Android-removed: Initialization not required on Android.
+ /*
+ /**
+ * Initializes native code.
+ *
+ private static native void initNative();
+ static {
+ initNative();
+ }
+ */
+ // END Android-removed: Initialization not required on Android.
+
+ /**
+ * Find the descriptor for a class that can be serialized. Creates an
+ * ObjectStreamClass instance if one does not exist yet for class. Null is
+ * returned if the specified class does not implement java.io.Serializable
+ * or java.io.Externalizable.
+ *
+ * @param cl class for which to get the descriptor
+ * @return the class descriptor for the specified class
+ */
+ public static ObjectStreamClass lookup(Class<?> cl) {
+ return lookup(cl, false);
+ }
+
+ /**
+ * Returns the descriptor for any class, regardless of whether it
+ * implements {@link Serializable}.
+ *
+ * @param cl class for which to get the descriptor
+ * @return the class descriptor for the specified class
+ * @since 1.6
+ */
+ public static ObjectStreamClass lookupAny(Class<?> cl) {
+ return lookup(cl, true);
+ }
+
+ /**
+ * Returns the name of the class described by this descriptor.
+ * This method returns the name of the class in the format that
+ * is used by the {@link Class#getName} method.
+ *
+ * @return a string representing the name of the class
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Return the serialVersionUID for this class. The serialVersionUID
+ * defines a set of classes all with the same name that have evolved from a
+ * common root class and agree to be serialized and deserialized using a
+ * common format. NonSerializable classes have a serialVersionUID of 0L.
+ *
+ * @return the SUID of the class described by this descriptor
+ */
+ public long getSerialVersionUID() {
+ // REMIND: synchronize instead of relying on volatile?
+ if (suid == null) {
+ suid = AccessController.doPrivileged(
+ new PrivilegedAction<Long>() {
+ public Long run() {
+ return computeDefaultSUID(cl);
+ }
+ }
+ );
+ }
+ return suid.longValue();
+ }
+
+ /**
+ * Return the class in the local VM that this version is mapped to. Null
+ * is returned if there is no corresponding local class.
+ *
+ * @return the <code>Class</code> instance that this descriptor represents
+ */
+ @CallerSensitive
+ public Class<?> forClass() {
+ if (cl == null) {
+ return null;
+ }
+ requireInitialized();
+ if (System.getSecurityManager() != null) {
+ Class<?> caller = Reflection.getCallerClass();
+ if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), cl.getClassLoader())) {
+ ReflectUtil.checkPackageAccess(cl);
+ }
+ }
+ return cl;
+ }
+
+ /**
+ * Return an array of the fields of this serializable class.
+ *
+ * @return an array containing an element for each persistent field of
+ * this class. Returns an array of length zero if there are no
+ * fields.
+ * @since 1.2
+ */
+ public ObjectStreamField[] getFields() {
+ return getFields(true);
+ }
+
+ /**
+ * Get the field of this class by name.
+ *
+ * @param name the name of the data field to look for
+ * @return The ObjectStreamField object of the named field or null if
+ * there is no such named field.
+ */
+ public ObjectStreamField getField(String name) {
+ return getField(name, null);
+ }
+
+ /**
+ * Return a string describing this ObjectStreamClass.
+ */
+ public String toString() {
+ return name + ": static final long serialVersionUID = " +
+ getSerialVersionUID() + "L;";
+ }
+
+ /**
+ * Looks up and returns class descriptor for given class, or null if class
+ * is non-serializable and "all" is set to false.
+ *
+ * @param cl class to look up
+ * @param all if true, return descriptors for all classes; if false, only
+ * return descriptors for serializable classes
+ */
+ static ObjectStreamClass lookup(Class<?> cl, boolean all) {
+ if (!(all || Serializable.class.isAssignableFrom(cl))) {
+ return null;
+ }
+ processQueue(Caches.localDescsQueue, Caches.localDescs);
+ WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue);
+ Reference<?> ref = Caches.localDescs.get(key);
+ Object entry = null;
+ if (ref != null) {
+ entry = ref.get();
+ }
+ EntryFuture future = null;
+ if (entry == null) {
+ EntryFuture newEntry = new EntryFuture();
+ Reference<?> newRef = new SoftReference<>(newEntry);
+ do {
+ if (ref != null) {
+ Caches.localDescs.remove(key, ref);
+ }
+ ref = Caches.localDescs.putIfAbsent(key, newRef);
+ if (ref != null) {
+ entry = ref.get();
+ }
+ } while (ref != null && entry == null);
+ if (entry == null) {
+ future = newEntry;
+ }
+ }
+
+ if (entry instanceof ObjectStreamClass) { // check common case first
+ return (ObjectStreamClass) entry;
+ }
+ if (entry instanceof EntryFuture) {
+ future = (EntryFuture) entry;
+ if (future.getOwner() == Thread.currentThread()) {
+ /*
+ * Handle nested call situation described by 4803747: waiting
+ * for future value to be set by a lookup() call further up the
+ * stack will result in deadlock, so calculate and set the
+ * future value here instead.
+ */
+ entry = null;
+ } else {
+ entry = future.get();
+ }
+ }
+ if (entry == null) {
+ try {
+ entry = new ObjectStreamClass(cl);
+ } catch (Throwable th) {
+ entry = th;
+ }
+ if (future.set(entry)) {
+ Caches.localDescs.put(key, new SoftReference<Object>(entry));
+ } else {
+ // nested lookup call already set future
+ entry = future.get();
+ }
+ }
+
+ if (entry instanceof ObjectStreamClass) {
+ return (ObjectStreamClass) entry;
+ } else if (entry instanceof RuntimeException) {
+ throw (RuntimeException) entry;
+ } else if (entry instanceof Error) {
+ throw (Error) entry;
+ } else {
+ throw new InternalError("unexpected entry: " + entry);
+ }
+ }
+
+ /**
+ * Placeholder used in class descriptor and field reflector lookup tables
+ * for an entry in the process of being initialized. (Internal) callers
+ * which receive an EntryFuture belonging to another thread as the result
+ * of a lookup should call the get() method of the EntryFuture; this will
+ * return the actual entry once it is ready for use and has been set(). To
+ * conserve objects, EntryFutures synchronize on themselves.
+ */
+ private static class EntryFuture {
+
+ private static final Object unset = new Object();
+ private final Thread owner = Thread.currentThread();
+ private Object entry = unset;
+
+ /**
+ * Attempts to set the value contained by this EntryFuture. If the
+ * EntryFuture's value has not been set already, then the value is
+ * saved, any callers blocked in the get() method are notified, and
+ * true is returned. If the value has already been set, then no saving
+ * or notification occurs, and false is returned.
+ */
+ synchronized boolean set(Object entry) {
+ if (this.entry != unset) {
+ return false;
+ }
+ this.entry = entry;
+ notifyAll();
+ return true;
+ }
+
+ /**
+ * Returns the value contained by this EntryFuture, blocking if
+ * necessary until a value is set.
+ */
+ synchronized Object get() {
+ boolean interrupted = false;
+ while (entry == unset) {
+ try {
+ wait();
+ } catch (InterruptedException ex) {
+ interrupted = true;
+ }
+ }
+ if (interrupted) {
+ AccessController.doPrivileged(
+ new PrivilegedAction<Void>() {
+ public Void run() {
+ Thread.currentThread().interrupt();
+ return null;
+ }
+ }
+ );
+ }
+ return entry;
+ }
+
+ /**
+ * Returns the thread that created this EntryFuture.
+ */
+ Thread getOwner() {
+ return owner;
+ }
+ }
+
+ /**
+ * Creates local class descriptor representing given class.
+ */
+ private ObjectStreamClass(final Class<?> cl) {
+ this.cl = cl;
+ name = cl.getName();
+ isProxy = Proxy.isProxyClass(cl);
+ isEnum = Enum.class.isAssignableFrom(cl);
+ serializable = Serializable.class.isAssignableFrom(cl);
+ externalizable = Externalizable.class.isAssignableFrom(cl);
+
+ Class<?> superCl = cl.getSuperclass();
+ superDesc = (superCl != null) ? lookup(superCl, false) : null;
+ localDesc = this;
+
+ if (serializable) {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run() {
+ if (isEnum) {
+ suid = Long.valueOf(0);
+ fields = NO_FIELDS;
+ return null;
+ }
+ if (cl.isArray()) {
+ fields = NO_FIELDS;
+ return null;
+ }
+
+ suid = getDeclaredSUID(cl);
+ try {
+ fields = getSerialFields(cl);
+ computeFieldOffsets();
+ } catch (InvalidClassException e) {
+ serializeEx = deserializeEx =
+ new ExceptionInfo(e.classname, e.getMessage());
+ fields = NO_FIELDS;
+ }
+
+ if (externalizable) {
+ cons = getExternalizableConstructor(cl);
+ } else {
+ cons = getSerializableConstructor(cl);
+ writeObjectMethod = getPrivateMethod(cl, "writeObject",
+ new Class<?>[] { ObjectOutputStream.class },
+ Void.TYPE);
+ readObjectMethod = getPrivateMethod(cl, "readObject",
+ new Class<?>[] { ObjectInputStream.class },
+ Void.TYPE);
+ readObjectNoDataMethod = getPrivateMethod(
+ cl, "readObjectNoData", null, Void.TYPE);
+ hasWriteObjectData = (writeObjectMethod != null);
+ }
+ writeReplaceMethod = getInheritableMethod(
+ cl, "writeReplace", null, Object.class);
+ readResolveMethod = getInheritableMethod(
+ cl, "readResolve", null, Object.class);
+ return null;
+ }
+ });
+ } else {
+ suid = Long.valueOf(0);
+ fields = NO_FIELDS;
+ }
+
+ try {
+ fieldRefl = getReflector(fields, this);
+ } catch (InvalidClassException ex) {
+ // field mismatches impossible when matching local fields vs. self
+ throw new InternalError(ex);
+ }
+
+ if (deserializeEx == null) {
+ if (isEnum) {
+ deserializeEx = new ExceptionInfo(name, "enum type");
+ } else if (cons == null) {
+ deserializeEx = new ExceptionInfo(name, "no valid constructor");
+ }
+ }
+ for (int i = 0; i < fields.length; i++) {
+ if (fields[i].getField() == null) {
+ defaultSerializeEx = new ExceptionInfo(
+ name, "unmatched serializable field(s) declared");
+ }
+ }
+ initialized = true;
+ }
+
+ /**
+ * Creates blank class descriptor which should be initialized via a
+ * subsequent call to initProxy(), initNonProxy() or readNonProxy().
+ */
+ ObjectStreamClass() {
+ }
+
+ /**
+ * Initializes class descriptor representing a proxy class.
+ */
+ void initProxy(Class<?> cl,
+ ClassNotFoundException resolveEx,
+ ObjectStreamClass superDesc)
+ throws InvalidClassException
+ {
+ ObjectStreamClass osc = null;
+ if (cl != null) {
+ osc = lookup(cl, true);
+ if (!osc.isProxy) {
+ throw new InvalidClassException(
+ "cannot bind proxy descriptor to a non-proxy class");
+ }
+ }
+ this.cl = cl;
+ this.resolveEx = resolveEx;
+ this.superDesc = superDesc;
+ isProxy = true;
+ serializable = true;
+ suid = Long.valueOf(0);
+ fields = NO_FIELDS;
+ if (osc != null) {
+ localDesc = osc;
+ name = localDesc.name;
+ externalizable = localDesc.externalizable;
+ writeReplaceMethod = localDesc.writeReplaceMethod;
+ readResolveMethod = localDesc.readResolveMethod;
+ deserializeEx = localDesc.deserializeEx;
+ cons = localDesc.cons;
+ }
+ fieldRefl = getReflector(fields, localDesc);
+ initialized = true;
+ }
+
+ /**
+ * Initializes class descriptor representing a non-proxy class.
+ */
+ void initNonProxy(ObjectStreamClass model,
+ Class<?> cl,
+ ClassNotFoundException resolveEx,
+ ObjectStreamClass superDesc)
+ throws InvalidClassException
+ {
+ long suid = Long.valueOf(model.getSerialVersionUID());
+ ObjectStreamClass osc = null;
+ if (cl != null) {
+ osc = lookup(cl, true);
+ if (osc.isProxy) {
+ throw new InvalidClassException(
+ "cannot bind non-proxy descriptor to a proxy class");
+ }
+ if (model.isEnum != osc.isEnum) {
+ throw new InvalidClassException(model.isEnum ?
+ "cannot bind enum descriptor to a non-enum class" :
+ "cannot bind non-enum descriptor to an enum class");
+ }
+
+ if (model.serializable == osc.serializable &&
+ !cl.isArray() &&
+ suid != osc.getSerialVersionUID()) {
+ throw new InvalidClassException(osc.name,
+ "local class incompatible: " +
+ "stream classdesc serialVersionUID = " + suid +
+ ", local class serialVersionUID = " +
+ osc.getSerialVersionUID());
+ }
+
+ if (!classNamesEqual(model.name, osc.name)) {
+ throw new InvalidClassException(osc.name,
+ "local class name incompatible with stream class " +
+ "name \"" + model.name + "\"");
+ }
+
+ if (!model.isEnum) {
+ if ((model.serializable == osc.serializable) &&
+ (model.externalizable != osc.externalizable)) {
+ throw new InvalidClassException(osc.name,
+ "Serializable incompatible with Externalizable");
+ }
+
+ if ((model.serializable != osc.serializable) ||
+ (model.externalizable != osc.externalizable) ||
+ !(model.serializable || model.externalizable)) {
+ deserializeEx = new ExceptionInfo(
+ osc.name, "class invalid for deserialization");
+ }
+ }
+ }
+
+ this.cl = cl;
+ this.resolveEx = resolveEx;
+ this.superDesc = superDesc;
+ name = model.name;
+ this.suid = suid;
+ isProxy = false;
+ isEnum = model.isEnum;
+ serializable = model.serializable;
+ externalizable = model.externalizable;
+ hasBlockExternalData = model.hasBlockExternalData;
+ hasWriteObjectData = model.hasWriteObjectData;
+ fields = model.fields;
+ primDataSize = model.primDataSize;
+ numObjFields = model.numObjFields;
+
+ if (osc != null) {
+ localDesc = osc;
+ writeObjectMethod = localDesc.writeObjectMethod;
+ readObjectMethod = localDesc.readObjectMethod;
+ readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
+ writeReplaceMethod = localDesc.writeReplaceMethod;
+ readResolveMethod = localDesc.readResolveMethod;
+ if (deserializeEx == null) {
+ deserializeEx = localDesc.deserializeEx;
+ }
+ cons = localDesc.cons;
+ }
+
+ fieldRefl = getReflector(fields, localDesc);
+ // reassign to matched fields so as to reflect local unshared settings
+ fields = fieldRefl.getFields();
+ initialized = true;
+ }
+
+ /**
+ * Reads non-proxy class descriptor information from given input stream.
+ * The resulting class descriptor is not fully functional; it can only be
+ * used as input to the ObjectInputStream.resolveClass() and
+ * ObjectStreamClass.initNonProxy() methods.
+ */
+ void readNonProxy(ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ name = in.readUTF();
+ suid = Long.valueOf(in.readLong());
+ isProxy = false;
+
+ byte flags = in.readByte();
+ hasWriteObjectData =
+ ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0);
+ hasBlockExternalData =
+ ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0);
+ externalizable =
+ ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0);
+ boolean sflag =
+ ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0);
+ if (externalizable && sflag) {
+ throw new InvalidClassException(
+ name, "serializable and externalizable flags conflict");
+ }
+ serializable = externalizable || sflag;
+ isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0);
+ if (isEnum && suid.longValue() != 0L) {
+ throw new InvalidClassException(name,
+ "enum descriptor has non-zero serialVersionUID: " + suid);
+ }
+
+ int numFields = in.readShort();
+ if (isEnum && numFields != 0) {
+ throw new InvalidClassException(name,
+ "enum descriptor has non-zero field count: " + numFields);
+ }
+ fields = (numFields > 0) ?
+ new ObjectStreamField[numFields] : NO_FIELDS;
+ for (int i = 0; i < numFields; i++) {
+ char tcode = (char) in.readByte();
+ String fname = in.readUTF();
+ String signature = ((tcode == 'L') || (tcode == '[')) ?
+ in.readTypeString() : new String(new char[] { tcode });
+ try {
+ fields[i] = new ObjectStreamField(fname, signature, false);
+ } catch (RuntimeException e) {
+ throw (IOException) new InvalidClassException(name,
+ "invalid descriptor for field " + fname).initCause(e);
+ }
+ }
+ computeFieldOffsets();
+ }
+
+ /**
+ * Writes non-proxy class descriptor information to given output stream.
+ */
+ void writeNonProxy(ObjectOutputStream out) throws IOException {
+ out.writeUTF(name);
+ out.writeLong(getSerialVersionUID());
+
+ byte flags = 0;
+ if (externalizable) {
+ flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
+ int protocol = out.getProtocolVersion();
+ if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
+ flags |= ObjectStreamConstants.SC_BLOCK_DATA;
+ }
+ } else if (serializable) {
+ flags |= ObjectStreamConstants.SC_SERIALIZABLE;
+ }
+ if (hasWriteObjectData) {
+ flags |= ObjectStreamConstants.SC_WRITE_METHOD;
+ }
+ if (isEnum) {
+ flags |= ObjectStreamConstants.SC_ENUM;
+ }
+ out.writeByte(flags);
+
+ out.writeShort(fields.length);
+ for (int i = 0; i < fields.length; i++) {
+ ObjectStreamField f = fields[i];
+ out.writeByte(f.getTypeCode());
+ out.writeUTF(f.getName());
+ if (!f.isPrimitive()) {
+ out.writeTypeString(f.getTypeString());
+ }
+ }
+ }
+
+ /**
+ * Returns ClassNotFoundException (if any) thrown while attempting to
+ * resolve local class corresponding to this class descriptor.
+ */
+ ClassNotFoundException getResolveException() {
+ return resolveEx;
+ }
+
+ /**
+ * Throws InternalError if not initialized.
+ */
+ private final void requireInitialized() {
+ if (!initialized)
+ throw new InternalError("Unexpected call when not initialized");
+ }
+
+ /**
+ * Throws an InvalidClassException if object instances referencing this
+ * class descriptor should not be allowed to deserialize. This method does
+ * not apply to deserialization of enum constants.
+ */
+ void checkDeserialize() throws InvalidClassException {
+ requireInitialized();
+ if (deserializeEx != null) {
+ throw deserializeEx.newInvalidClassException();
+ }
+ }
+
+ /**
+ * Throws an InvalidClassException if objects whose class is represented by
+ * this descriptor should not be allowed to serialize. This method does
+ * not apply to serialization of enum constants.
+ */
+ void checkSerialize() throws InvalidClassException {
+ requireInitialized();
+ if (serializeEx != null) {
+ throw serializeEx.newInvalidClassException();
+ }
+ }
+
+ /**
+ * Throws an InvalidClassException if objects whose class is represented by
+ * this descriptor should not be permitted to use default serialization
+ * (e.g., if the class declares serializable fields that do not correspond
+ * to actual fields, and hence must use the GetField API). This method
+ * does not apply to deserialization of enum constants.
+ */
+ void checkDefaultSerialize() throws InvalidClassException {
+ requireInitialized();
+ if (defaultSerializeEx != null) {
+ throw defaultSerializeEx.newInvalidClassException();
+ }
+ }
+
+ /**
+ * Returns superclass descriptor. Note that on the receiving side, the
+ * superclass descriptor may be bound to a class that is not a superclass
+ * of the subclass descriptor's bound class.
+ */
+ ObjectStreamClass getSuperDesc() {
+ requireInitialized();
+ return superDesc;
+ }
+
+ /**
+ * Returns the "local" class descriptor for the class associated with this
+ * class descriptor (i.e., the result of
+ * ObjectStreamClass.lookup(this.forClass())) or null if there is no class
+ * associated with this descriptor.
+ */
+ ObjectStreamClass getLocalDesc() {
+ requireInitialized();
+ return localDesc;
+ }
+
+ /**
+ * Returns arrays of ObjectStreamFields representing the serializable
+ * fields of the represented class. If copy is true, a clone of this class
+ * descriptor's field array is returned, otherwise the array itself is
+ * returned.
+ */
+ ObjectStreamField[] getFields(boolean copy) {
+ return copy ? fields.clone() : fields;
+ }
+
+ /**
+ * Looks up a serializable field of the represented class by name and type.
+ * A specified type of null matches all types, Object.class matches all
+ * non-primitive types, and any other non-null type matches assignable
+ * types only. Returns matching field, or null if no match found.
+ */
+ ObjectStreamField getField(String name, Class<?> type) {
+ for (int i = 0; i < fields.length; i++) {
+ ObjectStreamField f = fields[i];
+ if (f.getName().equals(name)) {
+ if (type == null ||
+ (type == Object.class && !f.isPrimitive()))
+ {
+ return f;
+ }
+ Class<?> ftype = f.getType();
+ if (ftype != null && type.isAssignableFrom(ftype)) {
+ return f;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if class descriptor represents a dynamic proxy class, false
+ * otherwise.
+ */
+ boolean isProxy() {
+ requireInitialized();
+ return isProxy;
+ }
+
+ /**
+ * Returns true if class descriptor represents an enum type, false
+ * otherwise.
+ */
+ boolean isEnum() {
+ requireInitialized();
+ return isEnum;
+ }
+
+ /**
+ * Returns true if represented class implements Externalizable, false
+ * otherwise.
+ */
+ boolean isExternalizable() {
+ requireInitialized();
+ return externalizable;
+ }
+
+ /**
+ * Returns true if represented class implements Serializable, false
+ * otherwise.
+ */
+ boolean isSerializable() {
+ requireInitialized();
+ return serializable;
+ }
+
+ /**
+ * Returns true if class descriptor represents externalizable class that
+ * has written its data in 1.2 (block data) format, false otherwise.
+ */
+ boolean hasBlockExternalData() {
+ requireInitialized();
+ return hasBlockExternalData;
+ }
+
+ /**
+ * Returns true if class descriptor represents serializable (but not
+ * externalizable) class which has written its data via a custom
+ * writeObject() method, false otherwise.
+ */
+ boolean hasWriteObjectData() {
+ requireInitialized();
+ return hasWriteObjectData;
+ }
+
+ /**
+ * Returns true if represented class is serializable/externalizable and can
+ * be instantiated by the serialization runtime--i.e., if it is
+ * externalizable and defines a public no-arg constructor, or if it is
+ * non-externalizable and its first non-serializable superclass defines an
+ * accessible no-arg constructor. Otherwise, returns false.
+ */
+ boolean isInstantiable() {
+ requireInitialized();
+ return (cons != null);
+ }
+
+ /**
+ * Returns true if represented class is serializable (but not
+ * externalizable) and defines a conformant writeObject method. Otherwise,
+ * returns false.
+ */
+ boolean hasWriteObjectMethod() {
+ requireInitialized();
+ return (writeObjectMethod != null);
+ }
+
+ /**
+ * Returns true if represented class is serializable (but not
+ * externalizable) and defines a conformant readObject method. Otherwise,
+ * returns false.
+ */
+ boolean hasReadObjectMethod() {
+ requireInitialized();
+ return (readObjectMethod != null);
+ }
+
+ /**
+ * Returns true if represented class is serializable (but not
+ * externalizable) and defines a conformant readObjectNoData method.
+ * Otherwise, returns false.
+ */
+ boolean hasReadObjectNoDataMethod() {
+ requireInitialized();
+ return (readObjectNoDataMethod != null);
+ }
+
+ /**
+ * Returns true if represented class is serializable or externalizable and
+ * defines a conformant writeReplace method. Otherwise, returns false.
+ */
+ boolean hasWriteReplaceMethod() {
+ requireInitialized();
+ return (writeReplaceMethod != null);
+ }
+
+ /**
+ * Returns true if represented class is serializable or externalizable and
+ * defines a conformant readResolve method. Otherwise, returns false.
+ */
+ boolean hasReadResolveMethod() {
+ requireInitialized();
+ return (readResolveMethod != null);
+ }
+
+ /**
+ * Creates a new instance of the represented class. If the class is
+ * externalizable, invokes its public no-arg constructor; otherwise, if the
+ * class is serializable, invokes the no-arg constructor of the first
+ * non-serializable superclass. Throws UnsupportedOperationException if
+ * this class descriptor is not associated with a class, if the associated
+ * class is non-serializable or if the appropriate no-arg constructor is
+ * inaccessible/unavailable.
+ */
+ Object newInstance()
+ throws InstantiationException, InvocationTargetException,
+ UnsupportedOperationException
+ {
+ requireInitialized();
+ if (cons != null) {
+ try {
+ return cons.newInstance();
+ } catch (IllegalAccessException ex) {
+ // should not occur, as access checks have been suppressed
+ throw new InternalError(ex);
+ }
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Invokes the writeObject method of the represented serializable class.
+ * Throws UnsupportedOperationException if this class descriptor is not
+ * associated with a class, or if the class is externalizable,
+ * non-serializable or does not define writeObject.
+ */
+ void invokeWriteObject(Object obj, ObjectOutputStream out)
+ throws IOException, UnsupportedOperationException
+ {
+ requireInitialized();
+ if (writeObjectMethod != null) {
+ try {
+ writeObjectMethod.invoke(obj, new Object[]{ out });
+ } catch (InvocationTargetException ex) {
+ Throwable th = ex.getTargetException();
+ if (th instanceof IOException) {
+ throw (IOException) th;
+ } else {
+ throwMiscException(th);
+ }
+ } catch (IllegalAccessException ex) {
+ // should not occur, as access checks have been suppressed
+ throw new InternalError(ex);
+ }
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Invokes the readObject method of the represented serializable class.
+ * Throws UnsupportedOperationException if this class descriptor is not
+ * associated with a class, or if the class is externalizable,
+ * non-serializable or does not define readObject.
+ */
+ void invokeReadObject(Object obj, ObjectInputStream in)
+ throws ClassNotFoundException, IOException,
+ UnsupportedOperationException
+ {
+ requireInitialized();
+ if (readObjectMethod != null) {
+ try {
+ readObjectMethod.invoke(obj, new Object[]{ in });
+ } catch (InvocationTargetException ex) {
+ Throwable th = ex.getTargetException();
+ if (th instanceof ClassNotFoundException) {
+ throw (ClassNotFoundException) th;
+ } else if (th instanceof IOException) {
+ throw (IOException) th;
+ } else {
+ throwMiscException(th);
+ }
+ } catch (IllegalAccessException ex) {
+ // should not occur, as access checks have been suppressed
+ throw new InternalError(ex);
+ }
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Invokes the readObjectNoData method of the represented serializable
+ * class. Throws UnsupportedOperationException if this class descriptor is
+ * not associated with a class, or if the class is externalizable,
+ * non-serializable or does not define readObjectNoData.
+ */
+ void invokeReadObjectNoData(Object obj)
+ throws IOException, UnsupportedOperationException
+ {
+ requireInitialized();
+ if (readObjectNoDataMethod != null) {
+ try {
+ readObjectNoDataMethod.invoke(obj, (Object[]) null);
+ } catch (InvocationTargetException ex) {
+ Throwable th = ex.getTargetException();
+ if (th instanceof ObjectStreamException) {
+ throw (ObjectStreamException) th;
+ } else {
+ throwMiscException(th);
+ }
+ } catch (IllegalAccessException ex) {
+ // should not occur, as access checks have been suppressed
+ throw new InternalError(ex);
+ }
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Invokes the writeReplace method of the represented serializable class and
+ * returns the result. Throws UnsupportedOperationException if this class
+ * descriptor is not associated with a class, or if the class is
+ * non-serializable or does not define writeReplace.
+ */
+ Object invokeWriteReplace(Object obj)
+ throws IOException, UnsupportedOperationException
+ {
+ requireInitialized();
+ if (writeReplaceMethod != null) {
+ try {
+ return writeReplaceMethod.invoke(obj, (Object[]) null);
+ } catch (InvocationTargetException ex) {
+ Throwable th = ex.getTargetException();
+ if (th instanceof ObjectStreamException) {
+ throw (ObjectStreamException) th;
+ } else {
+ throwMiscException(th);
+ throw new InternalError(th); // never reached
+ }
+ } catch (IllegalAccessException ex) {
+ // should not occur, as access checks have been suppressed
+ throw new InternalError(ex);
+ }
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Invokes the readResolve method of the represented serializable class and
+ * returns the result. Throws UnsupportedOperationException if this class
+ * descriptor is not associated with a class, or if the class is
+ * non-serializable or does not define readResolve.
+ */
+ Object invokeReadResolve(Object obj)
+ throws IOException, UnsupportedOperationException
+ {
+ requireInitialized();
+ if (readResolveMethod != null) {
+ try {
+ return readResolveMethod.invoke(obj, (Object[]) null);
+ } catch (InvocationTargetException ex) {
+ Throwable th = ex.getTargetException();
+ if (th instanceof ObjectStreamException) {
+ throw (ObjectStreamException) th;
+ } else {
+ throwMiscException(th);
+ throw new InternalError(th); // never reached
+ }
+ } catch (IllegalAccessException ex) {
+ // should not occur, as access checks have been suppressed
+ throw new InternalError(ex);
+ }
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Class representing the portion of an object's serialized form allotted
+ * to data described by a given class descriptor. If "hasData" is false,
+ * the object's serialized form does not contain data associated with the
+ * class descriptor.
+ */
+ static class ClassDataSlot {
+
+ /** class descriptor "occupying" this slot */
+ final ObjectStreamClass desc;
+ /** true if serialized form includes data for this slot's descriptor */
+ final boolean hasData;
+
+ ClassDataSlot(ObjectStreamClass desc, boolean hasData) {
+ this.desc = desc;
+ this.hasData = hasData;
+ }
+ }
+
+ /**
+ * Returns array of ClassDataSlot instances representing the data layout
+ * (including superclass data) for serialized objects described by this
+ * class descriptor. ClassDataSlots are ordered by inheritance with those
+ * containing "higher" superclasses appearing first. The final
+ * ClassDataSlot contains a reference to this descriptor.
+ */
+ ClassDataSlot[] getClassDataLayout() throws InvalidClassException {
+ // REMIND: synchronize instead of relying on volatile?
+ if (dataLayout == null) {
+ dataLayout = getClassDataLayout0();
+ }
+ return dataLayout;
+ }
+
+ private ClassDataSlot[] getClassDataLayout0()
+ throws InvalidClassException
+ {
+ ArrayList<ClassDataSlot> slots = new ArrayList<>();
+ Class<?> start = cl, end = cl;
+
+ // locate closest non-serializable superclass
+ while (end != null && Serializable.class.isAssignableFrom(end)) {
+ end = end.getSuperclass();
+ }
+
+ HashSet<String> oscNames = new HashSet<>(3);
+
+ for (ObjectStreamClass d = this; d != null; d = d.superDesc) {
+ if (oscNames.contains(d.name)) {
+ throw new InvalidClassException("Circular reference.");
+ } else {
+ oscNames.add(d.name);
+ }
+
+ // search up inheritance hierarchy for class with matching name
+ String searchName = (d.cl != null) ? d.cl.getName() : d.name;
+ Class<?> match = null;
+ for (Class<?> c = start; c != end; c = c.getSuperclass()) {
+ if (searchName.equals(c.getName())) {
+ match = c;
+ break;
+ }
+ }
+
+ // add "no data" slot for each unmatched class below match
+ if (match != null) {
+ for (Class<?> c = start; c != match; c = c.getSuperclass()) {
+ slots.add(new ClassDataSlot(
+ ObjectStreamClass.lookup(c, true), false));
+ }
+ start = match.getSuperclass();
+ }
+
+ // record descriptor/class pairing
+ slots.add(new ClassDataSlot(d.getVariantFor(match), true));
+ }
+
+ // add "no data" slot for any leftover unmatched classes
+ for (Class<?> c = start; c != end; c = c.getSuperclass()) {
+ slots.add(new ClassDataSlot(
+ ObjectStreamClass.lookup(c, true), false));
+ }
+
+ // order slots from superclass -> subclass
+ Collections.reverse(slots);
+ return slots.toArray(new ClassDataSlot[slots.size()]);
+ }
+
+ /**
+ * Returns aggregate size (in bytes) of marshalled primitive field values
+ * for represented class.
+ */
+ int getPrimDataSize() {
+ return primDataSize;
+ }
+
+ /**
+ * Returns number of non-primitive serializable fields of represented
+ * class.
+ */
+ int getNumObjFields() {
+ return numObjFields;
+ }
+
+ /**
+ * Fetches the serializable primitive field values of object obj and
+ * marshals them into byte array buf starting at offset 0. It is the
+ * responsibility of the caller to ensure that obj is of the proper type if
+ * non-null.
+ */
+ void getPrimFieldValues(Object obj, byte[] buf) {
+ fieldRefl.getPrimFieldValues(obj, buf);
+ }
+
+ /**
+ * Sets the serializable primitive fields of object obj using values
+ * unmarshalled from byte array buf starting at offset 0. It is the
+ * responsibility of the caller to ensure that obj is of the proper type if
+ * non-null.
+ */
+ void setPrimFieldValues(Object obj, byte[] buf) {
+ fieldRefl.setPrimFieldValues(obj, buf);
+ }
+
+ /**
+ * Fetches the serializable object field values of object obj and stores
+ * them in array vals starting at offset 0. It is the responsibility of
+ * the caller to ensure that obj is of the proper type if non-null.
+ */
+ void getObjFieldValues(Object obj, Object[] vals) {
+ fieldRefl.getObjFieldValues(obj, vals);
+ }
+
+ /**
+ * Sets the serializable object fields of object obj using values from
+ * array vals starting at offset 0. It is the responsibility of the caller
+ * to ensure that obj is of the proper type if non-null.
+ */
+ void setObjFieldValues(Object obj, Object[] vals) {
+ fieldRefl.setObjFieldValues(obj, vals);
+ }
+
+ /**
+ * Calculates and sets serializable field offsets, as well as primitive
+ * data size and object field count totals. Throws InvalidClassException
+ * if fields are illegally ordered.
+ */
+ private void computeFieldOffsets() throws InvalidClassException {
+ primDataSize = 0;
+ numObjFields = 0;
+ int firstObjIndex = -1;
+
+ for (int i = 0; i < fields.length; i++) {
+ ObjectStreamField f = fields[i];
+ switch (f.getTypeCode()) {
+ case 'Z':
+ case 'B':
+ f.setOffset(primDataSize++);
+ break;
+
+ case 'C':
+ case 'S':
+ f.setOffset(primDataSize);
+ primDataSize += 2;
+ break;
+
+ case 'I':
+ case 'F':
+ f.setOffset(primDataSize);
+ primDataSize += 4;
+ break;
+
+ case 'J':
+ case 'D':
+ f.setOffset(primDataSize);
+ primDataSize += 8;
+ break;
+
+ case '[':
+ case 'L':
+ f.setOffset(numObjFields++);
+ if (firstObjIndex == -1) {
+ firstObjIndex = i;
+ }
+ break;
+
+ default:
+ throw new InternalError();
+ }
+ }
+ if (firstObjIndex != -1 &&
+ firstObjIndex + numObjFields != fields.length)
+ {
+ throw new InvalidClassException(name, "illegal field order");
+ }
+ }
+
+ /**
+ * If given class is the same as the class associated with this class
+ * descriptor, returns reference to this class descriptor. Otherwise,
+ * returns variant of this class descriptor bound to given class.
+ */
+ private ObjectStreamClass getVariantFor(Class<?> cl)
+ throws InvalidClassException
+ {
+ if (this.cl == cl) {
+ return this;
+ }
+ ObjectStreamClass desc = new ObjectStreamClass();
+ if (isProxy) {
+ desc.initProxy(cl, null, superDesc);
+ } else {
+ desc.initNonProxy(this, cl, null, superDesc);
+ }
+ return desc;
+ }
+
+ /**
+ * Returns public no-arg constructor of given class, or null if none found.
+ * Access checks are disabled on the returned constructor (if any), since
+ * the defining class may still be non-public.
+ */
+ private static Constructor<?> getExternalizableConstructor(Class<?> cl) {
+ try {
+ Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null);
+ cons.setAccessible(true);
+ return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
+ cons : null;
+ } catch (NoSuchMethodException ex) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns subclass-accessible no-arg constructor of first non-serializable
+ * superclass, or null if none found. Access checks are disabled on the
+ * returned constructor (if any).
+ */
+ private static Constructor<?> getSerializableConstructor(Class<?> cl) {
+ Class<?> initCl = cl;
+ while (Serializable.class.isAssignableFrom(initCl)) {
+ if ((initCl = initCl.getSuperclass()) == null) {
+ return null;
+ }
+ }
+ try {
+ Constructor<?> cons = initCl.getDeclaredConstructor((Class<?>[]) null);
+ int mods = cons.getModifiers();
+ if ((mods & Modifier.PRIVATE) != 0 ||
+ ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
+ !packageEquals(cl, initCl)))
+ {
+ return null;
+ }
+ // BEGIN Android-changed: Serialization constructor obtained differently.
+ // cons = reflFactory.newConstructorForSerialization(cl, cons);
+ if (cons.getDeclaringClass() != cl) {
+ cons = cons.serializationCopy(cons.getDeclaringClass(), cl);
+ }
+ // END Android-changed: Serialization constructor obtained differently.
+ cons.setAccessible(true);
+ return cons;
+ } catch (NoSuchMethodException ex) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns non-static, non-abstract method with given signature provided it
+ * is defined by or accessible (via inheritance) by the given class, or
+ * null if no match found. Access checks are disabled on the returned
+ * method (if any).
+ */
+ private static Method getInheritableMethod(Class<?> cl, String name,
+ Class<?>[] argTypes,
+ Class<?> returnType)
+ {
+ Method meth = null;
+ Class<?> defCl = cl;
+ while (defCl != null) {
+ try {
+ meth = defCl.getDeclaredMethod(name, argTypes);
+ break;
+ } catch (NoSuchMethodException ex) {
+ defCl = defCl.getSuperclass();
+ }
+ }
+
+ if ((meth == null) || (meth.getReturnType() != returnType)) {
+ return null;
+ }
+ meth.setAccessible(true);
+ int mods = meth.getModifiers();
+ if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
+ return null;
+ } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
+ return meth;
+ } else if ((mods & Modifier.PRIVATE) != 0) {
+ return (cl == defCl) ? meth : null;
+ } else {
+ return packageEquals(cl, defCl) ? meth : null;
+ }
+ }
+
+ /**
+ * Returns non-static private method with given signature defined by given
+ * class, or null if none found. Access checks are disabled on the
+ * returned method (if any).
+ */
+ private static Method getPrivateMethod(Class<?> cl, String name,
+ Class<?>[] argTypes,
+ Class<?> returnType)
+ {
+ try {
+ Method meth = cl.getDeclaredMethod(name, argTypes);
+ meth.setAccessible(true);
+ int mods = meth.getModifiers();
+ return ((meth.getReturnType() == returnType) &&
+ ((mods & Modifier.STATIC) == 0) &&
+ ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
+ } catch (NoSuchMethodException ex) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns true if classes are defined in the same runtime package, false
+ * otherwise.
+ */
+ private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
+ return (cl1.getClassLoader() == cl2.getClassLoader() &&
+ getPackageName(cl1).equals(getPackageName(cl2)));
+ }
+
+ /**
+ * Returns package name of given class.
+ */
+ private static String getPackageName(Class<?> cl) {
+ String s = cl.getName();
+ int i = s.lastIndexOf('[');
+ if (i >= 0) {
+ s = s.substring(i + 2);
+ }
+ i = s.lastIndexOf('.');
+ return (i >= 0) ? s.substring(0, i) : "";
+ }
+
+ /**
+ * Compares class names for equality, ignoring package names. Returns true
+ * if class names equal, false otherwise.
+ */
+ private static boolean classNamesEqual(String name1, String name2) {
+ name1 = name1.substring(name1.lastIndexOf('.') + 1);
+ name2 = name2.substring(name2.lastIndexOf('.') + 1);
+ return name1.equals(name2);
+ }
+
+ /**
+ * Returns JVM type signature for given class.
+ */
+ private static String getClassSignature(Class<?> cl) {
+ StringBuilder sbuf = new StringBuilder();
+ while (cl.isArray()) {
+ sbuf.append('[');
+ cl = cl.getComponentType();
+ }
+ if (cl.isPrimitive()) {
+ if (cl == Integer.TYPE) {
+ sbuf.append('I');
+ } else if (cl == Byte.TYPE) {
+ sbuf.append('B');
+ } else if (cl == Long.TYPE) {
+ sbuf.append('J');
+ } else if (cl == Float.TYPE) {
+ sbuf.append('F');
+ } else if (cl == Double.TYPE) {
+ sbuf.append('D');
+ } else if (cl == Short.TYPE) {
+ sbuf.append('S');
+ } else if (cl == Character.TYPE) {
+ sbuf.append('C');
+ } else if (cl == Boolean.TYPE) {
+ sbuf.append('Z');
+ } else if (cl == Void.TYPE) {
+ sbuf.append('V');
+ } else {
+ throw new InternalError();
+ }
+ } else {
+ sbuf.append('L' + cl.getName().replace('.', '/') + ';');
+ }
+ return sbuf.toString();
+ }
+
+ /**
+ * Returns JVM type signature for given list of parameters and return type.
+ */
+ private static String getMethodSignature(Class<?>[] paramTypes,
+ Class<?> retType)
+ {
+ StringBuilder sbuf = new StringBuilder();
+ sbuf.append('(');
+ for (int i = 0; i < paramTypes.length; i++) {
+ sbuf.append(getClassSignature(paramTypes[i]));
+ }
+ sbuf.append(')');
+ sbuf.append(getClassSignature(retType));
+ return sbuf.toString();
+ }
+
+ /**
+ * Convenience method for throwing an exception that is either a
+ * RuntimeException, Error, or of some unexpected type (in which case it is
+ * wrapped inside an IOException).
+ */
+ private static void throwMiscException(Throwable th) throws IOException {
+ if (th instanceof RuntimeException) {
+ throw (RuntimeException) th;
+ } else if (th instanceof Error) {
+ throw (Error) th;
+ } else {
+ IOException ex = new IOException("unexpected exception type");
+ ex.initCause(th);
+ throw ex;
+ }
+ }
+
+ /**
+ * Returns ObjectStreamField array describing the serializable fields of
+ * the given class. Serializable fields backed by an actual field of the
+ * class are represented by ObjectStreamFields with corresponding non-null
+ * Field objects. Throws InvalidClassException if the (explicitly
+ * declared) serializable fields are invalid.
+ */
+ private static ObjectStreamField[] getSerialFields(Class<?> cl)
+ throws InvalidClassException
+ {
+ ObjectStreamField[] fields;
+ if (Serializable.class.isAssignableFrom(cl) &&
+ !Externalizable.class.isAssignableFrom(cl) &&
+ !Proxy.isProxyClass(cl) &&
+ !cl.isInterface())
+ {
+ if ((fields = getDeclaredSerialFields(cl)) == null) {
+ fields = getDefaultSerialFields(cl);
+ }
+ Arrays.sort(fields);
+ } else {
+ fields = NO_FIELDS;
+ }
+ return fields;
+ }
+
+ /**
+ * Returns serializable fields of given class as defined explicitly by a
+ * "serialPersistentFields" field, or null if no appropriate
+ * "serialPersistentFields" field is defined. Serializable fields backed
+ * by an actual field of the class are represented by ObjectStreamFields
+ * with corresponding non-null Field objects. For compatibility with past
+ * releases, a "serialPersistentFields" field with a null value is
+ * considered equivalent to not declaring "serialPersistentFields". Throws
+ * InvalidClassException if the declared serializable fields are
+ * invalid--e.g., if multiple fields share the same name.
+ */
+ private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl)
+ throws InvalidClassException
+ {
+ ObjectStreamField[] serialPersistentFields = null;
+ try {
+ Field f = cl.getDeclaredField("serialPersistentFields");
+ int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
+ if ((f.getModifiers() & mask) == mask) {
+ f.setAccessible(true);
+ serialPersistentFields = (ObjectStreamField[]) f.get(null);
+ }
+ } catch (Exception ex) {
+ }
+ if (serialPersistentFields == null) {
+ return null;
+ } else if (serialPersistentFields.length == 0) {
+ return NO_FIELDS;
+ }
+
+ ObjectStreamField[] boundFields =
+ new ObjectStreamField[serialPersistentFields.length];
+ Set<String> fieldNames = new HashSet<>(serialPersistentFields.length);
+
+ for (int i = 0; i < serialPersistentFields.length; i++) {
+ ObjectStreamField spf = serialPersistentFields[i];
+
+ String fname = spf.getName();
+ if (fieldNames.contains(fname)) {
+ throw new InvalidClassException(
+ "multiple serializable fields named " + fname);
+ }
+ fieldNames.add(fname);
+
+ try {
+ Field f = cl.getDeclaredField(fname);
+ if ((f.getType() == spf.getType()) &&
+ ((f.getModifiers() & Modifier.STATIC) == 0))
+ {
+ boundFields[i] =
+ new ObjectStreamField(f, spf.isUnshared(), true);
+ }
+ } catch (NoSuchFieldException ex) {
+ }
+ if (boundFields[i] == null) {
+ boundFields[i] = new ObjectStreamField(
+ fname, spf.getType(), spf.isUnshared());
+ }
+ }
+ return boundFields;
+ }
+
+ /**
+ * Returns array of ObjectStreamFields corresponding to all non-static
+ * non-transient fields declared by given class. Each ObjectStreamField
+ * contains a Field object for the field it represents. If no default
+ * serializable fields exist, NO_FIELDS is returned.
+ */
+ private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
+ Field[] clFields = cl.getDeclaredFields();
+ ArrayList<ObjectStreamField> list = new ArrayList<>();
+ int mask = Modifier.STATIC | Modifier.TRANSIENT;
+
+ for (int i = 0; i < clFields.length; i++) {
+ if ((clFields[i].getModifiers() & mask) == 0) {
+ list.add(new ObjectStreamField(clFields[i], false, true));
+ }
+ }
+ int size = list.size();
+ return (size == 0) ? NO_FIELDS :
+ list.toArray(new ObjectStreamField[size]);
+ }
+
+ /**
+ * Returns explicit serial version UID value declared by given class, or
+ * null if none.
+ */
+ private static Long getDeclaredSUID(Class<?> cl) {
+ try {
+ Field f = cl.getDeclaredField("serialVersionUID");
+ int mask = Modifier.STATIC | Modifier.FINAL;
+ if ((f.getModifiers() & mask) == mask) {
+ f.setAccessible(true);
+ return Long.valueOf(f.getLong(null));
+ }
+ } catch (Exception ex) {
+ }
+ return null;
+ }
+
+ /**
+ * Computes the default serial version UID value for the given class.
+ */
+ private static long computeDefaultSUID(Class<?> cl) {
+ if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
+ {
+ return 0L;
+ }
+
+ try {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ DataOutputStream dout = new DataOutputStream(bout);
+
+ dout.writeUTF(cl.getName());
+
+ int classMods = cl.getModifiers() &
+ (Modifier.PUBLIC | Modifier.FINAL |
+ Modifier.INTERFACE | Modifier.ABSTRACT);
+
+ /*
+ * compensate for javac bug in which ABSTRACT bit was set for an
+ * interface only if the interface declared methods
+ */
+ Method[] methods = cl.getDeclaredMethods();
+ if ((classMods & Modifier.INTERFACE) != 0) {
+ classMods = (methods.length > 0) ?
+ (classMods | Modifier.ABSTRACT) :
+ (classMods & ~Modifier.ABSTRACT);
+ }
+ dout.writeInt(classMods);
+
+ if (!cl.isArray()) {
+ /*
+ * compensate for change in 1.2FCS in which
+ * Class.getInterfaces() was modified to return Cloneable and
+ * Serializable for array classes.
+ */
+ Class<?>[] interfaces = cl.getInterfaces();
+ String[] ifaceNames = new String[interfaces.length];
+ for (int i = 0; i < interfaces.length; i++) {
+ ifaceNames[i] = interfaces[i].getName();
+ }
+ Arrays.sort(ifaceNames);
+ for (int i = 0; i < ifaceNames.length; i++) {
+ dout.writeUTF(ifaceNames[i]);
+ }
+ }
+
+ Field[] fields = cl.getDeclaredFields();
+ MemberSignature[] fieldSigs = new MemberSignature[fields.length];
+ for (int i = 0; i < fields.length; i++) {
+ fieldSigs[i] = new MemberSignature(fields[i]);
+ }
+ Arrays.sort(fieldSigs, new Comparator<MemberSignature>() {
+ public int compare(MemberSignature ms1, MemberSignature ms2) {
+ return ms1.name.compareTo(ms2.name);
+ }
+ });
+ for (int i = 0; i < fieldSigs.length; i++) {
+ MemberSignature sig = fieldSigs[i];
+ int mods = sig.member.getModifiers() &
+ (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
+ Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
+ Modifier.TRANSIENT);
+ if (((mods & Modifier.PRIVATE) == 0) ||
+ ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0))
+ {
+ dout.writeUTF(sig.name);
+ dout.writeInt(mods);
+ dout.writeUTF(sig.signature);
+ }
+ }
+
+ // BEGIN Android-changed: Fix/log clinit serialization workaround. b/29064453
+ // Prior to SDK 24 hasStaticInitializer() would return true if the superclass had a
+ // static initializer, that was contrary to the specification. In SDK 24 the default
+ // behavior was corrected but the old behavior was preserved for apps that targeted 23
+ // or below in order to maintain backwards compatibility.
+ //
+ // if (hasStaticInitializer(cl)) {
+ boolean inheritStaticInitializer =
+ (VMRuntime.getRuntime().getTargetSdkVersion()
+ <= MAX_SDK_TARGET_FOR_CLINIT_UIDGEN_WORKAROUND);
+ boolean warnIncompatibleSUIDChange = false;
+ if (hasStaticInitializer(cl, inheritStaticInitializer)) {
+ // If a static initializer was found but the current class does not have one then
+ // the class's default SUID will change if the app targets SDK > 24 so send a
+ // warning.
+ if (inheritStaticInitializer && !hasStaticInitializer(cl, false)) {
+ // Defer until hash has been calculated so the warning message can give precise
+ // instructions to the developer on how to fix the problems.
+ warnIncompatibleSUIDChange = true;
+ }
+ // END Android-changed: Fix/log clinit serialization workaround. b/29064453
+ dout.writeUTF("<clinit>");
+ dout.writeInt(Modifier.STATIC);
+ dout.writeUTF("()V");
+ }
+
+ Constructor<?>[] cons = cl.getDeclaredConstructors();
+ MemberSignature[] consSigs = new MemberSignature[cons.length];
+ for (int i = 0; i < cons.length; i++) {
+ consSigs[i] = new MemberSignature(cons[i]);
+ }
+ Arrays.sort(consSigs, new Comparator<MemberSignature>() {
+ public int compare(MemberSignature ms1, MemberSignature ms2) {
+ return ms1.signature.compareTo(ms2.signature);
+ }
+ });
+ for (int i = 0; i < consSigs.length; i++) {
+ MemberSignature sig = consSigs[i];
+ int mods = sig.member.getModifiers() &
+ (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
+ Modifier.STATIC | Modifier.FINAL |
+ Modifier.SYNCHRONIZED | Modifier.NATIVE |
+ Modifier.ABSTRACT | Modifier.STRICT);
+ if ((mods & Modifier.PRIVATE) == 0) {
+ dout.writeUTF("<init>");
+ dout.writeInt(mods);
+ dout.writeUTF(sig.signature.replace('/', '.'));
+ }
+ }
+
+ MemberSignature[] methSigs = new MemberSignature[methods.length];
+ for (int i = 0; i < methods.length; i++) {
+ methSigs[i] = new MemberSignature(methods[i]);
+ }
+ Arrays.sort(methSigs, new Comparator<MemberSignature>() {
+ public int compare(MemberSignature ms1, MemberSignature ms2) {
+ int comp = ms1.name.compareTo(ms2.name);
+ if (comp == 0) {
+ comp = ms1.signature.compareTo(ms2.signature);
+ }
+ return comp;
+ }
+ });
+ for (int i = 0; i < methSigs.length; i++) {
+ MemberSignature sig = methSigs[i];
+ int mods = sig.member.getModifiers() &
+ (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
+ Modifier.STATIC | Modifier.FINAL |
+ Modifier.SYNCHRONIZED | Modifier.NATIVE |
+ Modifier.ABSTRACT | Modifier.STRICT);
+ if ((mods & Modifier.PRIVATE) == 0) {
+ dout.writeUTF(sig.name);
+ dout.writeInt(mods);
+ dout.writeUTF(sig.signature.replace('/', '.'));
+ }
+ }
+
+ dout.flush();
+
+ MessageDigest md = MessageDigest.getInstance("SHA");
+ byte[] hashBytes = md.digest(bout.toByteArray());
+ long hash = 0;
+ for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
+ hash = (hash << 8) | (hashBytes[i] & 0xFF);
+ }
+ // BEGIN Android-added: Fix/log clinit serialization workaround. b/29064453
+ // ObjectStreamClass instances are cached per Class and caches its default
+ // serialVersionUID so it will only log one message per class per app process
+ // irrespective of the number of times the class is serialized.
+ if (warnIncompatibleSUIDChange) {
+ suidCompatibilityListener.warnDefaultSUIDTargetVersionDependent(cl, hash);
+ }
+ // END Android-added: Fix/log clinit serialization workaround. b/29064453
+ return hash;
+ } catch (IOException ex) {
+ throw new InternalError(ex);
+ } catch (NoSuchAlgorithmException ex) {
+ throw new SecurityException(ex.getMessage());
+ }
+ }
+
+ // BEGIN Android-changed: Fix/log clinit serialization workaround. b/29064453
+ /**
+ * Created for testing as there is no nice way to detect when a message is logged.
+ *
+ * @hide
+ */
+ public interface DefaultSUIDCompatibilityListener {
+ /**
+ * Called when a class being serialized/deserialized relies on the default SUID computation
+ * (because it has no explicit {@code serialVersionUID} field) where that computation is
+ * dependent on the app's targetSdkVersion.
+ *
+ * @param clazz the clazz for which the default SUID is being computed.
+ * @param hash the computed value.
+ */
+ void warnDefaultSUIDTargetVersionDependent(Class<?> clazz, long hash);
+ }
+
+ /**
+ * Public and mutable for testing purposes.
+ *
+ * @hide
+ */
+ public static DefaultSUIDCompatibilityListener suidCompatibilityListener =
+ (clazz, hash) -> {
+ System.logW("Class " + clazz.getCanonicalName() + " relies on its default SUID which"
+ + " is dependent on the app's targetSdkVersion. To avoid problems during upgrade"
+ + " add the following to class " + clazz.getCanonicalName() + "\n"
+ + " private static final long serialVersionUID = " + hash + "L;");
+ };
+
+ /** Max SDK target version for which we use buggy hasStaticInitializer implementation. */
+ static final int MAX_SDK_TARGET_FOR_CLINIT_UIDGEN_WORKAROUND = 23;
+
+ /**
+ * Returns true if the given class defines a static initializer method,
+ * false otherwise.
+ *
+ * @param inheritStaticInitializer if false then this method will return true iff the given
+ * class has its own static initializer, if true (used for backwards compatibility for apps
+ * that target SDK version <= {@link #MAX_SDK_TARGET_FOR_CLINIT_UIDGEN_WORKAROUND}) it will
+ * return true if the given class or any of its ancestor classes have a static initializer.
+ */
+ private native static boolean hasStaticInitializer(
+ Class<?> cl, boolean inheritStaticInitializer);
+ // END Android-changed: Fix/log clinit serialization workaround. b/29064453
+
+ /**
+ * Class for computing and caching field/constructor/method signatures
+ * during serialVersionUID calculation.
+ */
+ private static class MemberSignature {
+
+ public final Member member;
+ public final String name;
+ public final String signature;
+
+ public MemberSignature(Field field) {
+ member = field;
+ name = field.getName();
+ signature = getClassSignature(field.getType());
+ }
+
+ public MemberSignature(Constructor<?> cons) {
+ member = cons;
+ name = cons.getName();
+ signature = getMethodSignature(
+ cons.getParameterTypes(), Void.TYPE);
+ }
+
+ public MemberSignature(Method meth) {
+ member = meth;
+ name = meth.getName();
+ signature = getMethodSignature(
+ meth.getParameterTypes(), meth.getReturnType());
+ }
+ }
+
+ /**
+ * Class for setting and retrieving serializable field values in batch.
+ */
+ // REMIND: dynamically generate these?
+ private static class FieldReflector {
+
+ /** handle for performing unsafe operations */
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+ /** fields to operate on */
+ private final ObjectStreamField[] fields;
+ /** number of primitive fields */
+ private final int numPrimFields;
+ /** unsafe field keys for reading fields - may contain dupes */
+ private final long[] readKeys;
+ /** unsafe fields keys for writing fields - no dupes */
+ private final long[] writeKeys;
+ /** field data offsets */
+ private final int[] offsets;
+ /** field type codes */
+ private final char[] typeCodes;
+ /** field types */
+ private final Class<?>[] types;
+
+ /**
+ * Constructs FieldReflector capable of setting/getting values from the
+ * subset of fields whose ObjectStreamFields contain non-null
+ * reflective Field objects. ObjectStreamFields with null Fields are
+ * treated as filler, for which get operations return default values
+ * and set operations discard given values.
+ */
+ FieldReflector(ObjectStreamField[] fields) {
+ this.fields = fields;
+ int nfields = fields.length;
+ readKeys = new long[nfields];
+ writeKeys = new long[nfields];
+ offsets = new int[nfields];
+ typeCodes = new char[nfields];
+ ArrayList<Class<?>> typeList = new ArrayList<>();
+ Set<Long> usedKeys = new HashSet<>();
+
+
+ for (int i = 0; i < nfields; i++) {
+ ObjectStreamField f = fields[i];
+ Field rf = f.getField();
+ long key = (rf != null) ?
+ unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET;
+ readKeys[i] = key;
+ writeKeys[i] = usedKeys.add(key) ?
+ key : Unsafe.INVALID_FIELD_OFFSET;
+ offsets[i] = f.getOffset();
+ typeCodes[i] = f.getTypeCode();
+ if (!f.isPrimitive()) {
+ typeList.add((rf != null) ? rf.getType() : null);
+ }
+ }
+
+ types = typeList.toArray(new Class<?>[typeList.size()]);
+ numPrimFields = nfields - types.length;
+ }
+
+ /**
+ * Returns list of ObjectStreamFields representing fields operated on
+ * by this reflector. The shared/unshared values and Field objects
+ * contained by ObjectStreamFields in the list reflect their bindings
+ * to locally defined serializable fields.
+ */
+ ObjectStreamField[] getFields() {
+ return fields;
+ }
+
+ /**
+ * Fetches the serializable primitive field values of object obj and
+ * marshals them into byte array buf starting at offset 0. The caller
+ * is responsible for ensuring that obj is of the proper type.
+ */
+ void getPrimFieldValues(Object obj, byte[] buf) {
+ if (obj == null) {
+ throw new NullPointerException();
+ }
+ /* assuming checkDefaultSerialize() has been called on the class
+ * descriptor this FieldReflector was obtained from, no field keys
+ * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
+ */
+ for (int i = 0; i < numPrimFields; i++) {
+ long key = readKeys[i];
+ int off = offsets[i];
+ switch (typeCodes[i]) {
+ case 'Z':
+ Bits.putBoolean(buf, off, unsafe.getBoolean(obj, key));
+ break;
+
+ case 'B':
+ buf[off] = unsafe.getByte(obj, key);
+ break;
+
+ case 'C':
+ Bits.putChar(buf, off, unsafe.getChar(obj, key));
+ break;
+
+ case 'S':
+ Bits.putShort(buf, off, unsafe.getShort(obj, key));
+ break;
+
+ case 'I':
+ Bits.putInt(buf, off, unsafe.getInt(obj, key));
+ break;
+
+ case 'F':
+ Bits.putFloat(buf, off, unsafe.getFloat(obj, key));
+ break;
+
+ case 'J':
+ Bits.putLong(buf, off, unsafe.getLong(obj, key));
+ break;
+
+ case 'D':
+ Bits.putDouble(buf, off, unsafe.getDouble(obj, key));
+ break;
+
+ default:
+ throw new InternalError();
+ }
+ }
+ }
+
+ /**
+ * Sets the serializable primitive fields of object obj using values
+ * unmarshalled from byte array buf starting at offset 0. The caller
+ * is responsible for ensuring that obj is of the proper type.
+ */
+ void setPrimFieldValues(Object obj, byte[] buf) {
+ if (obj == null) {
+ throw new NullPointerException();
+ }
+ for (int i = 0; i < numPrimFields; i++) {
+ long key = writeKeys[i];
+ if (key == Unsafe.INVALID_FIELD_OFFSET) {
+ continue; // discard value
+ }
+ int off = offsets[i];
+ switch (typeCodes[i]) {
+ case 'Z':
+ unsafe.putBoolean(obj, key, Bits.getBoolean(buf, off));
+ break;
+
+ case 'B':
+ unsafe.putByte(obj, key, buf[off]);
+ break;
+
+ case 'C':
+ unsafe.putChar(obj, key, Bits.getChar(buf, off));
+ break;
+
+ case 'S':
+ unsafe.putShort(obj, key, Bits.getShort(buf, off));
+ break;
+
+ case 'I':
+ unsafe.putInt(obj, key, Bits.getInt(buf, off));
+ break;
+
+ case 'F':
+ unsafe.putFloat(obj, key, Bits.getFloat(buf, off));
+ break;
+
+ case 'J':
+ unsafe.putLong(obj, key, Bits.getLong(buf, off));
+ break;
+
+ case 'D':
+ unsafe.putDouble(obj, key, Bits.getDouble(buf, off));
+ break;
+
+ default:
+ throw new InternalError();
+ }
+ }
+ }
+
+ /**
+ * Fetches the serializable object field values of object obj and
+ * stores them in array vals starting at offset 0. The caller is
+ * responsible for ensuring that obj is of the proper type.
+ */
+ void getObjFieldValues(Object obj, Object[] vals) {
+ if (obj == null) {
+ throw new NullPointerException();
+ }
+ /* assuming checkDefaultSerialize() has been called on the class
+ * descriptor this FieldReflector was obtained from, no field keys
+ * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
+ */
+ for (int i = numPrimFields; i < fields.length; i++) {
+ switch (typeCodes[i]) {
+ case 'L':
+ case '[':
+ vals[offsets[i]] = unsafe.getObject(obj, readKeys[i]);
+ break;
+
+ default:
+ throw new InternalError();
+ }
+ }
+ }
+
+ /**
+ * Sets the serializable object fields of object obj using values from
+ * array vals starting at offset 0. The caller is responsible for
+ * ensuring that obj is of the proper type; however, attempts to set a
+ * field with a value of the wrong type will trigger an appropriate
+ * ClassCastException.
+ */
+ void setObjFieldValues(Object obj, Object[] vals) {
+ if (obj == null) {
+ throw new NullPointerException();
+ }
+ for (int i = numPrimFields; i < fields.length; i++) {
+ long key = writeKeys[i];
+ if (key == Unsafe.INVALID_FIELD_OFFSET) {
+ continue; // discard value
+ }
+ switch (typeCodes[i]) {
+ case 'L':
+ case '[':
+ Object val = vals[offsets[i]];
+ if (val != null &&
+ !types[i - numPrimFields].isInstance(val))
+ {
+ Field f = fields[i].getField();
+ throw new ClassCastException(
+ "cannot assign instance of " +
+ val.getClass().getName() + " to field " +
+ f.getDeclaringClass().getName() + "." +
+ f.getName() + " of type " +
+ f.getType().getName() + " in instance of " +
+ obj.getClass().getName());
+ }
+ unsafe.putObject(obj, key, val);
+ break;
+
+ default:
+ throw new InternalError();
+ }
+ }
+ }
+ }
+
+ /**
+ * Matches given set of serializable fields with serializable fields
+ * described by the given local class descriptor, and returns a
+ * FieldReflector instance capable of setting/getting values from the
+ * subset of fields that match (non-matching fields are treated as filler,
+ * for which get operations return default values and set operations
+ * discard given values). Throws InvalidClassException if unresolvable
+ * type conflicts exist between the two sets of fields.
+ */
+ private static FieldReflector getReflector(ObjectStreamField[] fields,
+ ObjectStreamClass localDesc)
+ throws InvalidClassException
+ {
+ // class irrelevant if no fields
+ Class<?> cl = (localDesc != null && fields.length > 0) ?
+ localDesc.cl : null;
+ processQueue(Caches.reflectorsQueue, Caches.reflectors);
+ FieldReflectorKey key = new FieldReflectorKey(cl, fields,
+ Caches.reflectorsQueue);
+ Reference<?> ref = Caches.reflectors.get(key);
+ Object entry = null;
+ if (ref != null) {
+ entry = ref.get();
+ }
+ EntryFuture future = null;
+ if (entry == null) {
+ EntryFuture newEntry = new EntryFuture();
+ Reference<?> newRef = new SoftReference<>(newEntry);
+ do {
+ if (ref != null) {
+ Caches.reflectors.remove(key, ref);
+ }
+ ref = Caches.reflectors.putIfAbsent(key, newRef);
+ if (ref != null) {
+ entry = ref.get();
+ }
+ } while (ref != null && entry == null);
+ if (entry == null) {
+ future = newEntry;
+ }
+ }
+
+ if (entry instanceof FieldReflector) { // check common case first
+ return (FieldReflector) entry;
+ } else if (entry instanceof EntryFuture) {
+ entry = ((EntryFuture) entry).get();
+ } else if (entry == null) {
+ try {
+ entry = new FieldReflector(matchFields(fields, localDesc));
+ } catch (Throwable th) {
+ entry = th;
+ }
+ future.set(entry);
+ Caches.reflectors.put(key, new SoftReference<Object>(entry));
+ }
+
+ if (entry instanceof FieldReflector) {
+ return (FieldReflector) entry;
+ } else if (entry instanceof InvalidClassException) {
+ throw (InvalidClassException) entry;
+ } else if (entry instanceof RuntimeException) {
+ throw (RuntimeException) entry;
+ } else if (entry instanceof Error) {
+ throw (Error) entry;
+ } else {
+ throw new InternalError("unexpected entry: " + entry);
+ }
+ }
+
+ /**
+ * FieldReflector cache lookup key. Keys are considered equal if they
+ * refer to the same class and equivalent field formats.
+ */
+ private static class FieldReflectorKey extends WeakReference<Class<?>> {
+
+ private final String sigs;
+ private final int hash;
+ private final boolean nullClass;
+
+ FieldReflectorKey(Class<?> cl, ObjectStreamField[] fields,
+ ReferenceQueue<Class<?>> queue)
+ {
+ super(cl, queue);
+ nullClass = (cl == null);
+ StringBuilder sbuf = new StringBuilder();
+ for (int i = 0; i < fields.length; i++) {
+ ObjectStreamField f = fields[i];
+ sbuf.append(f.getName()).append(f.getSignature());
+ }
+ sigs = sbuf.toString();
+ hash = System.identityHashCode(cl) + sigs.hashCode();
+ }
+
+ public int hashCode() {
+ return hash;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj instanceof FieldReflectorKey) {
+ FieldReflectorKey other = (FieldReflectorKey) obj;
+ Class<?> referent;
+ return (nullClass ? other.nullClass
+ : ((referent = get()) != null) &&
+ (referent == other.get())) &&
+ sigs.equals(other.sigs);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Matches given set of serializable fields with serializable fields
+ * obtained from the given local class descriptor (which contain bindings
+ * to reflective Field objects). Returns list of ObjectStreamFields in
+ * which each ObjectStreamField whose signature matches that of a local
+ * field contains a Field object for that field; unmatched
+ * ObjectStreamFields contain null Field objects. Shared/unshared settings
+ * of the returned ObjectStreamFields also reflect those of matched local
+ * ObjectStreamFields. Throws InvalidClassException if unresolvable type
+ * conflicts exist between the two sets of fields.
+ */
+ private static ObjectStreamField[] matchFields(ObjectStreamField[] fields,
+ ObjectStreamClass localDesc)
+ throws InvalidClassException
+ {
+ ObjectStreamField[] localFields = (localDesc != null) ?
+ localDesc.fields : NO_FIELDS;
+
+ /*
+ * Even if fields == localFields, we cannot simply return localFields
+ * here. In previous implementations of serialization,
+ * ObjectStreamField.getType() returned Object.class if the
+ * ObjectStreamField represented a non-primitive field and belonged to
+ * a non-local class descriptor. To preserve this (questionable)
+ * behavior, the ObjectStreamField instances returned by matchFields
+ * cannot report non-primitive types other than Object.class; hence
+ * localFields cannot be returned directly.
+ */
+
+ ObjectStreamField[] matches = new ObjectStreamField[fields.length];
+ for (int i = 0; i < fields.length; i++) {
+ ObjectStreamField f = fields[i], m = null;
+ for (int j = 0; j < localFields.length; j++) {
+ ObjectStreamField lf = localFields[j];
+ // Android-changed: We can have fields with a same name and a different type.
+ if (f.getName().equals(lf.getName()) &&
+ f.getSignature().equals(lf.getSignature())) {
+ if (lf.getField() != null) {
+ m = new ObjectStreamField(
+ lf.getField(), lf.isUnshared(), false);
+ } else {
+ m = new ObjectStreamField(
+ lf.getName(), lf.getSignature(), lf.isUnshared());
+ }
+ }
+ }
+ if (m == null) {
+ m = new ObjectStreamField(
+ f.getName(), f.getSignature(), false);
+ }
+ m.setOffset(f.getOffset());
+ matches[i] = m;
+ }
+ return matches;
+ }
+ // BEGIN Android-added: Keep some private API for app compat. b/28283540.
+ // NOTE: The following couple of methods are left here because frameworks such as objenesis
+ // use them.
+ //
+ // **** THESE METHODS WILL BE REMOVED IN A FUTURE ANDROID RELEASE ****.
+ //
+ private static long getConstructorId(Class<?> clazz) {
+ final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+ if (targetSdkVersion > 0 && targetSdkVersion <= 24) {
+ System.logE("WARNING: ObjectStreamClass.getConstructorId(Class<?>) is private API and" +
+ "will be removed in a future Android release.");
+ // NOTE: This method is a stub that returns a fixed value. It's meant to be used
+ // with newInstance(Class<?>, long) and our current implementation of that method ignores
+ // the "constructorId" argument. We return :
+ //
+ // oh one one eight nine nine nine
+ // eight eight one nine nine
+ // nine one one nine seven two five
+ // three
+ //
+ // in all cases.
+ return 1189998819991197253L;
+ }
+
+ throw new UnsupportedOperationException("ObjectStreamClass.getConstructorId(Class<?>) is " +
+ "not supported on SDK " + targetSdkVersion);
+ }
+ private static Object newInstance(Class<?> clazz, long constructorId) {
+ final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+ if (targetSdkVersion > 0 && targetSdkVersion <= 24) {
+ System.logE("WARNING: ObjectStreamClass.newInstance(Class<?>, long) is private API and" +
+ "will be removed in a future Android release.");
+ return sun.misc.Unsafe.getUnsafe().allocateInstance(clazz);
+ }
+
+ throw new UnsupportedOperationException("ObjectStreamClass.newInstance(Class<?>, long) " +
+ "is not supported on SDK " + targetSdkVersion);
+ }
+ // END Android-added: Keep some private API for app compat. b/28283540.
+
+ /**
+ * Removes from the specified map any keys that have been enqueued
+ * on the specified reference queue.
+ */
+ static void processQueue(ReferenceQueue<Class<?>> queue,
+ ConcurrentMap<? extends
+ WeakReference<Class<?>>, ?> map)
+ {
+ Reference<? extends Class<?>> ref;
+ while((ref = queue.poll()) != null) {
+ map.remove(ref);
+ }
+ }
+
+ /**
+ * Weak key for Class objects.
+ *
+ **/
+ static class WeakClassKey extends WeakReference<Class<?>> {
+ /**
+ * saved value of the referent's identity hash code, to maintain
+ * a consistent hash code after the referent has been cleared
+ */
+ private final int hash;
+
+ /**
+ * Create a new WeakClassKey to the given object, registered
+ * with a queue.
+ */
+ WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
+ super(cl, refQueue);
+ hash = System.identityHashCode(cl);
+ }
+
+ /**
+ * Returns the identity hash code of the original referent.
+ */
+ public int hashCode() {
+ return hash;
+ }
+
+ /**
+ * Returns true if the given object is this identical
+ * WeakClassKey instance, or, if this object's referent has not
+ * been cleared, if the given object is another WeakClassKey
+ * instance with the identical non-null referent as this one.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj instanceof WeakClassKey) {
+ Object referent = get();
+ return (referent != null) &&
+ (referent == ((WeakClassKey) obj).get());
+ } else {
+ return false;
+ }
+ }
+ }
+}
diff --git a/java/io/ObjectStreamConstants.java b/java/io/ObjectStreamConstants.java
new file mode 100644
index 0000000..23f72b4
--- /dev/null
+++ b/java/io/ObjectStreamConstants.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Constants written into the Object Serialization Stream.
+ *
+ * @author unascribed
+ * @since JDK 1.1
+ */
+public interface ObjectStreamConstants {
+
+ /**
+ * Magic number that is written to the stream header.
+ */
+ final static short STREAM_MAGIC = (short)0xaced;
+
+ /**
+ * Version number that is written to the stream header.
+ */
+ final static short STREAM_VERSION = 5;
+
+ /* Each item in the stream is preceded by a tag
+ */
+
+ /**
+ * First tag value.
+ */
+ final static byte TC_BASE = 0x70;
+
+ /**
+ * Null object reference.
+ */
+ final static byte TC_NULL = (byte)0x70;
+
+ /**
+ * Reference to an object already written into the stream.
+ */
+ final static byte TC_REFERENCE = (byte)0x71;
+
+ /**
+ * new Class Descriptor.
+ */
+ final static byte TC_CLASSDESC = (byte)0x72;
+
+ /**
+ * new Object.
+ */
+ final static byte TC_OBJECT = (byte)0x73;
+
+ /**
+ * new String.
+ */
+ final static byte TC_STRING = (byte)0x74;
+
+ /**
+ * new Array.
+ */
+ final static byte TC_ARRAY = (byte)0x75;
+
+ /**
+ * Reference to Class.
+ */
+ final static byte TC_CLASS = (byte)0x76;
+
+ /**
+ * Block of optional data. Byte following tag indicates number
+ * of bytes in this block data.
+ */
+ final static byte TC_BLOCKDATA = (byte)0x77;
+
+ /**
+ * End of optional block data blocks for an object.
+ */
+ final static byte TC_ENDBLOCKDATA = (byte)0x78;
+
+ /**
+ * Reset stream context. All handles written into stream are reset.
+ */
+ final static byte TC_RESET = (byte)0x79;
+
+ /**
+ * long Block data. The long following the tag indicates the
+ * number of bytes in this block data.
+ */
+ final static byte TC_BLOCKDATALONG= (byte)0x7A;
+
+ /**
+ * Exception during write.
+ */
+ final static byte TC_EXCEPTION = (byte)0x7B;
+
+ /**
+ * Long string.
+ */
+ final static byte TC_LONGSTRING = (byte)0x7C;
+
+ /**
+ * new Proxy Class Descriptor.
+ */
+ final static byte TC_PROXYCLASSDESC = (byte)0x7D;
+
+ /**
+ * new Enum constant.
+ * @since 1.5
+ */
+ final static byte TC_ENUM = (byte)0x7E;
+
+ /**
+ * Last tag value.
+ */
+ final static byte TC_MAX = (byte)0x7E;
+
+ /**
+ * First wire handle to be assigned.
+ */
+ final static int baseWireHandle = 0x7e0000;
+
+
+ /******************************************************/
+ /* Bit masks for ObjectStreamClass flag.*/
+
+ /**
+ * Bit mask for ObjectStreamClass flag. Indicates a Serializable class
+ * defines its own writeObject method.
+ */
+ final static byte SC_WRITE_METHOD = 0x01;
+
+ /**
+ * Bit mask for ObjectStreamClass flag. Indicates Externalizable data
+ * written in Block Data mode.
+ * Added for PROTOCOL_VERSION_2.
+ *
+ * @see #PROTOCOL_VERSION_2
+ * @since 1.2
+ */
+ final static byte SC_BLOCK_DATA = 0x08;
+
+ /**
+ * Bit mask for ObjectStreamClass flag. Indicates class is Serializable.
+ */
+ final static byte SC_SERIALIZABLE = 0x02;
+
+ /**
+ * Bit mask for ObjectStreamClass flag. Indicates class is Externalizable.
+ */
+ final static byte SC_EXTERNALIZABLE = 0x04;
+
+ /**
+ * Bit mask for ObjectStreamClass flag. Indicates class is an enum type.
+ * @since 1.5
+ */
+ final static byte SC_ENUM = 0x10;
+
+
+ /* *******************************************************************/
+ /* Security permissions */
+
+ /**
+ * Enable substitution of one object for another during
+ * serialization/deserialization.
+ *
+ * @see java.io.ObjectOutputStream#enableReplaceObject(boolean)
+ * @see java.io.ObjectInputStream#enableResolveObject(boolean)
+ * @since 1.2
+ */
+ final static SerializablePermission SUBSTITUTION_PERMISSION =
+ new SerializablePermission("enableSubstitution");
+
+ /**
+ * Enable overriding of readObject and writeObject.
+ *
+ * @see java.io.ObjectOutputStream#writeObjectOverride(Object)
+ * @see java.io.ObjectInputStream#readObjectOverride()
+ * @since 1.2
+ */
+ final static SerializablePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
+ new SerializablePermission("enableSubclassImplementation");
+ /**
+ * A Stream Protocol Version. <p>
+ *
+ * All externalizable data is written in JDK 1.1 external data
+ * format after calling this method. This version is needed to write
+ * streams containing Externalizable data that can be read by
+ * pre-JDK 1.1.6 JVMs.
+ *
+ * @see java.io.ObjectOutputStream#useProtocolVersion(int)
+ * @since 1.2
+ */
+ public final static int PROTOCOL_VERSION_1 = 1;
+
+
+ /**
+ * A Stream Protocol Version. <p>
+ *
+ * This protocol is written by JVM 1.2.
+ *
+ * Externalizable data is written in block data mode and is
+ * terminated with TC_ENDBLOCKDATA. Externalizable class descriptor
+ * flags has SC_BLOCK_DATA enabled. JVM 1.1.6 and greater can
+ * read this format change.
+ *
+ * Enables writing a nonSerializable class descriptor into the
+ * stream. The serialVersionUID of a nonSerializable class is
+ * set to 0L.
+ *
+ * @see java.io.ObjectOutputStream#useProtocolVersion(int)
+ * @see #SC_BLOCK_DATA
+ * @since 1.2
+ */
+ public final static int PROTOCOL_VERSION_2 = 2;
+}
diff --git a/java/io/ObjectStreamException.java b/java/io/ObjectStreamException.java
new file mode 100644
index 0000000..889cad3
--- /dev/null
+++ b/java/io/ObjectStreamException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Superclass of all exceptions specific to Object Stream classes.
+ *
+ * @author unascribed
+ * @since JDK1.1
+ */
+public abstract class ObjectStreamException extends IOException {
+
+ private static final long serialVersionUID = 7260898174833392607L;
+
+ /**
+ * Create an ObjectStreamException with the specified argument.
+ *
+ * @param classname the detailed message for the exception
+ */
+ protected ObjectStreamException(String classname) {
+ super(classname);
+ }
+
+ /**
+ * Create an ObjectStreamException.
+ */
+ protected ObjectStreamException() {
+ super();
+ }
+}
diff --git a/java/io/ObjectStreamField.java b/java/io/ObjectStreamField.java
new file mode 100644
index 0000000..d26535f
--- /dev/null
+++ b/java/io/ObjectStreamField.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.lang.reflect.Field;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+import sun.reflect.misc.ReflectUtil;
+
+/**
+ * A description of a Serializable field from a Serializable class. An array
+ * of ObjectStreamFields is used to declare the Serializable fields of a class.
+ *
+ * @author Mike Warres
+ * @author Roger Riggs
+ * @see ObjectStreamClass
+ * @since 1.2
+ */
+public class ObjectStreamField
+ implements Comparable<Object>
+{
+
+ /** field name */
+ private final String name;
+ /** canonical JVM signature of field type */
+ private final String signature;
+ /** field type (Object.class if unknown non-primitive type) */
+ private final Class<?> type;
+ /** whether or not to (de)serialize field values as unshared */
+ private final boolean unshared;
+ /** corresponding reflective field object, if any */
+ private final Field field;
+ /** offset of field value in enclosing field group */
+ private int offset = 0;
+
+ /**
+ * Create a Serializable field with the specified type. This field should
+ * be documented with a <code>serialField</code> tag.
+ *
+ * @param name the name of the serializable field
+ * @param type the <code>Class</code> object of the serializable field
+ */
+ public ObjectStreamField(String name, Class<?> type) {
+ this(name, type, false);
+ }
+
+ /**
+ * Creates an ObjectStreamField representing a serializable field with the
+ * given name and type. If unshared is false, values of the represented
+ * field are serialized and deserialized in the default manner--if the
+ * field is non-primitive, object values are serialized and deserialized as
+ * if they had been written and read by calls to writeObject and
+ * readObject. If unshared is true, values of the represented field are
+ * serialized and deserialized as if they had been written and read by
+ * calls to writeUnshared and readUnshared.
+ *
+ * @param name field name
+ * @param type field type
+ * @param unshared if false, write/read field values in the same manner
+ * as writeObject/readObject; if true, write/read in the same
+ * manner as writeUnshared/readUnshared
+ * @since 1.4
+ */
+ public ObjectStreamField(String name, Class<?> type, boolean unshared) {
+ if (name == null) {
+ throw new NullPointerException();
+ }
+ this.name = name;
+ this.type = type;
+ this.unshared = unshared;
+ signature = getClassSignature(type).intern();
+ field = null;
+ }
+
+ /**
+ * Creates an ObjectStreamField representing a field with the given name,
+ * signature and unshared setting.
+ */
+ ObjectStreamField(String name, String signature, boolean unshared) {
+ if (name == null) {
+ throw new NullPointerException();
+ }
+ this.name = name;
+ this.signature = signature.intern();
+ this.unshared = unshared;
+ field = null;
+
+ switch (signature.charAt(0)) {
+ case 'Z': type = Boolean.TYPE; break;
+ case 'B': type = Byte.TYPE; break;
+ case 'C': type = Character.TYPE; break;
+ case 'S': type = Short.TYPE; break;
+ case 'I': type = Integer.TYPE; break;
+ case 'J': type = Long.TYPE; break;
+ case 'F': type = Float.TYPE; break;
+ case 'D': type = Double.TYPE; break;
+ case 'L':
+ case '[': type = Object.class; break;
+ default: throw new IllegalArgumentException("illegal signature");
+ }
+ }
+
+ /**
+ * Creates an ObjectStreamField representing the given field with the
+ * specified unshared setting. For compatibility with the behavior of
+ * earlier serialization implementations, a "showType" parameter is
+ * necessary to govern whether or not a getType() call on this
+ * ObjectStreamField (if non-primitive) will return Object.class (as
+ * opposed to a more specific reference type).
+ */
+ ObjectStreamField(Field field, boolean unshared, boolean showType) {
+ this.field = field;
+ this.unshared = unshared;
+ name = field.getName();
+ Class<?> ftype = field.getType();
+ type = (showType || ftype.isPrimitive()) ? ftype : Object.class;
+ signature = getClassSignature(ftype).intern();
+ }
+
+ /**
+ * Get the name of this field.
+ *
+ * @return a <code>String</code> representing the name of the serializable
+ * field
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Get the type of the field. If the type is non-primitive and this
+ * <code>ObjectStreamField</code> was obtained from a deserialized {@link
+ * ObjectStreamClass} instance, then <code>Object.class</code> is returned.
+ * Otherwise, the <code>Class</code> object for the type of the field is
+ * returned.
+ *
+ * @return a <code>Class</code> object representing the type of the
+ * serializable field
+ */
+ @CallerSensitive
+ public Class<?> getType() {
+ // BEGIN Android-removed: Security manager is always null on Android.
+ /*
+ if (System.getSecurityManager() != null) {
+ Class<?> caller = Reflection.getCallerClass();
+ if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), type.getClassLoader())) {
+ ReflectUtil.checkPackageAccess(type);
+ }
+ }
+ */
+ // END Android-removed: Security manager is always null on Android.
+ return type;
+ }
+
+ /**
+ * Returns character encoding of field type. The encoding is as follows:
+ * <blockquote><pre>
+ * B byte
+ * C char
+ * D double
+ * F float
+ * I int
+ * J long
+ * L class or interface
+ * S short
+ * Z boolean
+ * [ array
+ * </pre></blockquote>
+ *
+ * @return the typecode of the serializable field
+ */
+ // REMIND: deprecate?
+ public char getTypeCode() {
+ return signature.charAt(0);
+ }
+
+ /**
+ * Return the JVM type signature.
+ *
+ * @return null if this field has a primitive type.
+ */
+ // REMIND: deprecate?
+ public String getTypeString() {
+ return isPrimitive() ? null : signature;
+ }
+
+ /**
+ * Offset of field within instance data.
+ *
+ * @return the offset of this field
+ * @see #setOffset
+ */
+ // REMIND: deprecate?
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Offset within instance data.
+ *
+ * @param offset the offset of the field
+ * @see #getOffset
+ */
+ // REMIND: deprecate?
+ protected void setOffset(int offset) {
+ this.offset = offset;
+ }
+
+ /**
+ * Return true if this field has a primitive type.
+ *
+ * @return true if and only if this field corresponds to a primitive type
+ */
+ // REMIND: deprecate?
+ public boolean isPrimitive() {
+ char tcode = signature.charAt(0);
+ return ((tcode != 'L') && (tcode != '['));
+ }
+
+ /**
+ * Returns boolean value indicating whether or not the serializable field
+ * represented by this ObjectStreamField instance is unshared.
+ *
+ * @return {@code true} if this field is unshared
+ *
+ * @since 1.4
+ */
+ public boolean isUnshared() {
+ return unshared;
+ }
+
+ /**
+ * Compare this field with another <code>ObjectStreamField</code>. Return
+ * -1 if this is smaller, 0 if equal, 1 if greater. Types that are
+ * primitives are "smaller" than object types. If equal, the field names
+ * are compared.
+ */
+ // REMIND: deprecate?
+ public int compareTo(Object obj) {
+ ObjectStreamField other = (ObjectStreamField) obj;
+ boolean isPrim = isPrimitive();
+ if (isPrim != other.isPrimitive()) {
+ return isPrim ? -1 : 1;
+ }
+ return name.compareTo(other.name);
+ }
+
+ /**
+ * Return a string that describes this field.
+ */
+ public String toString() {
+ return signature + ' ' + name;
+ }
+
+ /**
+ * Returns field represented by this ObjectStreamField, or null if
+ * ObjectStreamField is not associated with an actual field.
+ */
+ Field getField() {
+ return field;
+ }
+
+ /**
+ * Returns JVM type signature of field (similar to getTypeString, except
+ * that signature strings are returned for primitive fields as well).
+ */
+ String getSignature() {
+ return signature;
+ }
+
+ /**
+ * Returns JVM type signature for given class.
+ */
+ private static String getClassSignature(Class<?> cl) {
+ StringBuilder sbuf = new StringBuilder();
+ while (cl.isArray()) {
+ sbuf.append('[');
+ cl = cl.getComponentType();
+ }
+ if (cl.isPrimitive()) {
+ if (cl == Integer.TYPE) {
+ sbuf.append('I');
+ } else if (cl == Byte.TYPE) {
+ sbuf.append('B');
+ } else if (cl == Long.TYPE) {
+ sbuf.append('J');
+ } else if (cl == Float.TYPE) {
+ sbuf.append('F');
+ } else if (cl == Double.TYPE) {
+ sbuf.append('D');
+ } else if (cl == Short.TYPE) {
+ sbuf.append('S');
+ } else if (cl == Character.TYPE) {
+ sbuf.append('C');
+ } else if (cl == Boolean.TYPE) {
+ sbuf.append('Z');
+ } else if (cl == Void.TYPE) {
+ sbuf.append('V');
+ } else {
+ throw new InternalError();
+ }
+ } else {
+ sbuf.append('L' + cl.getName().replace('.', '/') + ';');
+ }
+ return sbuf.toString();
+ }
+}
diff --git a/java/io/OptionalDataException.java b/java/io/OptionalDataException.java
new file mode 100644
index 0000000..91283fd
--- /dev/null
+++ b/java/io/OptionalDataException.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.io;
+
+/**
+ * Exception indicating the failure of an object read operation due to
+ * unread primitive data, or the end of data belonging to a serialized
+ * object in the stream. This exception may be thrown in two cases:
+ *
+ * <ul>
+ * <li>An attempt was made to read an object when the next element in the
+ * stream is primitive data. In this case, the OptionalDataException's
+ * length field is set to the number of bytes of primitive data
+ * immediately readable from the stream, and the eof field is set to
+ * false.
+ *
+ * <li>An attempt was made to read past the end of data consumable by a
+ * class-defined readObject or readExternal method. In this case, the
+ * OptionalDataException's eof field is set to true, and the length field
+ * is set to 0.
+ * </ul>
+ *
+ * @author unascribed
+ * @since JDK1.1
+ */
+public class OptionalDataException extends ObjectStreamException {
+
+ private static final long serialVersionUID = -8011121865681257820L;
+
+ /*
+ * Create an <code>OptionalDataException</code> with a length.
+ */
+ OptionalDataException(int len) {
+ eof = false;
+ length = len;
+ }
+
+ /*
+ * Create an <code>OptionalDataException</code> signifying no
+ * more primitive data is available.
+ */
+ OptionalDataException(boolean end) {
+ length = 0;
+ eof = end;
+ }
+
+ /**
+ * The number of bytes of primitive data available to be read
+ * in the current buffer.
+ *
+ * @serial
+ */
+ public int length;
+
+ /**
+ * True if there is no more data in the buffered part of the stream.
+ *
+ * @serial
+ */
+ public boolean eof;
+}
diff --git a/java/io/OutputStream.java b/java/io/OutputStream.java
new file mode 100644
index 0000000..c6dd7de
--- /dev/null
+++ b/java/io/OutputStream.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This abstract class is the superclass of all classes representing
+ * an output stream of bytes. An output stream accepts output bytes
+ * and sends them to some sink.
+ * <p>
+ * Applications that need to define a subclass of
+ * <code>OutputStream</code> must always provide at least a method
+ * that writes one byte of output.
+ *
+ * @author Arthur van Hoff
+ * @see java.io.BufferedOutputStream
+ * @see java.io.ByteArrayOutputStream
+ * @see java.io.DataOutputStream
+ * @see java.io.FilterOutputStream
+ * @see java.io.InputStream
+ * @see java.io.OutputStream#write(int)
+ * @since JDK1.0
+ */
+public abstract class OutputStream implements Closeable, Flushable {
+ /**
+ * Writes the specified byte to this output stream. The general
+ * contract for <code>write</code> is that one byte is written
+ * to the output stream. The byte to be written is the eight
+ * low-order bits of the argument <code>b</code>. The 24
+ * high-order bits of <code>b</code> are ignored.
+ * <p>
+ * Subclasses of <code>OutputStream</code> must provide an
+ * implementation for this method.
+ *
+ * @param b the <code>byte</code>.
+ * @exception IOException if an I/O error occurs. In particular,
+ * an <code>IOException</code> may be thrown if the
+ * output stream has been closed.
+ */
+ public abstract void write(int b) throws IOException;
+
+ /**
+ * Writes <code>b.length</code> bytes from the specified byte array
+ * to this output stream. The general contract for <code>write(b)</code>
+ * is that it should have exactly the same effect as the call
+ * <code>write(b, 0, b.length)</code>.
+ *
+ * @param b the data.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.OutputStream#write(byte[], int, int)
+ */
+ public void write(byte b[]) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Writes <code>len</code> bytes from the specified byte array
+ * starting at offset <code>off</code> to this output stream.
+ * The general contract for <code>write(b, off, len)</code> is that
+ * some of the bytes in the array <code>b</code> are written to the
+ * output stream in order; element <code>b[off]</code> is the first
+ * byte written and <code>b[off+len-1]</code> is the last byte written
+ * by this operation.
+ * <p>
+ * The <code>write</code> method of <code>OutputStream</code> calls
+ * the write method of one argument on each of the bytes to be
+ * written out. Subclasses are encouraged to override this method and
+ * provide a more efficient implementation.
+ * <p>
+ * If <code>b</code> is <code>null</code>, a
+ * <code>NullPointerException</code> is thrown.
+ * <p>
+ * If <code>off</code> is negative, or <code>len</code> is negative, or
+ * <code>off+len</code> is greater than the length of the array
+ * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @exception IOException if an I/O error occurs. In particular,
+ * an <code>IOException</code> is thrown if the output
+ * stream is closed.
+ */
+ public void write(byte b[], int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) > b.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+ for (int i = 0 ; i < len ; i++) {
+ write(b[off + i]);
+ }
+ }
+
+ /**
+ * Flushes this output stream and forces any buffered output bytes
+ * to be written out. The general contract of <code>flush</code> is
+ * that calling it is an indication that, if any bytes previously
+ * written have been buffered by the implementation of the output
+ * stream, such bytes should immediately be written to their
+ * intended destination.
+ * <p>
+ * If the intended destination of this stream is an abstraction provided by
+ * the underlying operating system, for example a file, then flushing the
+ * stream guarantees only that bytes previously written to the stream are
+ * passed to the operating system for writing; it does not guarantee that
+ * they are actually written to a physical device such as a disk drive.
+ * <p>
+ * The <code>flush</code> method of <code>OutputStream</code> does nothing.
+ *
+ * @exception IOException if an I/O error occurs.
+ */
+ public void flush() throws IOException {
+ }
+
+ /**
+ * Closes this output stream and releases any system resources
+ * associated with this stream. The general contract of <code>close</code>
+ * is that it closes the output stream. A closed stream cannot perform
+ * output operations and cannot be reopened.
+ * <p>
+ * The <code>close</code> method of <code>OutputStream</code> does nothing.
+ *
+ * @exception IOException if an I/O error occurs.
+ */
+ public void close() throws IOException {
+ }
+
+}
diff --git a/java/io/OutputStreamWriter.java b/java/io/OutputStreamWriter.java
new file mode 100644
index 0000000..5f7b9e3
--- /dev/null
+++ b/java/io/OutputStreamWriter.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import sun.nio.cs.StreamEncoder;
+
+
+/**
+ * An OutputStreamWriter is a bridge from character streams to byte streams:
+ * Characters written to it are encoded into bytes using a specified {@link
+ * java.nio.charset.Charset charset}. The charset that it uses
+ * may be specified by name or may be given explicitly, or the platform's
+ * default charset may be accepted.
+ *
+ * <p> Each invocation of a write() method causes the encoding converter to be
+ * invoked on the given character(s). The resulting bytes are accumulated in a
+ * buffer before being written to the underlying output stream. The size of
+ * this buffer may be specified, but by default it is large enough for most
+ * purposes. Note that the characters passed to the write() methods are not
+ * buffered.
+ *
+ * <p> For top efficiency, consider wrapping an OutputStreamWriter within a
+ * BufferedWriter so as to avoid frequent converter invocations. For example:
+ *
+ * <pre>
+ * Writer out
+ * = new BufferedWriter(new OutputStreamWriter(System.out));
+ * </pre>
+ *
+ * <p> A <i>surrogate pair</i> is a character represented by a sequence of two
+ * <tt>char</tt> values: A <i>high</i> surrogate in the range '\uD800' to
+ * '\uDBFF' followed by a <i>low</i> surrogate in the range '\uDC00' to
+ * '\uDFFF'.
+ *
+ * <p> A <i>malformed surrogate element</i> is a high surrogate that is not
+ * followed by a low surrogate or a low surrogate that is not preceded by a
+ * high surrogate.
+ *
+ * <p> This class always replaces malformed surrogate elements and unmappable
+ * character sequences with the charset's default <i>substitution sequence</i>.
+ * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
+ * control over the encoding process is required.
+ *
+ * @see BufferedWriter
+ * @see OutputStream
+ * @see java.nio.charset.Charset
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class OutputStreamWriter extends Writer {
+
+ private final StreamEncoder se;
+
+ /**
+ * Creates an OutputStreamWriter that uses the named charset.
+ *
+ * @param out
+ * An OutputStream
+ *
+ * @param charsetName
+ * The name of a supported
+ * {@link java.nio.charset.Charset charset}
+ *
+ * @exception UnsupportedEncodingException
+ * If the named encoding is not supported
+ */
+ public OutputStreamWriter(OutputStream out, String charsetName)
+ throws UnsupportedEncodingException
+ {
+ super(out);
+ if (charsetName == null)
+ throw new NullPointerException("charsetName");
+ se = StreamEncoder.forOutputStreamWriter(out, this, charsetName);
+ }
+
+ /**
+ * Creates an OutputStreamWriter that uses the default character encoding.
+ *
+ * @param out An OutputStream
+ */
+ public OutputStreamWriter(OutputStream out) {
+ super(out);
+ try {
+ se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
+ } catch (UnsupportedEncodingException e) {
+ throw new Error(e);
+ }
+ }
+
+ /**
+ * Creates an OutputStreamWriter that uses the given charset.
+ *
+ * @param out
+ * An OutputStream
+ *
+ * @param cs
+ * A charset
+ *
+ * @since 1.4
+ * @spec JSR-51
+ */
+ public OutputStreamWriter(OutputStream out, Charset cs) {
+ super(out);
+ if (cs == null)
+ throw new NullPointerException("charset");
+ se = StreamEncoder.forOutputStreamWriter(out, this, cs);
+ }
+
+ /**
+ * Creates an OutputStreamWriter that uses the given charset encoder.
+ *
+ * @param out
+ * An OutputStream
+ *
+ * @param enc
+ * A charset encoder
+ *
+ * @since 1.4
+ * @spec JSR-51
+ */
+ public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {
+ super(out);
+ if (enc == null)
+ throw new NullPointerException("charset encoder");
+ se = StreamEncoder.forOutputStreamWriter(out, this, enc);
+ }
+
+ /**
+ * Returns the name of the character encoding being used by this stream.
+ *
+ * <p> If the encoding has an historical name then that name is returned;
+ * otherwise the encoding's canonical name is returned.
+ *
+ * <p> If this instance was created with the {@link
+ * #OutputStreamWriter(OutputStream, String)} constructor then the returned
+ * name, being unique for the encoding, may differ from the name passed to
+ * the constructor. This method may return <tt>null</tt> if the stream has
+ * been closed. </p>
+ *
+ * @return The historical name of this encoding, or possibly
+ * <code>null</code> if the stream has been closed
+ *
+ * @see java.nio.charset.Charset
+ *
+ * @revised 1.4
+ * @spec JSR-51
+ */
+ public String getEncoding() {
+ return se.getEncoding();
+ }
+
+ /**
+ * Flushes the output buffer to the underlying byte stream, without flushing
+ * the byte stream itself. This method is non-private only so that it may
+ * be invoked by PrintStream.
+ */
+ void flushBuffer() throws IOException {
+ se.flushBuffer();
+ }
+
+ /**
+ * Writes a single character.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void write(int c) throws IOException {
+ se.write(c);
+ }
+
+ /**
+ * Writes a portion of an array of characters.
+ *
+ * @param cbuf Buffer of characters
+ * @param off Offset from which to start writing characters
+ * @param len Number of characters to write
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void write(char cbuf[], int off, int len) throws IOException {
+ se.write(cbuf, off, len);
+ }
+
+ /**
+ * Writes a portion of a string.
+ *
+ * @param str A String
+ * @param off Offset from which to start writing characters
+ * @param len Number of characters to write
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void write(String str, int off, int len) throws IOException {
+ se.write(str, off, len);
+ }
+
+ /**
+ * Flushes the stream.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void flush() throws IOException {
+ se.flush();
+ }
+
+ public void close() throws IOException {
+ se.close();
+ }
+}
diff --git a/java/io/PipedInputStream.java b/java/io/PipedInputStream.java
new file mode 100644
index 0000000..b79bcbd
--- /dev/null
+++ b/java/io/PipedInputStream.java
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import libcore.io.IoUtils;
+
+/**
+ * A piped input stream should be connected
+ * to a piped output stream; the piped input
+ * stream then provides whatever data bytes
+ * are written to the piped output stream.
+ * Typically, data is read from a <code>PipedInputStream</code>
+ * object by one thread and data is written
+ * to the corresponding <code>PipedOutputStream</code>
+ * by some other thread. Attempting to use
+ * both objects from a single thread is not
+ * recommended, as it may deadlock the thread.
+ * The piped input stream contains a buffer,
+ * decoupling read operations from write operations,
+ * within limits.
+ * A pipe is said to be <a name="BROKEN"> <i>broken</i> </a> if a
+ * thread that was providing data bytes to the connected
+ * piped output stream is no longer alive.
+ *
+ * @author James Gosling
+ * @see java.io.PipedOutputStream
+ * @since JDK1.0
+ */
+public class PipedInputStream extends InputStream {
+ boolean closedByWriter = false;
+ volatile boolean closedByReader = false;
+ boolean connected = false;
+
+ /* REMIND: identification of the read and write sides needs to be
+ more sophisticated. Either using thread groups (but what about
+ pipes within a thread?) or using finalization (but it may be a
+ long time until the next GC). */
+ Thread readSide;
+ Thread writeSide;
+
+ private static final int DEFAULT_PIPE_SIZE = 1024;
+
+ /**
+ * The default size of the pipe's circular input buffer.
+ * @since JDK1.1
+ */
+ // This used to be a constant before the pipe size was allowed
+ // to change. This field will continue to be maintained
+ // for backward compatibility.
+ protected static final int PIPE_SIZE = DEFAULT_PIPE_SIZE;
+
+ /**
+ * The circular buffer into which incoming data is placed.
+ * @since JDK1.1
+ */
+ protected byte buffer[];
+
+ /**
+ * The index of the position in the circular buffer at which the
+ * next byte of data will be stored when received from the connected
+ * piped output stream. <code>in<0</code> implies the buffer is empty,
+ * <code>in==out</code> implies the buffer is full
+ * @since JDK1.1
+ */
+ protected int in = -1;
+
+ /**
+ * The index of the position in the circular buffer at which the next
+ * byte of data will be read by this piped input stream.
+ * @since JDK1.1
+ */
+ protected int out = 0;
+
+ /**
+ * Creates a <code>PipedInputStream</code> so
+ * that it is connected to the piped output
+ * stream <code>src</code>. Data bytes written
+ * to <code>src</code> will then be available
+ * as input from this stream.
+ *
+ * @param src the stream to connect to.
+ * @exception IOException if an I/O error occurs.
+ */
+ public PipedInputStream(PipedOutputStream src) throws IOException {
+ this(src, DEFAULT_PIPE_SIZE);
+ }
+
+ /**
+ * Creates a <code>PipedInputStream</code> so that it is
+ * connected to the piped output stream
+ * <code>src</code> and uses the specified pipe size for
+ * the pipe's buffer.
+ * Data bytes written to <code>src</code> will then
+ * be available as input from this stream.
+ *
+ * @param src the stream to connect to.
+ * @param pipeSize the size of the pipe's buffer.
+ * @exception IOException if an I/O error occurs.
+ * @exception IllegalArgumentException if {@code pipeSize <= 0}.
+ * @since 1.6
+ */
+ public PipedInputStream(PipedOutputStream src, int pipeSize)
+ throws IOException {
+ initPipe(pipeSize);
+ connect(src);
+ }
+
+ /**
+ * Creates a <code>PipedInputStream</code> so
+ * that it is not yet {@linkplain #connect(java.io.PipedOutputStream)
+ * connected}.
+ * It must be {@linkplain java.io.PipedOutputStream#connect(
+ * java.io.PipedInputStream) connected} to a
+ * <code>PipedOutputStream</code> before being used.
+ */
+ public PipedInputStream() {
+ initPipe(DEFAULT_PIPE_SIZE);
+ }
+
+ /**
+ * Creates a <code>PipedInputStream</code> so that it is not yet
+ * {@linkplain #connect(java.io.PipedOutputStream) connected} and
+ * uses the specified pipe size for the pipe's buffer.
+ * It must be {@linkplain java.io.PipedOutputStream#connect(
+ * java.io.PipedInputStream)
+ * connected} to a <code>PipedOutputStream</code> before being used.
+ *
+ * @param pipeSize the size of the pipe's buffer.
+ * @exception IllegalArgumentException if {@code pipeSize <= 0}.
+ * @since 1.6
+ */
+ public PipedInputStream(int pipeSize) {
+ initPipe(pipeSize);
+ }
+
+ private void initPipe(int pipeSize) {
+ if (pipeSize <= 0) {
+ throw new IllegalArgumentException("Pipe Size <= 0");
+ }
+ buffer = new byte[pipeSize];
+ }
+
+ /**
+ * Causes this piped input stream to be connected
+ * to the piped output stream <code>src</code>.
+ * If this object is already connected to some
+ * other piped output stream, an <code>IOException</code>
+ * is thrown.
+ * <p>
+ * If <code>src</code> is an
+ * unconnected piped output stream and <code>snk</code>
+ * is an unconnected piped input stream, they
+ * may be connected by either the call:
+ *
+ * <pre><code>snk.connect(src)</code> </pre>
+ * <p>
+ * or the call:
+ *
+ * <pre><code>src.connect(snk)</code> </pre>
+ * <p>
+ * The two calls have the same effect.
+ *
+ * @param src The piped output stream to connect to.
+ * @exception IOException if an I/O error occurs.
+ */
+ public void connect(PipedOutputStream src) throws IOException {
+ src.connect(this);
+ }
+
+ /**
+ * Receives a byte of data. This method will block if no input is
+ * available.
+ * @param b the byte being received
+ * @exception IOException If the pipe is <a href="#BROKEN"> <code>broken</code></a>,
+ * {@link #connect(java.io.PipedOutputStream) unconnected},
+ * closed, or if an I/O error occurs.
+ * @since JDK1.1
+ */
+ protected synchronized void receive(int b) throws IOException {
+ checkStateForReceive();
+ writeSide = Thread.currentThread();
+ if (in == out)
+ awaitSpace();
+ if (in < 0) {
+ in = 0;
+ out = 0;
+ }
+ buffer[in++] = (byte)(b & 0xFF);
+ if (in >= buffer.length) {
+ in = 0;
+ }
+ }
+
+ /**
+ * Receives data into an array of bytes. This method will
+ * block until some input is available.
+ * @param b the buffer into which the data is received
+ * @param off the start offset of the data
+ * @param len the maximum number of bytes received
+ * @exception IOException If the pipe is <a href="#BROKEN"> broken</a>,
+ * {@link #connect(java.io.PipedOutputStream) unconnected},
+ * closed,or if an I/O error occurs.
+ */
+ synchronized void receive(byte b[], int off, int len) throws IOException {
+ checkStateForReceive();
+ writeSide = Thread.currentThread();
+ int bytesToTransfer = len;
+ while (bytesToTransfer > 0) {
+ if (in == out)
+ awaitSpace();
+ int nextTransferAmount = 0;
+ if (out < in) {
+ nextTransferAmount = buffer.length - in;
+ } else if (in < out) {
+ if (in == -1) {
+ in = out = 0;
+ nextTransferAmount = buffer.length - in;
+ } else {
+ nextTransferAmount = out - in;
+ }
+ }
+ if (nextTransferAmount > bytesToTransfer)
+ nextTransferAmount = bytesToTransfer;
+ assert(nextTransferAmount > 0);
+ System.arraycopy(b, off, buffer, in, nextTransferAmount);
+ bytesToTransfer -= nextTransferAmount;
+ off += nextTransferAmount;
+ in += nextTransferAmount;
+ if (in >= buffer.length) {
+ in = 0;
+ }
+ }
+ }
+
+ private void checkStateForReceive() throws IOException {
+ if (!connected) {
+ throw new IOException("Pipe not connected");
+ } else if (closedByWriter || closedByReader) {
+ throw new IOException("Pipe closed");
+ } else if (readSide != null && !readSide.isAlive()) {
+ throw new IOException("Read end dead");
+ }
+ }
+
+ private void awaitSpace() throws IOException {
+ while (in == out) {
+ checkStateForReceive();
+
+ /* full: kick any waiting readers */
+ notifyAll();
+ try {
+ wait(1000);
+ } catch (InterruptedException ex) {
+ // Android-changed: re-set the thread's interrupt status
+ // throw new java.io.InterruptedIOException();
+ IoUtils.throwInterruptedIoException();
+ }
+ }
+ }
+
+ /**
+ * Notifies all waiting threads that the last byte of data has been
+ * received.
+ */
+ synchronized void receivedLast() {
+ closedByWriter = true;
+ notifyAll();
+ }
+
+ /**
+ * Reads the next byte of data from this piped input stream. The
+ * value byte is returned as an <code>int</code> in the range
+ * <code>0</code> to <code>255</code>.
+ * This method blocks until input data is available, the end of the
+ * stream is detected, or an exception is thrown.
+ *
+ * @return the next byte of data, or <code>-1</code> if the end of the
+ * stream is reached.
+ * @exception IOException if the pipe is
+ * {@link #connect(java.io.PipedOutputStream) unconnected},
+ * <a href="#BROKEN"> <code>broken</code></a>, closed,
+ * or if an I/O error occurs.
+ */
+ public synchronized int read() throws IOException {
+ if (!connected) {
+ throw new IOException("Pipe not connected");
+ } else if (closedByReader) {
+ throw new IOException("Pipe closed");
+ } else if (writeSide != null && !writeSide.isAlive()
+ && !closedByWriter && (in < 0)) {
+ throw new IOException("Write end dead");
+ }
+
+ readSide = Thread.currentThread();
+ int trials = 2;
+ while (in < 0) {
+ if (closedByWriter) {
+ /* closed by writer, return EOF */
+ return -1;
+ }
+ if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {
+ throw new IOException("Pipe broken");
+ }
+ /* might be a writer waiting */
+ notifyAll();
+ try {
+ wait(1000);
+ } catch (InterruptedException ex) {
+ // Android-changed: re-set the thread's interrupt status
+ // throw new java.io.InterruptedIOException();
+ IoUtils.throwInterruptedIoException();
+ }
+ }
+ int ret = buffer[out++] & 0xFF;
+ if (out >= buffer.length) {
+ out = 0;
+ }
+ if (in == out) {
+ /* now empty */
+ in = -1;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Reads up to <code>len</code> bytes of data from this piped input
+ * stream into an array of bytes. Less than <code>len</code> bytes
+ * will be read if the end of the data stream is reached or if
+ * <code>len</code> exceeds the pipe's buffer size.
+ * If <code>len </code> is zero, then no bytes are read and 0 is returned;
+ * otherwise, the method blocks until at least 1 byte of input is
+ * available, end of the stream has been detected, or an exception is
+ * thrown.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in the destination array <code>b</code>
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the stream has been reached.
+ * @exception NullPointerException If <code>b</code> is <code>null</code>.
+ * @exception IndexOutOfBoundsException If <code>off</code> is negative,
+ * <code>len</code> is negative, or <code>len</code> is greater than
+ * <code>b.length - off</code>
+ * @exception IOException if the pipe is <a href="#BROKEN"> <code>broken</code></a>,
+ * {@link #connect(java.io.PipedOutputStream) unconnected},
+ * closed, or if an I/O error occurs.
+ */
+ public synchronized int read(byte b[], int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ /* possibly wait on the first character */
+ int c = read();
+ if (c < 0) {
+ return -1;
+ }
+ b[off] = (byte) c;
+ int rlen = 1;
+ while ((in >= 0) && (len > 1)) {
+
+ int available;
+
+ if (in > out) {
+ available = Math.min((buffer.length - out), (in - out));
+ } else {
+ available = buffer.length - out;
+ }
+
+ // A byte is read beforehand outside the loop
+ if (available > (len - 1)) {
+ available = len - 1;
+ }
+ System.arraycopy(buffer, out, b, off + rlen, available);
+ out += available;
+ rlen += available;
+ len -= available;
+
+ if (out >= buffer.length) {
+ out = 0;
+ }
+ if (in == out) {
+ /* now empty */
+ in = -1;
+ }
+ }
+ return rlen;
+ }
+
+ /**
+ * Returns the number of bytes that can be read from this input
+ * stream without blocking.
+ *
+ * @return the number of bytes that can be read from this input stream
+ * without blocking, or {@code 0} if this input stream has been
+ * closed by invoking its {@link #close()} method, or if the pipe
+ * is {@link #connect(java.io.PipedOutputStream) unconnected}, or
+ * <a href="#BROKEN"> <code>broken</code></a>.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @since JDK1.0.2
+ */
+ public synchronized int available() throws IOException {
+ if(in < 0)
+ return 0;
+ else if(in == out)
+ return buffer.length;
+ else if (in > out)
+ return in - out;
+ else
+ return in + buffer.length - out;
+ }
+
+ /**
+ * Closes this piped input stream and releases any system resources
+ * associated with the stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ */
+ public void close() throws IOException {
+ closedByReader = true;
+ synchronized (this) {
+ in = -1;
+ }
+ }
+}
diff --git a/java/io/PipedOutputStream.java b/java/io/PipedOutputStream.java
new file mode 100644
index 0000000..feed73a
--- /dev/null
+++ b/java/io/PipedOutputStream.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.*;
+
+/**
+ * A piped output stream can be connected to a piped input stream
+ * to create a communications pipe. The piped output stream is the
+ * sending end of the pipe. Typically, data is written to a
+ * <code>PipedOutputStream</code> object by one thread and data is
+ * read from the connected <code>PipedInputStream</code> by some
+ * other thread. Attempting to use both objects from a single thread
+ * is not recommended as it may deadlock the thread.
+ * The pipe is said to be <a name=BROKEN> <i>broken</i> </a> if a
+ * thread that was reading data bytes from the connected piped input
+ * stream is no longer alive.
+ *
+ * @author James Gosling
+ * @see java.io.PipedInputStream
+ * @since JDK1.0
+ */
+public
+class PipedOutputStream extends OutputStream {
+
+ /* REMIND: identification of the read and write sides needs to be
+ more sophisticated. Either using thread groups (but what about
+ pipes within a thread?) or using finalization (but it may be a
+ long time until the next GC). */
+ private PipedInputStream sink;
+
+ /**
+ * Creates a piped output stream connected to the specified piped
+ * input stream. Data bytes written to this stream will then be
+ * available as input from <code>snk</code>.
+ *
+ * @param snk The piped input stream to connect to.
+ * @exception IOException if an I/O error occurs.
+ */
+ public PipedOutputStream(PipedInputStream snk) throws IOException {
+ connect(snk);
+ }
+
+ /**
+ * Creates a piped output stream that is not yet connected to a
+ * piped input stream. It must be connected to a piped input stream,
+ * either by the receiver or the sender, before being used.
+ *
+ * @see java.io.PipedInputStream#connect(java.io.PipedOutputStream)
+ * @see java.io.PipedOutputStream#connect(java.io.PipedInputStream)
+ */
+ public PipedOutputStream() {
+ }
+
+ /**
+ * Connects this piped output stream to a receiver. If this object
+ * is already connected to some other piped input stream, an
+ * <code>IOException</code> is thrown.
+ * <p>
+ * If <code>snk</code> is an unconnected piped input stream and
+ * <code>src</code> is an unconnected piped output stream, they may
+ * be connected by either the call:
+ * <blockquote><pre>
+ * src.connect(snk)</pre></blockquote>
+ * or the call:
+ * <blockquote><pre>
+ * snk.connect(src)</pre></blockquote>
+ * The two calls have the same effect.
+ *
+ * @param snk the piped input stream to connect to.
+ * @exception IOException if an I/O error occurs.
+ */
+ public synchronized void connect(PipedInputStream snk) throws IOException {
+ if (snk == null) {
+ throw new NullPointerException();
+ } else if (sink != null || snk.connected) {
+ throw new IOException("Already connected");
+ }
+ sink = snk;
+ snk.in = -1;
+ snk.out = 0;
+ snk.connected = true;
+ }
+
+ /**
+ * Writes the specified <code>byte</code> to the piped output stream.
+ * <p>
+ * Implements the <code>write</code> method of <code>OutputStream</code>.
+ *
+ * @param b the <code>byte</code> to be written.
+ * @exception IOException if the pipe is <a href=#BROKEN> broken</a>,
+ * {@link #connect(java.io.PipedInputStream) unconnected},
+ * closed, or if an I/O error occurs.
+ */
+ public void write(int b) throws IOException {
+ if (sink == null) {
+ throw new IOException("Pipe not connected");
+ }
+ sink.receive(b);
+ }
+
+ /**
+ * Writes <code>len</code> bytes from the specified byte array
+ * starting at offset <code>off</code> to this piped output stream.
+ * This method blocks until all the bytes are written to the output
+ * stream.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @exception IOException if the pipe is <a href=#BROKEN> broken</a>,
+ * {@link #connect(java.io.PipedInputStream) unconnected},
+ * closed, or if an I/O error occurs.
+ */
+ public void write(byte b[], int off, int len) throws IOException {
+ if (sink == null) {
+ throw new IOException("Pipe not connected");
+ } else if (b == null) {
+ throw new NullPointerException();
+ } else if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) > b.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+ sink.receive(b, off, len);
+ }
+
+ /**
+ * Flushes this output stream and forces any buffered output bytes
+ * to be written out.
+ * This will notify any readers that bytes are waiting in the pipe.
+ *
+ * @exception IOException if an I/O error occurs.
+ */
+ public synchronized void flush() throws IOException {
+ if (sink != null) {
+ synchronized (sink) {
+ sink.notifyAll();
+ }
+ }
+ }
+
+ /**
+ * Closes this piped output stream and releases any system resources
+ * associated with this stream. This stream may no longer be used for
+ * writing bytes.
+ *
+ * @exception IOException if an I/O error occurs.
+ */
+ public void close() throws IOException {
+ if (sink != null) {
+ sink.receivedLast();
+ }
+ }
+}
diff --git a/java/io/PipedReader.java b/java/io/PipedReader.java
new file mode 100644
index 0000000..d72e1e5
--- /dev/null
+++ b/java/io/PipedReader.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import libcore.io.IoUtils;
+
+/**
+ * Piped character-input streams.
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class PipedReader extends Reader {
+ boolean closedByWriter = false;
+ boolean closedByReader = false;
+ boolean connected = false;
+
+ /* REMIND: identification of the read and write sides needs to be
+ more sophisticated. Either using thread groups (but what about
+ pipes within a thread?) or using finalization (but it may be a
+ long time until the next GC). */
+ Thread readSide;
+ Thread writeSide;
+
+ /**
+ * The size of the pipe's circular input buffer.
+ */
+ private static final int DEFAULT_PIPE_SIZE = 1024;
+
+ /**
+ * The circular buffer into which incoming data is placed.
+ */
+ char buffer[];
+
+ /**
+ * The index of the position in the circular buffer at which the
+ * next character of data will be stored when received from the connected
+ * piped writer. <code>in<0</code> implies the buffer is empty,
+ * <code>in==out</code> implies the buffer is full
+ */
+ int in = -1;
+
+ /**
+ * The index of the position in the circular buffer at which the next
+ * character of data will be read by this piped reader.
+ */
+ int out = 0;
+
+ /**
+ * Creates a <code>PipedReader</code> so
+ * that it is connected to the piped writer
+ * <code>src</code>. Data written to <code>src</code>
+ * will then be available as input from this stream.
+ *
+ * @param src the stream to connect to.
+ * @exception IOException if an I/O error occurs.
+ */
+ public PipedReader(PipedWriter src) throws IOException {
+ this(src, DEFAULT_PIPE_SIZE);
+ }
+
+ /**
+ * Creates a <code>PipedReader</code> so that it is connected
+ * to the piped writer <code>src</code> and uses the specified
+ * pipe size for the pipe's buffer. Data written to <code>src</code>
+ * will then be available as input from this stream.
+
+ * @param src the stream to connect to.
+ * @param pipeSize the size of the pipe's buffer.
+ * @exception IOException if an I/O error occurs.
+ * @exception IllegalArgumentException if {@code pipeSize <= 0}.
+ * @since 1.6
+ */
+ public PipedReader(PipedWriter src, int pipeSize) throws IOException {
+ initPipe(pipeSize);
+ connect(src);
+ }
+
+
+ /**
+ * Creates a <code>PipedReader</code> so
+ * that it is not yet {@linkplain #connect(java.io.PipedWriter)
+ * connected}. It must be {@linkplain java.io.PipedWriter#connect(
+ * java.io.PipedReader) connected} to a <code>PipedWriter</code>
+ * before being used.
+ */
+ public PipedReader() {
+ initPipe(DEFAULT_PIPE_SIZE);
+ }
+
+ /**
+ * Creates a <code>PipedReader</code> so that it is not yet
+ * {@link #connect(java.io.PipedWriter) connected} and uses
+ * the specified pipe size for the pipe's buffer.
+ * It must be {@linkplain java.io.PipedWriter#connect(
+ * java.io.PipedReader) connected} to a <code>PipedWriter</code>
+ * before being used.
+ *
+ * @param pipeSize the size of the pipe's buffer.
+ * @exception IllegalArgumentException if {@code pipeSize <= 0}.
+ * @since 1.6
+ */
+ public PipedReader(int pipeSize) {
+ initPipe(pipeSize);
+ }
+
+ private void initPipe(int pipeSize) {
+ if (pipeSize <= 0) {
+ throw new IllegalArgumentException("Pipe size <= 0");
+ }
+ buffer = new char[pipeSize];
+ }
+
+ /**
+ * Causes this piped reader to be connected
+ * to the piped writer <code>src</code>.
+ * If this object is already connected to some
+ * other piped writer, an <code>IOException</code>
+ * is thrown.
+ * <p>
+ * If <code>src</code> is an
+ * unconnected piped writer and <code>snk</code>
+ * is an unconnected piped reader, they
+ * may be connected by either the call:
+ *
+ * <pre><code>snk.connect(src)</code> </pre>
+ * <p>
+ * or the call:
+ *
+ * <pre><code>src.connect(snk)</code> </pre>
+ * <p>
+ * The two calls have the same effect.
+ *
+ * @param src The piped writer to connect to.
+ * @exception IOException if an I/O error occurs.
+ */
+ public void connect(PipedWriter src) throws IOException {
+ src.connect(this);
+ }
+
+ /**
+ * Receives a char of data. This method will block if no input is
+ * available.
+ */
+ synchronized void receive(int c) throws IOException {
+ if (!connected) {
+ throw new IOException("Pipe not connected");
+ } else if (closedByWriter || closedByReader) {
+ throw new IOException("Pipe closed");
+ } else if (readSide != null && !readSide.isAlive()) {
+ throw new IOException("Read end dead");
+ }
+
+ writeSide = Thread.currentThread();
+ while (in == out) {
+ if ((readSide != null) && !readSide.isAlive()) {
+ throw new IOException("Pipe broken");
+ }
+ /* full: kick any waiting readers */
+ notifyAll();
+ try {
+ wait(1000);
+ } catch (InterruptedException ex) {
+ // Android-changed: re-set the thread's interrupt status
+ // throw new java.io.InterruptedIOException();
+ IoUtils.throwInterruptedIoException();
+ }
+ }
+ if (in < 0) {
+ in = 0;
+ out = 0;
+ }
+ buffer[in++] = (char) c;
+ if (in >= buffer.length) {
+ in = 0;
+ }
+ }
+
+ /**
+ * Receives data into an array of characters. This method will
+ * block until some input is available.
+ */
+ synchronized void receive(char c[], int off, int len) throws IOException {
+ while (--len >= 0) {
+ receive(c[off++]);
+ }
+ }
+
+ /**
+ * Notifies all waiting threads that the last character of data has been
+ * received.
+ */
+ synchronized void receivedLast() {
+ closedByWriter = true;
+ notifyAll();
+ }
+
+ /**
+ * Reads the next character of data from this piped stream.
+ * If no character is available because the end of the stream
+ * has been reached, the value <code>-1</code> is returned.
+ * This method blocks until input data is available, the end of
+ * the stream is detected, or an exception is thrown.
+ *
+ * @return the next character of data, or <code>-1</code> if the end of the
+ * stream is reached.
+ * @exception IOException if the pipe is
+ * <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
+ * {@link #connect(java.io.PipedWriter) unconnected}, closed,
+ * or an I/O error occurs.
+ */
+ public synchronized int read() throws IOException {
+ if (!connected) {
+ throw new IOException("Pipe not connected");
+ } else if (closedByReader) {
+ throw new IOException("Pipe closed");
+ } else if (writeSide != null && !writeSide.isAlive()
+ && !closedByWriter && (in < 0)) {
+ throw new IOException("Write end dead");
+ }
+
+ readSide = Thread.currentThread();
+ int trials = 2;
+ while (in < 0) {
+ if (closedByWriter) {
+ /* closed by writer, return EOF */
+ return -1;
+ }
+ if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {
+ throw new IOException("Pipe broken");
+ }
+ /* might be a writer waiting */
+ notifyAll();
+ try {
+ wait(1000);
+ } catch (InterruptedException ex) {
+ // Android-changed: re-set the thread's interrupt status
+ // throw new java.io.InterruptedIOException();
+ IoUtils.throwInterruptedIoException();
+ }
+ }
+ int ret = buffer[out++];
+ if (out >= buffer.length) {
+ out = 0;
+ }
+ if (in == out) {
+ /* now empty */
+ in = -1;
+ }
+ return ret;
+ }
+
+ /**
+ * Reads up to <code>len</code> characters of data from this piped
+ * stream into an array of characters. Less than <code>len</code> characters
+ * will be read if the end of the data stream is reached or if
+ * <code>len</code> exceeds the pipe's buffer size. This method
+ * blocks until at least one character of input is available.
+ *
+ * @param cbuf the buffer into which the data is read.
+ * @param off the start offset of the data.
+ * @param len the maximum number of characters read.
+ * @return the total number of characters read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the stream has been reached.
+ * @exception IOException if the pipe is
+ * <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
+ * {@link #connect(java.io.PipedWriter) unconnected}, closed,
+ * or an I/O error occurs.
+ */
+ public synchronized int read(char cbuf[], int off, int len) throws IOException {
+ if (!connected) {
+ throw new IOException("Pipe not connected");
+ } else if (closedByReader) {
+ throw new IOException("Pipe closed");
+ } else if (writeSide != null && !writeSide.isAlive()
+ && !closedByWriter && (in < 0)) {
+ throw new IOException("Write end dead");
+ }
+
+ if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+ ((off + len) > cbuf.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ /* possibly wait on the first character */
+ int c = read();
+ if (c < 0) {
+ return -1;
+ }
+ cbuf[off] = (char)c;
+ int rlen = 1;
+ while ((in >= 0) && (--len > 0)) {
+ cbuf[off + rlen] = buffer[out++];
+ rlen++;
+ if (out >= buffer.length) {
+ out = 0;
+ }
+ if (in == out) {
+ /* now empty */
+ in = -1;
+ }
+ }
+ return rlen;
+ }
+
+ /**
+ * Tell whether this stream is ready to be read. A piped character
+ * stream is ready if the circular buffer is not empty.
+ *
+ * @exception IOException if the pipe is
+ * <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
+ * {@link #connect(java.io.PipedWriter) unconnected}, or closed.
+ */
+ public synchronized boolean ready() throws IOException {
+ if (!connected) {
+ throw new IOException("Pipe not connected");
+ } else if (closedByReader) {
+ throw new IOException("Pipe closed");
+ } else if (writeSide != null && !writeSide.isAlive()
+ && !closedByWriter && (in < 0)) {
+ throw new IOException("Write end dead");
+ }
+ if (in < 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Closes this piped stream and releases any system resources
+ * associated with the stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ */
+ public void close() throws IOException {
+ in = -1;
+ closedByReader = true;
+ }
+}
diff --git a/java/io/PipedWriter.java b/java/io/PipedWriter.java
new file mode 100644
index 0000000..46e1455
--- /dev/null
+++ b/java/io/PipedWriter.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Piped character-output streams.
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class PipedWriter extends Writer {
+
+ /* REMIND: identification of the read and write sides needs to be
+ more sophisticated. Either using thread groups (but what about
+ pipes within a thread?) or using finalization (but it may be a
+ long time until the next GC). */
+ private PipedReader sink;
+
+ /* This flag records the open status of this particular writer. It
+ * is independent of the status flags defined in PipedReader. It is
+ * used to do a sanity check on connect.
+ */
+ private boolean closed = false;
+
+ /**
+ * Creates a piped writer connected to the specified piped
+ * reader. Data characters written to this stream will then be
+ * available as input from <code>snk</code>.
+ *
+ * @param snk The piped reader to connect to.
+ * @exception IOException if an I/O error occurs.
+ */
+ public PipedWriter(PipedReader snk) throws IOException {
+ connect(snk);
+ }
+
+ /**
+ * Creates a piped writer that is not yet connected to a
+ * piped reader. It must be connected to a piped reader,
+ * either by the receiver or the sender, before being used.
+ *
+ * @see java.io.PipedReader#connect(java.io.PipedWriter)
+ * @see java.io.PipedWriter#connect(java.io.PipedReader)
+ */
+ public PipedWriter() {
+ }
+
+ /**
+ * Connects this piped writer to a receiver. If this object
+ * is already connected to some other piped reader, an
+ * <code>IOException</code> is thrown.
+ * <p>
+ * If <code>snk</code> is an unconnected piped reader and
+ * <code>src</code> is an unconnected piped writer, they may
+ * be connected by either the call:
+ * <blockquote><pre>
+ * src.connect(snk)</pre></blockquote>
+ * or the call:
+ * <blockquote><pre>
+ * snk.connect(src)</pre></blockquote>
+ * The two calls have the same effect.
+ *
+ * @param snk the piped reader to connect to.
+ * @exception IOException if an I/O error occurs.
+ */
+ public synchronized void connect(PipedReader snk) throws IOException {
+ if (snk == null) {
+ throw new NullPointerException();
+ } else if (sink != null || snk.connected) {
+ throw new IOException("Already connected");
+ } else if (snk.closedByReader || closed) {
+ throw new IOException("Pipe closed");
+ }
+
+ sink = snk;
+ snk.in = -1;
+ snk.out = 0;
+ snk.connected = true;
+ }
+
+ /**
+ * Writes the specified <code>char</code> to the piped output stream.
+ * If a thread was reading data characters from the connected piped input
+ * stream, but the thread is no longer alive, then an
+ * <code>IOException</code> is thrown.
+ * <p>
+ * Implements the <code>write</code> method of <code>Writer</code>.
+ *
+ * @param c the <code>char</code> to be written.
+ * @exception IOException if the pipe is
+ * <a href=PipedOutputStream.html#BROKEN> <code>broken</code></a>,
+ * {@link #connect(java.io.PipedReader) unconnected}, closed
+ * or an I/O error occurs.
+ */
+ public void write(int c) throws IOException {
+ if (sink == null) {
+ throw new IOException("Pipe not connected");
+ }
+ sink.receive(c);
+ }
+
+ /**
+ * Writes <code>len</code> characters from the specified character array
+ * starting at offset <code>off</code> to this piped output stream.
+ * This method blocks until all the characters are written to the output
+ * stream.
+ * If a thread was reading data characters from the connected piped input
+ * stream, but the thread is no longer alive, then an
+ * <code>IOException</code> is thrown.
+ *
+ * @param cbuf the data.
+ * @param off the start offset in the data.
+ * @param len the number of characters to write.
+ * @exception IOException if the pipe is
+ * <a href=PipedOutputStream.html#BROKEN> <code>broken</code></a>,
+ * {@link #connect(java.io.PipedReader) unconnected}, closed
+ * or an I/O error occurs.
+ */
+ public void write(char cbuf[], int off, int len) throws IOException {
+ if (sink == null) {
+ throw new IOException("Pipe not connected");
+ } else if ((off | len | (off + len) | (cbuf.length - (off + len))) < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ sink.receive(cbuf, off, len);
+ }
+
+ /**
+ * Flushes this output stream and forces any buffered output characters
+ * to be written out.
+ * This will notify any readers that characters are waiting in the pipe.
+ *
+ * @exception IOException if the pipe is closed, or an I/O error occurs.
+ */
+ public synchronized void flush() throws IOException {
+ if (sink != null) {
+ if (sink.closedByReader || closed) {
+ throw new IOException("Pipe closed");
+ }
+ synchronized (sink) {
+ sink.notifyAll();
+ }
+ }
+ }
+
+ /**
+ * Closes this piped output stream and releases any system resources
+ * associated with this stream. This stream may no longer be used for
+ * writing characters.
+ *
+ * @exception IOException if an I/O error occurs.
+ */
+ public void close() throws IOException {
+ closed = true;
+ if (sink != null) {
+ sink.receivedLast();
+ }
+ }
+}
diff --git a/java/io/PrintStream.java b/java/io/PrintStream.java
new file mode 100644
index 0000000..809d39b
--- /dev/null
+++ b/java/io/PrintStream.java
@@ -0,0 +1,1158 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.Formatter;
+import java.util.Locale;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+
+/**
+ * A <code>PrintStream</code> adds functionality to another output stream,
+ * namely the ability to print representations of various data values
+ * conveniently. Two other features are provided as well. Unlike other output
+ * streams, a <code>PrintStream</code> never throws an
+ * <code>IOException</code>; instead, exceptional situations merely set an
+ * internal flag that can be tested via the <code>checkError</code> method.
+ * Optionally, a <code>PrintStream</code> can be created so as to flush
+ * automatically; this means that the <code>flush</code> method is
+ * automatically invoked after a byte array is written, one of the
+ * <code>println</code> methods is invoked, or a newline character or byte
+ * (<code>'\n'</code>) is written.
+ *
+ * <p> All characters printed by a <code>PrintStream</code> are converted into
+ * bytes using the platform's default character encoding. The <code>{@link
+ * PrintWriter}</code> class should be used in situations that require writing
+ * characters rather than bytes.
+ *
+ * @author Frank Yellin
+ * @author Mark Reinhold
+ * @since JDK1.0
+ */
+
+public class PrintStream extends FilterOutputStream
+ implements Appendable, Closeable
+{
+
+ private final boolean autoFlush;
+ private boolean trouble = false;
+ private Formatter formatter;
+
+ /**
+ * Track both the text- and character-output streams, so that their buffers
+ * can be flushed without flushing the entire stream.
+ */
+ private BufferedWriter textOut;
+ private OutputStreamWriter charOut;
+
+ // Android-added: Lazy initialization of charOut and textOut.
+ private Charset charset;
+
+ /**
+ * requireNonNull is explicitly declared here so as not to create an extra
+ * dependency on java.util.Objects.requireNonNull. PrintStream is loaded
+ * early during system initialization.
+ */
+ private static <T> T requireNonNull(T obj, String message) {
+ if (obj == null)
+ throw new NullPointerException(message);
+ return obj;
+ }
+
+ /**
+ * Returns a charset object for the given charset name.
+ * @throws NullPointerException is csn is null
+ * @throws UnsupportedEncodingException if the charset is not supported
+ */
+ private static Charset toCharset(String csn)
+ throws UnsupportedEncodingException
+ {
+ requireNonNull(csn, "charsetName");
+ try {
+ return Charset.forName(csn);
+ } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
+ // UnsupportedEncodingException should be thrown
+ throw new UnsupportedEncodingException(csn);
+ }
+ }
+
+ /* Private constructors */
+ private PrintStream(boolean autoFlush, OutputStream out) {
+ super(out);
+ this.autoFlush = autoFlush;
+ // Android-changed: Lazy initialization of charOut and textOut.
+ // this.charOut = new OutputStreamWriter(this);
+ // this.textOut = new BufferedWriter(charOut);
+ }
+
+ private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
+ super(out);
+ this.autoFlush = autoFlush;
+ // Android-changed: Lazy initialization of charOut and textOut.
+ // this.charOut = new OutputStreamWriter(this, charset);
+ // this.textOut = new BufferedWriter(charOut);
+ this.charset = charset;
+ }
+
+ /* Variant of the private constructor so that the given charset name
+ * can be verified before evaluating the OutputStream argument. Used
+ * by constructors creating a FileOutputStream that also take a
+ * charset name.
+ */
+ private PrintStream(boolean autoFlush, Charset charset, OutputStream out)
+ throws UnsupportedEncodingException
+ {
+ this(autoFlush, out, charset);
+ }
+
+ /**
+ * Creates a new print stream. This stream will not flush automatically.
+ *
+ * @param out The output stream to which values and objects will be
+ * printed
+ *
+ * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream)
+ */
+ public PrintStream(OutputStream out) {
+ this(out, false);
+ }
+
+ /**
+ * Creates a new print stream.
+ *
+ * @param out The output stream to which values and objects will be
+ * printed
+ * @param autoFlush A boolean; if true, the output buffer will be flushed
+ * whenever a byte array is written, one of the
+ * <code>println</code> methods is invoked, or a newline
+ * character or byte (<code>'\n'</code>) is written
+ *
+ * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean)
+ */
+ public PrintStream(OutputStream out, boolean autoFlush) {
+ this(autoFlush, requireNonNull(out, "Null output stream"));
+ }
+
+ /**
+ * Creates a new print stream.
+ *
+ * @param out The output stream to which values and objects will be
+ * printed
+ * @param autoFlush A boolean; if true, the output buffer will be flushed
+ * whenever a byte array is written, one of the
+ * <code>println</code> methods is invoked, or a newline
+ * character or byte (<code>'\n'</code>) is written
+ * @param encoding The name of a supported
+ * <a href="../lang/package-summary.html#charenc">
+ * character encoding</a>
+ *
+ * @throws UnsupportedEncodingException
+ * If the named encoding is not supported
+ *
+ * @since 1.4
+ */
+ public PrintStream(OutputStream out, boolean autoFlush, String encoding)
+ throws UnsupportedEncodingException
+ {
+ this(autoFlush,
+ requireNonNull(out, "Null output stream"),
+ toCharset(encoding));
+ }
+
+ /**
+ * Creates a new print stream, without automatic line flushing, with the
+ * specified file name. This convenience constructor creates
+ * the necessary intermediate {@link java.io.OutputStreamWriter
+ * OutputStreamWriter}, which will encode characters using the
+ * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}
+ * for this instance of the Java virtual machine.
+ *
+ * @param fileName
+ * The name of the file to use as the destination of this print
+ * stream. If the file exists, then it will be truncated to
+ * zero size; otherwise, a new file will be created. The output
+ * will be written to the file and is buffered.
+ *
+ * @throws FileNotFoundException
+ * If the given file object does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(fileName)} denies write
+ * access to the file
+ *
+ * @since 1.5
+ */
+ public PrintStream(String fileName) throws FileNotFoundException {
+ this(false, new FileOutputStream(fileName));
+ }
+
+ /**
+ * Creates a new print stream, without automatic line flushing, with the
+ * specified file name and charset. This convenience constructor creates
+ * the necessary intermediate {@link java.io.OutputStreamWriter
+ * OutputStreamWriter}, which will encode characters using the provided
+ * charset.
+ *
+ * @param fileName
+ * The name of the file to use as the destination of this print
+ * stream. If the file exists, then it will be truncated to
+ * zero size; otherwise, a new file will be created. The output
+ * will be written to the file and is buffered.
+ *
+ * @param csn
+ * The name of a supported {@linkplain java.nio.charset.Charset
+ * charset}
+ *
+ * @throws FileNotFoundException
+ * If the given file object does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(fileName)} denies write
+ * access to the file
+ *
+ * @throws UnsupportedEncodingException
+ * If the named charset is not supported
+ *
+ * @since 1.5
+ */
+ public PrintStream(String fileName, String csn)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ // ensure charset is checked before the file is opened
+ this(false, toCharset(csn), new FileOutputStream(fileName));
+ }
+
+ /**
+ * Creates a new print stream, without automatic line flushing, with the
+ * specified file. This convenience constructor creates the necessary
+ * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
+ * which will encode characters using the {@linkplain
+ * java.nio.charset.Charset#defaultCharset() default charset} for this
+ * instance of the Java virtual machine.
+ *
+ * @param file
+ * The file to use as the destination of this print stream. If the
+ * file exists, then it will be truncated to zero size; otherwise,
+ * a new file will be created. The output will be written to the
+ * file and is buffered.
+ *
+ * @throws FileNotFoundException
+ * If the given file object does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(file.getPath())}
+ * denies write access to the file
+ *
+ * @since 1.5
+ */
+ public PrintStream(File file) throws FileNotFoundException {
+ this(false, new FileOutputStream(file));
+ }
+
+ /**
+ * Creates a new print stream, without automatic line flushing, with the
+ * specified file and charset. This convenience constructor creates
+ * the necessary intermediate {@link java.io.OutputStreamWriter
+ * OutputStreamWriter}, which will encode characters using the provided
+ * charset.
+ *
+ * @param file
+ * The file to use as the destination of this print stream. If the
+ * file exists, then it will be truncated to zero size; otherwise,
+ * a new file will be created. The output will be written to the
+ * file and is buffered.
+ *
+ * @param csn
+ * The name of a supported {@linkplain java.nio.charset.Charset
+ * charset}
+ *
+ * @throws FileNotFoundException
+ * If the given file object does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(file.getPath())}
+ * denies write access to the file
+ *
+ * @throws UnsupportedEncodingException
+ * If the named charset is not supported
+ *
+ * @since 1.5
+ */
+ public PrintStream(File file, String csn)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ // ensure charset is checked before the file is opened
+ this(false, toCharset(csn), new FileOutputStream(file));
+ }
+
+ /** Check to make sure that the stream has not been closed */
+ private void ensureOpen() throws IOException {
+ if (out == null)
+ throw new IOException("Stream closed");
+ }
+
+ /**
+ * Flushes the stream. This is done by writing any buffered output bytes to
+ * the underlying output stream and then flushing that stream.
+ *
+ * @see java.io.OutputStream#flush()
+ */
+ public void flush() {
+ synchronized (this) {
+ try {
+ ensureOpen();
+ out.flush();
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+ }
+
+ private boolean closing = false; /* To avoid recursive closing */
+
+ // BEGIN Android-added: Lazy initialization of charOut and textOut.
+ private BufferedWriter getTextOut() {
+ if (textOut == null) {
+ charOut = charset != null ? new OutputStreamWriter(this, charset) :
+ new OutputStreamWriter(this);
+ textOut = new BufferedWriter(charOut);
+ }
+ return textOut;
+ }
+ // END Android-added: Lazy initialization of charOut and textOut.
+
+ /**
+ * Closes the stream. This is done by flushing the stream and then closing
+ * the underlying output stream.
+ *
+ * @see java.io.OutputStream#close()
+ */
+ public void close() {
+ synchronized (this) {
+ if (! closing) {
+ closing = true;
+ try {
+ // BEGIN Android-changed: Lazy initialization of charOut and textOut.
+ // textOut.close();
+ if (textOut != null) {
+ textOut.close();
+ }
+ // END Android-changed: Lazy initialization of charOut and textOut.
+ out.close();
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ textOut = null;
+ charOut = null;
+ out = null;
+ }
+ }
+ }
+
+ /**
+ * Flushes the stream and checks its error state. The internal error state
+ * is set to <code>true</code> when the underlying output stream throws an
+ * <code>IOException</code> other than <code>InterruptedIOException</code>,
+ * and when the <code>setError</code> method is invoked. If an operation
+ * on the underlying output stream throws an
+ * <code>InterruptedIOException</code>, then the <code>PrintStream</code>
+ * converts the exception back into an interrupt by doing:
+ * <pre>
+ * Thread.currentThread().interrupt();
+ * </pre>
+ * or the equivalent.
+ *
+ * @return <code>true</code> if and only if this stream has encountered an
+ * <code>IOException</code> other than
+ * <code>InterruptedIOException</code>, or the
+ * <code>setError</code> method has been invoked
+ */
+ public boolean checkError() {
+ if (out != null)
+ flush();
+ if (out instanceof java.io.PrintStream) {
+ PrintStream ps = (PrintStream) out;
+ return ps.checkError();
+ }
+ return trouble;
+ }
+
+ /**
+ * Sets the error state of the stream to <code>true</code>.
+ *
+ * <p> This method will cause subsequent invocations of {@link
+ * #checkError()} to return <tt>true</tt> until {@link
+ * #clearError()} is invoked.
+ *
+ * @since JDK1.1
+ */
+ protected void setError() {
+ trouble = true;
+ }
+
+ /**
+ * Clears the internal error state of this stream.
+ *
+ * <p> This method will cause subsequent invocations of {@link
+ * #checkError()} to return <tt>false</tt> until another write
+ * operation fails and invokes {@link #setError()}.
+ *
+ * @since 1.6
+ */
+ protected void clearError() {
+ trouble = false;
+ }
+
+ /*
+ * Exception-catching, synchronized output operations,
+ * which also implement the write() methods of OutputStream
+ */
+
+ /**
+ * Writes the specified byte to this stream. If the byte is a newline and
+ * automatic flushing is enabled then the <code>flush</code> method will be
+ * invoked.
+ *
+ * <p> Note that the byte is written as given; to write a character that
+ * will be translated according to the platform's default character
+ * encoding, use the <code>print(char)</code> or <code>println(char)</code>
+ * methods.
+ *
+ * @param b The byte to be written
+ * @see #print(char)
+ * @see #println(char)
+ */
+ public void write(int b) {
+ try {
+ synchronized (this) {
+ ensureOpen();
+ out.write(b);
+ if ((b == '\n') && autoFlush)
+ out.flush();
+ }
+ }
+ catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+
+ /**
+ * Writes <code>len</code> bytes from the specified byte array starting at
+ * offset <code>off</code> to this stream. If automatic flushing is
+ * enabled then the <code>flush</code> method will be invoked.
+ *
+ * <p> Note that the bytes will be written as given; to write characters
+ * that will be translated according to the platform's default character
+ * encoding, use the <code>print(char)</code> or <code>println(char)</code>
+ * methods.
+ *
+ * @param buf A byte array
+ * @param off Offset from which to start taking bytes
+ * @param len Number of bytes to write
+ */
+ public void write(byte buf[], int off, int len) {
+ try {
+ synchronized (this) {
+ ensureOpen();
+ out.write(buf, off, len);
+ if (autoFlush)
+ out.flush();
+ }
+ }
+ catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+
+ /*
+ * The following private methods on the text- and character-output streams
+ * always flush the stream buffers, so that writes to the underlying byte
+ * stream occur as promptly as with the original PrintStream.
+ */
+
+ private void write(char buf[]) {
+ try {
+ synchronized (this) {
+ ensureOpen();
+ // Android-added: Lazy initialization of charOut and textOut.
+ BufferedWriter textOut = getTextOut();
+ textOut.write(buf);
+ textOut.flushBuffer();
+ charOut.flushBuffer();
+ if (autoFlush) {
+ for (int i = 0; i < buf.length; i++)
+ if (buf[i] == '\n')
+ out.flush();
+ }
+ }
+ }
+ catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+
+ private void write(String s) {
+ try {
+ synchronized (this) {
+ ensureOpen();
+ // Android-added: Lazy initialization of charOut and textOut.
+ BufferedWriter textOut = getTextOut();
+ textOut.write(s);
+ textOut.flushBuffer();
+ charOut.flushBuffer();
+ if (autoFlush && (s.indexOf('\n') >= 0))
+ out.flush();
+ }
+ }
+ catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+
+ private void newLine() {
+ try {
+ synchronized (this) {
+ ensureOpen();
+ // Android-added: Lazy initialization of charOut and textOut.
+ BufferedWriter textOut = getTextOut();
+ textOut.newLine();
+ textOut.flushBuffer();
+ charOut.flushBuffer();
+ if (autoFlush)
+ out.flush();
+ }
+ }
+ catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+
+ /* Methods that do not terminate lines */
+
+ /**
+ * Prints a boolean value. The string produced by <code>{@link
+ * java.lang.String#valueOf(boolean)}</code> is translated into bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the
+ * <code>{@link #write(int)}</code> method.
+ *
+ * @param b The <code>boolean</code> to be printed
+ */
+ public void print(boolean b) {
+ write(b ? "true" : "false");
+ }
+
+ /**
+ * Prints a character. The character is translated into one or more bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the
+ * <code>{@link #write(int)}</code> method.
+ *
+ * @param c The <code>char</code> to be printed
+ */
+ public void print(char c) {
+ write(String.valueOf(c));
+ }
+
+ /**
+ * Prints an integer. The string produced by <code>{@link
+ * java.lang.String#valueOf(int)}</code> is translated into bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the
+ * <code>{@link #write(int)}</code> method.
+ *
+ * @param i The <code>int</code> to be printed
+ * @see java.lang.Integer#toString(int)
+ */
+ public void print(int i) {
+ write(String.valueOf(i));
+ }
+
+ /**
+ * Prints a long integer. The string produced by <code>{@link
+ * java.lang.String#valueOf(long)}</code> is translated into bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the
+ * <code>{@link #write(int)}</code> method.
+ *
+ * @param l The <code>long</code> to be printed
+ * @see java.lang.Long#toString(long)
+ */
+ public void print(long l) {
+ write(String.valueOf(l));
+ }
+
+ /**
+ * Prints a floating-point number. The string produced by <code>{@link
+ * java.lang.String#valueOf(float)}</code> is translated into bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the
+ * <code>{@link #write(int)}</code> method.
+ *
+ * @param f The <code>float</code> to be printed
+ * @see java.lang.Float#toString(float)
+ */
+ public void print(float f) {
+ write(String.valueOf(f));
+ }
+
+ /**
+ * Prints a double-precision floating-point number. The string produced by
+ * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
+ * bytes according to the platform's default character encoding, and these
+ * bytes are written in exactly the manner of the <code>{@link
+ * #write(int)}</code> method.
+ *
+ * @param d The <code>double</code> to be printed
+ * @see java.lang.Double#toString(double)
+ */
+ public void print(double d) {
+ write(String.valueOf(d));
+ }
+
+ /**
+ * Prints an array of characters. The characters are converted into bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the
+ * <code>{@link #write(int)}</code> method.
+ *
+ * @param s The array of chars to be printed
+ *
+ * @throws NullPointerException If <code>s</code> is <code>null</code>
+ */
+ public void print(char s[]) {
+ write(s);
+ }
+
+ /**
+ * Prints a string. If the argument is <code>null</code> then the string
+ * <code>"null"</code> is printed. Otherwise, the string's characters are
+ * converted into bytes according to the platform's default character
+ * encoding, and these bytes are written in exactly the manner of the
+ * <code>{@link #write(int)}</code> method.
+ *
+ * @param s The <code>String</code> to be printed
+ */
+ public void print(String s) {
+ if (s == null) {
+ s = "null";
+ }
+ write(s);
+ }
+
+ /**
+ * Prints an object. The string produced by the <code>{@link
+ * java.lang.String#valueOf(Object)}</code> method is translated into bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the
+ * <code>{@link #write(int)}</code> method.
+ *
+ * @param obj The <code>Object</code> to be printed
+ * @see java.lang.Object#toString()
+ */
+ public void print(Object obj) {
+ write(String.valueOf(obj));
+ }
+
+
+ /* Methods that do terminate lines */
+
+ /**
+ * Terminates the current line by writing the line separator string. The
+ * line separator string is defined by the system property
+ * <code>line.separator</code>, and is not necessarily a single newline
+ * character (<code>'\n'</code>).
+ */
+ public void println() {
+ newLine();
+ }
+
+ /**
+ * Prints a boolean and then terminate the line. This method behaves as
+ * though it invokes <code>{@link #print(boolean)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x The <code>boolean</code> to be printed
+ */
+ public void println(boolean x) {
+ synchronized (this) {
+ print(x);
+ newLine();
+ }
+ }
+
+ /**
+ * Prints a character and then terminate the line. This method behaves as
+ * though it invokes <code>{@link #print(char)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x The <code>char</code> to be printed.
+ */
+ public void println(char x) {
+ synchronized (this) {
+ print(x);
+ newLine();
+ }
+ }
+
+ /**
+ * Prints an integer and then terminate the line. This method behaves as
+ * though it invokes <code>{@link #print(int)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x The <code>int</code> to be printed.
+ */
+ public void println(int x) {
+ synchronized (this) {
+ print(x);
+ newLine();
+ }
+ }
+
+ /**
+ * Prints a long and then terminate the line. This method behaves as
+ * though it invokes <code>{@link #print(long)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x a The <code>long</code> to be printed.
+ */
+ public void println(long x) {
+ synchronized (this) {
+ print(x);
+ newLine();
+ }
+ }
+
+ /**
+ * Prints a float and then terminate the line. This method behaves as
+ * though it invokes <code>{@link #print(float)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x The <code>float</code> to be printed.
+ */
+ public void println(float x) {
+ synchronized (this) {
+ print(x);
+ newLine();
+ }
+ }
+
+ /**
+ * Prints a double and then terminate the line. This method behaves as
+ * though it invokes <code>{@link #print(double)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x The <code>double</code> to be printed.
+ */
+ public void println(double x) {
+ synchronized (this) {
+ print(x);
+ newLine();
+ }
+ }
+
+ /**
+ * Prints an array of characters and then terminate the line. This method
+ * behaves as though it invokes <code>{@link #print(char[])}</code> and
+ * then <code>{@link #println()}</code>.
+ *
+ * @param x an array of chars to print.
+ */
+ public void println(char x[]) {
+ synchronized (this) {
+ print(x);
+ newLine();
+ }
+ }
+
+ /**
+ * Prints a String and then terminate the line. This method behaves as
+ * though it invokes <code>{@link #print(String)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x The <code>String</code> to be printed.
+ */
+ public void println(String x) {
+ synchronized (this) {
+ print(x);
+ newLine();
+ }
+ }
+
+ /**
+ * Prints an Object and then terminate the line. This method calls
+ * at first String.valueOf(x) to get the printed object's string value,
+ * then behaves as
+ * though it invokes <code>{@link #print(String)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x The <code>Object</code> to be printed.
+ */
+ public void println(Object x) {
+ String s = String.valueOf(x);
+ synchronized (this) {
+ print(s);
+ newLine();
+ }
+ }
+
+
+ /**
+ * A convenience method to write a formatted string to this output stream
+ * using the specified format string and arguments.
+ *
+ * <p> An invocation of this method of the form <tt>out.printf(format,
+ * args)</tt> behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.format(format, args) </pre>
+ *
+ * @param format
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The number of arguments is
+ * variable and may be zero. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ * The behaviour on a
+ * <tt>null</tt> argument depends on the <a
+ * href="../util/Formatter.html#syntax">conversion</a>.
+ *
+ * @throws java.util.IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a> section of the
+ * formatter class specification.
+ *
+ * @throws NullPointerException
+ * If the <tt>format</tt> is <tt>null</tt>
+ *
+ * @return This output stream
+ *
+ * @since 1.5
+ */
+ public PrintStream printf(String format, Object ... args) {
+ return format(format, args);
+ }
+
+ /**
+ * A convenience method to write a formatted string to this output stream
+ * using the specified format string and arguments.
+ *
+ * <p> An invocation of this method of the form <tt>out.printf(l, format,
+ * args)</tt> behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.format(l, format, args) </pre>
+ *
+ * @param l
+ * The {@linkplain java.util.Locale locale} to apply during
+ * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
+ * is applied.
+ *
+ * @param format
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The number of arguments is
+ * variable and may be zero. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ * The behaviour on a
+ * <tt>null</tt> argument depends on the <a
+ * href="../util/Formatter.html#syntax">conversion</a>.
+ *
+ * @throws java.util.IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a> section of the
+ * formatter class specification.
+ *
+ * @throws NullPointerException
+ * If the <tt>format</tt> is <tt>null</tt>
+ *
+ * @return This output stream
+ *
+ * @since 1.5
+ */
+ public PrintStream printf(Locale l, String format, Object ... args) {
+ return format(l, format, args);
+ }
+
+ /**
+ * Writes a formatted string to this output stream using the specified
+ * format string and arguments.
+ *
+ * <p> The locale always used is the one returned by {@link
+ * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any
+ * previous invocations of other formatting methods on this object.
+ *
+ * @param format
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The number of arguments is
+ * variable and may be zero. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ * The behaviour on a
+ * <tt>null</tt> argument depends on the <a
+ * href="../util/Formatter.html#syntax">conversion</a>.
+ *
+ * @throws java.util.IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a> section of the
+ * formatter class specification.
+ *
+ * @throws NullPointerException
+ * If the <tt>format</tt> is <tt>null</tt>
+ *
+ * @return This output stream
+ *
+ * @since 1.5
+ */
+ public PrintStream format(String format, Object ... args) {
+ try {
+ synchronized (this) {
+ ensureOpen();
+ if ((formatter == null)
+ || (formatter.locale() != Locale.getDefault()))
+ formatter = new Formatter((Appendable) this);
+ formatter.format(Locale.getDefault(), format, args);
+ }
+ } catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ } catch (IOException x) {
+ trouble = true;
+ }
+ return this;
+ }
+
+ /**
+ * Writes a formatted string to this output stream using the specified
+ * format string and arguments.
+ *
+ * @param l
+ * The {@linkplain java.util.Locale locale} to apply during
+ * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
+ * is applied.
+ *
+ * @param format
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The number of arguments is
+ * variable and may be zero. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ * The behaviour on a
+ * <tt>null</tt> argument depends on the <a
+ * href="../util/Formatter.html#syntax">conversion</a>.
+ *
+ * @throws java.util.IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a> section of the
+ * formatter class specification.
+ *
+ * @throws NullPointerException
+ * If the <tt>format</tt> is <tt>null</tt>
+ *
+ * @return This output stream
+ *
+ * @since 1.5
+ */
+ public PrintStream format(Locale l, String format, Object ... args) {
+ try {
+ synchronized (this) {
+ ensureOpen();
+ if ((formatter == null)
+ || (formatter.locale() != l))
+ formatter = new Formatter(this, l);
+ formatter.format(l, format, args);
+ }
+ } catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ } catch (IOException x) {
+ trouble = true;
+ }
+ return this;
+ }
+
+ /**
+ * Appends the specified character sequence to this output stream.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.print(csq.toString()) </pre>
+ *
+ * <p> Depending on the specification of <tt>toString</tt> for the
+ * character sequence <tt>csq</tt>, the entire sequence may not be
+ * appended. For instance, invoking then <tt>toString</tt> method of a
+ * character buffer will return a subsequence whose content depends upon
+ * the buffer's position and limit.
+ *
+ * @param csq
+ * The character sequence to append. If <tt>csq</tt> is
+ * <tt>null</tt>, then the four characters <tt>"null"</tt> are
+ * appended to this output stream.
+ *
+ * @return This output stream
+ *
+ * @since 1.5
+ */
+ public PrintStream append(CharSequence csq) {
+ if (csq == null)
+ print("null");
+ else
+ print(csq.toString());
+ return this;
+ }
+
+ /**
+ * Appends a subsequence of the specified character sequence to this output
+ * stream.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(csq, start,
+ * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+ * exactly the same way as the invocation
+ *
+ * <pre>
+ * out.print(csq.subSequence(start, end).toString()) </pre>
+ *
+ * @param csq
+ * The character sequence from which a subsequence will be
+ * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
+ * will be appended as if <tt>csq</tt> contained the four
+ * characters <tt>"null"</tt>.
+ *
+ * @param start
+ * The index of the first character in the subsequence
+ *
+ * @param end
+ * The index of the character following the last character in the
+ * subsequence
+ *
+ * @return This output stream
+ *
+ * @throws IndexOutOfBoundsException
+ * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+ * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+ * <tt>csq.length()</tt>
+ *
+ * @since 1.5
+ */
+ public PrintStream append(CharSequence csq, int start, int end) {
+ CharSequence cs = (csq == null ? "null" : csq);
+ write(cs.subSequence(start, end).toString());
+ return this;
+ }
+
+ /**
+ * Appends the specified character to this output stream.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.print(c) </pre>
+ *
+ * @param c
+ * The 16-bit character to append
+ *
+ * @return This output stream
+ *
+ * @since 1.5
+ */
+ public PrintStream append(char c) {
+ print(c);
+ return this;
+ }
+
+}
diff --git a/java/io/PrintWriter.annotated.java b/java/io/PrintWriter.annotated.java
new file mode 100644
index 0000000..531dfb0
--- /dev/null
+++ b/java/io/PrintWriter.annotated.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.io;
+
+import java.nio.charset.Charset;
+import java.util.Formatter;
+import java.util.Locale;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class PrintWriter extends java.io.Writer {
+
+public PrintWriter(@libcore.util.NonNull java.io.Writer out) { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.io.Writer out, boolean autoFlush) { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.io.OutputStream out) { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.io.OutputStream out, boolean autoFlush) { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.lang.String fileName) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.lang.String fileName, @libcore.util.NonNull java.lang.String csn) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.io.File file) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.io.File file, @libcore.util.NonNull java.lang.String csn) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
+
+public void flush() { throw new RuntimeException("Stub!"); }
+
+public void close() { throw new RuntimeException("Stub!"); }
+
+public boolean checkError() { throw new RuntimeException("Stub!"); }
+
+protected void setError() { throw new RuntimeException("Stub!"); }
+
+protected void clearError() { throw new RuntimeException("Stub!"); }
+
+public void write(int c) { throw new RuntimeException("Stub!"); }
+
+public void write(char[] buf, int off, int len) { throw new RuntimeException("Stub!"); }
+
+public void write(char[] buf) { throw new RuntimeException("Stub!"); }
+
+public void write(@libcore.util.NonNull java.lang.String s, int off, int len) { throw new RuntimeException("Stub!"); }
+
+public void write(@libcore.util.NonNull java.lang.String s) { throw new RuntimeException("Stub!"); }
+
+public void print(boolean b) { throw new RuntimeException("Stub!"); }
+
+public void print(char c) { throw new RuntimeException("Stub!"); }
+
+public void print(int i) { throw new RuntimeException("Stub!"); }
+
+public void print(long l) { throw new RuntimeException("Stub!"); }
+
+public void print(float f) { throw new RuntimeException("Stub!"); }
+
+public void print(double d) { throw new RuntimeException("Stub!"); }
+
+public void print(char[] s) { throw new RuntimeException("Stub!"); }
+
+public void print(@libcore.util.Nullable java.lang.String s) { throw new RuntimeException("Stub!"); }
+
+public void print(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public void println() { throw new RuntimeException("Stub!"); }
+
+public void println(boolean x) { throw new RuntimeException("Stub!"); }
+
+public void println(char x) { throw new RuntimeException("Stub!"); }
+
+public void println(int x) { throw new RuntimeException("Stub!"); }
+
+public void println(long x) { throw new RuntimeException("Stub!"); }
+
+public void println(float x) { throw new RuntimeException("Stub!"); }
+
+public void println(double x) { throw new RuntimeException("Stub!"); }
+
+public void println(char[] x) { throw new RuntimeException("Stub!"); }
+
+public void println(@libcore.util.Nullable java.lang.String x) { throw new RuntimeException("Stub!"); }
+
+public void println(@libcore.util.Nullable java.lang.Object x) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter printf(@libcore.util.NonNull java.lang.String format, [email protected] Object @libcore.util.NonNull ... args) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter printf(@libcore.util.Nullable java.util.Locale l, @libcore.util.NonNull java.lang.String format, [email protected] Object @libcore.util.NonNull ... args) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter format(@libcore.util.NonNull java.lang.String format, [email protected] Object @libcore.util.NonNull ... args) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter format(@libcore.util.Nullable java.util.Locale l, @libcore.util.NonNull java.lang.String format, [email protected] Object @libcore.util.NonNull ... args) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter append(@libcore.util.Nullable java.lang.CharSequence csq) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter append(@libcore.util.Nullable java.lang.CharSequence csq, int start, int end) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter append(char c) { throw new RuntimeException("Stub!"); }
+
+protected java.io.Writer out;
+}
diff --git a/java/io/PrintWriter.java b/java/io/PrintWriter.java
new file mode 100644
index 0000000..9287a19
--- /dev/null
+++ b/java/io/PrintWriter.java
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.Objects;
+import java.util.Formatter;
+import java.util.Locale;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+
+/**
+ * Prints formatted representations of objects to a text-output stream. This
+ * class implements all of the <tt>print</tt> methods found in {@link
+ * PrintStream}. It does not contain methods for writing raw bytes, for which
+ * a program should use unencoded byte streams.
+ *
+ * <p> Unlike the {@link PrintStream} class, if automatic flushing is enabled
+ * it will be done only when one of the <tt>println</tt>, <tt>printf</tt>, or
+ * <tt>format</tt> methods is invoked, rather than whenever a newline character
+ * happens to be output. These methods use the platform's own notion of line
+ * separator rather than the newline character.
+ *
+ * <p> Methods in this class never throw I/O exceptions, although some of its
+ * constructors may. The client may inquire as to whether any errors have
+ * occurred by invoking {@link #checkError checkError()}.
+ *
+ * @author Frank Yellin
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class PrintWriter extends Writer {
+
+ /**
+ * The underlying character-output stream of this
+ * <code>PrintWriter</code>.
+ *
+ * @since 1.2
+ */
+ protected Writer out;
+
+ private final boolean autoFlush;
+ private boolean trouble = false;
+ private Formatter formatter;
+ private PrintStream psOut = null;
+
+ /**
+ * Line separator string. This is the value of the line.separator
+ * property at the moment that the stream was created.
+ */
+ private final String lineSeparator;
+
+ /**
+ * Returns a charset object for the given charset name.
+ * @throws NullPointerException is csn is null
+ * @throws UnsupportedEncodingException if the charset is not supported
+ */
+ private static Charset toCharset(String csn)
+ throws UnsupportedEncodingException
+ {
+ Objects.requireNonNull(csn, "charsetName");
+ try {
+ return Charset.forName(csn);
+ } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
+ // UnsupportedEncodingException should be thrown
+ throw new UnsupportedEncodingException(csn);
+ }
+ }
+
+ /**
+ * Creates a new PrintWriter, without automatic line flushing.
+ *
+ * @param out A character-output stream
+ */
+ public PrintWriter (Writer out) {
+ this(out, false);
+ }
+
+ /**
+ * Creates a new PrintWriter.
+ *
+ * @param out A character-output stream
+ * @param autoFlush A boolean; if true, the <tt>println</tt>,
+ * <tt>printf</tt>, or <tt>format</tt> methods will
+ * flush the output buffer
+ */
+ public PrintWriter(Writer out,
+ boolean autoFlush) {
+ super(out);
+ this.out = out;
+ this.autoFlush = autoFlush;
+ lineSeparator = java.security.AccessController.doPrivileged(
+ new sun.security.action.GetPropertyAction("line.separator"));
+ }
+
+ /**
+ * Creates a new PrintWriter, without automatic line flushing, from an
+ * existing OutputStream. This convenience constructor creates the
+ * necessary intermediate OutputStreamWriter, which will convert characters
+ * into bytes using the default character encoding.
+ *
+ * @param out An output stream
+ *
+ * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
+ */
+ public PrintWriter(OutputStream out) {
+ this(out, false);
+ }
+
+ /**
+ * Creates a new PrintWriter from an existing OutputStream. This
+ * convenience constructor creates the necessary intermediate
+ * OutputStreamWriter, which will convert characters into bytes using the
+ * default character encoding.
+ *
+ * @param out An output stream
+ * @param autoFlush A boolean; if true, the <tt>println</tt>,
+ * <tt>printf</tt>, or <tt>format</tt> methods will
+ * flush the output buffer
+ *
+ * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
+ */
+ public PrintWriter(OutputStream out, boolean autoFlush) {
+ this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
+
+ // save print stream for error propagation
+ if (out instanceof java.io.PrintStream) {
+ psOut = (PrintStream) out;
+ }
+ }
+
+ /**
+ * Creates a new PrintWriter, without automatic line flushing, with the
+ * specified file name. This convenience constructor creates the necessary
+ * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
+ * which will encode characters using the {@linkplain
+ * java.nio.charset.Charset#defaultCharset() default charset} for this
+ * instance of the Java virtual machine.
+ *
+ * @param fileName
+ * The name of the file to use as the destination of this writer.
+ * If the file exists then it will be truncated to zero size;
+ * otherwise, a new file will be created. The output will be
+ * written to the file and is buffered.
+ *
+ * @throws FileNotFoundException
+ * If the given string does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(fileName)} denies write
+ * access to the file
+ *
+ * @since 1.5
+ */
+ public PrintWriter(String fileName) throws FileNotFoundException {
+ this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
+ false);
+ }
+
+ /* Private constructor */
+ private PrintWriter(Charset charset, File file)
+ throws FileNotFoundException
+ {
+ this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)),
+ false);
+ }
+
+ /**
+ * Creates a new PrintWriter, without automatic line flushing, with the
+ * specified file name and charset. This convenience constructor creates
+ * the necessary intermediate {@link java.io.OutputStreamWriter
+ * OutputStreamWriter}, which will encode characters using the provided
+ * charset.
+ *
+ * @param fileName
+ * The name of the file to use as the destination of this writer.
+ * If the file exists then it will be truncated to zero size;
+ * otherwise, a new file will be created. The output will be
+ * written to the file and is buffered.
+ *
+ * @param csn
+ * The name of a supported {@linkplain java.nio.charset.Charset
+ * charset}
+ *
+ * @throws FileNotFoundException
+ * If the given string does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(fileName)} denies write
+ * access to the file
+ *
+ * @throws UnsupportedEncodingException
+ * If the named charset is not supported
+ *
+ * @since 1.5
+ */
+ public PrintWriter(String fileName, String csn)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ this(toCharset(csn), new File(fileName));
+ }
+
+ /**
+ * Creates a new PrintWriter, without automatic line flushing, with the
+ * specified file. This convenience constructor creates the necessary
+ * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
+ * which will encode characters using the {@linkplain
+ * java.nio.charset.Charset#defaultCharset() default charset} for this
+ * instance of the Java virtual machine.
+ *
+ * @param file
+ * The file to use as the destination of this writer. If the file
+ * exists then it will be truncated to zero size; otherwise, a new
+ * file will be created. The output will be written to the file
+ * and is buffered.
+ *
+ * @throws FileNotFoundException
+ * If the given file object does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(file.getPath())}
+ * denies write access to the file
+ *
+ * @since 1.5
+ */
+ public PrintWriter(File file) throws FileNotFoundException {
+ this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
+ false);
+ }
+
+ /**
+ * Creates a new PrintWriter, without automatic line flushing, with the
+ * specified file and charset. This convenience constructor creates the
+ * necessary intermediate {@link java.io.OutputStreamWriter
+ * OutputStreamWriter}, which will encode characters using the provided
+ * charset.
+ *
+ * @param file
+ * The file to use as the destination of this writer. If the file
+ * exists then it will be truncated to zero size; otherwise, a new
+ * file will be created. The output will be written to the file
+ * and is buffered.
+ *
+ * @param csn
+ * The name of a supported {@linkplain java.nio.charset.Charset
+ * charset}
+ *
+ * @throws FileNotFoundException
+ * If the given file object does not denote an existing, writable
+ * regular file and a new regular file of that name cannot be
+ * created, or if some other error occurs while opening or
+ * creating the file
+ *
+ * @throws SecurityException
+ * If a security manager is present and {@link
+ * SecurityManager#checkWrite checkWrite(file.getPath())}
+ * denies write access to the file
+ *
+ * @throws UnsupportedEncodingException
+ * If the named charset is not supported
+ *
+ * @since 1.5
+ */
+ public PrintWriter(File file, String csn)
+ throws FileNotFoundException, UnsupportedEncodingException
+ {
+ this(toCharset(csn), file);
+ }
+
+ /** Checks to make sure that the stream has not been closed */
+ private void ensureOpen() throws IOException {
+ if (out == null)
+ throw new IOException("Stream closed");
+ }
+
+ /**
+ * Flushes the stream.
+ * @see #checkError()
+ */
+ public void flush() {
+ try {
+ synchronized (lock) {
+ ensureOpen();
+ out.flush();
+ }
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+
+ /**
+ * Closes the stream and releases any system resources associated
+ * with it. Closing a previously closed stream has no effect.
+ *
+ * @see #checkError()
+ */
+ public void close() {
+ try {
+ synchronized (lock) {
+ if (out == null)
+ return;
+ out.close();
+ out = null;
+ }
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+
+ /**
+ * Flushes the stream if it's not closed and checks its error state.
+ *
+ * @return <code>true</code> if the print stream has encountered an error,
+ * either on the underlying output stream or during a format
+ * conversion.
+ */
+ public boolean checkError() {
+ if (out != null) {
+ flush();
+ }
+ if (out instanceof java.io.PrintWriter) {
+ PrintWriter pw = (PrintWriter) out;
+ return pw.checkError();
+ } else if (psOut != null) {
+ return psOut.checkError();
+ }
+ return trouble;
+ }
+
+ /**
+ * Indicates that an error has occurred.
+ *
+ * <p> This method will cause subsequent invocations of {@link
+ * #checkError()} to return <tt>true</tt> until {@link
+ * #clearError()} is invoked.
+ */
+ protected void setError() {
+ trouble = true;
+ }
+
+ /**
+ * Clears the error state of this stream.
+ *
+ * <p> This method will cause subsequent invocations of {@link
+ * #checkError()} to return <tt>false</tt> until another write
+ * operation fails and invokes {@link #setError()}.
+ *
+ * @since 1.6
+ */
+ protected void clearError() {
+ trouble = false;
+ }
+
+ /*
+ * Exception-catching, synchronized output operations,
+ * which also implement the write() methods of Writer
+ */
+
+ /**
+ * Writes a single character.
+ * @param c int specifying a character to be written.
+ */
+ public void write(int c) {
+ try {
+ synchronized (lock) {
+ ensureOpen();
+ out.write(c);
+ }
+ }
+ catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+
+ /**
+ * Writes A Portion of an array of characters.
+ * @param buf Array of characters
+ * @param off Offset from which to start writing characters
+ * @param len Number of characters to write
+ */
+ public void write(char buf[], int off, int len) {
+ try {
+ synchronized (lock) {
+ ensureOpen();
+ out.write(buf, off, len);
+ }
+ }
+ catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+
+ /**
+ * Writes an array of characters. This method cannot be inherited from the
+ * Writer class because it must suppress I/O exceptions.
+ * @param buf Array of characters to be written
+ */
+ public void write(char buf[]) {
+ write(buf, 0, buf.length);
+ }
+
+ /**
+ * Writes a portion of a string.
+ * @param s A String
+ * @param off Offset from which to start writing characters
+ * @param len Number of characters to write
+ */
+ public void write(String s, int off, int len) {
+ try {
+ synchronized (lock) {
+ ensureOpen();
+ out.write(s, off, len);
+ }
+ }
+ catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+
+ /**
+ * Writes a string. This method cannot be inherited from the Writer class
+ * because it must suppress I/O exceptions.
+ * @param s String to be written
+ */
+ public void write(String s) {
+ write(s, 0, s.length());
+ }
+
+ private void newLine() {
+ try {
+ synchronized (lock) {
+ ensureOpen();
+ out.write(lineSeparator);
+ if (autoFlush)
+ out.flush();
+ }
+ }
+ catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ }
+ catch (IOException x) {
+ trouble = true;
+ }
+ }
+
+ /* Methods that do not terminate lines */
+
+ /**
+ * Prints a boolean value. The string produced by <code>{@link
+ * java.lang.String#valueOf(boolean)}</code> is translated into bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the <code>{@link
+ * #write(int)}</code> method.
+ *
+ * @param b The <code>boolean</code> to be printed
+ */
+ public void print(boolean b) {
+ write(b ? "true" : "false");
+ }
+
+ /**
+ * Prints a character. The character is translated into one or more bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the <code>{@link
+ * #write(int)}</code> method.
+ *
+ * @param c The <code>char</code> to be printed
+ */
+ public void print(char c) {
+ write(c);
+ }
+
+ /**
+ * Prints an integer. The string produced by <code>{@link
+ * java.lang.String#valueOf(int)}</code> is translated into bytes according
+ * to the platform's default character encoding, and these bytes are
+ * written in exactly the manner of the <code>{@link #write(int)}</code>
+ * method.
+ *
+ * @param i The <code>int</code> to be printed
+ * @see java.lang.Integer#toString(int)
+ */
+ public void print(int i) {
+ write(String.valueOf(i));
+ }
+
+ /**
+ * Prints a long integer. The string produced by <code>{@link
+ * java.lang.String#valueOf(long)}</code> is translated into bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the <code>{@link #write(int)}</code>
+ * method.
+ *
+ * @param l The <code>long</code> to be printed
+ * @see java.lang.Long#toString(long)
+ */
+ public void print(long l) {
+ write(String.valueOf(l));
+ }
+
+ /**
+ * Prints a floating-point number. The string produced by <code>{@link
+ * java.lang.String#valueOf(float)}</code> is translated into bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the <code>{@link #write(int)}</code>
+ * method.
+ *
+ * @param f The <code>float</code> to be printed
+ * @see java.lang.Float#toString(float)
+ */
+ public void print(float f) {
+ write(String.valueOf(f));
+ }
+
+ /**
+ * Prints a double-precision floating-point number. The string produced by
+ * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
+ * bytes according to the platform's default character encoding, and these
+ * bytes are written in exactly the manner of the <code>{@link
+ * #write(int)}</code> method.
+ *
+ * @param d The <code>double</code> to be printed
+ * @see java.lang.Double#toString(double)
+ */
+ public void print(double d) {
+ write(String.valueOf(d));
+ }
+
+ /**
+ * Prints an array of characters. The characters are converted into bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the <code>{@link #write(int)}</code>
+ * method.
+ *
+ * @param s The array of chars to be printed
+ *
+ * @throws NullPointerException If <code>s</code> is <code>null</code>
+ */
+ public void print(char s[]) {
+ write(s);
+ }
+
+ /**
+ * Prints a string. If the argument is <code>null</code> then the string
+ * <code>"null"</code> is printed. Otherwise, the string's characters are
+ * converted into bytes according to the platform's default character
+ * encoding, and these bytes are written in exactly the manner of the
+ * <code>{@link #write(int)}</code> method.
+ *
+ * @param s The <code>String</code> to be printed
+ */
+ public void print(String s) {
+ if (s == null) {
+ s = "null";
+ }
+ write(s);
+ }
+
+ /**
+ * Prints an object. The string produced by the <code>{@link
+ * java.lang.String#valueOf(Object)}</code> method is translated into bytes
+ * according to the platform's default character encoding, and these bytes
+ * are written in exactly the manner of the <code>{@link #write(int)}</code>
+ * method.
+ *
+ * @param obj The <code>Object</code> to be printed
+ * @see java.lang.Object#toString()
+ */
+ public void print(Object obj) {
+ write(String.valueOf(obj));
+ }
+
+ /* Methods that do terminate lines */
+
+ /**
+ * Terminates the current line by writing the line separator string. The
+ * line separator string is defined by the system property
+ * <code>line.separator</code>, and is not necessarily a single newline
+ * character (<code>'\n'</code>).
+ */
+ public void println() {
+ newLine();
+ }
+
+ /**
+ * Prints a boolean value and then terminates the line. This method behaves
+ * as though it invokes <code>{@link #print(boolean)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x the <code>boolean</code> value to be printed
+ */
+ public void println(boolean x) {
+ synchronized (lock) {
+ print(x);
+ println();
+ }
+ }
+
+ /**
+ * Prints a character and then terminates the line. This method behaves as
+ * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
+ * #println()}</code>.
+ *
+ * @param x the <code>char</code> value to be printed
+ */
+ public void println(char x) {
+ synchronized (lock) {
+ print(x);
+ println();
+ }
+ }
+
+ /**
+ * Prints an integer and then terminates the line. This method behaves as
+ * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
+ * #println()}</code>.
+ *
+ * @param x the <code>int</code> value to be printed
+ */
+ public void println(int x) {
+ synchronized (lock) {
+ print(x);
+ println();
+ }
+ }
+
+ /**
+ * Prints a long integer and then terminates the line. This method behaves
+ * as though it invokes <code>{@link #print(long)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x the <code>long</code> value to be printed
+ */
+ public void println(long x) {
+ synchronized (lock) {
+ print(x);
+ println();
+ }
+ }
+
+ /**
+ * Prints a floating-point number and then terminates the line. This method
+ * behaves as though it invokes <code>{@link #print(float)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x the <code>float</code> value to be printed
+ */
+ public void println(float x) {
+ synchronized (lock) {
+ print(x);
+ println();
+ }
+ }
+
+ /**
+ * Prints a double-precision floating-point number and then terminates the
+ * line. This method behaves as though it invokes <code>{@link
+ * #print(double)}</code> and then <code>{@link #println()}</code>.
+ *
+ * @param x the <code>double</code> value to be printed
+ */
+ public void println(double x) {
+ synchronized (lock) {
+ print(x);
+ println();
+ }
+ }
+
+ /**
+ * Prints an array of characters and then terminates the line. This method
+ * behaves as though it invokes <code>{@link #print(char[])}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x the array of <code>char</code> values to be printed
+ */
+ public void println(char x[]) {
+ synchronized (lock) {
+ print(x);
+ println();
+ }
+ }
+
+ /**
+ * Prints a String and then terminates the line. This method behaves as
+ * though it invokes <code>{@link #print(String)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x the <code>String</code> value to be printed
+ */
+ public void println(String x) {
+ synchronized (lock) {
+ print(x);
+ println();
+ }
+ }
+
+ /**
+ * Prints an Object and then terminates the line. This method calls
+ * at first String.valueOf(x) to get the printed object's string value,
+ * then behaves as
+ * though it invokes <code>{@link #print(String)}</code> and then
+ * <code>{@link #println()}</code>.
+ *
+ * @param x The <code>Object</code> to be printed.
+ */
+ public void println(Object x) {
+ String s = String.valueOf(x);
+ synchronized (lock) {
+ print(s);
+ println();
+ }
+ }
+
+ /**
+ * A convenience method to write a formatted string to this writer using
+ * the specified format string and arguments. If automatic flushing is
+ * enabled, calls to this method will flush the output buffer.
+ *
+ * <p> An invocation of this method of the form <tt>out.printf(format,
+ * args)</tt> behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.format(format, args) </pre>
+ *
+ * @param format
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>.
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The number of arguments is
+ * variable and may be zero. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ * The behaviour on a
+ * <tt>null</tt> argument depends on the <a
+ * href="../util/Formatter.html#syntax">conversion</a>.
+ *
+ * @throws java.util.IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a> section of the
+ * formatter class specification.
+ *
+ * @throws NullPointerException
+ * If the <tt>format</tt> is <tt>null</tt>
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public PrintWriter printf(String format, Object ... args) {
+ return format(format, args);
+ }
+
+ /**
+ * A convenience method to write a formatted string to this writer using
+ * the specified format string and arguments. If automatic flushing is
+ * enabled, calls to this method will flush the output buffer.
+ *
+ * <p> An invocation of this method of the form <tt>out.printf(l, format,
+ * args)</tt> behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.format(l, format, args) </pre>
+ *
+ * @param l
+ * The {@linkplain java.util.Locale locale} to apply during
+ * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
+ * is applied.
+ *
+ * @param format
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>.
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The number of arguments is
+ * variable and may be zero. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ * The behaviour on a
+ * <tt>null</tt> argument depends on the <a
+ * href="../util/Formatter.html#syntax">conversion</a>.
+ *
+ * @throws java.util.IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a> section of the
+ * formatter class specification.
+ *
+ * @throws NullPointerException
+ * If the <tt>format</tt> is <tt>null</tt>
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public PrintWriter printf(Locale l, String format, Object ... args) {
+ return format(l, format, args);
+ }
+
+ /**
+ * Writes a formatted string to this writer using the specified format
+ * string and arguments. If automatic flushing is enabled, calls to this
+ * method will flush the output buffer.
+ *
+ * <p> The locale always used is the one returned by {@link
+ * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any
+ * previous invocations of other formatting methods on this object.
+ *
+ * @param format
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>.
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The number of arguments is
+ * variable and may be zero. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ * The behaviour on a
+ * <tt>null</tt> argument depends on the <a
+ * href="../util/Formatter.html#syntax">conversion</a>.
+ *
+ * @throws java.util.IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a> section of the
+ * Formatter class specification.
+ *
+ * @throws NullPointerException
+ * If the <tt>format</tt> is <tt>null</tt>
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public PrintWriter format(String format, Object ... args) {
+ try {
+ synchronized (lock) {
+ ensureOpen();
+ if ((formatter == null)
+ || (formatter.locale() != Locale.getDefault()))
+ formatter = new Formatter(this);
+ formatter.format(Locale.getDefault(), format, args);
+ if (autoFlush)
+ out.flush();
+ }
+ } catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ } catch (IOException x) {
+ trouble = true;
+ }
+ return this;
+ }
+
+ /**
+ * Writes a formatted string to this writer using the specified format
+ * string and arguments. If automatic flushing is enabled, calls to this
+ * method will flush the output buffer.
+ *
+ * @param l
+ * The {@linkplain java.util.Locale locale} to apply during
+ * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
+ * is applied.
+ *
+ * @param format
+ * A format string as described in <a
+ * href="../util/Formatter.html#syntax">Format string syntax</a>.
+ *
+ * @param args
+ * Arguments referenced by the format specifiers in the format
+ * string. If there are more arguments than format specifiers, the
+ * extra arguments are ignored. The number of arguments is
+ * variable and may be zero. The maximum number of arguments is
+ * limited by the maximum dimension of a Java array as defined by
+ * <cite>The Java™ Virtual Machine Specification</cite>.
+ * The behaviour on a
+ * <tt>null</tt> argument depends on the <a
+ * href="../util/Formatter.html#syntax">conversion</a>.
+ *
+ * @throws java.util.IllegalFormatException
+ * If a format string contains an illegal syntax, a format
+ * specifier that is incompatible with the given arguments,
+ * insufficient arguments given the format string, or other
+ * illegal conditions. For specification of all possible
+ * formatting errors, see the <a
+ * href="../util/Formatter.html#detail">Details</a> section of the
+ * formatter class specification.
+ *
+ * @throws NullPointerException
+ * If the <tt>format</tt> is <tt>null</tt>
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public PrintWriter format(Locale l, String format, Object ... args) {
+ try {
+ synchronized (lock) {
+ ensureOpen();
+ if ((formatter == null) || (formatter.locale() != l))
+ formatter = new Formatter(this, l);
+ formatter.format(l, format, args);
+ if (autoFlush)
+ out.flush();
+ }
+ } catch (InterruptedIOException x) {
+ Thread.currentThread().interrupt();
+ } catch (IOException x) {
+ trouble = true;
+ }
+ return this;
+ }
+
+ /**
+ * Appends the specified character sequence to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(csq.toString()) </pre>
+ *
+ * <p> Depending on the specification of <tt>toString</tt> for the
+ * character sequence <tt>csq</tt>, the entire sequence may not be
+ * appended. For instance, invoking the <tt>toString</tt> method of a
+ * character buffer will return a subsequence whose content depends upon
+ * the buffer's position and limit.
+ *
+ * @param csq
+ * The character sequence to append. If <tt>csq</tt> is
+ * <tt>null</tt>, then the four characters <tt>"null"</tt> are
+ * appended to this writer.
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public PrintWriter append(CharSequence csq) {
+ if (csq == null)
+ write("null");
+ else
+ write(csq.toString());
+ return this;
+ }
+
+ /**
+ * Appends a subsequence of the specified character sequence to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(csq, start,
+ * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+ * exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(csq.subSequence(start, end).toString()) </pre>
+ *
+ * @param csq
+ * The character sequence from which a subsequence will be
+ * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
+ * will be appended as if <tt>csq</tt> contained the four
+ * characters <tt>"null"</tt>.
+ *
+ * @param start
+ * The index of the first character in the subsequence
+ *
+ * @param end
+ * The index of the character following the last character in the
+ * subsequence
+ *
+ * @return This writer
+ *
+ * @throws IndexOutOfBoundsException
+ * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+ * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+ * <tt>csq.length()</tt>
+ *
+ * @since 1.5
+ */
+ public PrintWriter append(CharSequence csq, int start, int end) {
+ CharSequence cs = (csq == null ? "null" : csq);
+ write(cs.subSequence(start, end).toString());
+ return this;
+ }
+
+ /**
+ * Appends the specified character to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(c) </pre>
+ *
+ * @param c
+ * The 16-bit character to append
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public PrintWriter append(char c) {
+ write(c);
+ return this;
+ }
+}
diff --git a/java/io/PushbackInputStream.java b/java/io/PushbackInputStream.java
new file mode 100644
index 0000000..b44848d
--- /dev/null
+++ b/java/io/PushbackInputStream.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * A <code>PushbackInputStream</code> adds
+ * functionality to another input stream, namely
+ * the ability to "push back" or "unread"
+ * one byte. This is useful in situations where
+ * it is convenient for a fragment of code
+ * to read an indefinite number of data bytes
+ * that are delimited by a particular byte
+ * value; after reading the terminating byte,
+ * the code fragment can "unread" it, so that
+ * the next read operation on the input stream
+ * will reread the byte that was pushed back.
+ * For example, bytes representing the characters
+ * constituting an identifier might be terminated
+ * by a byte representing an operator character;
+ * a method whose job is to read just an identifier
+ * can read until it sees the operator and
+ * then push the operator back to be re-read.
+ *
+ * @author David Connelly
+ * @author Jonathan Payne
+ * @since JDK1.0
+ */
+public
+class PushbackInputStream extends FilterInputStream {
+ /**
+ * The pushback buffer.
+ * @since JDK1.1
+ */
+ protected byte[] buf;
+
+ /**
+ * The position within the pushback buffer from which the next byte will
+ * be read. When the buffer is empty, <code>pos</code> is equal to
+ * <code>buf.length</code>; when the buffer is full, <code>pos</code> is
+ * equal to zero.
+ *
+ * @since JDK1.1
+ */
+ protected int pos;
+
+ /**
+ * Check to make sure that this stream has not been closed
+ */
+ private void ensureOpen() throws IOException {
+ if (in == null)
+ throw new IOException("Stream closed");
+ }
+
+ /**
+ * Creates a <code>PushbackInputStream</code>
+ * with a pushback buffer of the specified <code>size</code>,
+ * and saves its argument, the input stream
+ * <code>in</code>, for later use. Initially,
+ * there is no pushed-back byte (the field
+ * <code>pushBack</code> is initialized to
+ * <code>-1</code>).
+ *
+ * @param in the input stream from which bytes will be read.
+ * @param size the size of the pushback buffer.
+ * @exception IllegalArgumentException if {@code size <= 0}
+ * @since JDK1.1
+ */
+ public PushbackInputStream(InputStream in, int size) {
+ super(in);
+ if (size <= 0) {
+ throw new IllegalArgumentException("size <= 0");
+ }
+ this.buf = new byte[size];
+ this.pos = size;
+ }
+
+ /**
+ * Creates a <code>PushbackInputStream</code>
+ * and saves its argument, the input stream
+ * <code>in</code>, for later use. Initially,
+ * there is no pushed-back byte (the field
+ * <code>pushBack</code> is initialized to
+ * <code>-1</code>).
+ *
+ * @param in the input stream from which bytes will be read.
+ */
+ public PushbackInputStream(InputStream in) {
+ this(in, 1);
+ }
+
+ /**
+ * Reads the next byte of data from this input stream. The value
+ * byte is returned as an <code>int</code> in the range
+ * <code>0</code> to <code>255</code>. If no byte is available
+ * because the end of the stream has been reached, the value
+ * <code>-1</code> is returned. This method blocks until input data
+ * is available, the end of the stream is detected, or an exception
+ * is thrown.
+ *
+ * <p> This method returns the most recently pushed-back byte, if there is
+ * one, and otherwise calls the <code>read</code> method of its underlying
+ * input stream and returns whatever value that method returns.
+ *
+ * @return the next byte of data, or <code>-1</code> if the end of the
+ * stream has been reached.
+ * @exception IOException if this input stream has been closed by
+ * invoking its {@link #close()} method,
+ * or an I/O error occurs.
+ * @see java.io.InputStream#read()
+ */
+ public int read() throws IOException {
+ ensureOpen();
+ if (pos < buf.length) {
+ return buf[pos++] & 0xff;
+ }
+ return super.read();
+ }
+
+ /**
+ * Reads up to <code>len</code> bytes of data from this input stream into
+ * an array of bytes. This method first reads any pushed-back bytes; after
+ * that, if fewer than <code>len</code> bytes have been read then it
+ * reads from the underlying input stream. If <code>len</code> is not zero, the method
+ * blocks until at least 1 byte of input is available; otherwise, no
+ * bytes are read and <code>0</code> is returned.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in the destination array <code>b</code>
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the stream has been reached.
+ * @exception NullPointerException If <code>b</code> is <code>null</code>.
+ * @exception IndexOutOfBoundsException If <code>off</code> is negative,
+ * <code>len</code> is negative, or <code>len</code> is greater than
+ * <code>b.length - off</code>
+ * @exception IOException if this input stream has been closed by
+ * invoking its {@link #close()} method,
+ * or an I/O error occurs.
+ * @see java.io.InputStream#read(byte[], int, int)
+ */
+ public int read(byte[] b, int off, int len) throws IOException {
+ ensureOpen();
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ int avail = buf.length - pos;
+ if (avail > 0) {
+ if (len < avail) {
+ avail = len;
+ }
+ System.arraycopy(buf, pos, b, off, avail);
+ pos += avail;
+ off += avail;
+ len -= avail;
+ }
+ if (len > 0) {
+ len = super.read(b, off, len);
+ if (len == -1) {
+ return avail == 0 ? -1 : avail;
+ }
+ return avail + len;
+ }
+ return avail;
+ }
+
+ /**
+ * Pushes back a byte by copying it to the front of the pushback buffer.
+ * After this method returns, the next byte to be read will have the value
+ * <code>(byte)b</code>.
+ *
+ * @param b the <code>int</code> value whose low-order
+ * byte is to be pushed back.
+ * @exception IOException If there is not enough room in the pushback
+ * buffer for the byte, or this input stream has been closed by
+ * invoking its {@link #close()} method.
+ */
+ public void unread(int b) throws IOException {
+ ensureOpen();
+ if (pos == 0) {
+ throw new IOException("Push back buffer is full");
+ }
+ buf[--pos] = (byte)b;
+ }
+
+ /**
+ * Pushes back a portion of an array of bytes by copying it to the front
+ * of the pushback buffer. After this method returns, the next byte to be
+ * read will have the value <code>b[off]</code>, the byte after that will
+ * have the value <code>b[off+1]</code>, and so forth.
+ *
+ * @param b the byte array to push back.
+ * @param off the start offset of the data.
+ * @param len the number of bytes to push back.
+ * @exception IOException If there is not enough room in the pushback
+ * buffer for the specified number of bytes,
+ * or this input stream has been closed by
+ * invoking its {@link #close()} method.
+ * @since JDK1.1
+ */
+ public void unread(byte[] b, int off, int len) throws IOException {
+ ensureOpen();
+ if (len > pos) {
+ throw new IOException("Push back buffer is full");
+ }
+ pos -= len;
+ System.arraycopy(b, off, buf, pos, len);
+ }
+
+ /**
+ * Pushes back an array of bytes by copying it to the front of the
+ * pushback buffer. After this method returns, the next byte to be read
+ * will have the value <code>b[0]</code>, the byte after that will have the
+ * value <code>b[1]</code>, and so forth.
+ *
+ * @param b the byte array to push back
+ * @exception IOException If there is not enough room in the pushback
+ * buffer for the specified number of bytes,
+ * or this input stream has been closed by
+ * invoking its {@link #close()} method.
+ * @since JDK1.1
+ */
+ public void unread(byte[] b) throws IOException {
+ unread(b, 0, b.length);
+ }
+
+ /**
+ * Returns an estimate of the number of bytes that can be read (or
+ * skipped over) from this input stream without blocking by the next
+ * invocation of a method for this input stream. The next invocation might be
+ * the same thread or another thread. A single read or skip of this
+ * many bytes will not block, but may read or skip fewer bytes.
+ *
+ * <p> The method returns the sum of the number of bytes that have been
+ * pushed back and the value returned by {@link
+ * java.io.FilterInputStream#available available}.
+ *
+ * @return the number of bytes that can be read (or skipped over) from
+ * the input stream without blocking.
+ * @exception IOException if this input stream has been closed by
+ * invoking its {@link #close()} method,
+ * or an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ * @see java.io.InputStream#available()
+ */
+ public int available() throws IOException {
+ ensureOpen();
+ int n = buf.length - pos;
+ int avail = super.available();
+ return n > (Integer.MAX_VALUE - avail)
+ ? Integer.MAX_VALUE
+ : n + avail;
+ }
+
+ /**
+ * Skips over and discards <code>n</code> bytes of data from this
+ * input stream. The <code>skip</code> method may, for a variety of
+ * reasons, end up skipping over some smaller number of bytes,
+ * possibly zero. If <code>n</code> is negative, no bytes are skipped.
+ *
+ * <p> The <code>skip</code> method of <code>PushbackInputStream</code>
+ * first skips over the bytes in the pushback buffer, if any. It then
+ * calls the <code>skip</code> method of the underlying input stream if
+ * more bytes need to be skipped. The actual number of bytes skipped
+ * is returned.
+ *
+ * @param n {@inheritDoc}
+ * @return {@inheritDoc}
+ * @exception IOException if the stream does not support seek,
+ * or the stream has been closed by
+ * invoking its {@link #close()} method,
+ * or an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ * @see java.io.InputStream#skip(long n)
+ * @since 1.2
+ */
+ public long skip(long n) throws IOException {
+ ensureOpen();
+ if (n <= 0) {
+ return 0;
+ }
+
+ long pskip = buf.length - pos;
+ if (pskip > 0) {
+ if (n < pskip) {
+ pskip = n;
+ }
+ pos += pskip;
+ n -= pskip;
+ }
+ if (n > 0) {
+ pskip += super.skip(n);
+ }
+ return pskip;
+ }
+
+ /**
+ * Tests if this input stream supports the <code>mark</code> and
+ * <code>reset</code> methods, which it does not.
+ *
+ * @return <code>false</code>, since this class does not support the
+ * <code>mark</code> and <code>reset</code> methods.
+ * @see java.io.InputStream#mark(int)
+ * @see java.io.InputStream#reset()
+ */
+ public boolean markSupported() {
+ return false;
+ }
+
+ /**
+ * Marks the current position in this input stream.
+ *
+ * <p> The <code>mark</code> method of <code>PushbackInputStream</code>
+ * does nothing.
+ *
+ * @param readlimit the maximum limit of bytes that can be read before
+ * the mark position becomes invalid.
+ * @see java.io.InputStream#reset()
+ */
+ public synchronized void mark(int readlimit) {
+ }
+
+ /**
+ * Repositions this stream to the position at the time the
+ * <code>mark</code> method was last called on this input stream.
+ *
+ * <p> The method <code>reset</code> for class
+ * <code>PushbackInputStream</code> does nothing except throw an
+ * <code>IOException</code>.
+ *
+ * @exception IOException if this method is invoked.
+ * @see java.io.InputStream#mark(int)
+ * @see java.io.IOException
+ */
+ public synchronized void reset() throws IOException {
+ throw new IOException("mark/reset not supported");
+ }
+
+ /**
+ * Closes this input stream and releases any system resources
+ * associated with the stream.
+ * Once the stream has been closed, further read(), unread(),
+ * available(), reset(), or skip() invocations will throw an IOException.
+ * Closing a previously closed stream has no effect.
+ *
+ * @exception IOException if an I/O error occurs.
+ */
+ public synchronized void close() throws IOException {
+ if (in == null)
+ return;
+ in.close();
+ in = null;
+ buf = null;
+ }
+}
diff --git a/java/io/PushbackReader.java b/java/io/PushbackReader.java
new file mode 100644
index 0000000..f918621
--- /dev/null
+++ b/java/io/PushbackReader.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * A character-stream reader that allows characters to be pushed back into the
+ * stream.
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class PushbackReader extends FilterReader {
+
+ /** Pushback buffer */
+ private char[] buf;
+
+ /** Current position in buffer */
+ private int pos;
+
+ /**
+ * Creates a new pushback reader with a pushback buffer of the given size.
+ *
+ * @param in The reader from which characters will be read
+ * @param size The size of the pushback buffer
+ * @exception IllegalArgumentException if {@code size <= 0}
+ */
+ public PushbackReader(Reader in, int size) {
+ super(in);
+ if (size <= 0) {
+ throw new IllegalArgumentException("size <= 0");
+ }
+ this.buf = new char[size];
+ this.pos = size;
+ }
+
+ /**
+ * Creates a new pushback reader with a one-character pushback buffer.
+ *
+ * @param in The reader from which characters will be read
+ */
+ public PushbackReader(Reader in) {
+ this(in, 1);
+ }
+
+ /** Checks to make sure that the stream has not been closed. */
+ private void ensureOpen() throws IOException {
+ if (buf == null)
+ throw new IOException("Stream closed");
+ }
+
+ /**
+ * Reads a single character.
+ *
+ * @return The character read, or -1 if the end of the stream has been
+ * reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if (pos < buf.length)
+ return buf[pos++];
+ else
+ return super.read();
+ }
+ }
+
+ /**
+ * Reads characters into a portion of an array.
+ *
+ * @param cbuf Destination buffer
+ * @param off Offset at which to start writing characters
+ * @param len Maximum number of characters to read
+ *
+ * @return The number of characters read, or -1 if the end of the
+ * stream has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read(char cbuf[], int off, int len) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ try {
+ if (len <= 0) {
+ if (len < 0) {
+ throw new IndexOutOfBoundsException();
+ } else if ((off < 0) || (off > cbuf.length)) {
+ throw new IndexOutOfBoundsException();
+ }
+ return 0;
+ }
+ int avail = buf.length - pos;
+ if (avail > 0) {
+ if (len < avail)
+ avail = len;
+ System.arraycopy(buf, pos, cbuf, off, avail);
+ pos += avail;
+ off += avail;
+ len -= avail;
+ }
+ if (len > 0) {
+ len = super.read(cbuf, off, len);
+ if (len == -1) {
+ return (avail == 0) ? -1 : avail;
+ }
+ return avail + len;
+ }
+ return avail;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+ }
+
+ /**
+ * Pushes back a single character by copying it to the front of the
+ * pushback buffer. After this method returns, the next character to be read
+ * will have the value <code>(char)c</code>.
+ *
+ * @param c The int value representing a character to be pushed back
+ *
+ * @exception IOException If the pushback buffer is full,
+ * or if some other I/O error occurs
+ */
+ public void unread(int c) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if (pos == 0)
+ throw new IOException("Pushback buffer overflow");
+ buf[--pos] = (char) c;
+ }
+ }
+
+ /**
+ * Pushes back a portion of an array of characters by copying it to the
+ * front of the pushback buffer. After this method returns, the next
+ * character to be read will have the value <code>cbuf[off]</code>, the
+ * character after that will have the value <code>cbuf[off+1]</code>, and
+ * so forth.
+ *
+ * @param cbuf Character array
+ * @param off Offset of first character to push back
+ * @param len Number of characters to push back
+ *
+ * @exception IOException If there is insufficient room in the pushback
+ * buffer, or if some other I/O error occurs
+ */
+ public void unread(char cbuf[], int off, int len) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if (len > pos)
+ throw new IOException("Pushback buffer overflow");
+ pos -= len;
+ System.arraycopy(cbuf, off, buf, pos, len);
+ }
+ }
+
+ /**
+ * Pushes back an array of characters by copying it to the front of the
+ * pushback buffer. After this method returns, the next character to be
+ * read will have the value <code>cbuf[0]</code>, the character after that
+ * will have the value <code>cbuf[1]</code>, and so forth.
+ *
+ * @param cbuf Character array to push back
+ *
+ * @exception IOException If there is insufficient room in the pushback
+ * buffer, or if some other I/O error occurs
+ */
+ public void unread(char cbuf[]) throws IOException {
+ unread(cbuf, 0, cbuf.length);
+ }
+
+ /**
+ * Tells whether this stream is ready to be read.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public boolean ready() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ return (pos < buf.length) || super.ready();
+ }
+ }
+
+ /**
+ * Marks the present position in the stream. The <code>mark</code>
+ * for class <code>PushbackReader</code> always throws an exception.
+ *
+ * @exception IOException Always, since mark is not supported
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ throw new IOException("mark/reset not supported");
+ }
+
+ /**
+ * Resets the stream. The <code>reset</code> method of
+ * <code>PushbackReader</code> always throws an exception.
+ *
+ * @exception IOException Always, since reset is not supported
+ */
+ public void reset() throws IOException {
+ throw new IOException("mark/reset not supported");
+ }
+
+ /**
+ * Tells whether this stream supports the mark() operation, which it does
+ * not.
+ */
+ public boolean markSupported() {
+ return false;
+ }
+
+ /**
+ * Closes the stream and releases any system resources associated with
+ * it. Once the stream has been closed, further read(),
+ * unread(), ready(), or skip() invocations will throw an IOException.
+ * Closing a previously closed stream has no effect.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void close() throws IOException {
+ super.close();
+ buf = null;
+ }
+
+ /**
+ * Skips characters. This method will block until some characters are
+ * available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * @param n The number of characters to skip
+ *
+ * @return The number of characters actually skipped
+ *
+ * @exception IllegalArgumentException If <code>n</code> is negative.
+ * @exception IOException If an I/O error occurs
+ */
+ public long skip(long n) throws IOException {
+ if (n < 0L)
+ throw new IllegalArgumentException("skip value is negative");
+ synchronized (lock) {
+ ensureOpen();
+ int avail = buf.length - pos;
+ if (avail > 0) {
+ if (n <= avail) {
+ pos += n;
+ return n;
+ } else {
+ pos = buf.length;
+ n -= avail;
+ }
+ }
+ return avail + super.skip(n);
+ }
+ }
+}
diff --git a/java/io/RandomAccessFile.java b/java/io/RandomAccessFile.java
new file mode 100644
index 0000000..06683ad
--- /dev/null
+++ b/java/io/RandomAccessFile.java
@@ -0,0 +1,1245 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.nio.channels.FileChannel;
+import sun.nio.ch.FileChannelImpl;
+import android.system.Os;
+import android.system.ErrnoException;
+import dalvik.system.CloseGuard;
+import libcore.io.IoBridge;
+import libcore.io.IoTracker;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import static android.system.OsConstants.*;
+
+
+/**
+ * Instances of this class support both reading and writing to a
+ * random access file. A random access file behaves like a large
+ * array of bytes stored in the file system. There is a kind of cursor,
+ * or index into the implied array, called the <em>file pointer</em>;
+ * input operations read bytes starting at the file pointer and advance
+ * the file pointer past the bytes read. If the random access file is
+ * created in read/write mode, then output operations are also available;
+ * output operations write bytes starting at the file pointer and advance
+ * the file pointer past the bytes written. Output operations that write
+ * past the current end of the implied array cause the array to be
+ * extended. The file pointer can be read by the
+ * {@code getFilePointer} method and set by the {@code seek}
+ * method.
+ * <p>
+ * It is generally true of all the reading routines in this class that
+ * if end-of-file is reached before the desired number of bytes has been
+ * read, an {@code EOFException} (which is a kind of
+ * {@code IOException}) is thrown. If any byte cannot be read for
+ * any reason other than end-of-file, an {@code IOException} other
+ * than {@code EOFException} is thrown. In particular, an
+ * {@code IOException} may be thrown if the stream has been closed.
+ *
+ * @author unascribed
+ * @since JDK1.0
+ */
+
+public class RandomAccessFile implements DataOutput, DataInput, Closeable {
+
+ // BEGIN Android-added: CloseGuard and some helper fields for Android changes in this file.
+ @ReachabilitySensitive
+ private final CloseGuard guard = CloseGuard.get();
+ private final byte[] scratch = new byte[8];
+
+ private static final int FLUSH_NONE = 0;
+ private static final int FLUSH_FSYNC = 1;
+ private static final int FLUSH_FDATASYNC = 2;
+ private int flushAfterWrite = FLUSH_NONE;
+
+ private int mode;
+ // END Android-added: CloseGuard and some helper fields for Android changes in this file.
+
+ // Android-added: @ReachabilitySensitive
+ @ReachabilitySensitive
+ private FileDescriptor fd;
+ private FileChannel channel = null;
+ private boolean rw;
+
+ /**
+ * The path of the referenced file
+ * (null if the stream is created with a file descriptor)
+ */
+ private final String path;
+
+ private Object closeLock = new Object();
+ private volatile boolean closed = false;
+
+ // BEGIN Android-added: IoTracker.
+ /**
+ * A single tracker to track both read and write. The tracker resets when the operation
+ * performed is different from the operation last performed.
+ */
+ private final IoTracker ioTracker = new IoTracker();
+ // END Android-added: IoTracker.
+
+ /**
+ * Creates a random access file stream to read from, and optionally
+ * to write to, a file with the specified name. A new
+ * {@link FileDescriptor} object is created to represent the
+ * connection to the file.
+ *
+ * <p> The <tt>mode</tt> argument specifies the access mode with which the
+ * file is to be opened. The permitted values and their meanings are as
+ * specified for the <a
+ * href="#mode"><tt>RandomAccessFile(File,String)</tt></a> constructor.
+ *
+ * <p>
+ * If there is a security manager, its {@code checkRead} method
+ * is called with the {@code name} argument
+ * as its argument to see if read access to the file is allowed.
+ * If the mode allows writing, the security manager's
+ * {@code checkWrite} method
+ * is also called with the {@code name} argument
+ * as its argument to see if write access to the file is allowed.
+ *
+ * @param name the system-dependent filename
+ * @param mode the access <a href="#mode">mode</a>
+ * @exception IllegalArgumentException if the mode argument is not equal
+ * to one of <tt>"r"</tt>, <tt>"rw"</tt>, <tt>"rws"</tt>, or
+ * <tt>"rwd"</tt>
+ * @exception FileNotFoundException
+ * if the mode is <tt>"r"</tt> but the given string does not
+ * denote an existing regular file, or if the mode begins with
+ * <tt>"rw"</tt> but the given string does not denote an
+ * existing, writable regular file and a new regular file of
+ * that name cannot be created, or if some other error occurs
+ * while opening or creating the file
+ * @exception SecurityException if a security manager exists and its
+ * {@code checkRead} method denies read access to the file
+ * or the mode is "rw" and the security manager's
+ * {@code checkWrite} method denies write access to the file
+ * @see java.lang.SecurityException
+ * @see java.lang.SecurityManager#checkRead(java.lang.String)
+ * @see java.lang.SecurityManager#checkWrite(java.lang.String)
+ * @revised 1.4
+ * @spec JSR-51
+ */
+ public RandomAccessFile(String name, String mode)
+ throws FileNotFoundException
+ {
+ this(name != null ? new File(name) : null, mode);
+ }
+
+ /**
+ * Creates a random access file stream to read from, and optionally to
+ * write to, the file specified by the {@link File} argument. A new {@link
+ * FileDescriptor} object is created to represent this file connection.
+ *
+ * <p>The <a name="mode"><tt>mode</tt></a> argument specifies the access mode
+ * in which the file is to be opened. The permitted values and their
+ * meanings are:
+ *
+ * <table summary="Access mode permitted values and meanings">
+ * <tr><th align="left">Value</th><th align="left">Meaning</th></tr>
+ * <tr><td valign="top"><tt>"r"</tt></td>
+ * <td> Open for reading only. Invoking any of the <tt>write</tt>
+ * methods of the resulting object will cause an {@link
+ * java.io.IOException} to be thrown. </td></tr>
+ * <tr><td valign="top"><tt>"rw"</tt></td>
+ * <td> Open for reading and writing. If the file does not already
+ * exist then an attempt will be made to create it. </td></tr>
+ * <tr><td valign="top"><tt>"rws"</tt></td>
+ * <td> Open for reading and writing, as with <tt>"rw"</tt>, and also
+ * require that every update to the file's content or metadata be
+ * written synchronously to the underlying storage device. </td></tr>
+ * <tr><td valign="top"><tt>"rwd" </tt></td>
+ * <td> Open for reading and writing, as with <tt>"rw"</tt>, and also
+ * require that every update to the file's content be written
+ * synchronously to the underlying storage device. </td></tr>
+ * </table>
+ *
+ * The <tt>"rws"</tt> and <tt>"rwd"</tt> modes work much like the {@link
+ * java.nio.channels.FileChannel#force(boolean) force(boolean)} method of
+ * the {@link java.nio.channels.FileChannel} class, passing arguments of
+ * <tt>true</tt> and <tt>false</tt>, respectively, except that they always
+ * apply to every I/O operation and are therefore often more efficient. If
+ * the file resides on a local storage device then when an invocation of a
+ * method of this class returns it is guaranteed that all changes made to
+ * the file by that invocation will have been written to that device. This
+ * is useful for ensuring that critical information is not lost in the
+ * event of a system crash. If the file does not reside on a local device
+ * then no such guarantee is made.
+ *
+ * <p>The <tt>"rwd"</tt> mode can be used to reduce the number of I/O
+ * operations performed. Using <tt>"rwd"</tt> only requires updates to the
+ * file's content to be written to storage; using <tt>"rws"</tt> requires
+ * updates to both the file's content and its metadata to be written, which
+ * generally requires at least one more low-level I/O operation.
+ *
+ * <p>If there is a security manager, its {@code checkRead} method is
+ * called with the pathname of the {@code file} argument as its
+ * argument to see if read access to the file is allowed. If the mode
+ * allows writing, the security manager's {@code checkWrite} method is
+ * also called with the path argument to see if write access to the file is
+ * allowed.
+ *
+ * @param file the file object
+ * @param mode the access mode, as described
+ * <a href="#mode">above</a>
+ * @exception IllegalArgumentException if the mode argument is not equal
+ * to one of <tt>"r"</tt>, <tt>"rw"</tt>, <tt>"rws"</tt>, or
+ * <tt>"rwd"</tt>
+ * @exception FileNotFoundException
+ * if the mode is <tt>"r"</tt> but the given file object does
+ * not denote an existing regular file, or if the mode begins
+ * with <tt>"rw"</tt> but the given file object does not denote
+ * an existing, writable regular file and a new regular file of
+ * that name cannot be created, or if some other error occurs
+ * while opening or creating the file
+ * @exception SecurityException if a security manager exists and its
+ * {@code checkRead} method denies read access to the file
+ * or the mode is "rw" and the security manager's
+ * {@code checkWrite} method denies write access to the file
+ * @see java.lang.SecurityManager#checkRead(java.lang.String)
+ * @see java.lang.SecurityManager#checkWrite(java.lang.String)
+ * @see java.nio.channels.FileChannel#force(boolean)
+ * @revised 1.4
+ * @spec JSR-51
+ */
+ public RandomAccessFile(File file, String mode)
+ throws FileNotFoundException
+ {
+ String name = (file != null ? file.getPath() : null);
+ int imode = -1;
+ if (mode.equals("r")) {
+ imode = O_RDONLY;
+ } else if (mode.startsWith("rw")) {
+ // Android-changed: Added. O_CREAT
+ // imode = O_RDWR;
+ imode = O_RDWR | O_CREAT;
+ rw = true;
+ if (mode.length() > 2) {
+ if (mode.equals("rws")) {
+ // Android-changed: For performance reasons, use fsync after each write.
+ // RandomAccessFile.write may result in multiple write syscalls,
+ // O_SYNC/O_DSYNC flags will cause a blocking wait on each syscall. Replacing
+ // them with single fsync/fdatasync call gives better performance with only
+ // minor decrease in reliability.
+ // imode |= O_SYNC;
+ flushAfterWrite = FLUSH_FSYNC;
+ } else if (mode.equals("rwd")) {
+ // Android-changed: For performance reasons, use fdatasync after each write.
+ // imode |= O_DSYNC;
+ flushAfterWrite = FLUSH_FDATASYNC;
+ } else {
+ imode = -1;
+ }
+ }
+ }
+ if (imode < 0) {
+ throw new IllegalArgumentException("Illegal mode \"" + mode
+ + "\" must be one of "
+ + "\"r\", \"rw\", \"rws\","
+ + " or \"rwd\"");
+ }
+ // Android-removed: do not use legacy security code
+ /*
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(name);
+ if (rw) {
+ security.checkWrite(name);
+ }
+ }
+ */
+ if (name == null) {
+ // Android-changed: different exception message in ctor when file == null.
+ // throw new NullPointerException();
+ throw new NullPointerException("file == null");
+ }
+ if (file.isInvalid()) {
+ throw new FileNotFoundException("Invalid file path");
+ }
+ this.path = name;
+ this.mode = imode;
+
+ // BEGIN Android-changed: Use IoBridge.open() instead of open.
+ fd = IoBridge.open(name, imode);
+ IoUtils.setFdOwner(fd, this);
+ maybeSync();
+ guard.open("close");
+ // END Android-changed: Use IoBridge.open() instead of open.
+ }
+
+ // BEGIN Android-added: Sync after rws/rwd write
+ private void maybeSync() {
+ if (flushAfterWrite == FLUSH_FSYNC) {
+ try {
+ fd.sync();
+ } catch (IOException e) {
+ // Ignored
+ }
+ } else if (flushAfterWrite == FLUSH_FDATASYNC) {
+ try {
+ Os.fdatasync(fd);
+ } catch (ErrnoException e) {
+ // Ignored
+ }
+ }
+ }
+ // END Android-added: Sync after rws/rwd write
+
+ /**
+ * Returns the opaque file descriptor object associated with this
+ * stream.
+ *
+ * @return the file descriptor object associated with this stream.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FileDescriptor
+ */
+ public final FileDescriptor getFD() throws IOException {
+ if (fd != null) {
+ return fd;
+ }
+ throw new IOException();
+ }
+
+ /**
+ * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
+ * object associated with this file.
+ *
+ * <p> The {@link java.nio.channels.FileChannel#position()
+ * position} of the returned channel will always be equal to
+ * this object's file-pointer offset as returned by the {@link
+ * #getFilePointer getFilePointer} method. Changing this object's
+ * file-pointer offset, whether explicitly or by reading or writing bytes,
+ * will change the position of the channel, and vice versa. Changing the
+ * file's length via this object will change the length seen via the file
+ * channel, and vice versa.
+ *
+ * @return the file channel associated with this file
+ *
+ * @since 1.4
+ * @spec JSR-51
+ */
+ public final FileChannel getChannel() {
+ synchronized (this) {
+ if (channel == null) {
+ channel = FileChannelImpl.open(fd, path, true, rw, this);
+ }
+ return channel;
+ }
+ }
+
+ /**
+ * Reads a byte of data from this file. The byte is returned as an
+ * integer in the range 0 to 255 ({@code 0x00-0x0ff}). This
+ * method blocks if no input is yet available.
+ * <p>
+ * Although {@code RandomAccessFile} is not a subclass of
+ * {@code InputStream}, this method behaves in exactly the same
+ * way as the {@link InputStream#read()} method of
+ * {@code InputStream}.
+ *
+ * @return the next byte of data, or {@code -1} if the end of the
+ * file has been reached.
+ * @exception IOException if an I/O error occurs. Not thrown if
+ * end-of-file has been reached.
+ */
+ public int read() throws IOException {
+ // Android-changed: Implement on top of libcore os API.
+ // return read0();
+ return (read(scratch, 0, 1) != -1) ? scratch[0] & 0xff : -1;
+ }
+
+ /**
+ * Reads a sub array as a sequence of bytes.
+ * @param b the buffer into which the data is read.
+ * @param off the start offset of the data.
+ * @param len the number of bytes to read.
+ * @exception IOException If an I/O error has occurred.
+ */
+ private int readBytes(byte b[], int off, int len) throws IOException {
+ // Android-changed: Implement on top of libcore os API.
+ ioTracker.trackIo(len, IoTracker.Mode.READ);
+ return IoBridge.read(fd, b, off, len);
+ }
+
+ /**
+ * Reads up to {@code len} bytes of data from this file into an
+ * array of bytes. This method blocks until at least one byte of input
+ * is available.
+ * <p>
+ * Although {@code RandomAccessFile} is not a subclass of
+ * {@code InputStream}, this method behaves in exactly the
+ * same way as the {@link InputStream#read(byte[], int, int)} method of
+ * {@code InputStream}.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in array {@code b}
+ * at which the data is written.
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * {@code -1} if there is no more data because the end of
+ * the file has been reached.
+ * @exception IOException If the first byte cannot be read for any reason
+ * other than end of file, or if the random access file has been closed, or if
+ * some other I/O error occurs.
+ * @exception NullPointerException If {@code b} is {@code null}.
+ * @exception IndexOutOfBoundsException If {@code off} is negative,
+ * {@code len} is negative, or {@code len} is greater than
+ * {@code b.length - off}
+ */
+ public int read(byte b[], int off, int len) throws IOException {
+ return readBytes(b, off, len);
+ }
+
+ /**
+ * Reads up to {@code b.length} bytes of data from this file
+ * into an array of bytes. This method blocks until at least one byte
+ * of input is available.
+ * <p>
+ * Although {@code RandomAccessFile} is not a subclass of
+ * {@code InputStream}, this method behaves in exactly the
+ * same way as the {@link InputStream#read(byte[])} method of
+ * {@code InputStream}.
+ *
+ * @param b the buffer into which the data is read.
+ * @return the total number of bytes read into the buffer, or
+ * {@code -1} if there is no more data because the end of
+ * this file has been reached.
+ * @exception IOException If the first byte cannot be read for any reason
+ * other than end of file, or if the random access file has been closed, or if
+ * some other I/O error occurs.
+ * @exception NullPointerException If {@code b} is {@code null}.
+ */
+ public int read(byte b[]) throws IOException {
+ return readBytes(b, 0, b.length);
+ }
+
+ /**
+ * Reads {@code b.length} bytes from this file into the byte
+ * array, starting at the current file pointer. This method reads
+ * repeatedly from the file until the requested number of bytes are
+ * read. This method blocks until the requested number of bytes are
+ * read, the end of the stream is detected, or an exception is thrown.
+ *
+ * @param b the buffer into which the data is read.
+ * @exception EOFException if this file reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final void readFully(byte b[]) throws IOException {
+ readFully(b, 0, b.length);
+ }
+
+ /**
+ * Reads exactly {@code len} bytes from this file into the byte
+ * array, starting at the current file pointer. This method reads
+ * repeatedly from the file until the requested number of bytes are
+ * read. This method blocks until the requested number of bytes are
+ * read, the end of the stream is detected, or an exception is thrown.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset of the data.
+ * @param len the number of bytes to read.
+ * @exception EOFException if this file reaches the end before reading
+ * all the bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final void readFully(byte b[], int off, int len) throws IOException {
+ int n = 0;
+ do {
+ int count = this.read(b, off + n, len - n);
+ if (count < 0)
+ throw new EOFException();
+ n += count;
+ } while (n < len);
+ }
+
+ /**
+ * Attempts to skip over {@code n} bytes of input discarding the
+ * skipped bytes.
+ * <p>
+ *
+ * This method may skip over some smaller number of bytes, possibly zero.
+ * This may result from any of a number of conditions; reaching end of
+ * file before {@code n} bytes have been skipped is only one
+ * possibility. This method never throws an {@code EOFException}.
+ * The actual number of bytes skipped is returned. If {@code n}
+ * is negative, no bytes are skipped.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the actual number of bytes skipped.
+ * @exception IOException if an I/O error occurs.
+ */
+ public int skipBytes(int n) throws IOException {
+ long pos;
+ long len;
+ long newpos;
+
+ if (n <= 0) {
+ return 0;
+ }
+ pos = getFilePointer();
+ len = length();
+ newpos = pos + n;
+ if (newpos > len) {
+ newpos = len;
+ }
+ seek(newpos);
+
+ /* return the actual number of bytes skipped */
+ return (int) (newpos - pos);
+ }
+
+ // 'Write' primitives
+
+ /**
+ * Writes the specified byte to this file. The write starts at
+ * the current file pointer.
+ *
+ * @param b the {@code byte} to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ public void write(int b) throws IOException {
+ // BEGIN Android-changed: Implement on top of libcore os API.
+ // write0(b);
+ scratch[0] = (byte) (b & 0xff);
+ write(scratch, 0, 1);
+ // END Android-changed: Implement on top of libcore os API.
+ }
+
+ /**
+ * Writes a sub array as a sequence of bytes.
+ * @param b the data to be written
+
+ * @param off the start offset in the data
+ * @param len the number of bytes that are written
+ * @exception IOException If an I/O error has occurred.
+ */
+ private void writeBytes(byte b[], int off, int len) throws IOException {
+ // BEGIN Android-changed: Implement on top of libcore os API.
+ ioTracker.trackIo(len, IoTracker.Mode.WRITE);
+ IoBridge.write(fd, b, off, len);
+ maybeSync();
+ // END Android-changed: Implement on top of libcore os API.
+ }
+
+ /**
+ * Writes {@code b.length} bytes from the specified byte array
+ * to this file, starting at the current file pointer.
+ *
+ * @param b the data.
+ * @exception IOException if an I/O error occurs.
+ */
+ public void write(byte b[]) throws IOException {
+ writeBytes(b, 0, b.length);
+ }
+
+ /**
+ * Writes {@code len} bytes from the specified byte array
+ * starting at offset {@code off} to this file.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @exception IOException if an I/O error occurs.
+ */
+ public void write(byte b[], int off, int len) throws IOException {
+ writeBytes(b, off, len);
+ }
+
+ // 'Random access' stuff
+
+ /**
+ * Returns the current offset in this file.
+ *
+ * @return the offset from the beginning of the file, in bytes,
+ * at which the next read or write occurs.
+ * @exception IOException if an I/O error occurs.
+ */
+ public long getFilePointer() throws IOException {
+ // BEGIN Android-changed: Implement on top of libcore os API.
+ try {
+ return Libcore.os.lseek(fd, 0L, SEEK_CUR);
+ } catch (ErrnoException errnoException) {
+ throw errnoException.rethrowAsIOException();
+ }
+ // END Android-changed: Implement on top of libcore os API.
+ }
+
+ /**
+ * Sets the file-pointer offset, measured from the beginning of this
+ * file, at which the next read or write occurs. The offset may be
+ * set beyond the end of the file. Setting the offset beyond the end
+ * of the file does not change the file length. The file length will
+ * change only by writing after the offset has been set beyond the end
+ * of the file.
+ *
+ * @param pos the offset position, measured in bytes from the
+ * beginning of the file, at which to set the file
+ * pointer.
+ * @exception IOException if {@code pos} is less than
+ * {@code 0} or if an I/O error occurs.
+ */
+ public void seek(long pos) throws IOException {
+ if (pos < 0) {
+ // Android-changed: different exception message for seek(-1).
+ // throw new IOException("Negative seek offset");
+ throw new IOException("offset < 0: " + pos);
+ } else {
+ // BEGIN Android-changed: Implement on top of libcore os API.
+ // seek0(pos);
+ try {
+ Libcore.os.lseek(fd, pos, SEEK_SET);
+ ioTracker.reset();
+ } catch (ErrnoException errnoException) {
+ throw errnoException.rethrowAsIOException();
+ }
+ // END Android-changed: Implement on top of libcore os API.
+ }
+ }
+
+ /**
+ * Returns the length of this file.
+ *
+ * @return the length of this file, measured in bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ public long length() throws IOException {
+ // BEGIN Android-changed: Implement on top of libcore os API.
+ try {
+ return Libcore.os.fstat(fd).st_size;
+ } catch (ErrnoException errnoException) {
+ throw errnoException.rethrowAsIOException();
+ }
+ // END Android-changed: Implement on top of libcore os API.
+ }
+
+ /**
+ * Sets the length of this file.
+ *
+ * <p> If the present length of the file as returned by the
+ * {@code length} method is greater than the {@code newLength}
+ * argument then the file will be truncated. In this case, if the file
+ * offset as returned by the {@code getFilePointer} method is greater
+ * than {@code newLength} then after this method returns the offset
+ * will be equal to {@code newLength}.
+ *
+ * <p> If the present length of the file as returned by the
+ * {@code length} method is smaller than the {@code newLength}
+ * argument then the file will be extended. In this case, the contents of
+ * the extended portion of the file are not defined.
+ *
+ * @param newLength The desired length of the file
+ * @exception IOException If an I/O error occurs
+ * @since 1.2
+ */
+ public void setLength(long newLength) throws IOException {
+ // BEGIN Android-changed: Implement on top of libcore os API.
+ if (newLength < 0) {
+ throw new IllegalArgumentException("newLength < 0");
+ }
+ try {
+ Libcore.os.ftruncate(fd, newLength);
+ } catch (ErrnoException errnoException) {
+ throw errnoException.rethrowAsIOException();
+ }
+
+ long filePointer = getFilePointer();
+ if (filePointer > newLength) {
+ seek(newLength);
+ }
+ maybeSync();
+ // END Android-changed: Implement on top of libcore os API.
+ }
+
+
+ /**
+ * Closes this random access file stream and releases any system
+ * resources associated with the stream. A closed random access
+ * file cannot perform input or output operations and cannot be
+ * reopened.
+ *
+ * <p> If this file has an associated channel then the channel is closed
+ * as well.
+ *
+ * @exception IOException if an I/O error occurs.
+ *
+ * @revised 1.4
+ * @spec JSR-51
+ */
+ public void close() throws IOException {
+ guard.close();
+ synchronized (closeLock) {
+ if (closed) {
+ return;
+ }
+ closed = true;
+ }
+
+ // BEGIN Android-changed: Implement on top of libcore os API.
+ if (channel != null && channel.isOpen()) {
+ channel.close();
+ }
+ IoBridge.closeAndSignalBlockedThreads(fd);
+ // END Android-changed: Implement on top of libcore os API.
+ }
+
+ //
+ // Some "reading/writing Java data types" methods stolen from
+ // DataInputStream and DataOutputStream.
+ //
+
+ /**
+ * Reads a {@code boolean} from this file. This method reads a
+ * single byte from the file, starting at the current file pointer.
+ * A value of {@code 0} represents
+ * {@code false}. Any other value represents {@code true}.
+ * This method blocks until the byte is read, the end of the stream
+ * is detected, or an exception is thrown.
+ *
+ * @return the {@code boolean} value read.
+ * @exception EOFException if this file has reached the end.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final boolean readBoolean() throws IOException {
+ int ch = this.read();
+ if (ch < 0)
+ throw new EOFException();
+ return (ch != 0);
+ }
+
+ /**
+ * Reads a signed eight-bit value from this file. This method reads a
+ * byte from the file, starting from the current file pointer.
+ * If the byte read is {@code b}, where
+ * <code>0 <= b <= 255</code>,
+ * then the result is:
+ * <blockquote><pre>
+ * (byte)(b)
+ * </pre></blockquote>
+ * <p>
+ * This method blocks until the byte is read, the end of the stream
+ * is detected, or an exception is thrown.
+ *
+ * @return the next byte of this file as a signed eight-bit
+ * {@code byte}.
+ * @exception EOFException if this file has reached the end.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final byte readByte() throws IOException {
+ int ch = this.read();
+ if (ch < 0)
+ throw new EOFException();
+ return (byte)(ch);
+ }
+
+ /**
+ * Reads an unsigned eight-bit number from this file. This method reads
+ * a byte from this file, starting at the current file pointer,
+ * and returns that byte.
+ * <p>
+ * This method blocks until the byte is read, the end of the stream
+ * is detected, or an exception is thrown.
+ *
+ * @return the next byte of this file, interpreted as an unsigned
+ * eight-bit number.
+ * @exception EOFException if this file has reached the end.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final int readUnsignedByte() throws IOException {
+ int ch = this.read();
+ if (ch < 0)
+ throw new EOFException();
+ return ch;
+ }
+
+ /**
+ * Reads a signed 16-bit number from this file. The method reads two
+ * bytes from this file, starting at the current file pointer.
+ * If the two bytes read, in order, are
+ * {@code b1} and {@code b2}, where each of the two values is
+ * between {@code 0} and {@code 255}, inclusive, then the
+ * result is equal to:
+ * <blockquote><pre>
+ * (short)((b1 << 8) | b2)
+ * </pre></blockquote>
+ * <p>
+ * This method blocks until the two bytes are read, the end of the
+ * stream is detected, or an exception is thrown.
+ *
+ * @return the next two bytes of this file, interpreted as a signed
+ * 16-bit number.
+ * @exception EOFException if this file reaches the end before reading
+ * two bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final short readShort() throws IOException {
+ int ch1 = this.read();
+ int ch2 = this.read();
+ if ((ch1 | ch2) < 0)
+ throw new EOFException();
+ return (short)((ch1 << 8) + (ch2 << 0));
+ }
+
+ /**
+ * Reads an unsigned 16-bit number from this file. This method reads
+ * two bytes from the file, starting at the current file pointer.
+ * If the bytes read, in order, are
+ * {@code b1} and {@code b2}, where
+ * <code>0 <= b1, b2 <= 255</code>,
+ * then the result is equal to:
+ * <blockquote><pre>
+ * (b1 << 8) | b2
+ * </pre></blockquote>
+ * <p>
+ * This method blocks until the two bytes are read, the end of the
+ * stream is detected, or an exception is thrown.
+ *
+ * @return the next two bytes of this file, interpreted as an unsigned
+ * 16-bit integer.
+ * @exception EOFException if this file reaches the end before reading
+ * two bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final int readUnsignedShort() throws IOException {
+ int ch1 = this.read();
+ int ch2 = this.read();
+ if ((ch1 | ch2) < 0)
+ throw new EOFException();
+ return (ch1 << 8) + (ch2 << 0);
+ }
+
+ /**
+ * Reads a character from this file. This method reads two
+ * bytes from the file, starting at the current file pointer.
+ * If the bytes read, in order, are
+ * {@code b1} and {@code b2}, where
+ * <code>0 <= b1, b2 <= 255</code>,
+ * then the result is equal to:
+ * <blockquote><pre>
+ * (char)((b1 << 8) | b2)
+ * </pre></blockquote>
+ * <p>
+ * This method blocks until the two bytes are read, the end of the
+ * stream is detected, or an exception is thrown.
+ *
+ * @return the next two bytes of this file, interpreted as a
+ * {@code char}.
+ * @exception EOFException if this file reaches the end before reading
+ * two bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final char readChar() throws IOException {
+ int ch1 = this.read();
+ int ch2 = this.read();
+ if ((ch1 | ch2) < 0)
+ throw new EOFException();
+ return (char)((ch1 << 8) + (ch2 << 0));
+ }
+
+ /**
+ * Reads a signed 32-bit integer from this file. This method reads 4
+ * bytes from the file, starting at the current file pointer.
+ * If the bytes read, in order, are {@code b1},
+ * {@code b2}, {@code b3}, and {@code b4}, where
+ * <code>0 <= b1, b2, b3, b4 <= 255</code>,
+ * then the result is equal to:
+ * <blockquote><pre>
+ * (b1 << 24) | (b2 << 16) + (b3 << 8) + b4
+ * </pre></blockquote>
+ * <p>
+ * This method blocks until the four bytes are read, the end of the
+ * stream is detected, or an exception is thrown.
+ *
+ * @return the next four bytes of this file, interpreted as an
+ * {@code int}.
+ * @exception EOFException if this file reaches the end before reading
+ * four bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final int readInt() throws IOException {
+ int ch1 = this.read();
+ int ch2 = this.read();
+ int ch3 = this.read();
+ int ch4 = this.read();
+ if ((ch1 | ch2 | ch3 | ch4) < 0)
+ throw new EOFException();
+ return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
+ }
+
+ /**
+ * Reads a signed 64-bit integer from this file. This method reads eight
+ * bytes from the file, starting at the current file pointer.
+ * If the bytes read, in order, are
+ * {@code b1}, {@code b2}, {@code b3},
+ * {@code b4}, {@code b5}, {@code b6},
+ * {@code b7}, and {@code b8,} where:
+ * <blockquote><pre>
+ * 0 <= b1, b2, b3, b4, b5, b6, b7, b8 <=255,
+ * </pre></blockquote>
+ * <p>
+ * then the result is equal to:
+ * <blockquote><pre>
+ * ((long)b1 << 56) + ((long)b2 << 48)
+ * + ((long)b3 << 40) + ((long)b4 << 32)
+ * + ((long)b5 << 24) + ((long)b6 << 16)
+ * + ((long)b7 << 8) + b8
+ * </pre></blockquote>
+ * <p>
+ * This method blocks until the eight bytes are read, the end of the
+ * stream is detected, or an exception is thrown.
+ *
+ * @return the next eight bytes of this file, interpreted as a
+ * {@code long}.
+ * @exception EOFException if this file reaches the end before reading
+ * eight bytes.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final long readLong() throws IOException {
+ return ((long)(readInt()) << 32) + (readInt() & 0xFFFFFFFFL);
+ }
+
+ /**
+ * Reads a {@code float} from this file. This method reads an
+ * {@code int} value, starting at the current file pointer,
+ * as if by the {@code readInt} method
+ * and then converts that {@code int} to a {@code float}
+ * using the {@code intBitsToFloat} method in class
+ * {@code Float}.
+ * <p>
+ * This method blocks until the four bytes are read, the end of the
+ * stream is detected, or an exception is thrown.
+ *
+ * @return the next four bytes of this file, interpreted as a
+ * {@code float}.
+ * @exception EOFException if this file reaches the end before reading
+ * four bytes.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.RandomAccessFile#readInt()
+ * @see java.lang.Float#intBitsToFloat(int)
+ */
+ public final float readFloat() throws IOException {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ /**
+ * Reads a {@code double} from this file. This method reads a
+ * {@code long} value, starting at the current file pointer,
+ * as if by the {@code readLong} method
+ * and then converts that {@code long} to a {@code double}
+ * using the {@code longBitsToDouble} method in
+ * class {@code Double}.
+ * <p>
+ * This method blocks until the eight bytes are read, the end of the
+ * stream is detected, or an exception is thrown.
+ *
+ * @return the next eight bytes of this file, interpreted as a
+ * {@code double}.
+ * @exception EOFException if this file reaches the end before reading
+ * eight bytes.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.RandomAccessFile#readLong()
+ * @see java.lang.Double#longBitsToDouble(long)
+ */
+ public final double readDouble() throws IOException {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ /**
+ * Reads the next line of text from this file. This method successively
+ * reads bytes from the file, starting at the current file pointer,
+ * until it reaches a line terminator or the end
+ * of the file. Each byte is converted into a character by taking the
+ * byte's value for the lower eight bits of the character and setting the
+ * high eight bits of the character to zero. This method does not,
+ * therefore, support the full Unicode character set.
+ *
+ * <p> A line of text is terminated by a carriage-return character
+ * ({@code '\u005Cr'}), a newline character ({@code '\u005Cn'}), a
+ * carriage-return character immediately followed by a newline character,
+ * or the end of the file. Line-terminating characters are discarded and
+ * are not included as part of the string returned.
+ *
+ * <p> This method blocks until a newline character is read, a carriage
+ * return and the byte following it are read (to see if it is a newline),
+ * the end of the file is reached, or an exception is thrown.
+ *
+ * @return the next line of text from this file, or null if end
+ * of file is encountered before even one byte is read.
+ * @exception IOException if an I/O error occurs.
+ */
+
+ public final String readLine() throws IOException {
+ StringBuffer input = new StringBuffer();
+ int c = -1;
+ boolean eol = false;
+
+ while (!eol) {
+ switch (c = read()) {
+ case -1:
+ case '\n':
+ eol = true;
+ break;
+ case '\r':
+ eol = true;
+ long cur = getFilePointer();
+ if ((read()) != '\n') {
+ seek(cur);
+ }
+ break;
+ default:
+ input.append((char)c);
+ break;
+ }
+ }
+
+ if ((c == -1) && (input.length() == 0)) {
+ return null;
+ }
+ return input.toString();
+ }
+
+ /**
+ * Reads in a string from this file. The string has been encoded
+ * using a
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+ * format.
+ * <p>
+ * The first two bytes are read, starting from the current file
+ * pointer, as if by
+ * {@code readUnsignedShort}. This value gives the number of
+ * following bytes that are in the encoded string, not
+ * the length of the resulting string. The following bytes are then
+ * interpreted as bytes encoding characters in the modified UTF-8 format
+ * and are converted into characters.
+ * <p>
+ * This method blocks until all the bytes are read, the end of the
+ * stream is detected, or an exception is thrown.
+ *
+ * @return a Unicode string.
+ * @exception EOFException if this file reaches the end before
+ * reading all the bytes.
+ * @exception IOException if an I/O error occurs.
+ * @exception UTFDataFormatException if the bytes do not represent
+ * valid modified UTF-8 encoding of a Unicode string.
+ * @see java.io.RandomAccessFile#readUnsignedShort()
+ */
+ public final String readUTF() throws IOException {
+ return DataInputStream.readUTF(this);
+ }
+
+ /**
+ * Writes a {@code boolean} to the file as a one-byte value. The
+ * value {@code true} is written out as the value
+ * {@code (byte)1}; the value {@code false} is written out
+ * as the value {@code (byte)0}. The write starts at
+ * the current position of the file pointer.
+ *
+ * @param v a {@code boolean} value to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final void writeBoolean(boolean v) throws IOException {
+ write(v ? 1 : 0);
+ //written++;
+ }
+
+ /**
+ * Writes a {@code byte} to the file as a one-byte value. The
+ * write starts at the current position of the file pointer.
+ *
+ * @param v a {@code byte} value to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final void writeByte(int v) throws IOException {
+ write(v);
+ //written++;
+ }
+
+ /**
+ * Writes a {@code short} to the file as two bytes, high byte first.
+ * The write starts at the current position of the file pointer.
+ *
+ * @param v a {@code short} to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final void writeShort(int v) throws IOException {
+ write((v >>> 8) & 0xFF);
+ write((v >>> 0) & 0xFF);
+ //written += 2;
+ }
+
+ /**
+ * Writes a {@code char} to the file as a two-byte value, high
+ * byte first. The write starts at the current position of the
+ * file pointer.
+ *
+ * @param v a {@code char} value to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final void writeChar(int v) throws IOException {
+ write((v >>> 8) & 0xFF);
+ write((v >>> 0) & 0xFF);
+ //written += 2;
+ }
+
+ /**
+ * Writes an {@code int} to the file as four bytes, high byte first.
+ * The write starts at the current position of the file pointer.
+ *
+ * @param v an {@code int} to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final void writeInt(int v) throws IOException {
+ write((v >>> 24) & 0xFF);
+ write((v >>> 16) & 0xFF);
+ write((v >>> 8) & 0xFF);
+ write((v >>> 0) & 0xFF);
+ //written += 4;
+ }
+
+ /**
+ * Writes a {@code long} to the file as eight bytes, high byte first.
+ * The write starts at the current position of the file pointer.
+ *
+ * @param v a {@code long} to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final void writeLong(long v) throws IOException {
+ write((int)(v >>> 56) & 0xFF);
+ write((int)(v >>> 48) & 0xFF);
+ write((int)(v >>> 40) & 0xFF);
+ write((int)(v >>> 32) & 0xFF);
+ write((int)(v >>> 24) & 0xFF);
+ write((int)(v >>> 16) & 0xFF);
+ write((int)(v >>> 8) & 0xFF);
+ write((int)(v >>> 0) & 0xFF);
+ //written += 8;
+ }
+
+ /**
+ * Converts the float argument to an {@code int} using the
+ * {@code floatToIntBits} method in class {@code Float},
+ * and then writes that {@code int} value to the file as a
+ * four-byte quantity, high byte first. The write starts at the
+ * current position of the file pointer.
+ *
+ * @param v a {@code float} value to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.lang.Float#floatToIntBits(float)
+ */
+ public final void writeFloat(float v) throws IOException {
+ writeInt(Float.floatToIntBits(v));
+ }
+
+ /**
+ * Converts the double argument to a {@code long} using the
+ * {@code doubleToLongBits} method in class {@code Double},
+ * and then writes that {@code long} value to the file as an
+ * eight-byte quantity, high byte first. The write starts at the current
+ * position of the file pointer.
+ *
+ * @param v a {@code double} value to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.lang.Double#doubleToLongBits(double)
+ */
+ public final void writeDouble(double v) throws IOException {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ /**
+ * Writes the string to the file as a sequence of bytes. Each
+ * character in the string is written out, in sequence, by discarding
+ * its high eight bits. The write starts at the current position of
+ * the file pointer.
+ *
+ * @param s a string of bytes to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ @SuppressWarnings("deprecation")
+ public final void writeBytes(String s) throws IOException {
+ int len = s.length();
+ byte[] b = new byte[len];
+ s.getBytes(0, len, b, 0);
+ writeBytes(b, 0, len);
+ }
+
+ /**
+ * Writes a string to the file as a sequence of characters. Each
+ * character is written to the data output stream as if by the
+ * {@code writeChar} method. The write starts at the current
+ * position of the file pointer.
+ *
+ * @param s a {@code String} value to be written.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.RandomAccessFile#writeChar(int)
+ */
+ public final void writeChars(String s) throws IOException {
+ int clen = s.length();
+ int blen = 2*clen;
+ byte[] b = new byte[blen];
+ char[] c = new char[clen];
+ s.getChars(0, clen, c, 0);
+ for (int i = 0, j = 0; i < clen; i++) {
+ b[j++] = (byte)(c[i] >>> 8);
+ b[j++] = (byte)(c[i] >>> 0);
+ }
+ writeBytes(b, 0, blen);
+ }
+
+ /**
+ * Writes a string to the file using
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+ * encoding in a machine-independent manner.
+ * <p>
+ * First, two bytes are written to the file, starting at the
+ * current file pointer, as if by the
+ * {@code writeShort} method giving the number of bytes to
+ * follow. This value is the number of bytes actually written out,
+ * not the length of the string. Following the length, each character
+ * of the string is output, in sequence, using the modified UTF-8 encoding
+ * for each character.
+ *
+ * @param str a string to be written.
+ * @exception IOException if an I/O error occurs.
+ */
+ public final void writeUTF(String str) throws IOException {
+ DataOutputStream.writeUTF(str, this);
+ }
+
+ // Android-added: use finalize() to detect if not close()d.
+ @Override protected void finalize() throws Throwable {
+ try {
+ if (guard != null) {
+ guard.warnIfOpen();
+ }
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+}
diff --git a/java/io/Reader.java b/java/io/Reader.java
new file mode 100644
index 0000000..1c9cca6
--- /dev/null
+++ b/java/io/Reader.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Abstract class for reading character streams. The only methods that a
+ * subclass must implement are read(char[], int, int) and close(). Most
+ * subclasses, however, will override some of the methods defined here in order
+ * to provide higher efficiency, additional functionality, or both.
+ *
+ *
+ * @see BufferedReader
+ * @see LineNumberReader
+ * @see CharArrayReader
+ * @see InputStreamReader
+ * @see FileReader
+ * @see FilterReader
+ * @see PushbackReader
+ * @see PipedReader
+ * @see StringReader
+ * @see Writer
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public abstract class Reader implements Readable, Closeable {
+
+ /**
+ * The object used to synchronize operations on this stream. For
+ * efficiency, a character-stream object may use an object other than
+ * itself to protect critical sections. A subclass should therefore use
+ * the object in this field rather than <tt>this</tt> or a synchronized
+ * method.
+ */
+ protected Object lock;
+
+ /**
+ * Creates a new character-stream reader whose critical sections will
+ * synchronize on the reader itself.
+ */
+ protected Reader() {
+ this.lock = this;
+ }
+
+ /**
+ * Creates a new character-stream reader whose critical sections will
+ * synchronize on the given object.
+ *
+ * @param lock The Object to synchronize on.
+ */
+ protected Reader(Object lock) {
+ if (lock == null) {
+ throw new NullPointerException();
+ }
+ this.lock = lock;
+ }
+
+ /**
+ * Attempts to read characters into the specified character buffer.
+ * The buffer is used as a repository of characters as-is: the only
+ * changes made are the results of a put operation. No flipping or
+ * rewinding of the buffer is performed.
+ *
+ * @param target the buffer to read characters into
+ * @return The number of characters added to the buffer, or
+ * -1 if this source of characters is at its end
+ * @throws IOException if an I/O error occurs
+ * @throws NullPointerException if target is null
+ * @throws java.nio.ReadOnlyBufferException if target is a read only buffer
+ * @since 1.5
+ */
+ public int read(java.nio.CharBuffer target) throws IOException {
+ int len = target.remaining();
+ char[] cbuf = new char[len];
+ int n = read(cbuf, 0, len);
+ if (n > 0)
+ target.put(cbuf, 0, n);
+ return n;
+ }
+
+ /**
+ * Reads a single character. This method will block until a character is
+ * available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * <p> Subclasses that intend to support efficient single-character input
+ * should override this method.
+ *
+ * @return The character read, as an integer in the range 0 to 65535
+ * (<tt>0x00-0xffff</tt>), or -1 if the end of the stream has
+ * been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read() throws IOException {
+ char cb[] = new char[1];
+ if (read(cb, 0, 1) == -1)
+ return -1;
+ else
+ return cb[0];
+ }
+
+ /**
+ * Reads characters into an array. This method will block until some input
+ * is available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * @param cbuf Destination buffer
+ *
+ * @return The number of characters read, or -1
+ * if the end of the stream
+ * has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read(char cbuf[]) throws IOException {
+ return read(cbuf, 0, cbuf.length);
+ }
+
+ /**
+ * Reads characters into a portion of an array. This method will block
+ * until some input is available, an I/O error occurs, or the end of the
+ * stream is reached.
+ *
+ * @param cbuf Destination buffer
+ * @param off Offset at which to start storing characters
+ * @param len Maximum number of characters to read
+ *
+ * @return The number of characters read, or -1 if the end of the
+ * stream has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ abstract public int read(char cbuf[], int off, int len) throws IOException;
+
+ /** Maximum skip-buffer size */
+ private static final int maxSkipBufferSize = 8192;
+
+ /** Skip buffer, null until allocated */
+ private char skipBuffer[] = null;
+
+ /**
+ * Skips characters. This method will block until some characters are
+ * available, an I/O error occurs, or the end of the stream is reached.
+ *
+ * @param n The number of characters to skip
+ *
+ * @return The number of characters actually skipped
+ *
+ * @exception IllegalArgumentException If <code>n</code> is negative.
+ * @exception IOException If an I/O error occurs
+ */
+ public long skip(long n) throws IOException {
+ if (n < 0L)
+ throw new IllegalArgumentException("skip value is negative");
+ int nn = (int) Math.min(n, maxSkipBufferSize);
+ synchronized (lock) {
+ if ((skipBuffer == null) || (skipBuffer.length < nn))
+ skipBuffer = new char[nn];
+ long r = n;
+ while (r > 0) {
+ int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
+ if (nc == -1)
+ break;
+ r -= nc;
+ }
+ return n - r;
+ }
+ }
+
+ /**
+ * Tells whether this stream is ready to be read.
+ *
+ * @return True if the next read() is guaranteed not to block for input,
+ * false otherwise. Note that returning false does not guarantee that the
+ * next read will block.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public boolean ready() throws IOException {
+ return false;
+ }
+
+ /**
+ * Tells whether this stream supports the mark() operation. The default
+ * implementation always returns false. Subclasses should override this
+ * method.
+ *
+ * @return true if and only if this stream supports the mark operation.
+ */
+ public boolean markSupported() {
+ return false;
+ }
+
+ /**
+ * Marks the present position in the stream. Subsequent calls to reset()
+ * will attempt to reposition the stream to this point. Not all
+ * character-input streams support the mark() operation.
+ *
+ * @param readAheadLimit Limit on the number of characters that may be
+ * read while still preserving the mark. After
+ * reading this many characters, attempting to
+ * reset the stream may fail.
+ *
+ * @exception IOException If the stream does not support mark(),
+ * or if some other I/O error occurs
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ throw new IOException("mark() not supported");
+ }
+
+ /**
+ * Resets the stream. If the stream has been marked, then attempt to
+ * reposition it at the mark. If the stream has not been marked, then
+ * attempt to reset it in some way appropriate to the particular stream,
+ * for example by repositioning it to its starting point. Not all
+ * character-input streams support the reset() operation, and some support
+ * reset() without supporting mark().
+ *
+ * @exception IOException If the stream has not been marked,
+ * or if the mark has been invalidated,
+ * or if the stream does not support reset(),
+ * or if some other I/O error occurs
+ */
+ public void reset() throws IOException {
+ throw new IOException("reset() not supported");
+ }
+
+ /**
+ * Closes the stream and releases any system resources associated with
+ * it. Once the stream has been closed, further read(), ready(),
+ * mark(), reset(), or skip() invocations will throw an IOException.
+ * Closing a previously closed stream has no effect.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ abstract public void close() throws IOException;
+
+}
diff --git a/java/io/SequenceInputStream.java b/java/io/SequenceInputStream.java
new file mode 100644
index 0000000..01da7f6
--- /dev/null
+++ b/java/io/SequenceInputStream.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * A <code>SequenceInputStream</code> represents
+ * the logical concatenation of other input
+ * streams. It starts out with an ordered
+ * collection of input streams and reads from
+ * the first one until end of file is reached,
+ * whereupon it reads from the second one,
+ * and so on, until end of file is reached
+ * on the last of the contained input streams.
+ *
+ * @author Author van Hoff
+ * @since JDK1.0
+ */
+public
+class SequenceInputStream extends InputStream {
+ Enumeration<? extends InputStream> e;
+ InputStream in;
+
+ /**
+ * Initializes a newly created <code>SequenceInputStream</code>
+ * by remembering the argument, which must
+ * be an <code>Enumeration</code> that produces
+ * objects whose run-time type is <code>InputStream</code>.
+ * The input streams that are produced by
+ * the enumeration will be read, in order,
+ * to provide the bytes to be read from this
+ * <code>SequenceInputStream</code>. After
+ * each input stream from the enumeration
+ * is exhausted, it is closed by calling its
+ * <code>close</code> method.
+ *
+ * @param e an enumeration of input streams.
+ * @see java.util.Enumeration
+ */
+ public SequenceInputStream(Enumeration<? extends InputStream> e) {
+ this.e = e;
+ try {
+ nextStream();
+ } catch (IOException ex) {
+ // This should never happen
+ throw new Error("panic");
+ }
+ }
+
+ /**
+ * Initializes a newly
+ * created <code>SequenceInputStream</code>
+ * by remembering the two arguments, which
+ * will be read in order, first <code>s1</code>
+ * and then <code>s2</code>, to provide the
+ * bytes to be read from this <code>SequenceInputStream</code>.
+ *
+ * @param s1 the first input stream to read.
+ * @param s2 the second input stream to read.
+ */
+ public SequenceInputStream(InputStream s1, InputStream s2) {
+ Vector<InputStream> v = new Vector<>(2);
+
+ v.addElement(s1);
+ v.addElement(s2);
+ e = v.elements();
+ try {
+ nextStream();
+ } catch (IOException ex) {
+ // This should never happen
+ throw new Error("panic");
+ }
+ }
+
+ /**
+ * Continues reading in the next stream if an EOF is reached.
+ */
+ final void nextStream() throws IOException {
+ if (in != null) {
+ in.close();
+ }
+
+ if (e.hasMoreElements()) {
+ in = (InputStream) e.nextElement();
+ if (in == null)
+ throw new NullPointerException();
+ }
+ else in = null;
+
+ }
+
+ /**
+ * Returns an estimate of the number of bytes that can be read (or
+ * skipped over) from the current underlying input stream without
+ * blocking by the next invocation of a method for the current
+ * underlying input stream. The next invocation might be
+ * the same thread or another thread. A single read or skip of this
+ * many bytes will not block, but may read or skip fewer bytes.
+ * <p>
+ * This method simply calls {@code available} of the current underlying
+ * input stream and returns the result.
+ *
+ * @return an estimate of the number of bytes that can be read (or
+ * skipped over) from the current underlying input stream
+ * without blocking or {@code 0} if this input stream
+ * has been closed by invoking its {@link #close()} method
+ * @exception IOException if an I/O error occurs.
+ *
+ * @since JDK1.1
+ */
+ public int available() throws IOException {
+ if (in == null) {
+ return 0; // no way to signal EOF from available()
+ }
+ return in.available();
+ }
+
+ /**
+ * Reads the next byte of data from this input stream. The byte is
+ * returned as an <code>int</code> in the range <code>0</code> to
+ * <code>255</code>. If no byte is available because the end of the
+ * stream has been reached, the value <code>-1</code> is returned.
+ * This method blocks until input data is available, the end of the
+ * stream is detected, or an exception is thrown.
+ * <p>
+ * This method
+ * tries to read one character from the current substream. If it
+ * reaches the end of the stream, it calls the <code>close</code>
+ * method of the current substream and begins reading from the next
+ * substream.
+ *
+ * @return the next byte of data, or <code>-1</code> if the end of the
+ * stream is reached.
+ * @exception IOException if an I/O error occurs.
+ */
+ public int read() throws IOException {
+ while (in != null) {
+ int c = in.read();
+ if (c != -1) {
+ return c;
+ }
+ nextStream();
+ }
+ return -1;
+ }
+
+ /**
+ * Reads up to <code>len</code> bytes of data from this input stream
+ * into an array of bytes. If <code>len</code> is not zero, the method
+ * blocks until at least 1 byte of input is available; otherwise, no
+ * bytes are read and <code>0</code> is returned.
+ * <p>
+ * The <code>read</code> method of <code>SequenceInputStream</code>
+ * tries to read the data from the current substream. If it fails to
+ * read any characters because the substream has reached the end of
+ * the stream, it calls the <code>close</code> method of the current
+ * substream and begins reading from the next substream.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in array <code>b</code>
+ * at which the data is written.
+ * @param len the maximum number of bytes read.
+ * @return int the number of bytes read.
+ * @exception NullPointerException If <code>b</code> is <code>null</code>.
+ * @exception IndexOutOfBoundsException If <code>off</code> is negative,
+ * <code>len</code> is negative, or <code>len</code> is greater than
+ * <code>b.length - off</code>
+ * @exception IOException if an I/O error occurs.
+ */
+ public int read(byte b[], int off, int len) throws IOException {
+ if (in == null) {
+ return -1;
+ } else if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+ do {
+ int n = in.read(b, off, len);
+ if (n > 0) {
+ return n;
+ }
+ nextStream();
+ } while (in != null);
+ return -1;
+ }
+
+ /**
+ * Closes this input stream and releases any system resources
+ * associated with the stream.
+ * A closed <code>SequenceInputStream</code>
+ * cannot perform input operations and cannot
+ * be reopened.
+ * <p>
+ * If this stream was created
+ * from an enumeration, all remaining elements
+ * are requested from the enumeration and closed
+ * before the <code>close</code> method returns.
+ *
+ * @exception IOException if an I/O error occurs.
+ */
+ public void close() throws IOException {
+ do {
+ nextStream();
+ } while (in != null);
+ }
+}
diff --git a/java/io/SerialCallbackContext.java b/java/io/SerialCallbackContext.java
new file mode 100644
index 0000000..4009087
--- /dev/null
+++ b/java/io/SerialCallbackContext.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Context during upcalls from object stream to class-defined
+ * readObject/writeObject methods.
+ * Holds object currently being deserialized and descriptor for current class.
+ *
+ * This context keeps track of the thread it was constructed on, and allows
+ * only a single call of defaultReadObject, readFields, defaultWriteObject
+ * or writeFields which must be invoked on the same thread before the class's
+ * readObject/writeObject method has returned.
+ * If not set to the current thread, the getObj method throws NotActiveException.
+ */
+final class SerialCallbackContext {
+ private final Object obj;
+ private final ObjectStreamClass desc;
+ /**
+ * Thread this context is in use by.
+ * As this only works in one thread, we do not need to worry about thread-safety.
+ */
+ private Thread thread;
+
+ public SerialCallbackContext(Object obj, ObjectStreamClass desc) {
+ this.obj = obj;
+ this.desc = desc;
+ this.thread = Thread.currentThread();
+ }
+
+ public Object getObj() throws NotActiveException {
+ checkAndSetUsed();
+ return obj;
+ }
+
+ public ObjectStreamClass getDesc() {
+ return desc;
+ }
+
+ public void check() throws NotActiveException {
+ if (thread != null && thread != Thread.currentThread()) {
+ throw new NotActiveException(
+ "expected thread: " + thread + ", but got: " + Thread.currentThread());
+ }
+ }
+
+ private void checkAndSetUsed() throws NotActiveException {
+ if (thread != Thread.currentThread()) {
+ throw new NotActiveException(
+ "not in readObject invocation or fields already read");
+ }
+ thread = null;
+ }
+
+ public void setUsed() {
+ thread = null;
+ }
+}
diff --git a/java/io/Serializable.java b/java/io/Serializable.java
new file mode 100644
index 0000000..496aef7
--- /dev/null
+++ b/java/io/Serializable.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+// Android-added: Notes about serialVersionUID, using serialization judiciously, JSON.
+/**
+ * Serializability of a class is enabled by the class implementing the
+ * java.io.Serializable interface. Classes that do not implement this
+ * interface will not have any of their state serialized or
+ * deserialized. All subtypes of a serializable class are themselves
+ * serializable. The serialization interface has no methods or fields
+ * and serves only to identify the semantics of being serializable. <p>
+ *
+ * To allow subtypes of non-serializable classes to be serialized, the
+ * subtype may assume responsibility for saving and restoring the
+ * state of the supertype's public, protected, and (if accessible)
+ * package fields. The subtype may assume this responsibility only if
+ * the class it extends has an accessible no-arg constructor to
+ * initialize the class's state. It is an error to declare a class
+ * Serializable if this is not the case. The error will be detected at
+ * runtime. <p>
+ *
+ * During deserialization, the fields of non-serializable classes will
+ * be initialized using the public or protected no-arg constructor of
+ * the class. A no-arg constructor must be accessible to the subclass
+ * that is serializable. The fields of serializable subclasses will
+ * be restored from the stream. <p>
+ *
+ * When traversing a graph, an object may be encountered that does not
+ * support the Serializable interface. In this case the
+ * NotSerializableException will be thrown and will identify the class
+ * of the non-serializable object. <p>
+ *
+ * Classes that require special handling during the serialization and
+ * deserialization process must implement special methods with these exact
+ * signatures:
+ *
+ * <PRE>
+ * private void writeObject(java.io.ObjectOutputStream out)
+ * throws IOException
+ * private void readObject(java.io.ObjectInputStream in)
+ * throws IOException, ClassNotFoundException;
+ * private void readObjectNoData()
+ * throws ObjectStreamException;
+ * </PRE>
+ *
+ * <p>The writeObject method is responsible for writing the state of the
+ * object for its particular class so that the corresponding
+ * readObject method can restore it. The default mechanism for saving
+ * the Object's fields can be invoked by calling
+ * out.defaultWriteObject. The method does not need to concern
+ * itself with the state belonging to its superclasses or subclasses.
+ * State is saved by writing the individual fields to the
+ * ObjectOutputStream using the writeObject method or by using the
+ * methods for primitive data types supported by DataOutput.
+ *
+ * <p>The readObject method is responsible for reading from the stream and
+ * restoring the classes fields. It may call in.defaultReadObject to invoke
+ * the default mechanism for restoring the object's non-static and
+ * non-transient fields. The defaultReadObject method uses information in
+ * the stream to assign the fields of the object saved in the stream with the
+ * correspondingly named fields in the current object. This handles the case
+ * when the class has evolved to add new fields. The method does not need to
+ * concern itself with the state belonging to its superclasses or subclasses.
+ * State is saved by writing the individual fields to the
+ * ObjectOutputStream using the writeObject method or by using the
+ * methods for primitive data types supported by DataOutput.
+ *
+ * <p>The readObjectNoData method is responsible for initializing the state of
+ * the object for its particular class in the event that the serialization
+ * stream does not list the given class as a superclass of the object being
+ * deserialized. This may occur in cases where the receiving party uses a
+ * different version of the deserialized instance's class than the sending
+ * party, and the receiver's version extends classes that are not extended by
+ * the sender's version. This may also occur if the serialization stream has
+ * been tampered; hence, readObjectNoData is useful for initializing
+ * deserialized objects properly despite a "hostile" or incomplete source
+ * stream.
+ *
+ * <p>Serializable classes that need to designate an alternative object to be
+ * used when writing an object to the stream should implement this
+ * special method with the exact signature:
+ *
+ * <PRE>
+ * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
+ * </PRE><p>
+ *
+ * This writeReplace method is invoked by serialization if the method
+ * exists and it would be accessible from a method defined within the
+ * class of the object being serialized. Thus, the method can have private,
+ * protected and package-private access. Subclass access to this method
+ * follows java accessibility rules. <p>
+ *
+ * Classes that need to designate a replacement when an instance of it
+ * is read from the stream should implement this special method with the
+ * exact signature.
+ *
+ * <PRE>
+ * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
+ * </PRE><p>
+ *
+ * This readResolve method follows the same invocation rules and
+ * accessibility rules as writeReplace.<p>
+ *
+ * The serialization runtime associates with each serializable class a version
+ * number, called a serialVersionUID, which is used during deserialization to
+ * verify that the sender and receiver of a serialized object have loaded
+ * classes for that object that are compatible with respect to serialization.
+ * If the receiver has loaded a class for the object that has a different
+ * serialVersionUID than that of the corresponding sender's class, then
+ * deserialization will result in an {@link InvalidClassException}. A
+ * serializable class can declare its own serialVersionUID explicitly by
+ * declaring a field named <code>"serialVersionUID"</code> that must be static,
+ * final, and of type <code>long</code>:
+ *
+ * <PRE>
+ * ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
+ * </PRE>
+ *
+ * If a serializable class does not explicitly declare a serialVersionUID, then
+ * the serialization runtime will calculate a default serialVersionUID value
+ * for that class based on various aspects of the class, as described in the
+ * Java(TM) Object Serialization Specification. However, it is <em>strongly
+ * recommended</em> that all serializable classes explicitly declare
+ * serialVersionUID values, since the default serialVersionUID computation is
+ * highly sensitive to class details that may vary depending on compiler
+ * implementations, and can thus result in unexpected
+ * <code>InvalidClassException</code>s during deserialization. Therefore, to
+ * guarantee a consistent serialVersionUID value across different java compiler
+ * implementations, a serializable class must declare an explicit
+ * serialVersionUID value. It is also strongly advised that explicit
+ * serialVersionUID declarations use the <code>private</code> modifier where
+ * possible, since such declarations apply only to the immediately declaring
+ * class--serialVersionUID fields are not useful as inherited members. Array
+ * classes cannot declare an explicit serialVersionUID, so they always have
+ * the default computed value, but the requirement for matching
+ * serialVersionUID values is waived for array classes.
+ *
+ * Android implementation of serialVersionUID computation will change slightly
+ * for some classes if you're targeting android N. In order to preserve compatibility,
+ * this change is only enabled is the application target SDK version is set to
+ * 24 or higher. It is highly recommended to use an explicit serialVersionUID
+ * field to avoid compatibility issues.
+ *
+ * <h3>Implement Serializable Judiciously</h3>
+ * Refer to <i>Effective Java</i>'s chapter on serialization for thorough
+ * coverage of the serialization API. The book explains how to use this
+ * interface without harming your application's maintainability.
+ *
+ * <h3>Recommended Alternatives</h3>
+ * <strong>JSON</strong> is concise, human-readable and efficient. Android
+ * includes both a {@link android.util.JsonReader streaming API} and a {@link
+ * org.json.JSONObject tree API} to read and write JSON. Use a binding library
+ * like <a href="http://code.google.com/p/google-gson/">GSON</a> to read and
+ * write Java objects directly.
+ *
+ * @author unascribed
+ * @see java.io.ObjectOutputStream
+ * @see java.io.ObjectInputStream
+ * @see java.io.ObjectOutput
+ * @see java.io.ObjectInput
+ * @see java.io.Externalizable
+ * @since JDK1.1
+ */
+public interface Serializable {
+}
diff --git a/java/io/SerializablePermission.java b/java/io/SerializablePermission.java
new file mode 100644
index 0000000..93bb4aa
--- /dev/null
+++ b/java/io/SerializablePermission.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.security.*;
+
+// Android-changed: Replaced with empty implementation and documented as legacy security code.
+/**
+ * This legacy security is not supported on Android. Do not use.
+ */
+public final class SerializablePermission extends BasicPermission {
+
+ public SerializablePermission(String name)
+ {
+ super("");
+ }
+
+ public SerializablePermission(String name, String actions)
+ {
+ super("", "");
+ }
+}
diff --git a/java/io/StreamCorruptedException.java b/java/io/StreamCorruptedException.java
new file mode 100644
index 0000000..57af82c
--- /dev/null
+++ b/java/io/StreamCorruptedException.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Thrown when control information that was read from an object stream
+ * violates internal consistency checks.
+ *
+ * @author unascribed
+ * @since JDK1.1
+ */
+public class StreamCorruptedException extends ObjectStreamException {
+
+ private static final long serialVersionUID = 8983558202217591746L;
+
+ /**
+ * Create a StreamCorruptedException and list a reason why thrown.
+ *
+ * @param reason String describing the reason for the exception.
+ */
+ public StreamCorruptedException(String reason) {
+ super(reason);
+ }
+
+ /**
+ * Create a StreamCorruptedException and list no reason why thrown.
+ */
+ public StreamCorruptedException() {
+ super();
+ }
+}
diff --git a/java/io/StreamTokenizer.java b/java/io/StreamTokenizer.java
new file mode 100644
index 0000000..3c7c7cc
--- /dev/null
+++ b/java/io/StreamTokenizer.java
@@ -0,0 +1,834 @@
+/*
+ * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.Arrays;
+
+/**
+ * The {@code StreamTokenizer} class takes an input stream and
+ * parses it into "tokens", allowing the tokens to be
+ * read one at a time. The parsing process is controlled by a table
+ * and a number of flags that can be set to various states. The
+ * stream tokenizer can recognize identifiers, numbers, quoted
+ * strings, and various comment styles.
+ * <p>
+ * Each byte read from the input stream is regarded as a character
+ * in the range {@code '\u005Cu0000'} through {@code '\u005Cu00FF'}.
+ * The character value is used to look up five possible attributes of
+ * the character: <i>white space</i>, <i>alphabetic</i>,
+ * <i>numeric</i>, <i>string quote</i>, and <i>comment character</i>.
+ * Each character can have zero or more of these attributes.
+ * <p>
+ * In addition, an instance has four flags. These flags indicate:
+ * <ul>
+ * <li>Whether line terminators are to be returned as tokens or treated
+ * as white space that merely separates tokens.
+ * <li>Whether C-style comments are to be recognized and skipped.
+ * <li>Whether C++-style comments are to be recognized and skipped.
+ * <li>Whether the characters of identifiers are converted to lowercase.
+ * </ul>
+ * <p>
+ * A typical application first constructs an instance of this class,
+ * sets up the syntax tables, and then repeatedly loops calling the
+ * {@code nextToken} method in each iteration of the loop until
+ * it returns the value {@code TT_EOF}.
+ *
+ * @author James Gosling
+ * @see java.io.StreamTokenizer#nextToken()
+ * @see java.io.StreamTokenizer#TT_EOF
+ * @since JDK1.0
+ */
+
+public class StreamTokenizer {
+
+ /* Only one of these will be non-null */
+ private Reader reader = null;
+ private InputStream input = null;
+
+ private char buf[] = new char[20];
+
+ /**
+ * The next character to be considered by the nextToken method. May also
+ * be NEED_CHAR to indicate that a new character should be read, or SKIP_LF
+ * to indicate that a new character should be read and, if it is a '\n'
+ * character, it should be discarded and a second new character should be
+ * read.
+ */
+ private int peekc = NEED_CHAR;
+
+ private static final int NEED_CHAR = Integer.MAX_VALUE;
+ private static final int SKIP_LF = Integer.MAX_VALUE - 1;
+
+ private boolean pushedBack;
+ private boolean forceLower;
+ /** The line number of the last token read */
+ private int LINENO = 1;
+
+ private boolean eolIsSignificantP = false;
+ private boolean slashSlashCommentsP = false;
+ private boolean slashStarCommentsP = false;
+
+ private byte ctype[] = new byte[256];
+ private static final byte CT_WHITESPACE = 1;
+ private static final byte CT_DIGIT = 2;
+ private static final byte CT_ALPHA = 4;
+ private static final byte CT_QUOTE = 8;
+ private static final byte CT_COMMENT = 16;
+
+ /**
+ * After a call to the {@code nextToken} method, this field
+ * contains the type of the token just read. For a single character
+ * token, its value is the single character, converted to an integer.
+ * For a quoted string token, its value is the quote character.
+ * Otherwise, its value is one of the following:
+ * <ul>
+ * <li>{@code TT_WORD} indicates that the token is a word.
+ * <li>{@code TT_NUMBER} indicates that the token is a number.
+ * <li>{@code TT_EOL} indicates that the end of line has been read.
+ * The field can only have this value if the
+ * {@code eolIsSignificant} method has been called with the
+ * argument {@code true}.
+ * <li>{@code TT_EOF} indicates that the end of the input stream
+ * has been reached.
+ * </ul>
+ * <p>
+ * The initial value of this field is -4.
+ *
+ * @see java.io.StreamTokenizer#eolIsSignificant(boolean)
+ * @see java.io.StreamTokenizer#nextToken()
+ * @see java.io.StreamTokenizer#quoteChar(int)
+ * @see java.io.StreamTokenizer#TT_EOF
+ * @see java.io.StreamTokenizer#TT_EOL
+ * @see java.io.StreamTokenizer#TT_NUMBER
+ * @see java.io.StreamTokenizer#TT_WORD
+ */
+ public int ttype = TT_NOTHING;
+
+ /**
+ * 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 token has been read, used for
+ * initializing ttype. FIXME This could be made public and
+ * made available as the part of the API in a future release.
+ */
+ private static final int TT_NOTHING = -4;
+
+ /**
+ * If the current token is a word token, this field contains a
+ * string giving the characters of the word token. When the current
+ * token is a quoted string token, this field contains the body of
+ * the string.
+ * <p>
+ * The current token is a word when the value of the
+ * {@code ttype} field is {@code TT_WORD}. The current token is
+ * a quoted string token when the value of the {@code ttype} field is
+ * a quote character.
+ * <p>
+ * The initial value of this field is null.
+ *
+ * @see java.io.StreamTokenizer#quoteChar(int)
+ * @see java.io.StreamTokenizer#TT_WORD
+ * @see java.io.StreamTokenizer#ttype
+ */
+ public String sval;
+
+ /**
+ * If the current token is a number, this field contains the value
+ * of that number. The current token is a number when the value of
+ * the {@code ttype} field is {@code TT_NUMBER}.
+ * <p>
+ * The initial value of this field is 0.0.
+ *
+ * @see java.io.StreamTokenizer#TT_NUMBER
+ * @see java.io.StreamTokenizer#ttype
+ */
+ public double nval;
+
+ /** Private constructor that initializes everything except the streams. */
+ private StreamTokenizer() {
+ wordChars('a', 'z');
+ wordChars('A', 'Z');
+ wordChars(128 + 32, 255);
+ whitespaceChars(0, ' ');
+ commentChar('/');
+ quoteChar('"');
+ quoteChar('\'');
+ parseNumbers();
+ }
+
+ /**
+ * Creates a stream tokenizer that parses the specified input
+ * stream. The stream tokenizer is initialized to the following
+ * default state:
+ * <ul>
+ * <li>All byte values {@code 'A'} through {@code 'Z'},
+ * {@code 'a'} through {@code 'z'}, and
+ * {@code '\u005Cu00A0'} through {@code '\u005Cu00FF'} are
+ * considered to be alphabetic.
+ * <li>All byte values {@code '\u005Cu0000'} through
+ * {@code '\u005Cu0020'} are considered to be white space.
+ * <li>{@code '/'} is a comment character.
+ * <li>Single quote {@code '\u005C''} and double quote {@code '"'}
+ * are string quote characters.
+ * <li>Numbers are parsed.
+ * <li>Ends of lines are treated as white space, not as separate tokens.
+ * <li>C-style and C++-style comments are not recognized.
+ * </ul>
+ *
+ * @deprecated As of JDK version 1.1, the preferred way to tokenize an
+ * input stream is to convert it into a character stream, for example:
+ * <blockquote><pre>
+ * Reader r = new BufferedReader(new InputStreamReader(is));
+ * StreamTokenizer st = new StreamTokenizer(r);
+ * </pre></blockquote>
+ *
+ * @param is an input stream.
+ * @see java.io.BufferedReader
+ * @see java.io.InputStreamReader
+ * @see java.io.StreamTokenizer#StreamTokenizer(java.io.Reader)
+ */
+ @Deprecated
+ public StreamTokenizer(InputStream is) {
+ this();
+ if (is == null) {
+ throw new NullPointerException();
+ }
+ input = is;
+ }
+
+ /**
+ * Create a tokenizer that parses the given character stream.
+ *
+ * @param r a Reader object providing the input stream.
+ * @since JDK1.1
+ */
+ public StreamTokenizer(Reader r) {
+ this();
+ if (r == null) {
+ throw new NullPointerException();
+ }
+ reader = r;
+ }
+
+ /**
+ * Resets this tokenizer's syntax table so that all characters are
+ * "ordinary." See the {@code ordinaryChar} method
+ * for more information on a character being ordinary.
+ *
+ * @see java.io.StreamTokenizer#ordinaryChar(int)
+ */
+ public void resetSyntax() {
+ for (int i = ctype.length; --i >= 0;)
+ ctype[i] = 0;
+ }
+
+ /**
+ * Specifies that all characters <i>c</i> in the range
+ * <code>low <= <i>c</i> <= high</code>
+ * are word constituents. A word token consists of a word constituent
+ * followed by zero or more word constituents or number constituents.
+ *
+ * @param low the low end of the range.
+ * @param hi the high end of the range.
+ */
+ public void wordChars(int low, int hi) {
+ if (low < 0)
+ low = 0;
+ if (hi >= ctype.length)
+ hi = ctype.length - 1;
+ while (low <= hi)
+ ctype[low++] |= CT_ALPHA;
+ }
+
+ /**
+ * Specifies that all characters <i>c</i> in the range
+ * <code>low <= <i>c</i> <= high</code>
+ * are white space characters. White space characters serve only to
+ * separate tokens in the input stream.
+ *
+ * <p>Any other attribute settings for the characters in the specified
+ * range are cleared.
+ *
+ * @param low the low end of the range.
+ * @param hi the high end of the range.
+ */
+ public void whitespaceChars(int low, int hi) {
+ if (low < 0)
+ low = 0;
+ if (hi >= ctype.length)
+ hi = ctype.length - 1;
+ while (low <= hi)
+ ctype[low++] = CT_WHITESPACE;
+ }
+
+ /**
+ * Specifies that all characters <i>c</i> in the range
+ * <code>low <= <i>c</i> <= high</code>
+ * are "ordinary" in this tokenizer. See the
+ * {@code ordinaryChar} method for more information on a
+ * character being ordinary.
+ *
+ * @param low the low end of the range.
+ * @param hi the high end of the range.
+ * @see java.io.StreamTokenizer#ordinaryChar(int)
+ */
+ public void ordinaryChars(int low, int hi) {
+ if (low < 0)
+ low = 0;
+ if (hi >= ctype.length)
+ hi = ctype.length - 1;
+ while (low <= hi)
+ ctype[low++] = 0;
+ }
+
+ /**
+ * Specifies that the character argument is "ordinary"
+ * in this tokenizer. It removes any special significance the
+ * character has as a comment character, word component, string
+ * delimiter, white space, or number character. When such a character
+ * is encountered by the parser, the parser treats it as a
+ * single-character token and sets {@code ttype} field to the
+ * character value.
+ *
+ * <p>Making a line terminator character "ordinary" may interfere
+ * with the ability of a {@code StreamTokenizer} to count
+ * lines. The {@code lineno} method may no longer reflect
+ * the presence of such terminator characters in its line count.
+ *
+ * @param ch the character.
+ * @see java.io.StreamTokenizer#ttype
+ */
+ public void ordinaryChar(int ch) {
+ if (ch >= 0 && ch < ctype.length)
+ ctype[ch] = 0;
+ }
+
+ /**
+ * Specified that the character argument starts a single-line
+ * comment. All characters from the comment character to the end of
+ * the line are ignored by this stream tokenizer.
+ *
+ * <p>Any other attribute settings for the specified character are cleared.
+ *
+ * @param ch the character.
+ */
+ public void commentChar(int ch) {
+ if (ch >= 0 && ch < ctype.length)
+ ctype[ch] = CT_COMMENT;
+ }
+
+ /**
+ * Specifies that matching pairs of this character delimit string
+ * constants in this tokenizer.
+ * <p>
+ * When the {@code nextToken} method encounters a string
+ * constant, the {@code ttype} field is set to the string
+ * delimiter and the {@code sval} field is set to the body of
+ * the string.
+ * <p>
+ * If a string quote character is encountered, then a string is
+ * recognized, consisting of all characters after (but not including)
+ * the string quote character, up to (but not including) the next
+ * occurrence of that same string quote character, or a line
+ * terminator, or end of file. The usual escape sequences such as
+ * {@code "\u005Cn"} and {@code "\u005Ct"} are recognized and
+ * converted to single characters as the string is parsed.
+ *
+ * <p>Any other attribute settings for the specified character are cleared.
+ *
+ * @param ch the character.
+ * @see java.io.StreamTokenizer#nextToken()
+ * @see java.io.StreamTokenizer#sval
+ * @see java.io.StreamTokenizer#ttype
+ */
+ public void quoteChar(int ch) {
+ if (ch >= 0 && ch < ctype.length)
+ ctype[ch] = CT_QUOTE;
+ }
+
+ /**
+ * Specifies that numbers should be parsed by this tokenizer. The
+ * syntax table of this tokenizer is modified so that each of the twelve
+ * characters:
+ * <blockquote><pre>
+ * 0 1 2 3 4 5 6 7 8 9 . -
+ * </pre></blockquote>
+ * <p>
+ * has the "numeric" attribute.
+ * <p>
+ * When the parser encounters a word token that has the format of a
+ * double precision floating-point number, it treats the token as a
+ * number rather than a word, by setting the {@code ttype}
+ * field to the value {@code TT_NUMBER} and putting the numeric
+ * value of the token into the {@code nval} field.
+ *
+ * @see java.io.StreamTokenizer#nval
+ * @see java.io.StreamTokenizer#TT_NUMBER
+ * @see java.io.StreamTokenizer#ttype
+ */
+ public void parseNumbers() {
+ for (int i = '0'; i <= '9'; i++)
+ ctype[i] |= CT_DIGIT;
+ ctype['.'] |= CT_DIGIT;
+ ctype['-'] |= CT_DIGIT;
+ }
+
+ /**
+ * Determines whether or not ends of line are treated as tokens.
+ * If the flag argument is true, this tokenizer treats end of lines
+ * as tokens; the {@code nextToken} method returns
+ * {@code TT_EOL} and also sets the {@code ttype} field to
+ * this value when an end of line is read.
+ * <p>
+ * A line is a sequence of characters ending with either a
+ * carriage-return character ({@code '\u005Cr'}) or a newline
+ * character ({@code '\u005Cn'}). In addition, a carriage-return
+ * character followed immediately by a newline character is treated
+ * as a single end-of-line token.
+ * <p>
+ * If the {@code flag} is false, end-of-line characters are
+ * treated as white space and serve only to separate tokens.
+ *
+ * @param flag {@code true} indicates that end-of-line characters
+ * are separate tokens; {@code false} indicates that
+ * end-of-line characters are white space.
+ * @see java.io.StreamTokenizer#nextToken()
+ * @see java.io.StreamTokenizer#ttype
+ * @see java.io.StreamTokenizer#TT_EOL
+ */
+ public void eolIsSignificant(boolean flag) {
+ eolIsSignificantP = flag;
+ }
+
+ /**
+ * Determines whether or not the tokenizer recognizes C-style comments.
+ * If the flag argument is {@code true}, this stream tokenizer
+ * recognizes C-style comments. All text between successive
+ * occurrences of {@code /*} and <code>*/</code> are discarded.
+ * <p>
+ * If the flag argument is {@code false}, then C-style comments
+ * are not treated specially.
+ *
+ * @param flag {@code true} indicates to recognize and ignore
+ * C-style comments.
+ */
+ public void slashStarComments(boolean flag) {
+ slashStarCommentsP = flag;
+ }
+
+ /**
+ * Determines whether or not the tokenizer recognizes C++-style comments.
+ * If the flag argument is {@code true}, this stream tokenizer
+ * recognizes C++-style comments. Any occurrence of two consecutive
+ * slash characters ({@code '/'}) is treated as the beginning of
+ * a comment that extends to the end of the line.
+ * <p>
+ * If the flag argument is {@code false}, then C++-style
+ * comments are not treated specially.
+ *
+ * @param flag {@code true} indicates to recognize and ignore
+ * C++-style comments.
+ */
+ public void slashSlashComments(boolean flag) {
+ slashSlashCommentsP = flag;
+ }
+
+ /**
+ * Determines whether or not word token are automatically lowercased.
+ * If the flag argument is {@code true}, then the value in the
+ * {@code sval} field is lowercased whenever a word token is
+ * returned (the {@code ttype} field has the
+ * value {@code TT_WORD} by the {@code nextToken} method
+ * of this tokenizer.
+ * <p>
+ * If the flag argument is {@code false}, then the
+ * {@code sval} field is not modified.
+ *
+ * @param fl {@code true} indicates that all word tokens should
+ * be lowercased.
+ * @see java.io.StreamTokenizer#nextToken()
+ * @see java.io.StreamTokenizer#ttype
+ * @see java.io.StreamTokenizer#TT_WORD
+ */
+ public void lowerCaseMode(boolean fl) {
+ forceLower = fl;
+ }
+
+ /** Read the next character */
+ private int read() throws IOException {
+ if (reader != null)
+ return reader.read();
+ else if (input != null)
+ return input.read();
+ else
+ throw new IllegalStateException();
+ }
+
+ /**
+ * Parses the next token from the input stream of this tokenizer.
+ * The type of the next token is returned in the {@code ttype}
+ * field. Additional information about the token may be in the
+ * {@code nval} field or the {@code sval} field of this
+ * tokenizer.
+ * <p>
+ * Typical clients of this
+ * class first set up the syntax tables and then sit in a loop
+ * calling nextToken to parse successive tokens until TT_EOF
+ * is returned.
+ *
+ * @return the value of the {@code ttype} field.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.StreamTokenizer#nval
+ * @see java.io.StreamTokenizer#sval
+ * @see java.io.StreamTokenizer#ttype
+ */
+ public int nextToken() throws IOException {
+ if (pushedBack) {
+ pushedBack = false;
+ return ttype;
+ }
+ byte ct[] = ctype;
+ sval = null;
+
+ int c = peekc;
+ if (c < 0)
+ c = NEED_CHAR;
+ if (c == SKIP_LF) {
+ c = read();
+ if (c < 0)
+ return ttype = TT_EOF;
+ if (c == '\n')
+ c = NEED_CHAR;
+ }
+ if (c == NEED_CHAR) {
+ c = read();
+ if (c < 0)
+ return ttype = TT_EOF;
+ }
+ ttype = c; /* Just to be safe */
+
+ /* Set peekc so that the next invocation of nextToken will read
+ * another character unless peekc is reset in this invocation
+ */
+ peekc = NEED_CHAR;
+
+ int ctype = c < 256 ? ct[c] : CT_ALPHA;
+ while ((ctype & CT_WHITESPACE) != 0) {
+ if (c == '\r') {
+ LINENO++;
+ if (eolIsSignificantP) {
+ peekc = SKIP_LF;
+ return ttype = TT_EOL;
+ }
+ c = read();
+ if (c == '\n')
+ c = read();
+ } else {
+ if (c == '\n') {
+ LINENO++;
+ if (eolIsSignificantP) {
+ return ttype = TT_EOL;
+ }
+ }
+ c = read();
+ }
+ if (c < 0)
+ return ttype = TT_EOF;
+ ctype = c < 256 ? ct[c] : CT_ALPHA;
+ }
+
+ if ((ctype & CT_DIGIT) != 0) {
+ boolean neg = false;
+ if (c == '-') {
+ c = read();
+ if (c != '.' && (c < '0' || c > '9')) {
+ peekc = c;
+ return ttype = '-';
+ }
+ neg = true;
+ }
+ double v = 0;
+ int decexp = 0;
+ int seendot = 0;
+ while (true) {
+ if (c == '.' && seendot == 0)
+ seendot = 1;
+ else if ('0' <= c && c <= '9') {
+ v = v * 10 + (c - '0');
+ decexp += seendot;
+ } else
+ break;
+ c = read();
+ }
+ peekc = c;
+ if (decexp != 0) {
+ double denom = 10;
+ decexp--;
+ while (decexp > 0) {
+ denom *= 10;
+ decexp--;
+ }
+ /* Do one division of a likely-to-be-more-accurate number */
+ v = v / denom;
+ }
+ nval = neg ? -v : v;
+ return ttype = TT_NUMBER;
+ }
+
+ if ((ctype & CT_ALPHA) != 0) {
+ int i = 0;
+ do {
+ if (i >= buf.length) {
+ buf = Arrays.copyOf(buf, buf.length * 2);
+ }
+ buf[i++] = (char) c;
+ c = read();
+ ctype = c < 0 ? CT_WHITESPACE : c < 256 ? ct[c] : CT_ALPHA;
+ } while ((ctype & (CT_ALPHA | CT_DIGIT)) != 0);
+ peekc = c;
+ sval = String.copyValueOf(buf, 0, i);
+ if (forceLower)
+ sval = sval.toLowerCase();
+ return ttype = TT_WORD;
+ }
+
+ if ((ctype & CT_QUOTE) != 0) {
+ ttype = c;
+ int i = 0;
+ /* Invariants (because \Octal needs a lookahead):
+ * (i) c contains char value
+ * (ii) d contains the lookahead
+ */
+ int d = read();
+ while (d >= 0 && d != ttype && d != '\n' && d != '\r') {
+ if (d == '\\') {
+ c = read();
+ int first = c; /* To allow \377, but not \477 */
+ if (c >= '0' && c <= '7') {
+ c = c - '0';
+ int c2 = read();
+ if ('0' <= c2 && c2 <= '7') {
+ c = (c << 3) + (c2 - '0');
+ c2 = read();
+ if ('0' <= c2 && c2 <= '7' && first <= '3') {
+ c = (c << 3) + (c2 - '0');
+ d = read();
+ } else
+ d = c2;
+ } else
+ d = c2;
+ } else {
+ switch (c) {
+ case 'a':
+ c = 0x7;
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'f':
+ c = 0xC;
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+ c = 0xB;
+ break;
+ }
+ d = read();
+ }
+ } else {
+ c = d;
+ d = read();
+ }
+ if (i >= buf.length) {
+ buf = Arrays.copyOf(buf, buf.length * 2);
+ }
+ buf[i++] = (char)c;
+ }
+
+ /* If we broke out of the loop because we found a matching quote
+ * character then arrange to read a new character next time
+ * around; otherwise, save the character.
+ */
+ peekc = (d == ttype) ? NEED_CHAR : d;
+
+ sval = String.copyValueOf(buf, 0, i);
+ return ttype;
+ }
+
+ if (c == '/' && (slashSlashCommentsP || slashStarCommentsP)) {
+ c = read();
+ if (c == '*' && slashStarCommentsP) {
+ int prevc = 0;
+ while ((c = read()) != '/' || prevc != '*') {
+ if (c == '\r') {
+ LINENO++;
+ c = read();
+ if (c == '\n') {
+ c = read();
+ }
+ } else {
+ if (c == '\n') {
+ LINENO++;
+ c = read();
+ }
+ }
+ if (c < 0)
+ return ttype = TT_EOF;
+ prevc = c;
+ }
+ return nextToken();
+ } else if (c == '/' && slashSlashCommentsP) {
+ while ((c = read()) != '\n' && c != '\r' && c >= 0);
+ peekc = c;
+ return nextToken();
+ } else {
+ /* Now see if it is still a single line comment */
+ if ((ct['/'] & CT_COMMENT) != 0) {
+ while ((c = read()) != '\n' && c != '\r' && c >= 0);
+ peekc = c;
+ return nextToken();
+ } else {
+ peekc = c;
+ return ttype = '/';
+ }
+ }
+ }
+
+ if ((ctype & CT_COMMENT) != 0) {
+ while ((c = read()) != '\n' && c != '\r' && c >= 0);
+ peekc = c;
+ return nextToken();
+ }
+
+ return ttype = c;
+ }
+
+ /**
+ * Causes the next call to the {@code nextToken} method of this
+ * tokenizer to return the current value in the {@code ttype}
+ * field, and not to modify the value in the {@code nval} or
+ * {@code sval} field.
+ *
+ * @see java.io.StreamTokenizer#nextToken()
+ * @see java.io.StreamTokenizer#nval
+ * @see java.io.StreamTokenizer#sval
+ * @see java.io.StreamTokenizer#ttype
+ */
+ public void pushBack() {
+ if (ttype != TT_NOTHING) /* No-op if nextToken() not called */
+ pushedBack = true;
+ }
+
+ /**
+ * Return the current line number.
+ *
+ * @return the current line number of this stream tokenizer.
+ */
+ public int lineno() {
+ return LINENO;
+ }
+
+ /**
+ * Returns the string representation of the current stream token and
+ * the line number it occurs on.
+ *
+ * <p>The precise string returned is unspecified, although the following
+ * example can be considered typical:
+ *
+ * <blockquote><pre>Token['a'], line 10</pre></blockquote>
+ *
+ * @return a string representation of the token
+ * @see java.io.StreamTokenizer#nval
+ * @see java.io.StreamTokenizer#sval
+ * @see java.io.StreamTokenizer#ttype
+ */
+ public String toString() {
+ String ret;
+ switch (ttype) {
+ case TT_EOF:
+ ret = "EOF";
+ break;
+ case TT_EOL:
+ ret = "EOL";
+ break;
+ case TT_WORD:
+ ret = sval;
+ break;
+ case TT_NUMBER:
+ ret = "n=" + nval;
+ break;
+ case TT_NOTHING:
+ ret = "NOTHING";
+ break;
+ default: {
+ /*
+ * ttype is the first character of either a quoted string or
+ * is an ordinary character. ttype can definitely not be less
+ * than 0, since those are reserved values used in the previous
+ * case statements
+ */
+ if (ttype < 256 &&
+ ((ctype[ttype] & CT_QUOTE) != 0)) {
+ ret = sval;
+ break;
+ }
+
+ char s[] = new char[3];
+ s[0] = s[2] = '\'';
+ s[1] = (char) ttype;
+ ret = new String(s);
+ break;
+ }
+ }
+ return "Token[" + ret + "], line " + LINENO;
+ }
+
+}
diff --git a/java/io/StringBufferInputStream.java b/java/io/StringBufferInputStream.java
new file mode 100644
index 0000000..90c5d4d
--- /dev/null
+++ b/java/io/StringBufferInputStream.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This class allows an application to create an input stream in
+ * which the bytes read are supplied by the contents of a string.
+ * Applications can also read bytes from a byte array by using a
+ * <code>ByteArrayInputStream</code>.
+ * <p>
+ * Only the low eight bits of each character in the string are used by
+ * this class.
+ *
+ * @author Arthur van Hoff
+ * @see java.io.ByteArrayInputStream
+ * @see java.io.StringReader
+ * @since JDK1.0
+ * @deprecated This class does not properly convert characters into bytes. As
+ * of JDK 1.1, the preferred way to create a stream from a
+ * string is via the <code>StringReader</code> class.
+ */
+@Deprecated
+public
+class StringBufferInputStream extends InputStream {
+ /**
+ * The string from which bytes are read.
+ */
+ protected String buffer;
+
+ /**
+ * The index of the next character to read from the input stream buffer.
+ *
+ * @see java.io.StringBufferInputStream#buffer
+ */
+ protected int pos;
+
+ /**
+ * The number of valid characters in the input stream buffer.
+ *
+ * @see java.io.StringBufferInputStream#buffer
+ */
+ protected int count;
+
+ /**
+ * Creates a string input stream to read data from the specified string.
+ *
+ * @param s the underlying input buffer.
+ */
+ public StringBufferInputStream(String s) {
+ this.buffer = s;
+ count = s.length();
+ }
+
+ /**
+ * Reads the next byte of data from this input stream. The value
+ * byte is returned as an <code>int</code> in the range
+ * <code>0</code> to <code>255</code>. If no byte is available
+ * because the end of the stream has been reached, the value
+ * <code>-1</code> is returned.
+ * <p>
+ * The <code>read</code> method of
+ * <code>StringBufferInputStream</code> cannot block. It returns the
+ * low eight bits of the next character in this input stream's buffer.
+ *
+ * @return the next byte of data, or <code>-1</code> if the end of the
+ * stream is reached.
+ */
+ public synchronized int read() {
+ return (pos < count) ? (buffer.charAt(pos++) & 0xFF) : -1;
+ }
+
+ /**
+ * Reads up to <code>len</code> bytes of data from this input stream
+ * into an array of bytes.
+ * <p>
+ * The <code>read</code> method of
+ * <code>StringBufferInputStream</code> cannot block. It copies the
+ * low eight bits from the characters in this input stream's buffer into
+ * the byte array argument.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset of the data.
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the stream has been reached.
+ */
+ public synchronized int read(byte b[], int off, int len) {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) > b.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (pos >= count) {
+ return -1;
+ }
+ // BEGIN Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+ int avail = count - pos;
+ if (len > avail) {
+ len = avail;
+ }
+ // END Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+ if (len <= 0) {
+ return 0;
+ }
+ String s = buffer;
+ int cnt = len;
+ while (--cnt >= 0) {
+ b[off++] = (byte)s.charAt(pos++);
+ }
+
+ return len;
+ }
+
+ /**
+ * Skips <code>n</code> bytes of input from this input stream. Fewer
+ * bytes might be skipped if the end of the input stream is reached.
+ *
+ * @param n the number of bytes to be skipped.
+ * @return the actual number of bytes skipped.
+ */
+ public synchronized long skip(long n) {
+ if (n < 0) {
+ return 0;
+ }
+ if (n > count - pos) {
+ n = count - pos;
+ }
+ pos += n;
+ return n;
+ }
+
+ /**
+ * Returns the number of bytes that can be read from the input
+ * stream without blocking.
+ *
+ * @return the value of <code>count - pos</code>, which is the
+ * number of bytes remaining to be read from the input buffer.
+ */
+ public synchronized int available() {
+ return count - pos;
+ }
+
+ /**
+ * Resets the input stream to begin reading from the first character
+ * of this input stream's underlying buffer.
+ */
+ public synchronized void reset() {
+ pos = 0;
+ }
+}
diff --git a/java/io/StringReader.java b/java/io/StringReader.java
new file mode 100644
index 0000000..ce9ff60
--- /dev/null
+++ b/java/io/StringReader.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * A character stream whose source is a string.
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class StringReader extends Reader {
+
+ private String str;
+ private int length;
+ private int next = 0;
+ private int mark = 0;
+
+ /**
+ * Creates a new string reader.
+ *
+ * @param s String providing the character stream.
+ */
+ public StringReader(String s) {
+ this.str = s;
+ this.length = s.length();
+ }
+
+ /** Check to make sure that the stream has not been closed */
+ private void ensureOpen() throws IOException {
+ if (str == null)
+ throw new IOException("Stream closed");
+ }
+
+ /**
+ * Reads a single character.
+ *
+ * @return The character read, or -1 if the end of the stream has been
+ * reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if (next >= length)
+ return -1;
+ return str.charAt(next++);
+ }
+ }
+
+ /**
+ * Reads characters into a portion of an array.
+ *
+ * @param cbuf Destination buffer
+ * @param off Offset at which to start writing characters
+ * @param len Maximum number of characters to read
+ *
+ * @return The number of characters read, or -1 if the end of the
+ * stream has been reached
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public int read(char cbuf[], int off, int len) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+ ((off + len) > cbuf.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+ if (next >= length)
+ return -1;
+ int n = Math.min(length - next, len);
+ str.getChars(next, next + n, cbuf, off);
+ next += n;
+ return n;
+ }
+ }
+
+ /**
+ * Skips the specified number of characters in the stream. Returns
+ * the number of characters that were skipped.
+ *
+ * <p>The <code>ns</code> parameter may be negative, even though the
+ * <code>skip</code> method of the {@link Reader} superclass throws
+ * an exception in this case. Negative values of <code>ns</code> cause the
+ * stream to skip backwards. Negative return values indicate a skip
+ * backwards. It is not possible to skip backwards past the beginning of
+ * the string.
+ *
+ * <p>If the entire string has been read or skipped, then this method has
+ * no effect and always returns 0.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public long skip(long ns) throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ if (next >= length)
+ return 0;
+ // Bound skip by beginning and end of the source
+ long n = Math.min(length - next, ns);
+ n = Math.max(-next, n);
+ next += n;
+ return n;
+ }
+ }
+
+ /**
+ * Tells whether this stream is ready to be read.
+ *
+ * @return True if the next read() is guaranteed not to block for input
+ *
+ * @exception IOException If the stream is closed
+ */
+ public boolean ready() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ return true;
+ }
+ }
+
+ /**
+ * Tells whether this stream supports the mark() operation, which it does.
+ */
+ public boolean markSupported() {
+ return true;
+ }
+
+ /**
+ * Marks the present position in the stream. Subsequent calls to reset()
+ * will reposition the stream to this point.
+ *
+ * @param readAheadLimit Limit on the number of characters that may be
+ * read while still preserving the mark. Because
+ * the stream's input comes from a string, there
+ * is no actual limit, so this argument must not
+ * be negative, but is otherwise ignored.
+ *
+ * @exception IllegalArgumentException If {@code readAheadLimit < 0}
+ * @exception IOException If an I/O error occurs
+ */
+ public void mark(int readAheadLimit) throws IOException {
+ if (readAheadLimit < 0){
+ throw new IllegalArgumentException("Read-ahead limit < 0");
+ }
+ synchronized (lock) {
+ ensureOpen();
+ mark = next;
+ }
+ }
+
+ /**
+ * Resets the stream to the most recent mark, or to the beginning of the
+ * string if it has never been marked.
+ *
+ * @exception IOException If an I/O error occurs
+ */
+ public void reset() throws IOException {
+ synchronized (lock) {
+ ensureOpen();
+ next = mark;
+ }
+ }
+
+ /**
+ * Closes the stream and releases any system resources associated with
+ * it. Once the stream has been closed, further read(),
+ * ready(), mark(), or reset() invocations will throw an IOException.
+ * Closing a previously closed stream has no effect.
+ */
+ public void close() {
+ str = null;
+ }
+}
diff --git a/java/io/StringWriter.java b/java/io/StringWriter.java
new file mode 100644
index 0000000..c4e5d40
--- /dev/null
+++ b/java/io/StringWriter.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * A character stream that collects its output in a string buffer, which can
+ * then be used to construct a string.
+ * <p>
+ * Closing a <tt>StringWriter</tt> has no effect. The methods in this class
+ * can be called after the stream has been closed without generating an
+ * <tt>IOException</tt>.
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public class StringWriter extends Writer {
+
+ private StringBuffer buf;
+
+ /**
+ * Create a new string writer using the default initial string-buffer
+ * size.
+ */
+ public StringWriter() {
+ buf = new StringBuffer();
+ lock = buf;
+ }
+
+ /**
+ * Create a new string writer using the specified initial string-buffer
+ * size.
+ *
+ * @param initialSize
+ * The number of <tt>char</tt> values that will fit into this buffer
+ * before it is automatically expanded
+ *
+ * @throws IllegalArgumentException
+ * If <tt>initialSize</tt> is negative
+ */
+ public StringWriter(int initialSize) {
+ if (initialSize < 0) {
+ throw new IllegalArgumentException("Negative buffer size");
+ }
+ buf = new StringBuffer(initialSize);
+ lock = buf;
+ }
+
+ /**
+ * Write a single character.
+ */
+ public void write(int c) {
+ buf.append((char) c);
+ }
+
+ /**
+ * Write a portion of an array of characters.
+ *
+ * @param cbuf Array of characters
+ * @param off Offset from which to start writing characters
+ * @param len Number of characters to write
+ */
+ public void write(char cbuf[], int off, int len) {
+ if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+ ((off + len) > cbuf.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+ buf.append(cbuf, off, len);
+ }
+
+ /**
+ * Write a string.
+ */
+ public void write(String str) {
+ buf.append(str);
+ }
+
+ /**
+ * Write a portion of a string.
+ *
+ * @param str String to be written
+ * @param off Offset from which to start writing characters
+ * @param len Number of characters to write
+ */
+ public void write(String str, int off, int len) {
+ buf.append(str.substring(off, off + len));
+ }
+
+ /**
+ * Appends the specified character sequence to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(csq.toString()) </pre>
+ *
+ * <p> Depending on the specification of <tt>toString</tt> for the
+ * character sequence <tt>csq</tt>, the entire sequence may not be
+ * appended. For instance, invoking the <tt>toString</tt> method of a
+ * character buffer will return a subsequence whose content depends upon
+ * the buffer's position and limit.
+ *
+ * @param csq
+ * The character sequence to append. If <tt>csq</tt> is
+ * <tt>null</tt>, then the four characters <tt>"null"</tt> are
+ * appended to this writer.
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public StringWriter append(CharSequence csq) {
+ if (csq == null)
+ write("null");
+ else
+ write(csq.toString());
+ return this;
+ }
+
+ /**
+ * Appends a subsequence of the specified character sequence to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(csq, start,
+ * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+ * exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(csq.subSequence(start, end).toString()) </pre>
+ *
+ * @param csq
+ * The character sequence from which a subsequence will be
+ * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
+ * will be appended as if <tt>csq</tt> contained the four
+ * characters <tt>"null"</tt>.
+ *
+ * @param start
+ * The index of the first character in the subsequence
+ *
+ * @param end
+ * The index of the character following the last character in the
+ * subsequence
+ *
+ * @return This writer
+ *
+ * @throws IndexOutOfBoundsException
+ * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+ * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+ * <tt>csq.length()</tt>
+ *
+ * @since 1.5
+ */
+ public StringWriter append(CharSequence csq, int start, int end) {
+ CharSequence cs = (csq == null ? "null" : csq);
+ write(cs.subSequence(start, end).toString());
+ return this;
+ }
+
+ /**
+ * Appends the specified character to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(c) </pre>
+ *
+ * @param c
+ * The 16-bit character to append
+ *
+ * @return This writer
+ *
+ * @since 1.5
+ */
+ public StringWriter append(char c) {
+ write(c);
+ return this;
+ }
+
+ /**
+ * Return the buffer's current value as a string.
+ */
+ public String toString() {
+ return buf.toString();
+ }
+
+ /**
+ * Return the string buffer itself.
+ *
+ * @return StringBuffer holding the current buffer value.
+ */
+ public StringBuffer getBuffer() {
+ return buf;
+ }
+
+ /**
+ * Flush the stream.
+ */
+ public void flush() {
+ }
+
+ /**
+ * Closing a <tt>StringWriter</tt> has no effect. The methods in this
+ * class can be called after the stream has been closed without generating
+ * an <tt>IOException</tt>.
+ */
+ public void close() throws IOException {
+ }
+
+}
diff --git a/java/io/SyncFailedException.java b/java/io/SyncFailedException.java
new file mode 100644
index 0000000..7e553a7
--- /dev/null
+++ b/java/io/SyncFailedException.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that a sync operation has failed.
+ *
+ * @author Ken Arnold
+ * @see java.io.FileDescriptor#sync
+ * @see java.io.IOException
+ * @since JDK1.1
+ */
+public class SyncFailedException extends IOException {
+ private static final long serialVersionUID = -2353342684412443330L;
+
+ /**
+ * Constructs an SyncFailedException with a detail message.
+ * A detail message is a String that describes this particular exception.
+ *
+ * @param desc a String describing the exception.
+ */
+ public SyncFailedException(String desc) {
+ super(desc);
+ }
+}
diff --git a/java/io/UTFDataFormatException.java b/java/io/UTFDataFormatException.java
new file mode 100644
index 0000000..422d28b
--- /dev/null
+++ b/java/io/UTFDataFormatException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that a malformed string in
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+ * format has been read in a data
+ * input stream or by any class that implements the data input
+ * interface.
+ * See the
+ * <a href="DataInput.html#modified-utf-8"><code>DataInput</code></a>
+ * class description for the format in
+ * which modified UTF-8 strings are read and written.
+ *
+ * @author Frank Yellin
+ * @see java.io.DataInput
+ * @see java.io.DataInputStream#readUTF(java.io.DataInput)
+ * @see java.io.IOException
+ * @since JDK1.0
+ */
+public
+class UTFDataFormatException extends IOException {
+ private static final long serialVersionUID = 420743449228280612L;
+
+ /**
+ * Constructs a <code>UTFDataFormatException</code> with
+ * <code>null</code> as its error detail message.
+ */
+ public UTFDataFormatException() {
+ super();
+ }
+
+ /**
+ * Constructs a <code>UTFDataFormatException</code> with the
+ * specified detail message. The string <code>s</code> can be
+ * retrieved later by the
+ * <code>{@link java.lang.Throwable#getMessage}</code>
+ * method of class <code>java.lang.Throwable</code>.
+ *
+ * @param s the detail message.
+ */
+ public UTFDataFormatException(String s) {
+ super(s);
+ }
+}
diff --git a/java/io/UncheckedIOException.java b/java/io/UncheckedIOException.java
new file mode 100644
index 0000000..22c43e3
--- /dev/null
+++ b/java/io/UncheckedIOException.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.io;
+
+import java.util.Objects;
+
+/**
+ * Wraps an {@link IOException} with an unchecked exception.
+ *
+ * @since 1.8
+ */
+public class UncheckedIOException extends RuntimeException {
+ private static final long serialVersionUID = -8134305061645241065L;
+
+ /**
+ * Constructs an instance of this class.
+ *
+ * @param message
+ * the detail message, can be null
+ * @param cause
+ * the {@code IOException}
+ *
+ * @throws NullPointerException
+ * if the cause is {@code null}
+ */
+ public UncheckedIOException(String message, IOException cause) {
+ super(message, Objects.requireNonNull(cause));
+ }
+
+ /**
+ * Constructs an instance of this class.
+ *
+ * @param cause
+ * the {@code IOException}
+ *
+ * @throws NullPointerException
+ * if the cause is {@code null}
+ */
+ public UncheckedIOException(IOException cause) {
+ super(Objects.requireNonNull(cause));
+ }
+
+ /**
+ * Returns the cause of this exception.
+ *
+ * @return the {@code IOException} which is the cause of this exception.
+ */
+ @Override
+ public IOException getCause() {
+ return (IOException) super.getCause();
+ }
+
+ /**
+ * Called to read the object from a stream.
+ *
+ * @throws InvalidObjectException
+ * if the object is invalid or has a cause that is not
+ * an {@code IOException}
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ Throwable cause = super.getCause();
+ if (!(cause instanceof IOException))
+ throw new InvalidObjectException("Cause must be an IOException");
+ }
+}
diff --git a/java/io/UnixFileSystem.java b/java/io/UnixFileSystem.java
new file mode 100644
index 0000000..e2aad21
--- /dev/null
+++ b/java/io/UnixFileSystem.java
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.security.AccessController;
+
+import android.system.ErrnoException;
+import android.system.OsConstants;
+
+import dalvik.system.BlockGuard;
+
+import libcore.io.Libcore;
+
+import sun.security.action.GetPropertyAction;
+
+
+class UnixFileSystem extends FileSystem {
+
+ private final char slash;
+ private final char colon;
+ private final String javaHome;
+
+ public UnixFileSystem() {
+ slash = AccessController.doPrivileged(
+ new GetPropertyAction("file.separator")).charAt(0);
+ colon = AccessController.doPrivileged(
+ new GetPropertyAction("path.separator")).charAt(0);
+ javaHome = AccessController.doPrivileged(
+ new GetPropertyAction("java.home"));
+ }
+
+
+ /* -- Normalization and construction -- */
+
+ public char getSeparator() {
+ return slash;
+ }
+
+ public char getPathSeparator() {
+ return colon;
+ }
+
+ /*
+ * A normal Unix pathname does not contain consecutive slashes and does not end
+ * with a slash. The empty string and "/" are special cases that are also
+ * considered normal.
+ */
+ public String normalize(String pathname) {
+ int n = pathname.length();
+ char[] normalized = pathname.toCharArray();
+ int index = 0;
+ char prevChar = 0;
+ for (int i = 0; i < n; i++) {
+ char current = normalized[i];
+ // Remove duplicate slashes.
+ if (!(current == '/' && prevChar == '/')) {
+ normalized[index++] = current;
+ }
+
+ prevChar = current;
+ }
+
+ // Omit the trailing slash, except when pathname == "/".
+ if (prevChar == '/' && n > 1) {
+ index--;
+ }
+
+ return (index != n) ? new String(normalized, 0, index) : pathname;
+ }
+
+ public int prefixLength(String pathname) {
+ if (pathname.length() == 0) return 0;
+ return (pathname.charAt(0) == '/') ? 1 : 0;
+ }
+
+ // Invariant: Both |parent| and |child| are normalized paths.
+ public String resolve(String parent, String child) {
+ if (child.isEmpty() || child.equals("/")) {
+ return parent;
+ }
+
+ if (child.charAt(0) == '/') {
+ if (parent.equals("/")) return child;
+ return parent + child;
+ }
+
+ if (parent.equals("/")) return parent + child;
+ return parent + '/' + child;
+ }
+
+ public String getDefaultParent() {
+ return "/";
+ }
+
+ public String fromURIPath(String path) {
+ String p = path;
+ if (p.endsWith("/") && (p.length() > 1)) {
+ // "/foo/" --> "/foo", but "/" --> "/"
+ p = p.substring(0, p.length() - 1);
+ }
+ return p;
+ }
+
+
+ /* -- Path operations -- */
+
+ public boolean isAbsolute(File f) {
+ return (f.getPrefixLength() != 0);
+ }
+
+ public String resolve(File f) {
+ if (isAbsolute(f)) return f.getPath();
+ return resolve(System.getProperty("user.dir"), f.getPath());
+ }
+
+ // Caches for canonicalization results to improve startup performance.
+ // The first cache handles repeated canonicalizations of the same path
+ // name. The prefix cache handles repeated canonicalizations within the
+ // same directory, and must not create results differing from the true
+ // canonicalization algorithm in canonicalize_md.c. For this reason the
+ // prefix cache is conservative and is not used for complex path names.
+ private ExpiringCache cache = new ExpiringCache();
+ // On Unix symlinks can jump anywhere in the file system, so we only
+ // treat prefixes in java.home as trusted and cacheable in the
+ // canonicalization algorithm
+ private ExpiringCache javaHomePrefixCache = new ExpiringCache();
+
+ public String canonicalize(String path) throws IOException {
+ if (!useCanonCaches) {
+ return canonicalize0(path);
+ } else {
+ String res = cache.get(path);
+ if (res == null) {
+ String dir = null;
+ String resDir = null;
+ if (useCanonPrefixCache) {
+ // Note that this can cause symlinks that should
+ // be resolved to a destination directory to be
+ // resolved to the directory they're contained in
+ dir = parentOrNull(path);
+ if (dir != null) {
+ resDir = javaHomePrefixCache.get(dir);
+ if (resDir != null) {
+ // Hit only in prefix cache; full path is canonical
+ String filename = path.substring(1 + dir.length());
+ res = resDir + slash + filename;
+ cache.put(dir + slash + filename, res);
+ }
+ }
+ }
+ if (res == null) {
+ // BEGIN Android-added: BlockGuard support.
+ BlockGuard.getThreadPolicy().onReadFromDisk();
+ BlockGuard.getVmPolicy().onPathAccess(path);
+ // END Android-added: BlockGuard support.
+ res = canonicalize0(path);
+ cache.put(path, res);
+ if (useCanonPrefixCache &&
+ dir != null && dir.startsWith(javaHome)) {
+ resDir = parentOrNull(res);
+ // Note that we don't allow a resolved symlink
+ // to elsewhere in java.home to pollute the
+ // prefix cache (java.home prefix cache could
+ // just as easily be a set at this point)
+ if (resDir != null && resDir.equals(dir)) {
+ File f = new File(res);
+ if (f.exists() && !f.isDirectory()) {
+ javaHomePrefixCache.put(dir, resDir);
+ }
+ }
+ }
+ }
+ }
+ return res;
+ }
+ }
+ private native String canonicalize0(String path) throws IOException;
+ // Best-effort attempt to get parent of this path; used for
+ // optimization of filename canonicalization. This must return null for
+ // any cases where the code in canonicalize_md.c would throw an
+ // exception or otherwise deal with non-simple pathnames like handling
+ // of "." and "..". It may conservatively return null in other
+ // situations as well. Returning null will cause the underlying
+ // (expensive) canonicalization routine to be called.
+ static String parentOrNull(String path) {
+ if (path == null) return null;
+ char sep = File.separatorChar;
+ int last = path.length() - 1;
+ int idx = last;
+ int adjacentDots = 0;
+ int nonDotCount = 0;
+ while (idx > 0) {
+ char c = path.charAt(idx);
+ if (c == '.') {
+ if (++adjacentDots >= 2) {
+ // Punt on pathnames containing . and ..
+ return null;
+ }
+ } else if (c == sep) {
+ if (adjacentDots == 1 && nonDotCount == 0) {
+ // Punt on pathnames containing . and ..
+ return null;
+ }
+ if (idx == 0 ||
+ idx >= last - 1 ||
+ path.charAt(idx - 1) == sep) {
+ // Punt on pathnames containing adjacent slashes
+ // toward the end
+ return null;
+ }
+ return path.substring(0, idx);
+ } else {
+ ++nonDotCount;
+ adjacentDots = 0;
+ }
+ --idx;
+ }
+ return null;
+ }
+
+ /* -- Attribute accessors -- */
+
+ private native int getBooleanAttributes0(String abspath);
+
+ public int getBooleanAttributes(File f) {
+ // BEGIN Android-added: BlockGuard support.
+ BlockGuard.getThreadPolicy().onReadFromDisk();
+ BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+ // END Android-added: BlockGuard support.
+
+ int rv = getBooleanAttributes0(f.getPath());
+ String name = f.getName();
+ boolean hidden = (name.length() > 0) && (name.charAt(0) == '.');
+ return rv | (hidden ? BA_HIDDEN : 0);
+ }
+
+ // Android-changed: Access files through common interface.
+ public boolean checkAccess(File f, int access) {
+ final int mode;
+ switch (access) {
+ case FileSystem.ACCESS_OK:
+ mode = OsConstants.F_OK;
+ break;
+ case FileSystem.ACCESS_READ:
+ mode = OsConstants.R_OK;
+ break;
+ case FileSystem.ACCESS_WRITE:
+ mode = OsConstants.W_OK;
+ break;
+ case FileSystem.ACCESS_EXECUTE:
+ mode = OsConstants.X_OK;
+ break;
+ default:
+ throw new IllegalArgumentException("Bad access mode: " + access);
+ }
+
+ try {
+ return Libcore.os.access(f.getPath(), mode);
+ } catch (ErrnoException e) {
+ return false;
+ }
+ }
+
+ // Android-changed: Add method to intercept native method call; BlockGuard support.
+ public long getLastModifiedTime(File f) {
+ BlockGuard.getThreadPolicy().onReadFromDisk();
+ BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+ return getLastModifiedTime0(f);
+ }
+ private native long getLastModifiedTime0(File f);
+
+ // Android-changed: Access files through common interface.
+ public long getLength(File f) {
+ try {
+ return Libcore.os.stat(f.getPath()).st_size;
+ } catch (ErrnoException e) {
+ return 0;
+ }
+ }
+
+ // Android-changed: Add method to intercept native method call; BlockGuard support.
+ public boolean setPermission(File f, int access, boolean enable, boolean owneronly) {
+ BlockGuard.getThreadPolicy().onWriteToDisk();
+ BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+ return setPermission0(f, access, enable, owneronly);
+ }
+ private native boolean setPermission0(File f, int access, boolean enable, boolean owneronly);
+
+ /* -- File operations -- */
+ // Android-changed: Add method to intercept native method call; BlockGuard support.
+ public boolean createFileExclusively(String path) throws IOException {
+ BlockGuard.getThreadPolicy().onWriteToDisk();
+ BlockGuard.getVmPolicy().onPathAccess(path);
+ return createFileExclusively0(path);
+ }
+ private native boolean createFileExclusively0(String path) throws IOException;
+
+ public boolean delete(File f) {
+ // Keep canonicalization caches in sync after file deletion
+ // and renaming operations. Could be more clever than this
+ // (i.e., only remove/update affected entries) but probably
+ // not worth it since these entries expire after 30 seconds
+ // anyway.
+ cache.clear();
+ javaHomePrefixCache.clear();
+ // BEGIN Android-changed: Access files through common interface.
+ try {
+ Libcore.os.remove(f.getPath());
+ return true;
+ } catch (ErrnoException e) {
+ return false;
+ }
+ // END Android-changed: Access files through common interface.
+ }
+
+ // Android-removed: Access files through common interface.
+ // private native boolean delete0(File f);
+
+ // Android-changed: Add method to intercept native method call; BlockGuard support.
+ public String[] list(File f) {
+ BlockGuard.getThreadPolicy().onReadFromDisk();
+ BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+ return list0(f);
+ }
+ private native String[] list0(File f);
+
+ // Android-changed: Add method to intercept native method call; BlockGuard support.
+ public boolean createDirectory(File f) {
+ BlockGuard.getThreadPolicy().onWriteToDisk();
+ BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+ return createDirectory0(f);
+ }
+ private native boolean createDirectory0(File f);
+
+ public boolean rename(File f1, File f2) {
+ // Keep canonicalization caches in sync after file deletion
+ // and renaming operations. Could be more clever than this
+ // (i.e., only remove/update affected entries) but probably
+ // not worth it since these entries expire after 30 seconds
+ // anyway.
+ cache.clear();
+ javaHomePrefixCache.clear();
+ // BEGIN Android-changed: Access files through common interface.
+ try {
+ Libcore.os.rename(f1.getPath(), f2.getPath());
+ return true;
+ } catch (ErrnoException e) {
+ return false;
+ }
+ // END Android-changed: Access files through common interface.
+ }
+
+ // Android-removed: Access files through common interface.
+ // private native boolean rename0(File f1, File f2);
+
+ // Android-changed: Add method to intercept native method call; BlockGuard support.
+ public boolean setLastModifiedTime(File f, long time) {
+ BlockGuard.getThreadPolicy().onWriteToDisk();
+ BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+ return setLastModifiedTime0(f, time);
+ }
+ private native boolean setLastModifiedTime0(File f, long time);
+
+ // Android-changed: Add method to intercept native method call; BlockGuard support.
+ public boolean setReadOnly(File f) {
+ BlockGuard.getThreadPolicy().onWriteToDisk();
+ BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+ return setReadOnly0(f);
+ }
+ private native boolean setReadOnly0(File f);
+
+
+ /* -- Filesystem interface -- */
+
+ public File[] listRoots() {
+ try {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead("/");
+ }
+ return new File[] { new File("/") };
+ } catch (SecurityException x) {
+ return new File[0];
+ }
+ }
+
+ /* -- Disk usage -- */
+ // Android-changed: Add method to intercept native method call; BlockGuard support.
+ public long getSpace(File f, int t) {
+ BlockGuard.getThreadPolicy().onReadFromDisk();
+ BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+
+ return getSpace0(f, t);
+ }
+ private native long getSpace0(File f, int t);
+
+ /* -- Basic infrastructure -- */
+
+ public int compare(File f1, File f2) {
+ return f1.getPath().compareTo(f2.getPath());
+ }
+
+ public int hashCode(File f) {
+ return f.getPath().hashCode() ^ 1234321;
+ }
+
+
+ private static native void initIDs();
+
+ static {
+ initIDs();
+ }
+
+}
diff --git a/java/io/UnsupportedEncodingException.java b/java/io/UnsupportedEncodingException.java
new file mode 100644
index 0000000..b59f9c3
--- /dev/null
+++ b/java/io/UnsupportedEncodingException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.io;
+
+/**
+ * The Character Encoding is not supported.
+ *
+ * @author Asmus Freytag
+ * @since JDK1.1
+ */
+public class UnsupportedEncodingException
+ extends IOException
+{
+ private static final long serialVersionUID = -4274276298326136670L;
+
+ /**
+ * Constructs an UnsupportedEncodingException without a detail message.
+ */
+ public UnsupportedEncodingException() {
+ super();
+ }
+
+ /**
+ * Constructs an UnsupportedEncodingException with a detail message.
+ * @param s Describes the reason for the exception.
+ */
+ public UnsupportedEncodingException(String s) {
+ super(s);
+ }
+}
diff --git a/java/io/WriteAbortedException.java b/java/io/WriteAbortedException.java
new file mode 100644
index 0000000..c39950d
--- /dev/null
+++ b/java/io/WriteAbortedException.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that one of the ObjectStreamExceptions was thrown during a
+ * write operation. Thrown during a read operation when one of the
+ * ObjectStreamExceptions was thrown during a write operation. The
+ * exception that terminated the write can be found in the detail
+ * field. The stream is reset to it's initial state and all references
+ * to objects already deserialized are discarded.
+ *
+ * <p>As of release 1.4, this exception has been retrofitted to conform to
+ * the general purpose exception-chaining mechanism. The "exception causing
+ * the abort" that is provided at construction time and
+ * accessed via the public {@link #detail} field is now known as the
+ * <i>cause</i>, and may be accessed via the {@link Throwable#getCause()}
+ * method, as well as the aforementioned "legacy field."
+ *
+ * @author unascribed
+ * @since JDK1.1
+ */
+public class WriteAbortedException extends ObjectStreamException {
+ private static final long serialVersionUID = -3326426625597282442L;
+
+ /**
+ * Exception that was caught while writing the ObjectStream.
+ *
+ * <p>This field predates the general-purpose exception chaining facility.
+ * The {@link Throwable#getCause()} method is now the preferred means of
+ * obtaining this information.
+ *
+ * @serial
+ */
+ public Exception detail;
+
+ /**
+ * Constructs a WriteAbortedException with a string describing
+ * the exception and the exception causing the abort.
+ * @param s String describing the exception.
+ * @param ex Exception causing the abort.
+ */
+ public WriteAbortedException(String s, Exception ex) {
+ super(s);
+ initCause(null); // Disallow subsequent initCause
+ detail = ex;
+ }
+
+ /**
+ * Produce the message and include the message from the nested
+ * exception, if there is one.
+ */
+ public String getMessage() {
+ if (detail == null)
+ return super.getMessage();
+ else
+ return super.getMessage() + "; " + detail.toString();
+ }
+
+ /**
+ * Returns the exception that terminated the operation (the <i>cause</i>).
+ *
+ * @return the exception that terminated the operation (the <i>cause</i>),
+ * which may be null.
+ * @since 1.4
+ */
+ public Throwable getCause() {
+ return detail;
+ }
+}
diff --git a/java/io/Writer.java b/java/io/Writer.java
new file mode 100644
index 0000000..8747a13
--- /dev/null
+++ b/java/io/Writer.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Abstract class for writing to character streams. The only methods that a
+ * subclass must implement are write(char[], int, int), flush(), and close().
+ * Most subclasses, however, will override some of the methods defined here in
+ * order to provide higher efficiency, additional functionality, or both.
+ *
+ * @see Writer
+ * @see BufferedWriter
+ * @see CharArrayWriter
+ * @see FilterWriter
+ * @see OutputStreamWriter
+ * @see FileWriter
+ * @see PipedWriter
+ * @see PrintWriter
+ * @see StringWriter
+ * @see Reader
+ *
+ * @author Mark Reinhold
+ * @since JDK1.1
+ */
+
+public abstract class Writer implements Appendable, Closeable, Flushable {
+
+ /**
+ * Temporary buffer used to hold writes of strings and single characters
+ */
+ private char[] writeBuffer;
+
+ /**
+ * Size of writeBuffer, must be >= 1
+ */
+ private static final int WRITE_BUFFER_SIZE = 1024;
+
+ /**
+ * The object used to synchronize operations on this stream. For
+ * efficiency, a character-stream object may use an object other than
+ * itself to protect critical sections. A subclass should therefore use
+ * the object in this field rather than <tt>this</tt> or a synchronized
+ * method.
+ */
+ protected Object lock;
+
+ /**
+ * Creates a new character-stream writer whose critical sections will
+ * synchronize on the writer itself.
+ */
+ protected Writer() {
+ this.lock = this;
+ }
+
+ /**
+ * Creates a new character-stream writer whose critical sections will
+ * synchronize on the given object.
+ *
+ * @param lock
+ * Object to synchronize on
+ */
+ protected Writer(Object lock) {
+ if (lock == null) {
+ throw new NullPointerException();
+ }
+ this.lock = lock;
+ }
+
+ /**
+ * Writes a single character. The character to be written is contained in
+ * the 16 low-order bits of the given integer value; the 16 high-order bits
+ * are ignored.
+ *
+ * <p> Subclasses that intend to support efficient single-character output
+ * should override this method.
+ *
+ * @param c
+ * int specifying a character to be written
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public void write(int c) throws IOException {
+ synchronized (lock) {
+ if (writeBuffer == null){
+ writeBuffer = new char[WRITE_BUFFER_SIZE];
+ }
+ writeBuffer[0] = (char) c;
+ write(writeBuffer, 0, 1);
+ }
+ }
+
+ /**
+ * Writes an array of characters.
+ *
+ * @param cbuf
+ * Array of characters to be written
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public void write(char cbuf[]) throws IOException {
+ write(cbuf, 0, cbuf.length);
+ }
+
+ /**
+ * Writes a portion of an array of characters.
+ *
+ * @param cbuf
+ * Array of characters
+ *
+ * @param off
+ * Offset from which to start writing characters
+ *
+ * @param len
+ * Number of characters to write
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ abstract public void write(char cbuf[], int off, int len) throws IOException;
+
+ /**
+ * Writes a string.
+ *
+ * @param str
+ * String to be written
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public void write(String str) throws IOException {
+ write(str, 0, str.length());
+ }
+
+ /**
+ * Writes a portion of a string.
+ *
+ * @param str
+ * A String
+ *
+ * @param off
+ * Offset from which to start writing characters
+ *
+ * @param len
+ * Number of characters to write
+ *
+ * @throws IndexOutOfBoundsException
+ * If <tt>off</tt> is negative, or <tt>len</tt> is negative,
+ * or <tt>off+len</tt> is negative or greater than the length
+ * of the given string
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public void write(String str, int off, int len) throws IOException {
+ synchronized (lock) {
+ char cbuf[];
+ if (len <= WRITE_BUFFER_SIZE) {
+ if (writeBuffer == null) {
+ writeBuffer = new char[WRITE_BUFFER_SIZE];
+ }
+ cbuf = writeBuffer;
+ } else { // Don't permanently allocate very large buffers.
+ cbuf = new char[len];
+ }
+ str.getChars(off, (off + len), cbuf, 0);
+ write(cbuf, 0, len);
+ }
+ }
+
+ /**
+ * Appends the specified character sequence to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(csq.toString()) </pre>
+ *
+ * <p> Depending on the specification of <tt>toString</tt> for the
+ * character sequence <tt>csq</tt>, the entire sequence may not be
+ * appended. For instance, invoking the <tt>toString</tt> method of a
+ * character buffer will return a subsequence whose content depends upon
+ * the buffer's position and limit.
+ *
+ * @param csq
+ * The character sequence to append. If <tt>csq</tt> is
+ * <tt>null</tt>, then the four characters <tt>"null"</tt> are
+ * appended to this writer.
+ *
+ * @return This writer
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @since 1.5
+ */
+ public Writer append(CharSequence csq) throws IOException {
+ if (csq == null)
+ write("null");
+ else
+ write(csq.toString());
+ return this;
+ }
+
+ /**
+ * Appends a subsequence of the specified character sequence to this writer.
+ * <tt>Appendable</tt>.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(csq, start,
+ * end)</tt> when <tt>csq</tt> is not <tt>null</tt> behaves in exactly the
+ * same way as the invocation
+ *
+ * <pre>
+ * out.write(csq.subSequence(start, end).toString()) </pre>
+ *
+ * @param csq
+ * The character sequence from which a subsequence will be
+ * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
+ * will be appended as if <tt>csq</tt> contained the four
+ * characters <tt>"null"</tt>.
+ *
+ * @param start
+ * The index of the first character in the subsequence
+ *
+ * @param end
+ * The index of the character following the last character in the
+ * subsequence
+ *
+ * @return This writer
+ *
+ * @throws IndexOutOfBoundsException
+ * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+ * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+ * <tt>csq.length()</tt>
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @since 1.5
+ */
+ public Writer append(CharSequence csq, int start, int end) throws IOException {
+ CharSequence cs = (csq == null ? "null" : csq);
+ write(cs.subSequence(start, end).toString());
+ return this;
+ }
+
+ /**
+ * Appends the specified character to this writer.
+ *
+ * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+ * behaves in exactly the same way as the invocation
+ *
+ * <pre>
+ * out.write(c) </pre>
+ *
+ * @param c
+ * The 16-bit character to append
+ *
+ * @return This writer
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @since 1.5
+ */
+ public Writer append(char c) throws IOException {
+ write(c);
+ return this;
+ }
+
+ /**
+ * Flushes the stream. If the stream has saved any characters from the
+ * various write() methods in a buffer, write them immediately to their
+ * intended destination. Then, if that destination is another character or
+ * byte stream, flush it. Thus one flush() invocation will flush all the
+ * buffers in a chain of Writers and OutputStreams.
+ *
+ * <p> If the intended destination of this stream is an abstraction provided
+ * by the underlying operating system, for example a file, then flushing the
+ * stream guarantees only that bytes previously written to the stream are
+ * passed to the operating system for writing; it does not guarantee that
+ * they are actually written to a physical device such as a disk drive.
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ abstract public void flush() throws IOException;
+
+ /**
+ * Closes the stream, flushing it first. Once the stream has been closed,
+ * further write() or flush() invocations will cause an IOException to be
+ * thrown. Closing a previously closed stream has no effect.
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ abstract public void close() throws IOException;
+
+}