Showing the changes to java/pkg/java/io (208 of 18352 files). Show all
Unified · Split
Binary file not shown.
| @@ -0,0 +1,123 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Utility methods for packing/unpacking primitive values in/out of byte arrays | |
| 30 | + * using big-endian byte ordering. | |
| 31 | + */ | |
| 32 | +class Bits { | |
| 33 | + | |
| 34 | + /* | |
| 35 | + * Methods for unpacking primitive values from byte arrays starting at | |
| 36 | + * given offsets. | |
| 37 | + */ | |
| 38 | + | |
| 39 | + static boolean getBoolean(byte[] b, int off) { | |
| 40 | + return b[off] != 0; | |
| 41 | + } | |
| 42 | + | |
| 43 | + static char getChar(byte[] b, int off) { | |
| 44 | + return (char) ((b[off + 1] & 0xFF) + | |
| 45 | + (b[off] << 8)); | |
| 46 | + } | |
| 47 | + | |
| 48 | + static short getShort(byte[] b, int off) { | |
| 49 | + return (short) ((b[off + 1] & 0xFF) + | |
| 50 | + (b[off] << 8)); | |
| 51 | + } | |
| 52 | + | |
| 53 | + static int getInt(byte[] b, int off) { | |
| 54 | + return ((b[off + 3] & 0xFF) ) + | |
| 55 | + ((b[off + 2] & 0xFF) << 8) + | |
| 56 | + ((b[off + 1] & 0xFF) << 16) + | |
| 57 | + ((b[off ] ) << 24); | |
| 58 | + } | |
| 59 | + | |
| 60 | + static float getFloat(byte[] b, int off) { | |
| 61 | + return Float.intBitsToFloat(getInt(b, off)); | |
| 62 | + } | |
| 63 | + | |
| 64 | + static long getLong(byte[] b, int off) { | |
| 65 | + return ((b[off + 7] & 0xFFL) ) + | |
| 66 | + ((b[off + 6] & 0xFFL) << 8) + | |
| 67 | + ((b[off + 5] & 0xFFL) << 16) + | |
| 68 | + ((b[off + 4] & 0xFFL) << 24) + | |
| 69 | + ((b[off + 3] & 0xFFL) << 32) + | |
| 70 | + ((b[off + 2] & 0xFFL) << 40) + | |
| 71 | + ((b[off + 1] & 0xFFL) << 48) + | |
| 72 | + (((long) b[off]) << 56); | |
| 73 | + } | |
| 74 | + | |
| 75 | + static double getDouble(byte[] b, int off) { | |
| 76 | + return Double.longBitsToDouble(getLong(b, off)); | |
| 77 | + } | |
| 78 | + | |
| 79 | + /* | |
| 80 | + * Methods for packing primitive values into byte arrays starting at given | |
| 81 | + * offsets. | |
| 82 | + */ | |
| 83 | + | |
| 84 | + static void putBoolean(byte[] b, int off, boolean val) { | |
| 85 | + b[off] = (byte) (val ? 1 : 0); | |
| 86 | + } | |
| 87 | + | |
| 88 | + static void putChar(byte[] b, int off, char val) { | |
| 89 | + b[off + 1] = (byte) (val ); | |
| 90 | + b[off ] = (byte) (val >>> 8); | |
| 91 | + } | |
| 92 | + | |
| 93 | + static void putShort(byte[] b, int off, short val) { | |
| 94 | + b[off + 1] = (byte) (val ); | |
| 95 | + b[off ] = (byte) (val >>> 8); | |
| 96 | + } | |
| 97 | + | |
| 98 | + static void putInt(byte[] b, int off, int val) { | |
| 99 | + b[off + 3] = (byte) (val ); | |
| 100 | + b[off + 2] = (byte) (val >>> 8); | |
| 101 | + b[off + 1] = (byte) (val >>> 16); | |
| 102 | + b[off ] = (byte) (val >>> 24); | |
| 103 | + } | |
| 104 | + | |
| 105 | + static void putFloat(byte[] b, int off, float val) { | |
| 106 | + putInt(b, off, Float.floatToIntBits(val)); | |
| 107 | + } | |
| 108 | + | |
| 109 | + static void putLong(byte[] b, int off, long val) { | |
| 110 | + b[off + 7] = (byte) (val ); | |
| 111 | + b[off + 6] = (byte) (val >>> 8); | |
| 112 | + b[off + 5] = (byte) (val >>> 16); | |
| 113 | + b[off + 4] = (byte) (val >>> 24); | |
| 114 | + b[off + 3] = (byte) (val >>> 32); | |
| 115 | + b[off + 2] = (byte) (val >>> 40); | |
| 116 | + b[off + 1] = (byte) (val >>> 48); | |
| 117 | + b[off ] = (byte) (val >>> 56); | |
| 118 | + } | |
| 119 | + | |
| 120 | + static void putDouble(byte[] b, int off, double val) { | |
| 121 | + putLong(b, off, Double.doubleToLongBits(val)); | |
| 122 | + } | |
| 123 | +} | |
Binary file not shown.
| @@ -0,0 +1,478 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * A <code>BufferedInputStream</code> adds | |
| 31 | + * functionality to another input stream-namely, | |
| 32 | + * the ability to buffer the input and to | |
| 33 | + * support the <code>mark</code> and <code>reset</code> | |
| 34 | + * methods. When the <code>BufferedInputStream</code> | |
| 35 | + * is created, an internal buffer array is | |
| 36 | + * created. As bytes from the stream are read | |
| 37 | + * or skipped, the internal buffer is refilled | |
| 38 | + * as necessary from the contained input stream, | |
| 39 | + * many bytes at a time. The <code>mark</code> | |
| 40 | + * operation remembers a point in the input | |
| 41 | + * stream and the <code>reset</code> operation | |
| 42 | + * causes all the bytes read since the most | |
| 43 | + * recent <code>mark</code> operation to be | |
| 44 | + * reread before new bytes are taken from | |
| 45 | + * the contained input stream. | |
| 46 | + * | |
| 47 | + * @author Arthur van Hoff | |
| 48 | + * @since JDK1.0 | |
| 49 | + */ | |
| 50 | +public | |
| 51 | +class BufferedInputStream extends FilterInputStream { | |
| 52 | + | |
| 53 | + private static int defaultBufferSize = 8192; | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * The internal buffer array where the data is stored. When necessary, | |
| 57 | + * it may be replaced by another array of | |
| 58 | + * a different size. | |
| 59 | + */ | |
| 60 | + protected volatile byte buf[]; | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Atomic updater to provide compareAndSet for buf. This is | |
| 64 | + * necessary because closes can be asynchronous. We use nullness | |
| 65 | + * of buf[] as primary indicator that this stream is closed. (The | |
| 66 | + * "in" field is also nulled out on close.) | |
| 67 | + */ | |
| 68 | + private static final | |
| 69 | + AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater = | |
| 70 | + AtomicReferenceFieldUpdater.newUpdater | |
| 71 | + (BufferedInputStream.class, byte[].class, "buf"); | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * The index one greater than the index of the last valid byte in | |
| 75 | + * the buffer. | |
| 76 | + * This value is always | |
| 77 | + * in the range <code>0</code> through <code>buf.length</code>; | |
| 78 | + * elements <code>buf[0]</code> through <code>buf[count-1] | |
| 79 | + * </code>contain buffered input data obtained | |
| 80 | + * from the underlying input stream. | |
| 81 | + */ | |
| 82 | + protected int count; | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * The current position in the buffer. This is the index of the next | |
| 86 | + * character to be read from the <code>buf</code> array. | |
| 87 | + * <p> | |
| 88 | + * This value is always in the range <code>0</code> | |
| 89 | + * through <code>count</code>. If it is less | |
| 90 | + * than <code>count</code>, then <code>buf[pos]</code> | |
| 91 | + * is the next byte to be supplied as input; | |
| 92 | + * if it is equal to <code>count</code>, then | |
| 93 | + * the next <code>read</code> or <code>skip</code> | |
| 94 | + * operation will require more bytes to be | |
| 95 | + * read from the contained input stream. | |
| 96 | + * | |
| 97 | + * @see java.io.BufferedInputStream#buf | |
| 98 | + */ | |
| 99 | + protected int pos; | |
| 100 | + | |
| 101 | + /** | |
| 102 | + * The value of the <code>pos</code> field at the time the last | |
| 103 | + * <code>mark</code> method was called. | |
| 104 | + * <p> | |
| 105 | + * This value is always | |
| 106 | + * in the range <code>-1</code> through <code>pos</code>. | |
| 107 | + * If there is no marked position in the input | |
| 108 | + * stream, this field is <code>-1</code>. If | |
| 109 | + * there is a marked position in the input | |
| 110 | + * stream, then <code>buf[markpos]</code> | |
| 111 | + * is the first byte to be supplied as input | |
| 112 | + * after a <code>reset</code> operation. If | |
| 113 | + * <code>markpos</code> is not <code>-1</code>, | |
| 114 | + * then all bytes from positions <code>buf[markpos]</code> | |
| 115 | + * through <code>buf[pos-1]</code> must remain | |
| 116 | + * in the buffer array (though they may be | |
| 117 | + * moved to another place in the buffer array, | |
| 118 | + * with suitable adjustments to the values | |
| 119 | + * of <code>count</code>, <code>pos</code>, | |
| 120 | + * and <code>markpos</code>); they may not | |
| 121 | + * be discarded unless and until the difference | |
| 122 | + * between <code>pos</code> and <code>markpos</code> | |
| 123 | + * exceeds <code>marklimit</code>. | |
| 124 | + * | |
| 125 | + * @see java.io.BufferedInputStream#mark(int) | |
| 126 | + * @see java.io.BufferedInputStream#pos | |
| 127 | + */ | |
| 128 | + protected int markpos = -1; | |
| 129 | + | |
| 130 | + /** | |
| 131 | + * The maximum read ahead allowed after a call to the | |
| 132 | + * <code>mark</code> method before subsequent calls to the | |
| 133 | + * <code>reset</code> method fail. | |
| 134 | + * Whenever the difference between <code>pos</code> | |
| 135 | + * and <code>markpos</code> exceeds <code>marklimit</code>, | |
| 136 | + * then the mark may be dropped by setting | |
| 137 | + * <code>markpos</code> to <code>-1</code>. | |
| 138 | + * | |
| 139 | + * @see java.io.BufferedInputStream#mark(int) | |
| 140 | + * @see java.io.BufferedInputStream#reset() | |
| 141 | + */ | |
| 142 | + protected int marklimit; | |
| 143 | + | |
| 144 | + /** | |
| 145 | + * Check to make sure that underlying input stream has not been | |
| 146 | + * nulled out due to close; if not return it; | |
| 147 | + */ | |
| 148 | + private InputStream getInIfOpen() throws IOException { | |
| 149 | + InputStream input = in; | |
| 150 | + if (input == null) | |
| 151 | + throw new IOException("Stream closed"); | |
| 152 | + return input; | |
| 153 | + } | |
| 154 | + | |
| 155 | + /** | |
| 156 | + * Check to make sure that buffer has not been nulled out due to | |
| 157 | + * close; if not return it; | |
| 158 | + */ | |
| 159 | + private byte[] getBufIfOpen() throws IOException { | |
| 160 | + byte[] buffer = buf; | |
| 161 | + if (buffer == null) | |
| 162 | + throw new IOException("Stream closed"); | |
| 163 | + return buffer; | |
| 164 | + } | |
| 165 | + | |
| 166 | + /** | |
| 167 | + * Creates a <code>BufferedInputStream</code> | |
| 168 | + * and saves its argument, the input stream | |
| 169 | + * <code>in</code>, for later use. An internal | |
| 170 | + * buffer array is created and stored in <code>buf</code>. | |
| 171 | + * | |
| 172 | + * @param in the underlying input stream. | |
| 173 | + */ | |
| 174 | + public BufferedInputStream(InputStream in) { | |
| 175 | + this(in, defaultBufferSize); | |
| 176 | + } | |
| 177 | + | |
| 178 | + /** | |
| 179 | + * Creates a <code>BufferedInputStream</code> | |
| 180 | + * with the specified buffer size, | |
| 181 | + * and saves its argument, the input stream | |
| 182 | + * <code>in</code>, for later use. An internal | |
| 183 | + * buffer array of length <code>size</code> | |
| 184 | + * is created and stored in <code>buf</code>. | |
| 185 | + * | |
| 186 | + * @param in the underlying input stream. | |
| 187 | + * @param size the buffer size. | |
| 188 | + * @exception IllegalArgumentException if size <= 0. | |
| 189 | + */ | |
| 190 | + public BufferedInputStream(InputStream in, int size) { | |
| 191 | + super(in); | |
| 192 | + if (size <= 0) { | |
| 193 | + throw new IllegalArgumentException("Buffer size <= 0"); | |
| 194 | + } | |
| 195 | + buf = new byte[size]; | |
| 196 | + } | |
| 197 | + | |
| 198 | + /** | |
| 199 | + * Fills the buffer with more data, taking into account | |
| 200 | + * shuffling and other tricks for dealing with marks. | |
| 201 | + * Assumes that it is being called by a synchronized method. | |
| 202 | + * This method also assumes that all data has already been read in, | |
| 203 | + * hence pos > count. | |
| 204 | + */ | |
| 205 | + private void fill() throws IOException { | |
| 206 | + byte[] buffer = getBufIfOpen(); | |
| 207 | + if (markpos < 0) | |
| 208 | + pos = 0; /* no mark: throw away the buffer */ | |
| 209 | + else if (pos >= buffer.length) /* no room left in buffer */ | |
| 210 | + if (markpos > 0) { /* can throw away early part of the buffer */ | |
| 211 | + int sz = pos - markpos; | |
| 212 | + System.arraycopy(buffer, markpos, buffer, 0, sz); | |
| 213 | + pos = sz; | |
| 214 | + markpos = 0; | |
| 215 | + } else if (buffer.length >= marklimit) { | |
| 216 | + markpos = -1; /* buffer got too big, invalidate mark */ | |
| 217 | + pos = 0; /* drop buffer contents */ | |
| 218 | + } else { /* grow buffer */ | |
| 219 | + int nsz = pos * 2; | |
| 220 | + if (nsz > marklimit) | |
| 221 | + nsz = marklimit; | |
| 222 | + byte nbuf[] = new byte[nsz]; | |
| 223 | + System.arraycopy(buffer, 0, nbuf, 0, pos); | |
| 224 | + if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { | |
| 225 | + // Can't replace buf if there was an async close. | |
| 226 | + // Note: This would need to be changed if fill() | |
| 227 | + // is ever made accessible to multiple threads. | |
| 228 | + // But for now, the only way CAS can fail is via close. | |
| 229 | + // assert buf == null; | |
| 230 | + throw new IOException("Stream closed"); | |
| 231 | + } | |
| 232 | + buffer = nbuf; | |
| 233 | + } | |
| 234 | + count = pos; | |
| 235 | + int n = getInIfOpen().read(buffer, pos, buffer.length - pos); | |
| 236 | + if (n > 0) | |
| 237 | + count = n + pos; | |
| 238 | + } | |
| 239 | + | |
| 240 | + /** | |
| 241 | + * See | |
| 242 | + * the general contract of the <code>read</code> | |
| 243 | + * method of <code>InputStream</code>. | |
| 244 | + * | |
| 245 | + * @return the next byte of data, or <code>-1</code> if the end of the | |
| 246 | + * stream is reached. | |
| 247 | + * @exception IOException if this input stream has been closed by | |
| 248 | + * invoking its {@link #close()} method, | |
| 249 | + * or an I/O error occurs. | |
| 250 | + * @see java.io.FilterInputStream#in | |
| 251 | + */ | |
| 252 | + public synchronized int read() throws IOException { | |
| 253 | + if (pos >= count) { | |
| 254 | + fill(); | |
| 255 | + if (pos >= count) | |
| 256 | + return -1; | |
| 257 | + } | |
| 258 | + return getBufIfOpen()[pos++] & 0xff; | |
| 259 | + } | |
| 260 | + | |
| 261 | + /** | |
| 262 | + * Read characters into a portion of an array, reading from the underlying | |
| 263 | + * stream at most once if necessary. | |
| 264 | + */ | |
| 265 | + private int read1(byte[] b, int off, int len) throws IOException { | |
| 266 | + int avail = count - pos; | |
| 267 | + if (avail <= 0) { | |
| 268 | + /* If the requested length is at least as large as the buffer, and | |
| 269 | + if there is no mark/reset activity, do not bother to copy the | |
| 270 | + bytes into the local buffer. In this way buffered streams will | |
| 271 | + cascade harmlessly. */ | |
| 272 | + if (len >= getBufIfOpen().length && markpos < 0) { | |
| 273 | + return getInIfOpen().read(b, off, len); | |
| 274 | + } | |
| 275 | + fill(); | |
| 276 | + avail = count - pos; | |
| 277 | + if (avail <= 0) return -1; | |
| 278 | + } | |
| 279 | + int cnt = (avail < len) ? avail : len; | |
| 280 | + System.arraycopy(getBufIfOpen(), pos, b, off, cnt); | |
| 281 | + pos += cnt; | |
| 282 | + return cnt; | |
| 283 | + } | |
| 284 | + | |
| 285 | + /** | |
| 286 | + * Reads bytes from this byte-input stream into the specified byte array, | |
| 287 | + * starting at the given offset. | |
| 288 | + * | |
| 289 | + * <p> This method implements the general contract of the corresponding | |
| 290 | + * <code>{@link InputStream#read(byte[], int, int) read}</code> method of | |
| 291 | + * the <code>{@link InputStream}</code> class. As an additional | |
| 292 | + * convenience, it attempts to read as many bytes as possible by repeatedly | |
| 293 | + * invoking the <code>read</code> method of the underlying stream. This | |
| 294 | + * iterated <code>read</code> continues until one of the following | |
| 295 | + * conditions becomes true: <ul> | |
| 296 | + * | |
| 297 | + * <li> The specified number of bytes have been read, | |
| 298 | + * | |
| 299 | + * <li> The <code>read</code> method of the underlying stream returns | |
| 300 | + * <code>-1</code>, indicating end-of-file, or | |
| 301 | + * | |
| 302 | + * <li> The <code>available</code> method of the underlying stream | |
| 303 | + * returns zero, indicating that further input requests would block. | |
| 304 | + * | |
| 305 | + * </ul> If the first <code>read</code> on the underlying stream returns | |
| 306 | + * <code>-1</code> to indicate end-of-file then this method returns | |
| 307 | + * <code>-1</code>. Otherwise this method returns the number of bytes | |
| 308 | + * actually read. | |
| 309 | + * | |
| 310 | + * <p> Subclasses of this class are encouraged, but not required, to | |
| 311 | + * attempt to read as many bytes as possible in the same fashion. | |
| 312 | + * | |
| 313 | + * @param b destination buffer. | |
| 314 | + * @param off offset at which to start storing bytes. | |
| 315 | + * @param len maximum number of bytes to read. | |
| 316 | + * @return the number of bytes read, or <code>-1</code> if the end of | |
| 317 | + * the stream has been reached. | |
| 318 | + * @exception IOException if this input stream has been closed by | |
| 319 | + * invoking its {@link #close()} method, | |
| 320 | + * or an I/O error occurs. | |
| 321 | + */ | |
| 322 | + public synchronized int read(byte b[], int off, int len) | |
| 323 | + throws IOException | |
| 324 | + { | |
| 325 | + getBufIfOpen(); // Check for closed stream | |
| 326 | + if ((off | len | (off + len) | (b.length - (off + len))) < 0) { | |
| 327 | + throw new IndexOutOfBoundsException(); | |
| 328 | + } else if (len == 0) { | |
| 329 | + return 0; | |
| 330 | + } | |
| 331 | + | |
| 332 | + int n = 0; | |
| 333 | + for (;;) { | |
| 334 | + int nread = read1(b, off + n, len - n); | |
| 335 | + if (nread <= 0) | |
| 336 | + return (n == 0) ? nread : n; | |
| 337 | + n += nread; | |
| 338 | + if (n >= len) | |
| 339 | + return n; | |
| 340 | + // if not closed but no bytes available, return | |
| 341 | + InputStream input = in; | |
| 342 | + if (input != null && input.available() <= 0) | |
| 343 | + return n; | |
| 344 | + } | |
| 345 | + } | |
| 346 | + | |
| 347 | + /** | |
| 348 | + * See the general contract of the <code>skip</code> | |
| 349 | + * method of <code>InputStream</code>. | |
| 350 | + * | |
| 351 | + * @exception IOException if the stream does not support seek, | |
| 352 | + * or if this input stream has been closed by | |
| 353 | + * invoking its {@link #close()} method, or an | |
| 354 | + * I/O error occurs. | |
| 355 | + */ | |
| 356 | + public synchronized long skip(long n) throws IOException { | |
| 357 | + getBufIfOpen(); // Check for closed stream | |
| 358 | + if (n <= 0) { | |
| 359 | + return 0; | |
| 360 | + } | |
| 361 | + long avail = count - pos; | |
| 362 | + | |
| 363 | + if (avail <= 0) { | |
| 364 | + // If no mark position set then don't keep in buffer | |
| 365 | + if (markpos <0) | |
| 366 | + return getInIfOpen().skip(n); | |
| 367 | + | |
| 368 | + // Fill in buffer to save bytes for reset | |
| 369 | + fill(); | |
| 370 | + avail = count - pos; | |
| 371 | + if (avail <= 0) | |
| 372 | + return 0; | |
| 373 | + } | |
| 374 | + | |
| 375 | + long skipped = (avail < n) ? avail : n; | |
| 376 | + pos += skipped; | |
| 377 | + return skipped; | |
| 378 | + } | |
| 379 | + | |
| 380 | + /** | |
| 381 | + * Returns an estimate of the number of bytes that can be read (or | |
| 382 | + * skipped over) from this input stream without blocking by the next | |
| 383 | + * invocation of a method for this input stream. The next invocation might be | |
| 384 | + * the same thread or another thread. A single read or skip of this | |
| 385 | + * many bytes will not block, but may read or skip fewer bytes. | |
| 386 | + * <p> | |
| 387 | + * This method returns the sum of the number of bytes remaining to be read in | |
| 388 | + * the buffer (<code>count - pos</code>) and the result of calling the | |
| 389 | + * {@link java.io.FilterInputStream#in in}.available(). | |
| 390 | + * | |
| 391 | + * @return an estimate of the number of bytes that can be read (or skipped | |
| 392 | + * over) from this input stream without blocking. | |
| 393 | + * @exception IOException if this input stream has been closed by | |
| 394 | + * invoking its {@link #close()} method, | |
| 395 | + * or an I/O error occurs. | |
| 396 | + */ | |
| 397 | + public synchronized int available() throws IOException { | |
| 398 | + int n = count - pos; | |
| 399 | + int avail = getInIfOpen().available(); | |
| 400 | + return n > (Integer.MAX_VALUE - avail) | |
| 401 | + ? Integer.MAX_VALUE | |
| 402 | + : n + avail; | |
| 403 | + } | |
| 404 | + | |
| 405 | + /** | |
| 406 | + * See the general contract of the <code>mark</code> | |
| 407 | + * method of <code>InputStream</code>. | |
| 408 | + * | |
| 409 | + * @param readlimit the maximum limit of bytes that can be read before | |
| 410 | + * the mark position becomes invalid. | |
| 411 | + * @see java.io.BufferedInputStream#reset() | |
| 412 | + */ | |
| 413 | + public synchronized void mark(int readlimit) { | |
| 414 | + marklimit = readlimit; | |
| 415 | + markpos = pos; | |
| 416 | + } | |
| 417 | + | |
| 418 | + /** | |
| 419 | + * See the general contract of the <code>reset</code> | |
| 420 | + * method of <code>InputStream</code>. | |
| 421 | + * <p> | |
| 422 | + * If <code>markpos</code> is <code>-1</code> | |
| 423 | + * (no mark has been set or the mark has been | |
| 424 | + * invalidated), an <code>IOException</code> | |
| 425 | + * is thrown. Otherwise, <code>pos</code> is | |
| 426 | + * set equal to <code>markpos</code>. | |
| 427 | + * | |
| 428 | + * @exception IOException if this stream has not been marked or, | |
| 429 | + * if the mark has been invalidated, or the stream | |
| 430 | + * has been closed by invoking its {@link #close()} | |
| 431 | + * method, or an I/O error occurs. | |
| 432 | + * @see java.io.BufferedInputStream#mark(int) | |
| 433 | + */ | |
| 434 | + public synchronized void reset() throws IOException { | |
| 435 | + getBufIfOpen(); // Cause exception if closed | |
| 436 | + if (markpos < 0) | |
| 437 | + throw new IOException("Resetting to invalid mark"); | |
| 438 | + pos = markpos; | |
| 439 | + } | |
| 440 | + | |
| 441 | + /** | |
| 442 | + * Tests if this input stream supports the <code>mark</code> | |
| 443 | + * and <code>reset</code> methods. The <code>markSupported</code> | |
| 444 | + * method of <code>BufferedInputStream</code> returns | |
| 445 | + * <code>true</code>. | |
| 446 | + * | |
| 447 | + * @return a <code>boolean</code> indicating if this stream type supports | |
| 448 | + * the <code>mark</code> and <code>reset</code> methods. | |
| 449 | + * @see java.io.InputStream#mark(int) | |
| 450 | + * @see java.io.InputStream#reset() | |
| 451 | + */ | |
| 452 | + public boolean markSupported() { | |
| 453 | + return true; | |
| 454 | + } | |
| 455 | + | |
| 456 | + /** | |
| 457 | + * Closes this input stream and releases any system resources | |
| 458 | + * associated with the stream. | |
| 459 | + * Once the stream has been closed, further read(), available(), reset(), | |
| 460 | + * or skip() invocations will throw an IOException. | |
| 461 | + * Closing a previously closed stream has no effect. | |
| 462 | + * | |
| 463 | + * @exception IOException if an I/O error occurs. | |
| 464 | + */ | |
| 465 | + public void close() throws IOException { | |
| 466 | + byte[] buffer; | |
| 467 | + while ( (buffer = buf) != null) { | |
| 468 | + if (bufUpdater.compareAndSet(this, buffer, null)) { | |
| 469 | + InputStream input = in; | |
| 470 | + in = null; | |
| 471 | + if (input != null) | |
| 472 | + input.close(); | |
| 473 | + return; | |
| 474 | + } | |
| 475 | + // Else retry in case a new buf was CASed in fill() | |
| 476 | + } | |
| 477 | + } | |
| 478 | +} | |
Binary file not shown.
| @@ -0,0 +1,143 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * The class implements a buffered output stream. By setting up such | |
| 30 | + * an output stream, an application can write bytes to the underlying | |
| 31 | + * output stream without necessarily causing a call to the underlying | |
| 32 | + * system for each byte written. | |
| 33 | + * | |
| 34 | + * @author Arthur van Hoff | |
| 35 | + * @since JDK1.0 | |
| 36 | + */ | |
| 37 | +public | |
| 38 | +class BufferedOutputStream extends FilterOutputStream { | |
| 39 | + /** | |
| 40 | + * The internal buffer where data is stored. | |
| 41 | + */ | |
| 42 | + protected byte buf[]; | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * The number of valid bytes in the buffer. This value is always | |
| 46 | + * in the range <tt>0</tt> through <tt>buf.length</tt>; elements | |
| 47 | + * <tt>buf[0]</tt> through <tt>buf[count-1]</tt> contain valid | |
| 48 | + * byte data. | |
| 49 | + */ | |
| 50 | + protected int count; | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * Creates a new buffered output stream to write data to the | |
| 54 | + * specified underlying output stream. | |
| 55 | + * | |
| 56 | + * @param out the underlying output stream. | |
| 57 | + */ | |
| 58 | + public BufferedOutputStream(OutputStream out) { | |
| 59 | + this(out, 8192); | |
| 60 | + } | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Creates a new buffered output stream to write data to the | |
| 64 | + * specified underlying output stream with the specified buffer | |
| 65 | + * size. | |
| 66 | + * | |
| 67 | + * @param out the underlying output stream. | |
| 68 | + * @param size the buffer size. | |
| 69 | + * @exception IllegalArgumentException if size <= 0. | |
| 70 | + */ | |
| 71 | + public BufferedOutputStream(OutputStream out, int size) { | |
| 72 | + super(out); | |
| 73 | + if (size <= 0) { | |
| 74 | + throw new IllegalArgumentException("Buffer size <= 0"); | |
| 75 | + } | |
| 76 | + buf = new byte[size]; | |
| 77 | + } | |
| 78 | + | |
| 79 | + /** Flush the internal buffer */ | |
| 80 | + private void flushBuffer() throws IOException { | |
| 81 | + if (count > 0) { | |
| 82 | + out.write(buf, 0, count); | |
| 83 | + count = 0; | |
| 84 | + } | |
| 85 | + } | |
| 86 | + | |
| 87 | + /** | |
| 88 | + * Writes the specified byte to this buffered output stream. | |
| 89 | + * | |
| 90 | + * @param b the byte to be written. | |
| 91 | + * @exception IOException if an I/O error occurs. | |
| 92 | + */ | |
| 93 | + public synchronized void write(int b) throws IOException { | |
| 94 | + if (count >= buf.length) { | |
| 95 | + flushBuffer(); | |
| 96 | + } | |
| 97 | + buf[count++] = (byte)b; | |
| 98 | + } | |
| 99 | + | |
| 100 | + /** | |
| 101 | + * Writes <code>len</code> bytes from the specified byte array | |
| 102 | + * starting at offset <code>off</code> to this buffered output stream. | |
| 103 | + * | |
| 104 | + * <p> Ordinarily this method stores bytes from the given array into this | |
| 105 | + * stream's buffer, flushing the buffer to the underlying output stream as | |
| 106 | + * needed. If the requested length is at least as large as this stream's | |
| 107 | + * buffer, however, then this method will flush the buffer and write the | |
| 108 | + * bytes directly to the underlying output stream. Thus redundant | |
| 109 | + * <code>BufferedOutputStream</code>s will not copy data unnecessarily. | |
| 110 | + * | |
| 111 | + * @param b the data. | |
| 112 | + * @param off the start offset in the data. | |
| 113 | + * @param len the number of bytes to write. | |
| 114 | + * @exception IOException if an I/O error occurs. | |
| 115 | + */ | |
| 116 | + public synchronized void write(byte b[], int off, int len) throws IOException { | |
| 117 | + if (len >= buf.length) { | |
| 118 | + /* If the request length exceeds the size of the output buffer, | |
| 119 | + flush the output buffer and then write the data directly. | |
| 120 | + In this way buffered streams will cascade harmlessly. */ | |
| 121 | + flushBuffer(); | |
| 122 | + out.write(b, off, len); | |
| 123 | + return; | |
| 124 | + } | |
| 125 | + if (len > buf.length - count) { | |
| 126 | + flushBuffer(); | |
| 127 | + } | |
| 128 | + System.arraycopy(b, off, buf, count, len); | |
| 129 | + count += len; | |
| 130 | + } | |
| 131 | + | |
| 132 | + /** | |
| 133 | + * Flushes this buffered output stream. This forces any buffered | |
| 134 | + * output bytes to be written out to the underlying output stream. | |
| 135 | + * | |
| 136 | + * @exception IOException if an I/O error occurs. | |
| 137 | + * @see java.io.FilterOutputStream#out | |
| 138 | + */ | |
| 139 | + public synchronized void flush() throws IOException { | |
| 140 | + flushBuffer(); | |
| 141 | + out.flush(); | |
| 142 | + } | |
| 143 | +} | |
Binary file not shown.
| @@ -0,0 +1,522 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * Reads text from a character-input stream, buffering characters so as to | |
| 31 | + * provide for the efficient reading of characters, arrays, and lines. | |
| 32 | + * | |
| 33 | + * <p> The buffer size may be specified, or the default size may be used. The | |
| 34 | + * default is large enough for most purposes. | |
| 35 | + * | |
| 36 | + * <p> In general, each read request made of a Reader causes a corresponding | |
| 37 | + * read request to be made of the underlying character or byte stream. It is | |
| 38 | + * therefore advisable to wrap a BufferedReader around any Reader whose read() | |
| 39 | + * operations may be costly, such as FileReaders and InputStreamReaders. For | |
| 40 | + * example, | |
| 41 | + * | |
| 42 | + * <pre> | |
| 43 | + * BufferedReader in | |
| 44 | + * = new BufferedReader(new FileReader("foo.in")); | |
| 45 | + * </pre> | |
| 46 | + * | |
| 47 | + * will buffer the input from the specified file. Without buffering, each | |
| 48 | + * invocation of read() or readLine() could cause bytes to be read from the | |
| 49 | + * file, converted into characters, and then returned, which can be very | |
| 50 | + * inefficient. | |
| 51 | + * | |
| 52 | + * <p> Programs that use DataInputStreams for textual input can be localized by | |
| 53 | + * replacing each DataInputStream with an appropriate BufferedReader. | |
| 54 | + * | |
| 55 | + * @see FileReader | |
| 56 | + * @see InputStreamReader | |
| 57 | + * @see java.nio.file.Files#newBufferedReader | |
| 58 | + * | |
| 59 | + * @author Mark Reinhold | |
| 60 | + * @since JDK1.1 | |
| 61 | + */ | |
| 62 | + | |
| 63 | +public class BufferedReader extends Reader { | |
| 64 | + | |
| 65 | + private Reader in; | |
| 66 | + | |
| 67 | + private char cb[]; | |
| 68 | + private int nChars, nextChar; | |
| 69 | + | |
| 70 | + private static final int INVALIDATED = -2; | |
| 71 | + private static final int UNMARKED = -1; | |
| 72 | + private int markedChar = UNMARKED; | |
| 73 | + private int readAheadLimit = 0; /* Valid only when markedChar > 0 */ | |
| 74 | + | |
| 75 | + /** If the next character is a line feed, skip it */ | |
| 76 | + private boolean skipLF = false; | |
| 77 | + | |
| 78 | + /** The skipLF flag when the mark was set */ | |
| 79 | + private boolean markedSkipLF = false; | |
| 80 | + | |
| 81 | + private static int defaultCharBufferSize = 8192; | |
| 82 | + private static int defaultExpectedLineLength = 80; | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * Creates a buffering character-input stream that uses an input buffer of | |
| 86 | + * the specified size. | |
| 87 | + * | |
| 88 | + * @param in A Reader | |
| 89 | + * @param sz Input-buffer size | |
| 90 | + * | |
| 91 | + * @exception IllegalArgumentException If sz is <= 0 | |
| 92 | + */ | |
| 93 | + public BufferedReader(Reader in, int sz) { | |
| 94 | + super(in); | |
| 95 | + if (sz <= 0) | |
| 96 | + throw new IllegalArgumentException("Buffer size <= 0"); | |
| 97 | + this.in = in; | |
| 98 | + cb = new char[sz]; | |
| 99 | + nextChar = nChars = 0; | |
| 100 | + } | |
| 101 | + | |
| 102 | + /** | |
| 103 | + * Creates a buffering character-input stream that uses a default-sized | |
| 104 | + * input buffer. | |
| 105 | + * | |
| 106 | + * @param in A Reader | |
| 107 | + */ | |
| 108 | + public BufferedReader(Reader in) { | |
| 109 | + this(in, defaultCharBufferSize); | |
| 110 | + } | |
| 111 | + | |
| 112 | + /** Checks to make sure that the stream has not been closed */ | |
| 113 | + private void ensureOpen() throws IOException { | |
| 114 | + if (in == null) | |
| 115 | + throw new IOException("Stream closed"); | |
| 116 | + } | |
| 117 | + | |
| 118 | + /** | |
| 119 | + * Fills the input buffer, taking the mark into account if it is valid. | |
| 120 | + */ | |
| 121 | + private void fill() throws IOException { | |
| 122 | + int dst; | |
| 123 | + if (markedChar <= UNMARKED) { | |
| 124 | + /* No mark */ | |
| 125 | + dst = 0; | |
| 126 | + } else { | |
| 127 | + /* Marked */ | |
| 128 | + int delta = nextChar - markedChar; | |
| 129 | + if (delta >= readAheadLimit) { | |
| 130 | + /* Gone past read-ahead limit: Invalidate mark */ | |
| 131 | + markedChar = INVALIDATED; | |
| 132 | + readAheadLimit = 0; | |
| 133 | + dst = 0; | |
| 134 | + } else { | |
| 135 | + if (readAheadLimit <= cb.length) { | |
| 136 | + /* Shuffle in the current buffer */ | |
| 137 | + System.arraycopy(cb, markedChar, cb, 0, delta); | |
| 138 | + markedChar = 0; | |
| 139 | + dst = delta; | |
| 140 | + } else { | |
| 141 | + /* Reallocate buffer to accommodate read-ahead limit */ | |
| 142 | + char ncb[] = new char[readAheadLimit]; | |
| 143 | + System.arraycopy(cb, markedChar, ncb, 0, delta); | |
| 144 | + cb = ncb; | |
| 145 | + markedChar = 0; | |
| 146 | + dst = delta; | |
| 147 | + } | |
| 148 | + nextChar = nChars = delta; | |
| 149 | + } | |
| 150 | + } | |
| 151 | + | |
| 152 | + int n; | |
| 153 | + do { | |
| 154 | + n = in.read(cb, dst, cb.length - dst); | |
| 155 | + } while (n == 0); | |
| 156 | + if (n > 0) { | |
| 157 | + nChars = dst + n; | |
| 158 | + nextChar = dst; | |
| 159 | + } | |
| 160 | + } | |
| 161 | + | |
| 162 | + /** | |
| 163 | + * Reads a single character. | |
| 164 | + * | |
| 165 | + * @return The character read, as an integer in the range | |
| 166 | + * 0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the | |
| 167 | + * end of the stream has been reached | |
| 168 | + * @exception IOException If an I/O error occurs | |
| 169 | + */ | |
| 170 | + public int read() throws IOException { | |
| 171 | + synchronized (lock) { | |
| 172 | + ensureOpen(); | |
| 173 | + for (;;) { | |
| 174 | + if (nextChar >= nChars) { | |
| 175 | + fill(); | |
| 176 | + if (nextChar >= nChars) | |
| 177 | + return -1; | |
| 178 | + } | |
| 179 | + if (skipLF) { | |
| 180 | + skipLF = false; | |
| 181 | + if (cb[nextChar] == '\n') { | |
| 182 | + nextChar++; | |
| 183 | + continue; | |
| 184 | + } | |
| 185 | + } | |
| 186 | + return cb[nextChar++]; | |
| 187 | + } | |
| 188 | + } | |
| 189 | + } | |
| 190 | + | |
| 191 | + /** | |
| 192 | + * Reads characters into a portion of an array, reading from the underlying | |
| 193 | + * stream if necessary. | |
| 194 | + */ | |
| 195 | + private int read1(char[] cbuf, int off, int len) throws IOException { | |
| 196 | + if (nextChar >= nChars) { | |
| 197 | + /* If the requested length is at least as large as the buffer, and | |
| 198 | + if there is no mark/reset activity, and if line feeds are not | |
| 199 | + being skipped, do not bother to copy the characters into the | |
| 200 | + local buffer. In this way buffered streams will cascade | |
| 201 | + harmlessly. */ | |
| 202 | + if (len >= cb.length && markedChar <= UNMARKED && !skipLF) { | |
| 203 | + return in.read(cbuf, off, len); | |
| 204 | + } | |
| 205 | + fill(); | |
| 206 | + } | |
| 207 | + if (nextChar >= nChars) return -1; | |
| 208 | + if (skipLF) { | |
| 209 | + skipLF = false; | |
| 210 | + if (cb[nextChar] == '\n') { | |
| 211 | + nextChar++; | |
| 212 | + if (nextChar >= nChars) | |
| 213 | + fill(); | |
| 214 | + if (nextChar >= nChars) | |
| 215 | + return -1; | |
| 216 | + } | |
| 217 | + } | |
| 218 | + int n = Math.min(len, nChars - nextChar); | |
| 219 | + System.arraycopy(cb, nextChar, cbuf, off, n); | |
| 220 | + nextChar += n; | |
| 221 | + return n; | |
| 222 | + } | |
| 223 | + | |
| 224 | + /** | |
| 225 | + * Reads characters into a portion of an array. | |
| 226 | + * | |
| 227 | + * <p> This method implements the general contract of the corresponding | |
| 228 | + * <code>{@link Reader#read(char[], int, int) read}</code> method of the | |
| 229 | + * <code>{@link Reader}</code> class. As an additional convenience, it | |
| 230 | + * attempts to read as many characters as possible by repeatedly invoking | |
| 231 | + * the <code>read</code> method of the underlying stream. This iterated | |
| 232 | + * <code>read</code> continues until one of the following conditions becomes | |
| 233 | + * true: <ul> | |
| 234 | + * | |
| 235 | + * <li> The specified number of characters have been read, | |
| 236 | + * | |
| 237 | + * <li> The <code>read</code> method of the underlying stream returns | |
| 238 | + * <code>-1</code>, indicating end-of-file, or | |
| 239 | + * | |
| 240 | + * <li> The <code>ready</code> method of the underlying stream | |
| 241 | + * returns <code>false</code>, indicating that further input requests | |
| 242 | + * would block. | |
| 243 | + * | |
| 244 | + * </ul> If the first <code>read</code> on the underlying stream returns | |
| 245 | + * <code>-1</code> to indicate end-of-file then this method returns | |
| 246 | + * <code>-1</code>. Otherwise this method returns the number of characters | |
| 247 | + * actually read. | |
| 248 | + * | |
| 249 | + * <p> Subclasses of this class are encouraged, but not required, to | |
| 250 | + * attempt to read as many characters as possible in the same fashion. | |
| 251 | + * | |
| 252 | + * <p> Ordinarily this method takes characters from this stream's character | |
| 253 | + * buffer, filling it from the underlying stream as necessary. If, | |
| 254 | + * however, the buffer is empty, the mark is not valid, and the requested | |
| 255 | + * length is at least as large as the buffer, then this method will read | |
| 256 | + * characters directly from the underlying stream into the given array. | |
| 257 | + * Thus redundant <code>BufferedReader</code>s will not copy data | |
| 258 | + * unnecessarily. | |
| 259 | + * | |
| 260 | + * @param cbuf Destination buffer | |
| 261 | + * @param off Offset at which to start storing characters | |
| 262 | + * @param len Maximum number of characters to read | |
| 263 | + * | |
| 264 | + * @return The number of characters read, or -1 if the end of the | |
| 265 | + * stream has been reached | |
| 266 | + * | |
| 267 | + * @exception IOException If an I/O error occurs | |
| 268 | + */ | |
| 269 | + public int read(char cbuf[], int off, int len) throws IOException { | |
| 270 | + synchronized (lock) { | |
| 271 | + ensureOpen(); | |
| 272 | + if ((off < 0) || (off > cbuf.length) || (len < 0) || | |
| 273 | + ((off + len) > cbuf.length) || ((off + len) < 0)) { | |
| 274 | + throw new IndexOutOfBoundsException(); | |
| 275 | + } else if (len == 0) { | |
| 276 | + return 0; | |
| 277 | + } | |
| 278 | + | |
| 279 | + int n = read1(cbuf, off, len); | |
| 280 | + if (n <= 0) return n; | |
| 281 | + while ((n < len) && in.ready()) { | |
| 282 | + int n1 = read1(cbuf, off + n, len - n); | |
| 283 | + if (n1 <= 0) break; | |
| 284 | + n += n1; | |
| 285 | + } | |
| 286 | + return n; | |
| 287 | + } | |
| 288 | + } | |
| 289 | + | |
| 290 | + /** | |
| 291 | + * Reads a line of text. A line is considered to be terminated by any one | |
| 292 | + * of a line feed ('\n'), a carriage return ('\r'), or a carriage return | |
| 293 | + * followed immediately by a linefeed. | |
| 294 | + * | |
| 295 | + * @param ignoreLF If true, the next '\n' will be skipped | |
| 296 | + * | |
| 297 | + * @return A String containing the contents of the line, not including | |
| 298 | + * any line-termination characters, or null if the end of the | |
| 299 | + * stream has been reached | |
| 300 | + * | |
| 301 | + * @see java.io.LineNumberReader#readLine() | |
| 302 | + * | |
| 303 | + * @exception IOException If an I/O error occurs | |
| 304 | + */ | |
| 305 | + String readLine(boolean ignoreLF) throws IOException { | |
| 306 | + StringBuffer s = null; | |
| 307 | + int startChar; | |
| 308 | + | |
| 309 | + synchronized (lock) { | |
| 310 | + ensureOpen(); | |
| 311 | + boolean omitLF = ignoreLF || skipLF; | |
| 312 | + | |
| 313 | + bufferLoop: | |
| 314 | + for (;;) { | |
| 315 | + | |
| 316 | + if (nextChar >= nChars) | |
| 317 | + fill(); | |
| 318 | + if (nextChar >= nChars) { /* EOF */ | |
| 319 | + if (s != null && s.length() > 0) | |
| 320 | + return s.toString(); | |
| 321 | + else | |
| 322 | + return null; | |
| 323 | + } | |
| 324 | + boolean eol = false; | |
| 325 | + char c = 0; | |
| 326 | + int i; | |
| 327 | + | |
| 328 | + /* Skip a leftover '\n', if necessary */ | |
| 329 | + if (omitLF && (cb[nextChar] == '\n')) | |
| 330 | + nextChar++; | |
| 331 | + skipLF = false; | |
| 332 | + omitLF = false; | |
| 333 | + | |
| 334 | + charLoop: | |
| 335 | + for (i = nextChar; i < nChars; i++) { | |
| 336 | + c = cb[i]; | |
| 337 | + if ((c == '\n') || (c == '\r')) { | |
| 338 | + eol = true; | |
| 339 | + break charLoop; | |
| 340 | + } | |
| 341 | + } | |
| 342 | + | |
| 343 | + startChar = nextChar; | |
| 344 | + nextChar = i; | |
| 345 | + | |
| 346 | + if (eol) { | |
| 347 | + String str; | |
| 348 | + if (s == null) { | |
| 349 | + str = new String(cb, startChar, i - startChar); | |
| 350 | + } else { | |
| 351 | + s.append(cb, startChar, i - startChar); | |
| 352 | + str = s.toString(); | |
| 353 | + } | |
| 354 | + nextChar++; | |
| 355 | + if (c == '\r') { | |
| 356 | + skipLF = true; | |
| 357 | + } | |
| 358 | + return str; | |
| 359 | + } | |
| 360 | + | |
| 361 | + if (s == null) | |
| 362 | + s = new StringBuffer(defaultExpectedLineLength); | |
| 363 | + s.append(cb, startChar, i - startChar); | |
| 364 | + } | |
| 365 | + } | |
| 366 | + } | |
| 367 | + | |
| 368 | + /** | |
| 369 | + * Reads a line of text. A line is considered to be terminated by any one | |
| 370 | + * of a line feed ('\n'), a carriage return ('\r'), or a carriage return | |
| 371 | + * followed immediately by a linefeed. | |
| 372 | + * | |
| 373 | + * @return A String containing the contents of the line, not including | |
| 374 | + * any line-termination characters, or null if the end of the | |
| 375 | + * stream has been reached | |
| 376 | + * | |
| 377 | + * @exception IOException If an I/O error occurs | |
| 378 | + * | |
| 379 | + * @see java.nio.file.Files#readAllLines | |
| 380 | + */ | |
| 381 | + public String readLine() throws IOException { | |
| 382 | + return readLine(false); | |
| 383 | + } | |
| 384 | + | |
| 385 | + /** | |
| 386 | + * Skips characters. | |
| 387 | + * | |
| 388 | + * @param n The number of characters to skip | |
| 389 | + * | |
| 390 | + * @return The number of characters actually skipped | |
| 391 | + * | |
| 392 | + * @exception IllegalArgumentException If <code>n</code> is negative. | |
| 393 | + * @exception IOException If an I/O error occurs | |
| 394 | + */ | |
| 395 | + public long skip(long n) throws IOException { | |
| 396 | + if (n < 0L) { | |
| 397 | + throw new IllegalArgumentException("skip value is negative"); | |
| 398 | + } | |
| 399 | + synchronized (lock) { | |
| 400 | + ensureOpen(); | |
| 401 | + long r = n; | |
| 402 | + while (r > 0) { | |
| 403 | + if (nextChar >= nChars) | |
| 404 | + fill(); | |
| 405 | + if (nextChar >= nChars) /* EOF */ | |
| 406 | + break; | |
| 407 | + if (skipLF) { | |
| 408 | + skipLF = false; | |
| 409 | + if (cb[nextChar] == '\n') { | |
| 410 | + nextChar++; | |
| 411 | + } | |
| 412 | + } | |
| 413 | + long d = nChars - nextChar; | |
| 414 | + if (r <= d) { | |
| 415 | + nextChar += r; | |
| 416 | + r = 0; | |
| 417 | + break; | |
| 418 | + } | |
| 419 | + else { | |
| 420 | + r -= d; | |
| 421 | + nextChar = nChars; | |
| 422 | + } | |
| 423 | + } | |
| 424 | + return n - r; | |
| 425 | + } | |
| 426 | + } | |
| 427 | + | |
| 428 | + /** | |
| 429 | + * Tells whether this stream is ready to be read. A buffered character | |
| 430 | + * stream is ready if the buffer is not empty, or if the underlying | |
| 431 | + * character stream is ready. | |
| 432 | + * | |
| 433 | + * @exception IOException If an I/O error occurs | |
| 434 | + */ | |
| 435 | + public boolean ready() throws IOException { | |
| 436 | + synchronized (lock) { | |
| 437 | + ensureOpen(); | |
| 438 | + | |
| 439 | + /* | |
| 440 | + * If newline needs to be skipped and the next char to be read | |
| 441 | + * is a newline character, then just skip it right away. | |
| 442 | + */ | |
| 443 | + if (skipLF) { | |
| 444 | + /* Note that in.ready() will return true if and only if the next | |
| 445 | + * read on the stream will not block. | |
| 446 | + */ | |
| 447 | + if (nextChar >= nChars && in.ready()) { | |
| 448 | + fill(); | |
| 449 | + } | |
| 450 | + if (nextChar < nChars) { | |
| 451 | + if (cb[nextChar] == '\n') | |
| 452 | + nextChar++; | |
| 453 | + skipLF = false; | |
| 454 | + } | |
| 455 | + } | |
| 456 | + return (nextChar < nChars) || in.ready(); | |
| 457 | + } | |
| 458 | + } | |
| 459 | + | |
| 460 | + /** | |
| 461 | + * Tells whether this stream supports the mark() operation, which it does. | |
| 462 | + */ | |
| 463 | + public boolean markSupported() { | |
| 464 | + return true; | |
| 465 | + } | |
| 466 | + | |
| 467 | + /** | |
| 468 | + * Marks the present position in the stream. Subsequent calls to reset() | |
| 469 | + * will attempt to reposition the stream to this point. | |
| 470 | + * | |
| 471 | + * @param readAheadLimit Limit on the number of characters that may be | |
| 472 | + * read while still preserving the mark. An attempt | |
| 473 | + * to reset the stream after reading characters | |
| 474 | + * up to this limit or beyond may fail. | |
| 475 | + * A limit value larger than the size of the input | |
| 476 | + * buffer will cause a new buffer to be allocated | |
| 477 | + * whose size is no smaller than limit. | |
| 478 | + * Therefore large values should be used with care. | |
| 479 | + * | |
| 480 | + * @exception IllegalArgumentException If readAheadLimit is < 0 | |
| 481 | + * @exception IOException If an I/O error occurs | |
| 482 | + */ | |
| 483 | + public void mark(int readAheadLimit) throws IOException { | |
| 484 | + if (readAheadLimit < 0) { | |
| 485 | + throw new IllegalArgumentException("Read-ahead limit < 0"); | |
| 486 | + } | |
| 487 | + synchronized (lock) { | |
| 488 | + ensureOpen(); | |
| 489 | + this.readAheadLimit = readAheadLimit; | |
| 490 | + markedChar = nextChar; | |
| 491 | + markedSkipLF = skipLF; | |
| 492 | + } | |
| 493 | + } | |
| 494 | + | |
| 495 | + /** | |
| 496 | + * Resets the stream to the most recent mark. | |
| 497 | + * | |
| 498 | + * @exception IOException If the stream has never been marked, | |
| 499 | + * or if the mark has been invalidated | |
| 500 | + */ | |
| 501 | + public void reset() throws IOException { | |
| 502 | + synchronized (lock) { | |
| 503 | + ensureOpen(); | |
| 504 | + if (markedChar < 0) | |
| 505 | + throw new IOException((markedChar == INVALIDATED) | |
| 506 | + ? "Mark invalid" | |
| 507 | + : "Stream not marked"); | |
| 508 | + nextChar = markedChar; | |
| 509 | + skipLF = markedSkipLF; | |
| 510 | + } | |
| 511 | + } | |
| 512 | + | |
| 513 | + public void close() throws IOException { | |
| 514 | + synchronized (lock) { | |
| 515 | + if (in == null) | |
| 516 | + return; | |
| 517 | + in.close(); | |
| 518 | + in = null; | |
| 519 | + cb = null; | |
| 520 | + } | |
| 521 | + } | |
| 522 | +} | |
Binary file not shown.
| @@ -0,0 +1,272 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * Writes text to a character-output stream, buffering characters so as to | |
| 31 | + * provide for the efficient writing of single characters, arrays, and strings. | |
| 32 | + * | |
| 33 | + * <p> The buffer size may be specified, or the default size may be accepted. | |
| 34 | + * The default is large enough for most purposes. | |
| 35 | + * | |
| 36 | + * <p> A newLine() method is provided, which uses the platform's own notion of | |
| 37 | + * line separator as defined by the system property <tt>line.separator</tt>. | |
| 38 | + * Not all platforms use the newline character ('\n') to terminate lines. | |
| 39 | + * Calling this method to terminate each output line is therefore preferred to | |
| 40 | + * writing a newline character directly. | |
| 41 | + * | |
| 42 | + * <p> In general, a Writer sends its output immediately to the underlying | |
| 43 | + * character or byte stream. Unless prompt output is required, it is advisable | |
| 44 | + * to wrap a BufferedWriter around any Writer whose write() operations may be | |
| 45 | + * costly, such as FileWriters and OutputStreamWriters. For example, | |
| 46 | + * | |
| 47 | + * <pre> | |
| 48 | + * PrintWriter out | |
| 49 | + * = new PrintWriter(new BufferedWriter(new FileWriter("foo.out"))); | |
| 50 | + * </pre> | |
| 51 | + * | |
| 52 | + * will buffer the PrintWriter's output to the file. Without buffering, each | |
| 53 | + * invocation of a print() method would cause characters to be converted into | |
| 54 | + * bytes that would then be written immediately to the file, which can be very | |
| 55 | + * inefficient. | |
| 56 | + * | |
| 57 | + * @see PrintWriter | |
| 58 | + * @see FileWriter | |
| 59 | + * @see OutputStreamWriter | |
| 60 | + * @see java.nio.file.Files#newBufferedWriter | |
| 61 | + * | |
| 62 | + * @author Mark Reinhold | |
| 63 | + * @since JDK1.1 | |
| 64 | + */ | |
| 65 | + | |
| 66 | +public class BufferedWriter extends Writer { | |
| 67 | + | |
| 68 | + private Writer out; | |
| 69 | + | |
| 70 | + private char cb[]; | |
| 71 | + private int nChars, nextChar; | |
| 72 | + | |
| 73 | + private static int defaultCharBufferSize = 8192; | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * Line separator string. This is the value of the line.separator | |
| 77 | + * property at the moment that the stream was created. | |
| 78 | + */ | |
| 79 | + private String lineSeparator; | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * Creates a buffered character-output stream that uses a default-sized | |
| 83 | + * output buffer. | |
| 84 | + * | |
| 85 | + * @param out A Writer | |
| 86 | + */ | |
| 87 | + public BufferedWriter(Writer out) { | |
| 88 | + this(out, defaultCharBufferSize); | |
| 89 | + } | |
| 90 | + | |
| 91 | + /** | |
| 92 | + * Creates a new buffered character-output stream that uses an output | |
| 93 | + * buffer of the given size. | |
| 94 | + * | |
| 95 | + * @param out A Writer | |
| 96 | + * @param sz Output-buffer size, a positive integer | |
| 97 | + * | |
| 98 | + * @exception IllegalArgumentException If sz is <= 0 | |
| 99 | + */ | |
| 100 | + public BufferedWriter(Writer out, int sz) { | |
| 101 | + super(out); | |
| 102 | + if (sz <= 0) | |
| 103 | + throw new IllegalArgumentException("Buffer size <= 0"); | |
| 104 | + this.out = out; | |
| 105 | + cb = new char[sz]; | |
| 106 | + nChars = sz; | |
| 107 | + nextChar = 0; | |
| 108 | + | |
| 109 | + lineSeparator = java.security.AccessController.doPrivileged( | |
| 110 | + new sun.security.action.GetPropertyAction("line.separator")); | |
| 111 | + } | |
| 112 | + | |
| 113 | + /** Checks to make sure that the stream has not been closed */ | |
| 114 | + private void ensureOpen() throws IOException { | |
| 115 | + if (out == null) | |
| 116 | + throw new IOException("Stream closed"); | |
| 117 | + } | |
| 118 | + | |
| 119 | + /** | |
| 120 | + * Flushes the output buffer to the underlying character stream, without | |
| 121 | + * flushing the stream itself. This method is non-private only so that it | |
| 122 | + * may be invoked by PrintStream. | |
| 123 | + */ | |
| 124 | + void flushBuffer() throws IOException { | |
| 125 | + synchronized (lock) { | |
| 126 | + ensureOpen(); | |
| 127 | + if (nextChar == 0) | |
| 128 | + return; | |
| 129 | + out.write(cb, 0, nextChar); | |
| 130 | + nextChar = 0; | |
| 131 | + } | |
| 132 | + } | |
| 133 | + | |
| 134 | + /** | |
| 135 | + * Writes a single character. | |
| 136 | + * | |
| 137 | + * @exception IOException If an I/O error occurs | |
| 138 | + */ | |
| 139 | + public void write(int c) throws IOException { | |
| 140 | + synchronized (lock) { | |
| 141 | + ensureOpen(); | |
| 142 | + if (nextChar >= nChars) | |
| 143 | + flushBuffer(); | |
| 144 | + cb[nextChar++] = (char) c; | |
| 145 | + } | |
| 146 | + } | |
| 147 | + | |
| 148 | + /** | |
| 149 | + * Our own little min method, to avoid loading java.lang.Math if we've run | |
| 150 | + * out of file descriptors and we're trying to print a stack trace. | |
| 151 | + */ | |
| 152 | + private int min(int a, int b) { | |
| 153 | + if (a < b) return a; | |
| 154 | + return b; | |
| 155 | + } | |
| 156 | + | |
| 157 | + /** | |
| 158 | + * Writes a portion of an array of characters. | |
| 159 | + * | |
| 160 | + * <p> Ordinarily this method stores characters from the given array into | |
| 161 | + * this stream's buffer, flushing the buffer to the underlying stream as | |
| 162 | + * needed. If the requested length is at least as large as the buffer, | |
| 163 | + * however, then this method will flush the buffer and write the characters | |
| 164 | + * directly to the underlying stream. Thus redundant | |
| 165 | + * <code>BufferedWriter</code>s will not copy data unnecessarily. | |
| 166 | + * | |
| 167 | + * @param cbuf A character array | |
| 168 | + * @param off Offset from which to start reading characters | |
| 169 | + * @param len Number of characters to write | |
| 170 | + * | |
| 171 | + * @exception IOException If an I/O error occurs | |
| 172 | + */ | |
| 173 | + public void write(char cbuf[], int off, int len) throws IOException { | |
| 174 | + synchronized (lock) { | |
| 175 | + ensureOpen(); | |
| 176 | + if ((off < 0) || (off > cbuf.length) || (len < 0) || | |
| 177 | + ((off + len) > cbuf.length) || ((off + len) < 0)) { | |
| 178 | + throw new IndexOutOfBoundsException(); | |
| 179 | + } else if (len == 0) { | |
| 180 | + return; | |
| 181 | + } | |
| 182 | + | |
| 183 | + if (len >= nChars) { | |
| 184 | + /* If the request length exceeds the size of the output buffer, | |
| 185 | + flush the buffer and then write the data directly. In this | |
| 186 | + way buffered streams will cascade harmlessly. */ | |
| 187 | + flushBuffer(); | |
| 188 | + out.write(cbuf, off, len); | |
| 189 | + return; | |
| 190 | + } | |
| 191 | + | |
| 192 | + int b = off, t = off + len; | |
| 193 | + while (b < t) { | |
| 194 | + int d = min(nChars - nextChar, t - b); | |
| 195 | + System.arraycopy(cbuf, b, cb, nextChar, d); | |
| 196 | + b += d; | |
| 197 | + nextChar += d; | |
| 198 | + if (nextChar >= nChars) | |
| 199 | + flushBuffer(); | |
| 200 | + } | |
| 201 | + } | |
| 202 | + } | |
| 203 | + | |
| 204 | + /** | |
| 205 | + * Writes a portion of a String. | |
| 206 | + * | |
| 207 | + * <p> If the value of the <tt>len</tt> parameter is negative then no | |
| 208 | + * characters are written. This is contrary to the specification of this | |
| 209 | + * method in the {@linkplain java.io.Writer#write(java.lang.String,int,int) | |
| 210 | + * superclass}, which requires that an {@link IndexOutOfBoundsException} be | |
| 211 | + * thrown. | |
| 212 | + * | |
| 213 | + * @param s String to be written | |
| 214 | + * @param off Offset from which to start reading characters | |
| 215 | + * @param len Number of characters to be written | |
| 216 | + * | |
| 217 | + * @exception IOException If an I/O error occurs | |
| 218 | + */ | |
| 219 | + public void write(String s, int off, int len) throws IOException { | |
| 220 | + synchronized (lock) { | |
| 221 | + ensureOpen(); | |
| 222 | + | |
| 223 | + int b = off, t = off + len; | |
| 224 | + while (b < t) { | |
| 225 | + int d = min(nChars - nextChar, t - b); | |
| 226 | + s.getChars(b, b + d, cb, nextChar); | |
| 227 | + b += d; | |
| 228 | + nextChar += d; | |
| 229 | + if (nextChar >= nChars) | |
| 230 | + flushBuffer(); | |
| 231 | + } | |
| 232 | + } | |
| 233 | + } | |
| 234 | + | |
| 235 | + /** | |
| 236 | + * Writes a line separator. The line separator string is defined by the | |
| 237 | + * system property <tt>line.separator</tt>, and is not necessarily a single | |
| 238 | + * newline ('\n') character. | |
| 239 | + * | |
| 240 | + * @exception IOException If an I/O error occurs | |
| 241 | + */ | |
| 242 | + public void newLine() throws IOException { | |
| 243 | + write(lineSeparator); | |
| 244 | + } | |
| 245 | + | |
| 246 | + /** | |
| 247 | + * Flushes the stream. | |
| 248 | + * | |
| 249 | + * @exception IOException If an I/O error occurs | |
| 250 | + */ | |
| 251 | + public void flush() throws IOException { | |
| 252 | + synchronized (lock) { | |
| 253 | + flushBuffer(); | |
| 254 | + out.flush(); | |
| 255 | + } | |
| 256 | + } | |
| 257 | + | |
| 258 | + public void close() throws IOException { | |
| 259 | + synchronized (lock) { | |
| 260 | + if (out == null) { | |
| 261 | + return; | |
| 262 | + } | |
| 263 | + try { | |
| 264 | + flushBuffer(); | |
| 265 | + } finally { | |
| 266 | + out.close(); | |
| 267 | + out = null; | |
| 268 | + cb = null; | |
| 269 | + } | |
| 270 | + } | |
| 271 | + } | |
| 272 | +} | |
Binary file not shown.
| @@ -0,0 +1,283 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * A <code>ByteArrayInputStream</code> contains | |
| 30 | + * an internal buffer that contains bytes that | |
| 31 | + * may be read from the stream. An internal | |
| 32 | + * counter keeps track of the next byte to | |
| 33 | + * be supplied by the <code>read</code> method. | |
| 34 | + * <p> | |
| 35 | + * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in | |
| 36 | + * this class can be called after the stream has been closed without | |
| 37 | + * generating an <tt>IOException</tt>. | |
| 38 | + * | |
| 39 | + * @author Arthur van Hoff | |
| 40 | + * @see java.io.StringBufferInputStream | |
| 41 | + * @since JDK1.0 | |
| 42 | + */ | |
| 43 | +public | |
| 44 | +class ByteArrayInputStream extends InputStream { | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * An array of bytes that was provided | |
| 48 | + * by the creator of the stream. Elements <code>buf[0]</code> | |
| 49 | + * through <code>buf[count-1]</code> are the | |
| 50 | + * only bytes that can ever be read from the | |
| 51 | + * stream; element <code>buf[pos]</code> is | |
| 52 | + * the next byte to be read. | |
| 53 | + */ | |
| 54 | + protected byte buf[]; | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * The index of the next character to read from the input stream buffer. | |
| 58 | + * This value should always be nonnegative | |
| 59 | + * and not larger than the value of <code>count</code>. | |
| 60 | + * The next byte to be read from the input stream buffer | |
| 61 | + * will be <code>buf[pos]</code>. | |
| 62 | + */ | |
| 63 | + protected int pos; | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * The currently marked position in the stream. | |
| 67 | + * ByteArrayInputStream objects are marked at position zero by | |
| 68 | + * default when constructed. They may be marked at another | |
| 69 | + * position within the buffer by the <code>mark()</code> method. | |
| 70 | + * The current buffer position is set to this point by the | |
| 71 | + * <code>reset()</code> method. | |
| 72 | + * <p> | |
| 73 | + * If no mark has been set, then the value of mark is the offset | |
| 74 | + * passed to the constructor (or 0 if the offset was not supplied). | |
| 75 | + * | |
| 76 | + * @since JDK1.1 | |
| 77 | + */ | |
| 78 | + protected int mark = 0; | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * The index one greater than the last valid character in the input | |
| 82 | + * stream buffer. | |
| 83 | + * This value should always be nonnegative | |
| 84 | + * and not larger than the length of <code>buf</code>. | |
| 85 | + * It is one greater than the position of | |
| 86 | + * the last byte within <code>buf</code> that | |
| 87 | + * can ever be read from the input stream buffer. | |
| 88 | + */ | |
| 89 | + protected int count; | |
| 90 | + | |
| 91 | + /** | |
| 92 | + * Creates a <code>ByteArrayInputStream</code> | |
| 93 | + * so that it uses <code>buf</code> as its | |
| 94 | + * buffer array. | |
| 95 | + * The buffer array is not copied. | |
| 96 | + * The initial value of <code>pos</code> | |
| 97 | + * is <code>0</code> and the initial value | |
| 98 | + * of <code>count</code> is the length of | |
| 99 | + * <code>buf</code>. | |
| 100 | + * | |
| 101 | + * @param buf the input buffer. | |
| 102 | + */ | |
| 103 | + public ByteArrayInputStream(byte buf[]) { | |
| 104 | + this.buf = buf; | |
| 105 | + this.pos = 0; | |
| 106 | + this.count = buf.length; | |
| 107 | + } | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * Creates <code>ByteArrayInputStream</code> | |
| 111 | + * that uses <code>buf</code> as its | |
| 112 | + * buffer array. The initial value of <code>pos</code> | |
| 113 | + * is <code>offset</code> and the initial value | |
| 114 | + * of <code>count</code> is the minimum of <code>offset+length</code> | |
| 115 | + * and <code>buf.length</code>. | |
| 116 | + * The buffer array is not copied. The buffer's mark is | |
| 117 | + * set to the specified offset. | |
| 118 | + * | |
| 119 | + * @param buf the input buffer. | |
| 120 | + * @param offset the offset in the buffer of the first byte to read. | |
| 121 | + * @param length the maximum number of bytes to read from the buffer. | |
| 122 | + */ | |
| 123 | + public ByteArrayInputStream(byte buf[], int offset, int length) { | |
| 124 | + this.buf = buf; | |
| 125 | + this.pos = offset; | |
| 126 | + this.count = Math.min(offset + length, buf.length); | |
| 127 | + this.mark = offset; | |
| 128 | + } | |
| 129 | + | |
| 130 | + /** | |
| 131 | + * Reads the next byte of data from this input stream. The value | |
| 132 | + * byte is returned as an <code>int</code> in the range | |
| 133 | + * <code>0</code> to <code>255</code>. If no byte is available | |
| 134 | + * because the end of the stream has been reached, the value | |
| 135 | + * <code>-1</code> is returned. | |
| 136 | + * <p> | |
| 137 | + * This <code>read</code> method | |
| 138 | + * cannot block. | |
| 139 | + * | |
| 140 | + * @return the next byte of data, or <code>-1</code> if the end of the | |
| 141 | + * stream has been reached. | |
| 142 | + */ | |
| 143 | + public synchronized int read() { | |
| 144 | + return (pos < count) ? (buf[pos++] & 0xff) : -1; | |
| 145 | + } | |
| 146 | + | |
| 147 | + /** | |
| 148 | + * Reads up to <code>len</code> bytes of data into an array of bytes | |
| 149 | + * from this input stream. | |
| 150 | + * If <code>pos</code> equals <code>count</code>, | |
| 151 | + * then <code>-1</code> is returned to indicate | |
| 152 | + * end of file. Otherwise, the number <code>k</code> | |
| 153 | + * of bytes read is equal to the smaller of | |
| 154 | + * <code>len</code> and <code>count-pos</code>. | |
| 155 | + * If <code>k</code> is positive, then bytes | |
| 156 | + * <code>buf[pos]</code> through <code>buf[pos+k-1]</code> | |
| 157 | + * are copied into <code>b[off]</code> through | |
| 158 | + * <code>b[off+k-1]</code> in the manner performed | |
| 159 | + * by <code>System.arraycopy</code>. The | |
| 160 | + * value <code>k</code> is added into <code>pos</code> | |
| 161 | + * and <code>k</code> is returned. | |
| 162 | + * <p> | |
| 163 | + * This <code>read</code> method cannot block. | |
| 164 | + * | |
| 165 | + * @param b the buffer into which the data is read. | |
| 166 | + * @param off the start offset in the destination array <code>b</code> | |
| 167 | + * @param len the maximum number of bytes read. | |
| 168 | + * @return the total number of bytes read into the buffer, or | |
| 169 | + * <code>-1</code> if there is no more data because the end of | |
| 170 | + * the stream has been reached. | |
| 171 | + * @exception NullPointerException If <code>b</code> is <code>null</code>. | |
| 172 | + * @exception IndexOutOfBoundsException If <code>off</code> is negative, | |
| 173 | + * <code>len</code> is negative, or <code>len</code> is greater than | |
| 174 | + * <code>b.length - off</code> | |
| 175 | + */ | |
| 176 | + public synchronized int read(byte b[], int off, int len) { | |
| 177 | + if (b == null) { | |
| 178 | + throw new NullPointerException(); | |
| 179 | + } else if (off < 0 || len < 0 || len > b.length - off) { | |
| 180 | + throw new IndexOutOfBoundsException(); | |
| 181 | + } | |
| 182 | + | |
| 183 | + if (pos >= count) { | |
| 184 | + return -1; | |
| 185 | + } | |
| 186 | + | |
| 187 | + int avail = count - pos; | |
| 188 | + if (len > avail) { | |
| 189 | + len = avail; | |
| 190 | + } | |
| 191 | + if (len <= 0) { | |
| 192 | + return 0; | |
| 193 | + } | |
| 194 | + System.arraycopy(buf, pos, b, off, len); | |
| 195 | + pos += len; | |
| 196 | + return len; | |
| 197 | + } | |
| 198 | + | |
| 199 | + /** | |
| 200 | + * Skips <code>n</code> bytes of input from this input stream. Fewer | |
| 201 | + * bytes might be skipped if the end of the input stream is reached. | |
| 202 | + * The actual number <code>k</code> | |
| 203 | + * of bytes to be skipped is equal to the smaller | |
| 204 | + * of <code>n</code> and <code>count-pos</code>. | |
| 205 | + * The value <code>k</code> is added into <code>pos</code> | |
| 206 | + * and <code>k</code> is returned. | |
| 207 | + * | |
| 208 | + * @param n the number of bytes to be skipped. | |
| 209 | + * @return the actual number of bytes skipped. | |
| 210 | + */ | |
| 211 | + public synchronized long skip(long n) { | |
| 212 | + long k = count - pos; | |
| 213 | + if (n < k) { | |
| 214 | + k = n < 0 ? 0 : n; | |
| 215 | + } | |
| 216 | + | |
| 217 | + pos += k; | |
| 218 | + return k; | |
| 219 | + } | |
| 220 | + | |
| 221 | + /** | |
| 222 | + * Returns the number of remaining bytes that can be read (or skipped over) | |
| 223 | + * from this input stream. | |
| 224 | + * <p> | |
| 225 | + * The value returned is <code>count - pos</code>, | |
| 226 | + * which is the number of bytes remaining to be read from the input buffer. | |
| 227 | + * | |
| 228 | + * @return the number of remaining bytes that can be read (or skipped | |
| 229 | + * over) from this input stream without blocking. | |
| 230 | + */ | |
| 231 | + public synchronized int available() { | |
| 232 | + return count - pos; | |
| 233 | + } | |
| 234 | + | |
| 235 | + /** | |
| 236 | + * Tests if this <code>InputStream</code> supports mark/reset. The | |
| 237 | + * <code>markSupported</code> method of <code>ByteArrayInputStream</code> | |
| 238 | + * always returns <code>true</code>. | |
| 239 | + * | |
| 240 | + * @since JDK1.1 | |
| 241 | + */ | |
| 242 | + public boolean markSupported() { | |
| 243 | + return true; | |
| 244 | + } | |
| 245 | + | |
| 246 | + /** | |
| 247 | + * Set the current marked position in the stream. | |
| 248 | + * ByteArrayInputStream objects are marked at position zero by | |
| 249 | + * default when constructed. They may be marked at another | |
| 250 | + * position within the buffer by this method. | |
| 251 | + * <p> | |
| 252 | + * If no mark has been set, then the value of the mark is the | |
| 253 | + * offset passed to the constructor (or 0 if the offset was not | |
| 254 | + * supplied). | |
| 255 | + * | |
| 256 | + * <p> Note: The <code>readAheadLimit</code> for this class | |
| 257 | + * has no meaning. | |
| 258 | + * | |
| 259 | + * @since JDK1.1 | |
| 260 | + */ | |
| 261 | + public void mark(int readAheadLimit) { | |
| 262 | + mark = pos; | |
| 263 | + } | |
| 264 | + | |
| 265 | + /** | |
| 266 | + * Resets the buffer to the marked position. The marked position | |
| 267 | + * is 0 unless another position was marked or an offset was specified | |
| 268 | + * in the constructor. | |
| 269 | + */ | |
| 270 | + public synchronized void reset() { | |
| 271 | + pos = mark; | |
| 272 | + } | |
| 273 | + | |
| 274 | + /** | |
| 275 | + * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in | |
| 276 | + * this class can be called after the stream has been closed without | |
| 277 | + * generating an <tt>IOException</tt>. | |
| 278 | + * <p> | |
| 279 | + */ | |
| 280 | + public void close() throws IOException { | |
| 281 | + } | |
| 282 | + | |
| 283 | +} | |
Binary file not shown.
| @@ -0,0 +1,272 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.util.Arrays; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * This class implements an output stream in which the data is | |
| 32 | + * written into a byte array. The buffer automatically grows as data | |
| 33 | + * is written to it. | |
| 34 | + * The data can be retrieved using <code>toByteArray()</code> and | |
| 35 | + * <code>toString()</code>. | |
| 36 | + * <p> | |
| 37 | + * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in | |
| 38 | + * this class can be called after the stream has been closed without | |
| 39 | + * generating an <tt>IOException</tt>. | |
| 40 | + * | |
| 41 | + * @author Arthur van Hoff | |
| 42 | + * @since JDK1.0 | |
| 43 | + */ | |
| 44 | + | |
| 45 | +public class ByteArrayOutputStream extends OutputStream { | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * The buffer where data is stored. | |
| 49 | + */ | |
| 50 | + protected byte buf[]; | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * The number of valid bytes in the buffer. | |
| 54 | + */ | |
| 55 | + protected int count; | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * Creates a new byte array output stream. The buffer capacity is | |
| 59 | + * initially 32 bytes, though its size increases if necessary. | |
| 60 | + */ | |
| 61 | + public ByteArrayOutputStream() { | |
| 62 | + this(32); | |
| 63 | + } | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * Creates a new byte array output stream, with a buffer capacity of | |
| 67 | + * the specified size, in bytes. | |
| 68 | + * | |
| 69 | + * @param size the initial size. | |
| 70 | + * @exception IllegalArgumentException if size is negative. | |
| 71 | + */ | |
| 72 | + public ByteArrayOutputStream(int size) { | |
| 73 | + if (size < 0) { | |
| 74 | + throw new IllegalArgumentException("Negative initial size: " | |
| 75 | + + size); | |
| 76 | + } | |
| 77 | + buf = new byte[size]; | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * Increases the capacity if necessary to ensure that it can hold | |
| 82 | + * at least the number of elements specified by the minimum | |
| 83 | + * capacity argument. | |
| 84 | + * | |
| 85 | + * @param minCapacity the desired minimum capacity | |
| 86 | + * @throws OutOfMemoryError if {@code minCapacity < 0}. This is | |
| 87 | + * interpreted as a request for the unsatisfiably large capacity | |
| 88 | + * {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}. | |
| 89 | + */ | |
| 90 | + private void ensureCapacity(int minCapacity) { | |
| 91 | + // overflow-conscious code | |
| 92 | + if (minCapacity - buf.length > 0) | |
| 93 | + grow(minCapacity); | |
| 94 | + } | |
| 95 | + | |
| 96 | + /** | |
| 97 | + * Increases the capacity to ensure that it can hold at least the | |
| 98 | + * number of elements specified by the minimum capacity argument. | |
| 99 | + * | |
| 100 | + * @param minCapacity the desired minimum capacity | |
| 101 | + */ | |
| 102 | + private void grow(int minCapacity) { | |
| 103 | + // overflow-conscious code | |
| 104 | + int oldCapacity = buf.length; | |
| 105 | + int newCapacity = oldCapacity << 1; | |
| 106 | + if (newCapacity - minCapacity < 0) | |
| 107 | + newCapacity = minCapacity; | |
| 108 | + if (newCapacity < 0) { | |
| 109 | + if (minCapacity < 0) // overflow | |
| 110 | + throw new OutOfMemoryError(); | |
| 111 | + newCapacity = Integer.MAX_VALUE; | |
| 112 | + } | |
| 113 | + buf = Arrays.copyOf(buf, newCapacity); | |
| 114 | + } | |
| 115 | + | |
| 116 | + /** | |
| 117 | + * Writes the specified byte to this byte array output stream. | |
| 118 | + * | |
| 119 | + * @param b the byte to be written. | |
| 120 | + */ | |
| 121 | + public synchronized void write(int b) { | |
| 122 | + ensureCapacity(count + 1); | |
| 123 | + buf[count] = (byte) b; | |
| 124 | + count += 1; | |
| 125 | + } | |
| 126 | + | |
| 127 | + /** | |
| 128 | + * Writes <code>len</code> bytes from the specified byte array | |
| 129 | + * starting at offset <code>off</code> to this byte array output stream. | |
| 130 | + * | |
| 131 | + * @param b the data. | |
| 132 | + * @param off the start offset in the data. | |
| 133 | + * @param len the number of bytes to write. | |
| 134 | + */ | |
| 135 | + public synchronized void write(byte b[], int off, int len) { | |
| 136 | + if ((off < 0) || (off > b.length) || (len < 0) || | |
| 137 | + ((off + len) - b.length > 0)) { | |
| 138 | + throw new IndexOutOfBoundsException(); | |
| 139 | + } | |
| 140 | + ensureCapacity(count + len); | |
| 141 | + System.arraycopy(b, off, buf, count, len); | |
| 142 | + count += len; | |
| 143 | + } | |
| 144 | + | |
| 145 | + /** | |
| 146 | + * Writes the complete contents of this byte array output stream to | |
| 147 | + * the specified output stream argument, as if by calling the output | |
| 148 | + * stream's write method using <code>out.write(buf, 0, count)</code>. | |
| 149 | + * | |
| 150 | + * @param out the output stream to which to write the data. | |
| 151 | + * @exception IOException if an I/O error occurs. | |
| 152 | + */ | |
| 153 | + public synchronized void writeTo(OutputStream out) throws IOException { | |
| 154 | + out.write(buf, 0, count); | |
| 155 | + } | |
| 156 | + | |
| 157 | + /** | |
| 158 | + * Resets the <code>count</code> field of this byte array output | |
| 159 | + * stream to zero, so that all currently accumulated output in the | |
| 160 | + * output stream is discarded. The output stream can be used again, | |
| 161 | + * reusing the already allocated buffer space. | |
| 162 | + * | |
| 163 | + * @see java.io.ByteArrayInputStream#count | |
| 164 | + */ | |
| 165 | + public synchronized void reset() { | |
| 166 | + count = 0; | |
| 167 | + } | |
| 168 | + | |
| 169 | + /** | |
| 170 | + * Creates a newly allocated byte array. Its size is the current | |
| 171 | + * size of this output stream and the valid contents of the buffer | |
| 172 | + * have been copied into it. | |
| 173 | + * | |
| 174 | + * @return the current contents of this output stream, as a byte array. | |
| 175 | + * @see java.io.ByteArrayOutputStream#size() | |
| 176 | + */ | |
| 177 | + public synchronized byte toByteArray()[] { | |
| 178 | + return Arrays.copyOf(buf, count); | |
| 179 | + } | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * Returns the current size of the buffer. | |
| 183 | + * | |
| 184 | + * @return the value of the <code>count</code> field, which is the number | |
| 185 | + * of valid bytes in this output stream. | |
| 186 | + * @see java.io.ByteArrayOutputStream#count | |
| 187 | + */ | |
| 188 | + public synchronized int size() { | |
| 189 | + return count; | |
| 190 | + } | |
| 191 | + | |
| 192 | + /** | |
| 193 | + * Converts the buffer's contents into a string decoding bytes using the | |
| 194 | + * platform's default character set. The length of the new <tt>String</tt> | |
| 195 | + * is a function of the character set, and hence may not be equal to the | |
| 196 | + * size of the buffer. | |
| 197 | + * | |
| 198 | + * <p> This method always replaces malformed-input and unmappable-character | |
| 199 | + * sequences with the default replacement string for the platform's | |
| 200 | + * default character set. The {@linkplain java.nio.charset.CharsetDecoder} | |
| 201 | + * class should be used when more control over the decoding process is | |
| 202 | + * required. | |
| 203 | + * | |
| 204 | + * @return String decoded from the buffer's contents. | |
| 205 | + * @since JDK1.1 | |
| 206 | + */ | |
| 207 | + public synchronized String toString() { | |
| 208 | + return new String(buf, 0, count); | |
| 209 | + } | |
| 210 | + | |
| 211 | + /** | |
| 212 | + * Converts the buffer's contents into a string by decoding the bytes using | |
| 213 | + * the specified {@link java.nio.charset.Charset charsetName}. The length of | |
| 214 | + * the new <tt>String</tt> is a function of the charset, and hence may not be | |
| 215 | + * equal to the length of the byte array. | |
| 216 | + * | |
| 217 | + * <p> This method always replaces malformed-input and unmappable-character | |
| 218 | + * sequences with this charset's default replacement string. The {@link | |
| 219 | + * java.nio.charset.CharsetDecoder} class should be used when more control | |
| 220 | + * over the decoding process is required. | |
| 221 | + * | |
| 222 | + * @param charsetName the name of a supported | |
| 223 | + * {@linkplain java.nio.charset.Charset </code>charset<code>} | |
| 224 | + * @return String decoded from the buffer's contents. | |
| 225 | + * @exception UnsupportedEncodingException | |
| 226 | + * If the named charset is not supported | |
| 227 | + * @since JDK1.1 | |
| 228 | + */ | |
| 229 | + public synchronized String toString(String charsetName) | |
| 230 | + throws UnsupportedEncodingException | |
| 231 | + { | |
| 232 | + return new String(buf, 0, count, charsetName); | |
| 233 | + } | |
| 234 | + | |
| 235 | + /** | |
| 236 | + * Creates a newly allocated string. Its size is the current size of | |
| 237 | + * the output stream and the valid contents of the buffer have been | |
| 238 | + * copied into it. Each character <i>c</i> in the resulting string is | |
| 239 | + * constructed from the corresponding element <i>b</i> in the byte | |
| 240 | + * array such that: | |
| 241 | + * <blockquote><pre> | |
| 242 | + * c == (char)(((hibyte & 0xff) << 8) | (b & 0xff)) | |
| 243 | + * </pre></blockquote> | |
| 244 | + * | |
| 245 | + * @deprecated This method does not properly convert bytes into characters. | |
| 246 | + * As of JDK 1.1, the preferred way to do this is via the | |
| 247 | + * <code>toString(String enc)</code> method, which takes an encoding-name | |
| 248 | + * argument, or the <code>toString()</code> method, which uses the | |
| 249 | + * platform's default character encoding. | |
| 250 | + * | |
| 251 | + * @param hibyte the high byte of each resulting Unicode character. | |
| 252 | + * @return the current contents of the output stream, as a string. | |
| 253 | + * @see java.io.ByteArrayOutputStream#size() | |
| 254 | + * @see java.io.ByteArrayOutputStream#toString(String) | |
| 255 | + * @see java.io.ByteArrayOutputStream#toString() | |
| 256 | + */ | |
| 257 | + @Deprecated | |
| 258 | + public synchronized String toString(int hibyte) { | |
| 259 | + return new String(buf, hibyte, 0, count); | |
| 260 | + } | |
| 261 | + | |
| 262 | + /** | |
| 263 | + * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in | |
| 264 | + * this class can be called after the stream has been closed without | |
| 265 | + * generating an <tt>IOException</tt>. | |
| 266 | + * <p> | |
| 267 | + * | |
| 268 | + */ | |
| 269 | + public void close() throws IOException { | |
| 270 | + } | |
| 271 | + | |
| 272 | +} | |
Binary file not shown.
| @@ -0,0 +1,232 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class implements a character buffer that can be used as a | |
| 30 | + * character-input stream. | |
| 31 | + * | |
| 32 | + * @author Herb Jellinek | |
| 33 | + * @since JDK1.1 | |
| 34 | + */ | |
| 35 | +public class CharArrayReader extends Reader { | |
| 36 | + /** The character buffer. */ | |
| 37 | + protected char buf[]; | |
| 38 | + | |
| 39 | + /** The current buffer position. */ | |
| 40 | + protected int pos; | |
| 41 | + | |
| 42 | + /** The position of mark in buffer. */ | |
| 43 | + protected int markedPos = 0; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * The index of the end of this buffer. There is not valid | |
| 47 | + * data at or beyond this index. | |
| 48 | + */ | |
| 49 | + protected int count; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * Creates a CharArrayReader from the specified array of chars. | |
| 53 | + * @param buf Input buffer (not copied) | |
| 54 | + */ | |
| 55 | + public CharArrayReader(char buf[]) { | |
| 56 | + this.buf = buf; | |
| 57 | + this.pos = 0; | |
| 58 | + this.count = buf.length; | |
| 59 | + } | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * Creates a CharArrayReader from the specified array of chars. | |
| 63 | + * | |
| 64 | + * <p> The resulting reader will start reading at the given | |
| 65 | + * <tt>offset</tt>. The total number of <tt>char</tt> values that can be | |
| 66 | + * read from this reader will be either <tt>length</tt> or | |
| 67 | + * <tt>buf.length-offset</tt>, whichever is smaller. | |
| 68 | + * | |
| 69 | + * @throws IllegalArgumentException | |
| 70 | + * If <tt>offset</tt> is negative or greater than | |
| 71 | + * <tt>buf.length</tt>, or if <tt>length</tt> is negative, or if | |
| 72 | + * the sum of these two values is negative. | |
| 73 | + * | |
| 74 | + * @param buf Input buffer (not copied) | |
| 75 | + * @param offset Offset of the first char to read | |
| 76 | + * @param length Number of chars to read | |
| 77 | + */ | |
| 78 | + public CharArrayReader(char buf[], int offset, int length) { | |
| 79 | + if ((offset < 0) || (offset > buf.length) || (length < 0) || | |
| 80 | + ((offset + length) < 0)) { | |
| 81 | + throw new IllegalArgumentException(); | |
| 82 | + } | |
| 83 | + this.buf = buf; | |
| 84 | + this.pos = offset; | |
| 85 | + this.count = Math.min(offset + length, buf.length); | |
| 86 | + this.markedPos = offset; | |
| 87 | + } | |
| 88 | + | |
| 89 | + /** Checks to make sure that the stream has not been closed */ | |
| 90 | + private void ensureOpen() throws IOException { | |
| 91 | + if (buf == null) | |
| 92 | + throw new IOException("Stream closed"); | |
| 93 | + } | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * Reads a single character. | |
| 97 | + * | |
| 98 | + * @exception IOException If an I/O error occurs | |
| 99 | + */ | |
| 100 | + public int read() throws IOException { | |
| 101 | + synchronized (lock) { | |
| 102 | + ensureOpen(); | |
| 103 | + if (pos >= count) | |
| 104 | + return -1; | |
| 105 | + else | |
| 106 | + return buf[pos++]; | |
| 107 | + } | |
| 108 | + } | |
| 109 | + | |
| 110 | + /** | |
| 111 | + * Reads characters into a portion of an array. | |
| 112 | + * @param b Destination buffer | |
| 113 | + * @param off Offset at which to start storing characters | |
| 114 | + * @param len Maximum number of characters to read | |
| 115 | + * @return The actual number of characters read, or -1 if | |
| 116 | + * the end of the stream has been reached | |
| 117 | + * | |
| 118 | + * @exception IOException If an I/O error occurs | |
| 119 | + */ | |
| 120 | + public int read(char b[], int off, int len) throws IOException { | |
| 121 | + synchronized (lock) { | |
| 122 | + ensureOpen(); | |
| 123 | + if ((off < 0) || (off > b.length) || (len < 0) || | |
| 124 | + ((off + len) > b.length) || ((off + len) < 0)) { | |
| 125 | + throw new IndexOutOfBoundsException(); | |
| 126 | + } else if (len == 0) { | |
| 127 | + return 0; | |
| 128 | + } | |
| 129 | + | |
| 130 | + if (pos >= count) { | |
| 131 | + return -1; | |
| 132 | + } | |
| 133 | + if (pos + len > count) { | |
| 134 | + len = count - pos; | |
| 135 | + } | |
| 136 | + if (len <= 0) { | |
| 137 | + return 0; | |
| 138 | + } | |
| 139 | + System.arraycopy(buf, pos, b, off, len); | |
| 140 | + pos += len; | |
| 141 | + return len; | |
| 142 | + } | |
| 143 | + } | |
| 144 | + | |
| 145 | + /** | |
| 146 | + * Skips characters. Returns the number of characters that were skipped. | |
| 147 | + * | |
| 148 | + * <p>The <code>n</code> parameter may be negative, even though the | |
| 149 | + * <code>skip</code> method of the {@link Reader} superclass throws | |
| 150 | + * an exception in this case. If <code>n</code> is negative, then | |
| 151 | + * this method does nothing and returns <code>0</code>. | |
| 152 | + * | |
| 153 | + * @param n The number of characters to skip | |
| 154 | + * @return The number of characters actually skipped | |
| 155 | + * @exception IOException If the stream is closed, or an I/O error occurs | |
| 156 | + */ | |
| 157 | + public long skip(long n) throws IOException { | |
| 158 | + synchronized (lock) { | |
| 159 | + ensureOpen(); | |
| 160 | + if (pos + n > count) { | |
| 161 | + n = count - pos; | |
| 162 | + } | |
| 163 | + if (n < 0) { | |
| 164 | + return 0; | |
| 165 | + } | |
| 166 | + pos += n; | |
| 167 | + return n; | |
| 168 | + } | |
| 169 | + } | |
| 170 | + | |
| 171 | + /** | |
| 172 | + * Tells whether this stream is ready to be read. Character-array readers | |
| 173 | + * are always ready to be read. | |
| 174 | + * | |
| 175 | + * @exception IOException If an I/O error occurs | |
| 176 | + */ | |
| 177 | + public boolean ready() throws IOException { | |
| 178 | + synchronized (lock) { | |
| 179 | + ensureOpen(); | |
| 180 | + return (count - pos) > 0; | |
| 181 | + } | |
| 182 | + } | |
| 183 | + | |
| 184 | + /** | |
| 185 | + * Tells whether this stream supports the mark() operation, which it does. | |
| 186 | + */ | |
| 187 | + public boolean markSupported() { | |
| 188 | + return true; | |
| 189 | + } | |
| 190 | + | |
| 191 | + /** | |
| 192 | + * Marks the present position in the stream. Subsequent calls to reset() | |
| 193 | + * will reposition the stream to this point. | |
| 194 | + * | |
| 195 | + * @param readAheadLimit Limit on the number of characters that may be | |
| 196 | + * read while still preserving the mark. Because | |
| 197 | + * the stream's input comes from a character array, | |
| 198 | + * there is no actual limit; hence this argument is | |
| 199 | + * ignored. | |
| 200 | + * | |
| 201 | + * @exception IOException If an I/O error occurs | |
| 202 | + */ | |
| 203 | + public void mark(int readAheadLimit) throws IOException { | |
| 204 | + synchronized (lock) { | |
| 205 | + ensureOpen(); | |
| 206 | + markedPos = pos; | |
| 207 | + } | |
| 208 | + } | |
| 209 | + | |
| 210 | + /** | |
| 211 | + * Resets the stream to the most recent mark, or to the beginning if it has | |
| 212 | + * never been marked. | |
| 213 | + * | |
| 214 | + * @exception IOException If an I/O error occurs | |
| 215 | + */ | |
| 216 | + public void reset() throws IOException { | |
| 217 | + synchronized (lock) { | |
| 218 | + ensureOpen(); | |
| 219 | + pos = markedPos; | |
| 220 | + } | |
| 221 | + } | |
| 222 | + | |
| 223 | + /** | |
| 224 | + * Closes the stream and releases any system resources associated with | |
| 225 | + * it. Once the stream has been closed, further read(), ready(), | |
| 226 | + * mark(), reset(), or skip() invocations will throw an IOException. | |
| 227 | + * Closing a previously closed stream has no effect. | |
| 228 | + */ | |
| 229 | + public void close() { | |
| 230 | + buf = null; | |
| 231 | + } | |
| 232 | +} | |
Binary file not shown.
| @@ -0,0 +1,280 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.util.Arrays; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * This class implements a character buffer that can be used as an Writer. | |
| 32 | + * The buffer automatically grows when data is written to the stream. The data | |
| 33 | + * can be retrieved using toCharArray() and toString(). | |
| 34 | + * <P> | |
| 35 | + * Note: Invoking close() on this class has no effect, and methods | |
| 36 | + * of this class can be called after the stream has closed | |
| 37 | + * without generating an IOException. | |
| 38 | + * | |
| 39 | + * @author Herb Jellinek | |
| 40 | + * @since JDK1.1 | |
| 41 | + */ | |
| 42 | +public | |
| 43 | +class CharArrayWriter extends Writer { | |
| 44 | + /** | |
| 45 | + * The buffer where data is stored. | |
| 46 | + */ | |
| 47 | + protected char buf[]; | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * The number of chars in the buffer. | |
| 51 | + */ | |
| 52 | + protected int count; | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * Creates a new CharArrayWriter. | |
| 56 | + */ | |
| 57 | + public CharArrayWriter() { | |
| 58 | + this(32); | |
| 59 | + } | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * Creates a new CharArrayWriter with the specified initial size. | |
| 63 | + * | |
| 64 | + * @param initialSize an int specifying the initial buffer size. | |
| 65 | + * @exception IllegalArgumentException if initialSize is negative | |
| 66 | + */ | |
| 67 | + public CharArrayWriter(int initialSize) { | |
| 68 | + if (initialSize < 0) { | |
| 69 | + throw new IllegalArgumentException("Negative initial size: " | |
| 70 | + + initialSize); | |
| 71 | + } | |
| 72 | + buf = new char[initialSize]; | |
| 73 | + } | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * Writes a character to the buffer. | |
| 77 | + */ | |
| 78 | + public void write(int c) { | |
| 79 | + synchronized (lock) { | |
| 80 | + int newcount = count + 1; | |
| 81 | + if (newcount > buf.length) { | |
| 82 | + buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount)); | |
| 83 | + } | |
| 84 | + buf[count] = (char)c; | |
| 85 | + count = newcount; | |
| 86 | + } | |
| 87 | + } | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * Writes characters to the buffer. | |
| 91 | + * @param c the data to be written | |
| 92 | + * @param off the start offset in the data | |
| 93 | + * @param len the number of chars that are written | |
| 94 | + */ | |
| 95 | + public void write(char c[], int off, int len) { | |
| 96 | + if ((off < 0) || (off > c.length) || (len < 0) || | |
| 97 | + ((off + len) > c.length) || ((off + len) < 0)) { | |
| 98 | + throw new IndexOutOfBoundsException(); | |
| 99 | + } else if (len == 0) { | |
| 100 | + return; | |
| 101 | + } | |
| 102 | + synchronized (lock) { | |
| 103 | + int newcount = count + len; | |
| 104 | + if (newcount > buf.length) { | |
| 105 | + buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount)); | |
| 106 | + } | |
| 107 | + System.arraycopy(c, off, buf, count, len); | |
| 108 | + count = newcount; | |
| 109 | + } | |
| 110 | + } | |
| 111 | + | |
| 112 | + /** | |
| 113 | + * Write a portion of a string to the buffer. | |
| 114 | + * @param str String to be written from | |
| 115 | + * @param off Offset from which to start reading characters | |
| 116 | + * @param len Number of characters to be written | |
| 117 | + */ | |
| 118 | + public void write(String str, int off, int len) { | |
| 119 | + synchronized (lock) { | |
| 120 | + int newcount = count + len; | |
| 121 | + if (newcount > buf.length) { | |
| 122 | + buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount)); | |
| 123 | + } | |
| 124 | + str.getChars(off, off + len, buf, count); | |
| 125 | + count = newcount; | |
| 126 | + } | |
| 127 | + } | |
| 128 | + | |
| 129 | + /** | |
| 130 | + * Writes the contents of the buffer to another character stream. | |
| 131 | + * | |
| 132 | + * @param out the output stream to write to | |
| 133 | + * @throws IOException If an I/O error occurs. | |
| 134 | + */ | |
| 135 | + public void writeTo(Writer out) throws IOException { | |
| 136 | + synchronized (lock) { | |
| 137 | + out.write(buf, 0, count); | |
| 138 | + } | |
| 139 | + } | |
| 140 | + | |
| 141 | + /** | |
| 142 | + * Appends the specified character sequence to this writer. | |
| 143 | + * | |
| 144 | + * <p> An invocation of this method of the form <tt>out.append(csq)</tt> | |
| 145 | + * behaves in exactly the same way as the invocation | |
| 146 | + * | |
| 147 | + * <pre> | |
| 148 | + * out.write(csq.toString()) </pre> | |
| 149 | + * | |
| 150 | + * <p> Depending on the specification of <tt>toString</tt> for the | |
| 151 | + * character sequence <tt>csq</tt>, the entire sequence may not be | |
| 152 | + * appended. For instance, invoking the <tt>toString</tt> method of a | |
| 153 | + * character buffer will return a subsequence whose content depends upon | |
| 154 | + * the buffer's position and limit. | |
| 155 | + * | |
| 156 | + * @param csq | |
| 157 | + * The character sequence to append. If <tt>csq</tt> is | |
| 158 | + * <tt>null</tt>, then the four characters <tt>"null"</tt> are | |
| 159 | + * appended to this writer. | |
| 160 | + * | |
| 161 | + * @return This writer | |
| 162 | + * | |
| 163 | + * @since 1.5 | |
| 164 | + */ | |
| 165 | + public CharArrayWriter append(CharSequence csq) { | |
| 166 | + String s = (csq == null ? "null" : csq.toString()); | |
| 167 | + write(s, 0, s.length()); | |
| 168 | + return this; | |
| 169 | + } | |
| 170 | + | |
| 171 | + /** | |
| 172 | + * Appends a subsequence of the specified character sequence to this writer. | |
| 173 | + * | |
| 174 | + * <p> An invocation of this method of the form <tt>out.append(csq, start, | |
| 175 | + * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in | |
| 176 | + * exactly the same way as the invocation | |
| 177 | + * | |
| 178 | + * <pre> | |
| 179 | + * out.write(csq.subSequence(start, end).toString()) </pre> | |
| 180 | + * | |
| 181 | + * @param csq | |
| 182 | + * The character sequence from which a subsequence will be | |
| 183 | + * appended. If <tt>csq</tt> is <tt>null</tt>, then characters | |
| 184 | + * will be appended as if <tt>csq</tt> contained the four | |
| 185 | + * characters <tt>"null"</tt>. | |
| 186 | + * | |
| 187 | + * @param start | |
| 188 | + * The index of the first character in the subsequence | |
| 189 | + * | |
| 190 | + * @param end | |
| 191 | + * The index of the character following the last character in the | |
| 192 | + * subsequence | |
| 193 | + * | |
| 194 | + * @return This writer | |
| 195 | + * | |
| 196 | + * @throws IndexOutOfBoundsException | |
| 197 | + * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt> | |
| 198 | + * is greater than <tt>end</tt>, or <tt>end</tt> is greater than | |
| 199 | + * <tt>csq.length()</tt> | |
| 200 | + * | |
| 201 | + * @since 1.5 | |
| 202 | + */ | |
| 203 | + public CharArrayWriter append(CharSequence csq, int start, int end) { | |
| 204 | + String s = (csq == null ? "null" : csq).subSequence(start, end).toString(); | |
| 205 | + write(s, 0, s.length()); | |
| 206 | + return this; | |
| 207 | + } | |
| 208 | + | |
| 209 | + /** | |
| 210 | + * Appends the specified character to this writer. | |
| 211 | + * | |
| 212 | + * <p> An invocation of this method of the form <tt>out.append(c)</tt> | |
| 213 | + * behaves in exactly the same way as the invocation | |
| 214 | + * | |
| 215 | + * <pre> | |
| 216 | + * out.write(c) </pre> | |
| 217 | + * | |
| 218 | + * @param c | |
| 219 | + * The 16-bit character to append | |
| 220 | + * | |
| 221 | + * @return This writer | |
| 222 | + * | |
| 223 | + * @since 1.5 | |
| 224 | + */ | |
| 225 | + public CharArrayWriter append(char c) { | |
| 226 | + write(c); | |
| 227 | + return this; | |
| 228 | + } | |
| 229 | + | |
| 230 | + /** | |
| 231 | + * Resets the buffer so that you can use it again without | |
| 232 | + * throwing away the already allocated buffer. | |
| 233 | + */ | |
| 234 | + public void reset() { | |
| 235 | + count = 0; | |
| 236 | + } | |
| 237 | + | |
| 238 | + /** | |
| 239 | + * Returns a copy of the input data. | |
| 240 | + * | |
| 241 | + * @return an array of chars copied from the input data. | |
| 242 | + */ | |
| 243 | + public char toCharArray()[] { | |
| 244 | + synchronized (lock) { | |
| 245 | + return Arrays.copyOf(buf, count); | |
| 246 | + } | |
| 247 | + } | |
| 248 | + | |
| 249 | + /** | |
| 250 | + * Returns the current size of the buffer. | |
| 251 | + * | |
| 252 | + * @return an int representing the current size of the buffer. | |
| 253 | + */ | |
| 254 | + public int size() { | |
| 255 | + return count; | |
| 256 | + } | |
| 257 | + | |
| 258 | + /** | |
| 259 | + * Converts input data to a string. | |
| 260 | + * @return the string. | |
| 261 | + */ | |
| 262 | + public String toString() { | |
| 263 | + synchronized (lock) { | |
| 264 | + return new String(buf, 0, count); | |
| 265 | + } | |
| 266 | + } | |
| 267 | + | |
| 268 | + /** | |
| 269 | + * Flush the stream. | |
| 270 | + */ | |
| 271 | + public void flush() { } | |
| 272 | + | |
| 273 | + /** | |
| 274 | + * Close the stream. This method does not release the buffer, since its | |
| 275 | + * contents might still be required. Note: Invoking this method in this class | |
| 276 | + * will have no effect. | |
| 277 | + */ | |
| 278 | + public void close() { } | |
| 279 | + | |
| 280 | +} | |
Binary file not shown.
| @@ -0,0 +1,51 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | +package java.io; | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * Base class for character conversion exceptions. | |
| 29 | + * | |
| 30 | + * @author Asmus Freytag | |
| 31 | + * @since JDK1.1 | |
| 32 | + */ | |
| 33 | +public class CharConversionException | |
| 34 | + extends java.io.IOException | |
| 35 | +{ | |
| 36 | + private static final long serialVersionUID = -8680016352018427031L; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * This provides no detailed message. | |
| 40 | + */ | |
| 41 | + public CharConversionException() { | |
| 42 | + } | |
| 43 | + /** | |
| 44 | + * This provides a detailed message. | |
| 45 | + * | |
| 46 | + * @param s the detailed message associated with the exception. | |
| 47 | + */ | |
| 48 | + public CharConversionException(String s) { | |
| 49 | + super(s); | |
| 50 | + } | |
| 51 | +} | |
Binary file not shown.
| @@ -0,0 +1,48 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * A {@code Closeable} is a source or destination of data that can be closed. | |
| 32 | + * The close method is invoked to release resources that the object is | |
| 33 | + * holding (such as open files). | |
| 34 | + * | |
| 35 | + * @since 1.5 | |
| 36 | + */ | |
| 37 | + | |
| 38 | +public interface Closeable extends AutoCloseable { | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * Closes this stream and releases any system resources associated | |
| 42 | + * with it. If the stream is already closed then invoking this | |
| 43 | + * method has no effect. | |
| 44 | + * | |
| 45 | + * @throws IOException if an I/O error occurs | |
| 46 | + */ | |
| 47 | + public void close() throws IOException; | |
| 48 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,578 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.util.*; | |
| 29 | +import java.nio.charset.Charset; | |
| 30 | +import sun.nio.cs.StreamDecoder; | |
| 31 | +import sun.nio.cs.StreamEncoder; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * Methods to access the character-based console device, if any, associated | |
| 35 | + * with the current Java virtual machine. | |
| 36 | + * | |
| 37 | + * <p> Whether a virtual machine has a console is dependent upon the | |
| 38 | + * underlying platform and also upon the manner in which the virtual | |
| 39 | + * machine is invoked. If the virtual machine is started from an | |
| 40 | + * interactive command line without redirecting the standard input and | |
| 41 | + * output streams then its console will exist and will typically be | |
| 42 | + * connected to the keyboard and display from which the virtual machine | |
| 43 | + * was launched. If the virtual machine is started automatically, for | |
| 44 | + * example by a background job scheduler, then it will typically not | |
| 45 | + * have a console. | |
| 46 | + * <p> | |
| 47 | + * If this virtual machine has a console then it is represented by a | |
| 48 | + * unique instance of this class which can be obtained by invoking the | |
| 49 | + * {@link java.lang.System#console()} method. If no console device is | |
| 50 | + * available then an invocation of that method will return <tt>null</tt>. | |
| 51 | + * <p> | |
| 52 | + * Read and write operations are synchronized to guarantee the atomic | |
| 53 | + * completion of critical operations; therefore invoking methods | |
| 54 | + * {@link #readLine()}, {@link #readPassword()}, {@link #format format()}, | |
| 55 | + * {@link #printf printf()} as well as the read, format and write operations | |
| 56 | + * on the objects returned by {@link #reader()} and {@link #writer()} may | |
| 57 | + * block in multithreaded scenarios. | |
| 58 | + * <p> | |
| 59 | + * Invoking <tt>close()</tt> on the objects returned by the {@link #reader()} | |
| 60 | + * and the {@link #writer()} will not close the underlying stream of those | |
| 61 | + * objects. | |
| 62 | + * <p> | |
| 63 | + * The console-read methods return <tt>null</tt> when the end of the | |
| 64 | + * console input stream is reached, for example by typing control-D on | |
| 65 | + * Unix or control-Z on Windows. Subsequent read operations will succeed | |
| 66 | + * if additional characters are later entered on the console's input | |
| 67 | + * device. | |
| 68 | + * <p> | |
| 69 | + * Unless otherwise specified, passing a <tt>null</tt> argument to any method | |
| 70 | + * in this class will cause a {@link NullPointerException} to be thrown. | |
| 71 | + * <p> | |
| 72 | + * <b>Security note:</b> | |
| 73 | + * If an application needs to read a password or other secure data, it should | |
| 74 | + * use {@link #readPassword()} or {@link #readPassword(String, Object...)} and | |
| 75 | + * manually zero the returned character array after processing to minimize the | |
| 76 | + * lifetime of sensitive data in memory. | |
| 77 | + * | |
| 78 | + * <blockquote><pre> | |
| 79 | + * Console cons; | |
| 80 | + * char[] passwd; | |
| 81 | + * if ((cons = System.console()) != null && | |
| 82 | + * (passwd = cons.readPassword("[%s]", "Password:")) != null) { | |
| 83 | + * ... | |
| 84 | + * java.util.Arrays.fill(passwd, ' '); | |
| 85 | + * } | |
| 86 | + * </pre></blockquote> | |
| 87 | + * | |
| 88 | + * @author Xueming Shen | |
| 89 | + * @since 1.6 | |
| 90 | + */ | |
| 91 | + | |
| 92 | +public final class Console implements Flushable | |
| 93 | +{ | |
| 94 | + /** | |
| 95 | + * Retrieves the unique {@link java.io.PrintWriter PrintWriter} object | |
| 96 | + * associated with this console. | |
| 97 | + * | |
| 98 | + * @return The printwriter associated with this console | |
| 99 | + */ | |
| 100 | + public PrintWriter writer() { | |
| 101 | + return pw; | |
| 102 | + } | |
| 103 | + | |
| 104 | + /** | |
| 105 | + * Retrieves the unique {@link java.io.Reader Reader} object associated | |
| 106 | + * with this console. | |
| 107 | + * <p> | |
| 108 | + * This method is intended to be used by sophisticated applications, for | |
| 109 | + * example, a {@link java.util.Scanner} object which utilizes the rich | |
| 110 | + * parsing/scanning functionality provided by the <tt>Scanner</tt>: | |
| 111 | + * <blockquote><pre> | |
| 112 | + * Console con = System.console(); | |
| 113 | + * if (con != null) { | |
| 114 | + * Scanner sc = new Scanner(con.reader()); | |
| 115 | + * ... | |
| 116 | + * } | |
| 117 | + * </pre></blockquote> | |
| 118 | + * <p> | |
| 119 | + * For simple applications requiring only line-oriented reading, use | |
| 120 | + * <tt>{@link #readLine}</tt>. | |
| 121 | + * <p> | |
| 122 | + * The bulk read operations {@link java.io.Reader#read(char[]) read(char[]) }, | |
| 123 | + * {@link java.io.Reader#read(char[], int, int) read(char[], int, int) } and | |
| 124 | + * {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)} | |
| 125 | + * on the returned object will not read in characters beyond the line | |
| 126 | + * bound for each invocation, even if the destination buffer has space for | |
| 127 | + * more characters. A line bound is considered to be any one of a line feed | |
| 128 | + * (<tt>'\n'</tt>), a carriage return (<tt>'\r'</tt>), a carriage return | |
| 129 | + * followed immediately by a linefeed, or an end of stream. | |
| 130 | + * | |
| 131 | + * @return The reader associated with this console | |
| 132 | + */ | |
| 133 | + public Reader reader() { | |
| 134 | + return reader; | |
| 135 | + } | |
| 136 | + | |
| 137 | + /** | |
| 138 | + * Writes a formatted string to this console's output stream using | |
| 139 | + * the specified format string and arguments. | |
| 140 | + * | |
| 141 | + * @param fmt | |
| 142 | + * A format string as described in <a | |
| 143 | + * href="../util/Formatter.html#syntax">Format string syntax</a> | |
| 144 | + * | |
| 145 | + * @param args | |
| 146 | + * Arguments referenced by the format specifiers in the format | |
| 147 | + * string. If there are more arguments than format specifiers, the | |
| 148 | + * extra arguments are ignored. The number of arguments is | |
| 149 | + * variable and may be zero. The maximum number of arguments is | |
| 150 | + * limited by the maximum dimension of a Java array as defined by | |
| 151 | + * <cite>The Java™ Virtual Machine Specification</cite>. | |
| 152 | + * The behaviour on a | |
| 153 | + * <tt>null</tt> argument depends on the <a | |
| 154 | + * href="../util/Formatter.html#syntax">conversion</a>. | |
| 155 | + * | |
| 156 | + * @throws IllegalFormatException | |
| 157 | + * If a format string contains an illegal syntax, a format | |
| 158 | + * specifier that is incompatible with the given arguments, | |
| 159 | + * insufficient arguments given the format string, or other | |
| 160 | + * illegal conditions. For specification of all possible | |
| 161 | + * formatting errors, see the <a | |
| 162 | + * href="../util/Formatter.html#detail">Details</a> section | |
| 163 | + * of the formatter class specification. | |
| 164 | + * | |
| 165 | + * @return This console | |
| 166 | + */ | |
| 167 | + public Console format(String fmt, Object ...args) { | |
| 168 | + formatter.format(fmt, args).flush(); | |
| 169 | + return this; | |
| 170 | + } | |
| 171 | + | |
| 172 | + /** | |
| 173 | + * A convenience method to write a formatted string to this console's | |
| 174 | + * output stream using the specified format string and arguments. | |
| 175 | + * | |
| 176 | + * <p> An invocation of this method of the form <tt>con.printf(format, | |
| 177 | + * args)</tt> behaves in exactly the same way as the invocation of | |
| 178 | + * <pre>con.format(format, args)</pre>. | |
| 179 | + * | |
| 180 | + * @param format | |
| 181 | + * A format string as described in <a | |
| 182 | + * href="../util/Formatter.html#syntax">Format string syntax</a>. | |
| 183 | + * | |
| 184 | + * @param args | |
| 185 | + * Arguments referenced by the format specifiers in the format | |
| 186 | + * string. If there are more arguments than format specifiers, the | |
| 187 | + * extra arguments are ignored. The number of arguments is | |
| 188 | + * variable and may be zero. The maximum number of arguments is | |
| 189 | + * limited by the maximum dimension of a Java array as defined by | |
| 190 | + * <cite>The Java™ Virtual Machine Specification</cite>. | |
| 191 | + * The behaviour on a | |
| 192 | + * <tt>null</tt> argument depends on the <a | |
| 193 | + * href="../util/Formatter.html#syntax">conversion</a>. | |
| 194 | + * | |
| 195 | + * @throws IllegalFormatException | |
| 196 | + * If a format string contains an illegal syntax, a format | |
| 197 | + * specifier that is incompatible with the given arguments, | |
| 198 | + * insufficient arguments given the format string, or other | |
| 199 | + * illegal conditions. For specification of all possible | |
| 200 | + * formatting errors, see the <a | |
| 201 | + * href="../util/Formatter.html#detail">Details</a> section of the | |
| 202 | + * formatter class specification. | |
| 203 | + * | |
| 204 | + * @return This console | |
| 205 | + */ | |
| 206 | + public Console printf(String format, Object ... args) { | |
| 207 | + return format(format, args); | |
| 208 | + } | |
| 209 | + | |
| 210 | + /** | |
| 211 | + * Provides a formatted prompt, then reads a single line of text from the | |
| 212 | + * console. | |
| 213 | + * | |
| 214 | + * @param fmt | |
| 215 | + * A format string as described in <a | |
| 216 | + * href="../util/Formatter.html#syntax">Format string syntax</a>. | |
| 217 | + * | |
| 218 | + * @param args | |
| 219 | + * Arguments referenced by the format specifiers in the format | |
| 220 | + * string. If there are more arguments than format specifiers, the | |
| 221 | + * extra arguments are ignored. The maximum number of arguments is | |
| 222 | + * limited by the maximum dimension of a Java array as defined by | |
| 223 | + * <cite>The Java™ Virtual Machine Specification</cite>. | |
| 224 | + * | |
| 225 | + * @throws IllegalFormatException | |
| 226 | + * If a format string contains an illegal syntax, a format | |
| 227 | + * specifier that is incompatible with the given arguments, | |
| 228 | + * insufficient arguments given the format string, or other | |
| 229 | + * illegal conditions. For specification of all possible | |
| 230 | + * formatting errors, see the <a | |
| 231 | + * href="../util/Formatter.html#detail">Details</a> section | |
| 232 | + * of the formatter class specification. | |
| 233 | + * | |
| 234 | + * @throws IOError | |
| 235 | + * If an I/O error occurs. | |
| 236 | + * | |
| 237 | + * @return A string containing the line read from the console, not | |
| 238 | + * including any line-termination characters, or <tt>null</tt> | |
| 239 | + * if an end of stream has been reached. | |
| 240 | + */ | |
| 241 | + public String readLine(String fmt, Object ... args) { | |
| 242 | + String line = null; | |
| 243 | + synchronized (writeLock) { | |
| 244 | + synchronized(readLock) { | |
| 245 | + if (fmt.length() != 0) | |
| 246 | + pw.format(fmt, args); | |
| 247 | + try { | |
| 248 | + char[] ca = readline(false); | |
| 249 | + if (ca != null) | |
| 250 | + line = new String(ca); | |
| 251 | + } catch (IOException x) { | |
| 252 | + throw new IOError(x); | |
| 253 | + } | |
| 254 | + } | |
| 255 | + } | |
| 256 | + return line; | |
| 257 | + } | |
| 258 | + | |
| 259 | + /** | |
| 260 | + * Reads a single line of text from the console. | |
| 261 | + * | |
| 262 | + * @throws IOError | |
| 263 | + * If an I/O error occurs. | |
| 264 | + * | |
| 265 | + * @return A string containing the line read from the console, not | |
| 266 | + * including any line-termination characters, or <tt>null</tt> | |
| 267 | + * if an end of stream has been reached. | |
| 268 | + */ | |
| 269 | + public String readLine() { | |
| 270 | + return readLine(""); | |
| 271 | + } | |
| 272 | + | |
| 273 | + /** | |
| 274 | + * Provides a formatted prompt, then reads a password or passphrase from | |
| 275 | + * the console with echoing disabled. | |
| 276 | + * | |
| 277 | + * @param fmt | |
| 278 | + * A format string as described in <a | |
| 279 | + * href="../util/Formatter.html#syntax">Format string syntax</a> | |
| 280 | + * for the prompt text. | |
| 281 | + * | |
| 282 | + * @param args | |
| 283 | + * Arguments referenced by the format specifiers in the format | |
| 284 | + * string. If there are more arguments than format specifiers, the | |
| 285 | + * extra arguments are ignored. The maximum number of arguments is | |
| 286 | + * limited by the maximum dimension of a Java array as defined by | |
| 287 | + * <cite>The Java™ Virtual Machine Specification</cite>. | |
| 288 | + * | |
| 289 | + * @throws IllegalFormatException | |
| 290 | + * If a format string contains an illegal syntax, a format | |
| 291 | + * specifier that is incompatible with the given arguments, | |
| 292 | + * insufficient arguments given the format string, or other | |
| 293 | + * illegal conditions. For specification of all possible | |
| 294 | + * formatting errors, see the <a | |
| 295 | + * href="../util/Formatter.html#detail">Details</a> | |
| 296 | + * section of the formatter class specification. | |
| 297 | + * | |
| 298 | + * @throws IOError | |
| 299 | + * If an I/O error occurs. | |
| 300 | + * | |
| 301 | + * @return A character array containing the password or passphrase read | |
| 302 | + * from the console, not including any line-termination characters, | |
| 303 | + * or <tt>null</tt> if an end of stream has been reached. | |
| 304 | + */ | |
| 305 | + public char[] readPassword(String fmt, Object ... args) { | |
| 306 | + char[] passwd = null; | |
| 307 | + synchronized (writeLock) { | |
| 308 | + synchronized(readLock) { | |
| 309 | + try { | |
| 310 | + echoOff = echo(false); | |
| 311 | + } catch (IOException x) { | |
| 312 | + throw new IOError(x); | |
| 313 | + } | |
| 314 | + IOError ioe = null; | |
| 315 | + try { | |
| 316 | + if (fmt.length() != 0) | |
| 317 | + pw.format(fmt, args); | |
| 318 | + passwd = readline(true); | |
| 319 | + } catch (IOException x) { | |
| 320 | + ioe = new IOError(x); | |
| 321 | + } finally { | |
| 322 | + try { | |
| 323 | + echoOff = echo(true); | |
| 324 | + } catch (IOException x) { | |
| 325 | + if (ioe == null) | |
| 326 | + ioe = new IOError(x); | |
| 327 | + else | |
| 328 | + ioe.addSuppressed(x); | |
| 329 | + } | |
| 330 | + if (ioe != null) | |
| 331 | + throw ioe; | |
| 332 | + } | |
| 333 | + pw.println(); | |
| 334 | + } | |
| 335 | + } | |
| 336 | + return passwd; | |
| 337 | + } | |
| 338 | + | |
| 339 | + /** | |
| 340 | + * Reads a password or passphrase from the console with echoing disabled | |
| 341 | + * | |
| 342 | + * @throws IOError | |
| 343 | + * If an I/O error occurs. | |
| 344 | + * | |
| 345 | + * @return A character array containing the password or passphrase read | |
| 346 | + * from the console, not including any line-termination characters, | |
| 347 | + * or <tt>null</tt> if an end of stream has been reached. | |
| 348 | + */ | |
| 349 | + public char[] readPassword() { | |
| 350 | + return readPassword(""); | |
| 351 | + } | |
| 352 | + | |
| 353 | + /** | |
| 354 | + * Flushes the console and forces any buffered output to be written | |
| 355 | + * immediately . | |
| 356 | + */ | |
| 357 | + public void flush() { | |
| 358 | + pw.flush(); | |
| 359 | + } | |
| 360 | + | |
| 361 | + private Object readLock; | |
| 362 | + private Object writeLock; | |
| 363 | + private Reader reader; | |
| 364 | + private Writer out; | |
| 365 | + private PrintWriter pw; | |
| 366 | + private Formatter formatter; | |
| 367 | + private Charset cs; | |
| 368 | + private char[] rcb; | |
| 369 | + private static native String encoding(); | |
| 370 | + private static native boolean echo(boolean on) throws IOException; | |
| 371 | + private static boolean echoOff; | |
| 372 | + | |
| 373 | + private char[] readline(boolean zeroOut) throws IOException { | |
| 374 | + int len = reader.read(rcb, 0, rcb.length); | |
| 375 | + if (len < 0) | |
| 376 | + return null; //EOL | |
| 377 | + if (rcb[len-1] == '\r') | |
| 378 | + len--; //remove CR at end; | |
| 379 | + else if (rcb[len-1] == '\n') { | |
| 380 | + len--; //remove LF at end; | |
| 381 | + if (len > 0 && rcb[len-1] == '\r') | |
| 382 | + len--; //remove the CR, if there is one | |
| 383 | + } | |
| 384 | + char[] b = new char[len]; | |
| 385 | + if (len > 0) { | |
| 386 | + System.arraycopy(rcb, 0, b, 0, len); | |
| 387 | + if (zeroOut) { | |
| 388 | + Arrays.fill(rcb, 0, len, ' '); | |
| 389 | + } | |
| 390 | + } | |
| 391 | + return b; | |
| 392 | + } | |
| 393 | + | |
| 394 | + private char[] grow() { | |
| 395 | + assert Thread.holdsLock(readLock); | |
| 396 | + char[] t = new char[rcb.length * 2]; | |
| 397 | + System.arraycopy(rcb, 0, t, 0, rcb.length); | |
| 398 | + rcb = t; | |
| 399 | + return rcb; | |
| 400 | + } | |
| 401 | + | |
| 402 | + class LineReader extends Reader { | |
| 403 | + private Reader in; | |
| 404 | + private char[] cb; | |
| 405 | + private int nChars, nextChar; | |
| 406 | + boolean leftoverLF; | |
| 407 | + LineReader(Reader in) { | |
| 408 | + this.in = in; | |
| 409 | + cb = new char[1024]; | |
| 410 | + nextChar = nChars = 0; | |
| 411 | + leftoverLF = false; | |
| 412 | + } | |
| 413 | + public void close () {} | |
| 414 | + public boolean ready() throws IOException { | |
| 415 | + //in.ready synchronizes on readLock already | |
| 416 | + return in.ready(); | |
| 417 | + } | |
| 418 | + | |
| 419 | + public int read(char cbuf[], int offset, int length) | |
| 420 | + throws IOException | |
| 421 | + { | |
| 422 | + int off = offset; | |
| 423 | + int end = offset + length; | |
| 424 | + if (offset < 0 || offset > cbuf.length || length < 0 || | |
| 425 | + end < 0 || end > cbuf.length) { | |
| 426 | + throw new IndexOutOfBoundsException(); | |
| 427 | + } | |
| 428 | + synchronized(readLock) { | |
| 429 | + boolean eof = false; | |
| 430 | + char c = 0; | |
| 431 | + for (;;) { | |
| 432 | + if (nextChar >= nChars) { //fill | |
| 433 | + int n = 0; | |
| 434 | + do { | |
| 435 | + n = in.read(cb, 0, cb.length); | |
| 436 | + } while (n == 0); | |
| 437 | + if (n > 0) { | |
| 438 | + nChars = n; | |
| 439 | + nextChar = 0; | |
| 440 | + if (n < cb.length && | |
| 441 | + cb[n-1] != '\n' && cb[n-1] != '\r') { | |
| 442 | + /* | |
| 443 | + * we're in canonical mode so each "fill" should | |
| 444 | + * come back with an eol. if there no lf or nl at | |
| 445 | + * the end of returned bytes we reached an eof. | |
| 446 | + */ | |
| 447 | + eof = true; | |
| 448 | + } | |
| 449 | + } else { /*EOF*/ | |
| 450 | + if (off - offset == 0) | |
| 451 | + return -1; | |
| 452 | + return off - offset; | |
| 453 | + } | |
| 454 | + } | |
| 455 | + if (leftoverLF && cbuf == rcb && cb[nextChar] == '\n') { | |
| 456 | + /* | |
| 457 | + * if invoked by our readline, skip the leftover, otherwise | |
| 458 | + * return the LF. | |
| 459 | + */ | |
| 460 | + nextChar++; | |
| 461 | + } | |
| 462 | + leftoverLF = false; | |
| 463 | + while (nextChar < nChars) { | |
| 464 | + c = cbuf[off++] = cb[nextChar]; | |
| 465 | + cb[nextChar++] = 0; | |
| 466 | + if (c == '\n') { | |
| 467 | + return off - offset; | |
| 468 | + } else if (c == '\r') { | |
| 469 | + if (off == end) { | |
| 470 | + /* no space left even the next is LF, so return | |
| 471 | + * whatever we have if the invoker is not our | |
| 472 | + * readLine() | |
| 473 | + */ | |
| 474 | + if (cbuf == rcb) { | |
| 475 | + cbuf = grow(); | |
| 476 | + end = cbuf.length; | |
| 477 | + } else { | |
| 478 | + leftoverLF = true; | |
| 479 | + return off - offset; | |
| 480 | + } | |
| 481 | + } | |
| 482 | + if (nextChar == nChars && in.ready()) { | |
| 483 | + /* | |
| 484 | + * we have a CR and we reached the end of | |
| 485 | + * the read in buffer, fill to make sure we | |
| 486 | + * don't miss a LF, if there is one, it's possible | |
| 487 | + * that it got cut off during last round reading | |
| 488 | + * simply because the read in buffer was full. | |
| 489 | + */ | |
| 490 | + nChars = in.read(cb, 0, cb.length); | |
| 491 | + nextChar = 0; | |
| 492 | + } | |
| 493 | + if (nextChar < nChars && cb[nextChar] == '\n') { | |
| 494 | + cbuf[off++] = '\n'; | |
| 495 | + nextChar++; | |
| 496 | + } | |
| 497 | + return off - offset; | |
| 498 | + } else if (off == end) { | |
| 499 | + if (cbuf == rcb) { | |
| 500 | + cbuf = grow(); | |
| 501 | + end = cbuf.length; | |
| 502 | + } else { | |
| 503 | + return off - offset; | |
| 504 | + } | |
| 505 | + } | |
| 506 | + } | |
| 507 | + if (eof) | |
| 508 | + return off - offset; | |
| 509 | + } | |
| 510 | + } | |
| 511 | + } | |
| 512 | + } | |
| 513 | + | |
| 514 | + // Set up JavaIOAccess in SharedSecrets | |
| 515 | + static { | |
| 516 | + try { | |
| 517 | + // Add a shutdown hook to restore console's echo state should | |
| 518 | + // it be necessary. | |
| 519 | + sun.misc.SharedSecrets.getJavaLangAccess() | |
| 520 | + .registerShutdownHook(0 /* shutdown hook invocation order */, | |
| 521 | + false /* only register if shutdown is not in progress */, | |
| 522 | + new Runnable() { | |
| 523 | + public void run() { | |
| 524 | + try { | |
| 525 | + if (echoOff) { | |
| 526 | + echo(true); | |
| 527 | + } | |
| 528 | + } catch (IOException x) { } | |
| 529 | + } | |
| 530 | + }); | |
| 531 | + } catch (IllegalStateException e) { | |
| 532 | + // shutdown is already in progress and console is first used | |
| 533 | + // by a shutdown hook | |
| 534 | + } | |
| 535 | + | |
| 536 | + sun.misc.SharedSecrets.setJavaIOAccess(new sun.misc.JavaIOAccess() { | |
| 537 | + public Console console() { | |
| 538 | + if (istty()) { | |
| 539 | + if (cons == null) | |
| 540 | + cons = new Console(); | |
| 541 | + return cons; | |
| 542 | + } | |
| 543 | + return null; | |
| 544 | + } | |
| 545 | + | |
| 546 | + public Charset charset() { | |
| 547 | + // This method is called in sun.security.util.Password, | |
| 548 | + // cons already exists when this method is called | |
| 549 | + return cons.cs; | |
| 550 | + } | |
| 551 | + }); | |
| 552 | + } | |
| 553 | + private static Console cons; | |
| 554 | + private native static boolean istty(); | |
| 555 | + private Console() { | |
| 556 | + readLock = new Object(); | |
| 557 | + writeLock = new Object(); | |
| 558 | + String csname = encoding(); | |
| 559 | + if (csname != null) { | |
| 560 | + try { | |
| 561 | + cs = Charset.forName(csname); | |
| 562 | + } catch (Exception x) {} | |
| 563 | + } | |
| 564 | + if (cs == null) | |
| 565 | + cs = Charset.defaultCharset(); | |
| 566 | + out = StreamEncoder.forOutputStreamWriter( | |
| 567 | + new FileOutputStream(FileDescriptor.out), | |
| 568 | + writeLock, | |
| 569 | + cs); | |
| 570 | + pw = new PrintWriter(out, true) { public void close() {} }; | |
| 571 | + formatter = new Formatter(out); | |
| 572 | + reader = new LineReader(StreamDecoder.forInputStreamReader( | |
| 573 | + new FileInputStream(FileDescriptor.in), | |
| 574 | + readLock, | |
| 575 | + cs)); | |
| 576 | + rcb = new char[1024]; | |
| 577 | + } | |
| 578 | +} | |
Binary file not shown.
| @@ -0,0 +1,635 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * The <code>DataInput</code> interface provides | |
| 30 | + * for reading bytes from a binary stream and | |
| 31 | + * reconstructing from them data in any of | |
| 32 | + * the Java primitive types. There is also | |
| 33 | + * a | |
| 34 | + * facility for reconstructing a <code>String</code> | |
| 35 | + * from data in | |
| 36 | + * <a href="#modified-utf-8">modified UTF-8</a> | |
| 37 | + * format. | |
| 38 | + * <p> | |
| 39 | + * It is generally true of all the reading | |
| 40 | + * routines in this interface that if end of | |
| 41 | + * file is reached before the desired number | |
| 42 | + * of bytes has been read, an <code>EOFException</code> | |
| 43 | + * (which is a kind of <code>IOException</code>) | |
| 44 | + * is thrown. If any byte cannot be read for | |
| 45 | + * any reason other than end of file, an <code>IOException</code> | |
| 46 | + * other than <code>EOFException</code> is | |
| 47 | + * thrown. In particular, an <code>IOException</code> | |
| 48 | + * may be thrown if the input stream has been | |
| 49 | + * closed. | |
| 50 | + * | |
| 51 | + * <h4><a name="modified-utf-8">Modified UTF-8</a></h4> | |
| 52 | + * <p> | |
| 53 | + * Implementations of the DataInput and DataOutput interfaces represent | |
| 54 | + * Unicode strings in a format that is a slight modification of UTF-8. | |
| 55 | + * (For information regarding the standard UTF-8 format, see section | |
| 56 | + * <i>3.9 Unicode Encoding Forms</i> of <i>The Unicode Standard, Version | |
| 57 | + * 4.0</i>). | |
| 58 | + * Note that in the following tables, the most significant bit appears in the | |
| 59 | + * far left-hand column. | |
| 60 | + * <p> | |
| 61 | + * All characters in the range <code>'\u0001'</code> to | |
| 62 | + * <code>'\u007F'</code> are represented by a single byte: | |
| 63 | + * | |
| 64 | + * <blockquote> | |
| 65 | + * <table border="1" cellspacing="0" cellpadding="8" width="50%" | |
| 66 | + * summary="Bit values and bytes"> | |
| 67 | + * <tr> | |
| 68 | + * <td></td> | |
| 69 | + * <th id="bit">Bit Values</th> | |
| 70 | + * </tr> | |
| 71 | + * <tr> | |
| 72 | + * <th id="byte1">Byte 1</th> | |
| 73 | + * <td> | |
| 74 | + * <table border="1" cellspacing="0" width="100%"> | |
| 75 | + * <tr> | |
| 76 | + * <td width="12%"><center>0</center> | |
| 77 | + * <td colspan="7"><center>bits 6-0</center> | |
| 78 | + * </tr> | |
| 79 | + * </table> | |
| 80 | + * </td> | |
| 81 | + * </tr> | |
| 82 | + * </table> | |
| 83 | + * </blockquote> | |
| 84 | + * | |
| 85 | + * <p> | |
| 86 | + * The null character <code>'\u0000'</code> and characters in the | |
| 87 | + * range <code>'\u0080'</code> to <code>'\u07FF'</code> are | |
| 88 | + * represented by a pair of bytes: | |
| 89 | + * | |
| 90 | + * <blockquote> | |
| 91 | + * <table border="1" cellspacing="0" cellpadding="8" width="50%" | |
| 92 | + * summary="Bit values and bytes"> | |
| 93 | + * <tr> | |
| 94 | + * <td></td> | |
| 95 | + * <th id="bit">Bit Values</th> | |
| 96 | + * </tr> | |
| 97 | + * <tr> | |
| 98 | + * <th id="byte1">Byte 1</th> | |
| 99 | + * <td> | |
| 100 | + * <table border="1" cellspacing="0" width="100%"> | |
| 101 | + * <tr> | |
| 102 | + * <td width="12%"><center>1</center> | |
| 103 | + * <td width="13%"><center>1</center> | |
| 104 | + * <td width="12%"><center>0</center> | |
| 105 | + * <td colspan="5"><center>bits 10-6</center> | |
| 106 | + * </tr> | |
| 107 | + * </table> | |
| 108 | + * </td> | |
| 109 | + * </tr> | |
| 110 | + * <tr> | |
| 111 | + * <th id="byte2">Byte 2</th> | |
| 112 | + * <td> | |
| 113 | + * <table border="1" cellspacing="0" width="100%"> | |
| 114 | + * <tr> | |
| 115 | + * <td width="12%"><center>1</center> | |
| 116 | + * <td width="13%"><center>0</center> | |
| 117 | + * <td colspan="6"><center>bits 5-0</center> | |
| 118 | + * </tr> | |
| 119 | + * </table> | |
| 120 | + * </td> | |
| 121 | + * </tr> | |
| 122 | + * </table> | |
| 123 | + * </blockquote> | |
| 124 | + * | |
| 125 | + * <br> | |
| 126 | + * <code>char</code> values in the range <code>'\u0800'</code> to | |
| 127 | + * <code>'\uFFFF'</code> are represented by three bytes: | |
| 128 | + * | |
| 129 | + * <blockquote> | |
| 130 | + * <table border="1" cellspacing="0" cellpadding="8" width="50%" | |
| 131 | + * summary="Bit values and bytes"> | |
| 132 | + * <tr> | |
| 133 | + * <td></td> | |
| 134 | + * <th id="bit">Bit Values</th> | |
| 135 | + * </tr> | |
| 136 | + * <tr> | |
| 137 | + * <th id="byte1">Byte 1</th> | |
| 138 | + * <td> | |
| 139 | + * <table border="1" cellspacing="0" width="100%"> | |
| 140 | + * <tr> | |
| 141 | + * <td width="12%"><center>1</center> | |
| 142 | + * <td width="13%"><center>1</center> | |
| 143 | + * <td width="12%"><center>1</center> | |
| 144 | + * <td width="13%"><center>0</center> | |
| 145 | + * <td colspan="4"><center>bits 15-12</center> | |
| 146 | + * </tr> | |
| 147 | + * </table> | |
| 148 | + * </td> | |
| 149 | + * </tr> | |
| 150 | + * <tr> | |
| 151 | + * <th id="byte2">Byte 2</th> | |
| 152 | + * <td> | |
| 153 | + * <table border="1" cellspacing="0" width="100%"> | |
| 154 | + * <tr> | |
| 155 | + * <td width="12%"><center>1</center> | |
| 156 | + * <td width="13%"><center>0</center> | |
| 157 | + * <td colspan="6"><center>bits 11-6</center> | |
| 158 | + * </tr> | |
| 159 | + * </table> | |
| 160 | + * </td> | |
| 161 | + * </tr> | |
| 162 | + * <tr> | |
| 163 | + * <th id="byte3">Byte 3</th> | |
| 164 | + * <td> | |
| 165 | + * <table border="1" cellspacing="0" width="100%"> | |
| 166 | + * <tr> | |
| 167 | + * <td width="12%"><center>1</center> | |
| 168 | + * <td width="13%"><center>0</center> | |
| 169 | + * <td colspan="6"><center>bits 5-0</center> | |
| 170 | + * </tr> | |
| 171 | + * </table> | |
| 172 | + * </td> | |
| 173 | + * </tr> | |
| 174 | + * </table> | |
| 175 | + * </blockquote> | |
| 176 | + * | |
| 177 | + * <p> | |
| 178 | + * The differences between this format and the | |
| 179 | + * standard UTF-8 format are the following: | |
| 180 | + * <ul> | |
| 181 | + * <li>The null byte <code>'\u0000'</code> is encoded in 2-byte format | |
| 182 | + * rather than 1-byte, so that the encoded strings never have | |
| 183 | + * embedded nulls. | |
| 184 | + * <li>Only the 1-byte, 2-byte, and 3-byte formats are used. | |
| 185 | + * <li><a href="../lang/Character.html#unicode">Supplementary characters</a> | |
| 186 | + * are represented in the form of surrogate pairs. | |
| 187 | + * </ul> | |
| 188 | + * @author Frank Yellin | |
| 189 | + * @see java.io.DataInputStream | |
| 190 | + * @see java.io.DataOutput | |
| 191 | + * @since JDK1.0 | |
| 192 | + */ | |
| 193 | +public | |
| 194 | +interface DataInput { | |
| 195 | + /** | |
| 196 | + * Reads some bytes from an input | |
| 197 | + * stream and stores them into the buffer | |
| 198 | + * array <code>b</code>. The number of bytes | |
| 199 | + * read is equal | |
| 200 | + * to the length of <code>b</code>. | |
| 201 | + * <p> | |
| 202 | + * This method blocks until one of the | |
| 203 | + * following conditions occurs:<p> | |
| 204 | + * <ul> | |
| 205 | + * <li><code>b.length</code> | |
| 206 | + * bytes of input data are available, in which | |
| 207 | + * case a normal return is made. | |
| 208 | + * | |
| 209 | + * <li>End of | |
| 210 | + * file is detected, in which case an <code>EOFException</code> | |
| 211 | + * is thrown. | |
| 212 | + * | |
| 213 | + * <li>An I/O error occurs, in | |
| 214 | + * which case an <code>IOException</code> other | |
| 215 | + * than <code>EOFException</code> is thrown. | |
| 216 | + * </ul> | |
| 217 | + * <p> | |
| 218 | + * If <code>b</code> is <code>null</code>, | |
| 219 | + * a <code>NullPointerException</code> is thrown. | |
| 220 | + * If <code>b.length</code> is zero, then | |
| 221 | + * no bytes are read. Otherwise, the first | |
| 222 | + * byte read is stored into element <code>b[0]</code>, | |
| 223 | + * the next one into <code>b[1]</code>, and | |
| 224 | + * so on. | |
| 225 | + * If an exception is thrown from | |
| 226 | + * this method, then it may be that some but | |
| 227 | + * not all bytes of <code>b</code> have been | |
| 228 | + * updated with data from the input stream. | |
| 229 | + * | |
| 230 | + * @param b the buffer into which the data is read. | |
| 231 | + * @exception EOFException if this stream reaches the end before reading | |
| 232 | + * all the bytes. | |
| 233 | + * @exception IOException if an I/O error occurs. | |
| 234 | + */ | |
| 235 | + void readFully(byte b[]) throws IOException; | |
| 236 | + | |
| 237 | + /** | |
| 238 | + * | |
| 239 | + * Reads <code>len</code> | |
| 240 | + * bytes from | |
| 241 | + * an input stream. | |
| 242 | + * <p> | |
| 243 | + * This method | |
| 244 | + * blocks until one of the following conditions | |
| 245 | + * occurs:<p> | |
| 246 | + * <ul> | |
| 247 | + * <li><code>len</code> bytes | |
| 248 | + * of input data are available, in which case | |
| 249 | + * a normal return is made. | |
| 250 | + * | |
| 251 | + * <li>End of file | |
| 252 | + * is detected, in which case an <code>EOFException</code> | |
| 253 | + * is thrown. | |
| 254 | + * | |
| 255 | + * <li>An I/O error occurs, in | |
| 256 | + * which case an <code>IOException</code> other | |
| 257 | + * than <code>EOFException</code> is thrown. | |
| 258 | + * </ul> | |
| 259 | + * <p> | |
| 260 | + * If <code>b</code> is <code>null</code>, | |
| 261 | + * a <code>NullPointerException</code> is thrown. | |
| 262 | + * If <code>off</code> is negative, or <code>len</code> | |
| 263 | + * is negative, or <code>off+len</code> is | |
| 264 | + * greater than the length of the array <code>b</code>, | |
| 265 | + * then an <code>IndexOutOfBoundsException</code> | |
| 266 | + * is thrown. | |
| 267 | + * If <code>len</code> is zero, | |
| 268 | + * then no bytes are read. Otherwise, the first | |
| 269 | + * byte read is stored into element <code>b[off]</code>, | |
| 270 | + * the next one into <code>b[off+1]</code>, | |
| 271 | + * and so on. The number of bytes read is, | |
| 272 | + * at most, equal to <code>len</code>. | |
| 273 | + * | |
| 274 | + * @param b the buffer into which the data is read. | |
| 275 | + * @param off an int specifying the offset into the data. | |
| 276 | + * @param len an int specifying the number of bytes to read. | |
| 277 | + * @exception EOFException if this stream reaches the end before reading | |
| 278 | + * all the bytes. | |
| 279 | + * @exception IOException if an I/O error occurs. | |
| 280 | + */ | |
| 281 | + void readFully(byte b[], int off, int len) throws IOException; | |
| 282 | + | |
| 283 | + /** | |
| 284 | + * Makes an attempt to skip over | |
| 285 | + * <code>n</code> bytes | |
| 286 | + * of data from the input | |
| 287 | + * stream, discarding the skipped bytes. However, | |
| 288 | + * it may skip | |
| 289 | + * over some smaller number of | |
| 290 | + * bytes, possibly zero. This may result from | |
| 291 | + * any of a | |
| 292 | + * number of conditions; reaching | |
| 293 | + * end of file before <code>n</code> bytes | |
| 294 | + * have been skipped is | |
| 295 | + * only one possibility. | |
| 296 | + * This method never throws an <code>EOFException</code>. | |
| 297 | + * The actual | |
| 298 | + * number of bytes skipped is returned. | |
| 299 | + * | |
| 300 | + * @param n the number of bytes to be skipped. | |
| 301 | + * @return the number of bytes actually skipped. | |
| 302 | + * @exception IOException if an I/O error occurs. | |
| 303 | + */ | |
| 304 | + int skipBytes(int n) throws IOException; | |
| 305 | + | |
| 306 | + /** | |
| 307 | + * Reads one input byte and returns | |
| 308 | + * <code>true</code> if that byte is nonzero, | |
| 309 | + * <code>false</code> if that byte is zero. | |
| 310 | + * This method is suitable for reading | |
| 311 | + * the byte written by the <code>writeBoolean</code> | |
| 312 | + * method of interface <code>DataOutput</code>. | |
| 313 | + * | |
| 314 | + * @return the <code>boolean</code> value read. | |
| 315 | + * @exception EOFException if this stream reaches the end before reading | |
| 316 | + * all the bytes. | |
| 317 | + * @exception IOException if an I/O error occurs. | |
| 318 | + */ | |
| 319 | + boolean readBoolean() throws IOException; | |
| 320 | + | |
| 321 | + /** | |
| 322 | + * Reads and returns one input byte. | |
| 323 | + * The byte is treated as a signed value in | |
| 324 | + * the range <code>-128</code> through <code>127</code>, | |
| 325 | + * inclusive. | |
| 326 | + * This method is suitable for | |
| 327 | + * reading the byte written by the <code>writeByte</code> | |
| 328 | + * method of interface <code>DataOutput</code>. | |
| 329 | + * | |
| 330 | + * @return the 8-bit value read. | |
| 331 | + * @exception EOFException if this stream reaches the end before reading | |
| 332 | + * all the bytes. | |
| 333 | + * @exception IOException if an I/O error occurs. | |
| 334 | + */ | |
| 335 | + byte readByte() throws IOException; | |
| 336 | + | |
| 337 | + /** | |
| 338 | + * Reads one input byte, zero-extends | |
| 339 | + * it to type <code>int</code>, and returns | |
| 340 | + * the result, which is therefore in the range | |
| 341 | + * <code>0</code> | |
| 342 | + * through <code>255</code>. | |
| 343 | + * This method is suitable for reading | |
| 344 | + * the byte written by the <code>writeByte</code> | |
| 345 | + * method of interface <code>DataOutput</code> | |
| 346 | + * if the argument to <code>writeByte</code> | |
| 347 | + * was intended to be a value in the range | |
| 348 | + * <code>0</code> through <code>255</code>. | |
| 349 | + * | |
| 350 | + * @return the unsigned 8-bit value read. | |
| 351 | + * @exception EOFException if this stream reaches the end before reading | |
| 352 | + * all the bytes. | |
| 353 | + * @exception IOException if an I/O error occurs. | |
| 354 | + */ | |
| 355 | + int readUnsignedByte() throws IOException; | |
| 356 | + | |
| 357 | + /** | |
| 358 | + * Reads two input bytes and returns | |
| 359 | + * a <code>short</code> value. Let <code>a</code> | |
| 360 | + * be the first byte read and <code>b</code> | |
| 361 | + * be the second byte. The value | |
| 362 | + * returned | |
| 363 | + * is: | |
| 364 | + * <p><pre><code>(short)((a << 8) | (b & 0xff)) | |
| 365 | + * </code></pre> | |
| 366 | + * This method | |
| 367 | + * is suitable for reading the bytes written | |
| 368 | + * by the <code>writeShort</code> method of | |
| 369 | + * interface <code>DataOutput</code>. | |
| 370 | + * | |
| 371 | + * @return the 16-bit value read. | |
| 372 | + * @exception EOFException if this stream reaches the end before reading | |
| 373 | + * all the bytes. | |
| 374 | + * @exception IOException if an I/O error occurs. | |
| 375 | + */ | |
| 376 | + short readShort() throws IOException; | |
| 377 | + | |
| 378 | + /** | |
| 379 | + * Reads two input bytes and returns | |
| 380 | + * an <code>int</code> value in the range <code>0</code> | |
| 381 | + * through <code>65535</code>. Let <code>a</code> | |
| 382 | + * be the first byte read and | |
| 383 | + * <code>b</code> | |
| 384 | + * be the second byte. The value returned is: | |
| 385 | + * <p><pre><code>(((a & 0xff) << 8) | (b & 0xff)) | |
| 386 | + * </code></pre> | |
| 387 | + * This method is suitable for reading the bytes | |
| 388 | + * written by the <code>writeShort</code> method | |
| 389 | + * of interface <code>DataOutput</code> if | |
| 390 | + * the argument to <code>writeShort</code> | |
| 391 | + * was intended to be a value in the range | |
| 392 | + * <code>0</code> through <code>65535</code>. | |
| 393 | + * | |
| 394 | + * @return the unsigned 16-bit value read. | |
| 395 | + * @exception EOFException if this stream reaches the end before reading | |
| 396 | + * all the bytes. | |
| 397 | + * @exception IOException if an I/O error occurs. | |
| 398 | + */ | |
| 399 | + int readUnsignedShort() throws IOException; | |
| 400 | + | |
| 401 | + /** | |
| 402 | + * Reads two input bytes and returns a <code>char</code> value. | |
| 403 | + * Let <code>a</code> | |
| 404 | + * be the first byte read and <code>b</code> | |
| 405 | + * be the second byte. The value | |
| 406 | + * returned is: | |
| 407 | + * <p><pre><code>(char)((a << 8) | (b & 0xff)) | |
| 408 | + * </code></pre> | |
| 409 | + * This method | |
| 410 | + * is suitable for reading bytes written by | |
| 411 | + * the <code>writeChar</code> method of interface | |
| 412 | + * <code>DataOutput</code>. | |
| 413 | + * | |
| 414 | + * @return the <code>char</code> value read. | |
| 415 | + * @exception EOFException if this stream reaches the end before reading | |
| 416 | + * all the bytes. | |
| 417 | + * @exception IOException if an I/O error occurs. | |
| 418 | + */ | |
| 419 | + char readChar() throws IOException; | |
| 420 | + | |
| 421 | + /** | |
| 422 | + * Reads four input bytes and returns an | |
| 423 | + * <code>int</code> value. Let <code>a-d</code> | |
| 424 | + * be the first through fourth bytes read. The value returned is: | |
| 425 | + * <p><pre> | |
| 426 | + * <code> | |
| 427 | + * (((a & 0xff) << 24) | ((b & 0xff) << 16) | | |
| 428 | + *  ((c & 0xff) << 8) | (d & 0xff)) | |
| 429 | + * </code></pre> | |
| 430 | + * This method is suitable | |
| 431 | + * for reading bytes written by the <code>writeInt</code> | |
| 432 | + * method of interface <code>DataOutput</code>. | |
| 433 | + * | |
| 434 | + * @return the <code>int</code> value read. | |
| 435 | + * @exception EOFException if this stream reaches the end before reading | |
| 436 | + * all the bytes. | |
| 437 | + * @exception IOException if an I/O error occurs. | |
| 438 | + */ | |
| 439 | + int readInt() throws IOException; | |
| 440 | + | |
| 441 | + /** | |
| 442 | + * Reads eight input bytes and returns | |
| 443 | + * a <code>long</code> value. Let <code>a-h</code> | |
| 444 | + * be the first through eighth bytes read. | |
| 445 | + * The value returned is: | |
| 446 | + * <p><pre> <code> | |
| 447 | + * (((long)(a & 0xff) << 56) | | |
| 448 | + * ((long)(b & 0xff) << 48) | | |
| 449 | + * ((long)(c & 0xff) << 40) | | |
| 450 | + * ((long)(d & 0xff) << 32) | | |
| 451 | + * ((long)(e & 0xff) << 24) | | |
| 452 | + * ((long)(f & 0xff) << 16) | | |
| 453 | + * ((long)(g & 0xff) << 8) | | |
| 454 | + * ((long)(h & 0xff))) | |
| 455 | + * </code></pre> | |
| 456 | + * <p> | |
| 457 | + * This method is suitable | |
| 458 | + * for reading bytes written by the <code>writeLong</code> | |
| 459 | + * method of interface <code>DataOutput</code>. | |
| 460 | + * | |
| 461 | + * @return the <code>long</code> value read. | |
| 462 | + * @exception EOFException if this stream reaches the end before reading | |
| 463 | + * all the bytes. | |
| 464 | + * @exception IOException if an I/O error occurs. | |
| 465 | + */ | |
| 466 | + long readLong() throws IOException; | |
| 467 | + | |
| 468 | + /** | |
| 469 | + * Reads four input bytes and returns | |
| 470 | + * a <code>float</code> value. It does this | |
| 471 | + * by first constructing an <code>int</code> | |
| 472 | + * value in exactly the manner | |
| 473 | + * of the <code>readInt</code> | |
| 474 | + * method, then converting this <code>int</code> | |
| 475 | + * value to a <code>float</code> in | |
| 476 | + * exactly the manner of the method <code>Float.intBitsToFloat</code>. | |
| 477 | + * This method is suitable for reading | |
| 478 | + * bytes written by the <code>writeFloat</code> | |
| 479 | + * method of interface <code>DataOutput</code>. | |
| 480 | + * | |
| 481 | + * @return the <code>float</code> value read. | |
| 482 | + * @exception EOFException if this stream reaches the end before reading | |
| 483 | + * all the bytes. | |
| 484 | + * @exception IOException if an I/O error occurs. | |
| 485 | + */ | |
| 486 | + float readFloat() throws IOException; | |
| 487 | + | |
| 488 | + /** | |
| 489 | + * Reads eight input bytes and returns | |
| 490 | + * a <code>double</code> value. It does this | |
| 491 | + * by first constructing a <code>long</code> | |
| 492 | + * value in exactly the manner | |
| 493 | + * of the <code>readlong</code> | |
| 494 | + * method, then converting this <code>long</code> | |
| 495 | + * value to a <code>double</code> in exactly | |
| 496 | + * the manner of the method <code>Double.longBitsToDouble</code>. | |
| 497 | + * This method is suitable for reading | |
| 498 | + * bytes written by the <code>writeDouble</code> | |
| 499 | + * method of interface <code>DataOutput</code>. | |
| 500 | + * | |
| 501 | + * @return the <code>double</code> value read. | |
| 502 | + * @exception EOFException if this stream reaches the end before reading | |
| 503 | + * all the bytes. | |
| 504 | + * @exception IOException if an I/O error occurs. | |
| 505 | + */ | |
| 506 | + double readDouble() throws IOException; | |
| 507 | + | |
| 508 | + /** | |
| 509 | + * Reads the next line of text from the input stream. | |
| 510 | + * It reads successive bytes, converting | |
| 511 | + * each byte separately into a character, | |
| 512 | + * until it encounters a line terminator or | |
| 513 | + * end of | |
| 514 | + * file; the characters read are then | |
| 515 | + * returned as a <code>String</code>. Note | |
| 516 | + * that because this | |
| 517 | + * method processes bytes, | |
| 518 | + * it does not support input of the full Unicode | |
| 519 | + * character set. | |
| 520 | + * <p> | |
| 521 | + * If end of file is encountered | |
| 522 | + * before even one byte can be read, then <code>null</code> | |
| 523 | + * is returned. Otherwise, each byte that is | |
| 524 | + * read is converted to type <code>char</code> | |
| 525 | + * by zero-extension. If the character <code>'\n'</code> | |
| 526 | + * is encountered, it is discarded and reading | |
| 527 | + * ceases. If the character <code>'\r'</code> | |
| 528 | + * is encountered, it is discarded and, if | |
| 529 | + * the following byte converts  to the | |
| 530 | + * character <code>'\n'</code>, then that is | |
| 531 | + * discarded also; reading then ceases. If | |
| 532 | + * end of file is encountered before either | |
| 533 | + * of the characters <code>'\n'</code> and | |
| 534 | + * <code>'\r'</code> is encountered, reading | |
| 535 | + * ceases. Once reading has ceased, a <code>String</code> | |
| 536 | + * is returned that contains all the characters | |
| 537 | + * read and not discarded, taken in order. | |
| 538 | + * Note that every character in this string | |
| 539 | + * will have a value less than <code>\u0100</code>, | |
| 540 | + * that is, <code>(char)256</code>. | |
| 541 | + * | |
| 542 | + * @return the next line of text from the input stream, | |
| 543 | + * or <CODE>null</CODE> if the end of file is | |
| 544 | + * encountered before a byte can be read. | |
| 545 | + * @exception IOException if an I/O error occurs. | |
| 546 | + */ | |
| 547 | + String readLine() throws IOException; | |
| 548 | + | |
| 549 | + /** | |
| 550 | + * Reads in a string that has been encoded using a | |
| 551 | + * <a href="#modified-utf-8">modified UTF-8</a> | |
| 552 | + * format. | |
| 553 | + * The general contract of <code>readUTF</code> | |
| 554 | + * is that it reads a representation of a Unicode | |
| 555 | + * character string encoded in modified | |
| 556 | + * UTF-8 format; this string of characters | |
| 557 | + * is then returned as a <code>String</code>. | |
| 558 | + * <p> | |
| 559 | + * First, two bytes are read and used to | |
| 560 | + * construct an unsigned 16-bit integer in | |
| 561 | + * exactly the manner of the <code>readUnsignedShort</code> | |
| 562 | + * method . This integer value is called the | |
| 563 | + * <i>UTF length</i> and specifies the number | |
| 564 | + * of additional bytes to be read. These bytes | |
| 565 | + * are then converted to characters by considering | |
| 566 | + * them in groups. The length of each group | |
| 567 | + * is computed from the value of the first | |
| 568 | + * byte of the group. The byte following a | |
| 569 | + * group, if any, is the first byte of the | |
| 570 | + * next group. | |
| 571 | + * <p> | |
| 572 | + * If the first byte of a group | |
| 573 | + * matches the bit pattern <code>0xxxxxxx</code> | |
| 574 | + * (where <code>x</code> means "may be <code>0</code> | |
| 575 | + * or <code>1</code>"), then the group consists | |
| 576 | + * of just that byte. The byte is zero-extended | |
| 577 | + * to form a character. | |
| 578 | + * <p> | |
| 579 | + * If the first byte | |
| 580 | + * of a group matches the bit pattern <code>110xxxxx</code>, | |
| 581 | + * then the group consists of that byte <code>a</code> | |
| 582 | + * and a second byte <code>b</code>. If there | |
| 583 | + * is no byte <code>b</code> (because byte | |
| 584 | + * <code>a</code> was the last of the bytes | |
| 585 | + * to be read), or if byte <code>b</code> does | |
| 586 | + * not match the bit pattern <code>10xxxxxx</code>, | |
| 587 | + * then a <code>UTFDataFormatException</code> | |
| 588 | + * is thrown. Otherwise, the group is converted | |
| 589 | + * to the character:<p> | |
| 590 | + * <pre><code>(char)(((a& 0x1F) << 6) | (b & 0x3F)) | |
| 591 | + * </code></pre> | |
| 592 | + * If the first byte of a group | |
| 593 | + * matches the bit pattern <code>1110xxxx</code>, | |
| 594 | + * then the group consists of that byte <code>a</code> | |
| 595 | + * and two more bytes <code>b</code> and <code>c</code>. | |
| 596 | + * If there is no byte <code>c</code> (because | |
| 597 | + * byte <code>a</code> was one of the last | |
| 598 | + * two of the bytes to be read), or either | |
| 599 | + * byte <code>b</code> or byte <code>c</code> | |
| 600 | + * does not match the bit pattern <code>10xxxxxx</code>, | |
| 601 | + * then a <code>UTFDataFormatException</code> | |
| 602 | + * is thrown. Otherwise, the group is converted | |
| 603 | + * to the character:<p> | |
| 604 | + * <pre><code> | |
| 605 | + * (char)(((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F)) | |
| 606 | + * </code></pre> | |
| 607 | + * If the first byte of a group matches the | |
| 608 | + * pattern <code>1111xxxx</code> or the pattern | |
| 609 | + * <code>10xxxxxx</code>, then a <code>UTFDataFormatException</code> | |
| 610 | + * is thrown. | |
| 611 | + * <p> | |
| 612 | + * If end of file is encountered | |
| 613 | + * at any time during this entire process, | |
| 614 | + * then an <code>EOFException</code> is thrown. | |
| 615 | + * <p> | |
| 616 | + * After every group has been converted to | |
| 617 | + * a character by this process, the characters | |
| 618 | + * are gathered, in the same order in which | |
| 619 | + * their corresponding groups were read from | |
| 620 | + * the input stream, to form a <code>String</code>, | |
| 621 | + * which is returned. | |
| 622 | + * <p> | |
| 623 | + * The <code>writeUTF</code> | |
| 624 | + * method of interface <code>DataOutput</code> | |
| 625 | + * may be used to write data that is suitable | |
| 626 | + * for reading by this method. | |
| 627 | + * @return a Unicode string. | |
| 628 | + * @exception EOFException if this stream reaches the end | |
| 629 | + * before reading all the bytes. | |
| 630 | + * @exception IOException if an I/O error occurs. | |
| 631 | + * @exception UTFDataFormatException if the bytes do not represent a | |
| 632 | + * valid modified UTF-8 encoding of a string. | |
| 633 | + */ | |
| 634 | + String readUTF() throws IOException; | |
| 635 | +} | |
Binary file not shown.
| @@ -0,0 +1,663 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * A data input stream lets an application read primitive Java data | |
| 30 | + * types from an underlying input stream in a machine-independent | |
| 31 | + * way. An application uses a data output stream to write data that | |
| 32 | + * can later be read by a data input stream. | |
| 33 | + * <p> | |
| 34 | + * DataInputStream is not necessarily safe for multithreaded access. | |
| 35 | + * Thread safety is optional and is the responsibility of users of | |
| 36 | + * methods in this class. | |
| 37 | + * | |
| 38 | + * @author Arthur van Hoff | |
| 39 | + * @see java.io.DataOutputStream | |
| 40 | + * @since JDK1.0 | |
| 41 | + */ | |
| 42 | +public | |
| 43 | +class DataInputStream extends FilterInputStream implements DataInput { | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * Creates a DataInputStream that uses the specified | |
| 47 | + * underlying InputStream. | |
| 48 | + * | |
| 49 | + * @param in the specified input stream | |
| 50 | + */ | |
| 51 | + public DataInputStream(InputStream in) { | |
| 52 | + super(in); | |
| 53 | + } | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * working arrays initialized on demand by readUTF | |
| 57 | + */ | |
| 58 | + private byte bytearr[] = new byte[80]; | |
| 59 | + private char chararr[] = new char[80]; | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * Reads some number of bytes from the contained input stream and | |
| 63 | + * stores them into the buffer array <code>b</code>. The number of | |
| 64 | + * bytes actually read is returned as an integer. This method blocks | |
| 65 | + * until input data is available, end of file is detected, or an | |
| 66 | + * exception is thrown. | |
| 67 | + * | |
| 68 | + * <p>If <code>b</code> is null, a <code>NullPointerException</code> is | |
| 69 | + * thrown. If the length of <code>b</code> is zero, then no bytes are | |
| 70 | + * read and <code>0</code> is returned; otherwise, there is an attempt | |
| 71 | + * to read at least one byte. If no byte is available because the | |
| 72 | + * stream is at end of file, the value <code>-1</code> is returned; | |
| 73 | + * otherwise, at least one byte is read and stored into <code>b</code>. | |
| 74 | + * | |
| 75 | + * <p>The first byte read is stored into element <code>b[0]</code>, the | |
| 76 | + * next one into <code>b[1]</code>, and so on. The number of bytes read | |
| 77 | + * is, at most, equal to the length of <code>b</code>. Let <code>k</code> | |
| 78 | + * be the number of bytes actually read; these bytes will be stored in | |
| 79 | + * elements <code>b[0]</code> through <code>b[k-1]</code>, leaving | |
| 80 | + * elements <code>b[k]</code> through <code>b[b.length-1]</code> | |
| 81 | + * unaffected. | |
| 82 | + * | |
| 83 | + * <p>The <code>read(b)</code> method has the same effect as: | |
| 84 | + * <blockquote><pre> | |
| 85 | + * read(b, 0, b.length) | |
| 86 | + * </pre></blockquote> | |
| 87 | + * | |
| 88 | + * @param b the buffer into which the data is read. | |
| 89 | + * @return the total number of bytes read into the buffer, or | |
| 90 | + * <code>-1</code> if there is no more data because the end | |
| 91 | + * of the stream has been reached. | |
| 92 | + * @exception IOException if the first byte cannot be read for any reason | |
| 93 | + * other than end of file, the stream has been closed and the underlying | |
| 94 | + * input stream does not support reading after close, or another I/O | |
| 95 | + * error occurs. | |
| 96 | + * @see java.io.FilterInputStream#in | |
| 97 | + * @see java.io.InputStream#read(byte[], int, int) | |
| 98 | + */ | |
| 99 | + public final int read(byte b[]) throws IOException { | |
| 100 | + return in.read(b, 0, b.length); | |
| 101 | + } | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * Reads up to <code>len</code> bytes of data from the contained | |
| 105 | + * input stream into an array of bytes. An attempt is made to read | |
| 106 | + * as many as <code>len</code> bytes, but a smaller number may be read, | |
| 107 | + * possibly zero. The number of bytes actually read is returned as an | |
| 108 | + * integer. | |
| 109 | + * | |
| 110 | + * <p> This method blocks until input data is available, end of file is | |
| 111 | + * detected, or an exception is thrown. | |
| 112 | + * | |
| 113 | + * <p> If <code>len</code> is zero, then no bytes are read and | |
| 114 | + * <code>0</code> is returned; otherwise, there is an attempt to read at | |
| 115 | + * least one byte. If no byte is available because the stream is at end of | |
| 116 | + * file, the value <code>-1</code> is returned; otherwise, at least one | |
| 117 | + * byte is read and stored into <code>b</code>. | |
| 118 | + * | |
| 119 | + * <p> The first byte read is stored into element <code>b[off]</code>, the | |
| 120 | + * next one into <code>b[off+1]</code>, and so on. The number of bytes read | |
| 121 | + * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of | |
| 122 | + * bytes actually read; these bytes will be stored in elements | |
| 123 | + * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>, | |
| 124 | + * leaving elements <code>b[off+</code><i>k</i><code>]</code> through | |
| 125 | + * <code>b[off+len-1]</code> unaffected. | |
| 126 | + * | |
| 127 | + * <p> In every case, elements <code>b[0]</code> through | |
| 128 | + * <code>b[off]</code> and elements <code>b[off+len]</code> through | |
| 129 | + * <code>b[b.length-1]</code> are unaffected. | |
| 130 | + * | |
| 131 | + * @param b the buffer into which the data is read. | |
| 132 | + * @param off the start offset in the destination array <code>b</code> | |
| 133 | + * @param len the maximum number of bytes read. | |
| 134 | + * @return the total number of bytes read into the buffer, or | |
| 135 | + * <code>-1</code> if there is no more data because the end | |
| 136 | + * of the stream has been reached. | |
| 137 | + * @exception NullPointerException If <code>b</code> is <code>null</code>. | |
| 138 | + * @exception IndexOutOfBoundsException If <code>off</code> is negative, | |
| 139 | + * <code>len</code> is negative, or <code>len</code> is greater than | |
| 140 | + * <code>b.length - off</code> | |
| 141 | + * @exception IOException if the first byte cannot be read for any reason | |
| 142 | + * other than end of file, the stream has been closed and the underlying | |
| 143 | + * input stream does not support reading after close, or another I/O | |
| 144 | + * error occurs. | |
| 145 | + * @see java.io.FilterInputStream#in | |
| 146 | + * @see java.io.InputStream#read(byte[], int, int) | |
| 147 | + */ | |
| 148 | + public final int read(byte b[], int off, int len) throws IOException { | |
| 149 | + return in.read(b, off, len); | |
| 150 | + } | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * See the general contract of the <code>readFully</code> | |
| 154 | + * method of <code>DataInput</code>. | |
| 155 | + * <p> | |
| 156 | + * Bytes | |
| 157 | + * for this operation are read from the contained | |
| 158 | + * input stream. | |
| 159 | + * | |
| 160 | + * @param b the buffer into which the data is read. | |
| 161 | + * @exception EOFException if this input stream reaches the end before | |
| 162 | + * reading all the bytes. | |
| 163 | + * @exception IOException the stream has been closed and the contained | |
| 164 | + * input stream does not support reading after close, or | |
| 165 | + * another I/O error occurs. | |
| 166 | + * @see java.io.FilterInputStream#in | |
| 167 | + */ | |
| 168 | + public final void readFully(byte b[]) throws IOException { | |
| 169 | + readFully(b, 0, b.length); | |
| 170 | + } | |
| 171 | + | |
| 172 | + /** | |
| 173 | + * See the general contract of the <code>readFully</code> | |
| 174 | + * method of <code>DataInput</code>. | |
| 175 | + * <p> | |
| 176 | + * Bytes | |
| 177 | + * for this operation are read from the contained | |
| 178 | + * input stream. | |
| 179 | + * | |
| 180 | + * @param b the buffer into which the data is read. | |
| 181 | + * @param off the start offset of the data. | |
| 182 | + * @param len the number of bytes to read. | |
| 183 | + * @exception EOFException if this input stream reaches the end before | |
| 184 | + * reading all the bytes. | |
| 185 | + * @exception IOException the stream has been closed and the contained | |
| 186 | + * input stream does not support reading after close, or | |
| 187 | + * another I/O error occurs. | |
| 188 | + * @see java.io.FilterInputStream#in | |
| 189 | + */ | |
| 190 | + public final void readFully(byte b[], int off, int len) throws IOException { | |
| 191 | + if (len < 0) | |
| 192 | + throw new IndexOutOfBoundsException(); | |
| 193 | + int n = 0; | |
| 194 | + while (n < len) { | |
| 195 | + int count = in.read(b, off + n, len - n); | |
| 196 | + if (count < 0) | |
| 197 | + throw new EOFException(); | |
| 198 | + n += count; | |
| 199 | + } | |
| 200 | + } | |
| 201 | + | |
| 202 | + /** | |
| 203 | + * See the general contract of the <code>skipBytes</code> | |
| 204 | + * method of <code>DataInput</code>. | |
| 205 | + * <p> | |
| 206 | + * Bytes for this operation are read from the contained | |
| 207 | + * input stream. | |
| 208 | + * | |
| 209 | + * @param n the number of bytes to be skipped. | |
| 210 | + * @return the actual number of bytes skipped. | |
| 211 | + * @exception IOException if the contained input stream does not support | |
| 212 | + * seek, or the stream has been closed and | |
| 213 | + * the contained input stream does not support | |
| 214 | + * reading after close, or another I/O error occurs. | |
| 215 | + */ | |
| 216 | + public final int skipBytes(int n) throws IOException { | |
| 217 | + int total = 0; | |
| 218 | + int cur = 0; | |
| 219 | + | |
| 220 | + while ((total<n) && ((cur = (int) in.skip(n-total)) > 0)) { | |
| 221 | + total += cur; | |
| 222 | + } | |
| 223 | + | |
| 224 | + return total; | |
| 225 | + } | |
| 226 | + | |
| 227 | + /** | |
| 228 | + * See the general contract of the <code>readBoolean</code> | |
| 229 | + * method of <code>DataInput</code>. | |
| 230 | + * <p> | |
| 231 | + * Bytes for this operation are read from the contained | |
| 232 | + * input stream. | |
| 233 | + * | |
| 234 | + * @return the <code>boolean</code> value read. | |
| 235 | + * @exception EOFException if this input stream has reached the end. | |
| 236 | + * @exception IOException the stream has been closed and the contained | |
| 237 | + * input stream does not support reading after close, or | |
| 238 | + * another I/O error occurs. | |
| 239 | + * @see java.io.FilterInputStream#in | |
| 240 | + */ | |
| 241 | + public final boolean readBoolean() throws IOException { | |
| 242 | + int ch = in.read(); | |
| 243 | + if (ch < 0) | |
| 244 | + throw new EOFException(); | |
| 245 | + return (ch != 0); | |
| 246 | + } | |
| 247 | + | |
| 248 | + /** | |
| 249 | + * See the general contract of the <code>readByte</code> | |
| 250 | + * method of <code>DataInput</code>. | |
| 251 | + * <p> | |
| 252 | + * Bytes | |
| 253 | + * for this operation are read from the contained | |
| 254 | + * input stream. | |
| 255 | + * | |
| 256 | + * @return the next byte of this input stream as a signed 8-bit | |
| 257 | + * <code>byte</code>. | |
| 258 | + * @exception EOFException if this input stream has reached the end. | |
| 259 | + * @exception IOException the stream has been closed and the contained | |
| 260 | + * input stream does not support reading after close, or | |
| 261 | + * another I/O error occurs. | |
| 262 | + * @see java.io.FilterInputStream#in | |
| 263 | + */ | |
| 264 | + public final byte readByte() throws IOException { | |
| 265 | + int ch = in.read(); | |
| 266 | + if (ch < 0) | |
| 267 | + throw new EOFException(); | |
| 268 | + return (byte)(ch); | |
| 269 | + } | |
| 270 | + | |
| 271 | + /** | |
| 272 | + * See the general contract of the <code>readUnsignedByte</code> | |
| 273 | + * method of <code>DataInput</code>. | |
| 274 | + * <p> | |
| 275 | + * Bytes | |
| 276 | + * for this operation are read from the contained | |
| 277 | + * input stream. | |
| 278 | + * | |
| 279 | + * @return the next byte of this input stream, interpreted as an | |
| 280 | + * unsigned 8-bit number. | |
| 281 | + * @exception EOFException if this input stream has reached the end. | |
| 282 | + * @exception IOException the stream has been closed and the contained | |
| 283 | + * input stream does not support reading after close, or | |
| 284 | + * another I/O error occurs. | |
| 285 | + * @see java.io.FilterInputStream#in | |
| 286 | + */ | |
| 287 | + public final int readUnsignedByte() throws IOException { | |
| 288 | + int ch = in.read(); | |
| 289 | + if (ch < 0) | |
| 290 | + throw new EOFException(); | |
| 291 | + return ch; | |
| 292 | + } | |
| 293 | + | |
| 294 | + /** | |
| 295 | + * See the general contract of the <code>readShort</code> | |
| 296 | + * method of <code>DataInput</code>. | |
| 297 | + * <p> | |
| 298 | + * Bytes | |
| 299 | + * for this operation are read from the contained | |
| 300 | + * input stream. | |
| 301 | + * | |
| 302 | + * @return the next two bytes of this input stream, interpreted as a | |
| 303 | + * signed 16-bit number. | |
| 304 | + * @exception EOFException if this input stream reaches the end before | |
| 305 | + * reading two bytes. | |
| 306 | + * @exception IOException the stream has been closed and the contained | |
| 307 | + * input stream does not support reading after close, or | |
| 308 | + * another I/O error occurs. | |
| 309 | + * @see java.io.FilterInputStream#in | |
| 310 | + */ | |
| 311 | + public final short readShort() throws IOException { | |
| 312 | + int ch1 = in.read(); | |
| 313 | + int ch2 = in.read(); | |
| 314 | + if ((ch1 | ch2) < 0) | |
| 315 | + throw new EOFException(); | |
| 316 | + return (short)((ch1 << 8) + (ch2 << 0)); | |
| 317 | + } | |
| 318 | + | |
| 319 | + /** | |
| 320 | + * See the general contract of the <code>readUnsignedShort</code> | |
| 321 | + * method of <code>DataInput</code>. | |
| 322 | + * <p> | |
| 323 | + * Bytes | |
| 324 | + * for this operation are read from the contained | |
| 325 | + * input stream. | |
| 326 | + * | |
| 327 | + * @return the next two bytes of this input stream, interpreted as an | |
| 328 | + * unsigned 16-bit integer. | |
| 329 | + * @exception EOFException if this input stream reaches the end before | |
| 330 | + * reading two bytes. | |
| 331 | + * @exception IOException the stream has been closed and the contained | |
| 332 | + * input stream does not support reading after close, or | |
| 333 | + * another I/O error occurs. | |
| 334 | + * @see java.io.FilterInputStream#in | |
| 335 | + */ | |
| 336 | + public final int readUnsignedShort() throws IOException { | |
| 337 | + int ch1 = in.read(); | |
| 338 | + int ch2 = in.read(); | |
| 339 | + if ((ch1 | ch2) < 0) | |
| 340 | + throw new EOFException(); | |
| 341 | + return (ch1 << 8) + (ch2 << 0); | |
| 342 | + } | |
| 343 | + | |
| 344 | + /** | |
| 345 | + * See the general contract of the <code>readChar</code> | |
| 346 | + * method of <code>DataInput</code>. | |
| 347 | + * <p> | |
| 348 | + * Bytes | |
| 349 | + * for this operation are read from the contained | |
| 350 | + * input stream. | |
| 351 | + * | |
| 352 | + * @return the next two bytes of this input stream, interpreted as a | |
| 353 | + * <code>char</code>. | |
| 354 | + * @exception EOFException if this input stream reaches the end before | |
| 355 | + * reading two bytes. | |
| 356 | + * @exception IOException the stream has been closed and the contained | |
| 357 | + * input stream does not support reading after close, or | |
| 358 | + * another I/O error occurs. | |
| 359 | + * @see java.io.FilterInputStream#in | |
| 360 | + */ | |
| 361 | + public final char readChar() throws IOException { | |
| 362 | + int ch1 = in.read(); | |
| 363 | + int ch2 = in.read(); | |
| 364 | + if ((ch1 | ch2) < 0) | |
| 365 | + throw new EOFException(); | |
| 366 | + return (char)((ch1 << 8) + (ch2 << 0)); | |
| 367 | + } | |
| 368 | + | |
| 369 | + /** | |
| 370 | + * See the general contract of the <code>readInt</code> | |
| 371 | + * method of <code>DataInput</code>. | |
| 372 | + * <p> | |
| 373 | + * Bytes | |
| 374 | + * for this operation are read from the contained | |
| 375 | + * input stream. | |
| 376 | + * | |
| 377 | + * @return the next four bytes of this input stream, interpreted as an | |
| 378 | + * <code>int</code>. | |
| 379 | + * @exception EOFException if this input stream reaches the end before | |
| 380 | + * reading four bytes. | |
| 381 | + * @exception IOException the stream has been closed and the contained | |
| 382 | + * input stream does not support reading after close, or | |
| 383 | + * another I/O error occurs. | |
| 384 | + * @see java.io.FilterInputStream#in | |
| 385 | + */ | |
| 386 | + public final int readInt() throws IOException { | |
| 387 | + int ch1 = in.read(); | |
| 388 | + int ch2 = in.read(); | |
| 389 | + int ch3 = in.read(); | |
| 390 | + int ch4 = in.read(); | |
| 391 | + if ((ch1 | ch2 | ch3 | ch4) < 0) | |
| 392 | + throw new EOFException(); | |
| 393 | + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); | |
| 394 | + } | |
| 395 | + | |
| 396 | + private byte readBuffer[] = new byte[8]; | |
| 397 | + | |
| 398 | + /** | |
| 399 | + * See the general contract of the <code>readLong</code> | |
| 400 | + * method of <code>DataInput</code>. | |
| 401 | + * <p> | |
| 402 | + * Bytes | |
| 403 | + * for this operation are read from the contained | |
| 404 | + * input stream. | |
| 405 | + * | |
| 406 | + * @return the next eight bytes of this input stream, interpreted as a | |
| 407 | + * <code>long</code>. | |
| 408 | + * @exception EOFException if this input stream reaches the end before | |
| 409 | + * reading eight bytes. | |
| 410 | + * @exception IOException the stream has been closed and the contained | |
| 411 | + * input stream does not support reading after close, or | |
| 412 | + * another I/O error occurs. | |
| 413 | + * @see java.io.FilterInputStream#in | |
| 414 | + */ | |
| 415 | + public final long readLong() throws IOException { | |
| 416 | + readFully(readBuffer, 0, 8); | |
| 417 | + return (((long)readBuffer[0] << 56) + | |
| 418 | + ((long)(readBuffer[1] & 255) << 48) + | |
| 419 | + ((long)(readBuffer[2] & 255) << 40) + | |
| 420 | + ((long)(readBuffer[3] & 255) << 32) + | |
| 421 | + ((long)(readBuffer[4] & 255) << 24) + | |
| 422 | + ((readBuffer[5] & 255) << 16) + | |
| 423 | + ((readBuffer[6] & 255) << 8) + | |
| 424 | + ((readBuffer[7] & 255) << 0)); | |
| 425 | + } | |
| 426 | + | |
| 427 | + /** | |
| 428 | + * See the general contract of the <code>readFloat</code> | |
| 429 | + * method of <code>DataInput</code>. | |
| 430 | + * <p> | |
| 431 | + * Bytes | |
| 432 | + * for this operation are read from the contained | |
| 433 | + * input stream. | |
| 434 | + * | |
| 435 | + * @return the next four bytes of this input stream, interpreted as a | |
| 436 | + * <code>float</code>. | |
| 437 | + * @exception EOFException if this input stream reaches the end before | |
| 438 | + * reading four bytes. | |
| 439 | + * @exception IOException the stream has been closed and the contained | |
| 440 | + * input stream does not support reading after close, or | |
| 441 | + * another I/O error occurs. | |
| 442 | + * @see java.io.DataInputStream#readInt() | |
| 443 | + * @see java.lang.Float#intBitsToFloat(int) | |
| 444 | + */ | |
| 445 | + public final float readFloat() throws IOException { | |
| 446 | + return Float.intBitsToFloat(readInt()); | |
| 447 | + } | |
| 448 | + | |
| 449 | + /** | |
| 450 | + * See the general contract of the <code>readDouble</code> | |
| 451 | + * method of <code>DataInput</code>. | |
| 452 | + * <p> | |
| 453 | + * Bytes | |
| 454 | + * for this operation are read from the contained | |
| 455 | + * input stream. | |
| 456 | + * | |
| 457 | + * @return the next eight bytes of this input stream, interpreted as a | |
| 458 | + * <code>double</code>. | |
| 459 | + * @exception EOFException if this input stream reaches the end before | |
| 460 | + * reading eight bytes. | |
| 461 | + * @exception IOException the stream has been closed and the contained | |
| 462 | + * input stream does not support reading after close, or | |
| 463 | + * another I/O error occurs. | |
| 464 | + * @see java.io.DataInputStream#readLong() | |
| 465 | + * @see java.lang.Double#longBitsToDouble(long) | |
| 466 | + */ | |
| 467 | + public final double readDouble() throws IOException { | |
| 468 | + return Double.longBitsToDouble(readLong()); | |
| 469 | + } | |
| 470 | + | |
| 471 | + private char lineBuffer[]; | |
| 472 | + | |
| 473 | + /** | |
| 474 | + * See the general contract of the <code>readLine</code> | |
| 475 | + * method of <code>DataInput</code>. | |
| 476 | + * <p> | |
| 477 | + * Bytes | |
| 478 | + * for this operation are read from the contained | |
| 479 | + * input stream. | |
| 480 | + * | |
| 481 | + * @deprecated This method does not properly convert bytes to characters. | |
| 482 | + * As of JDK 1.1, the preferred way to read lines of text is via the | |
| 483 | + * <code>BufferedReader.readLine()</code> method. Programs that use the | |
| 484 | + * <code>DataInputStream</code> class to read lines can be converted to use | |
| 485 | + * the <code>BufferedReader</code> class by replacing code of the form: | |
| 486 | + * <blockquote><pre> | |
| 487 | + * DataInputStream d = new DataInputStream(in); | |
| 488 | + * </pre></blockquote> | |
| 489 | + * with: | |
| 490 | + * <blockquote><pre> | |
| 491 | + * BufferedReader d | |
| 492 | + * = new BufferedReader(new InputStreamReader(in)); | |
| 493 | + * </pre></blockquote> | |
| 494 | + * | |
| 495 | + * @return the next line of text from this input stream. | |
| 496 | + * @exception IOException if an I/O error occurs. | |
| 497 | + * @see java.io.BufferedReader#readLine() | |
| 498 | + * @see java.io.FilterInputStream#in | |
| 499 | + */ | |
| 500 | + @Deprecated | |
| 501 | + public final String readLine() throws IOException { | |
| 502 | + char buf[] = lineBuffer; | |
| 503 | + | |
| 504 | + if (buf == null) { | |
| 505 | + buf = lineBuffer = new char[128]; | |
| 506 | + } | |
| 507 | + | |
| 508 | + int room = buf.length; | |
| 509 | + int offset = 0; | |
| 510 | + int c; | |
| 511 | + | |
| 512 | +loop: while (true) { | |
| 513 | + switch (c = in.read()) { | |
| 514 | + case -1: | |
| 515 | + case '\n': | |
| 516 | + break loop; | |
| 517 | + | |
| 518 | + case '\r': | |
| 519 | + int c2 = in.read(); | |
| 520 | + if ((c2 != '\n') && (c2 != -1)) { | |
| 521 | + if (!(in instanceof PushbackInputStream)) { | |
| 522 | + this.in = new PushbackInputStream(in); | |
| 523 | + } | |
| 524 | + ((PushbackInputStream)in).unread(c2); | |
| 525 | + } | |
| 526 | + break loop; | |
| 527 | + | |
| 528 | + default: | |
| 529 | + if (--room < 0) { | |
| 530 | + buf = new char[offset + 128]; | |
| 531 | + room = buf.length - offset - 1; | |
| 532 | + System.arraycopy(lineBuffer, 0, buf, 0, offset); | |
| 533 | + lineBuffer = buf; | |
| 534 | + } | |
| 535 | + buf[offset++] = (char) c; | |
| 536 | + break; | |
| 537 | + } | |
| 538 | + } | |
| 539 | + if ((c == -1) && (offset == 0)) { | |
| 540 | + return null; | |
| 541 | + } | |
| 542 | + return String.copyValueOf(buf, 0, offset); | |
| 543 | + } | |
| 544 | + | |
| 545 | + /** | |
| 546 | + * See the general contract of the <code>readUTF</code> | |
| 547 | + * method of <code>DataInput</code>. | |
| 548 | + * <p> | |
| 549 | + * Bytes | |
| 550 | + * for this operation are read from the contained | |
| 551 | + * input stream. | |
| 552 | + * | |
| 553 | + * @return a Unicode string. | |
| 554 | + * @exception EOFException if this input stream reaches the end before | |
| 555 | + * reading all the bytes. | |
| 556 | + * @exception IOException the stream has been closed and the contained | |
| 557 | + * input stream does not support reading after close, or | |
| 558 | + * another I/O error occurs. | |
| 559 | + * @exception UTFDataFormatException if the bytes do not represent a valid | |
| 560 | + * modified UTF-8 encoding of a string. | |
| 561 | + * @see java.io.DataInputStream#readUTF(java.io.DataInput) | |
| 562 | + */ | |
| 563 | + public final String readUTF() throws IOException { | |
| 564 | + return readUTF(this); | |
| 565 | + } | |
| 566 | + | |
| 567 | + /** | |
| 568 | + * Reads from the | |
| 569 | + * stream <code>in</code> a representation | |
| 570 | + * of a Unicode character string encoded in | |
| 571 | + * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> format; | |
| 572 | + * this string of characters is then returned as a <code>String</code>. | |
| 573 | + * The details of the modified UTF-8 representation | |
| 574 | + * are exactly the same as for the <code>readUTF</code> | |
| 575 | + * method of <code>DataInput</code>. | |
| 576 | + * | |
| 577 | + * @param in a data input stream. | |
| 578 | + * @return a Unicode string. | |
| 579 | + * @exception EOFException if the input stream reaches the end | |
| 580 | + * before all the bytes. | |
| 581 | + * @exception IOException the stream has been closed and the contained | |
| 582 | + * input stream does not support reading after close, or | |
| 583 | + * another I/O error occurs. | |
| 584 | + * @exception UTFDataFormatException if the bytes do not represent a | |
| 585 | + * valid modified UTF-8 encoding of a Unicode string. | |
| 586 | + * @see java.io.DataInputStream#readUnsignedShort() | |
| 587 | + */ | |
| 588 | + public final static String readUTF(DataInput in) throws IOException { | |
| 589 | + int utflen = in.readUnsignedShort(); | |
| 590 | + byte[] bytearr = null; | |
| 591 | + char[] chararr = null; | |
| 592 | + if (in instanceof DataInputStream) { | |
| 593 | + DataInputStream dis = (DataInputStream)in; | |
| 594 | + if (dis.bytearr.length < utflen){ | |
| 595 | + dis.bytearr = new byte[utflen*2]; | |
| 596 | + dis.chararr = new char[utflen*2]; | |
| 597 | + } | |
| 598 | + chararr = dis.chararr; | |
| 599 | + bytearr = dis.bytearr; | |
| 600 | + } else { | |
| 601 | + bytearr = new byte[utflen]; | |
| 602 | + chararr = new char[utflen]; | |
| 603 | + } | |
| 604 | + | |
| 605 | + int c, char2, char3; | |
| 606 | + int count = 0; | |
| 607 | + int chararr_count=0; | |
| 608 | + | |
| 609 | + in.readFully(bytearr, 0, utflen); | |
| 610 | + | |
| 611 | + while (count < utflen) { | |
| 612 | + c = (int) bytearr[count] & 0xff; | |
| 613 | + if (c > 127) break; | |
| 614 | + count++; | |
| 615 | + chararr[chararr_count++]=(char)c; | |
| 616 | + } | |
| 617 | + | |
| 618 | + while (count < utflen) { | |
| 619 | + c = (int) bytearr[count] & 0xff; | |
| 620 | + switch (c >> 4) { | |
| 621 | + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: | |
| 622 | + /* 0xxxxxxx*/ | |
| 623 | + count++; | |
| 624 | + chararr[chararr_count++]=(char)c; | |
| 625 | + break; | |
| 626 | + case 12: case 13: | |
| 627 | + /* 110x xxxx 10xx xxxx*/ | |
| 628 | + count += 2; | |
| 629 | + if (count > utflen) | |
| 630 | + throw new UTFDataFormatException( | |
| 631 | + "malformed input: partial character at end"); | |
| 632 | + char2 = (int) bytearr[count-1]; | |
| 633 | + if ((char2 & 0xC0) != 0x80) | |
| 634 | + throw new UTFDataFormatException( | |
| 635 | + "malformed input around byte " + count); | |
| 636 | + chararr[chararr_count++]=(char)(((c & 0x1F) << 6) | | |
| 637 | + (char2 & 0x3F)); | |
| 638 | + break; | |
| 639 | + case 14: | |
| 640 | + /* 1110 xxxx 10xx xxxx 10xx xxxx */ | |
| 641 | + count += 3; | |
| 642 | + if (count > utflen) | |
| 643 | + throw new UTFDataFormatException( | |
| 644 | + "malformed input: partial character at end"); | |
| 645 | + char2 = (int) bytearr[count-2]; | |
| 646 | + char3 = (int) bytearr[count-1]; | |
| 647 | + if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) | |
| 648 | + throw new UTFDataFormatException( | |
| 649 | + "malformed input around byte " + (count-1)); | |
| 650 | + chararr[chararr_count++]=(char)(((c & 0x0F) << 12) | | |
| 651 | + ((char2 & 0x3F) << 6) | | |
| 652 | + ((char3 & 0x3F) << 0)); | |
| 653 | + break; | |
| 654 | + default: | |
| 655 | + /* 10xx xxxx, 1111 xxxx */ | |
| 656 | + throw new UTFDataFormatException( | |
| 657 | + "malformed input around byte " + count); | |
| 658 | + } | |
| 659 | + } | |
| 660 | + // The number of chars produced may be less than utflen | |
| 661 | + return new String(chararr, 0, chararr_count); | |
| 662 | + } | |
| 663 | +} | |
Binary file not shown.
| @@ -0,0 +1,354 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * The <code>DataOutput</code> interface provides | |
| 30 | + * for converting data from any of the Java | |
| 31 | + * primitive types to a series of bytes and | |
| 32 | + * writing these bytes to a binary stream. | |
| 33 | + * There is also a facility for converting | |
| 34 | + * a <code>String</code> into | |
| 35 | + * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> | |
| 36 | + * format and writing the resulting series | |
| 37 | + * of bytes. | |
| 38 | + * <p> | |
| 39 | + * For all the methods in this interface that | |
| 40 | + * write bytes, it is generally true that if | |
| 41 | + * a byte cannot be written for any reason, | |
| 42 | + * an <code>IOException</code> is thrown. | |
| 43 | + * | |
| 44 | + * @author Frank Yellin | |
| 45 | + * @see java.io.DataInput | |
| 46 | + * @see java.io.DataOutputStream | |
| 47 | + * @since JDK1.0 | |
| 48 | + */ | |
| 49 | +public | |
| 50 | +interface DataOutput { | |
| 51 | + /** | |
| 52 | + * Writes to the output stream the eight | |
| 53 | + * low-order bits of the argument <code>b</code>. | |
| 54 | + * The 24 high-order bits of <code>b</code> | |
| 55 | + * are ignored. | |
| 56 | + * | |
| 57 | + * @param b the byte to be written. | |
| 58 | + * @throws IOException if an I/O error occurs. | |
| 59 | + */ | |
| 60 | + void write(int b) throws IOException; | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Writes to the output stream all the bytes in array <code>b</code>. | |
| 64 | + * If <code>b</code> is <code>null</code>, | |
| 65 | + * a <code>NullPointerException</code> is thrown. | |
| 66 | + * If <code>b.length</code> is zero, then | |
| 67 | + * no bytes are written. Otherwise, the byte | |
| 68 | + * <code>b[0]</code> is written first, then | |
| 69 | + * <code>b[1]</code>, and so on; the last byte | |
| 70 | + * written is <code>b[b.length-1]</code>. | |
| 71 | + * | |
| 72 | + * @param b the data. | |
| 73 | + * @throws IOException if an I/O error occurs. | |
| 74 | + */ | |
| 75 | + void write(byte b[]) throws IOException; | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * Writes <code>len</code> bytes from array | |
| 79 | + * <code>b</code>, in order, to | |
| 80 | + * the output stream. If <code>b</code> | |
| 81 | + * is <code>null</code>, a <code>NullPointerException</code> | |
| 82 | + * is thrown. If <code>off</code> is negative, | |
| 83 | + * or <code>len</code> is negative, or <code>off+len</code> | |
| 84 | + * is greater than the length of the array | |
| 85 | + * <code>b</code>, then an <code>IndexOutOfBoundsException</code> | |
| 86 | + * is thrown. If <code>len</code> is zero, | |
| 87 | + * then no bytes are written. Otherwise, the | |
| 88 | + * byte <code>b[off]</code> is written first, | |
| 89 | + * then <code>b[off+1]</code>, and so on; the | |
| 90 | + * last byte written is <code>b[off+len-1]</code>. | |
| 91 | + * | |
| 92 | + * @param b the data. | |
| 93 | + * @param off the start offset in the data. | |
| 94 | + * @param len the number of bytes to write. | |
| 95 | + * @throws IOException if an I/O error occurs. | |
| 96 | + */ | |
| 97 | + void write(byte b[], int off, int len) throws IOException; | |
| 98 | + | |
| 99 | + /** | |
| 100 | + * Writes a <code>boolean</code> value to this output stream. | |
| 101 | + * If the argument <code>v</code> | |
| 102 | + * is <code>true</code>, the value <code>(byte)1</code> | |
| 103 | + * is written; if <code>v</code> is <code>false</code>, | |
| 104 | + * the value <code>(byte)0</code> is written. | |
| 105 | + * The byte written by this method may | |
| 106 | + * be read by the <code>readBoolean</code> | |
| 107 | + * method of interface <code>DataInput</code>, | |
| 108 | + * which will then return a <code>boolean</code> | |
| 109 | + * equal to <code>v</code>. | |
| 110 | + * | |
| 111 | + * @param v the boolean to be written. | |
| 112 | + * @throws IOException if an I/O error occurs. | |
| 113 | + */ | |
| 114 | + void writeBoolean(boolean v) throws IOException; | |
| 115 | + | |
| 116 | + /** | |
| 117 | + * Writes to the output stream the eight low- | |
| 118 | + * order bits of the argument <code>v</code>. | |
| 119 | + * The 24 high-order bits of <code>v</code> | |
| 120 | + * are ignored. (This means that <code>writeByte</code> | |
| 121 | + * does exactly the same thing as <code>write</code> | |
| 122 | + * for an integer argument.) The byte written | |
| 123 | + * by this method may be read by the <code>readByte</code> | |
| 124 | + * method of interface <code>DataInput</code>, | |
| 125 | + * which will then return a <code>byte</code> | |
| 126 | + * equal to <code>(byte)v</code>. | |
| 127 | + * | |
| 128 | + * @param v the byte value to be written. | |
| 129 | + * @throws IOException if an I/O error occurs. | |
| 130 | + */ | |
| 131 | + void writeByte(int v) throws IOException; | |
| 132 | + | |
| 133 | + /** | |
| 134 | + * Writes two bytes to the output | |
| 135 | + * stream to represent the value of the argument. | |
| 136 | + * The byte values to be written, in the order | |
| 137 | + * shown, are: <p> | |
| 138 | + * <pre><code> | |
| 139 | + * (byte)(0xff & (v >> 8)) | |
| 140 | + * (byte)(0xff & v) | |
| 141 | + * </code> </pre> <p> | |
| 142 | + * The bytes written by this method may be | |
| 143 | + * read by the <code>readShort</code> method | |
| 144 | + * of interface <code>DataInput</code> , which | |
| 145 | + * will then return a <code>short</code> equal | |
| 146 | + * to <code>(short)v</code>. | |
| 147 | + * | |
| 148 | + * @param v the <code>short</code> value to be written. | |
| 149 | + * @throws IOException if an I/O error occurs. | |
| 150 | + */ | |
| 151 | + void writeShort(int v) throws IOException; | |
| 152 | + | |
| 153 | + /** | |
| 154 | + * Writes a <code>char</code> value, which | |
| 155 | + * is comprised of two bytes, to the | |
| 156 | + * output stream. | |
| 157 | + * The byte values to be written, in the order | |
| 158 | + * shown, are: | |
| 159 | + * <p><pre><code> | |
| 160 | + * (byte)(0xff & (v >> 8)) | |
| 161 | + * (byte)(0xff & v) | |
| 162 | + * </code></pre><p> | |
| 163 | + * The bytes written by this method may be | |
| 164 | + * read by the <code>readChar</code> method | |
| 165 | + * of interface <code>DataInput</code> , which | |
| 166 | + * will then return a <code>char</code> equal | |
| 167 | + * to <code>(char)v</code>. | |
| 168 | + * | |
| 169 | + * @param v the <code>char</code> value to be written. | |
| 170 | + * @throws IOException if an I/O error occurs. | |
| 171 | + */ | |
| 172 | + void writeChar(int v) throws IOException; | |
| 173 | + | |
| 174 | + /** | |
| 175 | + * Writes an <code>int</code> value, which is | |
| 176 | + * comprised of four bytes, to the output stream. | |
| 177 | + * The byte values to be written, in the order | |
| 178 | + * shown, are: | |
| 179 | + * <p><pre><code> | |
| 180 | + * (byte)(0xff & (v >> 24)) | |
| 181 | + * (byte)(0xff & (v >> 16)) | |
| 182 | + * (byte)(0xff & (v >>    8)) | |
| 183 | + * (byte)(0xff & v) | |
| 184 | + * </code></pre><p> | |
| 185 | + * The bytes written by this method may be read | |
| 186 | + * by the <code>readInt</code> method of interface | |
| 187 | + * <code>DataInput</code> , which will then | |
| 188 | + * return an <code>int</code> equal to <code>v</code>. | |
| 189 | + * | |
| 190 | + * @param v the <code>int</code> value to be written. | |
| 191 | + * @throws IOException if an I/O error occurs. | |
| 192 | + */ | |
| 193 | + void writeInt(int v) throws IOException; | |
| 194 | + | |
| 195 | + /** | |
| 196 | + * Writes a <code>long</code> value, which is | |
| 197 | + * comprised of eight bytes, to the output stream. | |
| 198 | + * The byte values to be written, in the order | |
| 199 | + * shown, are: | |
| 200 | + * <p><pre><code> | |
| 201 | + * (byte)(0xff & (v >> 56)) | |
| 202 | + * (byte)(0xff & (v >> 48)) | |
| 203 | + * (byte)(0xff & (v >> 40)) | |
| 204 | + * (byte)(0xff & (v >> 32)) | |
| 205 | + * (byte)(0xff & (v >> 24)) | |
| 206 | + * (byte)(0xff & (v >> 16)) | |
| 207 | + * (byte)(0xff & (v >> 8)) | |
| 208 | + * (byte)(0xff & v) | |
| 209 | + * </code></pre><p> | |
| 210 | + * The bytes written by this method may be | |
| 211 | + * read by the <code>readLong</code> method | |
| 212 | + * of interface <code>DataInput</code> , which | |
| 213 | + * will then return a <code>long</code> equal | |
| 214 | + * to <code>v</code>. | |
| 215 | + * | |
| 216 | + * @param v the <code>long</code> value to be written. | |
| 217 | + * @throws IOException if an I/O error occurs. | |
| 218 | + */ | |
| 219 | + void writeLong(long v) throws IOException; | |
| 220 | + | |
| 221 | + /** | |
| 222 | + * Writes a <code>float</code> value, | |
| 223 | + * which is comprised of four bytes, to the output stream. | |
| 224 | + * It does this as if it first converts this | |
| 225 | + * <code>float</code> value to an <code>int</code> | |
| 226 | + * in exactly the manner of the <code>Float.floatToIntBits</code> | |
| 227 | + * method and then writes the <code>int</code> | |
| 228 | + * value in exactly the manner of the <code>writeInt</code> | |
| 229 | + * method. The bytes written by this method | |
| 230 | + * may be read by the <code>readFloat</code> | |
| 231 | + * method of interface <code>DataInput</code>, | |
| 232 | + * which will then return a <code>float</code> | |
| 233 | + * equal to <code>v</code>. | |
| 234 | + * | |
| 235 | + * @param v the <code>float</code> value to be written. | |
| 236 | + * @throws IOException if an I/O error occurs. | |
| 237 | + */ | |
| 238 | + void writeFloat(float v) throws IOException; | |
| 239 | + | |
| 240 | + /** | |
| 241 | + * Writes a <code>double</code> value, | |
| 242 | + * which is comprised of eight bytes, to the output stream. | |
| 243 | + * It does this as if it first converts this | |
| 244 | + * <code>double</code> value to a <code>long</code> | |
| 245 | + * in exactly the manner of the <code>Double.doubleToLongBits</code> | |
| 246 | + * method and then writes the <code>long</code> | |
| 247 | + * value in exactly the manner of the <code>writeLong</code> | |
| 248 | + * method. The bytes written by this method | |
| 249 | + * may be read by the <code>readDouble</code> | |
| 250 | + * method of interface <code>DataInput</code>, | |
| 251 | + * which will then return a <code>double</code> | |
| 252 | + * equal to <code>v</code>. | |
| 253 | + * | |
| 254 | + * @param v the <code>double</code> value to be written. | |
| 255 | + * @throws IOException if an I/O error occurs. | |
| 256 | + */ | |
| 257 | + void writeDouble(double v) throws IOException; | |
| 258 | + | |
| 259 | + /** | |
| 260 | + * Writes a string to the output stream. | |
| 261 | + * For every character in the string | |
| 262 | + * <code>s</code>, taken in order, one byte | |
| 263 | + * is written to the output stream. If | |
| 264 | + * <code>s</code> is <code>null</code>, a <code>NullPointerException</code> | |
| 265 | + * is thrown.<p> If <code>s.length</code> | |
| 266 | + * is zero, then no bytes are written. Otherwise, | |
| 267 | + * the character <code>s[0]</code> is written | |
| 268 | + * first, then <code>s[1]</code>, and so on; | |
| 269 | + * the last character written is <code>s[s.length-1]</code>. | |
| 270 | + * For each character, one byte is written, | |
| 271 | + * the low-order byte, in exactly the manner | |
| 272 | + * of the <code>writeByte</code> method . The | |
| 273 | + * high-order eight bits of each character | |
| 274 | + * in the string are ignored. | |
| 275 | + * | |
| 276 | + * @param s the string of bytes to be written. | |
| 277 | + * @throws IOException if an I/O error occurs. | |
| 278 | + */ | |
| 279 | + void writeBytes(String s) throws IOException; | |
| 280 | + | |
| 281 | + /** | |
| 282 | + * Writes every character in the string <code>s</code>, | |
| 283 | + * to the output stream, in order, | |
| 284 | + * two bytes per character. If <code>s</code> | |
| 285 | + * is <code>null</code>, a <code>NullPointerException</code> | |
| 286 | + * is thrown. If <code>s.length</code> | |
| 287 | + * is zero, then no characters are written. | |
| 288 | + * Otherwise, the character <code>s[0]</code> | |
| 289 | + * is written first, then <code>s[1]</code>, | |
| 290 | + * and so on; the last character written is | |
| 291 | + * <code>s[s.length-1]</code>. For each character, | |
| 292 | + * two bytes are actually written, high-order | |
| 293 | + * byte first, in exactly the manner of the | |
| 294 | + * <code>writeChar</code> method. | |
| 295 | + * | |
| 296 | + * @param s the string value to be written. | |
| 297 | + * @throws IOException if an I/O error occurs. | |
| 298 | + */ | |
| 299 | + void writeChars(String s) throws IOException; | |
| 300 | + | |
| 301 | + /** | |
| 302 | + * Writes two bytes of length information | |
| 303 | + * to the output stream, followed | |
| 304 | + * by the | |
| 305 | + * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> | |
| 306 | + * representation | |
| 307 | + * of every character in the string <code>s</code>. | |
| 308 | + * If <code>s</code> is <code>null</code>, | |
| 309 | + * a <code>NullPointerException</code> is thrown. | |
| 310 | + * Each character in the string <code>s</code> | |
| 311 | + * is converted to a group of one, two, or | |
| 312 | + * three bytes, depending on the value of the | |
| 313 | + * character.<p> | |
| 314 | + * If a character <code>c</code> | |
| 315 | + * is in the range <code>\u0001</code> through | |
| 316 | + * <code>\u007f</code>, it is represented | |
| 317 | + * by one byte:<p> | |
| 318 | + * <pre>(byte)c </pre> <p> | |
| 319 | + * If a character <code>c</code> is <code>\u0000</code> | |
| 320 | + * or is in the range <code>\u0080</code> | |
| 321 | + * through <code>\u07ff</code>, then it is | |
| 322 | + * represented by two bytes, to be written | |
| 323 | + * in the order shown:<p> <pre><code> | |
| 324 | + * (byte)(0xc0 | (0x1f & (c >> 6))) | |
| 325 | + * (byte)(0x80 | (0x3f & c)) | |
| 326 | + * </code></pre> <p> If a character | |
| 327 | + * <code>c</code> is in the range <code>\u0800</code> | |
| 328 | + * through <code>uffff</code>, then it is | |
| 329 | + * represented by three bytes, to be written | |
| 330 | + * in the order shown:<p> <pre><code> | |
| 331 | + * (byte)(0xe0 | (0x0f & (c >> 12))) | |
| 332 | + * (byte)(0x80 | (0x3f & (c >> 6))) | |
| 333 | + * (byte)(0x80 | (0x3f & c)) | |
| 334 | + * </code></pre> <p> First, | |
| 335 | + * the total number of bytes needed to represent | |
| 336 | + * all the characters of <code>s</code> is | |
| 337 | + * calculated. If this number is larger than | |
| 338 | + * <code>65535</code>, then a <code>UTFDataFormatException</code> | |
| 339 | + * is thrown. Otherwise, this length is written | |
| 340 | + * to the output stream in exactly the manner | |
| 341 | + * of the <code>writeShort</code> method; | |
| 342 | + * after this, the one-, two-, or three-byte | |
| 343 | + * representation of each character in the | |
| 344 | + * string <code>s</code> is written.<p> The | |
| 345 | + * bytes written by this method may be read | |
| 346 | + * by the <code>readUTF</code> method of interface | |
| 347 | + * <code>DataInput</code> , which will then | |
| 348 | + * return a <code>String</code> equal to <code>s</code>. | |
| 349 | + * | |
| 350 | + * @param s the string value to be written. | |
| 351 | + * @throws IOException if an I/O error occurs. | |
| 352 | + */ | |
| 353 | + void writeUTF(String s) throws IOException; | |
| 354 | +} | |
Binary file not shown.
| @@ -0,0 +1,416 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * A data output stream lets an application write primitive Java data | |
| 30 | + * types to an output stream in a portable way. An application can | |
| 31 | + * then use a data input stream to read the data back in. | |
| 32 | + * | |
| 33 | + * @author unascribed | |
| 34 | + * @see java.io.DataInputStream | |
| 35 | + * @since JDK1.0 | |
| 36 | + */ | |
| 37 | +public | |
| 38 | +class DataOutputStream extends FilterOutputStream implements DataOutput { | |
| 39 | + /** | |
| 40 | + * The number of bytes written to the data output stream so far. | |
| 41 | + * If this counter overflows, it will be wrapped to Integer.MAX_VALUE. | |
| 42 | + */ | |
| 43 | + protected int written; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * bytearr is initialized on demand by writeUTF | |
| 47 | + */ | |
| 48 | + private byte[] bytearr = null; | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Creates a new data output stream to write data to the specified | |
| 52 | + * underlying output stream. The counter <code>written</code> is | |
| 53 | + * set to zero. | |
| 54 | + * | |
| 55 | + * @param out the underlying output stream, to be saved for later | |
| 56 | + * use. | |
| 57 | + * @see java.io.FilterOutputStream#out | |
| 58 | + */ | |
| 59 | + public DataOutputStream(OutputStream out) { | |
| 60 | + super(out); | |
| 61 | + } | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * Increases the written counter by the specified value | |
| 65 | + * until it reaches Integer.MAX_VALUE. | |
| 66 | + */ | |
| 67 | + private void incCount(int value) { | |
| 68 | + int temp = written + value; | |
| 69 | + if (temp < 0) { | |
| 70 | + temp = Integer.MAX_VALUE; | |
| 71 | + } | |
| 72 | + written = temp; | |
| 73 | + } | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * Writes the specified byte (the low eight bits of the argument | |
| 77 | + * <code>b</code>) to the underlying output stream. If no exception | |
| 78 | + * is thrown, the counter <code>written</code> is incremented by | |
| 79 | + * <code>1</code>. | |
| 80 | + * <p> | |
| 81 | + * Implements the <code>write</code> method of <code>OutputStream</code>. | |
| 82 | + * | |
| 83 | + * @param b the <code>byte</code> to be written. | |
| 84 | + * @exception IOException if an I/O error occurs. | |
| 85 | + * @see java.io.FilterOutputStream#out | |
| 86 | + */ | |
| 87 | + public synchronized void write(int b) throws IOException { | |
| 88 | + out.write(b); | |
| 89 | + incCount(1); | |
| 90 | + } | |
| 91 | + | |
| 92 | + /** | |
| 93 | + * Writes <code>len</code> bytes from the specified byte array | |
| 94 | + * starting at offset <code>off</code> to the underlying output stream. | |
| 95 | + * If no exception is thrown, the counter <code>written</code> is | |
| 96 | + * incremented by <code>len</code>. | |
| 97 | + * | |
| 98 | + * @param b the data. | |
| 99 | + * @param off the start offset in the data. | |
| 100 | + * @param len the number of bytes to write. | |
| 101 | + * @exception IOException if an I/O error occurs. | |
| 102 | + * @see java.io.FilterOutputStream#out | |
| 103 | + */ | |
| 104 | + public synchronized void write(byte b[], int off, int len) | |
| 105 | + throws IOException | |
| 106 | + { | |
| 107 | + out.write(b, off, len); | |
| 108 | + incCount(len); | |
| 109 | + } | |
| 110 | + | |
| 111 | + /** | |
| 112 | + * Flushes this data output stream. This forces any buffered output | |
| 113 | + * bytes to be written out to the stream. | |
| 114 | + * <p> | |
| 115 | + * The <code>flush</code> method of <code>DataOutputStream</code> | |
| 116 | + * calls the <code>flush</code> method of its underlying output stream. | |
| 117 | + * | |
| 118 | + * @exception IOException if an I/O error occurs. | |
| 119 | + * @see java.io.FilterOutputStream#out | |
| 120 | + * @see java.io.OutputStream#flush() | |
| 121 | + */ | |
| 122 | + public void flush() throws IOException { | |
| 123 | + out.flush(); | |
| 124 | + } | |
| 125 | + | |
| 126 | + /** | |
| 127 | + * Writes a <code>boolean</code> to the underlying output stream as | |
| 128 | + * a 1-byte value. The value <code>true</code> is written out as the | |
| 129 | + * value <code>(byte)1</code>; the value <code>false</code> is | |
| 130 | + * written out as the value <code>(byte)0</code>. If no exception is | |
| 131 | + * thrown, the counter <code>written</code> is incremented by | |
| 132 | + * <code>1</code>. | |
| 133 | + * | |
| 134 | + * @param v a <code>boolean</code> value to be written. | |
| 135 | + * @exception IOException if an I/O error occurs. | |
| 136 | + * @see java.io.FilterOutputStream#out | |
| 137 | + */ | |
| 138 | + public final void writeBoolean(boolean v) throws IOException { | |
| 139 | + out.write(v ? 1 : 0); | |
| 140 | + incCount(1); | |
| 141 | + } | |
| 142 | + | |
| 143 | + /** | |
| 144 | + * Writes out a <code>byte</code> to the underlying output stream as | |
| 145 | + * a 1-byte value. If no exception is thrown, the counter | |
| 146 | + * <code>written</code> is incremented by <code>1</code>. | |
| 147 | + * | |
| 148 | + * @param v a <code>byte</code> value to be written. | |
| 149 | + * @exception IOException if an I/O error occurs. | |
| 150 | + * @see java.io.FilterOutputStream#out | |
| 151 | + */ | |
| 152 | + public final void writeByte(int v) throws IOException { | |
| 153 | + out.write(v); | |
| 154 | + incCount(1); | |
| 155 | + } | |
| 156 | + | |
| 157 | + /** | |
| 158 | + * Writes a <code>short</code> to the underlying output stream as two | |
| 159 | + * bytes, high byte first. If no exception is thrown, the counter | |
| 160 | + * <code>written</code> is incremented by <code>2</code>. | |
| 161 | + * | |
| 162 | + * @param v a <code>short</code> to be written. | |
| 163 | + * @exception IOException if an I/O error occurs. | |
| 164 | + * @see java.io.FilterOutputStream#out | |
| 165 | + */ | |
| 166 | + public final void writeShort(int v) throws IOException { | |
| 167 | + out.write((v >>> 8) & 0xFF); | |
| 168 | + out.write((v >>> 0) & 0xFF); | |
| 169 | + incCount(2); | |
| 170 | + } | |
| 171 | + | |
| 172 | + /** | |
| 173 | + * Writes a <code>char</code> to the underlying output stream as a | |
| 174 | + * 2-byte value, high byte first. If no exception is thrown, the | |
| 175 | + * counter <code>written</code> is incremented by <code>2</code>. | |
| 176 | + * | |
| 177 | + * @param v a <code>char</code> value to be written. | |
| 178 | + * @exception IOException if an I/O error occurs. | |
| 179 | + * @see java.io.FilterOutputStream#out | |
| 180 | + */ | |
| 181 | + public final void writeChar(int v) throws IOException { | |
| 182 | + out.write((v >>> 8) & 0xFF); | |
| 183 | + out.write((v >>> 0) & 0xFF); | |
| 184 | + incCount(2); | |
| 185 | + } | |
| 186 | + | |
| 187 | + /** | |
| 188 | + * Writes an <code>int</code> to the underlying output stream as four | |
| 189 | + * bytes, high byte first. If no exception is thrown, the counter | |
| 190 | + * <code>written</code> is incremented by <code>4</code>. | |
| 191 | + * | |
| 192 | + * @param v an <code>int</code> to be written. | |
| 193 | + * @exception IOException if an I/O error occurs. | |
| 194 | + * @see java.io.FilterOutputStream#out | |
| 195 | + */ | |
| 196 | + public final void writeInt(int v) throws IOException { | |
| 197 | + out.write((v >>> 24) & 0xFF); | |
| 198 | + out.write((v >>> 16) & 0xFF); | |
| 199 | + out.write((v >>> 8) & 0xFF); | |
| 200 | + out.write((v >>> 0) & 0xFF); | |
| 201 | + incCount(4); | |
| 202 | + } | |
| 203 | + | |
| 204 | + private byte writeBuffer[] = new byte[8]; | |
| 205 | + | |
| 206 | + /** | |
| 207 | + * Writes a <code>long</code> to the underlying output stream as eight | |
| 208 | + * bytes, high byte first. In no exception is thrown, the counter | |
| 209 | + * <code>written</code> is incremented by <code>8</code>. | |
| 210 | + * | |
| 211 | + * @param v a <code>long</code> to be written. | |
| 212 | + * @exception IOException if an I/O error occurs. | |
| 213 | + * @see java.io.FilterOutputStream#out | |
| 214 | + */ | |
| 215 | + public final void writeLong(long v) throws IOException { | |
| 216 | + writeBuffer[0] = (byte)(v >>> 56); | |
| 217 | + writeBuffer[1] = (byte)(v >>> 48); | |
| 218 | + writeBuffer[2] = (byte)(v >>> 40); | |
| 219 | + writeBuffer[3] = (byte)(v >>> 32); | |
| 220 | + writeBuffer[4] = (byte)(v >>> 24); | |
| 221 | + writeBuffer[5] = (byte)(v >>> 16); | |
| 222 | + writeBuffer[6] = (byte)(v >>> 8); | |
| 223 | + writeBuffer[7] = (byte)(v >>> 0); | |
| 224 | + out.write(writeBuffer, 0, 8); | |
| 225 | + incCount(8); | |
| 226 | + } | |
| 227 | + | |
| 228 | + /** | |
| 229 | + * Converts the float argument to an <code>int</code> using the | |
| 230 | + * <code>floatToIntBits</code> method in class <code>Float</code>, | |
| 231 | + * and then writes that <code>int</code> value to the underlying | |
| 232 | + * output stream as a 4-byte quantity, high byte first. If no | |
| 233 | + * exception is thrown, the counter <code>written</code> is | |
| 234 | + * incremented by <code>4</code>. | |
| 235 | + * | |
| 236 | + * @param v a <code>float</code> value to be written. | |
| 237 | + * @exception IOException if an I/O error occurs. | |
| 238 | + * @see java.io.FilterOutputStream#out | |
| 239 | + * @see java.lang.Float#floatToIntBits(float) | |
| 240 | + */ | |
| 241 | + public final void writeFloat(float v) throws IOException { | |
| 242 | + writeInt(Float.floatToIntBits(v)); | |
| 243 | + } | |
| 244 | + | |
| 245 | + /** | |
| 246 | + * Converts the double argument to a <code>long</code> using the | |
| 247 | + * <code>doubleToLongBits</code> method in class <code>Double</code>, | |
| 248 | + * and then writes that <code>long</code> value to the underlying | |
| 249 | + * output stream as an 8-byte quantity, high byte first. If no | |
| 250 | + * exception is thrown, the counter <code>written</code> is | |
| 251 | + * incremented by <code>8</code>. | |
| 252 | + * | |
| 253 | + * @param v a <code>double</code> value to be written. | |
| 254 | + * @exception IOException if an I/O error occurs. | |
| 255 | + * @see java.io.FilterOutputStream#out | |
| 256 | + * @see java.lang.Double#doubleToLongBits(double) | |
| 257 | + */ | |
| 258 | + public final void writeDouble(double v) throws IOException { | |
| 259 | + writeLong(Double.doubleToLongBits(v)); | |
| 260 | + } | |
| 261 | + | |
| 262 | + /** | |
| 263 | + * Writes out the string to the underlying output stream as a | |
| 264 | + * sequence of bytes. Each character in the string is written out, in | |
| 265 | + * sequence, by discarding its high eight bits. If no exception is | |
| 266 | + * thrown, the counter <code>written</code> is incremented by the | |
| 267 | + * length of <code>s</code>. | |
| 268 | + * | |
| 269 | + * @param s a string of bytes to be written. | |
| 270 | + * @exception IOException if an I/O error occurs. | |
| 271 | + * @see java.io.FilterOutputStream#out | |
| 272 | + */ | |
| 273 | + public final void writeBytes(String s) throws IOException { | |
| 274 | + int len = s.length(); | |
| 275 | + for (int i = 0 ; i < len ; i++) { | |
| 276 | + out.write((byte)s.charAt(i)); | |
| 277 | + } | |
| 278 | + incCount(len); | |
| 279 | + } | |
| 280 | + | |
| 281 | + /** | |
| 282 | + * Writes a string to the underlying output stream as a sequence of | |
| 283 | + * characters. Each character is written to the data output stream as | |
| 284 | + * if by the <code>writeChar</code> method. If no exception is | |
| 285 | + * thrown, the counter <code>written</code> is incremented by twice | |
| 286 | + * the length of <code>s</code>. | |
| 287 | + * | |
| 288 | + * @param s a <code>String</code> value to be written. | |
| 289 | + * @exception IOException if an I/O error occurs. | |
| 290 | + * @see java.io.DataOutputStream#writeChar(int) | |
| 291 | + * @see java.io.FilterOutputStream#out | |
| 292 | + */ | |
| 293 | + public final void writeChars(String s) throws IOException { | |
| 294 | + int len = s.length(); | |
| 295 | + for (int i = 0 ; i < len ; i++) { | |
| 296 | + int v = s.charAt(i); | |
| 297 | + out.write((v >>> 8) & 0xFF); | |
| 298 | + out.write((v >>> 0) & 0xFF); | |
| 299 | + } | |
| 300 | + incCount(len * 2); | |
| 301 | + } | |
| 302 | + | |
| 303 | + /** | |
| 304 | + * Writes a string to the underlying output stream using | |
| 305 | + * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> | |
| 306 | + * encoding in a machine-independent manner. | |
| 307 | + * <p> | |
| 308 | + * First, two bytes are written to the output stream as if by the | |
| 309 | + * <code>writeShort</code> method giving the number of bytes to | |
| 310 | + * follow. This value is the number of bytes actually written out, | |
| 311 | + * not the length of the string. Following the length, each character | |
| 312 | + * of the string is output, in sequence, using the modified UTF-8 encoding | |
| 313 | + * for the character. If no exception is thrown, the counter | |
| 314 | + * <code>written</code> is incremented by the total number of | |
| 315 | + * bytes written to the output stream. This will be at least two | |
| 316 | + * plus the length of <code>str</code>, and at most two plus | |
| 317 | + * thrice the length of <code>str</code>. | |
| 318 | + * | |
| 319 | + * @param str a string to be written. | |
| 320 | + * @exception IOException if an I/O error occurs. | |
| 321 | + */ | |
| 322 | + public final void writeUTF(String str) throws IOException { | |
| 323 | + writeUTF(str, this); | |
| 324 | + } | |
| 325 | + | |
| 326 | + /** | |
| 327 | + * Writes a string to the specified DataOutput using | |
| 328 | + * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> | |
| 329 | + * encoding in a machine-independent manner. | |
| 330 | + * <p> | |
| 331 | + * First, two bytes are written to out as if by the <code>writeShort</code> | |
| 332 | + * method giving the number of bytes to follow. This value is the number of | |
| 333 | + * bytes actually written out, not the length of the string. Following the | |
| 334 | + * length, each character of the string is output, in sequence, using the | |
| 335 | + * modified UTF-8 encoding for the character. If no exception is thrown, the | |
| 336 | + * counter <code>written</code> is incremented by the total number of | |
| 337 | + * bytes written to the output stream. This will be at least two | |
| 338 | + * plus the length of <code>str</code>, and at most two plus | |
| 339 | + * thrice the length of <code>str</code>. | |
| 340 | + * | |
| 341 | + * @param str a string to be written. | |
| 342 | + * @param out destination to write to | |
| 343 | + * @return The number of bytes written out. | |
| 344 | + * @exception IOException if an I/O error occurs. | |
| 345 | + */ | |
| 346 | + static int writeUTF(String str, DataOutput out) throws IOException { | |
| 347 | + int strlen = str.length(); | |
| 348 | + int utflen = 0; | |
| 349 | + int c, count = 0; | |
| 350 | + | |
| 351 | + /* use charAt instead of copying String to char array */ | |
| 352 | + for (int i = 0; i < strlen; i++) { | |
| 353 | + c = str.charAt(i); | |
| 354 | + if ((c >= 0x0001) && (c <= 0x007F)) { | |
| 355 | + utflen++; | |
| 356 | + } else if (c > 0x07FF) { | |
| 357 | + utflen += 3; | |
| 358 | + } else { | |
| 359 | + utflen += 2; | |
| 360 | + } | |
| 361 | + } | |
| 362 | + | |
| 363 | + if (utflen > 65535) | |
| 364 | + throw new UTFDataFormatException( | |
| 365 | + "encoded string too long: " + utflen + " bytes"); | |
| 366 | + | |
| 367 | + byte[] bytearr = null; | |
| 368 | + if (out instanceof DataOutputStream) { | |
| 369 | + DataOutputStream dos = (DataOutputStream)out; | |
| 370 | + if(dos.bytearr == null || (dos.bytearr.length < (utflen+2))) | |
| 371 | + dos.bytearr = new byte[(utflen*2) + 2]; | |
| 372 | + bytearr = dos.bytearr; | |
| 373 | + } else { | |
| 374 | + bytearr = new byte[utflen+2]; | |
| 375 | + } | |
| 376 | + | |
| 377 | + bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF); | |
| 378 | + bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF); | |
| 379 | + | |
| 380 | + int i=0; | |
| 381 | + for (i=0; i<strlen; i++) { | |
| 382 | + c = str.charAt(i); | |
| 383 | + if (!((c >= 0x0001) && (c <= 0x007F))) break; | |
| 384 | + bytearr[count++] = (byte) c; | |
| 385 | + } | |
| 386 | + | |
| 387 | + for (;i < strlen; i++){ | |
| 388 | + c = str.charAt(i); | |
| 389 | + if ((c >= 0x0001) && (c <= 0x007F)) { | |
| 390 | + bytearr[count++] = (byte) c; | |
| 391 | + | |
| 392 | + } else if (c > 0x07FF) { | |
| 393 | + bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F)); | |
| 394 | + bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F)); | |
| 395 | + bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F)); | |
| 396 | + } else { | |
| 397 | + bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F)); | |
| 398 | + bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F)); | |
| 399 | + } | |
| 400 | + } | |
| 401 | + out.write(bytearr, 0, utflen+2); | |
| 402 | + return utflen + 2; | |
| 403 | + } | |
| 404 | + | |
| 405 | + /** | |
| 406 | + * Returns the current value of the counter <code>written</code>, | |
| 407 | + * the number of bytes written to this data output stream so far. | |
| 408 | + * If the counter overflows, it will be wrapped to Integer.MAX_VALUE. | |
| 409 | + * | |
| 410 | + * @return the value of the <code>written</code> field. | |
| 411 | + * @see java.io.DataOutputStream#written | |
| 412 | + */ | |
| 413 | + public final int size() { | |
| 414 | + return written; | |
| 415 | + } | |
| 416 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,83 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | +package java.io; | |
| 26 | + | |
| 27 | +import java.util.*; | |
| 28 | +import java.io.File; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * This class holds a set of filenames to be deleted on VM exit through a shutdown hook. | |
| 32 | + * A set is used both to prevent double-insertion of the same file as well as offer | |
| 33 | + * quick removal. | |
| 34 | + */ | |
| 35 | + | |
| 36 | +class DeleteOnExitHook { | |
| 37 | + private static LinkedHashSet<String> files = new LinkedHashSet<>(); | |
| 38 | + static { | |
| 39 | + // DeleteOnExitHook must be the last shutdown hook to be invoked. | |
| 40 | + // Application shutdown hooks may add the first file to the | |
| 41 | + // delete on exit list and cause the DeleteOnExitHook to be | |
| 42 | + // registered during shutdown in progress. So set the | |
| 43 | + // registerShutdownInProgress parameter to true. | |
| 44 | + sun.misc.SharedSecrets.getJavaLangAccess() | |
| 45 | + .registerShutdownHook(2 /* Shutdown hook invocation order */, | |
| 46 | + true /* register even if shutdown in progress */, | |
| 47 | + new Runnable() { | |
| 48 | + public void run() { | |
| 49 | + runHooks(); | |
| 50 | + } | |
| 51 | + } | |
| 52 | + ); | |
| 53 | + } | |
| 54 | + | |
| 55 | + private DeleteOnExitHook() {} | |
| 56 | + | |
| 57 | + static synchronized void add(String file) { | |
| 58 | + if(files == null) { | |
| 59 | + // DeleteOnExitHook is running. Too late to add a file | |
| 60 | + throw new IllegalStateException("Shutdown in progress"); | |
| 61 | + } | |
| 62 | + | |
| 63 | + files.add(file); | |
| 64 | + } | |
| 65 | + | |
| 66 | + static void runHooks() { | |
| 67 | + LinkedHashSet<String> theFiles; | |
| 68 | + | |
| 69 | + synchronized (DeleteOnExitHook.class) { | |
| 70 | + theFiles = files; | |
| 71 | + files = null; | |
| 72 | + } | |
| 73 | + | |
| 74 | + ArrayList<String> toBeDeleted = new ArrayList<>(theFiles); | |
| 75 | + | |
| 76 | + // reverse the list to maintain previous jdk deletion order. | |
| 77 | + // Last in first deleted. | |
| 78 | + Collections.reverse(toBeDeleted); | |
| 79 | + for (String filename : toBeDeleted) { | |
| 80 | + (new File(filename)).delete(); | |
| 81 | + } | |
| 82 | + } | |
| 83 | +} | |
Binary file not shown.
| @@ -0,0 +1,65 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Signals that an end of file or end of stream has been reached | |
| 30 | + * unexpectedly during input. | |
| 31 | + * <p> | |
| 32 | + * This exception is mainly used by data input streams to signal end of | |
| 33 | + * stream. Note that many other input operations return a special value on | |
| 34 | + * end of stream rather than throwing an exception. | |
| 35 | + * <p> | |
| 36 | + * | |
| 37 | + * @author Frank Yellin | |
| 38 | + * @see java.io.DataInputStream | |
| 39 | + * @see java.io.IOException | |
| 40 | + * @since JDK1.0 | |
| 41 | + */ | |
| 42 | +public | |
| 43 | +class EOFException extends IOException { | |
| 44 | + private static final long serialVersionUID = 6433858223774886977L; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * Constructs an <code>EOFException</code> with <code>null</code> | |
| 48 | + * as its error detail message. | |
| 49 | + */ | |
| 50 | + public EOFException() { | |
| 51 | + super(); | |
| 52 | + } | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * Constructs an <code>EOFException</code> with the specified detail | |
| 56 | + * message. The string <code>s</code> may later be retrieved by the | |
| 57 | + * <code>{@link java.lang.Throwable#getMessage}</code> method of class | |
| 58 | + * <code>java.lang.Throwable</code>. | |
| 59 | + * | |
| 60 | + * @param s the detail message. | |
| 61 | + */ | |
| 62 | + public EOFException(String s) { | |
| 63 | + super(s); | |
| 64 | + } | |
| 65 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,127 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +/* | |
| 27 | + */ | |
| 28 | + | |
| 29 | +package java.io; | |
| 30 | + | |
| 31 | +import java.util.Iterator; | |
| 32 | +import java.util.Map; | |
| 33 | +import java.util.LinkedHashMap; | |
| 34 | +import java.util.Set; | |
| 35 | + | |
| 36 | +class ExpiringCache { | |
| 37 | + private long millisUntilExpiration; | |
| 38 | + private Map map; | |
| 39 | + // Clear out old entries every few queries | |
| 40 | + private int queryCount; | |
| 41 | + private int queryOverflow = 300; | |
| 42 | + private int MAX_ENTRIES = 200; | |
| 43 | + | |
| 44 | + static class Entry { | |
| 45 | + private long timestamp; | |
| 46 | + private String val; | |
| 47 | + | |
| 48 | + Entry(long timestamp, String val) { | |
| 49 | + this.timestamp = timestamp; | |
| 50 | + this.val = val; | |
| 51 | + } | |
| 52 | + | |
| 53 | + long timestamp() { return timestamp; } | |
| 54 | + void setTimestamp(long timestamp) { this.timestamp = timestamp; } | |
| 55 | + | |
| 56 | + String val() { return val; } | |
| 57 | + void setVal(String val) { this.val = val; } | |
| 58 | + } | |
| 59 | + | |
| 60 | + ExpiringCache() { | |
| 61 | + this(30000); | |
| 62 | + } | |
| 63 | + | |
| 64 | + ExpiringCache(long millisUntilExpiration) { | |
| 65 | + this.millisUntilExpiration = millisUntilExpiration; | |
| 66 | + map = new LinkedHashMap() { | |
| 67 | + protected boolean removeEldestEntry(Map.Entry eldest) { | |
| 68 | + return size() > MAX_ENTRIES; | |
| 69 | + } | |
| 70 | + }; | |
| 71 | + } | |
| 72 | + | |
| 73 | + synchronized String get(String key) { | |
| 74 | + if (++queryCount >= queryOverflow) { | |
| 75 | + cleanup(); | |
| 76 | + } | |
| 77 | + Entry entry = entryFor(key); | |
| 78 | + if (entry != null) { | |
| 79 | + return entry.val(); | |
| 80 | + } | |
| 81 | + return null; | |
| 82 | + } | |
| 83 | + | |
| 84 | + synchronized void put(String key, String val) { | |
| 85 | + if (++queryCount >= queryOverflow) { | |
| 86 | + cleanup(); | |
| 87 | + } | |
| 88 | + Entry entry = entryFor(key); | |
| 89 | + if (entry != null) { | |
| 90 | + entry.setTimestamp(System.currentTimeMillis()); | |
| 91 | + entry.setVal(val); | |
| 92 | + } else { | |
| 93 | + map.put(key, new Entry(System.currentTimeMillis(), val)); | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | + synchronized void clear() { | |
| 98 | + map.clear(); | |
| 99 | + } | |
| 100 | + | |
| 101 | + private Entry entryFor(String key) { | |
| 102 | + Entry entry = (Entry) map.get(key); | |
| 103 | + if (entry != null) { | |
| 104 | + long delta = System.currentTimeMillis() - entry.timestamp(); | |
| 105 | + if (delta < 0 || delta >= millisUntilExpiration) { | |
| 106 | + map.remove(key); | |
| 107 | + entry = null; | |
| 108 | + } | |
| 109 | + } | |
| 110 | + return entry; | |
| 111 | + } | |
| 112 | + | |
| 113 | + private void cleanup() { | |
| 114 | + Set keySet = map.keySet(); | |
| 115 | + // Avoid ConcurrentModificationExceptions | |
| 116 | + String[] keys = new String[keySet.size()]; | |
| 117 | + int i = 0; | |
| 118 | + for (Iterator iter = keySet.iterator(); iter.hasNext(); ) { | |
| 119 | + String key = (String) iter.next(); | |
| 120 | + keys[i++] = key; | |
| 121 | + } | |
| 122 | + for (int j = 0; j < keys.length; j++) { | |
| 123 | + entryFor(keys[j]); | |
| 124 | + } | |
| 125 | + queryCount = 0; | |
| 126 | + } | |
| 127 | +} | |
Binary file not shown.
| @@ -0,0 +1,97 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.io.ObjectOutput; | |
| 29 | +import java.io.ObjectInput; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * Only the identity of the class of an Externalizable instance is | |
| 33 | + * written in the serialization stream and it is the responsibility | |
| 34 | + * of the class to save and restore the contents of its instances. | |
| 35 | + * | |
| 36 | + * The writeExternal and readExternal methods of the Externalizable | |
| 37 | + * interface are implemented by a class to give the class complete | |
| 38 | + * control over the format and contents of the stream for an object | |
| 39 | + * and its supertypes. These methods must explicitly | |
| 40 | + * coordinate with the supertype to save its state. These methods supersede | |
| 41 | + * customized implementations of writeObject and readObject methods.<br> | |
| 42 | + * | |
| 43 | + * Object Serialization uses the Serializable and Externalizable | |
| 44 | + * interfaces. Object persistence mechanisms can use them as well. Each | |
| 45 | + * object to be stored is tested for the Externalizable interface. If | |
| 46 | + * the object supports Externalizable, the writeExternal method is called. If the | |
| 47 | + * object does not support Externalizable and does implement | |
| 48 | + * Serializable, the object is saved using | |
| 49 | + * ObjectOutputStream. <br> When an Externalizable object is | |
| 50 | + * reconstructed, an instance is created using the public no-arg | |
| 51 | + * constructor, then the readExternal method called. Serializable | |
| 52 | + * objects are restored by reading them from an ObjectInputStream.<br> | |
| 53 | + * | |
| 54 | + * An Externalizable instance can designate a substitution object via | |
| 55 | + * the writeReplace and readResolve methods documented in the Serializable | |
| 56 | + * interface.<br> | |
| 57 | + * | |
| 58 | + * @author unascribed | |
| 59 | + * @see java.io.ObjectOutputStream | |
| 60 | + * @see java.io.ObjectInputStream | |
| 61 | + * @see java.io.ObjectOutput | |
| 62 | + * @see java.io.ObjectInput | |
| 63 | + * @see java.io.Serializable | |
| 64 | + * @since JDK1.1 | |
| 65 | + */ | |
| 66 | +public interface Externalizable extends java.io.Serializable { | |
| 67 | + /** | |
| 68 | + * The object implements the writeExternal method to save its contents | |
| 69 | + * by calling the methods of DataOutput for its primitive values or | |
| 70 | + * calling the writeObject method of ObjectOutput for objects, strings, | |
| 71 | + * and arrays. | |
| 72 | + * | |
| 73 | + * @serialData Overriding methods should use this tag to describe | |
| 74 | + * the data layout of this Externalizable object. | |
| 75 | + * List the sequence of element types and, if possible, | |
| 76 | + * relate the element to a public/protected field and/or | |
| 77 | + * method of this Externalizable class. | |
| 78 | + * | |
| 79 | + * @param out the stream to write the object to | |
| 80 | + * @exception IOException Includes any I/O exceptions that may occur | |
| 81 | + */ | |
| 82 | + void writeExternal(ObjectOutput out) throws IOException; | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * The object implements the readExternal method to restore its | |
| 86 | + * contents by calling the methods of DataInput for primitive | |
| 87 | + * types and readObject for objects, strings and arrays. The | |
| 88 | + * readExternal method must read the values in the same sequence | |
| 89 | + * and with the same types as were written by writeExternal. | |
| 90 | + * | |
| 91 | + * @param in the stream to read data from in order to restore the object | |
| 92 | + * @exception IOException if I/O errors occur | |
| 93 | + * @exception ClassNotFoundException If the class for an object being | |
| 94 | + * restored cannot be found. | |
| 95 | + */ | |
| 96 | + void readExternal(ObjectInput in) throws IOException, ClassNotFoundException; | |
| 97 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,2076 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.net.URI; | |
| 29 | +import java.net.URL; | |
| 30 | +import java.net.MalformedURLException; | |
| 31 | +import java.net.URISyntaxException; | |
| 32 | +import java.util.List; | |
| 33 | +import java.util.ArrayList; | |
| 34 | +import java.security.AccessController; | |
| 35 | +import java.security.SecureRandom; | |
| 36 | +import java.nio.file.Path; | |
| 37 | +import java.nio.file.FileSystems; | |
| 38 | +import sun.security.action.GetPropertyAction; | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * An abstract representation of file and directory pathnames. | |
| 42 | + * | |
| 43 | + * <p> User interfaces and operating systems use system-dependent <em>pathname | |
| 44 | + * strings</em> to name files and directories. This class presents an | |
| 45 | + * abstract, system-independent view of hierarchical pathnames. An | |
| 46 | + * <em>abstract pathname</em> has two components: | |
| 47 | + * | |
| 48 | + * <ol> | |
| 49 | + * <li> An optional system-dependent <em>prefix</em> string, | |
| 50 | + * such as a disk-drive specifier, <code>"/"</code> for the UNIX root | |
| 51 | + * directory, or <code>"\\\\"</code> for a Microsoft Windows UNC pathname, and | |
| 52 | + * <li> A sequence of zero or more string <em>names</em>. | |
| 53 | + * </ol> | |
| 54 | + * | |
| 55 | + * The first name in an abstract pathname may be a directory name or, in the | |
| 56 | + * case of Microsoft Windows UNC pathnames, a hostname. Each subsequent name | |
| 57 | + * in an abstract pathname denotes a directory; the last name may denote | |
| 58 | + * either a directory or a file. The <em>empty</em> abstract pathname has no | |
| 59 | + * prefix and an empty name sequence. | |
| 60 | + * | |
| 61 | + * <p> The conversion of a pathname string to or from an abstract pathname is | |
| 62 | + * inherently system-dependent. When an abstract pathname is converted into a | |
| 63 | + * pathname string, each name is separated from the next by a single copy of | |
| 64 | + * the default <em>separator character</em>. The default name-separator | |
| 65 | + * character is defined by the system property <code>file.separator</code>, and | |
| 66 | + * is made available in the public static fields <code>{@link | |
| 67 | + * #separator}</code> and <code>{@link #separatorChar}</code> of this class. | |
| 68 | + * When a pathname string is converted into an abstract pathname, the names | |
| 69 | + * within it may be separated by the default name-separator character or by any | |
| 70 | + * other name-separator character that is supported by the underlying system. | |
| 71 | + * | |
| 72 | + * <p> A pathname, whether abstract or in string form, may be either | |
| 73 | + * <em>absolute</em> or <em>relative</em>. An absolute pathname is complete in | |
| 74 | + * that no other information is required in order to locate the file that it | |
| 75 | + * denotes. A relative pathname, in contrast, must be interpreted in terms of | |
| 76 | + * information taken from some other pathname. By default the classes in the | |
| 77 | + * <code>java.io</code> package always resolve relative pathnames against the | |
| 78 | + * current user directory. This directory is named by the system property | |
| 79 | + * <code>user.dir</code>, and is typically the directory in which the Java | |
| 80 | + * virtual machine was invoked. | |
| 81 | + * | |
| 82 | + * <p> The <em>parent</em> of an abstract pathname may be obtained by invoking | |
| 83 | + * the {@link #getParent} method of this class and consists of the pathname's | |
| 84 | + * prefix and each name in the pathname's name sequence except for the last. | |
| 85 | + * Each directory's absolute pathname is an ancestor of any <tt>File</tt> | |
| 86 | + * object with an absolute abstract pathname which begins with the directory's | |
| 87 | + * absolute pathname. For example, the directory denoted by the abstract | |
| 88 | + * pathname <tt>"/usr"</tt> is an ancestor of the directory denoted by the | |
| 89 | + * pathname <tt>"/usr/local/bin"</tt>. | |
| 90 | + * | |
| 91 | + * <p> The prefix concept is used to handle root directories on UNIX platforms, | |
| 92 | + * and drive specifiers, root directories and UNC pathnames on Microsoft Windows platforms, | |
| 93 | + * as follows: | |
| 94 | + * | |
| 95 | + * <ul> | |
| 96 | + * | |
| 97 | + * <li> For UNIX platforms, the prefix of an absolute pathname is always | |
| 98 | + * <code>"/"</code>. Relative pathnames have no prefix. The abstract pathname | |
| 99 | + * denoting the root directory has the prefix <code>"/"</code> and an empty | |
| 100 | + * name sequence. | |
| 101 | + * | |
| 102 | + * <li> For Microsoft Windows platforms, the prefix of a pathname that contains a drive | |
| 103 | + * specifier consists of the drive letter followed by <code>":"</code> and | |
| 104 | + * possibly followed by <code>"\\"</code> if the pathname is absolute. The | |
| 105 | + * prefix of a UNC pathname is <code>"\\\\"</code>; the hostname and the share | |
| 106 | + * name are the first two names in the name sequence. A relative pathname that | |
| 107 | + * does not specify a drive has no prefix. | |
| 108 | + * | |
| 109 | + * </ul> | |
| 110 | + * | |
| 111 | + * <p> Instances of this class may or may not denote an actual file-system | |
| 112 | + * object such as a file or a directory. If it does denote such an object | |
| 113 | + * then that object resides in a <i>partition</i>. A partition is an | |
| 114 | + * operating system-specific portion of storage for a file system. A single | |
| 115 | + * storage device (e.g. a physical disk-drive, flash memory, CD-ROM) may | |
| 116 | + * contain multiple partitions. The object, if any, will reside on the | |
| 117 | + * partition <a name="partName">named</a> by some ancestor of the absolute | |
| 118 | + * form of this pathname. | |
| 119 | + * | |
| 120 | + * <p> A file system may implement restrictions to certain operations on the | |
| 121 | + * actual file-system object, such as reading, writing, and executing. These | |
| 122 | + * restrictions are collectively known as <i>access permissions</i>. The file | |
| 123 | + * system may have multiple sets of access permissions on a single object. | |
| 124 | + * For example, one set may apply to the object's <i>owner</i>, and another | |
| 125 | + * may apply to all other users. The access permissions on an object may | |
| 126 | + * cause some methods in this class to fail. | |
| 127 | + * | |
| 128 | + * <p> Instances of the <code>File</code> class are immutable; that is, once | |
| 129 | + * created, the abstract pathname represented by a <code>File</code> object | |
| 130 | + * will never change. | |
| 131 | + * | |
| 132 | + * <h4>Interoperability with {@code java.nio.file} package</h4> | |
| 133 | + * | |
| 134 | + * <p> The <a href="../../java/nio/file/package-summary.html">{@code java.nio.file}</a> | |
| 135 | + * package defines interfaces and classes for the Java virtual machine to access | |
| 136 | + * files, file attributes, and file systems. This API may be used to overcome | |
| 137 | + * many of the limitations of the {@code java.io.File} class. | |
| 138 | + * The {@link #toPath toPath} method may be used to obtain a {@link | |
| 139 | + * Path} that uses the abstract path represented by a {@code File} object to | |
| 140 | + * locate a file. The resulting {@code Path} may be used with the {@link | |
| 141 | + * java.nio.file.Files} class to provide more efficient and extensive access to | |
| 142 | + * additional file operations, file attributes, and I/O exceptions to help | |
| 143 | + * diagnose errors when an operation on a file fails. | |
| 144 | + * | |
| 145 | + * @author unascribed | |
| 146 | + * @since JDK1.0 | |
| 147 | + */ | |
| 148 | + | |
| 149 | +public class File | |
| 150 | + implements Serializable, Comparable<File> | |
| 151 | +{ | |
| 152 | + | |
| 153 | + /** | |
| 154 | + * The FileSystem object representing the platform's local file system. | |
| 155 | + */ | |
| 156 | + static private FileSystem fs = FileSystem.getFileSystem(); | |
| 157 | + | |
| 158 | + /** | |
| 159 | + * This abstract pathname's normalized pathname string. A normalized | |
| 160 | + * pathname string uses the default name-separator character and does not | |
| 161 | + * contain any duplicate or redundant separators. | |
| 162 | + * | |
| 163 | + * @serial | |
| 164 | + */ | |
| 165 | + private String path; | |
| 166 | + | |
| 167 | + /** | |
| 168 | + * The length of this abstract pathname's prefix, or zero if it has no | |
| 169 | + * prefix. | |
| 170 | + */ | |
| 171 | + private transient int prefixLength; | |
| 172 | + | |
| 173 | + /** | |
| 174 | + * Returns the length of this abstract pathname's prefix. | |
| 175 | + * For use by FileSystem classes. | |
| 176 | + */ | |
| 177 | + int getPrefixLength() { | |
| 178 | + return prefixLength; | |
| 179 | + } | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * The system-dependent default name-separator character. This field is | |
| 183 | + * initialized to contain the first character of the value of the system | |
| 184 | + * property <code>file.separator</code>. On UNIX systems the value of this | |
| 185 | + * field is <code>'/'</code>; on Microsoft Windows systems it is <code>'\\'</code>. | |
| 186 | + * | |
| 187 | + * @see java.lang.System#getProperty(java.lang.String) | |
| 188 | + */ | |
| 189 | + public static final char separatorChar = fs.getSeparator(); | |
| 190 | + | |
| 191 | + /** | |
| 192 | + * The system-dependent default name-separator character, represented as a | |
| 193 | + * string for convenience. This string contains a single character, namely | |
| 194 | + * <code>{@link #separatorChar}</code>. | |
| 195 | + */ | |
| 196 | + public static final String separator = "" + separatorChar; | |
| 197 | + | |
| 198 | + /** | |
| 199 | + * The system-dependent path-separator character. This field is | |
| 200 | + * initialized to contain the first character of the value of the system | |
| 201 | + * property <code>path.separator</code>. This character is used to | |
| 202 | + * separate filenames in a sequence of files given as a <em>path list</em>. | |
| 203 | + * On UNIX systems, this character is <code>':'</code>; on Microsoft Windows systems it | |
| 204 | + * is <code>';'</code>. | |
| 205 | + * | |
| 206 | + * @see java.lang.System#getProperty(java.lang.String) | |
| 207 | + */ | |
| 208 | + public static final char pathSeparatorChar = fs.getPathSeparator(); | |
| 209 | + | |
| 210 | + /** | |
| 211 | + * The system-dependent path-separator character, represented as a string | |
| 212 | + * for convenience. This string contains a single character, namely | |
| 213 | + * <code>{@link #pathSeparatorChar}</code>. | |
| 214 | + */ | |
| 215 | + public static final String pathSeparator = "" + pathSeparatorChar; | |
| 216 | + | |
| 217 | + | |
| 218 | + /* -- Constructors -- */ | |
| 219 | + | |
| 220 | + /** | |
| 221 | + * Internal constructor for already-normalized pathname strings. | |
| 222 | + */ | |
| 223 | + private File(String pathname, int prefixLength) { | |
| 224 | + this.path = pathname; | |
| 225 | + this.prefixLength = prefixLength; | |
| 226 | + } | |
| 227 | + | |
| 228 | + /** | |
| 229 | + * Internal constructor for already-normalized pathname strings. | |
| 230 | + * The parameter order is used to disambiguate this method from the | |
| 231 | + * public(File, String) constructor. | |
| 232 | + */ | |
| 233 | + private File(String child, File parent) { | |
| 234 | + assert parent.path != null; | |
| 235 | + assert (!parent.path.equals("")); | |
| 236 | + this.path = fs.resolve(parent.path, child); | |
| 237 | + this.prefixLength = parent.prefixLength; | |
| 238 | + } | |
| 239 | + | |
| 240 | + /** | |
| 241 | + * Creates a new <code>File</code> instance by converting the given | |
| 242 | + * pathname string into an abstract pathname. If the given string is | |
| 243 | + * the empty string, then the result is the empty abstract pathname. | |
| 244 | + * | |
| 245 | + * @param pathname A pathname string | |
| 246 | + * @throws NullPointerException | |
| 247 | + * If the <code>pathname</code> argument is <code>null</code> | |
| 248 | + */ | |
| 249 | + public File(String pathname) { | |
| 250 | + if (pathname == null) { | |
| 251 | + throw new NullPointerException(); | |
| 252 | + } | |
| 253 | + this.path = fs.normalize(pathname); | |
| 254 | + this.prefixLength = fs.prefixLength(this.path); | |
| 255 | + } | |
| 256 | + | |
| 257 | + /* Note: The two-argument File constructors do not interpret an empty | |
| 258 | + parent abstract pathname as the current user directory. An empty parent | |
| 259 | + instead causes the child to be resolved against the system-dependent | |
| 260 | + directory defined by the FileSystem.getDefaultParent method. On Unix | |
| 261 | + this default is "/", while on Microsoft Windows it is "\\". This is required for | |
| 262 | + compatibility with the original behavior of this class. */ | |
| 263 | + | |
| 264 | + /** | |
| 265 | + * Creates a new <code>File</code> instance from a parent pathname string | |
| 266 | + * and a child pathname string. | |
| 267 | + * | |
| 268 | + * <p> If <code>parent</code> is <code>null</code> then the new | |
| 269 | + * <code>File</code> instance is created as if by invoking the | |
| 270 | + * single-argument <code>File</code> constructor on the given | |
| 271 | + * <code>child</code> pathname string. | |
| 272 | + * | |
| 273 | + * <p> Otherwise the <code>parent</code> pathname string is taken to denote | |
| 274 | + * a directory, and the <code>child</code> pathname string is taken to | |
| 275 | + * denote either a directory or a file. If the <code>child</code> pathname | |
| 276 | + * string is absolute then it is converted into a relative pathname in a | |
| 277 | + * system-dependent way. If <code>parent</code> is the empty string then | |
| 278 | + * the new <code>File</code> instance is created by converting | |
| 279 | + * <code>child</code> into an abstract pathname and resolving the result | |
| 280 | + * against a system-dependent default directory. Otherwise each pathname | |
| 281 | + * string is converted into an abstract pathname and the child abstract | |
| 282 | + * pathname is resolved against the parent. | |
| 283 | + * | |
| 284 | + * @param parent The parent pathname string | |
| 285 | + * @param child The child pathname string | |
| 286 | + * @throws NullPointerException | |
| 287 | + * If <code>child</code> is <code>null</code> | |
| 288 | + */ | |
| 289 | + public File(String parent, String child) { | |
| 290 | + if (child == null) { | |
| 291 | + throw new NullPointerException(); | |
| 292 | + } | |
| 293 | + if (parent != null) { | |
| 294 | + if (parent.equals("")) { | |
| 295 | + this.path = fs.resolve(fs.getDefaultParent(), | |
| 296 | + fs.normalize(child)); | |
| 297 | + } else { | |
| 298 | + this.path = fs.resolve(fs.normalize(parent), | |
| 299 | + fs.normalize(child)); | |
| 300 | + } | |
| 301 | + } else { | |
| 302 | + this.path = fs.normalize(child); | |
| 303 | + } | |
| 304 | + this.prefixLength = fs.prefixLength(this.path); | |
| 305 | + } | |
| 306 | + | |
| 307 | + /** | |
| 308 | + * Creates a new <code>File</code> instance from a parent abstract | |
| 309 | + * pathname and a child pathname string. | |
| 310 | + * | |
| 311 | + * <p> If <code>parent</code> is <code>null</code> then the new | |
| 312 | + * <code>File</code> instance is created as if by invoking the | |
| 313 | + * single-argument <code>File</code> constructor on the given | |
| 314 | + * <code>child</code> pathname string. | |
| 315 | + * | |
| 316 | + * <p> Otherwise the <code>parent</code> abstract pathname is taken to | |
| 317 | + * denote a directory, and the <code>child</code> pathname string is taken | |
| 318 | + * to denote either a directory or a file. If the <code>child</code> | |
| 319 | + * pathname string is absolute then it is converted into a relative | |
| 320 | + * pathname in a system-dependent way. If <code>parent</code> is the empty | |
| 321 | + * abstract pathname then the new <code>File</code> instance is created by | |
| 322 | + * converting <code>child</code> into an abstract pathname and resolving | |
| 323 | + * the result against a system-dependent default directory. Otherwise each | |
| 324 | + * pathname string is converted into an abstract pathname and the child | |
| 325 | + * abstract pathname is resolved against the parent. | |
| 326 | + * | |
| 327 | + * @param parent The parent abstract pathname | |
| 328 | + * @param child The child pathname string | |
| 329 | + * @throws NullPointerException | |
| 330 | + * If <code>child</code> is <code>null</code> | |
| 331 | + */ | |
| 332 | + public File(File parent, String child) { | |
| 333 | + if (child == null) { | |
| 334 | + throw new NullPointerException(); | |
| 335 | + } | |
| 336 | + if (parent != null) { | |
| 337 | + if (parent.path.equals("")) { | |
| 338 | + this.path = fs.resolve(fs.getDefaultParent(), | |
| 339 | + fs.normalize(child)); | |
| 340 | + } else { | |
| 341 | + this.path = fs.resolve(parent.path, | |
| 342 | + fs.normalize(child)); | |
| 343 | + } | |
| 344 | + } else { | |
| 345 | + this.path = fs.normalize(child); | |
| 346 | + } | |
| 347 | + this.prefixLength = fs.prefixLength(this.path); | |
| 348 | + } | |
| 349 | + | |
| 350 | + /** | |
| 351 | + * Creates a new <tt>File</tt> instance by converting the given | |
| 352 | + * <tt>file:</tt> URI into an abstract pathname. | |
| 353 | + * | |
| 354 | + * <p> The exact form of a <tt>file:</tt> URI is system-dependent, hence | |
| 355 | + * the transformation performed by this constructor is also | |
| 356 | + * system-dependent. | |
| 357 | + * | |
| 358 | + * <p> For a given abstract pathname <i>f</i> it is guaranteed that | |
| 359 | + * | |
| 360 | + * <blockquote><tt> | |
| 361 | + * new File(</tt><i> f</i><tt>.{@link #toURI() toURI}()).equals(</tt><i> f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}()) | |
| 362 | + * </tt></blockquote> | |
| 363 | + * | |
| 364 | + * so long as the original abstract pathname, the URI, and the new abstract | |
| 365 | + * pathname are all created in (possibly different invocations of) the same | |
| 366 | + * Java virtual machine. This relationship typically does not hold, | |
| 367 | + * however, when a <tt>file:</tt> URI that is created in a virtual machine | |
| 368 | + * on one operating system is converted into an abstract pathname in a | |
| 369 | + * virtual machine on a different operating system. | |
| 370 | + * | |
| 371 | + * @param uri | |
| 372 | + * An absolute, hierarchical URI with a scheme equal to | |
| 373 | + * <tt>"file"</tt>, a non-empty path component, and undefined | |
| 374 | + * authority, query, and fragment components | |
| 375 | + * | |
| 376 | + * @throws NullPointerException | |
| 377 | + * If <tt>uri</tt> is <tt>null</tt> | |
| 378 | + * | |
| 379 | + * @throws IllegalArgumentException | |
| 380 | + * If the preconditions on the parameter do not hold | |
| 381 | + * | |
| 382 | + * @see #toURI() | |
| 383 | + * @see java.net.URI | |
| 384 | + * @since 1.4 | |
| 385 | + */ | |
| 386 | + public File(URI uri) { | |
| 387 | + | |
| 388 | + // Check our many preconditions | |
| 389 | + if (!uri.isAbsolute()) | |
| 390 | + throw new IllegalArgumentException("URI is not absolute"); | |
| 391 | + if (uri.isOpaque()) | |
| 392 | + throw new IllegalArgumentException("URI is not hierarchical"); | |
| 393 | + String scheme = uri.getScheme(); | |
| 394 | + if ((scheme == null) || !scheme.equalsIgnoreCase("file")) | |
| 395 | + throw new IllegalArgumentException("URI scheme is not \"file\""); | |
| 396 | + if (uri.getAuthority() != null) | |
| 397 | + throw new IllegalArgumentException("URI has an authority component"); | |
| 398 | + if (uri.getFragment() != null) | |
| 399 | + throw new IllegalArgumentException("URI has a fragment component"); | |
| 400 | + if (uri.getQuery() != null) | |
| 401 | + throw new IllegalArgumentException("URI has a query component"); | |
| 402 | + String p = uri.getPath(); | |
| 403 | + if (p.equals("")) | |
| 404 | + throw new IllegalArgumentException("URI path component is empty"); | |
| 405 | + | |
| 406 | + // Okay, now initialize | |
| 407 | + p = fs.fromURIPath(p); | |
| 408 | + if (File.separatorChar != '/') | |
| 409 | + p = p.replace('/', File.separatorChar); | |
| 410 | + this.path = fs.normalize(p); | |
| 411 | + this.prefixLength = fs.prefixLength(this.path); | |
| 412 | + } | |
| 413 | + | |
| 414 | + | |
| 415 | + /* -- Path-component accessors -- */ | |
| 416 | + | |
| 417 | + /** | |
| 418 | + * Returns the name of the file or directory denoted by this abstract | |
| 419 | + * pathname. This is just the last name in the pathname's name | |
| 420 | + * sequence. If the pathname's name sequence is empty, then the empty | |
| 421 | + * string is returned. | |
| 422 | + * | |
| 423 | + * @return The name of the file or directory denoted by this abstract | |
| 424 | + * pathname, or the empty string if this pathname's name sequence | |
| 425 | + * is empty | |
| 426 | + */ | |
| 427 | + public String getName() { | |
| 428 | + int index = path.lastIndexOf(separatorChar); | |
| 429 | + if (index < prefixLength) return path.substring(prefixLength); | |
| 430 | + return path.substring(index + 1); | |
| 431 | + } | |
| 432 | + | |
| 433 | + /** | |
| 434 | + * Returns the pathname string of this abstract pathname's parent, or | |
| 435 | + * <code>null</code> if this pathname does not name a parent directory. | |
| 436 | + * | |
| 437 | + * <p> The <em>parent</em> of an abstract pathname consists of the | |
| 438 | + * pathname's prefix, if any, and each name in the pathname's name | |
| 439 | + * sequence except for the last. If the name sequence is empty then | |
| 440 | + * the pathname does not name a parent directory. | |
| 441 | + * | |
| 442 | + * @return The pathname string of the parent directory named by this | |
| 443 | + * abstract pathname, or <code>null</code> if this pathname | |
| 444 | + * does not name a parent | |
| 445 | + */ | |
| 446 | + public String getParent() { | |
| 447 | + int index = path.lastIndexOf(separatorChar); | |
| 448 | + if (index < prefixLength) { | |
| 449 | + if ((prefixLength > 0) && (path.length() > prefixLength)) | |
| 450 | + return path.substring(0, prefixLength); | |
| 451 | + return null; | |
| 452 | + } | |
| 453 | + return path.substring(0, index); | |
| 454 | + } | |
| 455 | + | |
| 456 | + /** | |
| 457 | + * Returns the abstract pathname of this abstract pathname's parent, | |
| 458 | + * or <code>null</code> if this pathname does not name a parent | |
| 459 | + * directory. | |
| 460 | + * | |
| 461 | + * <p> The <em>parent</em> of an abstract pathname consists of the | |
| 462 | + * pathname's prefix, if any, and each name in the pathname's name | |
| 463 | + * sequence except for the last. If the name sequence is empty then | |
| 464 | + * the pathname does not name a parent directory. | |
| 465 | + * | |
| 466 | + * @return The abstract pathname of the parent directory named by this | |
| 467 | + * abstract pathname, or <code>null</code> if this pathname | |
| 468 | + * does not name a parent | |
| 469 | + * | |
| 470 | + * @since 1.2 | |
| 471 | + */ | |
| 472 | + public File getParentFile() { | |
| 473 | + String p = this.getParent(); | |
| 474 | + if (p == null) return null; | |
| 475 | + return new File(p, this.prefixLength); | |
| 476 | + } | |
| 477 | + | |
| 478 | + /** | |
| 479 | + * Converts this abstract pathname into a pathname string. The resulting | |
| 480 | + * string uses the {@link #separator default name-separator character} to | |
| 481 | + * separate the names in the name sequence. | |
| 482 | + * | |
| 483 | + * @return The string form of this abstract pathname | |
| 484 | + */ | |
| 485 | + public String getPath() { | |
| 486 | + return path; | |
| 487 | + } | |
| 488 | + | |
| 489 | + | |
| 490 | + /* -- Path operations -- */ | |
| 491 | + | |
| 492 | + /** | |
| 493 | + * Tests whether this abstract pathname is absolute. The definition of | |
| 494 | + * absolute pathname is system dependent. On UNIX systems, a pathname is | |
| 495 | + * absolute if its prefix is <code>"/"</code>. On Microsoft Windows systems, a | |
| 496 | + * pathname is absolute if its prefix is a drive specifier followed by | |
| 497 | + * <code>"\\"</code>, or if its prefix is <code>"\\\\"</code>. | |
| 498 | + * | |
| 499 | + * @return <code>true</code> if this abstract pathname is absolute, | |
| 500 | + * <code>false</code> otherwise | |
| 501 | + */ | |
| 502 | + public boolean isAbsolute() { | |
| 503 | + return fs.isAbsolute(this); | |
| 504 | + } | |
| 505 | + | |
| 506 | + /** | |
| 507 | + * Returns the absolute pathname string of this abstract pathname. | |
| 508 | + * | |
| 509 | + * <p> If this abstract pathname is already absolute, then the pathname | |
| 510 | + * string is simply returned as if by the <code>{@link #getPath}</code> | |
| 511 | + * method. If this abstract pathname is the empty abstract pathname then | |
| 512 | + * the pathname string of the current user directory, which is named by the | |
| 513 | + * system property <code>user.dir</code>, is returned. Otherwise this | |
| 514 | + * pathname is resolved in a system-dependent way. On UNIX systems, a | |
| 515 | + * relative pathname is made absolute by resolving it against the current | |
| 516 | + * user directory. On Microsoft Windows systems, a relative pathname is made absolute | |
| 517 | + * by resolving it against the current directory of the drive named by the | |
| 518 | + * pathname, if any; if not, it is resolved against the current user | |
| 519 | + * directory. | |
| 520 | + * | |
| 521 | + * @return The absolute pathname string denoting the same file or | |
| 522 | + * directory as this abstract pathname | |
| 523 | + * | |
| 524 | + * @throws SecurityException | |
| 525 | + * If a required system property value cannot be accessed. | |
| 526 | + * | |
| 527 | + * @see java.io.File#isAbsolute() | |
| 528 | + */ | |
| 529 | + public String getAbsolutePath() { | |
| 530 | + return fs.resolve(this); | |
| 531 | + } | |
| 532 | + | |
| 533 | + /** | |
| 534 | + * Returns the absolute form of this abstract pathname. Equivalent to | |
| 535 | + * <code>new File(this.{@link #getAbsolutePath})</code>. | |
| 536 | + * | |
| 537 | + * @return The absolute abstract pathname denoting the same file or | |
| 538 | + * directory as this abstract pathname | |
| 539 | + * | |
| 540 | + * @throws SecurityException | |
| 541 | + * If a required system property value cannot be accessed. | |
| 542 | + * | |
| 543 | + * @since 1.2 | |
| 544 | + */ | |
| 545 | + public File getAbsoluteFile() { | |
| 546 | + String absPath = getAbsolutePath(); | |
| 547 | + return new File(absPath, fs.prefixLength(absPath)); | |
| 548 | + } | |
| 549 | + | |
| 550 | + /** | |
| 551 | + * Returns the canonical pathname string of this abstract pathname. | |
| 552 | + * | |
| 553 | + * <p> A canonical pathname is both absolute and unique. The precise | |
| 554 | + * definition of canonical form is system-dependent. This method first | |
| 555 | + * converts this pathname to absolute form if necessary, as if by invoking the | |
| 556 | + * {@link #getAbsolutePath} method, and then maps it to its unique form in a | |
| 557 | + * system-dependent way. This typically involves removing redundant names | |
| 558 | + * such as <tt>"."</tt> and <tt>".."</tt> from the pathname, resolving | |
| 559 | + * symbolic links (on UNIX platforms), and converting drive letters to a | |
| 560 | + * standard case (on Microsoft Windows platforms). | |
| 561 | + * | |
| 562 | + * <p> Every pathname that denotes an existing file or directory has a | |
| 563 | + * unique canonical form. Every pathname that denotes a nonexistent file | |
| 564 | + * or directory also has a unique canonical form. The canonical form of | |
| 565 | + * the pathname of a nonexistent file or directory may be different from | |
| 566 | + * the canonical form of the same pathname after the file or directory is | |
| 567 | + * created. Similarly, the canonical form of the pathname of an existing | |
| 568 | + * file or directory may be different from the canonical form of the same | |
| 569 | + * pathname after the file or directory is deleted. | |
| 570 | + * | |
| 571 | + * @return The canonical pathname string denoting the same file or | |
| 572 | + * directory as this abstract pathname | |
| 573 | + * | |
| 574 | + * @throws IOException | |
| 575 | + * If an I/O error occurs, which is possible because the | |
| 576 | + * construction of the canonical pathname may require | |
| 577 | + * filesystem queries | |
| 578 | + * | |
| 579 | + * @throws SecurityException | |
| 580 | + * If a required system property value cannot be accessed, or | |
| 581 | + * if a security manager exists and its <code>{@link | |
| 582 | + * java.lang.SecurityManager#checkRead}</code> method denies | |
| 583 | + * read access to the file | |
| 584 | + * | |
| 585 | + * @since JDK1.1 | |
| 586 | + * @see Path#toRealPath | |
| 587 | + */ | |
| 588 | + public String getCanonicalPath() throws IOException { | |
| 589 | + return fs.canonicalize(fs.resolve(this)); | |
| 590 | + } | |
| 591 | + | |
| 592 | + /** | |
| 593 | + * Returns the canonical form of this abstract pathname. Equivalent to | |
| 594 | + * <code>new File(this.{@link #getCanonicalPath})</code>. | |
| 595 | + * | |
| 596 | + * @return The canonical pathname string denoting the same file or | |
| 597 | + * directory as this abstract pathname | |
| 598 | + * | |
| 599 | + * @throws IOException | |
| 600 | + * If an I/O error occurs, which is possible because the | |
| 601 | + * construction of the canonical pathname may require | |
| 602 | + * filesystem queries | |
| 603 | + * | |
| 604 | + * @throws SecurityException | |
| 605 | + * If a required system property value cannot be accessed, or | |
| 606 | + * if a security manager exists and its <code>{@link | |
| 607 | + * java.lang.SecurityManager#checkRead}</code> method denies | |
| 608 | + * read access to the file | |
| 609 | + * | |
| 610 | + * @since 1.2 | |
| 611 | + * @see Path#toRealPath | |
| 612 | + */ | |
| 613 | + public File getCanonicalFile() throws IOException { | |
| 614 | + String canonPath = getCanonicalPath(); | |
| 615 | + return new File(canonPath, fs.prefixLength(canonPath)); | |
| 616 | + } | |
| 617 | + | |
| 618 | + private static String slashify(String path, boolean isDirectory) { | |
| 619 | + String p = path; | |
| 620 | + if (File.separatorChar != '/') | |
| 621 | + p = p.replace(File.separatorChar, '/'); | |
| 622 | + if (!p.startsWith("/")) | |
| 623 | + p = "/" + p; | |
| 624 | + if (!p.endsWith("/") && isDirectory) | |
| 625 | + p = p + "/"; | |
| 626 | + return p; | |
| 627 | + } | |
| 628 | + | |
| 629 | + /** | |
| 630 | + * Converts this abstract pathname into a <code>file:</code> URL. The | |
| 631 | + * exact form of the URL is system-dependent. If it can be determined that | |
| 632 | + * the file denoted by this abstract pathname is a directory, then the | |
| 633 | + * resulting URL will end with a slash. | |
| 634 | + * | |
| 635 | + * @return A URL object representing the equivalent file URL | |
| 636 | + * | |
| 637 | + * @throws MalformedURLException | |
| 638 | + * If the path cannot be parsed as a URL | |
| 639 | + * | |
| 640 | + * @see #toURI() | |
| 641 | + * @see java.net.URI | |
| 642 | + * @see java.net.URI#toURL() | |
| 643 | + * @see java.net.URL | |
| 644 | + * @since 1.2 | |
| 645 | + * | |
| 646 | + * @deprecated This method does not automatically escape characters that | |
| 647 | + * are illegal in URLs. It is recommended that new code convert an | |
| 648 | + * abstract pathname into a URL by first converting it into a URI, via the | |
| 649 | + * {@link #toURI() toURI} method, and then converting the URI into a URL | |
| 650 | + * via the {@link java.net.URI#toURL() URI.toURL} method. | |
| 651 | + */ | |
| 652 | + @Deprecated | |
| 653 | + public URL toURL() throws MalformedURLException { | |
| 654 | + return new URL("file", "", slashify(getAbsolutePath(), isDirectory())); | |
| 655 | + } | |
| 656 | + | |
| 657 | + /** | |
| 658 | + * Constructs a <tt>file:</tt> URI that represents this abstract pathname. | |
| 659 | + * | |
| 660 | + * <p> The exact form of the URI is system-dependent. If it can be | |
| 661 | + * determined that the file denoted by this abstract pathname is a | |
| 662 | + * directory, then the resulting URI will end with a slash. | |
| 663 | + * | |
| 664 | + * <p> For a given abstract pathname <i>f</i>, it is guaranteed that | |
| 665 | + * | |
| 666 | + * <blockquote><tt> | |
| 667 | + * new {@link #File(java.net.URI) File}(</tt><i> f</i><tt>.toURI()).equals(</tt><i> f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}()) | |
| 668 | + * </tt></blockquote> | |
| 669 | + * | |
| 670 | + * so long as the original abstract pathname, the URI, and the new abstract | |
| 671 | + * pathname are all created in (possibly different invocations of) the same | |
| 672 | + * Java virtual machine. Due to the system-dependent nature of abstract | |
| 673 | + * pathnames, however, this relationship typically does not hold when a | |
| 674 | + * <tt>file:</tt> URI that is created in a virtual machine on one operating | |
| 675 | + * system is converted into an abstract pathname in a virtual machine on a | |
| 676 | + * different operating system. | |
| 677 | + * | |
| 678 | + * <p> Note that when this abstract pathname represents a UNC pathname then | |
| 679 | + * all components of the UNC (including the server name component) are encoded | |
| 680 | + * in the {@code URI} path. The authority component is undefined, meaning | |
| 681 | + * that it is represented as {@code null}. The {@link Path} class defines the | |
| 682 | + * {@link Path#toUri toUri} method to encode the server name in the authority | |
| 683 | + * component of the resulting {@code URI}. The {@link #toPath toPath} method | |
| 684 | + * may be used to obtain a {@code Path} representing this abstract pathname. | |
| 685 | + * | |
| 686 | + * @return An absolute, hierarchical URI with a scheme equal to | |
| 687 | + * <tt>"file"</tt>, a path representing this abstract pathname, | |
| 688 | + * and undefined authority, query, and fragment components | |
| 689 | + * @throws SecurityException If a required system property value cannot | |
| 690 | + * be accessed. | |
| 691 | + * | |
| 692 | + * @see #File(java.net.URI) | |
| 693 | + * @see java.net.URI | |
| 694 | + * @see java.net.URI#toURL() | |
| 695 | + * @since 1.4 | |
| 696 | + */ | |
| 697 | + public URI toURI() { | |
| 698 | + try { | |
| 699 | + File f = getAbsoluteFile(); | |
| 700 | + String sp = slashify(f.getPath(), f.isDirectory()); | |
| 701 | + if (sp.startsWith("//")) | |
| 702 | + sp = "//" + sp; | |
| 703 | + return new URI("file", null, sp, null); | |
| 704 | + } catch (URISyntaxException x) { | |
| 705 | + throw new Error(x); // Can't happen | |
| 706 | + } | |
| 707 | + } | |
| 708 | + | |
| 709 | + | |
| 710 | + /* -- Attribute accessors -- */ | |
| 711 | + | |
| 712 | + /** | |
| 713 | + * Tests whether the application can read the file denoted by this | |
| 714 | + * abstract pathname. | |
| 715 | + * | |
| 716 | + * @return <code>true</code> if and only if the file specified by this | |
| 717 | + * abstract pathname exists <em>and</em> can be read by the | |
| 718 | + * application; <code>false</code> otherwise | |
| 719 | + * | |
| 720 | + * @throws SecurityException | |
| 721 | + * If a security manager exists and its <code>{@link | |
| 722 | + * java.lang.SecurityManager#checkRead(java.lang.String)}</code> | |
| 723 | + * method denies read access to the file | |
| 724 | + */ | |
| 725 | + public boolean canRead() { | |
| 726 | + SecurityManager security = System.getSecurityManager(); | |
| 727 | + if (security != null) { | |
| 728 | + security.checkRead(path); | |
| 729 | + } | |
| 730 | + return fs.checkAccess(this, FileSystem.ACCESS_READ); | |
| 731 | + } | |
| 732 | + | |
| 733 | + /** | |
| 734 | + * Tests whether the application can modify the file denoted by this | |
| 735 | + * abstract pathname. | |
| 736 | + * | |
| 737 | + * @return <code>true</code> if and only if the file system actually | |
| 738 | + * contains a file denoted by this abstract pathname <em>and</em> | |
| 739 | + * the application is allowed to write to the file; | |
| 740 | + * <code>false</code> otherwise. | |
| 741 | + * | |
| 742 | + * @throws SecurityException | |
| 743 | + * If a security manager exists and its <code>{@link | |
| 744 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 745 | + * method denies write access to the file | |
| 746 | + */ | |
| 747 | + public boolean canWrite() { | |
| 748 | + SecurityManager security = System.getSecurityManager(); | |
| 749 | + if (security != null) { | |
| 750 | + security.checkWrite(path); | |
| 751 | + } | |
| 752 | + return fs.checkAccess(this, FileSystem.ACCESS_WRITE); | |
| 753 | + } | |
| 754 | + | |
| 755 | + /** | |
| 756 | + * Tests whether the file or directory denoted by this abstract pathname | |
| 757 | + * exists. | |
| 758 | + * | |
| 759 | + * @return <code>true</code> if and only if the file or directory denoted | |
| 760 | + * by this abstract pathname exists; <code>false</code> otherwise | |
| 761 | + * | |
| 762 | + * @throws SecurityException | |
| 763 | + * If a security manager exists and its <code>{@link | |
| 764 | + * java.lang.SecurityManager#checkRead(java.lang.String)}</code> | |
| 765 | + * method denies read access to the file or directory | |
| 766 | + */ | |
| 767 | + public boolean exists() { | |
| 768 | + SecurityManager security = System.getSecurityManager(); | |
| 769 | + if (security != null) { | |
| 770 | + security.checkRead(path); | |
| 771 | + } | |
| 772 | + return ((fs.getBooleanAttributes(this) & FileSystem.BA_EXISTS) != 0); | |
| 773 | + } | |
| 774 | + | |
| 775 | + /** | |
| 776 | + * Tests whether the file denoted by this abstract pathname is a | |
| 777 | + * directory. | |
| 778 | + * | |
| 779 | + * <p> Where it is required to distinguish an I/O exception from the case | |
| 780 | + * that the file is not a directory, or where several attributes of the | |
| 781 | + * same file are required at the same time, then the {@link | |
| 782 | + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) | |
| 783 | + * Files.readAttributes} method may be used. | |
| 784 | + * | |
| 785 | + * @return <code>true</code> if and only if the file denoted by this | |
| 786 | + * abstract pathname exists <em>and</em> is a directory; | |
| 787 | + * <code>false</code> otherwise | |
| 788 | + * | |
| 789 | + * @throws SecurityException | |
| 790 | + * If a security manager exists and its <code>{@link | |
| 791 | + * java.lang.SecurityManager#checkRead(java.lang.String)}</code> | |
| 792 | + * method denies read access to the file | |
| 793 | + */ | |
| 794 | + public boolean isDirectory() { | |
| 795 | + SecurityManager security = System.getSecurityManager(); | |
| 796 | + if (security != null) { | |
| 797 | + security.checkRead(path); | |
| 798 | + } | |
| 799 | + return ((fs.getBooleanAttributes(this) & FileSystem.BA_DIRECTORY) | |
| 800 | + != 0); | |
| 801 | + } | |
| 802 | + | |
| 803 | + /** | |
| 804 | + * Tests whether the file denoted by this abstract pathname is a normal | |
| 805 | + * file. A file is <em>normal</em> if it is not a directory and, in | |
| 806 | + * addition, satisfies other system-dependent criteria. Any non-directory | |
| 807 | + * file created by a Java application is guaranteed to be a normal file. | |
| 808 | + * | |
| 809 | + * <p> Where it is required to distinguish an I/O exception from the case | |
| 810 | + * that the file is not a normal file, or where several attributes of the | |
| 811 | + * same file are required at the same time, then the {@link | |
| 812 | + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) | |
| 813 | + * Files.readAttributes} method may be used. | |
| 814 | + * | |
| 815 | + * @return <code>true</code> if and only if the file denoted by this | |
| 816 | + * abstract pathname exists <em>and</em> is a normal file; | |
| 817 | + * <code>false</code> otherwise | |
| 818 | + * | |
| 819 | + * @throws SecurityException | |
| 820 | + * If a security manager exists and its <code>{@link | |
| 821 | + * java.lang.SecurityManager#checkRead(java.lang.String)}</code> | |
| 822 | + * method denies read access to the file | |
| 823 | + */ | |
| 824 | + public boolean isFile() { | |
| 825 | + SecurityManager security = System.getSecurityManager(); | |
| 826 | + if (security != null) { | |
| 827 | + security.checkRead(path); | |
| 828 | + } | |
| 829 | + return ((fs.getBooleanAttributes(this) & FileSystem.BA_REGULAR) != 0); | |
| 830 | + } | |
| 831 | + | |
| 832 | + /** | |
| 833 | + * Tests whether the file named by this abstract pathname is a hidden | |
| 834 | + * file. The exact definition of <em>hidden</em> is system-dependent. On | |
| 835 | + * UNIX systems, a file is considered to be hidden if its name begins with | |
| 836 | + * a period character (<code>'.'</code>). On Microsoft Windows systems, a file is | |
| 837 | + * considered to be hidden if it has been marked as such in the filesystem. | |
| 838 | + * | |
| 839 | + * @return <code>true</code> if and only if the file denoted by this | |
| 840 | + * abstract pathname is hidden according to the conventions of the | |
| 841 | + * underlying platform | |
| 842 | + * | |
| 843 | + * @throws SecurityException | |
| 844 | + * If a security manager exists and its <code>{@link | |
| 845 | + * java.lang.SecurityManager#checkRead(java.lang.String)}</code> | |
| 846 | + * method denies read access to the file | |
| 847 | + * | |
| 848 | + * @since 1.2 | |
| 849 | + */ | |
| 850 | + public boolean isHidden() { | |
| 851 | + SecurityManager security = System.getSecurityManager(); | |
| 852 | + if (security != null) { | |
| 853 | + security.checkRead(path); | |
| 854 | + } | |
| 855 | + return ((fs.getBooleanAttributes(this) & FileSystem.BA_HIDDEN) != 0); | |
| 856 | + } | |
| 857 | + | |
| 858 | + /** | |
| 859 | + * Returns the time that the file denoted by this abstract pathname was | |
| 860 | + * last modified. | |
| 861 | + * | |
| 862 | + * <p> Where it is required to distinguish an I/O exception from the case | |
| 863 | + * where {@code 0L} is returned, or where several attributes of the | |
| 864 | + * same file are required at the same time, or where the time of last | |
| 865 | + * access or the creation time are required, then the {@link | |
| 866 | + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) | |
| 867 | + * Files.readAttributes} method may be used. | |
| 868 | + * | |
| 869 | + * @return A <code>long</code> value representing the time the file was | |
| 870 | + * last modified, measured in milliseconds since the epoch | |
| 871 | + * (00:00:00 GMT, January 1, 1970), or <code>0L</code> if the | |
| 872 | + * file does not exist or if an I/O error occurs | |
| 873 | + * | |
| 874 | + * @throws SecurityException | |
| 875 | + * If a security manager exists and its <code>{@link | |
| 876 | + * java.lang.SecurityManager#checkRead(java.lang.String)}</code> | |
| 877 | + * method denies read access to the file | |
| 878 | + */ | |
| 879 | + public long lastModified() { | |
| 880 | + SecurityManager security = System.getSecurityManager(); | |
| 881 | + if (security != null) { | |
| 882 | + security.checkRead(path); | |
| 883 | + } | |
| 884 | + return fs.getLastModifiedTime(this); | |
| 885 | + } | |
| 886 | + | |
| 887 | + /** | |
| 888 | + * Returns the length of the file denoted by this abstract pathname. | |
| 889 | + * The return value is unspecified if this pathname denotes a directory. | |
| 890 | + * | |
| 891 | + * <p> Where it is required to distinguish an I/O exception from the case | |
| 892 | + * that {@code 0L} is returned, or where several attributes of the same file | |
| 893 | + * are required at the same time, then the {@link | |
| 894 | + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) | |
| 895 | + * Files.readAttributes} method may be used. | |
| 896 | + * | |
| 897 | + * @return The length, in bytes, of the file denoted by this abstract | |
| 898 | + * pathname, or <code>0L</code> if the file does not exist. Some | |
| 899 | + * operating systems may return <code>0L</code> for pathnames | |
| 900 | + * denoting system-dependent entities such as devices or pipes. | |
| 901 | + * | |
| 902 | + * @throws SecurityException | |
| 903 | + * If a security manager exists and its <code>{@link | |
| 904 | + * java.lang.SecurityManager#checkRead(java.lang.String)}</code> | |
| 905 | + * method denies read access to the file | |
| 906 | + */ | |
| 907 | + public long length() { | |
| 908 | + SecurityManager security = System.getSecurityManager(); | |
| 909 | + if (security != null) { | |
| 910 | + security.checkRead(path); | |
| 911 | + } | |
| 912 | + return fs.getLength(this); | |
| 913 | + } | |
| 914 | + | |
| 915 | + | |
| 916 | + /* -- File operations -- */ | |
| 917 | + | |
| 918 | + /** | |
| 919 | + * Atomically creates a new, empty file named by this abstract pathname if | |
| 920 | + * and only if a file with this name does not yet exist. The check for the | |
| 921 | + * existence of the file and the creation of the file if it does not exist | |
| 922 | + * are a single operation that is atomic with respect to all other | |
| 923 | + * filesystem activities that might affect the file. | |
| 924 | + * <P> | |
| 925 | + * Note: this method should <i>not</i> be used for file-locking, as | |
| 926 | + * the resulting protocol cannot be made to work reliably. The | |
| 927 | + * {@link java.nio.channels.FileLock FileLock} | |
| 928 | + * facility should be used instead. | |
| 929 | + * | |
| 930 | + * @return <code>true</code> if the named file does not exist and was | |
| 931 | + * successfully created; <code>false</code> if the named file | |
| 932 | + * already exists | |
| 933 | + * | |
| 934 | + * @throws IOException | |
| 935 | + * If an I/O error occurred | |
| 936 | + * | |
| 937 | + * @throws SecurityException | |
| 938 | + * If a security manager exists and its <code>{@link | |
| 939 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 940 | + * method denies write access to the file | |
| 941 | + * | |
| 942 | + * @since 1.2 | |
| 943 | + */ | |
| 944 | + public boolean createNewFile() throws IOException { | |
| 945 | + SecurityManager security = System.getSecurityManager(); | |
| 946 | + if (security != null) security.checkWrite(path); | |
| 947 | + return fs.createFileExclusively(path); | |
| 948 | + } | |
| 949 | + | |
| 950 | + /** | |
| 951 | + * Deletes the file or directory denoted by this abstract pathname. If | |
| 952 | + * this pathname denotes a directory, then the directory must be empty in | |
| 953 | + * order to be deleted. | |
| 954 | + * | |
| 955 | + * <p> Note that the {@link java.nio.file.Files} class defines the {@link | |
| 956 | + * java.nio.file.Files#delete(Path) delete} method to throw an {@link IOException} | |
| 957 | + * when a file cannot be deleted. This is useful for error reporting and to | |
| 958 | + * diagnose why a file cannot be deleted. | |
| 959 | + * | |
| 960 | + * @return <code>true</code> if and only if the file or directory is | |
| 961 | + * successfully deleted; <code>false</code> otherwise | |
| 962 | + * | |
| 963 | + * @throws SecurityException | |
| 964 | + * If a security manager exists and its <code>{@link | |
| 965 | + * java.lang.SecurityManager#checkDelete}</code> method denies | |
| 966 | + * delete access to the file | |
| 967 | + */ | |
| 968 | + public boolean delete() { | |
| 969 | + SecurityManager security = System.getSecurityManager(); | |
| 970 | + if (security != null) { | |
| 971 | + security.checkDelete(path); | |
| 972 | + } | |
| 973 | + return fs.delete(this); | |
| 974 | + } | |
| 975 | + | |
| 976 | + /** | |
| 977 | + * Requests that the file or directory denoted by this abstract | |
| 978 | + * pathname be deleted when the virtual machine terminates. | |
| 979 | + * Files (or directories) are deleted in the reverse order that | |
| 980 | + * they are registered. Invoking this method to delete a file or | |
| 981 | + * directory that is already registered for deletion has no effect. | |
| 982 | + * Deletion will be attempted only for normal termination of the | |
| 983 | + * virtual machine, as defined by the Java Language Specification. | |
| 984 | + * | |
| 985 | + * <p> Once deletion has been requested, it is not possible to cancel the | |
| 986 | + * request. This method should therefore be used with care. | |
| 987 | + * | |
| 988 | + * <P> | |
| 989 | + * Note: this method should <i>not</i> be used for file-locking, as | |
| 990 | + * the resulting protocol cannot be made to work reliably. The | |
| 991 | + * {@link java.nio.channels.FileLock FileLock} | |
| 992 | + * facility should be used instead. | |
| 993 | + * | |
| 994 | + * @throws SecurityException | |
| 995 | + * If a security manager exists and its <code>{@link | |
| 996 | + * java.lang.SecurityManager#checkDelete}</code> method denies | |
| 997 | + * delete access to the file | |
| 998 | + * | |
| 999 | + * @see #delete | |
| 1000 | + * | |
| 1001 | + * @since 1.2 | |
| 1002 | + */ | |
| 1003 | + public void deleteOnExit() { | |
| 1004 | + SecurityManager security = System.getSecurityManager(); | |
| 1005 | + if (security != null) { | |
| 1006 | + security.checkDelete(path); | |
| 1007 | + } | |
| 1008 | + DeleteOnExitHook.add(path); | |
| 1009 | + } | |
| 1010 | + | |
| 1011 | + /** | |
| 1012 | + * Returns an array of strings naming the files and directories in the | |
| 1013 | + * directory denoted by this abstract pathname. | |
| 1014 | + * | |
| 1015 | + * <p> If this abstract pathname does not denote a directory, then this | |
| 1016 | + * method returns {@code null}. Otherwise an array of strings is | |
| 1017 | + * returned, one for each file or directory in the directory. Names | |
| 1018 | + * denoting the directory itself and the directory's parent directory are | |
| 1019 | + * not included in the result. Each string is a file name rather than a | |
| 1020 | + * complete path. | |
| 1021 | + * | |
| 1022 | + * <p> There is no guarantee that the name strings in the resulting array | |
| 1023 | + * will appear in any specific order; they are not, in particular, | |
| 1024 | + * guaranteed to appear in alphabetical order. | |
| 1025 | + * | |
| 1026 | + * <p> Note that the {@link java.nio.file.Files} class defines the {@link | |
| 1027 | + * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method to | |
| 1028 | + * open a directory and iterate over the names of the files in the directory. | |
| 1029 | + * This may use less resources when working with very large directories, and | |
| 1030 | + * may be more responsive when working with remote directories. | |
| 1031 | + * | |
| 1032 | + * @return An array of strings naming the files and directories in the | |
| 1033 | + * directory denoted by this abstract pathname. The array will be | |
| 1034 | + * empty if the directory is empty. Returns {@code null} if | |
| 1035 | + * this abstract pathname does not denote a directory, or if an | |
| 1036 | + * I/O error occurs. | |
| 1037 | + * | |
| 1038 | + * @throws SecurityException | |
| 1039 | + * If a security manager exists and its {@link | |
| 1040 | + * SecurityManager#checkRead(String)} method denies read access to | |
| 1041 | + * the directory | |
| 1042 | + */ | |
| 1043 | + public String[] list() { | |
| 1044 | + SecurityManager security = System.getSecurityManager(); | |
| 1045 | + if (security != null) { | |
| 1046 | + security.checkRead(path); | |
| 1047 | + } | |
| 1048 | + return fs.list(this); | |
| 1049 | + } | |
| 1050 | + | |
| 1051 | + /** | |
| 1052 | + * Returns an array of strings naming the files and directories in the | |
| 1053 | + * directory denoted by this abstract pathname that satisfy the specified | |
| 1054 | + * filter. The behavior of this method is the same as that of the | |
| 1055 | + * {@link #list()} method, except that the strings in the returned array | |
| 1056 | + * must satisfy the filter. If the given {@code filter} is {@code null} | |
| 1057 | + * then all names are accepted. Otherwise, a name satisfies the filter if | |
| 1058 | + * and only if the value {@code true} results when the {@link | |
| 1059 | + * FilenameFilter#accept FilenameFilter.accept(File, String)} method | |
| 1060 | + * of the filter is invoked on this abstract pathname and the name of a | |
| 1061 | + * file or directory in the directory that it denotes. | |
| 1062 | + * | |
| 1063 | + * @param filter | |
| 1064 | + * A filename filter | |
| 1065 | + * | |
| 1066 | + * @return An array of strings naming the files and directories in the | |
| 1067 | + * directory denoted by this abstract pathname that were accepted | |
| 1068 | + * by the given {@code filter}. The array will be empty if the | |
| 1069 | + * directory is empty or if no names were accepted by the filter. | |
| 1070 | + * Returns {@code null} if this abstract pathname does not denote | |
| 1071 | + * a directory, or if an I/O error occurs. | |
| 1072 | + * | |
| 1073 | + * @throws SecurityException | |
| 1074 | + * If a security manager exists and its {@link | |
| 1075 | + * SecurityManager#checkRead(String)} method denies read access to | |
| 1076 | + * the directory | |
| 1077 | + * | |
| 1078 | + * @see java.nio.file.Files#newDirectoryStream(Path,String) | |
| 1079 | + */ | |
| 1080 | + public String[] list(FilenameFilter filter) { | |
| 1081 | + String names[] = list(); | |
| 1082 | + if ((names == null) || (filter == null)) { | |
| 1083 | + return names; | |
| 1084 | + } | |
| 1085 | + List<String> v = new ArrayList<>(); | |
| 1086 | + for (int i = 0 ; i < names.length ; i++) { | |
| 1087 | + if (filter.accept(this, names[i])) { | |
| 1088 | + v.add(names[i]); | |
| 1089 | + } | |
| 1090 | + } | |
| 1091 | + return v.toArray(new String[v.size()]); | |
| 1092 | + } | |
| 1093 | + | |
| 1094 | + /** | |
| 1095 | + * Returns an array of abstract pathnames denoting the files in the | |
| 1096 | + * directory denoted by this abstract pathname. | |
| 1097 | + * | |
| 1098 | + * <p> If this abstract pathname does not denote a directory, then this | |
| 1099 | + * method returns {@code null}. Otherwise an array of {@code File} objects | |
| 1100 | + * is returned, one for each file or directory in the directory. Pathnames | |
| 1101 | + * denoting the directory itself and the directory's parent directory are | |
| 1102 | + * not included in the result. Each resulting abstract pathname is | |
| 1103 | + * constructed from this abstract pathname using the {@link #File(File, | |
| 1104 | + * String) File(File, String)} constructor. Therefore if this | |
| 1105 | + * pathname is absolute then each resulting pathname is absolute; if this | |
| 1106 | + * pathname is relative then each resulting pathname will be relative to | |
| 1107 | + * the same directory. | |
| 1108 | + * | |
| 1109 | + * <p> There is no guarantee that the name strings in the resulting array | |
| 1110 | + * will appear in any specific order; they are not, in particular, | |
| 1111 | + * guaranteed to appear in alphabetical order. | |
| 1112 | + * | |
| 1113 | + * <p> Note that the {@link java.nio.file.Files} class defines the {@link | |
| 1114 | + * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method | |
| 1115 | + * to open a directory and iterate over the names of the files in the | |
| 1116 | + * directory. This may use less resources when working with very large | |
| 1117 | + * directories. | |
| 1118 | + * | |
| 1119 | + * @return An array of abstract pathnames denoting the files and | |
| 1120 | + * directories in the directory denoted by this abstract pathname. | |
| 1121 | + * The array will be empty if the directory is empty. Returns | |
| 1122 | + * {@code null} if this abstract pathname does not denote a | |
| 1123 | + * directory, or if an I/O error occurs. | |
| 1124 | + * | |
| 1125 | + * @throws SecurityException | |
| 1126 | + * If a security manager exists and its {@link | |
| 1127 | + * SecurityManager#checkRead(String)} method denies read access to | |
| 1128 | + * the directory | |
| 1129 | + * | |
| 1130 | + * @since 1.2 | |
| 1131 | + */ | |
| 1132 | + public File[] listFiles() { | |
| 1133 | + String[] ss = list(); | |
| 1134 | + if (ss == null) return null; | |
| 1135 | + int n = ss.length; | |
| 1136 | + File[] fs = new File[n]; | |
| 1137 | + for (int i = 0; i < n; i++) { | |
| 1138 | + fs[i] = new File(ss[i], this); | |
| 1139 | + } | |
| 1140 | + return fs; | |
| 1141 | + } | |
| 1142 | + | |
| 1143 | + /** | |
| 1144 | + * Returns an array of abstract pathnames denoting the files and | |
| 1145 | + * directories in the directory denoted by this abstract pathname that | |
| 1146 | + * satisfy the specified filter. The behavior of this method is the same | |
| 1147 | + * as that of the {@link #listFiles()} method, except that the pathnames in | |
| 1148 | + * the returned array must satisfy the filter. If the given {@code filter} | |
| 1149 | + * is {@code null} then all pathnames are accepted. Otherwise, a pathname | |
| 1150 | + * satisfies the filter if and only if the value {@code true} results when | |
| 1151 | + * the {@link FilenameFilter#accept | |
| 1152 | + * FilenameFilter.accept(File, String)} method of the filter is | |
| 1153 | + * invoked on this abstract pathname and the name of a file or directory in | |
| 1154 | + * the directory that it denotes. | |
| 1155 | + * | |
| 1156 | + * @param filter | |
| 1157 | + * A filename filter | |
| 1158 | + * | |
| 1159 | + * @return An array of abstract pathnames denoting the files and | |
| 1160 | + * directories in the directory denoted by this abstract pathname. | |
| 1161 | + * The array will be empty if the directory is empty. Returns | |
| 1162 | + * {@code null} if this abstract pathname does not denote a | |
| 1163 | + * directory, or if an I/O error occurs. | |
| 1164 | + * | |
| 1165 | + * @throws SecurityException | |
| 1166 | + * If a security manager exists and its {@link | |
| 1167 | + * SecurityManager#checkRead(String)} method denies read access to | |
| 1168 | + * the directory | |
| 1169 | + * | |
| 1170 | + * @since 1.2 | |
| 1171 | + * @see java.nio.file.Files#newDirectoryStream(Path,String) | |
| 1172 | + */ | |
| 1173 | + public File[] listFiles(FilenameFilter filter) { | |
| 1174 | + String ss[] = list(); | |
| 1175 | + if (ss == null) return null; | |
| 1176 | + ArrayList<File> files = new ArrayList<>(); | |
| 1177 | + for (String s : ss) | |
| 1178 | + if ((filter == null) || filter.accept(this, s)) | |
| 1179 | + files.add(new File(s, this)); | |
| 1180 | + return files.toArray(new File[files.size()]); | |
| 1181 | + } | |
| 1182 | + | |
| 1183 | + /** | |
| 1184 | + * Returns an array of abstract pathnames denoting the files and | |
| 1185 | + * directories in the directory denoted by this abstract pathname that | |
| 1186 | + * satisfy the specified filter. The behavior of this method is the same | |
| 1187 | + * as that of the {@link #listFiles()} method, except that the pathnames in | |
| 1188 | + * the returned array must satisfy the filter. If the given {@code filter} | |
| 1189 | + * is {@code null} then all pathnames are accepted. Otherwise, a pathname | |
| 1190 | + * satisfies the filter if and only if the value {@code true} results when | |
| 1191 | + * the {@link FileFilter#accept FileFilter.accept(File)} method of the | |
| 1192 | + * filter is invoked on the pathname. | |
| 1193 | + * | |
| 1194 | + * @param filter | |
| 1195 | + * A file filter | |
| 1196 | + * | |
| 1197 | + * @return An array of abstract pathnames denoting the files and | |
| 1198 | + * directories in the directory denoted by this abstract pathname. | |
| 1199 | + * The array will be empty if the directory is empty. Returns | |
| 1200 | + * {@code null} if this abstract pathname does not denote a | |
| 1201 | + * directory, or if an I/O error occurs. | |
| 1202 | + * | |
| 1203 | + * @throws SecurityException | |
| 1204 | + * If a security manager exists and its {@link | |
| 1205 | + * SecurityManager#checkRead(String)} method denies read access to | |
| 1206 | + * the directory | |
| 1207 | + * | |
| 1208 | + * @since 1.2 | |
| 1209 | + * @see java.nio.file.Files#newDirectoryStream(Path,java.nio.file.DirectoryStream.Filter) | |
| 1210 | + */ | |
| 1211 | + public File[] listFiles(FileFilter filter) { | |
| 1212 | + String ss[] = list(); | |
| 1213 | + if (ss == null) return null; | |
| 1214 | + ArrayList<File> files = new ArrayList<>(); | |
| 1215 | + for (String s : ss) { | |
| 1216 | + File f = new File(s, this); | |
| 1217 | + if ((filter == null) || filter.accept(f)) | |
| 1218 | + files.add(f); | |
| 1219 | + } | |
| 1220 | + return files.toArray(new File[files.size()]); | |
| 1221 | + } | |
| 1222 | + | |
| 1223 | + /** | |
| 1224 | + * Creates the directory named by this abstract pathname. | |
| 1225 | + * | |
| 1226 | + * @return <code>true</code> if and only if the directory was | |
| 1227 | + * created; <code>false</code> otherwise | |
| 1228 | + * | |
| 1229 | + * @throws SecurityException | |
| 1230 | + * If a security manager exists and its <code>{@link | |
| 1231 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1232 | + * method does not permit the named directory to be created | |
| 1233 | + */ | |
| 1234 | + public boolean mkdir() { | |
| 1235 | + SecurityManager security = System.getSecurityManager(); | |
| 1236 | + if (security != null) { | |
| 1237 | + security.checkWrite(path); | |
| 1238 | + } | |
| 1239 | + return fs.createDirectory(this); | |
| 1240 | + } | |
| 1241 | + | |
| 1242 | + /** | |
| 1243 | + * Creates the directory named by this abstract pathname, including any | |
| 1244 | + * necessary but nonexistent parent directories. Note that if this | |
| 1245 | + * operation fails it may have succeeded in creating some of the necessary | |
| 1246 | + * parent directories. | |
| 1247 | + * | |
| 1248 | + * @return <code>true</code> if and only if the directory was created, | |
| 1249 | + * along with all necessary parent directories; <code>false</code> | |
| 1250 | + * otherwise | |
| 1251 | + * | |
| 1252 | + * @throws SecurityException | |
| 1253 | + * If a security manager exists and its <code>{@link | |
| 1254 | + * java.lang.SecurityManager#checkRead(java.lang.String)}</code> | |
| 1255 | + * method does not permit verification of the existence of the | |
| 1256 | + * named directory and all necessary parent directories; or if | |
| 1257 | + * the <code>{@link | |
| 1258 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1259 | + * method does not permit the named directory and all necessary | |
| 1260 | + * parent directories to be created | |
| 1261 | + */ | |
| 1262 | + public boolean mkdirs() { | |
| 1263 | + if (exists()) { | |
| 1264 | + return false; | |
| 1265 | + } | |
| 1266 | + if (mkdir()) { | |
| 1267 | + return true; | |
| 1268 | + } | |
| 1269 | + File canonFile = null; | |
| 1270 | + try { | |
| 1271 | + canonFile = getCanonicalFile(); | |
| 1272 | + } catch (IOException e) { | |
| 1273 | + return false; | |
| 1274 | + } | |
| 1275 | + | |
| 1276 | + File parent = canonFile.getParentFile(); | |
| 1277 | + return (parent != null && (parent.mkdirs() || parent.exists()) && | |
| 1278 | + canonFile.mkdir()); | |
| 1279 | + } | |
| 1280 | + | |
| 1281 | + /** | |
| 1282 | + * Renames the file denoted by this abstract pathname. | |
| 1283 | + * | |
| 1284 | + * <p> Many aspects of the behavior of this method are inherently | |
| 1285 | + * platform-dependent: The rename operation might not be able to move a | |
| 1286 | + * file from one filesystem to another, it might not be atomic, and it | |
| 1287 | + * might not succeed if a file with the destination abstract pathname | |
| 1288 | + * already exists. The return value should always be checked to make sure | |
| 1289 | + * that the rename operation was successful. | |
| 1290 | + * | |
| 1291 | + * <p> Note that the {@link java.nio.file.Files} class defines the {@link | |
| 1292 | + * java.nio.file.Files#move move} method to move or rename a file in a | |
| 1293 | + * platform independent manner. | |
| 1294 | + * | |
| 1295 | + * @param dest The new abstract pathname for the named file | |
| 1296 | + * | |
| 1297 | + * @return <code>true</code> if and only if the renaming succeeded; | |
| 1298 | + * <code>false</code> otherwise | |
| 1299 | + * | |
| 1300 | + * @throws SecurityException | |
| 1301 | + * If a security manager exists and its <code>{@link | |
| 1302 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1303 | + * method denies write access to either the old or new pathnames | |
| 1304 | + * | |
| 1305 | + * @throws NullPointerException | |
| 1306 | + * If parameter <code>dest</code> is <code>null</code> | |
| 1307 | + */ | |
| 1308 | + public boolean renameTo(File dest) { | |
| 1309 | + SecurityManager security = System.getSecurityManager(); | |
| 1310 | + if (security != null) { | |
| 1311 | + security.checkWrite(path); | |
| 1312 | + security.checkWrite(dest.path); | |
| 1313 | + } | |
| 1314 | + return fs.rename(this, dest); | |
| 1315 | + } | |
| 1316 | + | |
| 1317 | + /** | |
| 1318 | + * Sets the last-modified time of the file or directory named by this | |
| 1319 | + * abstract pathname. | |
| 1320 | + * | |
| 1321 | + * <p> All platforms support file-modification times to the nearest second, | |
| 1322 | + * but some provide more precision. The argument will be truncated to fit | |
| 1323 | + * the supported precision. If the operation succeeds and no intervening | |
| 1324 | + * operations on the file take place, then the next invocation of the | |
| 1325 | + * <code>{@link #lastModified}</code> method will return the (possibly | |
| 1326 | + * truncated) <code>time</code> argument that was passed to this method. | |
| 1327 | + * | |
| 1328 | + * @param time The new last-modified time, measured in milliseconds since | |
| 1329 | + * the epoch (00:00:00 GMT, January 1, 1970) | |
| 1330 | + * | |
| 1331 | + * @return <code>true</code> if and only if the operation succeeded; | |
| 1332 | + * <code>false</code> otherwise | |
| 1333 | + * | |
| 1334 | + * @throws IllegalArgumentException If the argument is negative | |
| 1335 | + * | |
| 1336 | + * @throws SecurityException | |
| 1337 | + * If a security manager exists and its <code>{@link | |
| 1338 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1339 | + * method denies write access to the named file | |
| 1340 | + * | |
| 1341 | + * @since 1.2 | |
| 1342 | + */ | |
| 1343 | + public boolean setLastModified(long time) { | |
| 1344 | + if (time < 0) throw new IllegalArgumentException("Negative time"); | |
| 1345 | + SecurityManager security = System.getSecurityManager(); | |
| 1346 | + if (security != null) { | |
| 1347 | + security.checkWrite(path); | |
| 1348 | + } | |
| 1349 | + return fs.setLastModifiedTime(this, time); | |
| 1350 | + } | |
| 1351 | + | |
| 1352 | + /** | |
| 1353 | + * Marks the file or directory named by this abstract pathname so that | |
| 1354 | + * only read operations are allowed. After invoking this method the file | |
| 1355 | + * or directory is guaranteed not to change until it is either deleted or | |
| 1356 | + * marked to allow write access. Whether or not a read-only file or | |
| 1357 | + * directory may be deleted depends upon the underlying system. | |
| 1358 | + * | |
| 1359 | + * @return <code>true</code> if and only if the operation succeeded; | |
| 1360 | + * <code>false</code> otherwise | |
| 1361 | + * | |
| 1362 | + * @throws SecurityException | |
| 1363 | + * If a security manager exists and its <code>{@link | |
| 1364 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1365 | + * method denies write access to the named file | |
| 1366 | + * | |
| 1367 | + * @since 1.2 | |
| 1368 | + */ | |
| 1369 | + public boolean setReadOnly() { | |
| 1370 | + SecurityManager security = System.getSecurityManager(); | |
| 1371 | + if (security != null) { | |
| 1372 | + security.checkWrite(path); | |
| 1373 | + } | |
| 1374 | + return fs.setReadOnly(this); | |
| 1375 | + } | |
| 1376 | + | |
| 1377 | + /** | |
| 1378 | + * Sets the owner's or everybody's write permission for this abstract | |
| 1379 | + * pathname. | |
| 1380 | + * | |
| 1381 | + * <p> The {@link java.nio.file.Files} class defines methods that operate on | |
| 1382 | + * file attributes including file permissions. This may be used when finer | |
| 1383 | + * manipulation of file permissions is required. | |
| 1384 | + * | |
| 1385 | + * @param writable | |
| 1386 | + * If <code>true</code>, sets the access permission to allow write | |
| 1387 | + * operations; if <code>false</code> to disallow write operations | |
| 1388 | + * | |
| 1389 | + * @param ownerOnly | |
| 1390 | + * If <code>true</code>, the write permission applies only to the | |
| 1391 | + * owner's write permission; otherwise, it applies to everybody. If | |
| 1392 | + * the underlying file system can not distinguish the owner's write | |
| 1393 | + * permission from that of others, then the permission will apply to | |
| 1394 | + * everybody, regardless of this value. | |
| 1395 | + * | |
| 1396 | + * @return <code>true</code> if and only if the operation succeeded. The | |
| 1397 | + * operation will fail if the user does not have permission to change | |
| 1398 | + * the access permissions of this abstract pathname. | |
| 1399 | + * | |
| 1400 | + * @throws SecurityException | |
| 1401 | + * If a security manager exists and its <code>{@link | |
| 1402 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1403 | + * method denies write access to the named file | |
| 1404 | + * | |
| 1405 | + * @since 1.6 | |
| 1406 | + */ | |
| 1407 | + public boolean setWritable(boolean writable, boolean ownerOnly) { | |
| 1408 | + SecurityManager security = System.getSecurityManager(); | |
| 1409 | + if (security != null) { | |
| 1410 | + security.checkWrite(path); | |
| 1411 | + } | |
| 1412 | + return fs.setPermission(this, FileSystem.ACCESS_WRITE, writable, ownerOnly); | |
| 1413 | + } | |
| 1414 | + | |
| 1415 | + /** | |
| 1416 | + * A convenience method to set the owner's write permission for this abstract | |
| 1417 | + * pathname. | |
| 1418 | + * | |
| 1419 | + * <p> An invocation of this method of the form <tt>file.setWritable(arg)</tt> | |
| 1420 | + * behaves in exactly the same way as the invocation | |
| 1421 | + * | |
| 1422 | + * <pre> | |
| 1423 | + * file.setWritable(arg, true) </pre> | |
| 1424 | + * | |
| 1425 | + * @param writable | |
| 1426 | + * If <code>true</code>, sets the access permission to allow write | |
| 1427 | + * operations; if <code>false</code> to disallow write operations | |
| 1428 | + * | |
| 1429 | + * @return <code>true</code> if and only if the operation succeeded. The | |
| 1430 | + * operation will fail if the user does not have permission to | |
| 1431 | + * change the access permissions of this abstract pathname. | |
| 1432 | + * | |
| 1433 | + * @throws SecurityException | |
| 1434 | + * If a security manager exists and its <code>{@link | |
| 1435 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1436 | + * method denies write access to the file | |
| 1437 | + * | |
| 1438 | + * @since 1.6 | |
| 1439 | + */ | |
| 1440 | + public boolean setWritable(boolean writable) { | |
| 1441 | + return setWritable(writable, true); | |
| 1442 | + } | |
| 1443 | + | |
| 1444 | + /** | |
| 1445 | + * Sets the owner's or everybody's read permission for this abstract | |
| 1446 | + * pathname. | |
| 1447 | + * | |
| 1448 | + * <p> The {@link java.nio.file.Files} class defines methods that operate on | |
| 1449 | + * file attributes including file permissions. This may be used when finer | |
| 1450 | + * manipulation of file permissions is required. | |
| 1451 | + * | |
| 1452 | + * @param readable | |
| 1453 | + * If <code>true</code>, sets the access permission to allow read | |
| 1454 | + * operations; if <code>false</code> to disallow read operations | |
| 1455 | + * | |
| 1456 | + * @param ownerOnly | |
| 1457 | + * If <code>true</code>, the read permission applies only to the | |
| 1458 | + * owner's read permission; otherwise, it applies to everybody. If | |
| 1459 | + * the underlying file system can not distinguish the owner's read | |
| 1460 | + * permission from that of others, then the permission will apply to | |
| 1461 | + * everybody, regardless of this value. | |
| 1462 | + * | |
| 1463 | + * @return <code>true</code> if and only if the operation succeeded. The | |
| 1464 | + * operation will fail if the user does not have permission to | |
| 1465 | + * change the access permissions of this abstract pathname. If | |
| 1466 | + * <code>readable</code> is <code>false</code> and the underlying | |
| 1467 | + * file system does not implement a read permission, then the | |
| 1468 | + * operation will fail. | |
| 1469 | + * | |
| 1470 | + * @throws SecurityException | |
| 1471 | + * If a security manager exists and its <code>{@link | |
| 1472 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1473 | + * method denies write access to the file | |
| 1474 | + * | |
| 1475 | + * @since 1.6 | |
| 1476 | + */ | |
| 1477 | + public boolean setReadable(boolean readable, boolean ownerOnly) { | |
| 1478 | + SecurityManager security = System.getSecurityManager(); | |
| 1479 | + if (security != null) { | |
| 1480 | + security.checkWrite(path); | |
| 1481 | + } | |
| 1482 | + return fs.setPermission(this, FileSystem.ACCESS_READ, readable, ownerOnly); | |
| 1483 | + } | |
| 1484 | + | |
| 1485 | + /** | |
| 1486 | + * A convenience method to set the owner's read permission for this abstract | |
| 1487 | + * pathname. | |
| 1488 | + * | |
| 1489 | + * <p>An invocation of this method of the form <tt>file.setReadable(arg)</tt> | |
| 1490 | + * behaves in exactly the same way as the invocation | |
| 1491 | + * | |
| 1492 | + * <pre> | |
| 1493 | + * file.setReadable(arg, true) </pre> | |
| 1494 | + * | |
| 1495 | + * @param readable | |
| 1496 | + * If <code>true</code>, sets the access permission to allow read | |
| 1497 | + * operations; if <code>false</code> to disallow read operations | |
| 1498 | + * | |
| 1499 | + * @return <code>true</code> if and only if the operation succeeded. The | |
| 1500 | + * operation will fail if the user does not have permission to | |
| 1501 | + * change the access permissions of this abstract pathname. If | |
| 1502 | + * <code>readable</code> is <code>false</code> and the underlying | |
| 1503 | + * file system does not implement a read permission, then the | |
| 1504 | + * operation will fail. | |
| 1505 | + * | |
| 1506 | + * @throws SecurityException | |
| 1507 | + * If a security manager exists and its <code>{@link | |
| 1508 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1509 | + * method denies write access to the file | |
| 1510 | + * | |
| 1511 | + * @since 1.6 | |
| 1512 | + */ | |
| 1513 | + public boolean setReadable(boolean readable) { | |
| 1514 | + return setReadable(readable, true); | |
| 1515 | + } | |
| 1516 | + | |
| 1517 | + /** | |
| 1518 | + * Sets the owner's or everybody's execute permission for this abstract | |
| 1519 | + * pathname. | |
| 1520 | + * | |
| 1521 | + * <p> The {@link java.nio.file.Files} class defines methods that operate on | |
| 1522 | + * file attributes including file permissions. This may be used when finer | |
| 1523 | + * manipulation of file permissions is required. | |
| 1524 | + * | |
| 1525 | + * @param executable | |
| 1526 | + * If <code>true</code>, sets the access permission to allow execute | |
| 1527 | + * operations; if <code>false</code> to disallow execute operations | |
| 1528 | + * | |
| 1529 | + * @param ownerOnly | |
| 1530 | + * If <code>true</code>, the execute permission applies only to the | |
| 1531 | + * owner's execute permission; otherwise, it applies to everybody. | |
| 1532 | + * If the underlying file system can not distinguish the owner's | |
| 1533 | + * execute permission from that of others, then the permission will | |
| 1534 | + * apply to everybody, regardless of this value. | |
| 1535 | + * | |
| 1536 | + * @return <code>true</code> if and only if the operation succeeded. The | |
| 1537 | + * operation will fail if the user does not have permission to | |
| 1538 | + * change the access permissions of this abstract pathname. If | |
| 1539 | + * <code>executable</code> is <code>false</code> and the underlying | |
| 1540 | + * file system does not implement an execute permission, then the | |
| 1541 | + * operation will fail. | |
| 1542 | + * | |
| 1543 | + * @throws SecurityException | |
| 1544 | + * If a security manager exists and its <code>{@link | |
| 1545 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1546 | + * method denies write access to the file | |
| 1547 | + * | |
| 1548 | + * @since 1.6 | |
| 1549 | + */ | |
| 1550 | + public boolean setExecutable(boolean executable, boolean ownerOnly) { | |
| 1551 | + SecurityManager security = System.getSecurityManager(); | |
| 1552 | + if (security != null) { | |
| 1553 | + security.checkWrite(path); | |
| 1554 | + } | |
| 1555 | + return fs.setPermission(this, FileSystem.ACCESS_EXECUTE, executable, ownerOnly); | |
| 1556 | + } | |
| 1557 | + | |
| 1558 | + /** | |
| 1559 | + * A convenience method to set the owner's execute permission for this abstract | |
| 1560 | + * pathname. | |
| 1561 | + * | |
| 1562 | + * <p>An invocation of this method of the form <tt>file.setExcutable(arg)</tt> | |
| 1563 | + * behaves in exactly the same way as the invocation | |
| 1564 | + * | |
| 1565 | + * <pre> | |
| 1566 | + * file.setExecutable(arg, true) </pre> | |
| 1567 | + * | |
| 1568 | + * @param executable | |
| 1569 | + * If <code>true</code>, sets the access permission to allow execute | |
| 1570 | + * operations; if <code>false</code> to disallow execute operations | |
| 1571 | + * | |
| 1572 | + * @return <code>true</code> if and only if the operation succeeded. The | |
| 1573 | + * operation will fail if the user does not have permission to | |
| 1574 | + * change the access permissions of this abstract pathname. If | |
| 1575 | + * <code>executable</code> is <code>false</code> and the underlying | |
| 1576 | + * file system does not implement an excute permission, then the | |
| 1577 | + * operation will fail. | |
| 1578 | + * | |
| 1579 | + * @throws SecurityException | |
| 1580 | + * If a security manager exists and its <code>{@link | |
| 1581 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1582 | + * method denies write access to the file | |
| 1583 | + * | |
| 1584 | + * @since 1.6 | |
| 1585 | + */ | |
| 1586 | + public boolean setExecutable(boolean executable) { | |
| 1587 | + return setExecutable(executable, true); | |
| 1588 | + } | |
| 1589 | + | |
| 1590 | + /** | |
| 1591 | + * Tests whether the application can execute the file denoted by this | |
| 1592 | + * abstract pathname. | |
| 1593 | + * | |
| 1594 | + * @return <code>true</code> if and only if the abstract pathname exists | |
| 1595 | + * <em>and</em> the application is allowed to execute the file | |
| 1596 | + * | |
| 1597 | + * @throws SecurityException | |
| 1598 | + * If a security manager exists and its <code>{@link | |
| 1599 | + * java.lang.SecurityManager#checkExec(java.lang.String)}</code> | |
| 1600 | + * method denies execute access to the file | |
| 1601 | + * | |
| 1602 | + * @since 1.6 | |
| 1603 | + */ | |
| 1604 | + public boolean canExecute() { | |
| 1605 | + SecurityManager security = System.getSecurityManager(); | |
| 1606 | + if (security != null) { | |
| 1607 | + security.checkExec(path); | |
| 1608 | + } | |
| 1609 | + return fs.checkAccess(this, FileSystem.ACCESS_EXECUTE); | |
| 1610 | + } | |
| 1611 | + | |
| 1612 | + | |
| 1613 | + /* -- Filesystem interface -- */ | |
| 1614 | + | |
| 1615 | + /** | |
| 1616 | + * List the available filesystem roots. | |
| 1617 | + * | |
| 1618 | + * <p> A particular Java platform may support zero or more | |
| 1619 | + * hierarchically-organized file systems. Each file system has a | |
| 1620 | + * {@code root} directory from which all other files in that file system | |
| 1621 | + * can be reached. Windows platforms, for example, have a root directory | |
| 1622 | + * for each active drive; UNIX platforms have a single root directory, | |
| 1623 | + * namely {@code "/"}. The set of available filesystem roots is affected | |
| 1624 | + * by various system-level operations such as the insertion or ejection of | |
| 1625 | + * removable media and the disconnecting or unmounting of physical or | |
| 1626 | + * virtual disk drives. | |
| 1627 | + * | |
| 1628 | + * <p> This method returns an array of {@code File} objects that denote the | |
| 1629 | + * root directories of the available filesystem roots. It is guaranteed | |
| 1630 | + * that the canonical pathname of any file physically present on the local | |
| 1631 | + * machine will begin with one of the roots returned by this method. | |
| 1632 | + * | |
| 1633 | + * <p> The canonical pathname of a file that resides on some other machine | |
| 1634 | + * and is accessed via a remote-filesystem protocol such as SMB or NFS may | |
| 1635 | + * or may not begin with one of the roots returned by this method. If the | |
| 1636 | + * pathname of a remote file is syntactically indistinguishable from the | |
| 1637 | + * pathname of a local file then it will begin with one of the roots | |
| 1638 | + * returned by this method. Thus, for example, {@code File} objects | |
| 1639 | + * denoting the root directories of the mapped network drives of a Windows | |
| 1640 | + * platform will be returned by this method, while {@code File} objects | |
| 1641 | + * containing UNC pathnames will not be returned by this method. | |
| 1642 | + * | |
| 1643 | + * <p> Unlike most methods in this class, this method does not throw | |
| 1644 | + * security exceptions. If a security manager exists and its {@link | |
| 1645 | + * SecurityManager#checkRead(String)} method denies read access to a | |
| 1646 | + * particular root directory, then that directory will not appear in the | |
| 1647 | + * result. | |
| 1648 | + * | |
| 1649 | + * @return An array of {@code File} objects denoting the available | |
| 1650 | + * filesystem roots, or {@code null} if the set of roots could not | |
| 1651 | + * be determined. The array will be empty if there are no | |
| 1652 | + * filesystem roots. | |
| 1653 | + * | |
| 1654 | + * @since 1.2 | |
| 1655 | + * @see java.nio.file.FileStore | |
| 1656 | + */ | |
| 1657 | + public static File[] listRoots() { | |
| 1658 | + return fs.listRoots(); | |
| 1659 | + } | |
| 1660 | + | |
| 1661 | + | |
| 1662 | + /* -- Disk usage -- */ | |
| 1663 | + | |
| 1664 | + /** | |
| 1665 | + * Returns the size of the partition <a href="#partName">named</a> by this | |
| 1666 | + * abstract pathname. | |
| 1667 | + * | |
| 1668 | + * @return The size, in bytes, of the partition or <tt>0L</tt> if this | |
| 1669 | + * abstract pathname does not name a partition | |
| 1670 | + * | |
| 1671 | + * @throws SecurityException | |
| 1672 | + * If a security manager has been installed and it denies | |
| 1673 | + * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt> | |
| 1674 | + * or its {@link SecurityManager#checkRead(String)} method denies | |
| 1675 | + * read access to the file named by this abstract pathname | |
| 1676 | + * | |
| 1677 | + * @since 1.6 | |
| 1678 | + */ | |
| 1679 | + public long getTotalSpace() { | |
| 1680 | + SecurityManager sm = System.getSecurityManager(); | |
| 1681 | + if (sm != null) { | |
| 1682 | + sm.checkPermission(new RuntimePermission("getFileSystemAttributes")); | |
| 1683 | + sm.checkRead(path); | |
| 1684 | + } | |
| 1685 | + return fs.getSpace(this, FileSystem.SPACE_TOTAL); | |
| 1686 | + } | |
| 1687 | + | |
| 1688 | + /** | |
| 1689 | + * Returns the number of unallocated bytes in the partition <a | |
| 1690 | + * href="#partName">named</a> by this abstract path name. | |
| 1691 | + * | |
| 1692 | + * <p> The returned number of unallocated bytes is a hint, but not | |
| 1693 | + * a guarantee, that it is possible to use most or any of these | |
| 1694 | + * bytes. The number of unallocated bytes is most likely to be | |
| 1695 | + * accurate immediately after this call. It is likely to be made | |
| 1696 | + * inaccurate by any external I/O operations including those made | |
| 1697 | + * on the system outside of this virtual machine. This method | |
| 1698 | + * makes no guarantee that write operations to this file system | |
| 1699 | + * will succeed. | |
| 1700 | + * | |
| 1701 | + * @return The number of unallocated bytes on the partition <tt>0L</tt> | |
| 1702 | + * if the abstract pathname does not name a partition. This | |
| 1703 | + * value will be less than or equal to the total file system size | |
| 1704 | + * returned by {@link #getTotalSpace}. | |
| 1705 | + * | |
| 1706 | + * @throws SecurityException | |
| 1707 | + * If a security manager has been installed and it denies | |
| 1708 | + * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt> | |
| 1709 | + * or its {@link SecurityManager#checkRead(String)} method denies | |
| 1710 | + * read access to the file named by this abstract pathname | |
| 1711 | + * | |
| 1712 | + * @since 1.6 | |
| 1713 | + */ | |
| 1714 | + public long getFreeSpace() { | |
| 1715 | + SecurityManager sm = System.getSecurityManager(); | |
| 1716 | + if (sm != null) { | |
| 1717 | + sm.checkPermission(new RuntimePermission("getFileSystemAttributes")); | |
| 1718 | + sm.checkRead(path); | |
| 1719 | + } | |
| 1720 | + return fs.getSpace(this, FileSystem.SPACE_FREE); | |
| 1721 | + } | |
| 1722 | + | |
| 1723 | + /** | |
| 1724 | + * Returns the number of bytes available to this virtual machine on the | |
| 1725 | + * partition <a href="#partName">named</a> by this abstract pathname. When | |
| 1726 | + * possible, this method checks for write permissions and other operating | |
| 1727 | + * system restrictions and will therefore usually provide a more accurate | |
| 1728 | + * estimate of how much new data can actually be written than {@link | |
| 1729 | + * #getFreeSpace}. | |
| 1730 | + * | |
| 1731 | + * <p> The returned number of available bytes is a hint, but not a | |
| 1732 | + * guarantee, that it is possible to use most or any of these bytes. The | |
| 1733 | + * number of unallocated bytes is most likely to be accurate immediately | |
| 1734 | + * after this call. It is likely to be made inaccurate by any external | |
| 1735 | + * I/O operations including those made on the system outside of this | |
| 1736 | + * virtual machine. This method makes no guarantee that write operations | |
| 1737 | + * to this file system will succeed. | |
| 1738 | + * | |
| 1739 | + * @return The number of available bytes on the partition or <tt>0L</tt> | |
| 1740 | + * if the abstract pathname does not name a partition. On | |
| 1741 | + * systems where this information is not available, this method | |
| 1742 | + * will be equivalent to a call to {@link #getFreeSpace}. | |
| 1743 | + * | |
| 1744 | + * @throws SecurityException | |
| 1745 | + * If a security manager has been installed and it denies | |
| 1746 | + * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt> | |
| 1747 | + * or its {@link SecurityManager#checkRead(String)} method denies | |
| 1748 | + * read access to the file named by this abstract pathname | |
| 1749 | + * | |
| 1750 | + * @since 1.6 | |
| 1751 | + */ | |
| 1752 | + public long getUsableSpace() { | |
| 1753 | + SecurityManager sm = System.getSecurityManager(); | |
| 1754 | + if (sm != null) { | |
| 1755 | + sm.checkPermission(new RuntimePermission("getFileSystemAttributes")); | |
| 1756 | + sm.checkRead(path); | |
| 1757 | + } | |
| 1758 | + return fs.getSpace(this, FileSystem.SPACE_USABLE); | |
| 1759 | + } | |
| 1760 | + | |
| 1761 | + /* -- Temporary files -- */ | |
| 1762 | + | |
| 1763 | + private static class TempDirectory { | |
| 1764 | + private TempDirectory() { } | |
| 1765 | + | |
| 1766 | + // temporary directory location | |
| 1767 | + private static final File tmpdir = new File(fs.normalize(AccessController | |
| 1768 | + .doPrivileged(new GetPropertyAction("java.io.tmpdir")))); | |
| 1769 | + static File location() { | |
| 1770 | + return tmpdir; | |
| 1771 | + } | |
| 1772 | + | |
| 1773 | + // file name generation | |
| 1774 | + private static final SecureRandom random = new SecureRandom(); | |
| 1775 | + static File generateFile(String prefix, String suffix, File dir) { | |
| 1776 | + long n = random.nextLong(); | |
| 1777 | + if (n == Long.MIN_VALUE) { | |
| 1778 | + n = 0; // corner case | |
| 1779 | + } else { | |
| 1780 | + n = Math.abs(n); | |
| 1781 | + } | |
| 1782 | + return new File(dir, prefix + Long.toString(n) + suffix); | |
| 1783 | + } | |
| 1784 | + } | |
| 1785 | + | |
| 1786 | + /** | |
| 1787 | + * <p> Creates a new empty file in the specified directory, using the | |
| 1788 | + * given prefix and suffix strings to generate its name. If this method | |
| 1789 | + * returns successfully then it is guaranteed that: | |
| 1790 | + * | |
| 1791 | + * <ol> | |
| 1792 | + * <li> The file denoted by the returned abstract pathname did not exist | |
| 1793 | + * before this method was invoked, and | |
| 1794 | + * <li> Neither this method nor any of its variants will return the same | |
| 1795 | + * abstract pathname again in the current invocation of the virtual | |
| 1796 | + * machine. | |
| 1797 | + * </ol> | |
| 1798 | + * | |
| 1799 | + * This method provides only part of a temporary-file facility. To arrange | |
| 1800 | + * for a file created by this method to be deleted automatically, use the | |
| 1801 | + * <code>{@link #deleteOnExit}</code> method. | |
| 1802 | + * | |
| 1803 | + * <p> The <code>prefix</code> argument must be at least three characters | |
| 1804 | + * long. It is recommended that the prefix be a short, meaningful string | |
| 1805 | + * such as <code>"hjb"</code> or <code>"mail"</code>. The | |
| 1806 | + * <code>suffix</code> argument may be <code>null</code>, in which case the | |
| 1807 | + * suffix <code>".tmp"</code> will be used. | |
| 1808 | + * | |
| 1809 | + * <p> To create the new file, the prefix and the suffix may first be | |
| 1810 | + * adjusted to fit the limitations of the underlying platform. If the | |
| 1811 | + * prefix is too long then it will be truncated, but its first three | |
| 1812 | + * characters will always be preserved. If the suffix is too long then it | |
| 1813 | + * too will be truncated, but if it begins with a period character | |
| 1814 | + * (<code>'.'</code>) then the period and the first three characters | |
| 1815 | + * following it will always be preserved. Once these adjustments have been | |
| 1816 | + * made the name of the new file will be generated by concatenating the | |
| 1817 | + * prefix, five or more internally-generated characters, and the suffix. | |
| 1818 | + * | |
| 1819 | + * <p> If the <code>directory</code> argument is <code>null</code> then the | |
| 1820 | + * system-dependent default temporary-file directory will be used. The | |
| 1821 | + * default temporary-file directory is specified by the system property | |
| 1822 | + * <code>java.io.tmpdir</code>. On UNIX systems the default value of this | |
| 1823 | + * property is typically <code>"/tmp"</code> or <code>"/var/tmp"</code>; on | |
| 1824 | + * Microsoft Windows systems it is typically <code>"C:\\WINNT\\TEMP"</code>. A different | |
| 1825 | + * value may be given to this system property when the Java virtual machine | |
| 1826 | + * is invoked, but programmatic changes to this property are not guaranteed | |
| 1827 | + * to have any effect upon the temporary directory used by this method. | |
| 1828 | + * | |
| 1829 | + * @param prefix The prefix string to be used in generating the file's | |
| 1830 | + * name; must be at least three characters long | |
| 1831 | + * | |
| 1832 | + * @param suffix The suffix string to be used in generating the file's | |
| 1833 | + * name; may be <code>null</code>, in which case the | |
| 1834 | + * suffix <code>".tmp"</code> will be used | |
| 1835 | + * | |
| 1836 | + * @param directory The directory in which the file is to be created, or | |
| 1837 | + * <code>null</code> if the default temporary-file | |
| 1838 | + * directory is to be used | |
| 1839 | + * | |
| 1840 | + * @return An abstract pathname denoting a newly-created empty file | |
| 1841 | + * | |
| 1842 | + * @throws IllegalArgumentException | |
| 1843 | + * If the <code>prefix</code> argument contains fewer than three | |
| 1844 | + * characters | |
| 1845 | + * | |
| 1846 | + * @throws IOException If a file could not be created | |
| 1847 | + * | |
| 1848 | + * @throws SecurityException | |
| 1849 | + * If a security manager exists and its <code>{@link | |
| 1850 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1851 | + * method does not allow a file to be created | |
| 1852 | + * | |
| 1853 | + * @since 1.2 | |
| 1854 | + */ | |
| 1855 | + public static File createTempFile(String prefix, String suffix, | |
| 1856 | + File directory) | |
| 1857 | + throws IOException | |
| 1858 | + { | |
| 1859 | + if (prefix.length() < 3) | |
| 1860 | + throw new IllegalArgumentException("Prefix string too short"); | |
| 1861 | + if (suffix == null) | |
| 1862 | + suffix = ".tmp"; | |
| 1863 | + | |
| 1864 | + File tmpdir = (directory != null) ? directory : TempDirectory.location(); | |
| 1865 | + SecurityManager sm = System.getSecurityManager(); | |
| 1866 | + File f; | |
| 1867 | + do { | |
| 1868 | + f = TempDirectory.generateFile(prefix, suffix, tmpdir); | |
| 1869 | + if (sm != null) { | |
| 1870 | + try { | |
| 1871 | + sm.checkWrite(f.getPath()); | |
| 1872 | + } catch (SecurityException se) { | |
| 1873 | + // don't reveal temporary directory location | |
| 1874 | + if (directory == null) | |
| 1875 | + throw new SecurityException("Unable to create temporary file"); | |
| 1876 | + throw se; | |
| 1877 | + } | |
| 1878 | + } | |
| 1879 | + } while (!fs.createFileExclusively(f.getPath())); | |
| 1880 | + return f; | |
| 1881 | + } | |
| 1882 | + | |
| 1883 | + /** | |
| 1884 | + * Creates an empty file in the default temporary-file directory, using | |
| 1885 | + * the given prefix and suffix to generate its name. Invoking this method | |
| 1886 | + * is equivalent to invoking <code>{@link #createTempFile(java.lang.String, | |
| 1887 | + * java.lang.String, java.io.File) | |
| 1888 | + * createTempFile(prefix, suffix, null)}</code>. | |
| 1889 | + * | |
| 1890 | + * <p> The {@link | |
| 1891 | + * java.nio.file.Files#createTempFile(String,String,java.nio.file.attribute.FileAttribute[]) | |
| 1892 | + * Files.createTempFile} method provides an alternative method to create an | |
| 1893 | + * empty file in the temporary-file directory. Files created by that method | |
| 1894 | + * may have more restrictive access permissions to files created by this | |
| 1895 | + * method and so may be more suited to security-sensitive applications. | |
| 1896 | + * | |
| 1897 | + * @param prefix The prefix string to be used in generating the file's | |
| 1898 | + * name; must be at least three characters long | |
| 1899 | + * | |
| 1900 | + * @param suffix The suffix string to be used in generating the file's | |
| 1901 | + * name; may be <code>null</code>, in which case the | |
| 1902 | + * suffix <code>".tmp"</code> will be used | |
| 1903 | + * | |
| 1904 | + * @return An abstract pathname denoting a newly-created empty file | |
| 1905 | + * | |
| 1906 | + * @throws IllegalArgumentException | |
| 1907 | + * If the <code>prefix</code> argument contains fewer than three | |
| 1908 | + * characters | |
| 1909 | + * | |
| 1910 | + * @throws IOException If a file could not be created | |
| 1911 | + * | |
| 1912 | + * @throws SecurityException | |
| 1913 | + * If a security manager exists and its <code>{@link | |
| 1914 | + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> | |
| 1915 | + * method does not allow a file to be created | |
| 1916 | + * | |
| 1917 | + * @since 1.2 | |
| 1918 | + * @see java.nio.file.Files#createTempDirectory(String,FileAttribute[]) | |
| 1919 | + */ | |
| 1920 | + public static File createTempFile(String prefix, String suffix) | |
| 1921 | + throws IOException | |
| 1922 | + { | |
| 1923 | + return createTempFile(prefix, suffix, null); | |
| 1924 | + } | |
| 1925 | + | |
| 1926 | + /* -- Basic infrastructure -- */ | |
| 1927 | + | |
| 1928 | + /** | |
| 1929 | + * Compares two abstract pathnames lexicographically. The ordering | |
| 1930 | + * defined by this method depends upon the underlying system. On UNIX | |
| 1931 | + * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows | |
| 1932 | + * systems it is not. | |
| 1933 | + * | |
| 1934 | + * @param pathname The abstract pathname to be compared to this abstract | |
| 1935 | + * pathname | |
| 1936 | + * | |
| 1937 | + * @return Zero if the argument is equal to this abstract pathname, a | |
| 1938 | + * value less than zero if this abstract pathname is | |
| 1939 | + * lexicographically less than the argument, or a value greater | |
| 1940 | + * than zero if this abstract pathname is lexicographically | |
| 1941 | + * greater than the argument | |
| 1942 | + * | |
| 1943 | + * @since 1.2 | |
| 1944 | + */ | |
| 1945 | + public int compareTo(File pathname) { | |
| 1946 | + return fs.compare(this, pathname); | |
| 1947 | + } | |
| 1948 | + | |
| 1949 | + /** | |
| 1950 | + * Tests this abstract pathname for equality with the given object. | |
| 1951 | + * Returns <code>true</code> if and only if the argument is not | |
| 1952 | + * <code>null</code> and is an abstract pathname that denotes the same file | |
| 1953 | + * or directory as this abstract pathname. Whether or not two abstract | |
| 1954 | + * pathnames are equal depends upon the underlying system. On UNIX | |
| 1955 | + * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows | |
| 1956 | + * systems it is not. | |
| 1957 | + * | |
| 1958 | + * @param obj The object to be compared with this abstract pathname | |
| 1959 | + * | |
| 1960 | + * @return <code>true</code> if and only if the objects are the same; | |
| 1961 | + * <code>false</code> otherwise | |
| 1962 | + */ | |
| 1963 | + public boolean equals(Object obj) { | |
| 1964 | + if ((obj != null) && (obj instanceof File)) { | |
| 1965 | + return compareTo((File)obj) == 0; | |
| 1966 | + } | |
| 1967 | + return false; | |
| 1968 | + } | |
| 1969 | + | |
| 1970 | + /** | |
| 1971 | + * Computes a hash code for this abstract pathname. Because equality of | |
| 1972 | + * abstract pathnames is inherently system-dependent, so is the computation | |
| 1973 | + * of their hash codes. On UNIX systems, the hash code of an abstract | |
| 1974 | + * pathname is equal to the exclusive <em>or</em> of the hash code | |
| 1975 | + * of its pathname string and the decimal value | |
| 1976 | + * <code>1234321</code>. On Microsoft Windows systems, the hash | |
| 1977 | + * code is equal to the exclusive <em>or</em> of the hash code of | |
| 1978 | + * its pathname string converted to lower case and the decimal | |
| 1979 | + * value <code>1234321</code>. Locale is not taken into account on | |
| 1980 | + * lowercasing the pathname string. | |
| 1981 | + * | |
| 1982 | + * @return A hash code for this abstract pathname | |
| 1983 | + */ | |
| 1984 | + public int hashCode() { | |
| 1985 | + return fs.hashCode(this); | |
| 1986 | + } | |
| 1987 | + | |
| 1988 | + /** | |
| 1989 | + * Returns the pathname string of this abstract pathname. This is just the | |
| 1990 | + * string returned by the <code>{@link #getPath}</code> method. | |
| 1991 | + * | |
| 1992 | + * @return The string form of this abstract pathname | |
| 1993 | + */ | |
| 1994 | + public String toString() { | |
| 1995 | + return getPath(); | |
| 1996 | + } | |
| 1997 | + | |
| 1998 | + /** | |
| 1999 | + * WriteObject is called to save this filename. | |
| 2000 | + * The separator character is saved also so it can be replaced | |
| 2001 | + * in case the path is reconstituted on a different host type. | |
| 2002 | + * <p> | |
| 2003 | + * @serialData Default fields followed by separator character. | |
| 2004 | + */ | |
| 2005 | + private synchronized void writeObject(java.io.ObjectOutputStream s) | |
| 2006 | + throws IOException | |
| 2007 | + { | |
| 2008 | + s.defaultWriteObject(); | |
| 2009 | + s.writeChar(this.separatorChar); // Add the separator character | |
| 2010 | + } | |
| 2011 | + | |
| 2012 | + /** | |
| 2013 | + * readObject is called to restore this filename. | |
| 2014 | + * The original separator character is read. If it is different | |
| 2015 | + * than the separator character on this system, then the old separator | |
| 2016 | + * is replaced by the local separator. | |
| 2017 | + */ | |
| 2018 | + private synchronized void readObject(java.io.ObjectInputStream s) | |
| 2019 | + throws IOException, ClassNotFoundException | |
| 2020 | + { | |
| 2021 | + ObjectInputStream.GetField fields = s.readFields(); | |
| 2022 | + String pathField = (String)fields.get("path", null); | |
| 2023 | + char sep = s.readChar(); // read the previous separator char | |
| 2024 | + if (sep != separatorChar) | |
| 2025 | + pathField = pathField.replace(sep, separatorChar); | |
| 2026 | + this.path = fs.normalize(pathField); | |
| 2027 | + this.prefixLength = fs.prefixLength(this.path); | |
| 2028 | + } | |
| 2029 | + | |
| 2030 | + /** use serialVersionUID from JDK 1.0.2 for interoperability */ | |
| 2031 | + private static final long serialVersionUID = 301077366599181567L; | |
| 2032 | + | |
| 2033 | + // -- Integration with java.nio.file -- | |
| 2034 | + | |
| 2035 | + private volatile transient Path filePath; | |
| 2036 | + | |
| 2037 | + /** | |
| 2038 | + * Returns a {@link Path java.nio.file.Path} object constructed from the | |
| 2039 | + * this abstract path. The resulting {@code Path} is associated with the | |
| 2040 | + * {@link java.nio.file.FileSystems#getDefault default-filesystem}. | |
| 2041 | + * | |
| 2042 | + * <p> The first invocation of this method works as if invoking it were | |
| 2043 | + * equivalent to evaluating the expression: | |
| 2044 | + * <blockquote><pre> | |
| 2045 | + * {@link java.nio.file.FileSystems#getDefault FileSystems.getDefault}().{@link | |
| 2046 | + * java.nio.file.FileSystem#getPath getPath}(this.{@link #getPath getPath}()); | |
| 2047 | + * </pre></blockquote> | |
| 2048 | + * Subsequent invocations of this method return the same {@code Path}. | |
| 2049 | + * | |
| 2050 | + * <p> If this abstract pathname is the empty abstract pathname then this | |
| 2051 | + * method returns a {@code Path} that may be used to access the current | |
| 2052 | + * user directory. | |
| 2053 | + * | |
| 2054 | + * @return a {@code Path} constructed from this abstract path | |
| 2055 | + * | |
| 2056 | + * @throws java.nio.file.InvalidPathException | |
| 2057 | + * if a {@code Path} object cannot be constructed from the abstract | |
| 2058 | + * path (see {@link java.nio.file.FileSystem#getPath FileSystem.getPath}) | |
| 2059 | + * | |
| 2060 | + * @since 1.7 | |
| 2061 | + * @see Path#toFile | |
| 2062 | + */ | |
| 2063 | + public Path toPath() { | |
| 2064 | + Path result = filePath; | |
| 2065 | + if (result == null) { | |
| 2066 | + synchronized (this) { | |
| 2067 | + result = filePath; | |
| 2068 | + if (result == null) { | |
| 2069 | + result = FileSystems.getDefault().getPath(path); | |
| 2070 | + filePath = result; | |
| 2071 | + } | |
| 2072 | + } | |
| 2073 | + } | |
| 2074 | + return result; | |
| 2075 | + } | |
| 2076 | +} | |
Binary file not shown.
| @@ -0,0 +1,50 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * A filter for abstract pathnames. | |
| 31 | + * | |
| 32 | + * <p> Instances of this interface may be passed to the <code>{@link | |
| 33 | + * File#listFiles(java.io.FileFilter) listFiles(FileFilter)}</code> method | |
| 34 | + * of the <code>{@link java.io.File}</code> class. | |
| 35 | + * | |
| 36 | + * @since 1.2 | |
| 37 | + */ | |
| 38 | +public interface FileFilter { | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * Tests whether or not the specified abstract pathname should be | |
| 42 | + * included in a pathname list. | |
| 43 | + * | |
| 44 | + * @param pathname The abstract pathname to be tested | |
| 45 | + * @return <code>true</code> if and only if <code>pathname</code> | |
| 46 | + * should be included | |
| 47 | + */ | |
| 48 | + boolean accept(File pathname); | |
| 49 | + | |
| 50 | +} | |
Binary file not shown.
| @@ -0,0 +1,408 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.nio.channels.FileChannel; | |
| 29 | +import sun.nio.ch.FileChannelImpl; | |
| 30 | + | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * A <code>FileInputStream</code> obtains input bytes | |
| 34 | + * from a file in a file system. What files | |
| 35 | + * are available depends on the host environment. | |
| 36 | + * | |
| 37 | + * <p><code>FileInputStream</code> is meant for reading streams of raw bytes | |
| 38 | + * such as image data. For reading streams of characters, consider using | |
| 39 | + * <code>FileReader</code>. | |
| 40 | + * | |
| 41 | + * @author Arthur van Hoff | |
| 42 | + * @see java.io.File | |
| 43 | + * @see java.io.FileDescriptor | |
| 44 | + * @see java.io.FileOutputStream | |
| 45 | + * @see java.nio.file.Files#newInputStream | |
| 46 | + * @since JDK1.0 | |
| 47 | + */ | |
| 48 | +public | |
| 49 | +class FileInputStream extends InputStream | |
| 50 | +{ | |
| 51 | + /* File Descriptor - handle to the open file */ | |
| 52 | + private final FileDescriptor fd; | |
| 53 | + | |
| 54 | + private FileChannel channel = null; | |
| 55 | + | |
| 56 | + private final Object closeLock = new Object(); | |
| 57 | + private volatile boolean closed = false; | |
| 58 | + | |
| 59 | + private static final ThreadLocal<Boolean> runningFinalize = | |
| 60 | + new ThreadLocal<>(); | |
| 61 | + | |
| 62 | + private static boolean isRunningFinalize() { | |
| 63 | + Boolean val; | |
| 64 | + if ((val = runningFinalize.get()) != null) | |
| 65 | + return val.booleanValue(); | |
| 66 | + return false; | |
| 67 | + } | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * Creates a <code>FileInputStream</code> by | |
| 71 | + * opening a connection to an actual file, | |
| 72 | + * the file named by the path name <code>name</code> | |
| 73 | + * in the file system. A new <code>FileDescriptor</code> | |
| 74 | + * object is created to represent this file | |
| 75 | + * connection. | |
| 76 | + * <p> | |
| 77 | + * First, if there is a security | |
| 78 | + * manager, its <code>checkRead</code> method | |
| 79 | + * is called with the <code>name</code> argument | |
| 80 | + * as its argument. | |
| 81 | + * <p> | |
| 82 | + * If the named file does not exist, is a directory rather than a regular | |
| 83 | + * file, or for some other reason cannot be opened for reading then a | |
| 84 | + * <code>FileNotFoundException</code> is thrown. | |
| 85 | + * | |
| 86 | + * @param name the system-dependent file name. | |
| 87 | + * @exception FileNotFoundException if the file does not exist, | |
| 88 | + * is a directory rather than a regular file, | |
| 89 | + * or for some other reason cannot be opened for | |
| 90 | + * reading. | |
| 91 | + * @exception SecurityException if a security manager exists and its | |
| 92 | + * <code>checkRead</code> method denies read access | |
| 93 | + * to the file. | |
| 94 | + * @see java.lang.SecurityManager#checkRead(java.lang.String) | |
| 95 | + */ | |
| 96 | + public FileInputStream(String name) throws FileNotFoundException { | |
| 97 | + this(name != null ? new File(name) : null); | |
| 98 | + } | |
| 99 | + | |
| 100 | + /** | |
| 101 | + * Creates a <code>FileInputStream</code> by | |
| 102 | + * opening a connection to an actual file, | |
| 103 | + * the file named by the <code>File</code> | |
| 104 | + * object <code>file</code> in the file system. | |
| 105 | + * A new <code>FileDescriptor</code> object | |
| 106 | + * is created to represent this file connection. | |
| 107 | + * <p> | |
| 108 | + * First, if there is a security manager, | |
| 109 | + * its <code>checkRead</code> method is called | |
| 110 | + * with the path represented by the <code>file</code> | |
| 111 | + * argument as its argument. | |
| 112 | + * <p> | |
| 113 | + * If the named file does not exist, is a directory rather than a regular | |
| 114 | + * file, or for some other reason cannot be opened for reading then a | |
| 115 | + * <code>FileNotFoundException</code> is thrown. | |
| 116 | + * | |
| 117 | + * @param file the file to be opened for reading. | |
| 118 | + * @exception FileNotFoundException if the file does not exist, | |
| 119 | + * is a directory rather than a regular file, | |
| 120 | + * or for some other reason cannot be opened for | |
| 121 | + * reading. | |
| 122 | + * @exception SecurityException if a security manager exists and its | |
| 123 | + * <code>checkRead</code> method denies read access to the file. | |
| 124 | + * @see java.io.File#getPath() | |
| 125 | + * @see java.lang.SecurityManager#checkRead(java.lang.String) | |
| 126 | + */ | |
| 127 | + public FileInputStream(File file) throws FileNotFoundException { | |
| 128 | + String name = (file != null ? file.getPath() : null); | |
| 129 | + SecurityManager security = System.getSecurityManager(); | |
| 130 | + if (security != null) { | |
| 131 | + security.checkRead(name); | |
| 132 | + } | |
| 133 | + if (name == null) { | |
| 134 | + throw new NullPointerException(); | |
| 135 | + } | |
| 136 | + fd = new FileDescriptor(); | |
| 137 | + fd.incrementAndGetUseCount(); | |
| 138 | + open(name); | |
| 139 | + } | |
| 140 | + | |
| 141 | + /** | |
| 142 | + * Creates a <code>FileInputStream</code> by using the file descriptor | |
| 143 | + * <code>fdObj</code>, which represents an existing connection to an | |
| 144 | + * actual file in the file system. | |
| 145 | + * <p> | |
| 146 | + * If there is a security manager, its <code>checkRead</code> method is | |
| 147 | + * called with the file descriptor <code>fdObj</code> as its argument to | |
| 148 | + * see if it's ok to read the file descriptor. If read access is denied | |
| 149 | + * to the file descriptor a <code>SecurityException</code> is thrown. | |
| 150 | + * <p> | |
| 151 | + * If <code>fdObj</code> is null then a <code>NullPointerException</code> | |
| 152 | + * is thrown. | |
| 153 | + * <p> | |
| 154 | + * This constructor does not throw an exception if <code>fdObj</code> | |
| 155 | + * is {@link java.io.FileDescriptor#valid() invalid}. | |
| 156 | + * However, if the methods are invoked on the resulting stream to attempt | |
| 157 | + * I/O on the stream, an <code>IOException</code> is thrown. | |
| 158 | + * | |
| 159 | + * @param fdObj the file descriptor to be opened for reading. | |
| 160 | + * @throws SecurityException if a security manager exists and its | |
| 161 | + * <code>checkRead</code> method denies read access to the | |
| 162 | + * file descriptor. | |
| 163 | + * @see SecurityManager#checkRead(java.io.FileDescriptor) | |
| 164 | + */ | |
| 165 | + public FileInputStream(FileDescriptor fdObj) { | |
| 166 | + SecurityManager security = System.getSecurityManager(); | |
| 167 | + if (fdObj == null) { | |
| 168 | + throw new NullPointerException(); | |
| 169 | + } | |
| 170 | + if (security != null) { | |
| 171 | + security.checkRead(fdObj); | |
| 172 | + } | |
| 173 | + fd = fdObj; | |
| 174 | + | |
| 175 | + /* | |
| 176 | + * FileDescriptor is being shared by streams. | |
| 177 | + * Ensure that it's GC'ed only when all the streams/channels are done | |
| 178 | + * using it. | |
| 179 | + */ | |
| 180 | + fd.incrementAndGetUseCount(); | |
| 181 | + } | |
| 182 | + | |
| 183 | + /** | |
| 184 | + * Opens the specified file for reading. | |
| 185 | + * @param name the name of the file | |
| 186 | + */ | |
| 187 | + private native void open(String name) throws FileNotFoundException; | |
| 188 | + | |
| 189 | + /** | |
| 190 | + * Reads a byte of data from this input stream. This method blocks | |
| 191 | + * if no input is yet available. | |
| 192 | + * | |
| 193 | + * @return the next byte of data, or <code>-1</code> if the end of the | |
| 194 | + * file is reached. | |
| 195 | + * @exception IOException if an I/O error occurs. | |
| 196 | + */ | |
| 197 | + public native int read() throws IOException; | |
| 198 | + | |
| 199 | + /** | |
| 200 | + * Reads a subarray as a sequence of bytes. | |
| 201 | + * @param b the data to be written | |
| 202 | + * @param off the start offset in the data | |
| 203 | + * @param len the number of bytes that are written | |
| 204 | + * @exception IOException If an I/O error has occurred. | |
| 205 | + */ | |
| 206 | + private native int readBytes(byte b[], int off, int len) throws IOException; | |
| 207 | + | |
| 208 | + /** | |
| 209 | + * Reads up to <code>b.length</code> bytes of data from this input | |
| 210 | + * stream into an array of bytes. This method blocks until some input | |
| 211 | + * is available. | |
| 212 | + * | |
| 213 | + * @param b the buffer into which the data is read. | |
| 214 | + * @return the total number of bytes read into the buffer, or | |
| 215 | + * <code>-1</code> if there is no more data because the end of | |
| 216 | + * the file has been reached. | |
| 217 | + * @exception IOException if an I/O error occurs. | |
| 218 | + */ | |
| 219 | + public int read(byte b[]) throws IOException { | |
| 220 | + return readBytes(b, 0, b.length); | |
| 221 | + } | |
| 222 | + | |
| 223 | + /** | |
| 224 | + * Reads up to <code>len</code> bytes of data from this input stream | |
| 225 | + * into an array of bytes. If <code>len</code> is not zero, the method | |
| 226 | + * blocks until some input is available; otherwise, no | |
| 227 | + * bytes are read and <code>0</code> is returned. | |
| 228 | + * | |
| 229 | + * @param b the buffer into which the data is read. | |
| 230 | + * @param off the start offset in the destination array <code>b</code> | |
| 231 | + * @param len the maximum number of bytes read. | |
| 232 | + * @return the total number of bytes read into the buffer, or | |
| 233 | + * <code>-1</code> if there is no more data because the end of | |
| 234 | + * the file has been reached. | |
| 235 | + * @exception NullPointerException If <code>b</code> is <code>null</code>. | |
| 236 | + * @exception IndexOutOfBoundsException If <code>off</code> is negative, | |
| 237 | + * <code>len</code> is negative, or <code>len</code> is greater than | |
| 238 | + * <code>b.length - off</code> | |
| 239 | + * @exception IOException if an I/O error occurs. | |
| 240 | + */ | |
| 241 | + public int read(byte b[], int off, int len) throws IOException { | |
| 242 | + return readBytes(b, off, len); | |
| 243 | + } | |
| 244 | + | |
| 245 | + /** | |
| 246 | + * Skips over and discards <code>n</code> bytes of data from the | |
| 247 | + * input stream. | |
| 248 | + * | |
| 249 | + * <p>The <code>skip</code> method may, for a variety of | |
| 250 | + * reasons, end up skipping over some smaller number of bytes, | |
| 251 | + * possibly <code>0</code>. If <code>n</code> is negative, an | |
| 252 | + * <code>IOException</code> is thrown, even though the <code>skip</code> | |
| 253 | + * method of the {@link InputStream} superclass does nothing in this case. | |
| 254 | + * The actual number of bytes skipped is returned. | |
| 255 | + * | |
| 256 | + * <p>This method may skip more bytes than are remaining in the backing | |
| 257 | + * file. This produces no exception and the number of bytes skipped | |
| 258 | + * may include some number of bytes that were beyond the EOF of the | |
| 259 | + * backing file. Attempting to read from the stream after skipping past | |
| 260 | + * the end will result in -1 indicating the end of the file. | |
| 261 | + * | |
| 262 | + * @param n the number of bytes to be skipped. | |
| 263 | + * @return the actual number of bytes skipped. | |
| 264 | + * @exception IOException if n is negative, if the stream does not | |
| 265 | + * support seek, or if an I/O error occurs. | |
| 266 | + */ | |
| 267 | + public native long skip(long n) throws IOException; | |
| 268 | + | |
| 269 | + /** | |
| 270 | + * Returns an estimate of the number of remaining bytes that can be read (or | |
| 271 | + * skipped over) from this input stream without blocking by the next | |
| 272 | + * invocation of a method for this input stream. The next invocation might be | |
| 273 | + * the same thread or another thread. A single read or skip of this | |
| 274 | + * many bytes will not block, but may read or skip fewer bytes. | |
| 275 | + * | |
| 276 | + * <p> In some cases, a non-blocking read (or skip) may appear to be | |
| 277 | + * blocked when it is merely slow, for example when reading large | |
| 278 | + * files over slow networks. | |
| 279 | + * | |
| 280 | + * @return an estimate of the number of remaining bytes that can be read | |
| 281 | + * (or skipped over) from this input stream without blocking. | |
| 282 | + * @exception IOException if this file input stream has been closed by calling | |
| 283 | + * {@code close} or an I/O error occurs. | |
| 284 | + */ | |
| 285 | + public native int available() throws IOException; | |
| 286 | + | |
| 287 | + /** | |
| 288 | + * Closes this file input stream and releases any system resources | |
| 289 | + * associated with the stream. | |
| 290 | + * | |
| 291 | + * <p> If this stream has an associated channel then the channel is closed | |
| 292 | + * as well. | |
| 293 | + * | |
| 294 | + * @exception IOException if an I/O error occurs. | |
| 295 | + * | |
| 296 | + * @revised 1.4 | |
| 297 | + * @spec JSR-51 | |
| 298 | + */ | |
| 299 | + public void close() throws IOException { | |
| 300 | + synchronized (closeLock) { | |
| 301 | + if (closed) { | |
| 302 | + return; | |
| 303 | + } | |
| 304 | + closed = true; | |
| 305 | + } | |
| 306 | + if (channel != null) { | |
| 307 | + /* | |
| 308 | + * Decrement the FD use count associated with the channel | |
| 309 | + * The use count is incremented whenever a new channel | |
| 310 | + * is obtained from this stream. | |
| 311 | + */ | |
| 312 | + fd.decrementAndGetUseCount(); | |
| 313 | + channel.close(); | |
| 314 | + } | |
| 315 | + | |
| 316 | + /* | |
| 317 | + * Decrement the FD use count associated with this stream | |
| 318 | + */ | |
| 319 | + int useCount = fd.decrementAndGetUseCount(); | |
| 320 | + | |
| 321 | + /* | |
| 322 | + * If FileDescriptor is still in use by another stream, the finalizer | |
| 323 | + * will not close it. | |
| 324 | + */ | |
| 325 | + if ((useCount <= 0) || !isRunningFinalize()) { | |
| 326 | + close0(); | |
| 327 | + } | |
| 328 | + } | |
| 329 | + | |
| 330 | + /** | |
| 331 | + * Returns the <code>FileDescriptor</code> | |
| 332 | + * object that represents the connection to | |
| 333 | + * the actual file in the file system being | |
| 334 | + * used by this <code>FileInputStream</code>. | |
| 335 | + * | |
| 336 | + * @return the file descriptor object associated with this stream. | |
| 337 | + * @exception IOException if an I/O error occurs. | |
| 338 | + * @see java.io.FileDescriptor | |
| 339 | + */ | |
| 340 | + public final FileDescriptor getFD() throws IOException { | |
| 341 | + if (fd != null) return fd; | |
| 342 | + throw new IOException(); | |
| 343 | + } | |
| 344 | + | |
| 345 | + /** | |
| 346 | + * Returns the unique {@link java.nio.channels.FileChannel FileChannel} | |
| 347 | + * object associated with this file input stream. | |
| 348 | + * | |
| 349 | + * <p> The initial {@link java.nio.channels.FileChannel#position() | |
| 350 | + * </code>position<code>} of the returned channel will be equal to the | |
| 351 | + * number of bytes read from the file so far. Reading bytes from this | |
| 352 | + * stream will increment the channel's position. Changing the channel's | |
| 353 | + * position, either explicitly or by reading, will change this stream's | |
| 354 | + * file position. | |
| 355 | + * | |
| 356 | + * @return the file channel associated with this file input stream | |
| 357 | + * | |
| 358 | + * @since 1.4 | |
| 359 | + * @spec JSR-51 | |
| 360 | + */ | |
| 361 | + public FileChannel getChannel() { | |
| 362 | + synchronized (this) { | |
| 363 | + if (channel == null) { | |
| 364 | + channel = FileChannelImpl.open(fd, true, false, this); | |
| 365 | + | |
| 366 | + /* | |
| 367 | + * Increment fd's use count. Invoking the channel's close() | |
| 368 | + * method will result in decrementing the use count set for | |
| 369 | + * the channel. | |
| 370 | + */ | |
| 371 | + fd.incrementAndGetUseCount(); | |
| 372 | + } | |
| 373 | + return channel; | |
| 374 | + } | |
| 375 | + } | |
| 376 | + | |
| 377 | + private static native void initIDs(); | |
| 378 | + | |
| 379 | + private native void close0() throws IOException; | |
| 380 | + | |
| 381 | + static { | |
| 382 | + initIDs(); | |
| 383 | + } | |
| 384 | + | |
| 385 | + /** | |
| 386 | + * Ensures that the <code>close</code> method of this file input stream is | |
| 387 | + * called when there are no more references to it. | |
| 388 | + * | |
| 389 | + * @exception IOException if an I/O error occurs. | |
| 390 | + * @see java.io.FileInputStream#close() | |
| 391 | + */ | |
| 392 | + protected void finalize() throws IOException { | |
| 393 | + if ((fd != null) && (fd != FileDescriptor.in)) { | |
| 394 | + | |
| 395 | + /* | |
| 396 | + * Finalizer should not release the FileDescriptor if another | |
| 397 | + * stream is still using it. If the user directly invokes | |
| 398 | + * close() then the FileDescriptor is also released. | |
| 399 | + */ | |
| 400 | + runningFinalize.set(Boolean.TRUE); | |
| 401 | + try { | |
| 402 | + close(); | |
| 403 | + } finally { | |
| 404 | + runningFinalize.set(Boolean.FALSE); | |
| 405 | + } | |
| 406 | + } | |
| 407 | + } | |
| 408 | +} | |
Binary file not shown.
| @@ -0,0 +1,82 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * Signals that an attempt to open the file denoted by a specified pathname | |
| 31 | + * has failed. | |
| 32 | + * | |
| 33 | + * <p> This exception will be thrown by the {@link FileInputStream}, {@link | |
| 34 | + * FileOutputStream}, and {@link RandomAccessFile} constructors when a file | |
| 35 | + * with the specified pathname does not exist. It will also be thrown by these | |
| 36 | + * constructors if the file does exist but for some reason is inaccessible, for | |
| 37 | + * example when an attempt is made to open a read-only file for writing. | |
| 38 | + * | |
| 39 | + * @author unascribed | |
| 40 | + * @since JDK1.0 | |
| 41 | + */ | |
| 42 | + | |
| 43 | +public class FileNotFoundException extends IOException { | |
| 44 | + private static final long serialVersionUID = -897856973823710492L; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * Constructs a <code>FileNotFoundException</code> with | |
| 48 | + * <code>null</code> as its error detail message. | |
| 49 | + */ | |
| 50 | + public FileNotFoundException() { | |
| 51 | + super(); | |
| 52 | + } | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * Constructs a <code>FileNotFoundException</code> with the | |
| 56 | + * specified detail message. The string <code>s</code> can be | |
| 57 | + * retrieved later by the | |
| 58 | + * <code>{@link java.lang.Throwable#getMessage}</code> | |
| 59 | + * method of class <code>java.lang.Throwable</code>. | |
| 60 | + * | |
| 61 | + * @param s the detail message. | |
| 62 | + */ | |
| 63 | + public FileNotFoundException(String s) { | |
| 64 | + super(s); | |
| 65 | + } | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * Constructs a <code>FileNotFoundException</code> with a detail message | |
| 69 | + * consisting of the given pathname string followed by the given reason | |
| 70 | + * string. If the <code>reason</code> argument is <code>null</code> then | |
| 71 | + * it will be omitted. This private constructor is invoked only by native | |
| 72 | + * I/O methods. | |
| 73 | + * | |
| 74 | + * @since 1.2 | |
| 75 | + */ | |
| 76 | + private FileNotFoundException(String path, String reason) { | |
| 77 | + super(path + ((reason == null) | |
| 78 | + ? "" | |
| 79 | + : " (" + reason + ")")); | |
| 80 | + } | |
| 81 | + | |
| 82 | +} | |
Binary file not shown.
| @@ -0,0 +1,451 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.nio.channels.FileChannel; | |
| 29 | +import sun.nio.ch.FileChannelImpl; | |
| 30 | + | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * A file output stream is an output stream for writing data to a | |
| 34 | + * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not | |
| 35 | + * a file is available or may be created depends upon the underlying | |
| 36 | + * platform. Some platforms, in particular, allow a file to be opened | |
| 37 | + * for writing by only one <tt>FileOutputStream</tt> (or other | |
| 38 | + * file-writing object) at a time. In such situations the constructors in | |
| 39 | + * this class will fail if the file involved is already open. | |
| 40 | + * | |
| 41 | + * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes | |
| 42 | + * such as image data. For writing streams of characters, consider using | |
| 43 | + * <code>FileWriter</code>. | |
| 44 | + * | |
| 45 | + * @author Arthur van Hoff | |
| 46 | + * @see java.io.File | |
| 47 | + * @see java.io.FileDescriptor | |
| 48 | + * @see java.io.FileInputStream | |
| 49 | + * @see java.nio.file.Files#newOutputStream | |
| 50 | + * @since JDK1.0 | |
| 51 | + */ | |
| 52 | +public | |
| 53 | +class FileOutputStream extends OutputStream | |
| 54 | +{ | |
| 55 | + /** | |
| 56 | + * The system dependent file descriptor. | |
| 57 | + */ | |
| 58 | + private final FileDescriptor fd; | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * True if the file is opened for append. | |
| 62 | + */ | |
| 63 | + private final boolean append; | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * The associated channel, initalized lazily. | |
| 67 | + */ | |
| 68 | + private FileChannel channel; | |
| 69 | + | |
| 70 | + private final Object closeLock = new Object(); | |
| 71 | + private volatile boolean closed = false; | |
| 72 | + private static final ThreadLocal<Boolean> runningFinalize = | |
| 73 | + new ThreadLocal<>(); | |
| 74 | + | |
| 75 | + private static boolean isRunningFinalize() { | |
| 76 | + Boolean val; | |
| 77 | + if ((val = runningFinalize.get()) != null) | |
| 78 | + return val.booleanValue(); | |
| 79 | + return false; | |
| 80 | + } | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * Creates a file output stream to write to the file with the | |
| 84 | + * specified name. A new <code>FileDescriptor</code> object is | |
| 85 | + * created to represent this file connection. | |
| 86 | + * <p> | |
| 87 | + * First, if there is a security manager, its <code>checkWrite</code> | |
| 88 | + * method is called with <code>name</code> as its argument. | |
| 89 | + * <p> | |
| 90 | + * If the file exists but is a directory rather than a regular file, does | |
| 91 | + * not exist but cannot be created, or cannot be opened for any other | |
| 92 | + * reason then a <code>FileNotFoundException</code> is thrown. | |
| 93 | + * | |
| 94 | + * @param name the system-dependent filename | |
| 95 | + * @exception FileNotFoundException if the file exists but is a directory | |
| 96 | + * rather than a regular file, does not exist but cannot | |
| 97 | + * be created, or cannot be opened for any other reason | |
| 98 | + * @exception SecurityException if a security manager exists and its | |
| 99 | + * <code>checkWrite</code> method denies write access | |
| 100 | + * to the file. | |
| 101 | + * @see java.lang.SecurityManager#checkWrite(java.lang.String) | |
| 102 | + */ | |
| 103 | + public FileOutputStream(String name) throws FileNotFoundException { | |
| 104 | + this(name != null ? new File(name) : null, false); | |
| 105 | + } | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * Creates a file output stream to write to the file with the specified | |
| 109 | + * name. If the second argument is <code>true</code>, then | |
| 110 | + * bytes will be written to the end of the file rather than the beginning. | |
| 111 | + * A new <code>FileDescriptor</code> object is created to represent this | |
| 112 | + * file connection. | |
| 113 | + * <p> | |
| 114 | + * First, if there is a security manager, its <code>checkWrite</code> | |
| 115 | + * method is called with <code>name</code> as its argument. | |
| 116 | + * <p> | |
| 117 | + * If the file exists but is a directory rather than a regular file, does | |
| 118 | + * not exist but cannot be created, or cannot be opened for any other | |
| 119 | + * reason then a <code>FileNotFoundException</code> is thrown. | |
| 120 | + * | |
| 121 | + * @param name the system-dependent file name | |
| 122 | + * @param append if <code>true</code>, then bytes will be written | |
| 123 | + * to the end of the file rather than the beginning | |
| 124 | + * @exception FileNotFoundException if the file exists but is a directory | |
| 125 | + * rather than a regular file, does not exist but cannot | |
| 126 | + * be created, or cannot be opened for any other reason. | |
| 127 | + * @exception SecurityException if a security manager exists and its | |
| 128 | + * <code>checkWrite</code> method denies write access | |
| 129 | + * to the file. | |
| 130 | + * @see java.lang.SecurityManager#checkWrite(java.lang.String) | |
| 131 | + * @since JDK1.1 | |
| 132 | + */ | |
| 133 | + public FileOutputStream(String name, boolean append) | |
| 134 | + throws FileNotFoundException | |
| 135 | + { | |
| 136 | + this(name != null ? new File(name) : null, append); | |
| 137 | + } | |
| 138 | + | |
| 139 | + /** | |
| 140 | + * Creates a file output stream to write to the file represented by | |
| 141 | + * the specified <code>File</code> object. A new | |
| 142 | + * <code>FileDescriptor</code> object is created to represent this | |
| 143 | + * file connection. | |
| 144 | + * <p> | |
| 145 | + * First, if there is a security manager, its <code>checkWrite</code> | |
| 146 | + * method is called with the path represented by the <code>file</code> | |
| 147 | + * argument as its argument. | |
| 148 | + * <p> | |
| 149 | + * If the file exists but is a directory rather than a regular file, does | |
| 150 | + * not exist but cannot be created, or cannot be opened for any other | |
| 151 | + * reason then a <code>FileNotFoundException</code> is thrown. | |
| 152 | + * | |
| 153 | + * @param file the file to be opened for writing. | |
| 154 | + * @exception FileNotFoundException if the file exists but is a directory | |
| 155 | + * rather than a regular file, does not exist but cannot | |
| 156 | + * be created, or cannot be opened for any other reason | |
| 157 | + * @exception SecurityException if a security manager exists and its | |
| 158 | + * <code>checkWrite</code> method denies write access | |
| 159 | + * to the file. | |
| 160 | + * @see java.io.File#getPath() | |
| 161 | + * @see java.lang.SecurityException | |
| 162 | + * @see java.lang.SecurityManager#checkWrite(java.lang.String) | |
| 163 | + */ | |
| 164 | + public FileOutputStream(File file) throws FileNotFoundException { | |
| 165 | + this(file, false); | |
| 166 | + } | |
| 167 | + | |
| 168 | + /** | |
| 169 | + * Creates a file output stream to write to the file represented by | |
| 170 | + * the specified <code>File</code> object. If the second argument is | |
| 171 | + * <code>true</code>, then bytes will be written to the end of the file | |
| 172 | + * rather than the beginning. A new <code>FileDescriptor</code> object is | |
| 173 | + * created to represent this file connection. | |
| 174 | + * <p> | |
| 175 | + * First, if there is a security manager, its <code>checkWrite</code> | |
| 176 | + * method is called with the path represented by the <code>file</code> | |
| 177 | + * argument as its argument. | |
| 178 | + * <p> | |
| 179 | + * If the file exists but is a directory rather than a regular file, does | |
| 180 | + * not exist but cannot be created, or cannot be opened for any other | |
| 181 | + * reason then a <code>FileNotFoundException</code> is thrown. | |
| 182 | + * | |
| 183 | + * @param file the file to be opened for writing. | |
| 184 | + * @param append if <code>true</code>, then bytes will be written | |
| 185 | + * to the end of the file rather than the beginning | |
| 186 | + * @exception FileNotFoundException if the file exists but is a directory | |
| 187 | + * rather than a regular file, does not exist but cannot | |
| 188 | + * be created, or cannot be opened for any other reason | |
| 189 | + * @exception SecurityException if a security manager exists and its | |
| 190 | + * <code>checkWrite</code> method denies write access | |
| 191 | + * to the file. | |
| 192 | + * @see java.io.File#getPath() | |
| 193 | + * @see java.lang.SecurityException | |
| 194 | + * @see java.lang.SecurityManager#checkWrite(java.lang.String) | |
| 195 | + * @since 1.4 | |
| 196 | + */ | |
| 197 | + public FileOutputStream(File file, boolean append) | |
| 198 | + throws FileNotFoundException | |
| 199 | + { | |
| 200 | + String name = (file != null ? file.getPath() : null); | |
| 201 | + SecurityManager security = System.getSecurityManager(); | |
| 202 | + if (security != null) { | |
| 203 | + security.checkWrite(name); | |
| 204 | + } | |
| 205 | + if (name == null) { | |
| 206 | + throw new NullPointerException(); | |
| 207 | + } | |
| 208 | + this.fd = new FileDescriptor(); | |
| 209 | + this.append = append; | |
| 210 | + | |
| 211 | + fd.incrementAndGetUseCount(); | |
| 212 | + open(name, append); | |
| 213 | + } | |
| 214 | + | |
| 215 | + /** | |
| 216 | + * Creates a file output stream to write to the specified file | |
| 217 | + * descriptor, which represents an existing connection to an actual | |
| 218 | + * file in the file system. | |
| 219 | + * <p> | |
| 220 | + * First, if there is a security manager, its <code>checkWrite</code> | |
| 221 | + * method is called with the file descriptor <code>fdObj</code> | |
| 222 | + * argument as its argument. | |
| 223 | + * <p> | |
| 224 | + * If <code>fdObj</code> is null then a <code>NullPointerException</code> | |
| 225 | + * is thrown. | |
| 226 | + * <p> | |
| 227 | + * This constructor does not throw an exception if <code>fdObj</code> | |
| 228 | + * is {@link java.io.FileDescriptor#valid() invalid}. | |
| 229 | + * However, if the methods are invoked on the resulting stream to attempt | |
| 230 | + * I/O on the stream, an <code>IOException</code> is thrown. | |
| 231 | + * | |
| 232 | + * @param fdObj the file descriptor to be opened for writing | |
| 233 | + * @exception SecurityException if a security manager exists and its | |
| 234 | + * <code>checkWrite</code> method denies | |
| 235 | + * write access to the file descriptor | |
| 236 | + * @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor) | |
| 237 | + */ | |
| 238 | + public FileOutputStream(FileDescriptor fdObj) { | |
| 239 | + SecurityManager security = System.getSecurityManager(); | |
| 240 | + if (fdObj == null) { | |
| 241 | + throw new NullPointerException(); | |
| 242 | + } | |
| 243 | + if (security != null) { | |
| 244 | + security.checkWrite(fdObj); | |
| 245 | + } | |
| 246 | + this.fd = fdObj; | |
| 247 | + this.append = false; | |
| 248 | + | |
| 249 | + /* | |
| 250 | + * FileDescriptor is being shared by streams. | |
| 251 | + * Ensure that it's GC'ed only when all the streams/channels are done | |
| 252 | + * using it. | |
| 253 | + */ | |
| 254 | + fd.incrementAndGetUseCount(); | |
| 255 | + } | |
| 256 | + | |
| 257 | + /** | |
| 258 | + * Opens a file, with the specified name, for overwriting or appending. | |
| 259 | + * @param name name of file to be opened | |
| 260 | + * @param append whether the file is to be opened in append mode | |
| 261 | + */ | |
| 262 | + private native void open(String name, boolean append) | |
| 263 | + throws FileNotFoundException; | |
| 264 | + | |
| 265 | + /** | |
| 266 | + * Writes the specified byte to this file output stream. | |
| 267 | + * | |
| 268 | + * @param b the byte to be written. | |
| 269 | + * @param append {@code true} if the write operation first | |
| 270 | + * advances the position to the end of file | |
| 271 | + */ | |
| 272 | + private native void write(int b, boolean append) throws IOException; | |
| 273 | + | |
| 274 | + /** | |
| 275 | + * Writes the specified byte to this file output stream. Implements | |
| 276 | + * the <code>write</code> method of <code>OutputStream</code>. | |
| 277 | + * | |
| 278 | + * @param b the byte to be written. | |
| 279 | + * @exception IOException if an I/O error occurs. | |
| 280 | + */ | |
| 281 | + public void write(int b) throws IOException { | |
| 282 | + write(b, append); | |
| 283 | + } | |
| 284 | + | |
| 285 | + /** | |
| 286 | + * Writes a sub array as a sequence of bytes. | |
| 287 | + * @param b the data to be written | |
| 288 | + * @param off the start offset in the data | |
| 289 | + * @param len the number of bytes that are written | |
| 290 | + * @param append {@code true} to first advance the position to the | |
| 291 | + * end of file | |
| 292 | + * @exception IOException If an I/O error has occurred. | |
| 293 | + */ | |
| 294 | + private native void writeBytes(byte b[], int off, int len, boolean append) | |
| 295 | + throws IOException; | |
| 296 | + | |
| 297 | + /** | |
| 298 | + * Writes <code>b.length</code> bytes from the specified byte array | |
| 299 | + * to this file output stream. | |
| 300 | + * | |
| 301 | + * @param b the data. | |
| 302 | + * @exception IOException if an I/O error occurs. | |
| 303 | + */ | |
| 304 | + public void write(byte b[]) throws IOException { | |
| 305 | + writeBytes(b, 0, b.length, append); | |
| 306 | + } | |
| 307 | + | |
| 308 | + /** | |
| 309 | + * Writes <code>len</code> bytes from the specified byte array | |
| 310 | + * starting at offset <code>off</code> to this file output stream. | |
| 311 | + * | |
| 312 | + * @param b the data. | |
| 313 | + * @param off the start offset in the data. | |
| 314 | + * @param len the number of bytes to write. | |
| 315 | + * @exception IOException if an I/O error occurs. | |
| 316 | + */ | |
| 317 | + public void write(byte b[], int off, int len) throws IOException { | |
| 318 | + writeBytes(b, off, len, append); | |
| 319 | + } | |
| 320 | + | |
| 321 | + /** | |
| 322 | + * Closes this file output stream and releases any system resources | |
| 323 | + * associated with this stream. This file output stream may no longer | |
| 324 | + * be used for writing bytes. | |
| 325 | + * | |
| 326 | + * <p> If this stream has an associated channel then the channel is closed | |
| 327 | + * as well. | |
| 328 | + * | |
| 329 | + * @exception IOException if an I/O error occurs. | |
| 330 | + * | |
| 331 | + * @revised 1.4 | |
| 332 | + * @spec JSR-51 | |
| 333 | + */ | |
| 334 | + public void close() throws IOException { | |
| 335 | + synchronized (closeLock) { | |
| 336 | + if (closed) { | |
| 337 | + return; | |
| 338 | + } | |
| 339 | + closed = true; | |
| 340 | + } | |
| 341 | + | |
| 342 | + if (channel != null) { | |
| 343 | + /* | |
| 344 | + * Decrement FD use count associated with the channel | |
| 345 | + * The use count is incremented whenever a new channel | |
| 346 | + * is obtained from this stream. | |
| 347 | + */ | |
| 348 | + fd.decrementAndGetUseCount(); | |
| 349 | + channel.close(); | |
| 350 | + } | |
| 351 | + | |
| 352 | + /* | |
| 353 | + * Decrement FD use count associated with this stream | |
| 354 | + */ | |
| 355 | + int useCount = fd.decrementAndGetUseCount(); | |
| 356 | + | |
| 357 | + /* | |
| 358 | + * If FileDescriptor is still in use by another stream, the finalizer | |
| 359 | + * will not close it. | |
| 360 | + */ | |
| 361 | + if ((useCount <= 0) || !isRunningFinalize()) { | |
| 362 | + close0(); | |
| 363 | + } | |
| 364 | + } | |
| 365 | + | |
| 366 | + /** | |
| 367 | + * Returns the file descriptor associated with this stream. | |
| 368 | + * | |
| 369 | + * @return the <code>FileDescriptor</code> object that represents | |
| 370 | + * the connection to the file in the file system being used | |
| 371 | + * by this <code>FileOutputStream</code> object. | |
| 372 | + * | |
| 373 | + * @exception IOException if an I/O error occurs. | |
| 374 | + * @see java.io.FileDescriptor | |
| 375 | + */ | |
| 376 | + public final FileDescriptor getFD() throws IOException { | |
| 377 | + if (fd != null) return fd; | |
| 378 | + throw new IOException(); | |
| 379 | + } | |
| 380 | + | |
| 381 | + /** | |
| 382 | + * Returns the unique {@link java.nio.channels.FileChannel FileChannel} | |
| 383 | + * object associated with this file output stream. </p> | |
| 384 | + * | |
| 385 | + * <p> The initial {@link java.nio.channels.FileChannel#position() | |
| 386 | + * </code>position<code>} of the returned channel will be equal to the | |
| 387 | + * number of bytes written to the file so far unless this stream is in | |
| 388 | + * append mode, in which case it will be equal to the size of the file. | |
| 389 | + * Writing bytes to this stream will increment the channel's position | |
| 390 | + * accordingly. Changing the channel's position, either explicitly or by | |
| 391 | + * writing, will change this stream's file position. | |
| 392 | + * | |
| 393 | + * @return the file channel associated with this file output stream | |
| 394 | + * | |
| 395 | + * @since 1.4 | |
| 396 | + * @spec JSR-51 | |
| 397 | + */ | |
| 398 | + public FileChannel getChannel() { | |
| 399 | + synchronized (this) { | |
| 400 | + if (channel == null) { | |
| 401 | + channel = FileChannelImpl.open(fd, false, true, append, this); | |
| 402 | + | |
| 403 | + /* | |
| 404 | + * Increment fd's use count. Invoking the channel's close() | |
| 405 | + * method will result in decrementing the use count set for | |
| 406 | + * the channel. | |
| 407 | + */ | |
| 408 | + fd.incrementAndGetUseCount(); | |
| 409 | + } | |
| 410 | + return channel; | |
| 411 | + } | |
| 412 | + } | |
| 413 | + | |
| 414 | + /** | |
| 415 | + * Cleans up the connection to the file, and ensures that the | |
| 416 | + * <code>close</code> method of this file output stream is | |
| 417 | + * called when there are no more references to this stream. | |
| 418 | + * | |
| 419 | + * @exception IOException if an I/O error occurs. | |
| 420 | + * @see java.io.FileInputStream#close() | |
| 421 | + */ | |
| 422 | + protected void finalize() throws IOException { | |
| 423 | + if (fd != null) { | |
| 424 | + if (fd == FileDescriptor.out || fd == FileDescriptor.err) { | |
| 425 | + flush(); | |
| 426 | + } else { | |
| 427 | + | |
| 428 | + /* | |
| 429 | + * Finalizer should not release the FileDescriptor if another | |
| 430 | + * stream is still using it. If the user directly invokes | |
| 431 | + * close() then the FileDescriptor is also released. | |
| 432 | + */ | |
| 433 | + runningFinalize.set(Boolean.TRUE); | |
| 434 | + try { | |
| 435 | + close(); | |
| 436 | + } finally { | |
| 437 | + runningFinalize.set(Boolean.FALSE); | |
| 438 | + } | |
| 439 | + } | |
| 440 | + } | |
| 441 | + } | |
| 442 | + | |
| 443 | + private native void close0() throws IOException; | |
| 444 | + | |
| 445 | + private static native void initIDs(); | |
| 446 | + | |
| 447 | + static { | |
| 448 | + initIDs(); | |
| 449 | + } | |
| 450 | + | |
| 451 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,859 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.security.*; | |
| 29 | +import java.util.Enumeration; | |
| 30 | +import java.util.List; | |
| 31 | +import java.util.ArrayList; | |
| 32 | +import java.util.Vector; | |
| 33 | +import java.util.Collections; | |
| 34 | +import java.io.ObjectStreamField; | |
| 35 | +import java.io.ObjectOutputStream; | |
| 36 | +import java.io.ObjectInputStream; | |
| 37 | +import java.io.IOException; | |
| 38 | +import sun.security.util.SecurityConstants; | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * This class represents access to a file or directory. A FilePermission consists | |
| 42 | + * of a pathname and a set of actions valid for that pathname. | |
| 43 | + * <P> | |
| 44 | + * Pathname is the pathname of the file or directory granted the specified | |
| 45 | + * actions. A pathname that ends in "/*" (where "/" is | |
| 46 | + * the file separator character, <code>File.separatorChar</code>) indicates | |
| 47 | + * all the files and directories contained in that directory. A pathname | |
| 48 | + * that ends with "/-" indicates (recursively) all files | |
| 49 | + * and subdirectories contained in that directory. A pathname consisting of | |
| 50 | + * the special token "<<ALL FILES>>" matches <b>any</b> file. | |
| 51 | + * <P> | |
| 52 | + * Note: A pathname consisting of a single "*" indicates all the files | |
| 53 | + * in the current directory, while a pathname consisting of a single "-" | |
| 54 | + * indicates all the files in the current directory and | |
| 55 | + * (recursively) all files and subdirectories contained in the current | |
| 56 | + * directory. | |
| 57 | + * <P> | |
| 58 | + * The actions to be granted are passed to the constructor in a string containing | |
| 59 | + * a list of one or more comma-separated keywords. The possible keywords are | |
| 60 | + * "read", "write", "execute", "delete", and "readlink". Their meaning is | |
| 61 | + * defined as follows: | |
| 62 | + * <P> | |
| 63 | + * <DL> | |
| 64 | + * <DT> read <DD> read permission | |
| 65 | + * <DT> write <DD> write permission | |
| 66 | + * <DT> execute | |
| 67 | + * <DD> execute permission. Allows <code>Runtime.exec</code> to | |
| 68 | + * be called. Corresponds to <code>SecurityManager.checkExec</code>. | |
| 69 | + * <DT> delete | |
| 70 | + * <DD> delete permission. Allows <code>File.delete</code> to | |
| 71 | + * be called. Corresponds to <code>SecurityManager.checkDelete</code>. | |
| 72 | + * <DT> readlink | |
| 73 | + * <DD> read link permission. Allows the target of a | |
| 74 | + * <a href="../nio/file/package-summary.html#links">symbolic link</a> | |
| 75 | + * to be read by invoking the {@link java.nio.file.Files#readSymbolicLink | |
| 76 | + * readSymbolicLink } method. | |
| 77 | + * </DL> | |
| 78 | + * <P> | |
| 79 | + * The actions string is converted to lowercase before processing. | |
| 80 | + * <P> | |
| 81 | + * Be careful when granting FilePermissions. Think about the implications | |
| 82 | + * of granting read and especially write access to various files and | |
| 83 | + * directories. The "<<ALL FILES>>" permission with write action is | |
| 84 | + * especially dangerous. This grants permission to write to the entire | |
| 85 | + * file system. One thing this effectively allows is replacement of the | |
| 86 | + * system binary, including the JVM runtime environment. | |
| 87 | + * | |
| 88 | + * <p>Please note: Code can always read a file from the same | |
| 89 | + * directory it's in (or a subdirectory of that directory); it does not | |
| 90 | + * need explicit permission to do so. | |
| 91 | + * | |
| 92 | + * @see java.security.Permission | |
| 93 | + * @see java.security.Permissions | |
| 94 | + * @see java.security.PermissionCollection | |
| 95 | + * | |
| 96 | + * | |
| 97 | + * @author Marianne Mueller | |
| 98 | + * @author Roland Schemers | |
| 99 | + * @since 1.2 | |
| 100 | + * | |
| 101 | + * @serial exclude | |
| 102 | + */ | |
| 103 | + | |
| 104 | +public final class FilePermission extends Permission implements Serializable { | |
| 105 | + | |
| 106 | + /** | |
| 107 | + * Execute action. | |
| 108 | + */ | |
| 109 | + private final static int EXECUTE = 0x1; | |
| 110 | + /** | |
| 111 | + * Write action. | |
| 112 | + */ | |
| 113 | + private final static int WRITE = 0x2; | |
| 114 | + /** | |
| 115 | + * Read action. | |
| 116 | + */ | |
| 117 | + private final static int READ = 0x4; | |
| 118 | + /** | |
| 119 | + * Delete action. | |
| 120 | + */ | |
| 121 | + private final static int DELETE = 0x8; | |
| 122 | + /** | |
| 123 | + * Read link action. | |
| 124 | + */ | |
| 125 | + private final static int READLINK = 0x10; | |
| 126 | + | |
| 127 | + /** | |
| 128 | + * All actions (read,write,execute,delete,readlink) | |
| 129 | + */ | |
| 130 | + private final static int ALL = READ|WRITE|EXECUTE|DELETE|READLINK; | |
| 131 | + /** | |
| 132 | + * No actions. | |
| 133 | + */ | |
| 134 | + private final static int NONE = 0x0; | |
| 135 | + | |
| 136 | + // the actions mask | |
| 137 | + private transient int mask; | |
| 138 | + | |
| 139 | + // does path indicate a directory? (wildcard or recursive) | |
| 140 | + private transient boolean directory; | |
| 141 | + | |
| 142 | + // is it a recursive directory specification? | |
| 143 | + private transient boolean recursive; | |
| 144 | + | |
| 145 | + /** | |
| 146 | + * the actions string. | |
| 147 | + * | |
| 148 | + * @serial | |
| 149 | + */ | |
| 150 | + private String actions; // Left null as long as possible, then | |
| 151 | + // created and re-used in the getAction function. | |
| 152 | + | |
| 153 | + // canonicalized dir path. In the case of | |
| 154 | + // directories, it is the name "/blah/*" or "/blah/-" without | |
| 155 | + // the last character (the "*" or "-"). | |
| 156 | + | |
| 157 | + private transient String cpath; | |
| 158 | + | |
| 159 | + // static Strings used by init(int mask) | |
| 160 | + private static final char RECURSIVE_CHAR = '-'; | |
| 161 | + private static final char WILD_CHAR = '*'; | |
| 162 | + | |
| 163 | +/* | |
| 164 | + public String toString() | |
| 165 | + { | |
| 166 | + StringBuffer sb = new StringBuffer(); | |
| 167 | + sb.append("***\n"); | |
| 168 | + sb.append("cpath = "+cpath+"\n"); | |
| 169 | + sb.append("mask = "+mask+"\n"); | |
| 170 | + sb.append("actions = "+getActions()+"\n"); | |
| 171 | + sb.append("directory = "+directory+"\n"); | |
| 172 | + sb.append("recursive = "+recursive+"\n"); | |
| 173 | + sb.append("***\n"); | |
| 174 | + return sb.toString(); | |
| 175 | + } | |
| 176 | +*/ | |
| 177 | + | |
| 178 | + private static final long serialVersionUID = 7930732926638008763L; | |
| 179 | + | |
| 180 | + /** | |
| 181 | + * initialize a FilePermission object. Common to all constructors. | |
| 182 | + * Also called during de-serialization. | |
| 183 | + * | |
| 184 | + * @param mask the actions mask to use. | |
| 185 | + * | |
| 186 | + */ | |
| 187 | + private void init(int mask) | |
| 188 | + { | |
| 189 | + | |
| 190 | + if ((mask & ALL) != mask) | |
| 191 | + throw new IllegalArgumentException("invalid actions mask"); | |
| 192 | + | |
| 193 | + if (mask == NONE) | |
| 194 | + throw new IllegalArgumentException("invalid actions mask"); | |
| 195 | + | |
| 196 | + if ((cpath = getName()) == null) | |
| 197 | + throw new NullPointerException("name can't be null"); | |
| 198 | + | |
| 199 | + this.mask = mask; | |
| 200 | + | |
| 201 | + if (cpath.equals("<<ALL FILES>>")) { | |
| 202 | + directory = true; | |
| 203 | + recursive = true; | |
| 204 | + cpath = ""; | |
| 205 | + return; | |
| 206 | + } | |
| 207 | + | |
| 208 | + // store only the canonical cpath if possible | |
| 209 | + cpath = AccessController.doPrivileged(new PrivilegedAction<String>() { | |
| 210 | + public String run() { | |
| 211 | + try { | |
| 212 | + String path = cpath; | |
| 213 | + if (cpath.endsWith("*")) { | |
| 214 | + // call getCanonicalPath with a path with wildcard character | |
| 215 | + // replaced to avoid calling it with paths that are | |
| 216 | + // intended to match all entries in a directory | |
| 217 | + path = path.substring(0, path.length()-1) + "-"; | |
| 218 | + path = new File(path).getCanonicalPath(); | |
| 219 | + return path.substring(0, path.length()-1) + "*"; | |
| 220 | + } else { | |
| 221 | + return new File(path).getCanonicalPath(); | |
| 222 | + } | |
| 223 | + } catch (IOException ioe) { | |
| 224 | + return cpath; | |
| 225 | + } | |
| 226 | + } | |
| 227 | + }); | |
| 228 | + | |
| 229 | + int len = cpath.length(); | |
| 230 | + char last = ((len > 0) ? cpath.charAt(len - 1) : 0); | |
| 231 | + | |
| 232 | + if (last == RECURSIVE_CHAR && | |
| 233 | + cpath.charAt(len - 2) == File.separatorChar) { | |
| 234 | + directory = true; | |
| 235 | + recursive = true; | |
| 236 | + cpath = cpath.substring(0, --len); | |
| 237 | + } else if (last == WILD_CHAR && | |
| 238 | + cpath.charAt(len - 2) == File.separatorChar) { | |
| 239 | + directory = true; | |
| 240 | + //recursive = false; | |
| 241 | + cpath = cpath.substring(0, --len); | |
| 242 | + } else { | |
| 243 | + // overkill since they are initialized to false, but | |
| 244 | + // commented out here to remind us... | |
| 245 | + //directory = false; | |
| 246 | + //recursive = false; | |
| 247 | + } | |
| 248 | + | |
| 249 | + // XXX: at this point the path should be absolute. die if it isn't? | |
| 250 | + } | |
| 251 | + | |
| 252 | + /** | |
| 253 | + * Creates a new FilePermission object with the specified actions. | |
| 254 | + * <i>path</i> is the pathname of a file or directory, and <i>actions</i> | |
| 255 | + * contains a comma-separated list of the desired actions granted on the | |
| 256 | + * file or directory. Possible actions are | |
| 257 | + * "read", "write", "execute", "delete", and "readlink". | |
| 258 | + * | |
| 259 | + * <p>A pathname that ends in "/*" (where "/" is | |
| 260 | + * the file separator character, <code>File.separatorChar</code>) | |
| 261 | + * indicates all the files and directories contained in that directory. | |
| 262 | + * A pathname that ends with "/-" indicates (recursively) all files and | |
| 263 | + * subdirectories contained in that directory. The special pathname | |
| 264 | + * "<<ALL FILES>>" matches any file. | |
| 265 | + * | |
| 266 | + * <p>A pathname consisting of a single "*" indicates all the files | |
| 267 | + * in the current directory, while a pathname consisting of a single "-" | |
| 268 | + * indicates all the files in the current directory and | |
| 269 | + * (recursively) all files and subdirectories contained in the current | |
| 270 | + * directory. | |
| 271 | + * | |
| 272 | + * <p>A pathname containing an empty string represents an empty path. | |
| 273 | + * | |
| 274 | + * @param path the pathname of the file/directory. | |
| 275 | + * @param actions the action string. | |
| 276 | + * | |
| 277 | + * @throws IllegalArgumentException | |
| 278 | + * If actions is <code>null</code>, empty or contains an action | |
| 279 | + * other than the specified possible actions. | |
| 280 | + */ | |
| 281 | + | |
| 282 | + public FilePermission(String path, String actions) | |
| 283 | + { | |
| 284 | + super(path); | |
| 285 | + init(getMask(actions)); | |
| 286 | + } | |
| 287 | + | |
| 288 | + /** | |
| 289 | + * Creates a new FilePermission object using an action mask. | |
| 290 | + * More efficient than the FilePermission(String, String) constructor. | |
| 291 | + * Can be used from within | |
| 292 | + * code that needs to create a FilePermission object to pass into the | |
| 293 | + * <code>implies</code> method. | |
| 294 | + * | |
| 295 | + * @param path the pathname of the file/directory. | |
| 296 | + * @param mask the action mask to use. | |
| 297 | + */ | |
| 298 | + | |
| 299 | + // package private for use by the FilePermissionCollection add method | |
| 300 | + FilePermission(String path, int mask) | |
| 301 | + { | |
| 302 | + super(path); | |
| 303 | + init(mask); | |
| 304 | + } | |
| 305 | + | |
| 306 | + /** | |
| 307 | + * Checks if this FilePermission object "implies" the specified permission. | |
| 308 | + * <P> | |
| 309 | + * More specifically, this method returns true if:<p> | |
| 310 | + * <ul> | |
| 311 | + * <li> <i>p</i> is an instanceof FilePermission,<p> | |
| 312 | + * <li> <i>p</i>'s actions are a proper subset of this | |
| 313 | + * object's actions, and <p> | |
| 314 | + * <li> <i>p</i>'s pathname is implied by this object's | |
| 315 | + * pathname. For example, "/tmp/*" implies "/tmp/foo", since | |
| 316 | + * "/tmp/*" encompasses all files in the "/tmp" directory, | |
| 317 | + * including the one named "foo". | |
| 318 | + * </ul> | |
| 319 | + * | |
| 320 | + * @param p the permission to check against. | |
| 321 | + * | |
| 322 | + * @return <code>true</code> if the specified permission is not | |
| 323 | + * <code>null</code> and is implied by this object, | |
| 324 | + * <code>false</code> otherwise. | |
| 325 | + */ | |
| 326 | + public boolean implies(Permission p) { | |
| 327 | + if (!(p instanceof FilePermission)) | |
| 328 | + return false; | |
| 329 | + | |
| 330 | + FilePermission that = (FilePermission) p; | |
| 331 | + | |
| 332 | + // we get the effective mask. i.e., the "and" of this and that. | |
| 333 | + // They must be equal to that.mask for implies to return true. | |
| 334 | + | |
| 335 | + return ((this.mask & that.mask) == that.mask) && impliesIgnoreMask(that); | |
| 336 | + } | |
| 337 | + | |
| 338 | + /** | |
| 339 | + * Checks if the Permission's actions are a proper subset of the | |
| 340 | + * this object's actions. Returns the effective mask iff the | |
| 341 | + * this FilePermission's path also implies that FilePermission's path. | |
| 342 | + * | |
| 343 | + * @param that the FilePermission to check against. | |
| 344 | + * @param exact return immediately if the masks are not equal | |
| 345 | + * @return the effective mask | |
| 346 | + */ | |
| 347 | + boolean impliesIgnoreMask(FilePermission that) { | |
| 348 | + if (this.directory) { | |
| 349 | + if (this.recursive) { | |
| 350 | + // make sure that.path is longer then path so | |
| 351 | + // something like /foo/- does not imply /foo | |
| 352 | + if (that.directory) { | |
| 353 | + return (that.cpath.length() >= this.cpath.length()) && | |
| 354 | + that.cpath.startsWith(this.cpath); | |
| 355 | + } else { | |
| 356 | + return ((that.cpath.length() > this.cpath.length()) && | |
| 357 | + that.cpath.startsWith(this.cpath)); | |
| 358 | + } | |
| 359 | + } else { | |
| 360 | + if (that.directory) { | |
| 361 | + // if the permission passed in is a directory | |
| 362 | + // specification, make sure that a non-recursive | |
| 363 | + // permission (i.e., this object) can't imply a recursive | |
| 364 | + // permission. | |
| 365 | + if (that.recursive) | |
| 366 | + return false; | |
| 367 | + else | |
| 368 | + return (this.cpath.equals(that.cpath)); | |
| 369 | + } else { | |
| 370 | + int last = that.cpath.lastIndexOf(File.separatorChar); | |
| 371 | + if (last == -1) | |
| 372 | + return false; | |
| 373 | + else { | |
| 374 | + // this.cpath.equals(that.cpath.substring(0, last+1)); | |
| 375 | + // Use regionMatches to avoid creating new string | |
| 376 | + return (this.cpath.length() == (last + 1)) && | |
| 377 | + this.cpath.regionMatches(0, that.cpath, 0, last+1); | |
| 378 | + } | |
| 379 | + } | |
| 380 | + } | |
| 381 | + } else if (that.directory) { | |
| 382 | + // if this is NOT recursive/wildcarded, | |
| 383 | + // do not let it imply a recursive/wildcarded permission | |
| 384 | + return false; | |
| 385 | + } else { | |
| 386 | + return (this.cpath.equals(that.cpath)); | |
| 387 | + } | |
| 388 | + } | |
| 389 | + | |
| 390 | + /** | |
| 391 | + * Checks two FilePermission objects for equality. Checks that <i>obj</i> is | |
| 392 | + * a FilePermission, and has the same pathname and actions as this object. | |
| 393 | + * <P> | |
| 394 | + * @param obj the object we are testing for equality with this object. | |
| 395 | + * @return <code>true</code> if obj is a FilePermission, and has the same | |
| 396 | + * pathname and actions as this FilePermission object, | |
| 397 | + * <code>false</code> otherwise. | |
| 398 | + */ | |
| 399 | + public boolean equals(Object obj) { | |
| 400 | + if (obj == this) | |
| 401 | + return true; | |
| 402 | + | |
| 403 | + if (! (obj instanceof FilePermission)) | |
| 404 | + return false; | |
| 405 | + | |
| 406 | + FilePermission that = (FilePermission) obj; | |
| 407 | + | |
| 408 | + return (this.mask == that.mask) && | |
| 409 | + this.cpath.equals(that.cpath) && | |
| 410 | + (this.directory == that.directory) && | |
| 411 | + (this.recursive == that.recursive); | |
| 412 | + } | |
| 413 | + | |
| 414 | + /** | |
| 415 | + * Returns the hash code value for this object. | |
| 416 | + * | |
| 417 | + * @return a hash code value for this object. | |
| 418 | + */ | |
| 419 | + | |
| 420 | + public int hashCode() { | |
| 421 | + return this.cpath.hashCode(); | |
| 422 | + } | |
| 423 | + | |
| 424 | + /** | |
| 425 | + * Converts an actions String to an actions mask. | |
| 426 | + * | |
| 427 | + * @param action the action string. | |
| 428 | + * @return the actions mask. | |
| 429 | + */ | |
| 430 | + private static int getMask(String actions) { | |
| 431 | + | |
| 432 | + int mask = NONE; | |
| 433 | + | |
| 434 | + // Null action valid? | |
| 435 | + if (actions == null) { | |
| 436 | + return mask; | |
| 437 | + } | |
| 438 | + // Check against use of constants (used heavily within the JDK) | |
| 439 | + if (actions == SecurityConstants.FILE_READ_ACTION) { | |
| 440 | + return READ; | |
| 441 | + } else if (actions == SecurityConstants.FILE_WRITE_ACTION) { | |
| 442 | + return WRITE; | |
| 443 | + } else if (actions == SecurityConstants.FILE_EXECUTE_ACTION) { | |
| 444 | + return EXECUTE; | |
| 445 | + } else if (actions == SecurityConstants.FILE_DELETE_ACTION) { | |
| 446 | + return DELETE; | |
| 447 | + } else if (actions == SecurityConstants.FILE_READLINK_ACTION) { | |
| 448 | + return READLINK; | |
| 449 | + } | |
| 450 | + | |
| 451 | + char[] a = actions.toCharArray(); | |
| 452 | + | |
| 453 | + int i = a.length - 1; | |
| 454 | + if (i < 0) | |
| 455 | + return mask; | |
| 456 | + | |
| 457 | + while (i != -1) { | |
| 458 | + char c; | |
| 459 | + | |
| 460 | + // skip whitespace | |
| 461 | + while ((i!=-1) && ((c = a[i]) == ' ' || | |
| 462 | + c == '\r' || | |
| 463 | + c == '\n' || | |
| 464 | + c == '\f' || | |
| 465 | + c == '\t')) | |
| 466 | + i--; | |
| 467 | + | |
| 468 | + // check for the known strings | |
| 469 | + int matchlen; | |
| 470 | + | |
| 471 | + if (i >= 3 && (a[i-3] == 'r' || a[i-3] == 'R') && | |
| 472 | + (a[i-2] == 'e' || a[i-2] == 'E') && | |
| 473 | + (a[i-1] == 'a' || a[i-1] == 'A') && | |
| 474 | + (a[i] == 'd' || a[i] == 'D')) | |
| 475 | + { | |
| 476 | + matchlen = 4; | |
| 477 | + mask |= READ; | |
| 478 | + | |
| 479 | + } else if (i >= 4 && (a[i-4] == 'w' || a[i-4] == 'W') && | |
| 480 | + (a[i-3] == 'r' || a[i-3] == 'R') && | |
| 481 | + (a[i-2] == 'i' || a[i-2] == 'I') && | |
| 482 | + (a[i-1] == 't' || a[i-1] == 'T') && | |
| 483 | + (a[i] == 'e' || a[i] == 'E')) | |
| 484 | + { | |
| 485 | + matchlen = 5; | |
| 486 | + mask |= WRITE; | |
| 487 | + | |
| 488 | + } else if (i >= 6 && (a[i-6] == 'e' || a[i-6] == 'E') && | |
| 489 | + (a[i-5] == 'x' || a[i-5] == 'X') && | |
| 490 | + (a[i-4] == 'e' || a[i-4] == 'E') && | |
| 491 | + (a[i-3] == 'c' || a[i-3] == 'C') && | |
| 492 | + (a[i-2] == 'u' || a[i-2] == 'U') && | |
| 493 | + (a[i-1] == 't' || a[i-1] == 'T') && | |
| 494 | + (a[i] == 'e' || a[i] == 'E')) | |
| 495 | + { | |
| 496 | + matchlen = 7; | |
| 497 | + mask |= EXECUTE; | |
| 498 | + | |
| 499 | + } else if (i >= 5 && (a[i-5] == 'd' || a[i-5] == 'D') && | |
| 500 | + (a[i-4] == 'e' || a[i-4] == 'E') && | |
| 501 | + (a[i-3] == 'l' || a[i-3] == 'L') && | |
| 502 | + (a[i-2] == 'e' || a[i-2] == 'E') && | |
| 503 | + (a[i-1] == 't' || a[i-1] == 'T') && | |
| 504 | + (a[i] == 'e' || a[i] == 'E')) | |
| 505 | + { | |
| 506 | + matchlen = 6; | |
| 507 | + mask |= DELETE; | |
| 508 | + | |
| 509 | + } else if (i >= 7 && (a[i-7] == 'r' || a[i-7] == 'R') && | |
| 510 | + (a[i-6] == 'e' || a[i-6] == 'E') && | |
| 511 | + (a[i-5] == 'a' || a[i-5] == 'A') && | |
| 512 | + (a[i-4] == 'd' || a[i-4] == 'D') && | |
| 513 | + (a[i-3] == 'l' || a[i-3] == 'L') && | |
| 514 | + (a[i-2] == 'i' || a[i-2] == 'I') && | |
| 515 | + (a[i-1] == 'n' || a[i-1] == 'N') && | |
| 516 | + (a[i] == 'k' || a[i] == 'K')) | |
| 517 | + { | |
| 518 | + matchlen = 8; | |
| 519 | + mask |= READLINK; | |
| 520 | + | |
| 521 | + } else { | |
| 522 | + // parse error | |
| 523 | + throw new IllegalArgumentException( | |
| 524 | + "invalid permission: " + actions); | |
| 525 | + } | |
| 526 | + | |
| 527 | + // make sure we didn't just match the tail of a word | |
| 528 | + // like "ackbarfaccept". Also, skip to the comma. | |
| 529 | + boolean seencomma = false; | |
| 530 | + while (i >= matchlen && !seencomma) { | |
| 531 | + switch(a[i-matchlen]) { | |
| 532 | + case ',': | |
| 533 | + seencomma = true; | |
| 534 | + /*FALLTHROUGH*/ | |
| 535 | + case ' ': case '\r': case '\n': | |
| 536 | + case '\f': case '\t': | |
| 537 | + break; | |
| 538 | + default: | |
| 539 | + throw new IllegalArgumentException( | |
| 540 | + "invalid permission: " + actions); | |
| 541 | + } | |
| 542 | + i--; | |
| 543 | + } | |
| 544 | + | |
| 545 | + // point i at the location of the comma minus one (or -1). | |
| 546 | + i -= matchlen; | |
| 547 | + } | |
| 548 | + | |
| 549 | + return mask; | |
| 550 | + } | |
| 551 | + | |
| 552 | + /** | |
| 553 | + * Return the current action mask. Used by the FilePermissionCollection. | |
| 554 | + * | |
| 555 | + * @return the actions mask. | |
| 556 | + */ | |
| 557 | + | |
| 558 | + int getMask() { | |
| 559 | + return mask; | |
| 560 | + } | |
| 561 | + | |
| 562 | + /** | |
| 563 | + * Return the canonical string representation of the actions. | |
| 564 | + * Always returns present actions in the following order: | |
| 565 | + * read, write, execute, delete, readlink. | |
| 566 | + * | |
| 567 | + * @return the canonical string representation of the actions. | |
| 568 | + */ | |
| 569 | + private static String getActions(int mask) | |
| 570 | + { | |
| 571 | + StringBuilder sb = new StringBuilder(); | |
| 572 | + boolean comma = false; | |
| 573 | + | |
| 574 | + if ((mask & READ) == READ) { | |
| 575 | + comma = true; | |
| 576 | + sb.append("read"); | |
| 577 | + } | |
| 578 | + | |
| 579 | + if ((mask & WRITE) == WRITE) { | |
| 580 | + if (comma) sb.append(','); | |
| 581 | + else comma = true; | |
| 582 | + sb.append("write"); | |
| 583 | + } | |
| 584 | + | |
| 585 | + if ((mask & EXECUTE) == EXECUTE) { | |
| 586 | + if (comma) sb.append(','); | |
| 587 | + else comma = true; | |
| 588 | + sb.append("execute"); | |
| 589 | + } | |
| 590 | + | |
| 591 | + if ((mask & DELETE) == DELETE) { | |
| 592 | + if (comma) sb.append(','); | |
| 593 | + else comma = true; | |
| 594 | + sb.append("delete"); | |
| 595 | + } | |
| 596 | + | |
| 597 | + if ((mask & READLINK) == READLINK) { | |
| 598 | + if (comma) sb.append(','); | |
| 599 | + else comma = true; | |
| 600 | + sb.append("readlink"); | |
| 601 | + } | |
| 602 | + | |
| 603 | + return sb.toString(); | |
| 604 | + } | |
| 605 | + | |
| 606 | + /** | |
| 607 | + * Returns the "canonical string representation" of the actions. | |
| 608 | + * That is, this method always returns present actions in the following order: | |
| 609 | + * read, write, execute, delete, readlink. For example, if this FilePermission | |
| 610 | + * object allows both write and read actions, a call to <code>getActions</code> | |
| 611 | + * will return the string "read,write". | |
| 612 | + * | |
| 613 | + * @return the canonical string representation of the actions. | |
| 614 | + */ | |
| 615 | + public String getActions() | |
| 616 | + { | |
| 617 | + if (actions == null) | |
| 618 | + actions = getActions(this.mask); | |
| 619 | + | |
| 620 | + return actions; | |
| 621 | + } | |
| 622 | + | |
| 623 | + | |
| 624 | + /** | |
| 625 | + * Returns a new PermissionCollection object for storing FilePermission | |
| 626 | + * objects. | |
| 627 | + * <p> | |
| 628 | + * FilePermission objects must be stored in a manner that allows them | |
| 629 | + * to be inserted into the collection in any order, but that also enables the | |
| 630 | + * PermissionCollection <code>implies</code> | |
| 631 | + * method to be implemented in an efficient (and consistent) manner. | |
| 632 | + * | |
| 633 | + * <p>For example, if you have two FilePermissions: | |
| 634 | + * <OL> | |
| 635 | + * <LI> <code>"/tmp/-", "read"</code> | |
| 636 | + * <LI> <code>"/tmp/scratch/foo", "write"</code> | |
| 637 | + * </OL> | |
| 638 | + * | |
| 639 | + * <p>and you are calling the <code>implies</code> method with the FilePermission: | |
| 640 | + * | |
| 641 | + * <pre> | |
| 642 | + * "/tmp/scratch/foo", "read,write", | |
| 643 | + * </pre> | |
| 644 | + * | |
| 645 | + * then the <code>implies</code> function must | |
| 646 | + * take into account both the "/tmp/-" and "/tmp/scratch/foo" | |
| 647 | + * permissions, so the effective permission is "read,write", | |
| 648 | + * and <code>implies</code> returns true. The "implies" semantics for | |
| 649 | + * FilePermissions are handled properly by the PermissionCollection object | |
| 650 | + * returned by this <code>newPermissionCollection</code> method. | |
| 651 | + * | |
| 652 | + * @return a new PermissionCollection object suitable for storing | |
| 653 | + * FilePermissions. | |
| 654 | + */ | |
| 655 | + | |
| 656 | + public PermissionCollection newPermissionCollection() { | |
| 657 | + return new FilePermissionCollection(); | |
| 658 | + } | |
| 659 | + | |
| 660 | + /** | |
| 661 | + * WriteObject is called to save the state of the FilePermission | |
| 662 | + * to a stream. The actions are serialized, and the superclass | |
| 663 | + * takes care of the name. | |
| 664 | + */ | |
| 665 | + private void writeObject(ObjectOutputStream s) | |
| 666 | + throws IOException | |
| 667 | + { | |
| 668 | + // Write out the actions. The superclass takes care of the name | |
| 669 | + // call getActions to make sure actions field is initialized | |
| 670 | + if (actions == null) | |
| 671 | + getActions(); | |
| 672 | + s.defaultWriteObject(); | |
| 673 | + } | |
| 674 | + | |
| 675 | + /** | |
| 676 | + * readObject is called to restore the state of the FilePermission from | |
| 677 | + * a stream. | |
| 678 | + */ | |
| 679 | + private void readObject(ObjectInputStream s) | |
| 680 | + throws IOException, ClassNotFoundException | |
| 681 | + { | |
| 682 | + // Read in the actions, then restore everything else by calling init. | |
| 683 | + s.defaultReadObject(); | |
| 684 | + init(getMask(actions)); | |
| 685 | + } | |
| 686 | +} | |
| 687 | + | |
| 688 | +/** | |
| 689 | + * A FilePermissionCollection stores a set of FilePermission permissions. | |
| 690 | + * FilePermission objects | |
| 691 | + * must be stored in a manner that allows them to be inserted in any | |
| 692 | + * order, but enable the implies function to evaluate the implies | |
| 693 | + * method. | |
| 694 | + * For example, if you have two FilePermissions: | |
| 695 | + * <OL> | |
| 696 | + * <LI> "/tmp/-", "read" | |
| 697 | + * <LI> "/tmp/scratch/foo", "write" | |
| 698 | + * </OL> | |
| 699 | + * And you are calling the implies function with the FilePermission: | |
| 700 | + * "/tmp/scratch/foo", "read,write", then the implies function must | |
| 701 | + * take into account both the /tmp/- and /tmp/scratch/foo | |
| 702 | + * permissions, so the effective permission is "read,write". | |
| 703 | + * | |
| 704 | + * @see java.security.Permission | |
| 705 | + * @see java.security.Permissions | |
| 706 | + * @see java.security.PermissionCollection | |
| 707 | + * | |
| 708 | + * | |
| 709 | + * @author Marianne Mueller | |
| 710 | + * @author Roland Schemers | |
| 711 | + * | |
| 712 | + * @serial include | |
| 713 | + * | |
| 714 | + */ | |
| 715 | + | |
| 716 | +final class FilePermissionCollection extends PermissionCollection | |
| 717 | +implements Serializable { | |
| 718 | + | |
| 719 | + // Not serialized; see serialization section at end of class | |
| 720 | + private transient List<Permission> perms; | |
| 721 | + | |
| 722 | + /** | |
| 723 | + * Create an empty FilePermissions object. | |
| 724 | + * | |
| 725 | + */ | |
| 726 | + | |
| 727 | + public FilePermissionCollection() { | |
| 728 | + perms = new ArrayList<>(); | |
| 729 | + } | |
| 730 | + | |
| 731 | + /** | |
| 732 | + * Adds a permission to the FilePermissions. The key for the hash is | |
| 733 | + * permission.path. | |
| 734 | + * | |
| 735 | + * @param permission the Permission object to add. | |
| 736 | + * | |
| 737 | + * @exception IllegalArgumentException - if the permission is not a | |
| 738 | + * FilePermission | |
| 739 | + * | |
| 740 | + * @exception SecurityException - if this FilePermissionCollection object | |
| 741 | + * has been marked readonly | |
| 742 | + */ | |
| 743 | + | |
| 744 | + public void add(Permission permission) | |
| 745 | + { | |
| 746 | + if (! (permission instanceof FilePermission)) | |
| 747 | + throw new IllegalArgumentException("invalid permission: "+ | |
| 748 | + permission); | |
| 749 | + if (isReadOnly()) | |
| 750 | + throw new SecurityException( | |
| 751 | + "attempt to add a Permission to a readonly PermissionCollection"); | |
| 752 | + | |
| 753 | + synchronized (this) { | |
| 754 | + perms.add(permission); | |
| 755 | + } | |
| 756 | + } | |
| 757 | + | |
| 758 | + /** | |
| 759 | + * Check and see if this set of permissions implies the permissions | |
| 760 | + * expressed in "permission". | |
| 761 | + * | |
| 762 | + * @param p the Permission object to compare | |
| 763 | + * | |
| 764 | + * @return true if "permission" is a proper subset of a permission in | |
| 765 | + * the set, false if not. | |
| 766 | + */ | |
| 767 | + | |
| 768 | + public boolean implies(Permission permission) | |
| 769 | + { | |
| 770 | + if (! (permission instanceof FilePermission)) | |
| 771 | + return false; | |
| 772 | + | |
| 773 | + FilePermission fp = (FilePermission) permission; | |
| 774 | + | |
| 775 | + int desired = fp.getMask(); | |
| 776 | + int effective = 0; | |
| 777 | + int needed = desired; | |
| 778 | + | |
| 779 | + synchronized (this) { | |
| 780 | + int len = perms.size(); | |
| 781 | + for (int i = 0; i < len; i++) { | |
| 782 | + FilePermission x = (FilePermission) perms.get(i); | |
| 783 | + if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp)) { | |
| 784 | + effective |= x.getMask(); | |
| 785 | + if ((effective & desired) == desired) | |
| 786 | + return true; | |
| 787 | + needed = (desired ^ effective); | |
| 788 | + } | |
| 789 | + } | |
| 790 | + } | |
| 791 | + return false; | |
| 792 | + } | |
| 793 | + | |
| 794 | + /** | |
| 795 | + * Returns an enumeration of all the FilePermission objects in the | |
| 796 | + * container. | |
| 797 | + * | |
| 798 | + * @return an enumeration of all the FilePermission objects. | |
| 799 | + */ | |
| 800 | + | |
| 801 | + public Enumeration elements() { | |
| 802 | + // Convert Iterator into Enumeration | |
| 803 | + synchronized (this) { | |
| 804 | + return Collections.enumeration(perms); | |
| 805 | + } | |
| 806 | + } | |
| 807 | + | |
| 808 | + private static final long serialVersionUID = 2202956749081564585L; | |
| 809 | + | |
| 810 | + // Need to maintain serialization interoperability with earlier releases, | |
| 811 | + // which had the serializable field: | |
| 812 | + // private Vector permissions; | |
| 813 | + | |
| 814 | + /** | |
| 815 | + * @serialField permissions java.util.Vector | |
| 816 | + * A list of FilePermission objects. | |
| 817 | + */ | |
| 818 | + private static final ObjectStreamField[] serialPersistentFields = { | |
| 819 | + new ObjectStreamField("permissions", Vector.class), | |
| 820 | + }; | |
| 821 | + | |
| 822 | + /** | |
| 823 | + * @serialData "permissions" field (a Vector containing the FilePermissions). | |
| 824 | + */ | |
| 825 | + /* | |
| 826 | + * Writes the contents of the perms field out as a Vector for | |
| 827 | + * serialization compatibility with earlier releases. | |
| 828 | + */ | |
| 829 | + private void writeObject(ObjectOutputStream out) throws IOException { | |
| 830 | + // Don't call out.defaultWriteObject() | |
| 831 | + | |
| 832 | + // Write out Vector | |
| 833 | + Vector<Permission> permissions = new Vector<>(perms.size()); | |
| 834 | + synchronized (this) { | |
| 835 | + permissions.addAll(perms); | |
| 836 | + } | |
| 837 | + | |
| 838 | + ObjectOutputStream.PutField pfields = out.putFields(); | |
| 839 | + pfields.put("permissions", permissions); | |
| 840 | + out.writeFields(); | |
| 841 | + } | |
| 842 | + | |
| 843 | + /* | |
| 844 | + * Reads in a Vector of FilePermissions and saves them in the perms field. | |
| 845 | + */ | |
| 846 | + @SuppressWarnings("unchecked") | |
| 847 | + private void readObject(ObjectInputStream in) throws IOException, | |
| 848 | + ClassNotFoundException { | |
| 849 | + // Don't call defaultReadObject() | |
| 850 | + | |
| 851 | + // Read in serialized fields | |
| 852 | + ObjectInputStream.GetField gfields = in.readFields(); | |
| 853 | + | |
| 854 | + // Get the one we want | |
| 855 | + Vector<Permission> permissions = (Vector<Permission>)gfields.get("permissions", null); | |
| 856 | + perms = new ArrayList<>(permissions.size()); | |
| 857 | + perms.addAll(permissions); | |
| 858 | + } | |
| 859 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,85 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * Convenience class for reading character files. The constructors of this | |
| 31 | + * class assume that the default character encoding and the default byte-buffer | |
| 32 | + * size are appropriate. To specify these values yourself, construct an | |
| 33 | + * InputStreamReader on a FileInputStream. | |
| 34 | + * | |
| 35 | + * <p><code>FileReader</code> is meant for reading streams of characters. | |
| 36 | + * For reading streams of raw bytes, consider using a | |
| 37 | + * <code>FileInputStream</code>. | |
| 38 | + * | |
| 39 | + * @see InputStreamReader | |
| 40 | + * @see FileInputStream | |
| 41 | + * | |
| 42 | + * @author Mark Reinhold | |
| 43 | + * @since JDK1.1 | |
| 44 | + */ | |
| 45 | +public class FileReader extends InputStreamReader { | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Creates a new <tt>FileReader</tt>, given the name of the | |
| 49 | + * file to read from. | |
| 50 | + * | |
| 51 | + * @param fileName the name of the file to read from | |
| 52 | + * @exception FileNotFoundException if the named file does not exist, | |
| 53 | + * is a directory rather than a regular file, | |
| 54 | + * or for some other reason cannot be opened for | |
| 55 | + * reading. | |
| 56 | + */ | |
| 57 | + public FileReader(String fileName) throws FileNotFoundException { | |
| 58 | + super(new FileInputStream(fileName)); | |
| 59 | + } | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * Creates a new <tt>FileReader</tt>, given the <tt>File</tt> | |
| 63 | + * to read from. | |
| 64 | + * | |
| 65 | + * @param file the <tt>File</tt> to read from | |
| 66 | + * @exception FileNotFoundException if the file does not exist, | |
| 67 | + * is a directory rather than a regular file, | |
| 68 | + * or for some other reason cannot be opened for | |
| 69 | + * reading. | |
| 70 | + */ | |
| 71 | + public FileReader(File file) throws FileNotFoundException { | |
| 72 | + super(new FileInputStream(file)); | |
| 73 | + } | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * Creates a new <tt>FileReader</tt>, given the | |
| 77 | + * <tt>FileDescriptor</tt> to read from. | |
| 78 | + * | |
| 79 | + * @param fd the FileDescriptor to read from | |
| 80 | + */ | |
| 81 | + public FileReader(FileDescriptor fd) { | |
| 82 | + super(new FileInputStream(fd)); | |
| 83 | + } | |
| 84 | + | |
| 85 | +} | |
Binary file not shown.
| @@ -0,0 +1,252 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * Package-private abstract class for the local filesystem abstraction. | |
| 31 | + */ | |
| 32 | + | |
| 33 | +abstract class FileSystem { | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * Return the FileSystem object representing this platform's local | |
| 37 | + * filesystem. | |
| 38 | + */ | |
| 39 | + public static native FileSystem getFileSystem(); | |
| 40 | + | |
| 41 | + | |
| 42 | + /* -- Normalization and construction -- */ | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * Return the local filesystem's name-separator character. | |
| 46 | + */ | |
| 47 | + public abstract char getSeparator(); | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * Return the local filesystem's path-separator character. | |
| 51 | + */ | |
| 52 | + public abstract char getPathSeparator(); | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * Convert the given pathname string to normal form. If the string is | |
| 56 | + * already in normal form then it is simply returned. | |
| 57 | + */ | |
| 58 | + public abstract String normalize(String path); | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * Compute the length of this pathname string's prefix. The pathname | |
| 62 | + * string must be in normal form. | |
| 63 | + */ | |
| 64 | + public abstract int prefixLength(String path); | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Resolve the child pathname string against the parent. | |
| 68 | + * Both strings must be in normal form, and the result | |
| 69 | + * will be in normal form. | |
| 70 | + */ | |
| 71 | + public abstract String resolve(String parent, String child); | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * Return the parent pathname string to be used when the parent-directory | |
| 75 | + * argument in one of the two-argument File constructors is the empty | |
| 76 | + * pathname. | |
| 77 | + */ | |
| 78 | + public abstract String getDefaultParent(); | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * Post-process the given URI path string if necessary. This is used on | |
| 82 | + * win32, e.g., to transform "/c:/foo" into "c:/foo". The path string | |
| 83 | + * still has slash separators; code in the File class will translate them | |
| 84 | + * after this method returns. | |
| 85 | + */ | |
| 86 | + public abstract String fromURIPath(String path); | |
| 87 | + | |
| 88 | + | |
| 89 | + /* -- Path operations -- */ | |
| 90 | + | |
| 91 | + /** | |
| 92 | + * Tell whether or not the given abstract pathname is absolute. | |
| 93 | + */ | |
| 94 | + public abstract boolean isAbsolute(File f); | |
| 95 | + | |
| 96 | + /** | |
| 97 | + * Resolve the given abstract pathname into absolute form. Invoked by the | |
| 98 | + * getAbsolutePath and getCanonicalPath methods in the File class. | |
| 99 | + */ | |
| 100 | + public abstract String resolve(File f); | |
| 101 | + | |
| 102 | + public abstract String canonicalize(String path) throws IOException; | |
| 103 | + | |
| 104 | + | |
| 105 | + /* -- Attribute accessors -- */ | |
| 106 | + | |
| 107 | + /* Constants for simple boolean attributes */ | |
| 108 | + public static final int BA_EXISTS = 0x01; | |
| 109 | + public static final int BA_REGULAR = 0x02; | |
| 110 | + public static final int BA_DIRECTORY = 0x04; | |
| 111 | + public static final int BA_HIDDEN = 0x08; | |
| 112 | + | |
| 113 | + /** | |
| 114 | + * Return the simple boolean attributes for the file or directory denoted | |
| 115 | + * by the given abstract pathname, or zero if it does not exist or some | |
| 116 | + * other I/O error occurs. | |
| 117 | + */ | |
| 118 | + public abstract int getBooleanAttributes(File f); | |
| 119 | + | |
| 120 | + public static final int ACCESS_READ = 0x04; | |
| 121 | + public static final int ACCESS_WRITE = 0x02; | |
| 122 | + public static final int ACCESS_EXECUTE = 0x01; | |
| 123 | + | |
| 124 | + /** | |
| 125 | + * Check whether the file or directory denoted by the given abstract | |
| 126 | + * pathname may be accessed by this process. The second argument specifies | |
| 127 | + * which access, ACCESS_READ, ACCESS_WRITE or ACCESS_EXECUTE, to check. | |
| 128 | + * Return false if access is denied or an I/O error occurs | |
| 129 | + */ | |
| 130 | + public abstract boolean checkAccess(File f, int access); | |
| 131 | + /** | |
| 132 | + * Set on or off the access permission (to owner only or to all) to the file | |
| 133 | + * or directory denoted by the given abstract pathname, based on the parameters | |
| 134 | + * enable, access and oweronly. | |
| 135 | + */ | |
| 136 | + public abstract boolean setPermission(File f, int access, boolean enable, boolean owneronly); | |
| 137 | + | |
| 138 | + /** | |
| 139 | + * Return the time at which the file or directory denoted by the given | |
| 140 | + * abstract pathname was last modified, or zero if it does not exist or | |
| 141 | + * some other I/O error occurs. | |
| 142 | + */ | |
| 143 | + public abstract long getLastModifiedTime(File f); | |
| 144 | + | |
| 145 | + /** | |
| 146 | + * Return the length in bytes of the file denoted by the given abstract | |
| 147 | + * pathname, or zero if it does not exist, is a directory, or some other | |
| 148 | + * I/O error occurs. | |
| 149 | + */ | |
| 150 | + public abstract long getLength(File f); | |
| 151 | + | |
| 152 | + | |
| 153 | + /* -- File operations -- */ | |
| 154 | + | |
| 155 | + /** | |
| 156 | + * Create a new empty file with the given pathname. Return | |
| 157 | + * <code>true</code> if the file was created and <code>false</code> if a | |
| 158 | + * file or directory with the given pathname already exists. Throw an | |
| 159 | + * IOException if an I/O error occurs. | |
| 160 | + */ | |
| 161 | + public abstract boolean createFileExclusively(String pathname) | |
| 162 | + throws IOException; | |
| 163 | + | |
| 164 | + /** | |
| 165 | + * Delete the file or directory denoted by the given abstract pathname, | |
| 166 | + * returning <code>true</code> if and only if the operation succeeds. | |
| 167 | + */ | |
| 168 | + public abstract boolean delete(File f); | |
| 169 | + | |
| 170 | + /** | |
| 171 | + * List the elements of the directory denoted by the given abstract | |
| 172 | + * pathname. Return an array of strings naming the elements of the | |
| 173 | + * directory if successful; otherwise, return <code>null</code>. | |
| 174 | + */ | |
| 175 | + public abstract String[] list(File f); | |
| 176 | + | |
| 177 | + /** | |
| 178 | + * Create a new directory denoted by the given abstract pathname, | |
| 179 | + * returning <code>true</code> if and only if the operation succeeds. | |
| 180 | + */ | |
| 181 | + public abstract boolean createDirectory(File f); | |
| 182 | + | |
| 183 | + /** | |
| 184 | + * Rename the file or directory denoted by the first abstract pathname to | |
| 185 | + * the second abstract pathname, returning <code>true</code> if and only if | |
| 186 | + * the operation succeeds. | |
| 187 | + */ | |
| 188 | + public abstract boolean rename(File f1, File f2); | |
| 189 | + | |
| 190 | + /** | |
| 191 | + * Set the last-modified time of the file or directory denoted by the | |
| 192 | + * given abstract pathname, returning <code>true</code> if and only if the | |
| 193 | + * operation succeeds. | |
| 194 | + */ | |
| 195 | + public abstract boolean setLastModifiedTime(File f, long time); | |
| 196 | + | |
| 197 | + /** | |
| 198 | + * Mark the file or directory denoted by the given abstract pathname as | |
| 199 | + * read-only, returning <code>true</code> if and only if the operation | |
| 200 | + * succeeds. | |
| 201 | + */ | |
| 202 | + public abstract boolean setReadOnly(File f); | |
| 203 | + | |
| 204 | + | |
| 205 | + /* -- Filesystem interface -- */ | |
| 206 | + | |
| 207 | + /** | |
| 208 | + * List the available filesystem roots. | |
| 209 | + */ | |
| 210 | + public abstract File[] listRoots(); | |
| 211 | + | |
| 212 | + /* -- Disk usage -- */ | |
| 213 | + public static final int SPACE_TOTAL = 0; | |
| 214 | + public static final int SPACE_FREE = 1; | |
| 215 | + public static final int SPACE_USABLE = 2; | |
| 216 | + | |
| 217 | + public abstract long getSpace(File f, int t); | |
| 218 | + | |
| 219 | + /* -- Basic infrastructure -- */ | |
| 220 | + | |
| 221 | + /** | |
| 222 | + * Compare two abstract pathnames lexicographically. | |
| 223 | + */ | |
| 224 | + public abstract int compare(File f1, File f2); | |
| 225 | + | |
| 226 | + /** | |
| 227 | + * Compute the hash code of an abstract pathname. | |
| 228 | + */ | |
| 229 | + public abstract int hashCode(File f); | |
| 230 | + | |
| 231 | + // Flags for enabling/disabling performance optimizations for file | |
| 232 | + // name canonicalization | |
| 233 | + static boolean useCanonCaches = true; | |
| 234 | + static boolean useCanonPrefixCache = true; | |
| 235 | + | |
| 236 | + private static boolean getBooleanProperty(String prop, boolean defaultVal) { | |
| 237 | + String val = System.getProperty(prop); | |
| 238 | + if (val == null) return defaultVal; | |
| 239 | + if (val.equalsIgnoreCase("true")) { | |
| 240 | + return true; | |
| 241 | + } else { | |
| 242 | + return false; | |
| 243 | + } | |
| 244 | + } | |
| 245 | + | |
| 246 | + static { | |
| 247 | + useCanonCaches = getBooleanProperty("sun.io.useCanonCaches", | |
| 248 | + useCanonCaches); | |
| 249 | + useCanonPrefixCache = getBooleanProperty("sun.io.useCanonPrefixCache", | |
| 250 | + useCanonPrefixCache); | |
| 251 | + } | |
| 252 | +} | |
Binary file not shown.
| @@ -0,0 +1,119 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * Convenience class for writing character files. The constructors of this | |
| 31 | + * class assume that the default character encoding and the default byte-buffer | |
| 32 | + * size are acceptable. To specify these values yourself, construct an | |
| 33 | + * OutputStreamWriter on a FileOutputStream. | |
| 34 | + * | |
| 35 | + * <p>Whether or not a file is available or may be created depends upon the | |
| 36 | + * underlying platform. Some platforms, in particular, allow a file to be | |
| 37 | + * opened for writing by only one <tt>FileWriter</tt> (or other file-writing | |
| 38 | + * object) at a time. In such situations the constructors in this class | |
| 39 | + * will fail if the file involved is already open. | |
| 40 | + * | |
| 41 | + * <p><code>FileWriter</code> is meant for writing streams of characters. | |
| 42 | + * For writing streams of raw bytes, consider using a | |
| 43 | + * <code>FileOutputStream</code>. | |
| 44 | + * | |
| 45 | + * @see OutputStreamWriter | |
| 46 | + * @see FileOutputStream | |
| 47 | + * | |
| 48 | + * @author Mark Reinhold | |
| 49 | + * @since JDK1.1 | |
| 50 | + */ | |
| 51 | + | |
| 52 | +public class FileWriter extends OutputStreamWriter { | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * Constructs a FileWriter object given a file name. | |
| 56 | + * | |
| 57 | + * @param fileName String The system-dependent filename. | |
| 58 | + * @throws IOException if the named file exists but is a directory rather | |
| 59 | + * than a regular file, does not exist but cannot be | |
| 60 | + * created, or cannot be opened for any other reason | |
| 61 | + */ | |
| 62 | + public FileWriter(String fileName) throws IOException { | |
| 63 | + super(new FileOutputStream(fileName)); | |
| 64 | + } | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Constructs a FileWriter object given a file name with a boolean | |
| 68 | + * indicating whether or not to append the data written. | |
| 69 | + * | |
| 70 | + * @param fileName String The system-dependent filename. | |
| 71 | + * @param append boolean if <code>true</code>, then data will be written | |
| 72 | + * to the end of the file rather than the beginning. | |
| 73 | + * @throws IOException if the named file exists but is a directory rather | |
| 74 | + * than a regular file, does not exist but cannot be | |
| 75 | + * created, or cannot be opened for any other reason | |
| 76 | + */ | |
| 77 | + public FileWriter(String fileName, boolean append) throws IOException { | |
| 78 | + super(new FileOutputStream(fileName, append)); | |
| 79 | + } | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * Constructs a FileWriter object given a File object. | |
| 83 | + * | |
| 84 | + * @param file a File object to write to. | |
| 85 | + * @throws IOException if the file exists but is a directory rather than | |
| 86 | + * a regular file, does not exist but cannot be created, | |
| 87 | + * or cannot be opened for any other reason | |
| 88 | + */ | |
| 89 | + public FileWriter(File file) throws IOException { | |
| 90 | + super(new FileOutputStream(file)); | |
| 91 | + } | |
| 92 | + | |
| 93 | + /** | |
| 94 | + * Constructs a FileWriter object given a File object. If the second | |
| 95 | + * argument is <code>true</code>, then bytes will be written to the end | |
| 96 | + * of the file rather than the beginning. | |
| 97 | + * | |
| 98 | + * @param file a File object to write to | |
| 99 | + * @param append if <code>true</code>, then bytes will be written | |
| 100 | + * to the end of the file rather than the beginning | |
| 101 | + * @throws IOException if the file exists but is a directory rather than | |
| 102 | + * a regular file, does not exist but cannot be created, | |
| 103 | + * or cannot be opened for any other reason | |
| 104 | + * @since 1.4 | |
| 105 | + */ | |
| 106 | + public FileWriter(File file, boolean append) throws IOException { | |
| 107 | + super(new FileOutputStream(file, append)); | |
| 108 | + } | |
| 109 | + | |
| 110 | + /** | |
| 111 | + * Constructs a FileWriter object associated with a file descriptor. | |
| 112 | + * | |
| 113 | + * @param fd FileDescriptor object to write to. | |
| 114 | + */ | |
| 115 | + public FileWriter(FileDescriptor fd) { | |
| 116 | + super(new FileOutputStream(fd)); | |
| 117 | + } | |
| 118 | + | |
| 119 | +} | |
Binary file not shown.
| @@ -0,0 +1,53 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Instances of classes that implement this interface are used to | |
| 30 | + * filter filenames. These instances are used to filter directory | |
| 31 | + * listings in the <code>list</code> method of class | |
| 32 | + * <code>File</code>, and by the Abstract Window Toolkit's file | |
| 33 | + * dialog component. | |
| 34 | + * | |
| 35 | + * @author Arthur van Hoff | |
| 36 | + * @author Jonathan Payne | |
| 37 | + * @see java.awt.FileDialog#setFilenameFilter(java.io.FilenameFilter) | |
| 38 | + * @see java.io.File | |
| 39 | + * @see java.io.File#list(java.io.FilenameFilter) | |
| 40 | + * @since JDK1.0 | |
| 41 | + */ | |
| 42 | +public | |
| 43 | +interface FilenameFilter { | |
| 44 | + /** | |
| 45 | + * Tests if a specified file should be included in a file list. | |
| 46 | + * | |
| 47 | + * @param dir the directory in which the file was found. | |
| 48 | + * @param name the name of the file. | |
| 49 | + * @return <code>true</code> if and only if the name should be | |
| 50 | + * included in the file list; <code>false</code> otherwise. | |
| 51 | + */ | |
| 52 | + boolean accept(File dir, String name); | |
| 53 | +} | |
Binary file not shown.
| @@ -0,0 +1,245 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * A <code>FilterInputStream</code> contains | |
| 30 | + * some other input stream, which it uses as | |
| 31 | + * its basic source of data, possibly transforming | |
| 32 | + * the data along the way or providing additional | |
| 33 | + * functionality. The class <code>FilterInputStream</code> | |
| 34 | + * itself simply overrides all methods of | |
| 35 | + * <code>InputStream</code> with versions that | |
| 36 | + * pass all requests to the contained input | |
| 37 | + * stream. Subclasses of <code>FilterInputStream</code> | |
| 38 | + * may further override some of these methods | |
| 39 | + * and may also provide additional methods | |
| 40 | + * and fields. | |
| 41 | + * | |
| 42 | + * @author Jonathan Payne | |
| 43 | + * @since JDK1.0 | |
| 44 | + */ | |
| 45 | +public | |
| 46 | +class FilterInputStream extends InputStream { | |
| 47 | + /** | |
| 48 | + * The input stream to be filtered. | |
| 49 | + */ | |
| 50 | + protected volatile InputStream in; | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * Creates a <code>FilterInputStream</code> | |
| 54 | + * by assigning the argument <code>in</code> | |
| 55 | + * to the field <code>this.in</code> so as | |
| 56 | + * to remember it for later use. | |
| 57 | + * | |
| 58 | + * @param in the underlying input stream, or <code>null</code> if | |
| 59 | + * this instance is to be created without an underlying stream. | |
| 60 | + */ | |
| 61 | + protected FilterInputStream(InputStream in) { | |
| 62 | + this.in = in; | |
| 63 | + } | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * Reads the next byte of data from this input stream. The value | |
| 67 | + * byte is returned as an <code>int</code> in the range | |
| 68 | + * <code>0</code> to <code>255</code>. If no byte is available | |
| 69 | + * because the end of the stream has been reached, the value | |
| 70 | + * <code>-1</code> is returned. This method blocks until input data | |
| 71 | + * is available, the end of the stream is detected, or an exception | |
| 72 | + * is thrown. | |
| 73 | + * <p> | |
| 74 | + * This method | |
| 75 | + * simply performs <code>in.read()</code> and returns the result. | |
| 76 | + * | |
| 77 | + * @return the next byte of data, or <code>-1</code> if the end of the | |
| 78 | + * stream is reached. | |
| 79 | + * @exception IOException if an I/O error occurs. | |
| 80 | + * @see java.io.FilterInputStream#in | |
| 81 | + */ | |
| 82 | + public int read() throws IOException { | |
| 83 | + return in.read(); | |
| 84 | + } | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * Reads up to <code>byte.length</code> bytes of data from this | |
| 88 | + * input stream into an array of bytes. This method blocks until some | |
| 89 | + * input is available. | |
| 90 | + * <p> | |
| 91 | + * This method simply performs the call | |
| 92 | + * <code>read(b, 0, b.length)</code> and returns | |
| 93 | + * the result. It is important that it does | |
| 94 | + * <i>not</i> do <code>in.read(b)</code> instead; | |
| 95 | + * certain subclasses of <code>FilterInputStream</code> | |
| 96 | + * depend on the implementation strategy actually | |
| 97 | + * used. | |
| 98 | + * | |
| 99 | + * @param b the buffer into which the data is read. | |
| 100 | + * @return the total number of bytes read into the buffer, or | |
| 101 | + * <code>-1</code> if there is no more data because the end of | |
| 102 | + * the stream has been reached. | |
| 103 | + * @exception IOException if an I/O error occurs. | |
| 104 | + * @see java.io.FilterInputStream#read(byte[], int, int) | |
| 105 | + */ | |
| 106 | + public int read(byte b[]) throws IOException { | |
| 107 | + return read(b, 0, b.length); | |
| 108 | + } | |
| 109 | + | |
| 110 | + /** | |
| 111 | + * Reads up to <code>len</code> bytes of data from this input stream | |
| 112 | + * into an array of bytes. If <code>len</code> is not zero, the method | |
| 113 | + * blocks until some input is available; otherwise, no | |
| 114 | + * bytes are read and <code>0</code> is returned. | |
| 115 | + * <p> | |
| 116 | + * This method simply performs <code>in.read(b, off, len)</code> | |
| 117 | + * and returns the result. | |
| 118 | + * | |
| 119 | + * @param b the buffer into which the data is read. | |
| 120 | + * @param off the start offset in the destination array <code>b</code> | |
| 121 | + * @param len the maximum number of bytes read. | |
| 122 | + * @return the total number of bytes read into the buffer, or | |
| 123 | + * <code>-1</code> if there is no more data because the end of | |
| 124 | + * the stream has been reached. | |
| 125 | + * @exception NullPointerException If <code>b</code> is <code>null</code>. | |
| 126 | + * @exception IndexOutOfBoundsException If <code>off</code> is negative, | |
| 127 | + * <code>len</code> is negative, or <code>len</code> is greater than | |
| 128 | + * <code>b.length - off</code> | |
| 129 | + * @exception IOException if an I/O error occurs. | |
| 130 | + * @see java.io.FilterInputStream#in | |
| 131 | + */ | |
| 132 | + public int read(byte b[], int off, int len) throws IOException { | |
| 133 | + return in.read(b, off, len); | |
| 134 | + } | |
| 135 | + | |
| 136 | + /** | |
| 137 | + * Skips over and discards <code>n</code> bytes of data from the | |
| 138 | + * input stream. The <code>skip</code> method may, for a variety of | |
| 139 | + * reasons, end up skipping over some smaller number of bytes, | |
| 140 | + * possibly <code>0</code>. The actual number of bytes skipped is | |
| 141 | + * returned. | |
| 142 | + * <p> | |
| 143 | + * This method simply performs <code>in.skip(n)</code>. | |
| 144 | + * | |
| 145 | + * @param n the number of bytes to be skipped. | |
| 146 | + * @return the actual number of bytes skipped. | |
| 147 | + * @exception IOException if the stream does not support seek, | |
| 148 | + * or if some other I/O error occurs. | |
| 149 | + */ | |
| 150 | + public long skip(long n) throws IOException { | |
| 151 | + return in.skip(n); | |
| 152 | + } | |
| 153 | + | |
| 154 | + /** | |
| 155 | + * Returns an estimate of the number of bytes that can be read (or | |
| 156 | + * skipped over) from this input stream without blocking by the next | |
| 157 | + * caller of a method for this input stream. The next caller might be | |
| 158 | + * the same thread or another thread. A single read or skip of this | |
| 159 | + * many bytes will not block, but may read or skip fewer bytes. | |
| 160 | + * <p> | |
| 161 | + * This method returns the result of {@link #in in}.available(). | |
| 162 | + * | |
| 163 | + * @return an estimate of the number of bytes that can be read (or skipped | |
| 164 | + * over) from this input stream without blocking. | |
| 165 | + * @exception IOException if an I/O error occurs. | |
| 166 | + */ | |
| 167 | + public int available() throws IOException { | |
| 168 | + return in.available(); | |
| 169 | + } | |
| 170 | + | |
| 171 | + /** | |
| 172 | + * Closes this input stream and releases any system resources | |
| 173 | + * associated with the stream. | |
| 174 | + * This | |
| 175 | + * method simply performs <code>in.close()</code>. | |
| 176 | + * | |
| 177 | + * @exception IOException if an I/O error occurs. | |
| 178 | + * @see java.io.FilterInputStream#in | |
| 179 | + */ | |
| 180 | + public void close() throws IOException { | |
| 181 | + in.close(); | |
| 182 | + } | |
| 183 | + | |
| 184 | + /** | |
| 185 | + * Marks the current position in this input stream. A subsequent | |
| 186 | + * call to the <code>reset</code> method repositions this stream at | |
| 187 | + * the last marked position so that subsequent reads re-read the same bytes. | |
| 188 | + * <p> | |
| 189 | + * The <code>readlimit</code> argument tells this input stream to | |
| 190 | + * allow that many bytes to be read before the mark position gets | |
| 191 | + * invalidated. | |
| 192 | + * <p> | |
| 193 | + * This method simply performs <code>in.mark(readlimit)</code>. | |
| 194 | + * | |
| 195 | + * @param readlimit the maximum limit of bytes that can be read before | |
| 196 | + * the mark position becomes invalid. | |
| 197 | + * @see java.io.FilterInputStream#in | |
| 198 | + * @see java.io.FilterInputStream#reset() | |
| 199 | + */ | |
| 200 | + public synchronized void mark(int readlimit) { | |
| 201 | + in.mark(readlimit); | |
| 202 | + } | |
| 203 | + | |
| 204 | + /** | |
| 205 | + * Repositions this stream to the position at the time the | |
| 206 | + * <code>mark</code> method was last called on this input stream. | |
| 207 | + * <p> | |
| 208 | + * This method | |
| 209 | + * simply performs <code>in.reset()</code>. | |
| 210 | + * <p> | |
| 211 | + * Stream marks are intended to be used in | |
| 212 | + * situations where you need to read ahead a little to see what's in | |
| 213 | + * the stream. Often this is most easily done by invoking some | |
| 214 | + * general parser. If the stream is of the type handled by the | |
| 215 | + * parse, it just chugs along happily. If the stream is not of | |
| 216 | + * that type, the parser should toss an exception when it fails. | |
| 217 | + * If this happens within readlimit bytes, it allows the outer | |
| 218 | + * code to reset the stream and try another parser. | |
| 219 | + * | |
| 220 | + * @exception IOException if the stream has not been marked or if the | |
| 221 | + * mark has been invalidated. | |
| 222 | + * @see java.io.FilterInputStream#in | |
| 223 | + * @see java.io.FilterInputStream#mark(int) | |
| 224 | + */ | |
| 225 | + public synchronized void reset() throws IOException { | |
| 226 | + in.reset(); | |
| 227 | + } | |
| 228 | + | |
| 229 | + /** | |
| 230 | + * Tests if this input stream supports the <code>mark</code> | |
| 231 | + * and <code>reset</code> methods. | |
| 232 | + * This method | |
| 233 | + * simply performs <code>in.markSupported()</code>. | |
| 234 | + * | |
| 235 | + * @return <code>true</code> if this stream type supports the | |
| 236 | + * <code>mark</code> and <code>reset</code> method; | |
| 237 | + * <code>false</code> otherwise. | |
| 238 | + * @see java.io.FilterInputStream#in | |
| 239 | + * @see java.io.InputStream#mark(int) | |
| 240 | + * @see java.io.InputStream#reset() | |
| 241 | + */ | |
| 242 | + public boolean markSupported() { | |
| 243 | + return in.markSupported(); | |
| 244 | + } | |
| 245 | +} | |
Binary file not shown.
| @@ -0,0 +1,162 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class is the superclass of all classes that filter output | |
| 30 | + * streams. These streams sit on top of an already existing output | |
| 31 | + * stream (the <i>underlying</i> output stream) which it uses as its | |
| 32 | + * basic sink of data, but possibly transforming the data along the | |
| 33 | + * way or providing additional functionality. | |
| 34 | + * <p> | |
| 35 | + * The class <code>FilterOutputStream</code> itself simply overrides | |
| 36 | + * all methods of <code>OutputStream</code> with versions that pass | |
| 37 | + * all requests to the underlying output stream. Subclasses of | |
| 38 | + * <code>FilterOutputStream</code> may further override some of these | |
| 39 | + * methods as well as provide additional methods and fields. | |
| 40 | + * | |
| 41 | + * @author Jonathan Payne | |
| 42 | + * @since JDK1.0 | |
| 43 | + */ | |
| 44 | +public | |
| 45 | +class FilterOutputStream extends OutputStream { | |
| 46 | + /** | |
| 47 | + * The underlying output stream to be filtered. | |
| 48 | + */ | |
| 49 | + protected OutputStream out; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * Creates an output stream filter built on top of the specified | |
| 53 | + * underlying output stream. | |
| 54 | + * | |
| 55 | + * @param out the underlying output stream to be assigned to | |
| 56 | + * the field <tt>this.out</tt> for later use, or | |
| 57 | + * <code>null</code> if this instance is to be | |
| 58 | + * created without an underlying stream. | |
| 59 | + */ | |
| 60 | + public FilterOutputStream(OutputStream out) { | |
| 61 | + this.out = out; | |
| 62 | + } | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * Writes the specified <code>byte</code> to this output stream. | |
| 66 | + * <p> | |
| 67 | + * The <code>write</code> method of <code>FilterOutputStream</code> | |
| 68 | + * calls the <code>write</code> method of its underlying output stream, | |
| 69 | + * that is, it performs <tt>out.write(b)</tt>. | |
| 70 | + * <p> | |
| 71 | + * Implements the abstract <tt>write</tt> method of <tt>OutputStream</tt>. | |
| 72 | + * | |
| 73 | + * @param b the <code>byte</code>. | |
| 74 | + * @exception IOException if an I/O error occurs. | |
| 75 | + */ | |
| 76 | + public void write(int b) throws IOException { | |
| 77 | + out.write(b); | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * Writes <code>b.length</code> bytes to this output stream. | |
| 82 | + * <p> | |
| 83 | + * The <code>write</code> method of <code>FilterOutputStream</code> | |
| 84 | + * calls its <code>write</code> method of three arguments with the | |
| 85 | + * arguments <code>b</code>, <code>0</code>, and | |
| 86 | + * <code>b.length</code>. | |
| 87 | + * <p> | |
| 88 | + * Note that this method does not call the one-argument | |
| 89 | + * <code>write</code> method of its underlying stream with the single | |
| 90 | + * argument <code>b</code>. | |
| 91 | + * | |
| 92 | + * @param b the data to be written. | |
| 93 | + * @exception IOException if an I/O error occurs. | |
| 94 | + * @see java.io.FilterOutputStream#write(byte[], int, int) | |
| 95 | + */ | |
| 96 | + public void write(byte b[]) throws IOException { | |
| 97 | + write(b, 0, b.length); | |
| 98 | + } | |
| 99 | + | |
| 100 | + /** | |
| 101 | + * Writes <code>len</code> bytes from the specified | |
| 102 | + * <code>byte</code> array starting at offset <code>off</code> to | |
| 103 | + * this output stream. | |
| 104 | + * <p> | |
| 105 | + * The <code>write</code> method of <code>FilterOutputStream</code> | |
| 106 | + * calls the <code>write</code> method of one argument on each | |
| 107 | + * <code>byte</code> to output. | |
| 108 | + * <p> | |
| 109 | + * Note that this method does not call the <code>write</code> method | |
| 110 | + * of its underlying input stream with the same arguments. Subclasses | |
| 111 | + * of <code>FilterOutputStream</code> should provide a more efficient | |
| 112 | + * implementation of this method. | |
| 113 | + * | |
| 114 | + * @param b the data. | |
| 115 | + * @param off the start offset in the data. | |
| 116 | + * @param len the number of bytes to write. | |
| 117 | + * @exception IOException if an I/O error occurs. | |
| 118 | + * @see java.io.FilterOutputStream#write(int) | |
| 119 | + */ | |
| 120 | + public void write(byte b[], int off, int len) throws IOException { | |
| 121 | + if ((off | len | (b.length - (len + off)) | (off + len)) < 0) | |
| 122 | + throw new IndexOutOfBoundsException(); | |
| 123 | + | |
| 124 | + for (int i = 0 ; i < len ; i++) { | |
| 125 | + write(b[off + i]); | |
| 126 | + } | |
| 127 | + } | |
| 128 | + | |
| 129 | + /** | |
| 130 | + * Flushes this output stream and forces any buffered output bytes | |
| 131 | + * to be written out to the stream. | |
| 132 | + * <p> | |
| 133 | + * The <code>flush</code> method of <code>FilterOutputStream</code> | |
| 134 | + * calls the <code>flush</code> method of its underlying output stream. | |
| 135 | + * | |
| 136 | + * @exception IOException if an I/O error occurs. | |
| 137 | + * @see java.io.FilterOutputStream#out | |
| 138 | + */ | |
| 139 | + public void flush() throws IOException { | |
| 140 | + out.flush(); | |
| 141 | + } | |
| 142 | + | |
| 143 | + /** | |
| 144 | + * Closes this output stream and releases any system resources | |
| 145 | + * associated with the stream. | |
| 146 | + * <p> | |
| 147 | + * The <code>close</code> method of <code>FilterOutputStream</code> | |
| 148 | + * calls its <code>flush</code> method, and then calls the | |
| 149 | + * <code>close</code> method of its underlying output stream. | |
| 150 | + * | |
| 151 | + * @exception IOException if an I/O error occurs. | |
| 152 | + * @see java.io.FilterOutputStream#flush() | |
| 153 | + * @see java.io.FilterOutputStream#out | |
| 154 | + */ | |
| 155 | + public void close() throws IOException { | |
| 156 | + try { | |
| 157 | + flush(); | |
| 158 | + } catch (IOException ignored) { | |
| 159 | + } | |
| 160 | + out.close(); | |
| 161 | + } | |
| 162 | +} | |
Binary file not shown.
| @@ -0,0 +1,124 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * Abstract class for reading filtered character streams. | |
| 31 | + * The abstract class <code>FilterReader</code> itself | |
| 32 | + * provides default methods that pass all requests to | |
| 33 | + * the contained stream. Subclasses of <code>FilterReader</code> | |
| 34 | + * should override some of these methods and may also provide | |
| 35 | + * additional methods and fields. | |
| 36 | + * | |
| 37 | + * @author Mark Reinhold | |
| 38 | + * @since JDK1.1 | |
| 39 | + */ | |
| 40 | + | |
| 41 | +public abstract class FilterReader extends Reader { | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * The underlying character-input stream. | |
| 45 | + */ | |
| 46 | + protected Reader in; | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * Creates a new filtered reader. | |
| 50 | + * | |
| 51 | + * @param in a Reader object providing the underlying stream. | |
| 52 | + * @throws NullPointerException if <code>in</code> is <code>null</code> | |
| 53 | + */ | |
| 54 | + protected FilterReader(Reader in) { | |
| 55 | + super(in); | |
| 56 | + this.in = in; | |
| 57 | + } | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * Reads a single character. | |
| 61 | + * | |
| 62 | + * @exception IOException If an I/O error occurs | |
| 63 | + */ | |
| 64 | + public int read() throws IOException { | |
| 65 | + return in.read(); | |
| 66 | + } | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * Reads characters into a portion of an array. | |
| 70 | + * | |
| 71 | + * @exception IOException If an I/O error occurs | |
| 72 | + */ | |
| 73 | + public int read(char cbuf[], int off, int len) throws IOException { | |
| 74 | + return in.read(cbuf, off, len); | |
| 75 | + } | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * Skips characters. | |
| 79 | + * | |
| 80 | + * @exception IOException If an I/O error occurs | |
| 81 | + */ | |
| 82 | + public long skip(long n) throws IOException { | |
| 83 | + return in.skip(n); | |
| 84 | + } | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * Tells whether this stream is ready to be read. | |
| 88 | + * | |
| 89 | + * @exception IOException If an I/O error occurs | |
| 90 | + */ | |
| 91 | + public boolean ready() throws IOException { | |
| 92 | + return in.ready(); | |
| 93 | + } | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * Tells whether this stream supports the mark() operation. | |
| 97 | + */ | |
| 98 | + public boolean markSupported() { | |
| 99 | + return in.markSupported(); | |
| 100 | + } | |
| 101 | + | |
| 102 | + /** | |
| 103 | + * Marks the present position in the stream. | |
| 104 | + * | |
| 105 | + * @exception IOException If an I/O error occurs | |
| 106 | + */ | |
| 107 | + public void mark(int readAheadLimit) throws IOException { | |
| 108 | + in.mark(readAheadLimit); | |
| 109 | + } | |
| 110 | + | |
| 111 | + /** | |
| 112 | + * Resets the stream. | |
| 113 | + * | |
| 114 | + * @exception IOException If an I/O error occurs | |
| 115 | + */ | |
| 116 | + public void reset() throws IOException { | |
| 117 | + in.reset(); | |
| 118 | + } | |
| 119 | + | |
| 120 | + public void close() throws IOException { | |
| 121 | + in.close(); | |
| 122 | + } | |
| 123 | + | |
| 124 | +} | |
Binary file not shown.
| @@ -0,0 +1,107 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * Abstract class for writing filtered character streams. | |
| 31 | + * The abstract class <code>FilterWriter</code> itself | |
| 32 | + * provides default methods that pass all requests to the | |
| 33 | + * contained stream. Subclasses of <code>FilterWriter</code> | |
| 34 | + * should override some of these methods and may also | |
| 35 | + * provide additional methods and fields. | |
| 36 | + * | |
| 37 | + * @author Mark Reinhold | |
| 38 | + * @since JDK1.1 | |
| 39 | + */ | |
| 40 | + | |
| 41 | +public abstract class FilterWriter extends Writer { | |
| 42 | + | |
| 43 | + /** | |
| 44 | + * The underlying character-output stream. | |
| 45 | + */ | |
| 46 | + protected Writer out; | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * Create a new filtered writer. | |
| 50 | + * | |
| 51 | + * @param out a Writer object to provide the underlying stream. | |
| 52 | + * @throws NullPointerException if <code>out</code> is <code>null</code> | |
| 53 | + */ | |
| 54 | + protected FilterWriter(Writer out) { | |
| 55 | + super(out); | |
| 56 | + this.out = out; | |
| 57 | + } | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * Writes a single character. | |
| 61 | + * | |
| 62 | + * @exception IOException If an I/O error occurs | |
| 63 | + */ | |
| 64 | + public void write(int c) throws IOException { | |
| 65 | + out.write(c); | |
| 66 | + } | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * Writes a portion of an array of characters. | |
| 70 | + * | |
| 71 | + * @param cbuf Buffer of characters to be written | |
| 72 | + * @param off Offset from which to start reading characters | |
| 73 | + * @param len Number of characters to be written | |
| 74 | + * | |
| 75 | + * @exception IOException If an I/O error occurs | |
| 76 | + */ | |
| 77 | + public void write(char cbuf[], int off, int len) throws IOException { | |
| 78 | + out.write(cbuf, off, len); | |
| 79 | + } | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * Writes a portion of a string. | |
| 83 | + * | |
| 84 | + * @param str String to be written | |
| 85 | + * @param off Offset from which to start reading characters | |
| 86 | + * @param len Number of characters to be written | |
| 87 | + * | |
| 88 | + * @exception IOException If an I/O error occurs | |
| 89 | + */ | |
| 90 | + public void write(String str, int off, int len) throws IOException { | |
| 91 | + out.write(str, off, len); | |
| 92 | + } | |
| 93 | + | |
| 94 | + /** | |
| 95 | + * Flushes the stream. | |
| 96 | + * | |
| 97 | + * @exception IOException If an I/O error occurs | |
| 98 | + */ | |
| 99 | + public void flush() throws IOException { | |
| 100 | + out.flush(); | |
| 101 | + } | |
| 102 | + | |
| 103 | + public void close() throws IOException { | |
| 104 | + out.close(); | |
| 105 | + } | |
| 106 | + | |
| 107 | +} | |
Binary file not shown.
| @@ -0,0 +1,47 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * A <tt>Flushable</tt> is a destination of data that can be flushed. The | |
| 32 | + * flush method is invoked to write any buffered output to the underlying | |
| 33 | + * stream. | |
| 34 | + * | |
| 35 | + * @since 1.5 | |
| 36 | + */ | |
| 37 | + | |
| 38 | +public interface Flushable { | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * Flushes this stream by writing any buffered output to the underlying | |
| 42 | + * stream. | |
| 43 | + * | |
| 44 | + * @throws IOException If an I/O error occurs | |
| 45 | + */ | |
| 46 | + void flush() throws IOException; | |
| 47 | +} | |
Binary file not shown.
| @@ -0,0 +1,50 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Thrown when a serious I/O error has occurred. | |
| 30 | + * | |
| 31 | + * @author Xueming Shen | |
| 32 | + * @since 1.6 | |
| 33 | + */ | |
| 34 | +public class IOError extends Error { | |
| 35 | + /** | |
| 36 | + * Constructs a new instance of IOError with the specified cause. The | |
| 37 | + * IOError is created with the detail message of | |
| 38 | + * <tt>(cause==null ? null : cause.toString())</tt> (which typically | |
| 39 | + * contains the class and detail message of cause). | |
| 40 | + * | |
| 41 | + * @param cause | |
| 42 | + * The cause of this error, or <tt>null</tt> if the cause | |
| 43 | + * is not known | |
| 44 | + */ | |
| 45 | + public IOError(Throwable cause) { | |
| 46 | + super(cause); | |
| 47 | + } | |
| 48 | + | |
| 49 | + private static final long serialVersionUID = 67100927991680413L; | |
| 50 | +} | |
Binary file not shown.
| @@ -0,0 +1,101 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Signals that an I/O exception of some sort has occurred. This | |
| 30 | + * class is the general class of exceptions produced by failed or | |
| 31 | + * interrupted I/O operations. | |
| 32 | + * | |
| 33 | + * @author unascribed | |
| 34 | + * @see java.io.InputStream | |
| 35 | + * @see java.io.OutputStream | |
| 36 | + * @since JDK1.0 | |
| 37 | + */ | |
| 38 | +public | |
| 39 | +class IOException extends Exception { | |
| 40 | + static final long serialVersionUID = 7818375828146090155L; | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * Constructs an {@code IOException} with {@code null} | |
| 44 | + * as its error detail message. | |
| 45 | + */ | |
| 46 | + public IOException() { | |
| 47 | + super(); | |
| 48 | + } | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Constructs an {@code IOException} with the specified detail message. | |
| 52 | + * | |
| 53 | + * @param message | |
| 54 | + * The detail message (which is saved for later retrieval | |
| 55 | + * by the {@link #getMessage()} method) | |
| 56 | + */ | |
| 57 | + public IOException(String message) { | |
| 58 | + super(message); | |
| 59 | + } | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * Constructs an {@code IOException} with the specified detail message | |
| 63 | + * and cause. | |
| 64 | + * | |
| 65 | + * <p> Note that the detail message associated with {@code cause} is | |
| 66 | + * <i>not</i> automatically incorporated into this exception's detail | |
| 67 | + * message. | |
| 68 | + * | |
| 69 | + * @param message | |
| 70 | + * The detail message (which is saved for later retrieval | |
| 71 | + * by the {@link #getMessage()} method) | |
| 72 | + * | |
| 73 | + * @param cause | |
| 74 | + * The cause (which is saved for later retrieval by the | |
| 75 | + * {@link #getCause()} method). (A null value is permitted, | |
| 76 | + * and indicates that the cause is nonexistent or unknown.) | |
| 77 | + * | |
| 78 | + * @since 1.6 | |
| 79 | + */ | |
| 80 | + public IOException(String message, Throwable cause) { | |
| 81 | + super(message, cause); | |
| 82 | + } | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * Constructs an {@code IOException} with the specified cause and a | |
| 86 | + * detail message of {@code (cause==null ? null : cause.toString())} | |
| 87 | + * (which typically contains the class and detail message of {@code cause}). | |
| 88 | + * This constructor is useful for IO exceptions that are little more | |
| 89 | + * than wrappers for other throwables. | |
| 90 | + * | |
| 91 | + * @param cause | |
| 92 | + * The cause (which is saved for later retrieval by the | |
| 93 | + * {@link #getCause()} method). (A null value is permitted, | |
| 94 | + * and indicates that the cause is nonexistent or unknown.) | |
| 95 | + * | |
| 96 | + * @since 1.6 | |
| 97 | + */ | |
| 98 | + public IOException(Throwable cause) { | |
| 99 | + super(cause); | |
| 100 | + } | |
| 101 | +} | |
Binary file not shown.
| @@ -0,0 +1,370 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This abstract class is the superclass of all classes representing | |
| 30 | + * an input stream of bytes. | |
| 31 | + * | |
| 32 | + * <p> Applications that need to define a subclass of <code>InputStream</code> | |
| 33 | + * must always provide a method that returns the next byte of input. | |
| 34 | + * | |
| 35 | + * @author Arthur van Hoff | |
| 36 | + * @see java.io.BufferedInputStream | |
| 37 | + * @see java.io.ByteArrayInputStream | |
| 38 | + * @see java.io.DataInputStream | |
| 39 | + * @see java.io.FilterInputStream | |
| 40 | + * @see java.io.InputStream#read() | |
| 41 | + * @see java.io.OutputStream | |
| 42 | + * @see java.io.PushbackInputStream | |
| 43 | + * @since JDK1.0 | |
| 44 | + */ | |
| 45 | +public abstract class InputStream implements Closeable { | |
| 46 | + | |
| 47 | + // SKIP_BUFFER_SIZE is used to determine the size of skipBuffer | |
| 48 | + private static final int SKIP_BUFFER_SIZE = 2048; | |
| 49 | + // skipBuffer is initialized in skip(long), if needed. | |
| 50 | + private static byte[] skipBuffer; | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * Reads the next byte of data from the input stream. The value byte is | |
| 54 | + * returned as an <code>int</code> in the range <code>0</code> to | |
| 55 | + * <code>255</code>. If no byte is available because the end of the stream | |
| 56 | + * has been reached, the value <code>-1</code> is returned. This method | |
| 57 | + * blocks until input data is available, the end of the stream is detected, | |
| 58 | + * or an exception is thrown. | |
| 59 | + * | |
| 60 | + * <p> A subclass must provide an implementation of this method. | |
| 61 | + * | |
| 62 | + * @return the next byte of data, or <code>-1</code> if the end of the | |
| 63 | + * stream is reached. | |
| 64 | + * @exception IOException if an I/O error occurs. | |
| 65 | + */ | |
| 66 | + public abstract int read() throws IOException; | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * Reads some number of bytes from the input stream and stores them into | |
| 70 | + * the buffer array <code>b</code>. The number of bytes actually read is | |
| 71 | + * returned as an integer. This method blocks until input data is | |
| 72 | + * available, end of file is detected, or an exception is thrown. | |
| 73 | + * | |
| 74 | + * <p> If the length of <code>b</code> is zero, then no bytes are read and | |
| 75 | + * <code>0</code> is returned; otherwise, there is an attempt to read at | |
| 76 | + * least one byte. If no byte is available because the stream is at the | |
| 77 | + * end of the file, the value <code>-1</code> is returned; otherwise, at | |
| 78 | + * least one byte is read and stored into <code>b</code>. | |
| 79 | + * | |
| 80 | + * <p> The first byte read is stored into element <code>b[0]</code>, the | |
| 81 | + * next one into <code>b[1]</code>, and so on. The number of bytes read is, | |
| 82 | + * at most, equal to the length of <code>b</code>. Let <i>k</i> be the | |
| 83 | + * number of bytes actually read; these bytes will be stored in elements | |
| 84 | + * <code>b[0]</code> through <code>b[</code><i>k</i><code>-1]</code>, | |
| 85 | + * leaving elements <code>b[</code><i>k</i><code>]</code> through | |
| 86 | + * <code>b[b.length-1]</code> unaffected. | |
| 87 | + * | |
| 88 | + * <p> The <code>read(b)</code> method for class <code>InputStream</code> | |
| 89 | + * has the same effect as: <pre><code> read(b, 0, b.length) </code></pre> | |
| 90 | + * | |
| 91 | + * @param b the buffer into which the data is read. | |
| 92 | + * @return the total number of bytes read into the buffer, or | |
| 93 | + * <code>-1</code> if there is no more data because the end of | |
| 94 | + * the stream has been reached. | |
| 95 | + * @exception IOException If the first byte cannot be read for any reason | |
| 96 | + * other than the end of the file, if the input stream has been closed, or | |
| 97 | + * if some other I/O error occurs. | |
| 98 | + * @exception NullPointerException if <code>b</code> is <code>null</code>. | |
| 99 | + * @see java.io.InputStream#read(byte[], int, int) | |
| 100 | + */ | |
| 101 | + public int read(byte b[]) throws IOException { | |
| 102 | + return read(b, 0, b.length); | |
| 103 | + } | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * Reads up to <code>len</code> bytes of data from the input stream into | |
| 107 | + * an array of bytes. An attempt is made to read as many as | |
| 108 | + * <code>len</code> bytes, but a smaller number may be read. | |
| 109 | + * The number of bytes actually read is returned as an integer. | |
| 110 | + * | |
| 111 | + * <p> This method blocks until input data is available, end of file is | |
| 112 | + * detected, or an exception is thrown. | |
| 113 | + * | |
| 114 | + * <p> If <code>len</code> is zero, then no bytes are read and | |
| 115 | + * <code>0</code> is returned; otherwise, there is an attempt to read at | |
| 116 | + * least one byte. If no byte is available because the stream is at end of | |
| 117 | + * file, the value <code>-1</code> is returned; otherwise, at least one | |
| 118 | + * byte is read and stored into <code>b</code>. | |
| 119 | + * | |
| 120 | + * <p> The first byte read is stored into element <code>b[off]</code>, the | |
| 121 | + * next one into <code>b[off+1]</code>, and so on. The number of bytes read | |
| 122 | + * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of | |
| 123 | + * bytes actually read; these bytes will be stored in elements | |
| 124 | + * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>, | |
| 125 | + * leaving elements <code>b[off+</code><i>k</i><code>]</code> through | |
| 126 | + * <code>b[off+len-1]</code> unaffected. | |
| 127 | + * | |
| 128 | + * <p> In every case, elements <code>b[0]</code> through | |
| 129 | + * <code>b[off]</code> and elements <code>b[off+len]</code> through | |
| 130 | + * <code>b[b.length-1]</code> are unaffected. | |
| 131 | + * | |
| 132 | + * <p> The <code>read(b,</code> <code>off,</code> <code>len)</code> method | |
| 133 | + * for class <code>InputStream</code> simply calls the method | |
| 134 | + * <code>read()</code> repeatedly. If the first such call results in an | |
| 135 | + * <code>IOException</code>, that exception is returned from the call to | |
| 136 | + * the <code>read(b,</code> <code>off,</code> <code>len)</code> method. If | |
| 137 | + * any subsequent call to <code>read()</code> results in a | |
| 138 | + * <code>IOException</code>, the exception is caught and treated as if it | |
| 139 | + * were end of file; the bytes read up to that point are stored into | |
| 140 | + * <code>b</code> and the number of bytes read before the exception | |
| 141 | + * occurred is returned. The default implementation of this method blocks | |
| 142 | + * until the requested amount of input data <code>len</code> has been read, | |
| 143 | + * end of file is detected, or an exception is thrown. Subclasses are encouraged | |
| 144 | + * to provide a more efficient implementation of this method. | |
| 145 | + * | |
| 146 | + * @param b the buffer into which the data is read. | |
| 147 | + * @param off the start offset in array <code>b</code> | |
| 148 | + * at which the data is written. | |
| 149 | + * @param len the maximum number of bytes to read. | |
| 150 | + * @return the total number of bytes read into the buffer, or | |
| 151 | + * <code>-1</code> if there is no more data because the end of | |
| 152 | + * the stream has been reached. | |
| 153 | + * @exception IOException If the first byte cannot be read for any reason | |
| 154 | + * other than end of file, or if the input stream has been closed, or if | |
| 155 | + * some other I/O error occurs. | |
| 156 | + * @exception NullPointerException If <code>b</code> is <code>null</code>. | |
| 157 | + * @exception IndexOutOfBoundsException If <code>off</code> is negative, | |
| 158 | + * <code>len</code> is negative, or <code>len</code> is greater than | |
| 159 | + * <code>b.length - off</code> | |
| 160 | + * @see java.io.InputStream#read() | |
| 161 | + */ | |
| 162 | + public int read(byte b[], int off, int len) throws IOException { | |
| 163 | + if (b == null) { | |
| 164 | + throw new NullPointerException(); | |
| 165 | + } else if (off < 0 || len < 0 || len > b.length - off) { | |
| 166 | + throw new IndexOutOfBoundsException(); | |
| 167 | + } else if (len == 0) { | |
| 168 | + return 0; | |
| 169 | + } | |
| 170 | + | |
| 171 | + int c = read(); | |
| 172 | + if (c == -1) { | |
| 173 | + return -1; | |
| 174 | + } | |
| 175 | + b[off] = (byte)c; | |
| 176 | + | |
| 177 | + int i = 1; | |
| 178 | + try { | |
| 179 | + for (; i < len ; i++) { | |
| 180 | + c = read(); | |
| 181 | + if (c == -1) { | |
| 182 | + break; | |
| 183 | + } | |
| 184 | + b[off + i] = (byte)c; | |
| 185 | + } | |
| 186 | + } catch (IOException ee) { | |
| 187 | + } | |
| 188 | + return i; | |
| 189 | + } | |
| 190 | + | |
| 191 | + /** | |
| 192 | + * Skips over and discards <code>n</code> bytes of data from this input | |
| 193 | + * stream. The <code>skip</code> method may, for a variety of reasons, end | |
| 194 | + * up skipping over some smaller number of bytes, possibly <code>0</code>. | |
| 195 | + * This may result from any of a number of conditions; reaching end of file | |
| 196 | + * before <code>n</code> bytes have been skipped is only one possibility. | |
| 197 | + * The actual number of bytes skipped is returned. If <code>n</code> is | |
| 198 | + * negative, no bytes are skipped. | |
| 199 | + * | |
| 200 | + * <p> The <code>skip</code> method of this class creates a | |
| 201 | + * byte array and then repeatedly reads into it until <code>n</code> bytes | |
| 202 | + * have been read or the end of the stream has been reached. Subclasses are | |
| 203 | + * encouraged to provide a more efficient implementation of this method. | |
| 204 | + * For instance, the implementation may depend on the ability to seek. | |
| 205 | + * | |
| 206 | + * @param n the number of bytes to be skipped. | |
| 207 | + * @return the actual number of bytes skipped. | |
| 208 | + * @exception IOException if the stream does not support seek, | |
| 209 | + * or if some other I/O error occurs. | |
| 210 | + */ | |
| 211 | + public long skip(long n) throws IOException { | |
| 212 | + | |
| 213 | + long remaining = n; | |
| 214 | + int nr; | |
| 215 | + if (skipBuffer == null) | |
| 216 | + skipBuffer = new byte[SKIP_BUFFER_SIZE]; | |
| 217 | + | |
| 218 | + byte[] localSkipBuffer = skipBuffer; | |
| 219 | + | |
| 220 | + if (n <= 0) { | |
| 221 | + return 0; | |
| 222 | + } | |
| 223 | + | |
| 224 | + while (remaining > 0) { | |
| 225 | + nr = read(localSkipBuffer, 0, | |
| 226 | + (int) Math.min(SKIP_BUFFER_SIZE, remaining)); | |
| 227 | + if (nr < 0) { | |
| 228 | + break; | |
| 229 | + } | |
| 230 | + remaining -= nr; | |
| 231 | + } | |
| 232 | + | |
| 233 | + return n - remaining; | |
| 234 | + } | |
| 235 | + | |
| 236 | + /** | |
| 237 | + * Returns an estimate of the number of bytes that can be read (or | |
| 238 | + * skipped over) from this input stream without blocking by the next | |
| 239 | + * invocation of a method for this input stream. The next invocation | |
| 240 | + * might be the same thread or another thread. A single read or skip of this | |
| 241 | + * many bytes will not block, but may read or skip fewer bytes. | |
| 242 | + * | |
| 243 | + * <p> Note that while some implementations of {@code InputStream} will return | |
| 244 | + * the total number of bytes in the stream, many will not. It is | |
| 245 | + * never correct to use the return value of this method to allocate | |
| 246 | + * a buffer intended to hold all data in this stream. | |
| 247 | + * | |
| 248 | + * <p> A subclass' implementation of this method may choose to throw an | |
| 249 | + * {@link IOException} if this input stream has been closed by | |
| 250 | + * invoking the {@link #close()} method. | |
| 251 | + * | |
| 252 | + * <p> The {@code available} method for class {@code InputStream} always | |
| 253 | + * returns {@code 0}. | |
| 254 | + * | |
| 255 | + * <p> This method should be overridden by subclasses. | |
| 256 | + * | |
| 257 | + * @return an estimate of the number of bytes that can be read (or skipped | |
| 258 | + * over) from this input stream without blocking or {@code 0} when | |
| 259 | + * it reaches the end of the input stream. | |
| 260 | + * @exception IOException if an I/O error occurs. | |
| 261 | + */ | |
| 262 | + public int available() throws IOException { | |
| 263 | + return 0; | |
| 264 | + } | |
| 265 | + | |
| 266 | + /** | |
| 267 | + * Closes this input stream and releases any system resources associated | |
| 268 | + * with the stream. | |
| 269 | + * | |
| 270 | + * <p> The <code>close</code> method of <code>InputStream</code> does | |
| 271 | + * nothing. | |
| 272 | + * | |
| 273 | + * @exception IOException if an I/O error occurs. | |
| 274 | + */ | |
| 275 | + public void close() throws IOException {} | |
| 276 | + | |
| 277 | + /** | |
| 278 | + * Marks the current position in this input stream. A subsequent call to | |
| 279 | + * the <code>reset</code> method repositions this stream at the last marked | |
| 280 | + * position so that subsequent reads re-read the same bytes. | |
| 281 | + * | |
| 282 | + * <p> The <code>readlimit</code> arguments tells this input stream to | |
| 283 | + * allow that many bytes to be read before the mark position gets | |
| 284 | + * invalidated. | |
| 285 | + * | |
| 286 | + * <p> The general contract of <code>mark</code> is that, if the method | |
| 287 | + * <code>markSupported</code> returns <code>true</code>, the stream somehow | |
| 288 | + * remembers all the bytes read after the call to <code>mark</code> and | |
| 289 | + * stands ready to supply those same bytes again if and whenever the method | |
| 290 | + * <code>reset</code> is called. However, the stream is not required to | |
| 291 | + * remember any data at all if more than <code>readlimit</code> bytes are | |
| 292 | + * read from the stream before <code>reset</code> is called. | |
| 293 | + * | |
| 294 | + * <p> Marking a closed stream should not have any effect on the stream. | |
| 295 | + * | |
| 296 | + * <p> The <code>mark</code> method of <code>InputStream</code> does | |
| 297 | + * nothing. | |
| 298 | + * | |
| 299 | + * @param readlimit the maximum limit of bytes that can be read before | |
| 300 | + * the mark position becomes invalid. | |
| 301 | + * @see java.io.InputStream#reset() | |
| 302 | + */ | |
| 303 | + public synchronized void mark(int readlimit) {} | |
| 304 | + | |
| 305 | + /** | |
| 306 | + * Repositions this stream to the position at the time the | |
| 307 | + * <code>mark</code> method was last called on this input stream. | |
| 308 | + * | |
| 309 | + * <p> The general contract of <code>reset</code> is: | |
| 310 | + * | |
| 311 | + * <p><ul> | |
| 312 | + * | |
| 313 | + * <li> If the method <code>markSupported</code> returns | |
| 314 | + * <code>true</code>, then: | |
| 315 | + * | |
| 316 | + * <ul><li> If the method <code>mark</code> has not been called since | |
| 317 | + * the stream was created, or the number of bytes read from the stream | |
| 318 | + * since <code>mark</code> was last called is larger than the argument | |
| 319 | + * to <code>mark</code> at that last call, then an | |
| 320 | + * <code>IOException</code> might be thrown. | |
| 321 | + * | |
| 322 | + * <li> If such an <code>IOException</code> is not thrown, then the | |
| 323 | + * stream is reset to a state such that all the bytes read since the | |
| 324 | + * most recent call to <code>mark</code> (or since the start of the | |
| 325 | + * file, if <code>mark</code> has not been called) will be resupplied | |
| 326 | + * to subsequent callers of the <code>read</code> method, followed by | |
| 327 | + * any bytes that otherwise would have been the next input data as of | |
| 328 | + * the time of the call to <code>reset</code>. </ul> | |
| 329 | + * | |
| 330 | + * <li> If the method <code>markSupported</code> returns | |
| 331 | + * <code>false</code>, then: | |
| 332 | + * | |
| 333 | + * <ul><li> The call to <code>reset</code> may throw an | |
| 334 | + * <code>IOException</code>. | |
| 335 | + * | |
| 336 | + * <li> If an <code>IOException</code> is not thrown, then the stream | |
| 337 | + * is reset to a fixed state that depends on the particular type of the | |
| 338 | + * input stream and how it was created. The bytes that will be supplied | |
| 339 | + * to subsequent callers of the <code>read</code> method depend on the | |
| 340 | + * particular type of the input stream. </ul></ul> | |
| 341 | + * | |
| 342 | + * <p>The method <code>reset</code> for class <code>InputStream</code> | |
| 343 | + * does nothing except throw an <code>IOException</code>. | |
| 344 | + * | |
| 345 | + * @exception IOException if this stream has not been marked or if the | |
| 346 | + * mark has been invalidated. | |
| 347 | + * @see java.io.InputStream#mark(int) | |
| 348 | + * @see java.io.IOException | |
| 349 | + */ | |
| 350 | + public synchronized void reset() throws IOException { | |
| 351 | + throw new IOException("mark/reset not supported"); | |
| 352 | + } | |
| 353 | + | |
| 354 | + /** | |
| 355 | + * Tests if this input stream supports the <code>mark</code> and | |
| 356 | + * <code>reset</code> methods. Whether or not <code>mark</code> and | |
| 357 | + * <code>reset</code> are supported is an invariant property of a | |
| 358 | + * particular input stream instance. The <code>markSupported</code> method | |
| 359 | + * of <code>InputStream</code> returns <code>false</code>. | |
| 360 | + * | |
| 361 | + * @return <code>true</code> if this stream instance supports the mark | |
| 362 | + * and reset methods; <code>false</code> otherwise. | |
| 363 | + * @see java.io.InputStream#mark(int) | |
| 364 | + * @see java.io.InputStream#reset() | |
| 365 | + */ | |
| 366 | + public boolean markSupported() { | |
| 367 | + return false; | |
| 368 | + } | |
| 369 | + | |
| 370 | +} | |
Binary file not shown.
| @@ -0,0 +1,201 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.nio.charset.Charset; | |
| 29 | +import java.nio.charset.CharsetDecoder; | |
| 30 | +import sun.nio.cs.StreamDecoder; | |
| 31 | + | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * An InputStreamReader is a bridge from byte streams to character streams: It | |
| 35 | + * reads bytes and decodes them into characters using a specified {@link | |
| 36 | + * java.nio.charset.Charset <code>charset</code>}. The charset that it uses | |
| 37 | + * may be specified by name or may be given explicitly, or the platform's | |
| 38 | + * default charset may be accepted. | |
| 39 | + * | |
| 40 | + * <p> Each invocation of one of an InputStreamReader's read() methods may | |
| 41 | + * cause one or more bytes to be read from the underlying byte-input stream. | |
| 42 | + * To enable the efficient conversion of bytes to characters, more bytes may | |
| 43 | + * be read ahead from the underlying stream than are necessary to satisfy the | |
| 44 | + * current read operation. | |
| 45 | + * | |
| 46 | + * <p> For top efficiency, consider wrapping an InputStreamReader within a | |
| 47 | + * BufferedReader. For example: | |
| 48 | + * | |
| 49 | + * <pre> | |
| 50 | + * BufferedReader in | |
| 51 | + * = new BufferedReader(new InputStreamReader(System.in)); | |
| 52 | + * </pre> | |
| 53 | + * | |
| 54 | + * @see BufferedReader | |
| 55 | + * @see InputStream | |
| 56 | + * @see java.nio.charset.Charset | |
| 57 | + * | |
| 58 | + * @author Mark Reinhold | |
| 59 | + * @since JDK1.1 | |
| 60 | + */ | |
| 61 | + | |
| 62 | +public class InputStreamReader extends Reader { | |
| 63 | + | |
| 64 | + private final StreamDecoder sd; | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Creates an InputStreamReader that uses the default charset. | |
| 68 | + * | |
| 69 | + * @param in An InputStream | |
| 70 | + */ | |
| 71 | + public InputStreamReader(InputStream in) { | |
| 72 | + super(in); | |
| 73 | + try { | |
| 74 | + sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object | |
| 75 | + } catch (UnsupportedEncodingException e) { | |
| 76 | + // The default encoding should always be available | |
| 77 | + throw new Error(e); | |
| 78 | + } | |
| 79 | + } | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * Creates an InputStreamReader that uses the named charset. | |
| 83 | + * | |
| 84 | + * @param in | |
| 85 | + * An InputStream | |
| 86 | + * | |
| 87 | + * @param charsetName | |
| 88 | + * The name of a supported | |
| 89 | + * {@link java.nio.charset.Charset </code>charset<code>} | |
| 90 | + * | |
| 91 | + * @exception UnsupportedEncodingException | |
| 92 | + * If the named charset is not supported | |
| 93 | + */ | |
| 94 | + public InputStreamReader(InputStream in, String charsetName) | |
| 95 | + throws UnsupportedEncodingException | |
| 96 | + { | |
| 97 | + super(in); | |
| 98 | + if (charsetName == null) | |
| 99 | + throw new NullPointerException("charsetName"); | |
| 100 | + sd = StreamDecoder.forInputStreamReader(in, this, charsetName); | |
| 101 | + } | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * Creates an InputStreamReader that uses the given charset. </p> | |
| 105 | + * | |
| 106 | + * @param in An InputStream | |
| 107 | + * @param cs A charset | |
| 108 | + * | |
| 109 | + * @since 1.4 | |
| 110 | + * @spec JSR-51 | |
| 111 | + */ | |
| 112 | + public InputStreamReader(InputStream in, Charset cs) { | |
| 113 | + super(in); | |
| 114 | + if (cs == null) | |
| 115 | + throw new NullPointerException("charset"); | |
| 116 | + sd = StreamDecoder.forInputStreamReader(in, this, cs); | |
| 117 | + } | |
| 118 | + | |
| 119 | + /** | |
| 120 | + * Creates an InputStreamReader that uses the given charset decoder. </p> | |
| 121 | + * | |
| 122 | + * @param in An InputStream | |
| 123 | + * @param dec A charset decoder | |
| 124 | + * | |
| 125 | + * @since 1.4 | |
| 126 | + * @spec JSR-51 | |
| 127 | + */ | |
| 128 | + public InputStreamReader(InputStream in, CharsetDecoder dec) { | |
| 129 | + super(in); | |
| 130 | + if (dec == null) | |
| 131 | + throw new NullPointerException("charset decoder"); | |
| 132 | + sd = StreamDecoder.forInputStreamReader(in, this, dec); | |
| 133 | + } | |
| 134 | + | |
| 135 | + /** | |
| 136 | + * Returns the name of the character encoding being used by this stream. | |
| 137 | + * | |
| 138 | + * <p> If the encoding has an historical name then that name is returned; | |
| 139 | + * otherwise the encoding's canonical name is returned. | |
| 140 | + * | |
| 141 | + * <p> If this instance was created with the {@link | |
| 142 | + * #InputStreamReader(InputStream, String)} constructor then the returned | |
| 143 | + * name, being unique for the encoding, may differ from the name passed to | |
| 144 | + * the constructor. This method will return <code>null</code> if the | |
| 145 | + * stream has been closed. | |
| 146 | + * </p> | |
| 147 | + * @return The historical name of this encoding, or | |
| 148 | + * <code>null</code> if the stream has been closed | |
| 149 | + * | |
| 150 | + * @see java.nio.charset.Charset | |
| 151 | + * | |
| 152 | + * @revised 1.4 | |
| 153 | + * @spec JSR-51 | |
| 154 | + */ | |
| 155 | + public String getEncoding() { | |
| 156 | + return sd.getEncoding(); | |
| 157 | + } | |
| 158 | + | |
| 159 | + /** | |
| 160 | + * Reads a single character. | |
| 161 | + * | |
| 162 | + * @return The character read, or -1 if the end of the stream has been | |
| 163 | + * reached | |
| 164 | + * | |
| 165 | + * @exception IOException If an I/O error occurs | |
| 166 | + */ | |
| 167 | + public int read() throws IOException { | |
| 168 | + return sd.read(); | |
| 169 | + } | |
| 170 | + | |
| 171 | + /** | |
| 172 | + * Reads characters into a portion of an array. | |
| 173 | + * | |
| 174 | + * @param cbuf Destination buffer | |
| 175 | + * @param offset Offset at which to start storing characters | |
| 176 | + * @param length Maximum number of characters to read | |
| 177 | + * | |
| 178 | + * @return The number of characters read, or -1 if the end of the | |
| 179 | + * stream has been reached | |
| 180 | + * | |
| 181 | + * @exception IOException If an I/O error occurs | |
| 182 | + */ | |
| 183 | + public int read(char cbuf[], int offset, int length) throws IOException { | |
| 184 | + return sd.read(cbuf, offset, length); | |
| 185 | + } | |
| 186 | + | |
| 187 | + /** | |
| 188 | + * Tells whether this stream is ready to be read. An InputStreamReader is | |
| 189 | + * ready if its input buffer is not empty, or if bytes are available to be | |
| 190 | + * read from the underlying byte stream. | |
| 191 | + * | |
| 192 | + * @exception IOException If an I/O error occurs | |
| 193 | + */ | |
| 194 | + public boolean ready() throws IOException { | |
| 195 | + return sd.ready(); | |
| 196 | + } | |
| 197 | + | |
| 198 | + public void close() throws IOException { | |
| 199 | + sd.close(); | |
| 200 | + } | |
| 201 | +} | |
Binary file not shown.
| @@ -0,0 +1,74 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Signals that an I/O operation has been interrupted. An | |
| 30 | + * <code>InterruptedIOException</code> is thrown to indicate that an | |
| 31 | + * input or output transfer has been terminated because the thread | |
| 32 | + * performing it was interrupted. The field {@link #bytesTransferred} | |
| 33 | + * indicates how many bytes were successfully transferred before | |
| 34 | + * the interruption occurred. | |
| 35 | + * | |
| 36 | + * @author unascribed | |
| 37 | + * @see java.io.InputStream | |
| 38 | + * @see java.io.OutputStream | |
| 39 | + * @see java.lang.Thread#interrupt() | |
| 40 | + * @since JDK1.0 | |
| 41 | + */ | |
| 42 | +public | |
| 43 | +class InterruptedIOException extends IOException { | |
| 44 | + private static final long serialVersionUID = 4020568460727500567L; | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * Constructs an <code>InterruptedIOException</code> with | |
| 48 | + * <code>null</code> as its error detail message. | |
| 49 | + */ | |
| 50 | + public InterruptedIOException() { | |
| 51 | + super(); | |
| 52 | + } | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * Constructs an <code>InterruptedIOException</code> with the | |
| 56 | + * specified detail message. The string <code>s</code> can be | |
| 57 | + * retrieved later by the | |
| 58 | + * <code>{@link java.lang.Throwable#getMessage}</code> | |
| 59 | + * method of class <code>java.lang.Throwable</code>. | |
| 60 | + * | |
| 61 | + * @param s the detail message. | |
| 62 | + */ | |
| 63 | + public InterruptedIOException(String s) { | |
| 64 | + super(s); | |
| 65 | + } | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * Reports how many bytes had been transferred as part of the I/O | |
| 69 | + * operation before it was interrupted. | |
| 70 | + * | |
| 71 | + * @serial | |
| 72 | + */ | |
| 73 | + public int bytesTransferred = 0; | |
| 74 | +} | |
Binary file not shown.
| @@ -0,0 +1,81 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Thrown when the Serialization runtime detects one of the following | |
| 30 | + * problems with a Class. | |
| 31 | + * <UL> | |
| 32 | + * <LI> The serial version of the class does not match that of the class | |
| 33 | + * descriptor read from the stream | |
| 34 | + * <LI> The class contains unknown datatypes | |
| 35 | + * <LI> The class does not have an accessible no-arg constructor | |
| 36 | + * </UL> | |
| 37 | + * | |
| 38 | + * @author unascribed | |
| 39 | + * @since JDK1.1 | |
| 40 | + */ | |
| 41 | +public class InvalidClassException extends ObjectStreamException { | |
| 42 | + | |
| 43 | + private static final long serialVersionUID = -4333316296251054416L; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * Name of the invalid class. | |
| 47 | + * | |
| 48 | + * @serial Name of the invalid class. | |
| 49 | + */ | |
| 50 | + public String classname; | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * Report an InvalidClassException for the reason specified. | |
| 54 | + * | |
| 55 | + * @param reason String describing the reason for the exception. | |
| 56 | + */ | |
| 57 | + public InvalidClassException(String reason) { | |
| 58 | + super(reason); | |
| 59 | + } | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * Constructs an InvalidClassException object. | |
| 63 | + * | |
| 64 | + * @param cname a String naming the invalid class. | |
| 65 | + * @param reason a String describing the reason for the exception. | |
| 66 | + */ | |
| 67 | + public InvalidClassException(String cname, String reason) { | |
| 68 | + super(reason); | |
| 69 | + classname = cname; | |
| 70 | + } | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * Produce the message and include the classname, if present. | |
| 74 | + */ | |
| 75 | + public String getMessage() { | |
| 76 | + if (classname == null) | |
| 77 | + return super.getMessage(); | |
| 78 | + else | |
| 79 | + return classname + "; " + super.getMessage(); | |
| 80 | + } | |
| 81 | +} | |
Binary file not shown.
| @@ -0,0 +1,51 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Indicates that one or more deserialized objects failed validation | |
| 30 | + * tests. The argument should provide the reason for the failure. | |
| 31 | + * | |
| 32 | + * @see ObjectInputValidation | |
| 33 | + * @since JDK1.1 | |
| 34 | + * | |
| 35 | + * @author unascribed | |
| 36 | + * @since JDK1.1 | |
| 37 | + */ | |
| 38 | +public class InvalidObjectException extends ObjectStreamException { | |
| 39 | + | |
| 40 | + private static final long serialVersionUID = 3233174318281839583L; | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * Constructs an <code>InvalidObjectException</code>. | |
| 44 | + * @param reason Detailed message explaining the reason for the failure. | |
| 45 | + * | |
| 46 | + * @see ObjectInputValidation | |
| 47 | + */ | |
| 48 | + public InvalidObjectException(String reason) { | |
| 49 | + super(reason); | |
| 50 | + } | |
| 51 | +} | |
Binary file not shown.
| @@ -0,0 +1,292 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class is an input stream filter that provides the added | |
| 30 | + * functionality of keeping track of the current line number. | |
| 31 | + * <p> | |
| 32 | + * A line is a sequence of bytes ending with a carriage return | |
| 33 | + * character (<code>'\r'</code>), a newline character | |
| 34 | + * (<code>'\n'</code>), or a carriage return character followed | |
| 35 | + * immediately by a linefeed character. In all three cases, the line | |
| 36 | + * terminating character(s) are returned as a single newline character. | |
| 37 | + * <p> | |
| 38 | + * The line number begins at <code>0</code>, and is incremented by | |
| 39 | + * <code>1</code> when a <code>read</code> returns a newline character. | |
| 40 | + * | |
| 41 | + * @author Arthur van Hoff | |
| 42 | + * @see java.io.LineNumberReader | |
| 43 | + * @since JDK1.0 | |
| 44 | + * @deprecated This class incorrectly assumes that bytes adequately represent | |
| 45 | + * characters. As of JDK 1.1, the preferred way to operate on | |
| 46 | + * character streams is via the new character-stream classes, which | |
| 47 | + * include a class for counting line numbers. | |
| 48 | + */ | |
| 49 | +@Deprecated | |
| 50 | +public | |
| 51 | +class LineNumberInputStream extends FilterInputStream { | |
| 52 | + int pushBack = -1; | |
| 53 | + int lineNumber; | |
| 54 | + int markLineNumber; | |
| 55 | + int markPushBack = -1; | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * Constructs a newline number input stream that reads its input | |
| 59 | + * from the specified input stream. | |
| 60 | + * | |
| 61 | + * @param in the underlying input stream. | |
| 62 | + */ | |
| 63 | + public LineNumberInputStream(InputStream in) { | |
| 64 | + super(in); | |
| 65 | + } | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * Reads the next byte of data from this input stream. The value | |
| 69 | + * byte is returned as an <code>int</code> in the range | |
| 70 | + * <code>0</code> to <code>255</code>. If no byte is available | |
| 71 | + * because the end of the stream has been reached, the value | |
| 72 | + * <code>-1</code> is returned. This method blocks until input data | |
| 73 | + * is available, the end of the stream is detected, or an exception | |
| 74 | + * is thrown. | |
| 75 | + * <p> | |
| 76 | + * The <code>read</code> method of | |
| 77 | + * <code>LineNumberInputStream</code> calls the <code>read</code> | |
| 78 | + * method of the underlying input stream. It checks for carriage | |
| 79 | + * returns and newline characters in the input, and modifies the | |
| 80 | + * current line number as appropriate. A carriage-return character or | |
| 81 | + * a carriage return followed by a newline character are both | |
| 82 | + * converted into a single newline character. | |
| 83 | + * | |
| 84 | + * @return the next byte of data, or <code>-1</code> if the end of this | |
| 85 | + * stream is reached. | |
| 86 | + * @exception IOException if an I/O error occurs. | |
| 87 | + * @see java.io.FilterInputStream#in | |
| 88 | + * @see java.io.LineNumberInputStream#getLineNumber() | |
| 89 | + */ | |
| 90 | + public int read() throws IOException { | |
| 91 | + int c = pushBack; | |
| 92 | + | |
| 93 | + if (c != -1) { | |
| 94 | + pushBack = -1; | |
| 95 | + } else { | |
| 96 | + c = in.read(); | |
| 97 | + } | |
| 98 | + | |
| 99 | + switch (c) { | |
| 100 | + case '\r': | |
| 101 | + pushBack = in.read(); | |
| 102 | + if (pushBack == '\n') { | |
| 103 | + pushBack = -1; | |
| 104 | + } | |
| 105 | + case '\n': | |
| 106 | + lineNumber++; | |
| 107 | + return '\n'; | |
| 108 | + } | |
| 109 | + return c; | |
| 110 | + } | |
| 111 | + | |
| 112 | + /** | |
| 113 | + * Reads up to <code>len</code> bytes of data from this input stream | |
| 114 | + * into an array of bytes. This method blocks until some input is available. | |
| 115 | + * <p> | |
| 116 | + * The <code>read</code> method of | |
| 117 | + * <code>LineNumberInputStream</code> repeatedly calls the | |
| 118 | + * <code>read</code> method of zero arguments to fill in the byte array. | |
| 119 | + * | |
| 120 | + * @param b the buffer into which the data is read. | |
| 121 | + * @param off the start offset of the data. | |
| 122 | + * @param len the maximum number of bytes read. | |
| 123 | + * @return the total number of bytes read into the buffer, or | |
| 124 | + * <code>-1</code> if there is no more data because the end of | |
| 125 | + * this stream has been reached. | |
| 126 | + * @exception IOException if an I/O error occurs. | |
| 127 | + * @see java.io.LineNumberInputStream#read() | |
| 128 | + */ | |
| 129 | + public int read(byte b[], int off, int len) throws IOException { | |
| 130 | + if (b == null) { | |
| 131 | + throw new NullPointerException(); | |
| 132 | + } else if ((off < 0) || (off > b.length) || (len < 0) || | |
| 133 | + ((off + len) > b.length) || ((off + len) < 0)) { | |
| 134 | + throw new IndexOutOfBoundsException(); | |
| 135 | + } else if (len == 0) { | |
| 136 | + return 0; | |
| 137 | + } | |
| 138 | + | |
| 139 | + int c = read(); | |
| 140 | + if (c == -1) { | |
| 141 | + return -1; | |
| 142 | + } | |
| 143 | + b[off] = (byte)c; | |
| 144 | + | |
| 145 | + int i = 1; | |
| 146 | + try { | |
| 147 | + for (; i < len ; i++) { | |
| 148 | + c = read(); | |
| 149 | + if (c == -1) { | |
| 150 | + break; | |
| 151 | + } | |
| 152 | + if (b != null) { | |
| 153 | + b[off + i] = (byte)c; | |
| 154 | + } | |
| 155 | + } | |
| 156 | + } catch (IOException ee) { | |
| 157 | + } | |
| 158 | + return i; | |
| 159 | + } | |
| 160 | + | |
| 161 | + /** | |
| 162 | + * Skips over and discards <code>n</code> bytes of data from this | |
| 163 | + * input stream. The <code>skip</code> method may, for a variety of | |
| 164 | + * reasons, end up skipping over some smaller number of bytes, | |
| 165 | + * possibly <code>0</code>. The actual number of bytes skipped is | |
| 166 | + * returned. If <code>n</code> is negative, no bytes are skipped. | |
| 167 | + * <p> | |
| 168 | + * The <code>skip</code> method of <code>LineNumberInputStream</code> creates | |
| 169 | + * a byte array and then repeatedly reads into it until | |
| 170 | + * <code>n</code> bytes have been read or the end of the stream has | |
| 171 | + * been reached. | |
| 172 | + * | |
| 173 | + * @param n the number of bytes to be skipped. | |
| 174 | + * @return the actual number of bytes skipped. | |
| 175 | + * @exception IOException if an I/O error occurs. | |
| 176 | + * @see java.io.FilterInputStream#in | |
| 177 | + */ | |
| 178 | + public long skip(long n) throws IOException { | |
| 179 | + int chunk = 2048; | |
| 180 | + long remaining = n; | |
| 181 | + byte data[]; | |
| 182 | + int nr; | |
| 183 | + | |
| 184 | + if (n <= 0) { | |
| 185 | + return 0; | |
| 186 | + } | |
| 187 | + | |
| 188 | + data = new byte[chunk]; | |
| 189 | + while (remaining > 0) { | |
| 190 | + nr = read(data, 0, (int) Math.min(chunk, remaining)); | |
| 191 | + if (nr < 0) { | |
| 192 | + break; | |
| 193 | + } | |
| 194 | + remaining -= nr; | |
| 195 | + } | |
| 196 | + | |
| 197 | + return n - remaining; | |
| 198 | + } | |
| 199 | + | |
| 200 | + /** | |
| 201 | + * Sets the line number to the specified argument. | |
| 202 | + * | |
| 203 | + * @param lineNumber the new line number. | |
| 204 | + * @see #getLineNumber | |
| 205 | + */ | |
| 206 | + public void setLineNumber(int lineNumber) { | |
| 207 | + this.lineNumber = lineNumber; | |
| 208 | + } | |
| 209 | + | |
| 210 | + /** | |
| 211 | + * Returns the current line number. | |
| 212 | + * | |
| 213 | + * @return the current line number. | |
| 214 | + * @see #setLineNumber | |
| 215 | + */ | |
| 216 | + public int getLineNumber() { | |
| 217 | + return lineNumber; | |
| 218 | + } | |
| 219 | + | |
| 220 | + | |
| 221 | + /** | |
| 222 | + * Returns the number of bytes that can be read from this input | |
| 223 | + * stream without blocking. | |
| 224 | + * <p> | |
| 225 | + * Note that if the underlying input stream is able to supply | |
| 226 | + * <i>k</i> input characters without blocking, the | |
| 227 | + * <code>LineNumberInputStream</code> can guarantee only to provide | |
| 228 | + * <i>k</i>/2 characters without blocking, because the | |
| 229 | + * <i>k</i> characters from the underlying input stream might | |
| 230 | + * consist of <i>k</i>/2 pairs of <code>'\r'</code> and | |
| 231 | + * <code>'\n'</code>, which are converted to just | |
| 232 | + * <i>k</i>/2 <code>'\n'</code> characters. | |
| 233 | + * | |
| 234 | + * @return the number of bytes that can be read from this input stream | |
| 235 | + * without blocking. | |
| 236 | + * @exception IOException if an I/O error occurs. | |
| 237 | + * @see java.io.FilterInputStream#in | |
| 238 | + */ | |
| 239 | + public int available() throws IOException { | |
| 240 | + return (pushBack == -1) ? super.available()/2 : super.available()/2 + 1; | |
| 241 | + } | |
| 242 | + | |
| 243 | + /** | |
| 244 | + * Marks the current position in this input stream. A subsequent | |
| 245 | + * call to the <code>reset</code> method repositions this stream at | |
| 246 | + * the last marked position so that subsequent reads re-read the same bytes. | |
| 247 | + * <p> | |
| 248 | + * The <code>mark</code> method of | |
| 249 | + * <code>LineNumberInputStream</code> remembers the current line | |
| 250 | + * number in a private variable, and then calls the <code>mark</code> | |
| 251 | + * method of the underlying input stream. | |
| 252 | + * | |
| 253 | + * @param readlimit the maximum limit of bytes that can be read before | |
| 254 | + * the mark position becomes invalid. | |
| 255 | + * @see java.io.FilterInputStream#in | |
| 256 | + * @see java.io.LineNumberInputStream#reset() | |
| 257 | + */ | |
| 258 | + public void mark(int readlimit) { | |
| 259 | + markLineNumber = lineNumber; | |
| 260 | + markPushBack = pushBack; | |
| 261 | + in.mark(readlimit); | |
| 262 | + } | |
| 263 | + | |
| 264 | + /** | |
| 265 | + * Repositions this stream to the position at the time the | |
| 266 | + * <code>mark</code> method was last called on this input stream. | |
| 267 | + * <p> | |
| 268 | + * The <code>reset</code> method of | |
| 269 | + * <code>LineNumberInputStream</code> resets the line number to be | |
| 270 | + * the line number at the time the <code>mark</code> method was | |
| 271 | + * called, and then calls the <code>reset</code> method of the | |
| 272 | + * underlying input stream. | |
| 273 | + * <p> | |
| 274 | + * Stream marks are intended to be used in | |
| 275 | + * situations where you need to read ahead a little to see what's in | |
| 276 | + * the stream. Often this is most easily done by invoking some | |
| 277 | + * general parser. If the stream is of the type handled by the | |
| 278 | + * parser, it just chugs along happily. If the stream is not of | |
| 279 | + * that type, the parser should toss an exception when it fails, | |
| 280 | + * which, if it happens within readlimit bytes, allows the outer | |
| 281 | + * code to reset the stream and try another parser. | |
| 282 | + * | |
| 283 | + * @exception IOException if an I/O error occurs. | |
| 284 | + * @see java.io.FilterInputStream#in | |
| 285 | + * @see java.io.LineNumberInputStream#mark(int) | |
| 286 | + */ | |
| 287 | + public void reset() throws IOException { | |
| 288 | + lineNumber = markLineNumber; | |
| 289 | + pushBack = markPushBack; | |
| 290 | + in.reset(); | |
| 291 | + } | |
| 292 | +} | |
Binary file not shown.
| @@ -0,0 +1,281 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * A buffered character-input stream that keeps track of line numbers. This | |
| 31 | + * class defines methods {@link #setLineNumber(int)} and {@link | |
| 32 | + * #getLineNumber()} for setting and getting the current line number | |
| 33 | + * respectively. | |
| 34 | + * | |
| 35 | + * <p> By default, line numbering begins at 0. This number increments at every | |
| 36 | + * <a href="#lt">line terminator</a> as the data is read, and can be changed | |
| 37 | + * with a call to <tt>setLineNumber(int)</tt>. Note however, that | |
| 38 | + * <tt>setLineNumber(int)</tt> does not actually change the current position in | |
| 39 | + * the stream; it only changes the value that will be returned by | |
| 40 | + * <tt>getLineNumber()</tt>. | |
| 41 | + * | |
| 42 | + * <p> A line is considered to be <a name="lt">terminated</a> by any one of a | |
| 43 | + * line feed ('\n'), a carriage return ('\r'), or a carriage return followed | |
| 44 | + * immediately by a linefeed. | |
| 45 | + * | |
| 46 | + * @author Mark Reinhold | |
| 47 | + * @since JDK1.1 | |
| 48 | + */ | |
| 49 | + | |
| 50 | +public class LineNumberReader extends BufferedReader { | |
| 51 | + | |
| 52 | + /** The current line number */ | |
| 53 | + private int lineNumber = 0; | |
| 54 | + | |
| 55 | + /** The line number of the mark, if any */ | |
| 56 | + private int markedLineNumber; // Defaults to 0 | |
| 57 | + | |
| 58 | + /** If the next character is a line feed, skip it */ | |
| 59 | + private boolean skipLF; | |
| 60 | + | |
| 61 | + /** The skipLF flag when the mark was set */ | |
| 62 | + private boolean markedSkipLF; | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * Create a new line-numbering reader, using the default input-buffer | |
| 66 | + * size. | |
| 67 | + * | |
| 68 | + * @param in | |
| 69 | + * A Reader object to provide the underlying stream | |
| 70 | + */ | |
| 71 | + public LineNumberReader(Reader in) { | |
| 72 | + super(in); | |
| 73 | + } | |
| 74 | + | |
| 75 | + /** | |
| 76 | + * Create a new line-numbering reader, reading characters into a buffer of | |
| 77 | + * the given size. | |
| 78 | + * | |
| 79 | + * @param in | |
| 80 | + * A Reader object to provide the underlying stream | |
| 81 | + * | |
| 82 | + * @param sz | |
| 83 | + * An int specifying the size of the buffer | |
| 84 | + */ | |
| 85 | + public LineNumberReader(Reader in, int sz) { | |
| 86 | + super(in, sz); | |
| 87 | + } | |
| 88 | + | |
| 89 | + /** | |
| 90 | + * Set the current line number. | |
| 91 | + * | |
| 92 | + * @param lineNumber | |
| 93 | + * An int specifying the line number | |
| 94 | + * | |
| 95 | + * @see #getLineNumber | |
| 96 | + */ | |
| 97 | + public void setLineNumber(int lineNumber) { | |
| 98 | + this.lineNumber = lineNumber; | |
| 99 | + } | |
| 100 | + | |
| 101 | + /** | |
| 102 | + * Get the current line number. | |
| 103 | + * | |
| 104 | + * @return The current line number | |
| 105 | + * | |
| 106 | + * @see #setLineNumber | |
| 107 | + */ | |
| 108 | + public int getLineNumber() { | |
| 109 | + return lineNumber; | |
| 110 | + } | |
| 111 | + | |
| 112 | + /** | |
| 113 | + * Read a single character. <a href="#lt">Line terminators</a> are | |
| 114 | + * compressed into single newline ('\n') characters. Whenever a line | |
| 115 | + * terminator is read the current line number is incremented. | |
| 116 | + * | |
| 117 | + * @return The character read, or -1 if the end of the stream has been | |
| 118 | + * reached | |
| 119 | + * | |
| 120 | + * @throws IOException | |
| 121 | + * If an I/O error occurs | |
| 122 | + */ | |
| 123 | + public int read() throws IOException { | |
| 124 | + synchronized (lock) { | |
| 125 | + int c = super.read(); | |
| 126 | + if (skipLF) { | |
| 127 | + if (c == '\n') | |
| 128 | + c = super.read(); | |
| 129 | + skipLF = false; | |
| 130 | + } | |
| 131 | + switch (c) { | |
| 132 | + case '\r': | |
| 133 | + skipLF = true; | |
| 134 | + case '\n': /* Fall through */ | |
| 135 | + lineNumber++; | |
| 136 | + return '\n'; | |
| 137 | + } | |
| 138 | + return c; | |
| 139 | + } | |
| 140 | + } | |
| 141 | + | |
| 142 | + /** | |
| 143 | + * Read characters into a portion of an array. Whenever a <a | |
| 144 | + * href="#lt">line terminator</a> is read the current line number is | |
| 145 | + * incremented. | |
| 146 | + * | |
| 147 | + * @param cbuf | |
| 148 | + * Destination buffer | |
| 149 | + * | |
| 150 | + * @param off | |
| 151 | + * Offset at which to start storing characters | |
| 152 | + * | |
| 153 | + * @param len | |
| 154 | + * Maximum number of characters to read | |
| 155 | + * | |
| 156 | + * @return The number of bytes read, or -1 if the end of the stream has | |
| 157 | + * already been reached | |
| 158 | + * | |
| 159 | + * @throws IOException | |
| 160 | + * If an I/O error occurs | |
| 161 | + */ | |
| 162 | + public int read(char cbuf[], int off, int len) throws IOException { | |
| 163 | + synchronized (lock) { | |
| 164 | + int n = super.read(cbuf, off, len); | |
| 165 | + | |
| 166 | + for (int i = off; i < off + n; i++) { | |
| 167 | + int c = cbuf[i]; | |
| 168 | + if (skipLF) { | |
| 169 | + skipLF = false; | |
| 170 | + if (c == '\n') | |
| 171 | + continue; | |
| 172 | + } | |
| 173 | + switch (c) { | |
| 174 | + case '\r': | |
| 175 | + skipLF = true; | |
| 176 | + case '\n': /* Fall through */ | |
| 177 | + lineNumber++; | |
| 178 | + break; | |
| 179 | + } | |
| 180 | + } | |
| 181 | + | |
| 182 | + return n; | |
| 183 | + } | |
| 184 | + } | |
| 185 | + | |
| 186 | + /** | |
| 187 | + * Read a line of text. Whenever a <a href="#lt">line terminator</a> is | |
| 188 | + * read the current line number is incremented. | |
| 189 | + * | |
| 190 | + * @return A String containing the contents of the line, not including | |
| 191 | + * any <a href="#lt">line termination characters</a>, or | |
| 192 | + * <tt>null</tt> if the end of the stream has been reached | |
| 193 | + * | |
| 194 | + * @throws IOException | |
| 195 | + * If an I/O error occurs | |
| 196 | + */ | |
| 197 | + public String readLine() throws IOException { | |
| 198 | + synchronized (lock) { | |
| 199 | + String l = super.readLine(skipLF); | |
| 200 | + skipLF = false; | |
| 201 | + if (l != null) | |
| 202 | + lineNumber++; | |
| 203 | + return l; | |
| 204 | + } | |
| 205 | + } | |
| 206 | + | |
| 207 | + /** Maximum skip-buffer size */ | |
| 208 | + private static final int maxSkipBufferSize = 8192; | |
| 209 | + | |
| 210 | + /** Skip buffer, null until allocated */ | |
| 211 | + private char skipBuffer[] = null; | |
| 212 | + | |
| 213 | + /** | |
| 214 | + * Skip characters. | |
| 215 | + * | |
| 216 | + * @param n | |
| 217 | + * The number of characters to skip | |
| 218 | + * | |
| 219 | + * @return The number of characters actually skipped | |
| 220 | + * | |
| 221 | + * @throws IOException | |
| 222 | + * If an I/O error occurs | |
| 223 | + * | |
| 224 | + * @throws IllegalArgumentException | |
| 225 | + * If <tt>n</tt> is negative | |
| 226 | + */ | |
| 227 | + public long skip(long n) throws IOException { | |
| 228 | + if (n < 0) | |
| 229 | + throw new IllegalArgumentException("skip() value is negative"); | |
| 230 | + int nn = (int) Math.min(n, maxSkipBufferSize); | |
| 231 | + synchronized (lock) { | |
| 232 | + if ((skipBuffer == null) || (skipBuffer.length < nn)) | |
| 233 | + skipBuffer = new char[nn]; | |
| 234 | + long r = n; | |
| 235 | + while (r > 0) { | |
| 236 | + int nc = read(skipBuffer, 0, (int) Math.min(r, nn)); | |
| 237 | + if (nc == -1) | |
| 238 | + break; | |
| 239 | + r -= nc; | |
| 240 | + } | |
| 241 | + return n - r; | |
| 242 | + } | |
| 243 | + } | |
| 244 | + | |
| 245 | + /** | |
| 246 | + * Mark the present position in the stream. Subsequent calls to reset() | |
| 247 | + * will attempt to reposition the stream to this point, and will also reset | |
| 248 | + * the line number appropriately. | |
| 249 | + * | |
| 250 | + * @param readAheadLimit | |
| 251 | + * Limit on the number of characters that may be read while still | |
| 252 | + * preserving the mark. After reading this many characters, | |
| 253 | + * attempting to reset the stream may fail. | |
| 254 | + * | |
| 255 | + * @throws IOException | |
| 256 | + * If an I/O error occurs | |
| 257 | + */ | |
| 258 | + public void mark(int readAheadLimit) throws IOException { | |
| 259 | + synchronized (lock) { | |
| 260 | + super.mark(readAheadLimit); | |
| 261 | + markedLineNumber = lineNumber; | |
| 262 | + markedSkipLF = skipLF; | |
| 263 | + } | |
| 264 | + } | |
| 265 | + | |
| 266 | + /** | |
| 267 | + * Reset the stream to the most recent mark. | |
| 268 | + * | |
| 269 | + * @throws IOException | |
| 270 | + * If the stream has not been marked, or if the mark has been | |
| 271 | + * invalidated | |
| 272 | + */ | |
| 273 | + public void reset() throws IOException { | |
| 274 | + synchronized (lock) { | |
| 275 | + super.reset(); | |
| 276 | + lineNumber = markedLineNumber; | |
| 277 | + skipLF = markedSkipLF; | |
| 278 | + } | |
| 279 | + } | |
| 280 | + | |
| 281 | +} | |
Binary file not shown.
| @@ -0,0 +1,53 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Thrown when serialization or deserialization is not active. | |
| 30 | + * | |
| 31 | + * @author unascribed | |
| 32 | + * @since JDK1.1 | |
| 33 | + */ | |
| 34 | +public class NotActiveException extends ObjectStreamException { | |
| 35 | + | |
| 36 | + private static final long serialVersionUID = -3893467273049808895L; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * Constructor to create a new NotActiveException with the reason given. | |
| 40 | + * | |
| 41 | + * @param reason a String describing the reason for the exception. | |
| 42 | + */ | |
| 43 | + public NotActiveException(String reason) { | |
| 44 | + super(reason); | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Constructor to create a new NotActiveException without a reason. | |
| 49 | + */ | |
| 50 | + public NotActiveException() { | |
| 51 | + super(); | |
| 52 | + } | |
| 53 | +} | |
Binary file not shown.
| @@ -0,0 +1,55 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Thrown when an instance is required to have a Serializable interface. | |
| 30 | + * The serialization runtime or the class of the instance can throw | |
| 31 | + * this exception. The argument should be the name of the class. | |
| 32 | + * | |
| 33 | + * @author unascribed | |
| 34 | + * @since JDK1.1 | |
| 35 | + */ | |
| 36 | +public class NotSerializableException extends ObjectStreamException { | |
| 37 | + | |
| 38 | + private static final long serialVersionUID = 2906642554793891381L; | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * Constructs a NotSerializableException object with message string. | |
| 42 | + * | |
| 43 | + * @param classname Class of the instance being serialized/deserialized. | |
| 44 | + */ | |
| 45 | + public NotSerializableException(String classname) { | |
| 46 | + super(classname); | |
| 47 | + } | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * Constructs a NotSerializableException object. | |
| 51 | + */ | |
| 52 | + public NotSerializableException() { | |
| 53 | + super(); | |
| 54 | + } | |
| 55 | +} | |
Binary file not shown.
| @@ -0,0 +1,107 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * ObjectInput extends the DataInput interface to include the reading of | |
| 30 | + * objects. DataInput includes methods for the input of primitive types, | |
| 31 | + * ObjectInput extends that interface to include objects, arrays, and Strings. | |
| 32 | + * | |
| 33 | + * @author unascribed | |
| 34 | + * @see java.io.InputStream | |
| 35 | + * @see java.io.ObjectOutputStream | |
| 36 | + * @see java.io.ObjectInputStream | |
| 37 | + * @since JDK1.1 | |
| 38 | + */ | |
| 39 | +public interface ObjectInput extends DataInput, AutoCloseable { | |
| 40 | + /** | |
| 41 | + * Read and return an object. The class that implements this interface | |
| 42 | + * defines where the object is "read" from. | |
| 43 | + * | |
| 44 | + * @return the object read from the stream | |
| 45 | + * @exception java.lang.ClassNotFoundException If the class of a serialized | |
| 46 | + * object cannot be found. | |
| 47 | + * @exception IOException If any of the usual Input/Output | |
| 48 | + * related exceptions occur. | |
| 49 | + */ | |
| 50 | + public Object readObject() | |
| 51 | + throws ClassNotFoundException, IOException; | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * Reads a byte of data. This method will block if no input is | |
| 55 | + * available. | |
| 56 | + * @return the byte read, or -1 if the end of the | |
| 57 | + * stream is reached. | |
| 58 | + * @exception IOException If an I/O error has occurred. | |
| 59 | + */ | |
| 60 | + public int read() throws IOException; | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Reads into an array of bytes. This method will | |
| 64 | + * block until some input is available. | |
| 65 | + * @param b the buffer into which the data is read | |
| 66 | + * @return the actual number of bytes read, -1 is | |
| 67 | + * returned when the end of the stream is reached. | |
| 68 | + * @exception IOException If an I/O error has occurred. | |
| 69 | + */ | |
| 70 | + public int read(byte b[]) throws IOException; | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * Reads into an array of bytes. This method will | |
| 74 | + * block until some input is available. | |
| 75 | + * @param b the buffer into which the data is read | |
| 76 | + * @param off the start offset of the data | |
| 77 | + * @param len the maximum number of bytes read | |
| 78 | + * @return the actual number of bytes read, -1 is | |
| 79 | + * returned when the end of the stream is reached. | |
| 80 | + * @exception IOException If an I/O error has occurred. | |
| 81 | + */ | |
| 82 | + public int read(byte b[], int off, int len) throws IOException; | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * Skips n bytes of input. | |
| 86 | + * @param n the number of bytes to be skipped | |
| 87 | + * @return the actual number of bytes skipped. | |
| 88 | + * @exception IOException If an I/O error has occurred. | |
| 89 | + */ | |
| 90 | + public long skip(long n) throws IOException; | |
| 91 | + | |
| 92 | + /** | |
| 93 | + * Returns the number of bytes that can be read | |
| 94 | + * without blocking. | |
| 95 | + * @return the number of available bytes. | |
| 96 | + * @exception IOException If an I/O error has occurred. | |
| 97 | + */ | |
| 98 | + public int available() throws IOException; | |
| 99 | + | |
| 100 | + /** | |
| 101 | + * Closes the input stream. Must be called | |
| 102 | + * to release any resources associated with | |
| 103 | + * the stream. | |
| 104 | + * @exception IOException If an I/O error has occurred. | |
| 105 | + */ | |
| 106 | + public void close() throws IOException; | |
| 107 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,3508 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.io.ObjectStreamClass.WeakClassKey; | |
| 29 | +import java.lang.ref.ReferenceQueue; | |
| 30 | +import java.lang.reflect.Array; | |
| 31 | +import java.lang.reflect.Modifier; | |
| 32 | +import java.lang.reflect.Proxy; | |
| 33 | +import java.security.AccessControlContext; | |
| 34 | +import java.security.AccessController; | |
| 35 | +import java.security.PrivilegedAction; | |
| 36 | +import java.security.PrivilegedActionException; | |
| 37 | +import java.security.PrivilegedExceptionAction; | |
| 38 | +import java.util.Arrays; | |
| 39 | +import java.util.HashMap; | |
| 40 | +import java.util.concurrent.ConcurrentHashMap; | |
| 41 | +import java.util.concurrent.ConcurrentMap; | |
| 42 | +import java.util.concurrent.atomic.AtomicBoolean; | |
| 43 | +import static java.io.ObjectStreamClass.processQueue; | |
| 44 | + | |
| 45 | +/** | |
| 46 | + * An ObjectInputStream deserializes primitive data and objects previously | |
| 47 | + * written using an ObjectOutputStream. | |
| 48 | + * | |
| 49 | + * <p>ObjectOutputStream and ObjectInputStream can provide an application with | |
| 50 | + * persistent storage for graphs of objects when used with a FileOutputStream | |
| 51 | + * and FileInputStream respectively. ObjectInputStream is used to recover | |
| 52 | + * those objects previously serialized. Other uses include passing objects | |
| 53 | + * between hosts using a socket stream or for marshaling and unmarshaling | |
| 54 | + * arguments and parameters in a remote communication system. | |
| 55 | + * | |
| 56 | + * <p>ObjectInputStream ensures that the types of all objects in the graph | |
| 57 | + * created from the stream match the classes present in the Java Virtual | |
| 58 | + * Machine. Classes are loaded as required using the standard mechanisms. | |
| 59 | + * | |
| 60 | + * <p>Only objects that support the java.io.Serializable or | |
| 61 | + * java.io.Externalizable interface can be read from streams. | |
| 62 | + * | |
| 63 | + * <p>The method <code>readObject</code> is used to read an object from the | |
| 64 | + * stream. Java's safe casting should be used to get the desired type. In | |
| 65 | + * Java, strings and arrays are objects and are treated as objects during | |
| 66 | + * serialization. When read they need to be cast to the expected type. | |
| 67 | + * | |
| 68 | + * <p>Primitive data types can be read from the stream using the appropriate | |
| 69 | + * method on DataInput. | |
| 70 | + * | |
| 71 | + * <p>The default deserialization mechanism for objects restores the contents | |
| 72 | + * of each field to the value and type it had when it was written. Fields | |
| 73 | + * declared as transient or static are ignored by the deserialization process. | |
| 74 | + * References to other objects cause those objects to be read from the stream | |
| 75 | + * as necessary. Graphs of objects are restored correctly using a reference | |
| 76 | + * sharing mechanism. New objects are always allocated when deserializing, | |
| 77 | + * which prevents existing objects from being overwritten. | |
| 78 | + * | |
| 79 | + * <p>Reading an object is analogous to running the constructors of a new | |
| 80 | + * object. Memory is allocated for the object and initialized to zero (NULL). | |
| 81 | + * No-arg constructors are invoked for the non-serializable classes and then | |
| 82 | + * the fields of the serializable classes are restored from the stream starting | |
| 83 | + * with the serializable class closest to java.lang.object and finishing with | |
| 84 | + * the object's most specific class. | |
| 85 | + * | |
| 86 | + * <p>For example to read from a stream as written by the example in | |
| 87 | + * ObjectOutputStream: | |
| 88 | + * <br> | |
| 89 | + * <pre> | |
| 90 | + * FileInputStream fis = new FileInputStream("t.tmp"); | |
| 91 | + * ObjectInputStream ois = new ObjectInputStream(fis); | |
| 92 | + * | |
| 93 | + * int i = ois.readInt(); | |
| 94 | + * String today = (String) ois.readObject(); | |
| 95 | + * Date date = (Date) ois.readObject(); | |
| 96 | + * | |
| 97 | + * ois.close(); | |
| 98 | + * </pre> | |
| 99 | + * | |
| 100 | + * <p>Classes control how they are serialized by implementing either the | |
| 101 | + * java.io.Serializable or java.io.Externalizable interfaces. | |
| 102 | + * | |
| 103 | + * <p>Implementing the Serializable interface allows object serialization to | |
| 104 | + * save and restore the entire state of the object and it allows classes to | |
| 105 | + * evolve between the time the stream is written and the time it is read. It | |
| 106 | + * automatically traverses references between objects, saving and restoring | |
| 107 | + * entire graphs. | |
| 108 | + * | |
| 109 | + * <p>Serializable classes that require special handling during the | |
| 110 | + * serialization and deserialization process should implement the following | |
| 111 | + * methods:<p> | |
| 112 | + * | |
| 113 | + * <pre> | |
| 114 | + * private void writeObject(java.io.ObjectOutputStream stream) | |
| 115 | + * throws IOException; | |
| 116 | + * private void readObject(java.io.ObjectInputStream stream) | |
| 117 | + * throws IOException, ClassNotFoundException; | |
| 118 | + * private void readObjectNoData() | |
| 119 | + * throws ObjectStreamException; | |
| 120 | + * </pre> | |
| 121 | + * | |
| 122 | + * <p>The readObject method is responsible for reading and restoring the state | |
| 123 | + * of the object for its particular class using data written to the stream by | |
| 124 | + * the corresponding writeObject method. The method does not need to concern | |
| 125 | + * itself with the state belonging to its superclasses or subclasses. State is | |
| 126 | + * restored by reading data from the ObjectInputStream for the individual | |
| 127 | + * fields and making assignments to the appropriate fields of the object. | |
| 128 | + * Reading primitive data types is supported by DataInput. | |
| 129 | + * | |
| 130 | + * <p>Any attempt to read object data which exceeds the boundaries of the | |
| 131 | + * custom data written by the corresponding writeObject method will cause an | |
| 132 | + * OptionalDataException to be thrown with an eof field value of true. | |
| 133 | + * Non-object reads which exceed the end of the allotted data will reflect the | |
| 134 | + * end of data in the same way that they would indicate the end of the stream: | |
| 135 | + * bytewise reads will return -1 as the byte read or number of bytes read, and | |
| 136 | + * primitive reads will throw EOFExceptions. If there is no corresponding | |
| 137 | + * writeObject method, then the end of default serialized data marks the end of | |
| 138 | + * the allotted data. | |
| 139 | + * | |
| 140 | + * <p>Primitive and object read calls issued from within a readExternal method | |
| 141 | + * behave in the same manner--if the stream is already positioned at the end of | |
| 142 | + * data written by the corresponding writeExternal method, object reads will | |
| 143 | + * throw OptionalDataExceptions with eof set to true, bytewise reads will | |
| 144 | + * return -1, and primitive reads will throw EOFExceptions. Note that this | |
| 145 | + * behavior does not hold for streams written with the old | |
| 146 | + * <code>ObjectStreamConstants.PROTOCOL_VERSION_1</code> protocol, in which the | |
| 147 | + * end of data written by writeExternal methods is not demarcated, and hence | |
| 148 | + * cannot be detected. | |
| 149 | + * | |
| 150 | + * <p>The readObjectNoData method is responsible for initializing the state of | |
| 151 | + * the object for its particular class in the event that the serialization | |
| 152 | + * stream does not list the given class as a superclass of the object being | |
| 153 | + * deserialized. This may occur in cases where the receiving party uses a | |
| 154 | + * different version of the deserialized instance's class than the sending | |
| 155 | + * party, and the receiver's version extends classes that are not extended by | |
| 156 | + * the sender's version. This may also occur if the serialization stream has | |
| 157 | + * been tampered; hence, readObjectNoData is useful for initializing | |
| 158 | + * deserialized objects properly despite a "hostile" or incomplete source | |
| 159 | + * stream. | |
| 160 | + * | |
| 161 | + * <p>Serialization does not read or assign values to the fields of any object | |
| 162 | + * that does not implement the java.io.Serializable interface. Subclasses of | |
| 163 | + * Objects that are not serializable can be serializable. In this case the | |
| 164 | + * non-serializable class must have a no-arg constructor to allow its fields to | |
| 165 | + * be initialized. In this case it is the responsibility of the subclass to | |
| 166 | + * save and restore the state of the non-serializable class. It is frequently | |
| 167 | + * the case that the fields of that class are accessible (public, package, or | |
| 168 | + * protected) or that there are get and set methods that can be used to restore | |
| 169 | + * the state. | |
| 170 | + * | |
| 171 | + * <p>Any exception that occurs while deserializing an object will be caught by | |
| 172 | + * the ObjectInputStream and abort the reading process. | |
| 173 | + * | |
| 174 | + * <p>Implementing the Externalizable interface allows the object to assume | |
| 175 | + * complete control over the contents and format of the object's serialized | |
| 176 | + * form. The methods of the Externalizable interface, writeExternal and | |
| 177 | + * readExternal, are called to save and restore the objects state. When | |
| 178 | + * implemented by a class they can write and read their own state using all of | |
| 179 | + * the methods of ObjectOutput and ObjectInput. It is the responsibility of | |
| 180 | + * the objects to handle any versioning that occurs. | |
| 181 | + * | |
| 182 | + * <p>Enum constants are deserialized differently than ordinary serializable or | |
| 183 | + * externalizable objects. The serialized form of an enum constant consists | |
| 184 | + * solely of its name; field values of the constant are not transmitted. To | |
| 185 | + * deserialize an enum constant, ObjectInputStream reads the constant name from | |
| 186 | + * the stream; the deserialized constant is then obtained by calling the static | |
| 187 | + * method <code>Enum.valueOf(Class, String)</code> with the enum constant's | |
| 188 | + * base type and the received constant name as arguments. Like other | |
| 189 | + * serializable or externalizable objects, enum constants can function as the | |
| 190 | + * targets of back references appearing subsequently in the serialization | |
| 191 | + * stream. The process by which enum constants are deserialized cannot be | |
| 192 | + * customized: any class-specific readObject, readObjectNoData, and readResolve | |
| 193 | + * methods defined by enum types are ignored during deserialization. | |
| 194 | + * Similarly, any serialPersistentFields or serialVersionUID field declarations | |
| 195 | + * are also ignored--all enum types have a fixed serialVersionUID of 0L. | |
| 196 | + * | |
| 197 | + * @author Mike Warres | |
| 198 | + * @author Roger Riggs | |
| 199 | + * @see java.io.DataInput | |
| 200 | + * @see java.io.ObjectOutputStream | |
| 201 | + * @see java.io.Serializable | |
| 202 | + * @see <a href="../../../platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a> | |
| 203 | + * @since JDK1.1 | |
| 204 | + */ | |
| 205 | +public class ObjectInputStream | |
| 206 | + extends InputStream implements ObjectInput, ObjectStreamConstants | |
| 207 | +{ | |
| 208 | + /** handle value representing null */ | |
| 209 | + private static final int NULL_HANDLE = -1; | |
| 210 | + | |
| 211 | + /** marker for unshared objects in internal handle table */ | |
| 212 | + private static final Object unsharedMarker = new Object(); | |
| 213 | + | |
| 214 | + /** table mapping primitive type names to corresponding class objects */ | |
| 215 | + private static final HashMap<String, Class<?>> primClasses | |
| 216 | + = new HashMap<>(8, 1.0F); | |
| 217 | + static { | |
| 218 | + primClasses.put("boolean", boolean.class); | |
| 219 | + primClasses.put("byte", byte.class); | |
| 220 | + primClasses.put("char", char.class); | |
| 221 | + primClasses.put("short", short.class); | |
| 222 | + primClasses.put("int", int.class); | |
| 223 | + primClasses.put("long", long.class); | |
| 224 | + primClasses.put("float", float.class); | |
| 225 | + primClasses.put("double", double.class); | |
| 226 | + primClasses.put("void", void.class); | |
| 227 | + } | |
| 228 | + | |
| 229 | + private static class Caches { | |
| 230 | + /** cache of subclass security audit results */ | |
| 231 | + static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits = | |
| 232 | + new ConcurrentHashMap<>(); | |
| 233 | + | |
| 234 | + /** queue for WeakReferences to audited subclasses */ | |
| 235 | + static final ReferenceQueue<Class<?>> subclassAuditsQueue = | |
| 236 | + new ReferenceQueue<>(); | |
| 237 | + } | |
| 238 | + | |
| 239 | + /** filter stream for handling block data conversion */ | |
| 240 | + private final BlockDataInputStream bin; | |
| 241 | + /** validation callback list */ | |
| 242 | + private final ValidationList vlist; | |
| 243 | + /** recursion depth */ | |
| 244 | + private int depth; | |
| 245 | + /** whether stream is closed */ | |
| 246 | + private boolean closed; | |
| 247 | + | |
| 248 | + /** wire handle -> obj/exception map */ | |
| 249 | + private final HandleTable handles; | |
| 250 | + /** scratch field for passing handle values up/down call stack */ | |
| 251 | + private int passHandle = NULL_HANDLE; | |
| 252 | + /** flag set when at end of field value block with no TC_ENDBLOCKDATA */ | |
| 253 | + private boolean defaultDataEnd = false; | |
| 254 | + | |
| 255 | + /** buffer for reading primitive field values */ | |
| 256 | + private byte[] primVals; | |
| 257 | + | |
| 258 | + /** if true, invoke readObjectOverride() instead of readObject() */ | |
| 259 | + private final boolean enableOverride; | |
| 260 | + /** if true, invoke resolveObject() */ | |
| 261 | + private boolean enableResolve; | |
| 262 | + | |
| 263 | + /** | |
| 264 | + * Context during upcalls to class-defined readObject methods; holds | |
| 265 | + * object currently being deserialized and descriptor for current class. | |
| 266 | + * Null when not during readObject upcall. | |
| 267 | + */ | |
| 268 | + private SerialCallbackContext curContext; | |
| 269 | + | |
| 270 | + /** | |
| 271 | + * Creates an ObjectInputStream that reads from the specified InputStream. | |
| 272 | + * A serialization stream header is read from the stream and verified. | |
| 273 | + * This constructor will block until the corresponding ObjectOutputStream | |
| 274 | + * has written and flushed the header. | |
| 275 | + * | |
| 276 | + * <p>If a security manager is installed, this constructor will check for | |
| 277 | + * the "enableSubclassImplementation" SerializablePermission when invoked | |
| 278 | + * directly or indirectly by the constructor of a subclass which overrides | |
| 279 | + * the ObjectInputStream.readFields or ObjectInputStream.readUnshared | |
| 280 | + * methods. | |
| 281 | + * | |
| 282 | + * @param in input stream to read from | |
| 283 | + * @throws StreamCorruptedException if the stream header is incorrect | |
| 284 | + * @throws IOException if an I/O error occurs while reading stream header | |
| 285 | + * @throws SecurityException if untrusted subclass illegally overrides | |
| 286 | + * security-sensitive methods | |
| 287 | + * @throws NullPointerException if <code>in</code> is <code>null</code> | |
| 288 | + * @see ObjectInputStream#ObjectInputStream() | |
| 289 | + * @see ObjectInputStream#readFields() | |
| 290 | + * @see ObjectOutputStream#ObjectOutputStream(OutputStream) | |
| 291 | + */ | |
| 292 | + public ObjectInputStream(InputStream in) throws IOException { | |
| 293 | + verifySubclass(); | |
| 294 | + bin = new BlockDataInputStream(in); | |
| 295 | + handles = new HandleTable(10); | |
| 296 | + vlist = new ValidationList(); | |
| 297 | + enableOverride = false; | |
| 298 | + readStreamHeader(); | |
| 299 | + bin.setBlockDataMode(true); | |
| 300 | + } | |
| 301 | + | |
| 302 | + /** | |
| 303 | + * Provide a way for subclasses that are completely reimplementing | |
| 304 | + * ObjectInputStream to not have to allocate private data just used by this | |
| 305 | + * implementation of ObjectInputStream. | |
| 306 | + * | |
| 307 | + * <p>If there is a security manager installed, this method first calls the | |
| 308 | + * security manager's <code>checkPermission</code> method with the | |
| 309 | + * <code>SerializablePermission("enableSubclassImplementation")</code> | |
| 310 | + * permission to ensure it's ok to enable subclassing. | |
| 311 | + * | |
| 312 | + * @throws SecurityException if a security manager exists and its | |
| 313 | + * <code>checkPermission</code> method denies enabling | |
| 314 | + * subclassing. | |
| 315 | + * @see SecurityManager#checkPermission | |
| 316 | + * @see java.io.SerializablePermission | |
| 317 | + */ | |
| 318 | + protected ObjectInputStream() throws IOException, SecurityException { | |
| 319 | + SecurityManager sm = System.getSecurityManager(); | |
| 320 | + if (sm != null) { | |
| 321 | + sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); | |
| 322 | + } | |
| 323 | + bin = null; | |
| 324 | + handles = null; | |
| 325 | + vlist = null; | |
| 326 | + enableOverride = true; | |
| 327 | + } | |
| 328 | + | |
| 329 | + /** | |
| 330 | + * Read an object from the ObjectInputStream. The class of the object, the | |
| 331 | + * signature of the class, and the values of the non-transient and | |
| 332 | + * non-static fields of the class and all of its supertypes are read. | |
| 333 | + * Default deserializing for a class can be overriden using the writeObject | |
| 334 | + * and readObject methods. Objects referenced by this object are read | |
| 335 | + * transitively so that a complete equivalent graph of objects is | |
| 336 | + * reconstructed by readObject. | |
| 337 | + * | |
| 338 | + * <p>The root object is completely restored when all of its fields and the | |
| 339 | + * objects it references are completely restored. At this point the object | |
| 340 | + * validation callbacks are executed in order based on their registered | |
| 341 | + * priorities. The callbacks are registered by objects (in the readObject | |
| 342 | + * special methods) as they are individually restored. | |
| 343 | + * | |
| 344 | + * <p>Exceptions are thrown for problems with the InputStream and for | |
| 345 | + * classes that should not be deserialized. All exceptions are fatal to | |
| 346 | + * the InputStream and leave it in an indeterminate state; it is up to the | |
| 347 | + * caller to ignore or recover the stream state. | |
| 348 | + * | |
| 349 | + * @throws ClassNotFoundException Class of a serialized object cannot be | |
| 350 | + * found. | |
| 351 | + * @throws InvalidClassException Something is wrong with a class used by | |
| 352 | + * serialization. | |
| 353 | + * @throws StreamCorruptedException Control information in the | |
| 354 | + * stream is inconsistent. | |
| 355 | + * @throws OptionalDataException Primitive data was found in the | |
| 356 | + * stream instead of objects. | |
| 357 | + * @throws IOException Any of the usual Input/Output related exceptions. | |
| 358 | + */ | |
| 359 | + public final Object readObject() | |
| 360 | + throws IOException, ClassNotFoundException | |
| 361 | + { | |
| 362 | + if (enableOverride) { | |
| 363 | + return readObjectOverride(); | |
| 364 | + } | |
| 365 | + | |
| 366 | + // if nested read, passHandle contains handle of enclosing object | |
| 367 | + int outerHandle = passHandle; | |
| 368 | + try { | |
| 369 | + Object obj = readObject0(false); | |
| 370 | + handles.markDependency(outerHandle, passHandle); | |
| 371 | + ClassNotFoundException ex = handles.lookupException(passHandle); | |
| 372 | + if (ex != null) { | |
| 373 | + throw ex; | |
| 374 | + } | |
| 375 | + if (depth == 0) { | |
| 376 | + vlist.doCallbacks(); | |
| 377 | + } | |
| 378 | + return obj; | |
| 379 | + } finally { | |
| 380 | + passHandle = outerHandle; | |
| 381 | + if (closed && depth == 0) { | |
| 382 | + clear(); | |
| 383 | + } | |
| 384 | + } | |
| 385 | + } | |
| 386 | + | |
| 387 | + /** | |
| 388 | + * This method is called by trusted subclasses of ObjectOutputStream that | |
| 389 | + * constructed ObjectOutputStream using the protected no-arg constructor. | |
| 390 | + * The subclass is expected to provide an override method with the modifier | |
| 391 | + * "final". | |
| 392 | + * | |
| 393 | + * @return the Object read from the stream. | |
| 394 | + * @throws ClassNotFoundException Class definition of a serialized object | |
| 395 | + * cannot be found. | |
| 396 | + * @throws OptionalDataException Primitive data was found in the stream | |
| 397 | + * instead of objects. | |
| 398 | + * @throws IOException if I/O errors occurred while reading from the | |
| 399 | + * underlying stream | |
| 400 | + * @see #ObjectInputStream() | |
| 401 | + * @see #readObject() | |
| 402 | + * @since 1.2 | |
| 403 | + */ | |
| 404 | + protected Object readObjectOverride() | |
| 405 | + throws IOException, ClassNotFoundException | |
| 406 | + { | |
| 407 | + return null; | |
| 408 | + } | |
| 409 | + | |
| 410 | + /** | |
| 411 | + * Reads an "unshared" object from the ObjectInputStream. This method is | |
| 412 | + * identical to readObject, except that it prevents subsequent calls to | |
| 413 | + * readObject and readUnshared from returning additional references to the | |
| 414 | + * deserialized instance obtained via this call. Specifically: | |
| 415 | + * <ul> | |
| 416 | + * <li>If readUnshared is called to deserialize a back-reference (the | |
| 417 | + * stream representation of an object which has been written | |
| 418 | + * previously to the stream), an ObjectStreamException will be | |
| 419 | + * thrown. | |
| 420 | + * | |
| 421 | + * <li>If readUnshared returns successfully, then any subsequent attempts | |
| 422 | + * to deserialize back-references to the stream handle deserialized | |
| 423 | + * by readUnshared will cause an ObjectStreamException to be thrown. | |
| 424 | + * </ul> | |
| 425 | + * Deserializing an object via readUnshared invalidates the stream handle | |
| 426 | + * associated with the returned object. Note that this in itself does not | |
| 427 | + * always guarantee that the reference returned by readUnshared is unique; | |
| 428 | + * the deserialized object may define a readResolve method which returns an | |
| 429 | + * object visible to other parties, or readUnshared may return a Class | |
| 430 | + * object or enum constant obtainable elsewhere in the stream or through | |
| 431 | + * external means. If the deserialized object defines a readResolve method | |
| 432 | + * and the invocation of that method returns an array, then readUnshared | |
| 433 | + * returns a shallow clone of that array; this guarantees that the returned | |
| 434 | + * array object is unique and cannot be obtained a second time from an | |
| 435 | + * invocation of readObject or readUnshared on the ObjectInputStream, | |
| 436 | + * even if the underlying data stream has been manipulated. | |
| 437 | + * | |
| 438 | + * <p>ObjectInputStream subclasses which override this method can only be | |
| 439 | + * constructed in security contexts possessing the | |
| 440 | + * "enableSubclassImplementation" SerializablePermission; any attempt to | |
| 441 | + * instantiate such a subclass without this permission will cause a | |
| 442 | + * SecurityException to be thrown. | |
| 443 | + * | |
| 444 | + * @return reference to deserialized object | |
| 445 | + * @throws ClassNotFoundException if class of an object to deserialize | |
| 446 | + * cannot be found | |
| 447 | + * @throws StreamCorruptedException if control information in the stream | |
| 448 | + * is inconsistent | |
| 449 | + * @throws ObjectStreamException if object to deserialize has already | |
| 450 | + * appeared in stream | |
| 451 | + * @throws OptionalDataException if primitive data is next in stream | |
| 452 | + * @throws IOException if an I/O error occurs during deserialization | |
| 453 | + * @since 1.4 | |
| 454 | + */ | |
| 455 | + public Object readUnshared() throws IOException, ClassNotFoundException { | |
| 456 | + // if nested read, passHandle contains handle of enclosing object | |
| 457 | + int outerHandle = passHandle; | |
| 458 | + try { | |
| 459 | + Object obj = readObject0(true); | |
| 460 | + handles.markDependency(outerHandle, passHandle); | |
| 461 | + ClassNotFoundException ex = handles.lookupException(passHandle); | |
| 462 | + if (ex != null) { | |
| 463 | + throw ex; | |
| 464 | + } | |
| 465 | + if (depth == 0) { | |
| 466 | + vlist.doCallbacks(); | |
| 467 | + } | |
| 468 | + return obj; | |
| 469 | + } finally { | |
| 470 | + passHandle = outerHandle; | |
| 471 | + if (closed && depth == 0) { | |
| 472 | + clear(); | |
| 473 | + } | |
| 474 | + } | |
| 475 | + } | |
| 476 | + | |
| 477 | + /** | |
| 478 | + * Read the non-static and non-transient fields of the current class from | |
| 479 | + * this stream. This may only be called from the readObject method of the | |
| 480 | + * class being deserialized. It will throw the NotActiveException if it is | |
| 481 | + * called otherwise. | |
| 482 | + * | |
| 483 | + * @throws ClassNotFoundException if the class of a serialized object | |
| 484 | + * could not be found. | |
| 485 | + * @throws IOException if an I/O error occurs. | |
| 486 | + * @throws NotActiveException if the stream is not currently reading | |
| 487 | + * objects. | |
| 488 | + */ | |
| 489 | + public void defaultReadObject() | |
| 490 | + throws IOException, ClassNotFoundException | |
| 491 | + { | |
| 492 | + if (curContext == null) { | |
| 493 | + throw new NotActiveException("not in call to readObject"); | |
| 494 | + } | |
| 495 | + Object curObj = curContext.getObj(); | |
| 496 | + ObjectStreamClass curDesc = curContext.getDesc(); | |
| 497 | + bin.setBlockDataMode(false); | |
| 498 | + defaultReadFields(curObj, curDesc); | |
| 499 | + bin.setBlockDataMode(true); | |
| 500 | + if (!curDesc.hasWriteObjectData()) { | |
| 501 | + /* | |
| 502 | + * Fix for 4360508: since stream does not contain terminating | |
| 503 | + * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere | |
| 504 | + * knows to simulate end-of-custom-data behavior. | |
| 505 | + */ | |
| 506 | + defaultDataEnd = true; | |
| 507 | + } | |
| 508 | + ClassNotFoundException ex = handles.lookupException(passHandle); | |
| 509 | + if (ex != null) { | |
| 510 | + throw ex; | |
| 511 | + } | |
| 512 | + } | |
| 513 | + | |
| 514 | + /** | |
| 515 | + * Reads the persistent fields from the stream and makes them available by | |
| 516 | + * name. | |
| 517 | + * | |
| 518 | + * @return the <code>GetField</code> object representing the persistent | |
| 519 | + * fields of the object being deserialized | |
| 520 | + * @throws ClassNotFoundException if the class of a serialized object | |
| 521 | + * could not be found. | |
| 522 | + * @throws IOException if an I/O error occurs. | |
| 523 | + * @throws NotActiveException if the stream is not currently reading | |
| 524 | + * objects. | |
| 525 | + * @since 1.2 | |
| 526 | + */ | |
| 527 | + public ObjectInputStream.GetField readFields() | |
| 528 | + throws IOException, ClassNotFoundException | |
| 529 | + { | |
| 530 | + if (curContext == null) { | |
| 531 | + throw new NotActiveException("not in call to readObject"); | |
| 532 | + } | |
| 533 | + Object curObj = curContext.getObj(); | |
| 534 | + ObjectStreamClass curDesc = curContext.getDesc(); | |
| 535 | + bin.setBlockDataMode(false); | |
| 536 | + GetFieldImpl getField = new GetFieldImpl(curDesc); | |
| 537 | + getField.readFields(); | |
| 538 | + bin.setBlockDataMode(true); | |
| 539 | + if (!curDesc.hasWriteObjectData()) { | |
| 540 | + /* | |
| 541 | + * Fix for 4360508: since stream does not contain terminating | |
| 542 | + * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere | |
| 543 | + * knows to simulate end-of-custom-data behavior. | |
| 544 | + */ | |
| 545 | + defaultDataEnd = true; | |
| 546 | + } | |
| 547 | + | |
| 548 | + return getField; | |
| 549 | + } | |
| 550 | + | |
| 551 | + /** | |
| 552 | + * Register an object to be validated before the graph is returned. While | |
| 553 | + * similar to resolveObject these validations are called after the entire | |
| 554 | + * graph has been reconstituted. Typically, a readObject method will | |
| 555 | + * register the object with the stream so that when all of the objects are | |
| 556 | + * restored a final set of validations can be performed. | |
| 557 | + * | |
| 558 | + * @param obj the object to receive the validation callback. | |
| 559 | + * @param prio controls the order of callbacks;zero is a good default. | |
| 560 | + * Use higher numbers to be called back earlier, lower numbers for | |
| 561 | + * later callbacks. Within a priority, callbacks are processed in | |
| 562 | + * no particular order. | |
| 563 | + * @throws NotActiveException The stream is not currently reading objects | |
| 564 | + * so it is invalid to register a callback. | |
| 565 | + * @throws InvalidObjectException The validation object is null. | |
| 566 | + */ | |
| 567 | + public void registerValidation(ObjectInputValidation obj, int prio) | |
| 568 | + throws NotActiveException, InvalidObjectException | |
| 569 | + { | |
| 570 | + if (depth == 0) { | |
| 571 | + throw new NotActiveException("stream inactive"); | |
| 572 | + } | |
| 573 | + vlist.register(obj, prio); | |
| 574 | + } | |
| 575 | + | |
| 576 | + /** | |
| 577 | + * Load the local class equivalent of the specified stream class | |
| 578 | + * description. Subclasses may implement this method to allow classes to | |
| 579 | + * be fetched from an alternate source. | |
| 580 | + * | |
| 581 | + * <p>The corresponding method in <code>ObjectOutputStream</code> is | |
| 582 | + * <code>annotateClass</code>. This method will be invoked only once for | |
| 583 | + * each unique class in the stream. This method can be implemented by | |
| 584 | + * subclasses to use an alternate loading mechanism but must return a | |
| 585 | + * <code>Class</code> object. Once returned, if the class is not an array | |
| 586 | + * class, its serialVersionUID is compared to the serialVersionUID of the | |
| 587 | + * serialized class, and if there is a mismatch, the deserialization fails | |
| 588 | + * and an {@link InvalidClassException} is thrown. | |
| 589 | + * | |
| 590 | + * <p>The default implementation of this method in | |
| 591 | + * <code>ObjectInputStream</code> returns the result of calling | |
| 592 | + * <pre> | |
| 593 | + * Class.forName(desc.getName(), false, loader) | |
| 594 | + * </pre> | |
| 595 | + * where <code>loader</code> is determined as follows: if there is a | |
| 596 | + * method on the current thread's stack whose declaring class was | |
| 597 | + * defined by a user-defined class loader (and was not a generated to | |
| 598 | + * implement reflective invocations), then <code>loader</code> is class | |
| 599 | + * loader corresponding to the closest such method to the currently | |
| 600 | + * executing frame; otherwise, <code>loader</code> is | |
| 601 | + * <code>null</code>. If this call results in a | |
| 602 | + * <code>ClassNotFoundException</code> and the name of the passed | |
| 603 | + * <code>ObjectStreamClass</code> instance is the Java language keyword | |
| 604 | + * for a primitive type or void, then the <code>Class</code> object | |
| 605 | + * representing that primitive type or void will be returned | |
| 606 | + * (e.g., an <code>ObjectStreamClass</code> with the name | |
| 607 | + * <code>"int"</code> will be resolved to <code>Integer.TYPE</code>). | |
| 608 | + * Otherwise, the <code>ClassNotFoundException</code> will be thrown to | |
| 609 | + * the caller of this method. | |
| 610 | + * | |
| 611 | + * @param desc an instance of class <code>ObjectStreamClass</code> | |
| 612 | + * @return a <code>Class</code> object corresponding to <code>desc</code> | |
| 613 | + * @throws IOException any of the usual Input/Output exceptions. | |
| 614 | + * @throws ClassNotFoundException if class of a serialized object cannot | |
| 615 | + * be found. | |
| 616 | + */ | |
| 617 | + protected Class<?> resolveClass(ObjectStreamClass desc) | |
| 618 | + throws IOException, ClassNotFoundException | |
| 619 | + { | |
| 620 | + String name = desc.getName(); | |
| 621 | + try { | |
| 622 | + return Class.forName(name, false, latestUserDefinedLoader()); | |
| 623 | + } catch (ClassNotFoundException ex) { | |
| 624 | + Class<?> cl = primClasses.get(name); | |
| 625 | + if (cl != null) { | |
| 626 | + return cl; | |
| 627 | + } else { | |
| 628 | + throw ex; | |
| 629 | + } | |
| 630 | + } | |
| 631 | + } | |
| 632 | + | |
| 633 | + /** | |
| 634 | + * Returns a proxy class that implements the interfaces named in a proxy | |
| 635 | + * class descriptor; subclasses may implement this method to read custom | |
| 636 | + * data from the stream along with the descriptors for dynamic proxy | |
| 637 | + * classes, allowing them to use an alternate loading mechanism for the | |
| 638 | + * interfaces and the proxy class. | |
| 639 | + * | |
| 640 | + * <p>This method is called exactly once for each unique proxy class | |
| 641 | + * descriptor in the stream. | |
| 642 | + * | |
| 643 | + * <p>The corresponding method in <code>ObjectOutputStream</code> is | |
| 644 | + * <code>annotateProxyClass</code>. For a given subclass of | |
| 645 | + * <code>ObjectInputStream</code> that overrides this method, the | |
| 646 | + * <code>annotateProxyClass</code> method in the corresponding subclass of | |
| 647 | + * <code>ObjectOutputStream</code> must write any data or objects read by | |
| 648 | + * this method. | |
| 649 | + * | |
| 650 | + * <p>The default implementation of this method in | |
| 651 | + * <code>ObjectInputStream</code> returns the result of calling | |
| 652 | + * <code>Proxy.getProxyClass</code> with the list of <code>Class</code> | |
| 653 | + * objects for the interfaces that are named in the <code>interfaces</code> | |
| 654 | + * parameter. The <code>Class</code> object for each interface name | |
| 655 | + * <code>i</code> is the value returned by calling | |
| 656 | + * <pre> | |
| 657 | + * Class.forName(i, false, loader) | |
| 658 | + * </pre> | |
| 659 | + * where <code>loader</code> is that of the first non-<code>null</code> | |
| 660 | + * class loader up the execution stack, or <code>null</code> if no | |
| 661 | + * non-<code>null</code> class loaders are on the stack (the same class | |
| 662 | + * loader choice used by the <code>resolveClass</code> method). Unless any | |
| 663 | + * of the resolved interfaces are non-public, this same value of | |
| 664 | + * <code>loader</code> is also the class loader passed to | |
| 665 | + * <code>Proxy.getProxyClass</code>; if non-public interfaces are present, | |
| 666 | + * their class loader is passed instead (if more than one non-public | |
| 667 | + * interface class loader is encountered, an | |
| 668 | + * <code>IllegalAccessError</code> is thrown). | |
| 669 | + * If <code>Proxy.getProxyClass</code> throws an | |
| 670 | + * <code>IllegalArgumentException</code>, <code>resolveProxyClass</code> | |
| 671 | + * will throw a <code>ClassNotFoundException</code> containing the | |
| 672 | + * <code>IllegalArgumentException</code>. | |
| 673 | + * | |
| 674 | + * @param interfaces the list of interface names that were | |
| 675 | + * deserialized in the proxy class descriptor | |
| 676 | + * @return a proxy class for the specified interfaces | |
| 677 | + * @throws IOException any exception thrown by the underlying | |
| 678 | + * <code>InputStream</code> | |
| 679 | + * @throws ClassNotFoundException if the proxy class or any of the | |
| 680 | + * named interfaces could not be found | |
| 681 | + * @see ObjectOutputStream#annotateProxyClass(Class) | |
| 682 | + * @since 1.3 | |
| 683 | + */ | |
| 684 | + protected Class<?> resolveProxyClass(String[] interfaces) | |
| 685 | + throws IOException, ClassNotFoundException | |
| 686 | + { | |
| 687 | + ClassLoader latestLoader = latestUserDefinedLoader(); | |
| 688 | + ClassLoader nonPublicLoader = null; | |
| 689 | + boolean hasNonPublicInterface = false; | |
| 690 | + | |
| 691 | + // define proxy in class loader of non-public interface(s), if any | |
| 692 | + Class[] classObjs = new Class[interfaces.length]; | |
| 693 | + for (int i = 0; i < interfaces.length; i++) { | |
| 694 | + Class cl = Class.forName(interfaces[i], false, latestLoader); | |
| 695 | + if ((cl.getModifiers() & Modifier.PUBLIC) == 0) { | |
| 696 | + if (hasNonPublicInterface) { | |
| 697 | + if (nonPublicLoader != cl.getClassLoader()) { | |
| 698 | + throw new IllegalAccessError( | |
| 699 | + "conflicting non-public interface class loaders"); | |
| 700 | + } | |
| 701 | + } else { | |
| 702 | + nonPublicLoader = cl.getClassLoader(); | |
| 703 | + hasNonPublicInterface = true; | |
| 704 | + } | |
| 705 | + } | |
| 706 | + classObjs[i] = cl; | |
| 707 | + } | |
| 708 | + try { | |
| 709 | + return Proxy.getProxyClass( | |
| 710 | + hasNonPublicInterface ? nonPublicLoader : latestLoader, | |
| 711 | + classObjs); | |
| 712 | + } catch (IllegalArgumentException e) { | |
| 713 | + throw new ClassNotFoundException(null, e); | |
| 714 | + } | |
| 715 | + } | |
| 716 | + | |
| 717 | + /** | |
| 718 | + * This method will allow trusted subclasses of ObjectInputStream to | |
| 719 | + * substitute one object for another during deserialization. Replacing | |
| 720 | + * objects is disabled until enableResolveObject is called. The | |
| 721 | + * enableResolveObject method checks that the stream requesting to resolve | |
| 722 | + * object can be trusted. Every reference to serializable objects is passed | |
| 723 | + * to resolveObject. To insure that the private state of objects is not | |
| 724 | + * unintentionally exposed only trusted streams may use resolveObject. | |
| 725 | + * | |
| 726 | + * <p>This method is called after an object has been read but before it is | |
| 727 | + * returned from readObject. The default resolveObject method just returns | |
| 728 | + * the same object. | |
| 729 | + * | |
| 730 | + * <p>When a subclass is replacing objects it must insure that the | |
| 731 | + * substituted object is compatible with every field where the reference | |
| 732 | + * will be stored. Objects whose type is not a subclass of the type of the | |
| 733 | + * field or array element abort the serialization by raising an exception | |
| 734 | + * and the object is not be stored. | |
| 735 | + * | |
| 736 | + * <p>This method is called only once when each object is first | |
| 737 | + * encountered. All subsequent references to the object will be redirected | |
| 738 | + * to the new object. | |
| 739 | + * | |
| 740 | + * @param obj object to be substituted | |
| 741 | + * @return the substituted object | |
| 742 | + * @throws IOException Any of the usual Input/Output exceptions. | |
| 743 | + */ | |
| 744 | + protected Object resolveObject(Object obj) throws IOException { | |
| 745 | + return obj; | |
| 746 | + } | |
| 747 | + | |
| 748 | + /** | |
| 749 | + * Enable the stream to allow objects read from the stream to be replaced. | |
| 750 | + * When enabled, the resolveObject method is called for every object being | |
| 751 | + * deserialized. | |
| 752 | + * | |
| 753 | + * <p>If <i>enable</i> is true, and there is a security manager installed, | |
| 754 | + * this method first calls the security manager's | |
| 755 | + * <code>checkPermission</code> method with the | |
| 756 | + * <code>SerializablePermission("enableSubstitution")</code> permission to | |
| 757 | + * ensure it's ok to enable the stream to allow objects read from the | |
| 758 | + * stream to be replaced. | |
| 759 | + * | |
| 760 | + * @param enable true for enabling use of <code>resolveObject</code> for | |
| 761 | + * every object being deserialized | |
| 762 | + * @return the previous setting before this method was invoked | |
| 763 | + * @throws SecurityException if a security manager exists and its | |
| 764 | + * <code>checkPermission</code> method denies enabling the stream | |
| 765 | + * to allow objects read from the stream to be replaced. | |
| 766 | + * @see SecurityManager#checkPermission | |
| 767 | + * @see java.io.SerializablePermission | |
| 768 | + */ | |
| 769 | + protected boolean enableResolveObject(boolean enable) | |
| 770 | + throws SecurityException | |
| 771 | + { | |
| 772 | + if (enable == enableResolve) { | |
| 773 | + return enable; | |
| 774 | + } | |
| 775 | + if (enable) { | |
| 776 | + SecurityManager sm = System.getSecurityManager(); | |
| 777 | + if (sm != null) { | |
| 778 | + sm.checkPermission(SUBSTITUTION_PERMISSION); | |
| 779 | + } | |
| 780 | + } | |
| 781 | + enableResolve = enable; | |
| 782 | + return !enableResolve; | |
| 783 | + } | |
| 784 | + | |
| 785 | + /** | |
| 786 | + * The readStreamHeader method is provided to allow subclasses to read and | |
| 787 | + * verify their own stream headers. It reads and verifies the magic number | |
| 788 | + * and version number. | |
| 789 | + * | |
| 790 | + * @throws IOException if there are I/O errors while reading from the | |
| 791 | + * underlying <code>InputStream</code> | |
| 792 | + * @throws StreamCorruptedException if control information in the stream | |
| 793 | + * is inconsistent | |
| 794 | + */ | |
| 795 | + protected void readStreamHeader() | |
| 796 | + throws IOException, StreamCorruptedException | |
| 797 | + { | |
| 798 | + short s0 = bin.readShort(); | |
| 799 | + short s1 = bin.readShort(); | |
| 800 | + if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) { | |
| 801 | + throw new StreamCorruptedException( | |
| 802 | + String.format("invalid stream header: %04X%04X", s0, s1)); | |
| 803 | + } | |
| 804 | + } | |
| 805 | + | |
| 806 | + /** | |
| 807 | + * Read a class descriptor from the serialization stream. This method is | |
| 808 | + * called when the ObjectInputStream expects a class descriptor as the next | |
| 809 | + * item in the serialization stream. Subclasses of ObjectInputStream may | |
| 810 | + * override this method to read in class descriptors that have been written | |
| 811 | + * in non-standard formats (by subclasses of ObjectOutputStream which have | |
| 812 | + * overridden the <code>writeClassDescriptor</code> method). By default, | |
| 813 | + * this method reads class descriptors according to the format defined in | |
| 814 | + * the Object Serialization specification. | |
| 815 | + * | |
| 816 | + * @return the class descriptor read | |
| 817 | + * @throws IOException If an I/O error has occurred. | |
| 818 | + * @throws ClassNotFoundException If the Class of a serialized object used | |
| 819 | + * in the class descriptor representation cannot be found | |
| 820 | + * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass) | |
| 821 | + * @since 1.3 | |
| 822 | + */ | |
| 823 | + protected ObjectStreamClass readClassDescriptor() | |
| 824 | + throws IOException, ClassNotFoundException | |
| 825 | + { | |
| 826 | + ObjectStreamClass desc = new ObjectStreamClass(); | |
| 827 | + desc.readNonProxy(this); | |
| 828 | + return desc; | |
| 829 | + } | |
| 830 | + | |
| 831 | + /** | |
| 832 | + * Reads a byte of data. This method will block if no input is available. | |
| 833 | + * | |
| 834 | + * @return the byte read, or -1 if the end of the stream is reached. | |
| 835 | + * @throws IOException If an I/O error has occurred. | |
| 836 | + */ | |
| 837 | + public int read() throws IOException { | |
| 838 | + return bin.read(); | |
| 839 | + } | |
| 840 | + | |
| 841 | + /** | |
| 842 | + * Reads into an array of bytes. This method will block until some input | |
| 843 | + * is available. Consider using java.io.DataInputStream.readFully to read | |
| 844 | + * exactly 'length' bytes. | |
| 845 | + * | |
| 846 | + * @param buf the buffer into which the data is read | |
| 847 | + * @param off the start offset of the data | |
| 848 | + * @param len the maximum number of bytes read | |
| 849 | + * @return the actual number of bytes read, -1 is returned when the end of | |
| 850 | + * the stream is reached. | |
| 851 | + * @throws IOException If an I/O error has occurred. | |
| 852 | + * @see java.io.DataInputStream#readFully(byte[],int,int) | |
| 853 | + */ | |
| 854 | + public int read(byte[] buf, int off, int len) throws IOException { | |
| 855 | + if (buf == null) { | |
| 856 | + throw new NullPointerException(); | |
| 857 | + } | |
| 858 | + int endoff = off + len; | |
| 859 | + if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) { | |
| 860 | + throw new IndexOutOfBoundsException(); | |
| 861 | + } | |
| 862 | + return bin.read(buf, off, len, false); | |
| 863 | + } | |
| 864 | + | |
| 865 | + /** | |
| 866 | + * Returns the number of bytes that can be read without blocking. | |
| 867 | + * | |
| 868 | + * @return the number of available bytes. | |
| 869 | + * @throws IOException if there are I/O errors while reading from the | |
| 870 | + * underlying <code>InputStream</code> | |
| 871 | + */ | |
| 872 | + public int available() throws IOException { | |
| 873 | + return bin.available(); | |
| 874 | + } | |
| 875 | + | |
| 876 | + /** | |
| 877 | + * Closes the input stream. Must be called to release any resources | |
| 878 | + * associated with the stream. | |
| 879 | + * | |
| 880 | + * @throws IOException If an I/O error has occurred. | |
| 881 | + */ | |
| 882 | + public void close() throws IOException { | |
| 883 | + /* | |
| 884 | + * Even if stream already closed, propagate redundant close to | |
| 885 | + * underlying stream to stay consistent with previous implementations. | |
| 886 | + */ | |
| 887 | + closed = true; | |
| 888 | + if (depth == 0) { | |
| 889 | + clear(); | |
| 890 | + } | |
| 891 | + bin.close(); | |
| 892 | + } | |
| 893 | + | |
| 894 | + /** | |
| 895 | + * Reads in a boolean. | |
| 896 | + * | |
| 897 | + * @return the boolean read. | |
| 898 | + * @throws EOFException If end of file is reached. | |
| 899 | + * @throws IOException If other I/O error has occurred. | |
| 900 | + */ | |
| 901 | + public boolean readBoolean() throws IOException { | |
| 902 | + return bin.readBoolean(); | |
| 903 | + } | |
| 904 | + | |
| 905 | + /** | |
| 906 | + * Reads an 8 bit byte. | |
| 907 | + * | |
| 908 | + * @return the 8 bit byte read. | |
| 909 | + * @throws EOFException If end of file is reached. | |
| 910 | + * @throws IOException If other I/O error has occurred. | |
| 911 | + */ | |
| 912 | + public byte readByte() throws IOException { | |
| 913 | + return bin.readByte(); | |
| 914 | + } | |
| 915 | + | |
| 916 | + /** | |
| 917 | + * Reads an unsigned 8 bit byte. | |
| 918 | + * | |
| 919 | + * @return the 8 bit byte read. | |
| 920 | + * @throws EOFException If end of file is reached. | |
| 921 | + * @throws IOException If other I/O error has occurred. | |
| 922 | + */ | |
| 923 | + public int readUnsignedByte() throws IOException { | |
| 924 | + return bin.readUnsignedByte(); | |
| 925 | + } | |
| 926 | + | |
| 927 | + /** | |
| 928 | + * Reads a 16 bit char. | |
| 929 | + * | |
| 930 | + * @return the 16 bit char read. | |
| 931 | + * @throws EOFException If end of file is reached. | |
| 932 | + * @throws IOException If other I/O error has occurred. | |
| 933 | + */ | |
| 934 | + public char readChar() throws IOException { | |
| 935 | + return bin.readChar(); | |
| 936 | + } | |
| 937 | + | |
| 938 | + /** | |
| 939 | + * Reads a 16 bit short. | |
| 940 | + * | |
| 941 | + * @return the 16 bit short read. | |
| 942 | + * @throws EOFException If end of file is reached. | |
| 943 | + * @throws IOException If other I/O error has occurred. | |
| 944 | + */ | |
| 945 | + public short readShort() throws IOException { | |
| 946 | + return bin.readShort(); | |
| 947 | + } | |
| 948 | + | |
| 949 | + /** | |
| 950 | + * Reads an unsigned 16 bit short. | |
| 951 | + * | |
| 952 | + * @return the 16 bit short read. | |
| 953 | + * @throws EOFException If end of file is reached. | |
| 954 | + * @throws IOException If other I/O error has occurred. | |
| 955 | + */ | |
| 956 | + public int readUnsignedShort() throws IOException { | |
| 957 | + return bin.readUnsignedShort(); | |
| 958 | + } | |
| 959 | + | |
| 960 | + /** | |
| 961 | + * Reads a 32 bit int. | |
| 962 | + * | |
| 963 | + * @return the 32 bit integer read. | |
| 964 | + * @throws EOFException If end of file is reached. | |
| 965 | + * @throws IOException If other I/O error has occurred. | |
| 966 | + */ | |
| 967 | + public int readInt() throws IOException { | |
| 968 | + return bin.readInt(); | |
| 969 | + } | |
| 970 | + | |
| 971 | + /** | |
| 972 | + * Reads a 64 bit long. | |
| 973 | + * | |
| 974 | + * @return the read 64 bit long. | |
| 975 | + * @throws EOFException If end of file is reached. | |
| 976 | + * @throws IOException If other I/O error has occurred. | |
| 977 | + */ | |
| 978 | + public long readLong() throws IOException { | |
| 979 | + return bin.readLong(); | |
| 980 | + } | |
| 981 | + | |
| 982 | + /** | |
| 983 | + * Reads a 32 bit float. | |
| 984 | + * | |
| 985 | + * @return the 32 bit float read. | |
| 986 | + * @throws EOFException If end of file is reached. | |
| 987 | + * @throws IOException If other I/O error has occurred. | |
| 988 | + */ | |
| 989 | + public float readFloat() throws IOException { | |
| 990 | + return bin.readFloat(); | |
| 991 | + } | |
| 992 | + | |
| 993 | + /** | |
| 994 | + * Reads a 64 bit double. | |
| 995 | + * | |
| 996 | + * @return the 64 bit double read. | |
| 997 | + * @throws EOFException If end of file is reached. | |
| 998 | + * @throws IOException If other I/O error has occurred. | |
| 999 | + */ | |
| 1000 | + public double readDouble() throws IOException { | |
| 1001 | + return bin.readDouble(); | |
| 1002 | + } | |
| 1003 | + | |
| 1004 | + /** | |
| 1005 | + * Reads bytes, blocking until all bytes are read. | |
| 1006 | + * | |
| 1007 | + * @param buf the buffer into which the data is read | |
| 1008 | + * @throws EOFException If end of file is reached. | |
| 1009 | + * @throws IOException If other I/O error has occurred. | |
| 1010 | + */ | |
| 1011 | + public void readFully(byte[] buf) throws IOException { | |
| 1012 | + bin.readFully(buf, 0, buf.length, false); | |
| 1013 | + } | |
| 1014 | + | |
| 1015 | + /** | |
| 1016 | + * Reads bytes, blocking until all bytes are read. | |
| 1017 | + * | |
| 1018 | + * @param buf the buffer into which the data is read | |
| 1019 | + * @param off the start offset of the data | |
| 1020 | + * @param len the maximum number of bytes to read | |
| 1021 | + * @throws EOFException If end of file is reached. | |
| 1022 | + * @throws IOException If other I/O error has occurred. | |
| 1023 | + */ | |
| 1024 | + public void readFully(byte[] buf, int off, int len) throws IOException { | |
| 1025 | + int endoff = off + len; | |
| 1026 | + if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) { | |
| 1027 | + throw new IndexOutOfBoundsException(); | |
| 1028 | + } | |
| 1029 | + bin.readFully(buf, off, len, false); | |
| 1030 | + } | |
| 1031 | + | |
| 1032 | + /** | |
| 1033 | + * Skips bytes. | |
| 1034 | + * | |
| 1035 | + * @param len the number of bytes to be skipped | |
| 1036 | + * @return the actual number of bytes skipped. | |
| 1037 | + * @throws IOException If an I/O error has occurred. | |
| 1038 | + */ | |
| 1039 | + public int skipBytes(int len) throws IOException { | |
| 1040 | + return bin.skipBytes(len); | |
| 1041 | + } | |
| 1042 | + | |
| 1043 | + /** | |
| 1044 | + * Reads in a line that has been terminated by a \n, \r, \r\n or EOF. | |
| 1045 | + * | |
| 1046 | + * @return a String copy of the line. | |
| 1047 | + * @throws IOException if there are I/O errors while reading from the | |
| 1048 | + * underlying <code>InputStream</code> | |
| 1049 | + * @deprecated This method does not properly convert bytes to characters. | |
| 1050 | + * see DataInputStream for the details and alternatives. | |
| 1051 | + */ | |
| 1052 | + @Deprecated | |
| 1053 | + public String readLine() throws IOException { | |
| 1054 | + return bin.readLine(); | |
| 1055 | + } | |
| 1056 | + | |
| 1057 | + /** | |
| 1058 | + * Reads a String in | |
| 1059 | + * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> | |
| 1060 | + * format. | |
| 1061 | + * | |
| 1062 | + * @return the String. | |
| 1063 | + * @throws IOException if there are I/O errors while reading from the | |
| 1064 | + * underlying <code>InputStream</code> | |
| 1065 | + * @throws UTFDataFormatException if read bytes do not represent a valid | |
| 1066 | + * modified UTF-8 encoding of a string | |
| 1067 | + */ | |
| 1068 | + public String readUTF() throws IOException { | |
| 1069 | + return bin.readUTF(); | |
| 1070 | + } | |
| 1071 | + | |
| 1072 | + /** | |
| 1073 | + * Provide access to the persistent fields read from the input stream. | |
| 1074 | + */ | |
| 1075 | + public static abstract class GetField { | |
| 1076 | + | |
| 1077 | + /** | |
| 1078 | + * Get the ObjectStreamClass that describes the fields in the stream. | |
| 1079 | + * | |
| 1080 | + * @return the descriptor class that describes the serializable fields | |
| 1081 | + */ | |
| 1082 | + public abstract ObjectStreamClass getObjectStreamClass(); | |
| 1083 | + | |
| 1084 | + /** | |
| 1085 | + * Return true if the named field is defaulted and has no value in this | |
| 1086 | + * stream. | |
| 1087 | + * | |
| 1088 | + * @param name the name of the field | |
| 1089 | + * @return true, if and only if the named field is defaulted | |
| 1090 | + * @throws IOException if there are I/O errors while reading from | |
| 1091 | + * the underlying <code>InputStream</code> | |
| 1092 | + * @throws IllegalArgumentException if <code>name</code> does not | |
| 1093 | + * correspond to a serializable field | |
| 1094 | + */ | |
| 1095 | + public abstract boolean defaulted(String name) throws IOException; | |
| 1096 | + | |
| 1097 | + /** | |
| 1098 | + * Get the value of the named boolean field from the persistent field. | |
| 1099 | + * | |
| 1100 | + * @param name the name of the field | |
| 1101 | + * @param val the default value to use if <code>name</code> does not | |
| 1102 | + * have a value | |
| 1103 | + * @return the value of the named <code>boolean</code> field | |
| 1104 | + * @throws IOException if there are I/O errors while reading from the | |
| 1105 | + * underlying <code>InputStream</code> | |
| 1106 | + * @throws IllegalArgumentException if type of <code>name</code> is | |
| 1107 | + * not serializable or if the field type is incorrect | |
| 1108 | + */ | |
| 1109 | + public abstract boolean get(String name, boolean val) | |
| 1110 | + throws IOException; | |
| 1111 | + | |
| 1112 | + /** | |
| 1113 | + * Get the value of the named byte field from the persistent field. | |
| 1114 | + * | |
| 1115 | + * @param name the name of the field | |
| 1116 | + * @param val the default value to use if <code>name</code> does not | |
| 1117 | + * have a value | |
| 1118 | + * @return the value of the named <code>byte</code> field | |
| 1119 | + * @throws IOException if there are I/O errors while reading from the | |
| 1120 | + * underlying <code>InputStream</code> | |
| 1121 | + * @throws IllegalArgumentException if type of <code>name</code> is | |
| 1122 | + * not serializable or if the field type is incorrect | |
| 1123 | + */ | |
| 1124 | + public abstract byte get(String name, byte val) throws IOException; | |
| 1125 | + | |
| 1126 | + /** | |
| 1127 | + * Get the value of the named char field from the persistent field. | |
| 1128 | + * | |
| 1129 | + * @param name the name of the field | |
| 1130 | + * @param val the default value to use if <code>name</code> does not | |
| 1131 | + * have a value | |
| 1132 | + * @return the value of the named <code>char</code> field | |
| 1133 | + * @throws IOException if there are I/O errors while reading from the | |
| 1134 | + * underlying <code>InputStream</code> | |
| 1135 | + * @throws IllegalArgumentException if type of <code>name</code> is | |
| 1136 | + * not serializable or if the field type is incorrect | |
| 1137 | + */ | |
| 1138 | + public abstract char get(String name, char val) throws IOException; | |
| 1139 | + | |
| 1140 | + /** | |
| 1141 | + * Get the value of the named short field from the persistent field. | |
| 1142 | + * | |
| 1143 | + * @param name the name of the field | |
| 1144 | + * @param val the default value to use if <code>name</code> does not | |
| 1145 | + * have a value | |
| 1146 | + * @return the value of the named <code>short</code> field | |
| 1147 | + * @throws IOException if there are I/O errors while reading from the | |
| 1148 | + * underlying <code>InputStream</code> | |
| 1149 | + * @throws IllegalArgumentException if type of <code>name</code> is | |
| 1150 | + * not serializable or if the field type is incorrect | |
| 1151 | + */ | |
| 1152 | + public abstract short get(String name, short val) throws IOException; | |
| 1153 | + | |
| 1154 | + /** | |
| 1155 | + * Get the value of the named int field from the persistent field. | |
| 1156 | + * | |
| 1157 | + * @param name the name of the field | |
| 1158 | + * @param val the default value to use if <code>name</code> does not | |
| 1159 | + * have a value | |
| 1160 | + * @return the value of the named <code>int</code> field | |
| 1161 | + * @throws IOException if there are I/O errors while reading from the | |
| 1162 | + * underlying <code>InputStream</code> | |
| 1163 | + * @throws IllegalArgumentException if type of <code>name</code> is | |
| 1164 | + * not serializable or if the field type is incorrect | |
| 1165 | + */ | |
| 1166 | + public abstract int get(String name, int val) throws IOException; | |
| 1167 | + | |
| 1168 | + /** | |
| 1169 | + * Get the value of the named long field from the persistent field. | |
| 1170 | + * | |
| 1171 | + * @param name the name of the field | |
| 1172 | + * @param val the default value to use if <code>name</code> does not | |
| 1173 | + * have a value | |
| 1174 | + * @return the value of the named <code>long</code> field | |
| 1175 | + * @throws IOException if there are I/O errors while reading from the | |
| 1176 | + * underlying <code>InputStream</code> | |
| 1177 | + * @throws IllegalArgumentException if type of <code>name</code> is | |
| 1178 | + * not serializable or if the field type is incorrect | |
| 1179 | + */ | |
| 1180 | + public abstract long get(String name, long val) throws IOException; | |
| 1181 | + | |
| 1182 | + /** | |
| 1183 | + * Get the value of the named float field from the persistent field. | |
| 1184 | + * | |
| 1185 | + * @param name the name of the field | |
| 1186 | + * @param val the default value to use if <code>name</code> does not | |
| 1187 | + * have a value | |
| 1188 | + * @return the value of the named <code>float</code> field | |
| 1189 | + * @throws IOException if there are I/O errors while reading from the | |
| 1190 | + * underlying <code>InputStream</code> | |
| 1191 | + * @throws IllegalArgumentException if type of <code>name</code> is | |
| 1192 | + * not serializable or if the field type is incorrect | |
| 1193 | + */ | |
| 1194 | + public abstract float get(String name, float val) throws IOException; | |
| 1195 | + | |
| 1196 | + /** | |
| 1197 | + * Get the value of the named double field from the persistent field. | |
| 1198 | + * | |
| 1199 | + * @param name the name of the field | |
| 1200 | + * @param val the default value to use if <code>name</code> does not | |
| 1201 | + * have a value | |
| 1202 | + * @return the value of the named <code>double</code> field | |
| 1203 | + * @throws IOException if there are I/O errors while reading from the | |
| 1204 | + * underlying <code>InputStream</code> | |
| 1205 | + * @throws IllegalArgumentException if type of <code>name</code> is | |
| 1206 | + * not serializable or if the field type is incorrect | |
| 1207 | + */ | |
| 1208 | + public abstract double get(String name, double val) throws IOException; | |
| 1209 | + | |
| 1210 | + /** | |
| 1211 | + * Get the value of the named Object field from the persistent field. | |
| 1212 | + * | |
| 1213 | + * @param name the name of the field | |
| 1214 | + * @param val the default value to use if <code>name</code> does not | |
| 1215 | + * have a value | |
| 1216 | + * @return the value of the named <code>Object</code> field | |
| 1217 | + * @throws IOException if there are I/O errors while reading from the | |
| 1218 | + * underlying <code>InputStream</code> | |
| 1219 | + * @throws IllegalArgumentException if type of <code>name</code> is | |
| 1220 | + * not serializable or if the field type is incorrect | |
| 1221 | + */ | |
| 1222 | + public abstract Object get(String name, Object val) throws IOException; | |
| 1223 | + } | |
| 1224 | + | |
| 1225 | + /** | |
| 1226 | + * Verifies that this (possibly subclass) instance can be constructed | |
| 1227 | + * without violating security constraints: the subclass must not override | |
| 1228 | + * security-sensitive non-final methods, or else the | |
| 1229 | + * "enableSubclassImplementation" SerializablePermission is checked. | |
| 1230 | + */ | |
| 1231 | + private void verifySubclass() { | |
| 1232 | + Class cl = getClass(); | |
| 1233 | + if (cl == ObjectInputStream.class) { | |
| 1234 | + return; | |
| 1235 | + } | |
| 1236 | + SecurityManager sm = System.getSecurityManager(); | |
| 1237 | + if (sm == null) { | |
| 1238 | + return; | |
| 1239 | + } | |
| 1240 | + processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); | |
| 1241 | + WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); | |
| 1242 | + Boolean result = Caches.subclassAudits.get(key); | |
| 1243 | + if (result == null) { | |
| 1244 | + result = Boolean.valueOf(auditSubclass(cl)); | |
| 1245 | + Caches.subclassAudits.putIfAbsent(key, result); | |
| 1246 | + } | |
| 1247 | + if (result.booleanValue()) { | |
| 1248 | + return; | |
| 1249 | + } | |
| 1250 | + sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); | |
| 1251 | + } | |
| 1252 | + | |
| 1253 | + /** | |
| 1254 | + * Performs reflective checks on given subclass to verify that it doesn't | |
| 1255 | + * override security-sensitive non-final methods. Returns true if subclass | |
| 1256 | + * is "safe", false otherwise. | |
| 1257 | + */ | |
| 1258 | + private static boolean auditSubclass(final Class<?> subcl) { | |
| 1259 | + Boolean result = AccessController.doPrivileged( | |
| 1260 | + new PrivilegedAction<Boolean>() { | |
| 1261 | + public Boolean run() { | |
| 1262 | + for (Class<?> cl = subcl; | |
| 1263 | + cl != ObjectInputStream.class; | |
| 1264 | + cl = cl.getSuperclass()) | |
| 1265 | + { | |
| 1266 | + try { | |
| 1267 | + cl.getDeclaredMethod( | |
| 1268 | + "readUnshared", (Class[]) null); | |
| 1269 | + return Boolean.FALSE; | |
| 1270 | + } catch (NoSuchMethodException ex) { | |
| 1271 | + } | |
| 1272 | + try { | |
| 1273 | + cl.getDeclaredMethod("readFields", (Class[]) null); | |
| 1274 | + return Boolean.FALSE; | |
| 1275 | + } catch (NoSuchMethodException ex) { | |
| 1276 | + } | |
| 1277 | + } | |
| 1278 | + return Boolean.TRUE; | |
| 1279 | + } | |
| 1280 | + } | |
| 1281 | + ); | |
| 1282 | + return result.booleanValue(); | |
| 1283 | + } | |
| 1284 | + | |
| 1285 | + /** | |
| 1286 | + * Clears internal data structures. | |
| 1287 | + */ | |
| 1288 | + private void clear() { | |
| 1289 | + handles.clear(); | |
| 1290 | + vlist.clear(); | |
| 1291 | + } | |
| 1292 | + | |
| 1293 | + /** | |
| 1294 | + * Underlying readObject implementation. | |
| 1295 | + */ | |
| 1296 | + private Object readObject0(boolean unshared) throws IOException { | |
| 1297 | + boolean oldMode = bin.getBlockDataMode(); | |
| 1298 | + if (oldMode) { | |
| 1299 | + int remain = bin.currentBlockRemaining(); | |
| 1300 | + if (remain > 0) { | |
| 1301 | + throw new OptionalDataException(remain); | |
| 1302 | + } else if (defaultDataEnd) { | |
| 1303 | + /* | |
| 1304 | + * Fix for 4360508: stream is currently at the end of a field | |
| 1305 | + * value block written via default serialization; since there | |
| 1306 | + * is no terminating TC_ENDBLOCKDATA tag, simulate | |
| 1307 | + * end-of-custom-data behavior explicitly. | |
| 1308 | + */ | |
| 1309 | + throw new OptionalDataException(true); | |
| 1310 | + } | |
| 1311 | + bin.setBlockDataMode(false); | |
| 1312 | + } | |
| 1313 | + | |
| 1314 | + byte tc; | |
| 1315 | + while ((tc = bin.peekByte()) == TC_RESET) { | |
| 1316 | + bin.readByte(); | |
| 1317 | + handleReset(); | |
| 1318 | + } | |
| 1319 | + | |
| 1320 | + depth++; | |
| 1321 | + try { | |
| 1322 | + switch (tc) { | |
| 1323 | + case TC_NULL: | |
| 1324 | + return readNull(); | |
| 1325 | + | |
| 1326 | + case TC_REFERENCE: | |
| 1327 | + return readHandle(unshared); | |
| 1328 | + | |
| 1329 | + case TC_CLASS: | |
| 1330 | + return readClass(unshared); | |
| 1331 | + | |
| 1332 | + case TC_CLASSDESC: | |
| 1333 | + case TC_PROXYCLASSDESC: | |
| 1334 | + return readClassDesc(unshared); | |
| 1335 | + | |
| 1336 | + case TC_STRING: | |
| 1337 | + case TC_LONGSTRING: | |
| 1338 | + return checkResolve(readString(unshared)); | |
| 1339 | + | |
| 1340 | + case TC_ARRAY: | |
| 1341 | + return checkResolve(readArray(unshared)); | |
| 1342 | + | |
| 1343 | + case TC_ENUM: | |
| 1344 | + return checkResolve(readEnum(unshared)); | |
| 1345 | + | |
| 1346 | + case TC_OBJECT: | |
| 1347 | + return checkResolve(readOrdinaryObject(unshared)); | |
| 1348 | + | |
| 1349 | + case TC_EXCEPTION: | |
| 1350 | + IOException ex = readFatalException(); | |
| 1351 | + throw new WriteAbortedException("writing aborted", ex); | |
| 1352 | + | |
| 1353 | + case TC_BLOCKDATA: | |
| 1354 | + case TC_BLOCKDATALONG: | |
| 1355 | + if (oldMode) { | |
| 1356 | + bin.setBlockDataMode(true); | |
| 1357 | + bin.peek(); // force header read | |
| 1358 | + throw new OptionalDataException( | |
| 1359 | + bin.currentBlockRemaining()); | |
| 1360 | + } else { | |
| 1361 | + throw new StreamCorruptedException( | |
| 1362 | + "unexpected block data"); | |
| 1363 | + } | |
| 1364 | + | |
| 1365 | + case TC_ENDBLOCKDATA: | |
| 1366 | + if (oldMode) { | |
| 1367 | + throw new OptionalDataException(true); | |
| 1368 | + } else { | |
| 1369 | + throw new StreamCorruptedException( | |
| 1370 | + "unexpected end of block data"); | |
| 1371 | + } | |
| 1372 | + | |
| 1373 | + default: | |
| 1374 | + throw new StreamCorruptedException( | |
| 1375 | + String.format("invalid type code: %02X", tc)); | |
| 1376 | + } | |
| 1377 | + } finally { | |
| 1378 | + depth--; | |
| 1379 | + bin.setBlockDataMode(oldMode); | |
| 1380 | + } | |
| 1381 | + } | |
| 1382 | + | |
| 1383 | + /** | |
| 1384 | + * If resolveObject has been enabled and given object does not have an | |
| 1385 | + * exception associated with it, calls resolveObject to determine | |
| 1386 | + * replacement for object, and updates handle table accordingly. Returns | |
| 1387 | + * replacement object, or echoes provided object if no replacement | |
| 1388 | + * occurred. Expects that passHandle is set to given object's handle prior | |
| 1389 | + * to calling this method. | |
| 1390 | + */ | |
| 1391 | + private Object checkResolve(Object obj) throws IOException { | |
| 1392 | + if (!enableResolve || handles.lookupException(passHandle) != null) { | |
| 1393 | + return obj; | |
| 1394 | + } | |
| 1395 | + Object rep = resolveObject(obj); | |
| 1396 | + if (rep != obj) { | |
| 1397 | + handles.setObject(passHandle, rep); | |
| 1398 | + } | |
| 1399 | + return rep; | |
| 1400 | + } | |
| 1401 | + | |
| 1402 | + /** | |
| 1403 | + * Reads string without allowing it to be replaced in stream. Called from | |
| 1404 | + * within ObjectStreamClass.read(). | |
| 1405 | + */ | |
| 1406 | + String readTypeString() throws IOException { | |
| 1407 | + int oldHandle = passHandle; | |
| 1408 | + try { | |
| 1409 | + byte tc = bin.peekByte(); | |
| 1410 | + switch (tc) { | |
| 1411 | + case TC_NULL: | |
| 1412 | + return (String) readNull(); | |
| 1413 | + | |
| 1414 | + case TC_REFERENCE: | |
| 1415 | + return (String) readHandle(false); | |
| 1416 | + | |
| 1417 | + case TC_STRING: | |
| 1418 | + case TC_LONGSTRING: | |
| 1419 | + return readString(false); | |
| 1420 | + | |
| 1421 | + default: | |
| 1422 | + throw new StreamCorruptedException( | |
| 1423 | + String.format("invalid type code: %02X", tc)); | |
| 1424 | + } | |
| 1425 | + } finally { | |
| 1426 | + passHandle = oldHandle; | |
| 1427 | + } | |
| 1428 | + } | |
| 1429 | + | |
| 1430 | + /** | |
| 1431 | + * Reads in null code, sets passHandle to NULL_HANDLE and returns null. | |
| 1432 | + */ | |
| 1433 | + private Object readNull() throws IOException { | |
| 1434 | + if (bin.readByte() != TC_NULL) { | |
| 1435 | + throw new InternalError(); | |
| 1436 | + } | |
| 1437 | + passHandle = NULL_HANDLE; | |
| 1438 | + return null; | |
| 1439 | + } | |
| 1440 | + | |
| 1441 | + /** | |
| 1442 | + * Reads in object handle, sets passHandle to the read handle, and returns | |
| 1443 | + * object associated with the handle. | |
| 1444 | + */ | |
| 1445 | + private Object readHandle(boolean unshared) throws IOException { | |
| 1446 | + if (bin.readByte() != TC_REFERENCE) { | |
| 1447 | + throw new InternalError(); | |
| 1448 | + } | |
| 1449 | + passHandle = bin.readInt() - baseWireHandle; | |
| 1450 | + if (passHandle < 0 || passHandle >= handles.size()) { | |
| 1451 | + throw new StreamCorruptedException( | |
| 1452 | + String.format("invalid handle value: %08X", passHandle + | |
| 1453 | + baseWireHandle)); | |
| 1454 | + } | |
| 1455 | + if (unshared) { | |
| 1456 | + // REMIND: what type of exception to throw here? | |
| 1457 | + throw new InvalidObjectException( | |
| 1458 | + "cannot read back reference as unshared"); | |
| 1459 | + } | |
| 1460 | + | |
| 1461 | + Object obj = handles.lookupObject(passHandle); | |
| 1462 | + if (obj == unsharedMarker) { | |
| 1463 | + // REMIND: what type of exception to throw here? | |
| 1464 | + throw new InvalidObjectException( | |
| 1465 | + "cannot read back reference to unshared object"); | |
| 1466 | + } | |
| 1467 | + return obj; | |
| 1468 | + } | |
| 1469 | + | |
| 1470 | + /** | |
| 1471 | + * Reads in and returns class object. Sets passHandle to class object's | |
| 1472 | + * assigned handle. Returns null if class is unresolvable (in which case a | |
| 1473 | + * ClassNotFoundException will be associated with the class' handle in the | |
| 1474 | + * handle table). | |
| 1475 | + */ | |
| 1476 | + private Class readClass(boolean unshared) throws IOException { | |
| 1477 | + if (bin.readByte() != TC_CLASS) { | |
| 1478 | + throw new InternalError(); | |
| 1479 | + } | |
| 1480 | + ObjectStreamClass desc = readClassDesc(false); | |
| 1481 | + Class cl = desc.forClass(); | |
| 1482 | + passHandle = handles.assign(unshared ? unsharedMarker : cl); | |
| 1483 | + | |
| 1484 | + ClassNotFoundException resolveEx = desc.getResolveException(); | |
| 1485 | + if (resolveEx != null) { | |
| 1486 | + handles.markException(passHandle, resolveEx); | |
| 1487 | + } | |
| 1488 | + | |
| 1489 | + handles.finish(passHandle); | |
| 1490 | + return cl; | |
| 1491 | + } | |
| 1492 | + | |
| 1493 | + /** | |
| 1494 | + * Reads in and returns (possibly null) class descriptor. Sets passHandle | |
| 1495 | + * to class descriptor's assigned handle. If class descriptor cannot be | |
| 1496 | + * resolved to a class in the local VM, a ClassNotFoundException is | |
| 1497 | + * associated with the class descriptor's handle. | |
| 1498 | + */ | |
| 1499 | + private ObjectStreamClass readClassDesc(boolean unshared) | |
| 1500 | + throws IOException | |
| 1501 | + { | |
| 1502 | + byte tc = bin.peekByte(); | |
| 1503 | + switch (tc) { | |
| 1504 | + case TC_NULL: | |
| 1505 | + return (ObjectStreamClass) readNull(); | |
| 1506 | + | |
| 1507 | + case TC_REFERENCE: | |
| 1508 | + return (ObjectStreamClass) readHandle(unshared); | |
| 1509 | + | |
| 1510 | + case TC_PROXYCLASSDESC: | |
| 1511 | + return readProxyDesc(unshared); | |
| 1512 | + | |
| 1513 | + case TC_CLASSDESC: | |
| 1514 | + return readNonProxyDesc(unshared); | |
| 1515 | + | |
| 1516 | + default: | |
| 1517 | + throw new StreamCorruptedException( | |
| 1518 | + String.format("invalid type code: %02X", tc)); | |
| 1519 | + } | |
| 1520 | + } | |
| 1521 | + | |
| 1522 | + /** | |
| 1523 | + * Reads in and returns class descriptor for a dynamic proxy class. Sets | |
| 1524 | + * passHandle to proxy class descriptor's assigned handle. If proxy class | |
| 1525 | + * descriptor cannot be resolved to a class in the local VM, a | |
| 1526 | + * ClassNotFoundException is associated with the descriptor's handle. | |
| 1527 | + */ | |
| 1528 | + private ObjectStreamClass readProxyDesc(boolean unshared) | |
| 1529 | + throws IOException | |
| 1530 | + { | |
| 1531 | + if (bin.readByte() != TC_PROXYCLASSDESC) { | |
| 1532 | + throw new InternalError(); | |
| 1533 | + } | |
| 1534 | + | |
| 1535 | + ObjectStreamClass desc = new ObjectStreamClass(); | |
| 1536 | + int descHandle = handles.assign(unshared ? unsharedMarker : desc); | |
| 1537 | + passHandle = NULL_HANDLE; | |
| 1538 | + | |
| 1539 | + int numIfaces = bin.readInt(); | |
| 1540 | + String[] ifaces = new String[numIfaces]; | |
| 1541 | + for (int i = 0; i < numIfaces; i++) { | |
| 1542 | + ifaces[i] = bin.readUTF(); | |
| 1543 | + } | |
| 1544 | + | |
| 1545 | + Class cl = null; | |
| 1546 | + ClassNotFoundException resolveEx = null; | |
| 1547 | + bin.setBlockDataMode(true); | |
| 1548 | + try { | |
| 1549 | + if ((cl = resolveProxyClass(ifaces)) == null) { | |
| 1550 | + resolveEx = new ClassNotFoundException("null class"); | |
| 1551 | + } | |
| 1552 | + } catch (ClassNotFoundException ex) { | |
| 1553 | + resolveEx = ex; | |
| 1554 | + } | |
| 1555 | + skipCustomData(); | |
| 1556 | + | |
| 1557 | + desc.initProxy(cl, resolveEx, readClassDesc(false)); | |
| 1558 | + | |
| 1559 | + handles.finish(descHandle); | |
| 1560 | + passHandle = descHandle; | |
| 1561 | + return desc; | |
| 1562 | + } | |
| 1563 | + | |
| 1564 | + /** | |
| 1565 | + * Reads in and returns class descriptor for a class that is not a dynamic | |
| 1566 | + * proxy class. Sets passHandle to class descriptor's assigned handle. If | |
| 1567 | + * class descriptor cannot be resolved to a class in the local VM, a | |
| 1568 | + * ClassNotFoundException is associated with the descriptor's handle. | |
| 1569 | + */ | |
| 1570 | + private ObjectStreamClass readNonProxyDesc(boolean unshared) | |
| 1571 | + throws IOException | |
| 1572 | + { | |
| 1573 | + if (bin.readByte() != TC_CLASSDESC) { | |
| 1574 | + throw new InternalError(); | |
| 1575 | + } | |
| 1576 | + | |
| 1577 | + ObjectStreamClass desc = new ObjectStreamClass(); | |
| 1578 | + int descHandle = handles.assign(unshared ? unsharedMarker : desc); | |
| 1579 | + passHandle = NULL_HANDLE; | |
| 1580 | + | |
| 1581 | + ObjectStreamClass readDesc = null; | |
| 1582 | + try { | |
| 1583 | + readDesc = readClassDescriptor(); | |
| 1584 | + } catch (ClassNotFoundException ex) { | |
| 1585 | + throw (IOException) new InvalidClassException( | |
| 1586 | + "failed to read class descriptor").initCause(ex); | |
| 1587 | + } | |
| 1588 | + | |
| 1589 | + Class cl = null; | |
| 1590 | + ClassNotFoundException resolveEx = null; | |
| 1591 | + bin.setBlockDataMode(true); | |
| 1592 | + try { | |
| 1593 | + if ((cl = resolveClass(readDesc)) == null) { | |
| 1594 | + resolveEx = new ClassNotFoundException("null class"); | |
| 1595 | + } | |
| 1596 | + } catch (ClassNotFoundException ex) { | |
| 1597 | + resolveEx = ex; | |
| 1598 | + } | |
| 1599 | + skipCustomData(); | |
| 1600 | + | |
| 1601 | + desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false)); | |
| 1602 | + | |
| 1603 | + handles.finish(descHandle); | |
| 1604 | + passHandle = descHandle; | |
| 1605 | + return desc; | |
| 1606 | + } | |
| 1607 | + | |
| 1608 | + /** | |
| 1609 | + * Reads in and returns new string. Sets passHandle to new string's | |
| 1610 | + * assigned handle. | |
| 1611 | + */ | |
| 1612 | + private String readString(boolean unshared) throws IOException { | |
| 1613 | + String str; | |
| 1614 | + byte tc = bin.readByte(); | |
| 1615 | + switch (tc) { | |
| 1616 | + case TC_STRING: | |
| 1617 | + str = bin.readUTF(); | |
| 1618 | + break; | |
| 1619 | + | |
| 1620 | + case TC_LONGSTRING: | |
| 1621 | + str = bin.readLongUTF(); | |
| 1622 | + break; | |
| 1623 | + | |
| 1624 | + default: | |
| 1625 | + throw new StreamCorruptedException( | |
| 1626 | + String.format("invalid type code: %02X", tc)); | |
| 1627 | + } | |
| 1628 | + passHandle = handles.assign(unshared ? unsharedMarker : str); | |
| 1629 | + handles.finish(passHandle); | |
| 1630 | + return str; | |
| 1631 | + } | |
| 1632 | + | |
| 1633 | + /** | |
| 1634 | + * Reads in and returns array object, or null if array class is | |
| 1635 | + * unresolvable. Sets passHandle to array's assigned handle. | |
| 1636 | + */ | |
| 1637 | + private Object readArray(boolean unshared) throws IOException { | |
| 1638 | + if (bin.readByte() != TC_ARRAY) { | |
| 1639 | + throw new InternalError(); | |
| 1640 | + } | |
| 1641 | + | |
| 1642 | + ObjectStreamClass desc = readClassDesc(false); | |
| 1643 | + int len = bin.readInt(); | |
| 1644 | + | |
| 1645 | + Object array = null; | |
| 1646 | + Class cl, ccl = null; | |
| 1647 | + if ((cl = desc.forClass()) != null) { | |
| 1648 | + ccl = cl.getComponentType(); | |
| 1649 | + array = Array.newInstance(ccl, len); | |
| 1650 | + } | |
| 1651 | + | |
| 1652 | + int arrayHandle = handles.assign(unshared ? unsharedMarker : array); | |
| 1653 | + ClassNotFoundException resolveEx = desc.getResolveException(); | |
| 1654 | + if (resolveEx != null) { | |
| 1655 | + handles.markException(arrayHandle, resolveEx); | |
| 1656 | + } | |
| 1657 | + | |
| 1658 | + if (ccl == null) { | |
| 1659 | + for (int i = 0; i < len; i++) { | |
| 1660 | + readObject0(false); | |
| 1661 | + } | |
| 1662 | + } else if (ccl.isPrimitive()) { | |
| 1663 | + if (ccl == Integer.TYPE) { | |
| 1664 | + bin.readInts((int[]) array, 0, len); | |
| 1665 | + } else if (ccl == Byte.TYPE) { | |
| 1666 | + bin.readFully((byte[]) array, 0, len, true); | |
| 1667 | + } else if (ccl == Long.TYPE) { | |
| 1668 | + bin.readLongs((long[]) array, 0, len); | |
| 1669 | + } else if (ccl == Float.TYPE) { | |
| 1670 | + bin.readFloats((float[]) array, 0, len); | |
| 1671 | + } else if (ccl == Double.TYPE) { | |
| 1672 | + bin.readDoubles((double[]) array, 0, len); | |
| 1673 | + } else if (ccl == Short.TYPE) { | |
| 1674 | + bin.readShorts((short[]) array, 0, len); | |
| 1675 | + } else if (ccl == Character.TYPE) { | |
| 1676 | + bin.readChars((char[]) array, 0, len); | |
| 1677 | + } else if (ccl == Boolean.TYPE) { | |
| 1678 | + bin.readBooleans((boolean[]) array, 0, len); | |
| 1679 | + } else { | |
| 1680 | + throw new InternalError(); | |
| 1681 | + } | |
| 1682 | + } else { | |
| 1683 | + Object[] oa = (Object[]) array; | |
| 1684 | + for (int i = 0; i < len; i++) { | |
| 1685 | + oa[i] = readObject0(false); | |
| 1686 | + handles.markDependency(arrayHandle, passHandle); | |
| 1687 | + } | |
| 1688 | + } | |
| 1689 | + | |
| 1690 | + handles.finish(arrayHandle); | |
| 1691 | + passHandle = arrayHandle; | |
| 1692 | + return array; | |
| 1693 | + } | |
| 1694 | + | |
| 1695 | + /** | |
| 1696 | + * Reads in and returns enum constant, or null if enum type is | |
| 1697 | + * unresolvable. Sets passHandle to enum constant's assigned handle. | |
| 1698 | + */ | |
| 1699 | + private Enum readEnum(boolean unshared) throws IOException { | |
| 1700 | + if (bin.readByte() != TC_ENUM) { | |
| 1701 | + throw new InternalError(); | |
| 1702 | + } | |
| 1703 | + | |
| 1704 | + ObjectStreamClass desc = readClassDesc(false); | |
| 1705 | + if (!desc.isEnum()) { | |
| 1706 | + throw new InvalidClassException("non-enum class: " + desc); | |
| 1707 | + } | |
| 1708 | + | |
| 1709 | + int enumHandle = handles.assign(unshared ? unsharedMarker : null); | |
| 1710 | + ClassNotFoundException resolveEx = desc.getResolveException(); | |
| 1711 | + if (resolveEx != null) { | |
| 1712 | + handles.markException(enumHandle, resolveEx); | |
| 1713 | + } | |
| 1714 | + | |
| 1715 | + String name = readString(false); | |
| 1716 | + Enum en = null; | |
| 1717 | + Class cl = desc.forClass(); | |
| 1718 | + if (cl != null) { | |
| 1719 | + try { | |
| 1720 | + en = Enum.valueOf(cl, name); | |
| 1721 | + } catch (IllegalArgumentException ex) { | |
| 1722 | + throw (IOException) new InvalidObjectException( | |
| 1723 | + "enum constant " + name + " does not exist in " + | |
| 1724 | + cl).initCause(ex); | |
| 1725 | + } | |
| 1726 | + if (!unshared) { | |
| 1727 | + handles.setObject(enumHandle, en); | |
| 1728 | + } | |
| 1729 | + } | |
| 1730 | + | |
| 1731 | + handles.finish(enumHandle); | |
| 1732 | + passHandle = enumHandle; | |
| 1733 | + return en; | |
| 1734 | + } | |
| 1735 | + | |
| 1736 | + /** | |
| 1737 | + * Reads and returns "ordinary" (i.e., not a String, Class, | |
| 1738 | + * ObjectStreamClass, array, or enum constant) object, or null if object's | |
| 1739 | + * class is unresolvable (in which case a ClassNotFoundException will be | |
| 1740 | + * associated with object's handle). Sets passHandle to object's assigned | |
| 1741 | + * handle. | |
| 1742 | + */ | |
| 1743 | + private Object readOrdinaryObject(boolean unshared) | |
| 1744 | + throws IOException | |
| 1745 | + { | |
| 1746 | + if (bin.readByte() != TC_OBJECT) { | |
| 1747 | + throw new InternalError(); | |
| 1748 | + } | |
| 1749 | + | |
| 1750 | + ObjectStreamClass desc = readClassDesc(false); | |
| 1751 | + desc.checkDeserialize(); | |
| 1752 | + | |
| 1753 | + Object obj; | |
| 1754 | + try { | |
| 1755 | + obj = desc.isInstantiable() ? desc.newInstance() : null; | |
| 1756 | + } catch (Exception ex) { | |
| 1757 | + throw (IOException) new InvalidClassException( | |
| 1758 | + desc.forClass().getName(), | |
| 1759 | + "unable to create instance").initCause(ex); | |
| 1760 | + } | |
| 1761 | + | |
| 1762 | + passHandle = handles.assign(unshared ? unsharedMarker : obj); | |
| 1763 | + ClassNotFoundException resolveEx = desc.getResolveException(); | |
| 1764 | + if (resolveEx != null) { | |
| 1765 | + handles.markException(passHandle, resolveEx); | |
| 1766 | + } | |
| 1767 | + | |
| 1768 | + if (desc.isExternalizable()) { | |
| 1769 | + readExternalData((Externalizable) obj, desc); | |
| 1770 | + } else { | |
| 1771 | + readSerialData(obj, desc); | |
| 1772 | + } | |
| 1773 | + | |
| 1774 | + handles.finish(passHandle); | |
| 1775 | + | |
| 1776 | + if (obj != null && | |
| 1777 | + handles.lookupException(passHandle) == null && | |
| 1778 | + desc.hasReadResolveMethod()) | |
| 1779 | + { | |
| 1780 | + Object rep = desc.invokeReadResolve(obj); | |
| 1781 | + if (unshared && rep.getClass().isArray()) { | |
| 1782 | + rep = cloneArray(rep); | |
| 1783 | + } | |
| 1784 | + if (rep != obj) { | |
| 1785 | + handles.setObject(passHandle, obj = rep); | |
| 1786 | + } | |
| 1787 | + } | |
| 1788 | + | |
| 1789 | + return obj; | |
| 1790 | + } | |
| 1791 | + | |
| 1792 | + /** | |
| 1793 | + * If obj is non-null, reads externalizable data by invoking readExternal() | |
| 1794 | + * method of obj; otherwise, attempts to skip over externalizable data. | |
| 1795 | + * Expects that passHandle is set to obj's handle before this method is | |
| 1796 | + * called. | |
| 1797 | + */ | |
| 1798 | + private void readExternalData(Externalizable obj, ObjectStreamClass desc) | |
| 1799 | + throws IOException | |
| 1800 | + { | |
| 1801 | + SerialCallbackContext oldContext = curContext; | |
| 1802 | + curContext = null; | |
| 1803 | + try { | |
| 1804 | + boolean blocked = desc.hasBlockExternalData(); | |
| 1805 | + if (blocked) { | |
| 1806 | + bin.setBlockDataMode(true); | |
| 1807 | + } | |
| 1808 | + if (obj != null) { | |
| 1809 | + try { | |
| 1810 | + obj.readExternal(this); | |
| 1811 | + } catch (ClassNotFoundException ex) { | |
| 1812 | + /* | |
| 1813 | + * In most cases, the handle table has already propagated | |
| 1814 | + * a CNFException to passHandle at this point; this mark | |
| 1815 | + * call is included to address cases where the readExternal | |
| 1816 | + * method has cons'ed and thrown a new CNFException of its | |
| 1817 | + * own. | |
| 1818 | + */ | |
| 1819 | + handles.markException(passHandle, ex); | |
| 1820 | + } | |
| 1821 | + } | |
| 1822 | + if (blocked) { | |
| 1823 | + skipCustomData(); | |
| 1824 | + } | |
| 1825 | + } finally { | |
| 1826 | + curContext = oldContext; | |
| 1827 | + } | |
| 1828 | + /* | |
| 1829 | + * At this point, if the externalizable data was not written in | |
| 1830 | + * block-data form and either the externalizable class doesn't exist | |
| 1831 | + * locally (i.e., obj == null) or readExternal() just threw a | |
| 1832 | + * CNFException, then the stream is probably in an inconsistent state, | |
| 1833 | + * since some (or all) of the externalizable data may not have been | |
| 1834 | + * consumed. Since there's no "correct" action to take in this case, | |
| 1835 | + * we mimic the behavior of past serialization implementations and | |
| 1836 | + * blindly hope that the stream is in sync; if it isn't and additional | |
| 1837 | + * externalizable data remains in the stream, a subsequent read will | |
| 1838 | + * most likely throw a StreamCorruptedException. | |
| 1839 | + */ | |
| 1840 | + } | |
| 1841 | + | |
| 1842 | + /** | |
| 1843 | + * Reads (or attempts to skip, if obj is null or is tagged with a | |
| 1844 | + * ClassNotFoundException) instance data for each serializable class of | |
| 1845 | + * object in stream, from superclass to subclass. Expects that passHandle | |
| 1846 | + * is set to obj's handle before this method is called. | |
| 1847 | + */ | |
| 1848 | + private void readSerialData(Object obj, ObjectStreamClass desc) | |
| 1849 | + throws IOException | |
| 1850 | + { | |
| 1851 | + ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); | |
| 1852 | + for (int i = 0; i < slots.length; i++) { | |
| 1853 | + ObjectStreamClass slotDesc = slots[i].desc; | |
| 1854 | + | |
| 1855 | + if (slots[i].hasData) { | |
| 1856 | + if (obj != null && | |
| 1857 | + slotDesc.hasReadObjectMethod() && | |
| 1858 | + handles.lookupException(passHandle) == null) | |
| 1859 | + { | |
| 1860 | + SerialCallbackContext oldContext = curContext; | |
| 1861 | + | |
| 1862 | + try { | |
| 1863 | + curContext = new SerialCallbackContext(obj, slotDesc); | |
| 1864 | + | |
| 1865 | + bin.setBlockDataMode(true); | |
| 1866 | + slotDesc.invokeReadObject(obj, this); | |
| 1867 | + } catch (ClassNotFoundException ex) { | |
| 1868 | + /* | |
| 1869 | + * In most cases, the handle table has already | |
| 1870 | + * propagated a CNFException to passHandle at this | |
| 1871 | + * point; this mark call is included to address cases | |
| 1872 | + * where the custom readObject method has cons'ed and | |
| 1873 | + * thrown a new CNFException of its own. | |
| 1874 | + */ | |
| 1875 | + handles.markException(passHandle, ex); | |
| 1876 | + } finally { | |
| 1877 | + curContext.setUsed(); | |
| 1878 | + curContext = oldContext; | |
| 1879 | + } | |
| 1880 | + | |
| 1881 | + /* | |
| 1882 | + * defaultDataEnd may have been set indirectly by custom | |
| 1883 | + * readObject() method when calling defaultReadObject() or | |
| 1884 | + * readFields(); clear it to restore normal read behavior. | |
| 1885 | + */ | |
| 1886 | + defaultDataEnd = false; | |
| 1887 | + } else { | |
| 1888 | + defaultReadFields(obj, slotDesc); | |
| 1889 | + } | |
| 1890 | + if (slotDesc.hasWriteObjectData()) { | |
| 1891 | + skipCustomData(); | |
| 1892 | + } else { | |
| 1893 | + bin.setBlockDataMode(false); | |
| 1894 | + } | |
| 1895 | + } else { | |
| 1896 | + if (obj != null && | |
| 1897 | + slotDesc.hasReadObjectNoDataMethod() && | |
| 1898 | + handles.lookupException(passHandle) == null) | |
| 1899 | + { | |
| 1900 | + slotDesc.invokeReadObjectNoData(obj); | |
| 1901 | + } | |
| 1902 | + } | |
| 1903 | + } | |
| 1904 | + } | |
| 1905 | + | |
| 1906 | + /** | |
| 1907 | + * Skips over all block data and objects until TC_ENDBLOCKDATA is | |
| 1908 | + * encountered. | |
| 1909 | + */ | |
| 1910 | + private void skipCustomData() throws IOException { | |
| 1911 | + int oldHandle = passHandle; | |
| 1912 | + for (;;) { | |
| 1913 | + if (bin.getBlockDataMode()) { | |
| 1914 | + bin.skipBlockData(); | |
| 1915 | + bin.setBlockDataMode(false); | |
| 1916 | + } | |
| 1917 | + switch (bin.peekByte()) { | |
| 1918 | + case TC_BLOCKDATA: | |
| 1919 | + case TC_BLOCKDATALONG: | |
| 1920 | + bin.setBlockDataMode(true); | |
| 1921 | + break; | |
| 1922 | + | |
| 1923 | + case TC_ENDBLOCKDATA: | |
| 1924 | + bin.readByte(); | |
| 1925 | + passHandle = oldHandle; | |
| 1926 | + return; | |
| 1927 | + | |
| 1928 | + default: | |
| 1929 | + readObject0(false); | |
| 1930 | + break; | |
| 1931 | + } | |
| 1932 | + } | |
| 1933 | + } | |
| 1934 | + | |
| 1935 | + /** | |
| 1936 | + * Reads in values of serializable fields declared by given class | |
| 1937 | + * descriptor. If obj is non-null, sets field values in obj. Expects that | |
| 1938 | + * passHandle is set to obj's handle before this method is called. | |
| 1939 | + */ | |
| 1940 | + private void defaultReadFields(Object obj, ObjectStreamClass desc) | |
| 1941 | + throws IOException | |
| 1942 | + { | |
| 1943 | + // REMIND: is isInstance check necessary? | |
| 1944 | + Class cl = desc.forClass(); | |
| 1945 | + if (cl != null && obj != null && !cl.isInstance(obj)) { | |
| 1946 | + throw new ClassCastException(); | |
| 1947 | + } | |
| 1948 | + | |
| 1949 | + int primDataSize = desc.getPrimDataSize(); | |
| 1950 | + if (primVals == null || primVals.length < primDataSize) { | |
| 1951 | + primVals = new byte[primDataSize]; | |
| 1952 | + } | |
| 1953 | + bin.readFully(primVals, 0, primDataSize, false); | |
| 1954 | + if (obj != null) { | |
| 1955 | + desc.setPrimFieldValues(obj, primVals); | |
| 1956 | + } | |
| 1957 | + | |
| 1958 | + int objHandle = passHandle; | |
| 1959 | + ObjectStreamField[] fields = desc.getFields(false); | |
| 1960 | + Object[] objVals = new Object[desc.getNumObjFields()]; | |
| 1961 | + int numPrimFields = fields.length - objVals.length; | |
| 1962 | + for (int i = 0; i < objVals.length; i++) { | |
| 1963 | + ObjectStreamField f = fields[numPrimFields + i]; | |
| 1964 | + objVals[i] = readObject0(f.isUnshared()); | |
| 1965 | + if (f.getField() != null) { | |
| 1966 | + handles.markDependency(objHandle, passHandle); | |
| 1967 | + } | |
| 1968 | + } | |
| 1969 | + if (obj != null) { | |
| 1970 | + desc.setObjFieldValues(obj, objVals); | |
| 1971 | + } | |
| 1972 | + passHandle = objHandle; | |
| 1973 | + } | |
| 1974 | + | |
| 1975 | + /** | |
| 1976 | + * Reads in and returns IOException that caused serialization to abort. | |
| 1977 | + * All stream state is discarded prior to reading in fatal exception. Sets | |
| 1978 | + * passHandle to fatal exception's handle. | |
| 1979 | + */ | |
| 1980 | + private IOException readFatalException() throws IOException { | |
| 1981 | + if (bin.readByte() != TC_EXCEPTION) { | |
| 1982 | + throw new InternalError(); | |
| 1983 | + } | |
| 1984 | + clear(); | |
| 1985 | + return (IOException) readObject0(false); | |
| 1986 | + } | |
| 1987 | + | |
| 1988 | + /** | |
| 1989 | + * If recursion depth is 0, clears internal data structures; otherwise, | |
| 1990 | + * throws a StreamCorruptedException. This method is called when a | |
| 1991 | + * TC_RESET typecode is encountered. | |
| 1992 | + */ | |
| 1993 | + private void handleReset() throws StreamCorruptedException { | |
| 1994 | + if (depth > 0) { | |
| 1995 | + throw new StreamCorruptedException( | |
| 1996 | + "unexpected reset; recursion depth: " + depth); | |
| 1997 | + } | |
| 1998 | + clear(); | |
| 1999 | + } | |
| 2000 | + | |
| 2001 | + /** | |
| 2002 | + * Converts specified span of bytes into float values. | |
| 2003 | + */ | |
| 2004 | + // REMIND: remove once hotspot inlines Float.intBitsToFloat | |
| 2005 | + private static native void bytesToFloats(byte[] src, int srcpos, | |
| 2006 | + float[] dst, int dstpos, | |
| 2007 | + int nfloats); | |
| 2008 | + | |
| 2009 | + /** | |
| 2010 | + * Converts specified span of bytes into double values. | |
| 2011 | + */ | |
| 2012 | + // REMIND: remove once hotspot inlines Double.longBitsToDouble | |
| 2013 | + private static native void bytesToDoubles(byte[] src, int srcpos, | |
| 2014 | + double[] dst, int dstpos, | |
| 2015 | + int ndoubles); | |
| 2016 | + | |
| 2017 | + /** | |
| 2018 | + * Returns the first non-null class loader (not counting class loaders of | |
| 2019 | + * generated reflection implementation classes) up the execution stack, or | |
| 2020 | + * null if only code from the null class loader is on the stack. This | |
| 2021 | + * method is also called via reflection by the following RMI-IIOP class: | |
| 2022 | + * | |
| 2023 | + * com.sun.corba.se.internal.util.JDKClassLoader | |
| 2024 | + * | |
| 2025 | + * This method should not be removed or its signature changed without | |
| 2026 | + * corresponding modifications to the above class. | |
| 2027 | + */ | |
| 2028 | + // REMIND: change name to something more accurate? | |
| 2029 | + private static native ClassLoader latestUserDefinedLoader(); | |
| 2030 | + | |
| 2031 | + /** | |
| 2032 | + * Default GetField implementation. | |
| 2033 | + */ | |
| 2034 | + private class GetFieldImpl extends GetField { | |
| 2035 | + | |
| 2036 | + /** class descriptor describing serializable fields */ | |
| 2037 | + private final ObjectStreamClass desc; | |
| 2038 | + /** primitive field values */ | |
| 2039 | + private final byte[] primVals; | |
| 2040 | + /** object field values */ | |
| 2041 | + private final Object[] objVals; | |
| 2042 | + /** object field value handles */ | |
| 2043 | + private final int[] objHandles; | |
| 2044 | + | |
| 2045 | + /** | |
| 2046 | + * Creates GetFieldImpl object for reading fields defined in given | |
| 2047 | + * class descriptor. | |
| 2048 | + */ | |
| 2049 | + GetFieldImpl(ObjectStreamClass desc) { | |
| 2050 | + this.desc = desc; | |
| 2051 | + primVals = new byte[desc.getPrimDataSize()]; | |
| 2052 | + objVals = new Object[desc.getNumObjFields()]; | |
| 2053 | + objHandles = new int[objVals.length]; | |
| 2054 | + } | |
| 2055 | + | |
| 2056 | + public ObjectStreamClass getObjectStreamClass() { | |
| 2057 | + return desc; | |
| 2058 | + } | |
| 2059 | + | |
| 2060 | + public boolean defaulted(String name) throws IOException { | |
| 2061 | + return (getFieldOffset(name, null) < 0); | |
| 2062 | + } | |
| 2063 | + | |
| 2064 | + public boolean get(String name, boolean val) throws IOException { | |
| 2065 | + int off = getFieldOffset(name, Boolean.TYPE); | |
| 2066 | + return (off >= 0) ? Bits.getBoolean(primVals, off) : val; | |
| 2067 | + } | |
| 2068 | + | |
| 2069 | + public byte get(String name, byte val) throws IOException { | |
| 2070 | + int off = getFieldOffset(name, Byte.TYPE); | |
| 2071 | + return (off >= 0) ? primVals[off] : val; | |
| 2072 | + } | |
| 2073 | + | |
| 2074 | + public char get(String name, char val) throws IOException { | |
| 2075 | + int off = getFieldOffset(name, Character.TYPE); | |
| 2076 | + return (off >= 0) ? Bits.getChar(primVals, off) : val; | |
| 2077 | + } | |
| 2078 | + | |
| 2079 | + public short get(String name, short val) throws IOException { | |
| 2080 | + int off = getFieldOffset(name, Short.TYPE); | |
| 2081 | + return (off >= 0) ? Bits.getShort(primVals, off) : val; | |
| 2082 | + } | |
| 2083 | + | |
| 2084 | + public int get(String name, int val) throws IOException { | |
| 2085 | + int off = getFieldOffset(name, Integer.TYPE); | |
| 2086 | + return (off >= 0) ? Bits.getInt(primVals, off) : val; | |
| 2087 | + } | |
| 2088 | + | |
| 2089 | + public float get(String name, float val) throws IOException { | |
| 2090 | + int off = getFieldOffset(name, Float.TYPE); | |
| 2091 | + return (off >= 0) ? Bits.getFloat(primVals, off) : val; | |
| 2092 | + } | |
| 2093 | + | |
| 2094 | + public long get(String name, long val) throws IOException { | |
| 2095 | + int off = getFieldOffset(name, Long.TYPE); | |
| 2096 | + return (off >= 0) ? Bits.getLong(primVals, off) : val; | |
| 2097 | + } | |
| 2098 | + | |
| 2099 | + public double get(String name, double val) throws IOException { | |
| 2100 | + int off = getFieldOffset(name, Double.TYPE); | |
| 2101 | + return (off >= 0) ? Bits.getDouble(primVals, off) : val; | |
| 2102 | + } | |
| 2103 | + | |
| 2104 | + public Object get(String name, Object val) throws IOException { | |
| 2105 | + int off = getFieldOffset(name, Object.class); | |
| 2106 | + if (off >= 0) { | |
| 2107 | + int objHandle = objHandles[off]; | |
| 2108 | + handles.markDependency(passHandle, objHandle); | |
| 2109 | + return (handles.lookupException(objHandle) == null) ? | |
| 2110 | + objVals[off] : null; | |
| 2111 | + } else { | |
| 2112 | + return val; | |
| 2113 | + } | |
| 2114 | + } | |
| 2115 | + | |
| 2116 | + /** | |
| 2117 | + * Reads primitive and object field values from stream. | |
| 2118 | + */ | |
| 2119 | + void readFields() throws IOException { | |
| 2120 | + bin.readFully(primVals, 0, primVals.length, false); | |
| 2121 | + | |
| 2122 | + int oldHandle = passHandle; | |
| 2123 | + ObjectStreamField[] fields = desc.getFields(false); | |
| 2124 | + int numPrimFields = fields.length - objVals.length; | |
| 2125 | + for (int i = 0; i < objVals.length; i++) { | |
| 2126 | + objVals[i] = | |
| 2127 | + readObject0(fields[numPrimFields + i].isUnshared()); | |
| 2128 | + objHandles[i] = passHandle; | |
| 2129 | + } | |
| 2130 | + passHandle = oldHandle; | |
| 2131 | + } | |
| 2132 | + | |
| 2133 | + /** | |
| 2134 | + * Returns offset of field with given name and type. A specified type | |
| 2135 | + * of null matches all types, Object.class matches all non-primitive | |
| 2136 | + * types, and any other non-null type matches assignable types only. | |
| 2137 | + * If no matching field is found in the (incoming) class | |
| 2138 | + * descriptor but a matching field is present in the associated local | |
| 2139 | + * class descriptor, returns -1. Throws IllegalArgumentException if | |
| 2140 | + * neither incoming nor local class descriptor contains a match. | |
| 2141 | + */ | |
| 2142 | + private int getFieldOffset(String name, Class type) { | |
| 2143 | + ObjectStreamField field = desc.getField(name, type); | |
| 2144 | + if (field != null) { | |
| 2145 | + return field.getOffset(); | |
| 2146 | + } else if (desc.getLocalDesc().getField(name, type) != null) { | |
| 2147 | + return -1; | |
| 2148 | + } else { | |
| 2149 | + throw new IllegalArgumentException("no such field " + name + | |
| 2150 | + " with type " + type); | |
| 2151 | + } | |
| 2152 | + } | |
| 2153 | + } | |
| 2154 | + | |
| 2155 | + /** | |
| 2156 | + * Prioritized list of callbacks to be performed once object graph has been | |
| 2157 | + * completely deserialized. | |
| 2158 | + */ | |
| 2159 | + private static class ValidationList { | |
| 2160 | + | |
| 2161 | + private static class Callback { | |
| 2162 | + final ObjectInputValidation obj; | |
| 2163 | + final int priority; | |
| 2164 | + Callback next; | |
| 2165 | + final AccessControlContext acc; | |
| 2166 | + | |
| 2167 | + Callback(ObjectInputValidation obj, int priority, Callback next, | |
| 2168 | + AccessControlContext acc) | |
| 2169 | + { | |
| 2170 | + this.obj = obj; | |
| 2171 | + this.priority = priority; | |
| 2172 | + this.next = next; | |
| 2173 | + this.acc = acc; | |
| 2174 | + } | |
| 2175 | + } | |
| 2176 | + | |
| 2177 | + /** linked list of callbacks */ | |
| 2178 | + private Callback list; | |
| 2179 | + | |
| 2180 | + /** | |
| 2181 | + * Creates new (empty) ValidationList. | |
| 2182 | + */ | |
| 2183 | + ValidationList() { | |
| 2184 | + } | |
| 2185 | + | |
| 2186 | + /** | |
| 2187 | + * Registers callback. Throws InvalidObjectException if callback | |
| 2188 | + * object is null. | |
| 2189 | + */ | |
| 2190 | + void register(ObjectInputValidation obj, int priority) | |
| 2191 | + throws InvalidObjectException | |
| 2192 | + { | |
| 2193 | + if (obj == null) { | |
| 2194 | + throw new InvalidObjectException("null callback"); | |
| 2195 | + } | |
| 2196 | + | |
| 2197 | + Callback prev = null, cur = list; | |
| 2198 | + while (cur != null && priority < cur.priority) { | |
| 2199 | + prev = cur; | |
| 2200 | + cur = cur.next; | |
| 2201 | + } | |
| 2202 | + AccessControlContext acc = AccessController.getContext(); | |
| 2203 | + if (prev != null) { | |
| 2204 | + prev.next = new Callback(obj, priority, cur, acc); | |
| 2205 | + } else { | |
| 2206 | + list = new Callback(obj, priority, list, acc); | |
| 2207 | + } | |
| 2208 | + } | |
| 2209 | + | |
| 2210 | + /** | |
| 2211 | + * Invokes all registered callbacks and clears the callback list. | |
| 2212 | + * Callbacks with higher priorities are called first; those with equal | |
| 2213 | + * priorities may be called in any order. If any of the callbacks | |
| 2214 | + * throws an InvalidObjectException, the callback process is terminated | |
| 2215 | + * and the exception propagated upwards. | |
| 2216 | + */ | |
| 2217 | + void doCallbacks() throws InvalidObjectException { | |
| 2218 | + try { | |
| 2219 | + while (list != null) { | |
| 2220 | + AccessController.doPrivileged( | |
| 2221 | + new PrivilegedExceptionAction<Void>() | |
| 2222 | + { | |
| 2223 | + public Void run() throws InvalidObjectException { | |
| 2224 | + list.obj.validateObject(); | |
| 2225 | + return null; | |
| 2226 | + } | |
| 2227 | + }, list.acc); | |
| 2228 | + list = list.next; | |
| 2229 | + } | |
| 2230 | + } catch (PrivilegedActionException ex) { | |
| 2231 | + list = null; | |
| 2232 | + throw (InvalidObjectException) ex.getException(); | |
| 2233 | + } | |
| 2234 | + } | |
| 2235 | + | |
| 2236 | + /** | |
| 2237 | + * Resets the callback list to its initial (empty) state. | |
| 2238 | + */ | |
| 2239 | + public void clear() { | |
| 2240 | + list = null; | |
| 2241 | + } | |
| 2242 | + } | |
| 2243 | + | |
| 2244 | + /** | |
| 2245 | + * Input stream supporting single-byte peek operations. | |
| 2246 | + */ | |
| 2247 | + private static class PeekInputStream extends InputStream { | |
| 2248 | + | |
| 2249 | + /** underlying stream */ | |
| 2250 | + private final InputStream in; | |
| 2251 | + /** peeked byte */ | |
| 2252 | + private int peekb = -1; | |
| 2253 | + | |
| 2254 | + /** | |
| 2255 | + * Creates new PeekInputStream on top of given underlying stream. | |
| 2256 | + */ | |
| 2257 | + PeekInputStream(InputStream in) { | |
| 2258 | + this.in = in; | |
| 2259 | + } | |
| 2260 | + | |
| 2261 | + /** | |
| 2262 | + * Peeks at next byte value in stream. Similar to read(), except | |
| 2263 | + * that it does not consume the read value. | |
| 2264 | + */ | |
| 2265 | + int peek() throws IOException { | |
| 2266 | + return (peekb >= 0) ? peekb : (peekb = in.read()); | |
| 2267 | + } | |
| 2268 | + | |
| 2269 | + public int read() throws IOException { | |
| 2270 | + if (peekb >= 0) { | |
| 2271 | + int v = peekb; | |
| 2272 | + peekb = -1; | |
| 2273 | + return v; | |
| 2274 | + } else { | |
| 2275 | + return in.read(); | |
| 2276 | + } | |
| 2277 | + } | |
| 2278 | + | |
| 2279 | + public int read(byte[] b, int off, int len) throws IOException { | |
| 2280 | + if (len == 0) { | |
| 2281 | + return 0; | |
| 2282 | + } else if (peekb < 0) { | |
| 2283 | + return in.read(b, off, len); | |
| 2284 | + } else { | |
| 2285 | + b[off++] = (byte) peekb; | |
| 2286 | + len--; | |
| 2287 | + peekb = -1; | |
| 2288 | + int n = in.read(b, off, len); | |
| 2289 | + return (n >= 0) ? (n + 1) : 1; | |
| 2290 | + } | |
| 2291 | + } | |
| 2292 | + | |
| 2293 | + void readFully(byte[] b, int off, int len) throws IOException { | |
| 2294 | + int n = 0; | |
| 2295 | + while (n < len) { | |
| 2296 | + int count = read(b, off + n, len - n); | |
| 2297 | + if (count < 0) { | |
| 2298 | + throw new EOFException(); | |
| 2299 | + } | |
| 2300 | + n += count; | |
| 2301 | + } | |
| 2302 | + } | |
| 2303 | + | |
| 2304 | + public long skip(long n) throws IOException { | |
| 2305 | + if (n <= 0) { | |
| 2306 | + return 0; | |
| 2307 | + } | |
| 2308 | + int skipped = 0; | |
| 2309 | + if (peekb >= 0) { | |
| 2310 | + peekb = -1; | |
| 2311 | + skipped++; | |
| 2312 | + n--; | |
| 2313 | + } | |
| 2314 | + return skipped + skip(n); | |
| 2315 | + } | |
| 2316 | + | |
| 2317 | + public int available() throws IOException { | |
| 2318 | + return in.available() + ((peekb >= 0) ? 1 : 0); | |
| 2319 | + } | |
| 2320 | + | |
| 2321 | + public void close() throws IOException { | |
| 2322 | + in.close(); | |
| 2323 | + } | |
| 2324 | + } | |
| 2325 | + | |
| 2326 | + /** | |
| 2327 | + * Input stream with two modes: in default mode, inputs data written in the | |
| 2328 | + * same format as DataOutputStream; in "block data" mode, inputs data | |
| 2329 | + * bracketed by block data markers (see object serialization specification | |
| 2330 | + * for details). Buffering depends on block data mode: when in default | |
| 2331 | + * mode, no data is buffered in advance; when in block data mode, all data | |
| 2332 | + * for the current data block is read in at once (and buffered). | |
| 2333 | + */ | |
| 2334 | + private class BlockDataInputStream | |
| 2335 | + extends InputStream implements DataInput | |
| 2336 | + { | |
| 2337 | + /** maximum data block length */ | |
| 2338 | + private static final int MAX_BLOCK_SIZE = 1024; | |
| 2339 | + /** maximum data block header length */ | |
| 2340 | + private static final int MAX_HEADER_SIZE = 5; | |
| 2341 | + /** (tunable) length of char buffer (for reading strings) */ | |
| 2342 | + private static final int CHAR_BUF_SIZE = 256; | |
| 2343 | + /** readBlockHeader() return value indicating header read may block */ | |
| 2344 | + private static final int HEADER_BLOCKED = -2; | |
| 2345 | + | |
| 2346 | + /** buffer for reading general/block data */ | |
| 2347 | + private final byte[] buf = new byte[MAX_BLOCK_SIZE]; | |
| 2348 | + /** buffer for reading block data headers */ | |
| 2349 | + private final byte[] hbuf = new byte[MAX_HEADER_SIZE]; | |
| 2350 | + /** char buffer for fast string reads */ | |
| 2351 | + private final char[] cbuf = new char[CHAR_BUF_SIZE]; | |
| 2352 | + | |
| 2353 | + /** block data mode */ | |
| 2354 | + private boolean blkmode = false; | |
| 2355 | + | |
| 2356 | + // block data state fields; values meaningful only when blkmode true | |
| 2357 | + /** current offset into buf */ | |
| 2358 | + private int pos = 0; | |
| 2359 | + /** end offset of valid data in buf, or -1 if no more block data */ | |
| 2360 | + private int end = -1; | |
| 2361 | + /** number of bytes in current block yet to be read from stream */ | |
| 2362 | + private int unread = 0; | |
| 2363 | + | |
| 2364 | + /** underlying stream (wrapped in peekable filter stream) */ | |
| 2365 | + private final PeekInputStream in; | |
| 2366 | + /** loopback stream (for data reads that span data blocks) */ | |
| 2367 | + private final DataInputStream din; | |
| 2368 | + | |
| 2369 | + /** | |
| 2370 | + * Creates new BlockDataInputStream on top of given underlying stream. | |
| 2371 | + * Block data mode is turned off by default. | |
| 2372 | + */ | |
| 2373 | + BlockDataInputStream(InputStream in) { | |
| 2374 | + this.in = new PeekInputStream(in); | |
| 2375 | + din = new DataInputStream(this); | |
| 2376 | + } | |
| 2377 | + | |
| 2378 | + /** | |
| 2379 | + * Sets block data mode to the given mode (true == on, false == off) | |
| 2380 | + * and returns the previous mode value. If the new mode is the same as | |
| 2381 | + * the old mode, no action is taken. Throws IllegalStateException if | |
| 2382 | + * block data mode is being switched from on to off while unconsumed | |
| 2383 | + * block data is still present in the stream. | |
| 2384 | + */ | |
| 2385 | + boolean setBlockDataMode(boolean newmode) throws IOException { | |
| 2386 | + if (blkmode == newmode) { | |
| 2387 | + return blkmode; | |
| 2388 | + } | |
| 2389 | + if (newmode) { | |
| 2390 | + pos = 0; | |
| 2391 | + end = 0; | |
| 2392 | + unread = 0; | |
| 2393 | + } else if (pos < end) { | |
| 2394 | + throw new IllegalStateException("unread block data"); | |
| 2395 | + } | |
| 2396 | + blkmode = newmode; | |
| 2397 | + return !blkmode; | |
| 2398 | + } | |
| 2399 | + | |
| 2400 | + /** | |
| 2401 | + * Returns true if the stream is currently in block data mode, false | |
| 2402 | + * otherwise. | |
| 2403 | + */ | |
| 2404 | + boolean getBlockDataMode() { | |
| 2405 | + return blkmode; | |
| 2406 | + } | |
| 2407 | + | |
| 2408 | + /** | |
| 2409 | + * If in block data mode, skips to the end of the current group of data | |
| 2410 | + * blocks (but does not unset block data mode). If not in block data | |
| 2411 | + * mode, throws an IllegalStateException. | |
| 2412 | + */ | |
| 2413 | + void skipBlockData() throws IOException { | |
| 2414 | + if (!blkmode) { | |
| 2415 | + throw new IllegalStateException("not in block data mode"); | |
| 2416 | + } | |
| 2417 | + while (end >= 0) { | |
| 2418 | + refill(); | |
| 2419 | + } | |
| 2420 | + } | |
| 2421 | + | |
| 2422 | + /** | |
| 2423 | + * Attempts to read in the next block data header (if any). If | |
| 2424 | + * canBlock is false and a full header cannot be read without possibly | |
| 2425 | + * blocking, returns HEADER_BLOCKED, else if the next element in the | |
| 2426 | + * stream is a block data header, returns the block data length | |
| 2427 | + * specified by the header, else returns -1. | |
| 2428 | + */ | |
| 2429 | + private int readBlockHeader(boolean canBlock) throws IOException { | |
| 2430 | + if (defaultDataEnd) { | |
| 2431 | + /* | |
| 2432 | + * Fix for 4360508: stream is currently at the end of a field | |
| 2433 | + * value block written via default serialization; since there | |
| 2434 | + * is no terminating TC_ENDBLOCKDATA tag, simulate | |
| 2435 | + * end-of-custom-data behavior explicitly. | |
| 2436 | + */ | |
| 2437 | + return -1; | |
| 2438 | + } | |
| 2439 | + try { | |
| 2440 | + for (;;) { | |
| 2441 | + int avail = canBlock ? Integer.MAX_VALUE : in.available(); | |
| 2442 | + if (avail == 0) { | |
| 2443 | + return HEADER_BLOCKED; | |
| 2444 | + } | |
| 2445 | + | |
| 2446 | + int tc = in.peek(); | |
| 2447 | + switch (tc) { | |
| 2448 | + case TC_BLOCKDATA: | |
| 2449 | + if (avail < 2) { | |
| 2450 | + return HEADER_BLOCKED; | |
| 2451 | + } | |
| 2452 | + in.readFully(hbuf, 0, 2); | |
| 2453 | + return hbuf[1] & 0xFF; | |
| 2454 | + | |
| 2455 | + case TC_BLOCKDATALONG: | |
| 2456 | + if (avail < 5) { | |
| 2457 | + return HEADER_BLOCKED; | |
| 2458 | + } | |
| 2459 | + in.readFully(hbuf, 0, 5); | |
| 2460 | + int len = Bits.getInt(hbuf, 1); | |
| 2461 | + if (len < 0) { | |
| 2462 | + throw new StreamCorruptedException( | |
| 2463 | + "illegal block data header length: " + | |
| 2464 | + len); | |
| 2465 | + } | |
| 2466 | + return len; | |
| 2467 | + | |
| 2468 | + /* | |
| 2469 | + * TC_RESETs may occur in between data blocks. | |
| 2470 | + * Unfortunately, this case must be parsed at a lower | |
| 2471 | + * level than other typecodes, since primitive data | |
| 2472 | + * reads may span data blocks separated by a TC_RESET. | |
| 2473 | + */ | |
| 2474 | + case TC_RESET: | |
| 2475 | + in.read(); | |
| 2476 | + handleReset(); | |
| 2477 | + break; | |
| 2478 | + | |
| 2479 | + default: | |
| 2480 | + if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) { | |
| 2481 | + throw new StreamCorruptedException( | |
| 2482 | + String.format("invalid type code: %02X", | |
| 2483 | + tc)); | |
| 2484 | + } | |
| 2485 | + return -1; | |
| 2486 | + } | |
| 2487 | + } | |
| 2488 | + } catch (EOFException ex) { | |
| 2489 | + throw new StreamCorruptedException( | |
| 2490 | + "unexpected EOF while reading block data header"); | |
| 2491 | + } | |
| 2492 | + } | |
| 2493 | + | |
| 2494 | + /** | |
| 2495 | + * Refills internal buffer buf with block data. Any data in buf at the | |
| 2496 | + * time of the call is considered consumed. Sets the pos, end, and | |
| 2497 | + * unread fields to reflect the new amount of available block data; if | |
| 2498 | + * the next element in the stream is not a data block, sets pos and | |
| 2499 | + * unread to 0 and end to -1. | |
| 2500 | + */ | |
| 2501 | + private void refill() throws IOException { | |
| 2502 | + try { | |
| 2503 | + do { | |
| 2504 | + pos = 0; | |
| 2505 | + if (unread > 0) { | |
| 2506 | + int n = | |
| 2507 | + in.read(buf, 0, Math.min(unread, MAX_BLOCK_SIZE)); | |
| 2508 | + if (n >= 0) { | |
| 2509 | + end = n; | |
| 2510 | + unread -= n; | |
| 2511 | + } else { | |
| 2512 | + throw new StreamCorruptedException( | |
| 2513 | + "unexpected EOF in middle of data block"); | |
| 2514 | + } | |
| 2515 | + } else { | |
| 2516 | + int n = readBlockHeader(true); | |
| 2517 | + if (n >= 0) { | |
| 2518 | + end = 0; | |
| 2519 | + unread = n; | |
| 2520 | + } else { | |
| 2521 | + end = -1; | |
| 2522 | + unread = 0; | |
| 2523 | + } | |
| 2524 | + } | |
| 2525 | + } while (pos == end); | |
| 2526 | + } catch (IOException ex) { | |
| 2527 | + pos = 0; | |
| 2528 | + end = -1; | |
| 2529 | + unread = 0; | |
| 2530 | + throw ex; | |
| 2531 | + } | |
| 2532 | + } | |
| 2533 | + | |
| 2534 | + /** | |
| 2535 | + * If in block data mode, returns the number of unconsumed bytes | |
| 2536 | + * remaining in the current data block. If not in block data mode, | |
| 2537 | + * throws an IllegalStateException. | |
| 2538 | + */ | |
| 2539 | + int currentBlockRemaining() { | |
| 2540 | + if (blkmode) { | |
| 2541 | + return (end >= 0) ? (end - pos) + unread : 0; | |
| 2542 | + } else { | |
| 2543 | + throw new IllegalStateException(); | |
| 2544 | + } | |
| 2545 | + } | |
| 2546 | + | |
| 2547 | + /** | |
| 2548 | + * Peeks at (but does not consume) and returns the next byte value in | |
| 2549 | + * the stream, or -1 if the end of the stream/block data (if in block | |
| 2550 | + * data mode) has been reached. | |
| 2551 | + */ | |
| 2552 | + int peek() throws IOException { | |
| 2553 | + if (blkmode) { | |
| 2554 | + if (pos == end) { | |
| 2555 | + refill(); | |
| 2556 | + } | |
| 2557 | + return (end >= 0) ? (buf[pos] & 0xFF) : -1; | |
| 2558 | + } else { | |
| 2559 | + return in.peek(); | |
| 2560 | + } | |
| 2561 | + } | |
| 2562 | + | |
| 2563 | + /** | |
| 2564 | + * Peeks at (but does not consume) and returns the next byte value in | |
| 2565 | + * the stream, or throws EOFException if end of stream/block data has | |
| 2566 | + * been reached. | |
| 2567 | + */ | |
| 2568 | + byte peekByte() throws IOException { | |
| 2569 | + int val = peek(); | |
| 2570 | + if (val < 0) { | |
| 2571 | + throw new EOFException(); | |
| 2572 | + } | |
| 2573 | + return (byte) val; | |
| 2574 | + } | |
| 2575 | + | |
| 2576 | + | |
| 2577 | + /* ----------------- generic input stream methods ------------------ */ | |
| 2578 | + /* | |
| 2579 | + * The following methods are equivalent to their counterparts in | |
| 2580 | + * InputStream, except that they interpret data block boundaries and | |
| 2581 | + * read the requested data from within data blocks when in block data | |
| 2582 | + * mode. | |
| 2583 | + */ | |
| 2584 | + | |
| 2585 | + public int read() throws IOException { | |
| 2586 | + if (blkmode) { | |
| 2587 | + if (pos == end) { | |
| 2588 | + refill(); | |
| 2589 | + } | |
| 2590 | + return (end >= 0) ? (buf[pos++] & 0xFF) : -1; | |
| 2591 | + } else { | |
| 2592 | + return in.read(); | |
| 2593 | + } | |
| 2594 | + } | |
| 2595 | + | |
| 2596 | + public int read(byte[] b, int off, int len) throws IOException { | |
| 2597 | + return read(b, off, len, false); | |
| 2598 | + } | |
| 2599 | + | |
| 2600 | + public long skip(long len) throws IOException { | |
| 2601 | + long remain = len; | |
| 2602 | + while (remain > 0) { | |
| 2603 | + if (blkmode) { | |
| 2604 | + if (pos == end) { | |
| 2605 | + refill(); | |
| 2606 | + } | |
| 2607 | + if (end < 0) { | |
| 2608 | + break; | |
| 2609 | + } | |
| 2610 | + int nread = (int) Math.min(remain, end - pos); | |
| 2611 | + remain -= nread; | |
| 2612 | + pos += nread; | |
| 2613 | + } else { | |
| 2614 | + int nread = (int) Math.min(remain, MAX_BLOCK_SIZE); | |
| 2615 | + if ((nread = in.read(buf, 0, nread)) < 0) { | |
| 2616 | + break; | |
| 2617 | + } | |
| 2618 | + remain -= nread; | |
| 2619 | + } | |
| 2620 | + } | |
| 2621 | + return len - remain; | |
| 2622 | + } | |
| 2623 | + | |
| 2624 | + public int available() throws IOException { | |
| 2625 | + if (blkmode) { | |
| 2626 | + if ((pos == end) && (unread == 0)) { | |
| 2627 | + int n; | |
| 2628 | + while ((n = readBlockHeader(false)) == 0) ; | |
| 2629 | + switch (n) { | |
| 2630 | + case HEADER_BLOCKED: | |
| 2631 | + break; | |
| 2632 | + | |
| 2633 | + case -1: | |
| 2634 | + pos = 0; | |
| 2635 | + end = -1; | |
| 2636 | + break; | |
| 2637 | + | |
| 2638 | + default: | |
| 2639 | + pos = 0; | |
| 2640 | + end = 0; | |
| 2641 | + unread = n; | |
| 2642 | + break; | |
| 2643 | + } | |
| 2644 | + } | |
| 2645 | + // avoid unnecessary call to in.available() if possible | |
| 2646 | + int unreadAvail = (unread > 0) ? | |
| 2647 | + Math.min(in.available(), unread) : 0; | |
| 2648 | + return (end >= 0) ? (end - pos) + unreadAvail : 0; | |
| 2649 | + } else { | |
| 2650 | + return in.available(); | |
| 2651 | + } | |
| 2652 | + } | |
| 2653 | + | |
| 2654 | + public void close() throws IOException { | |
| 2655 | + if (blkmode) { | |
| 2656 | + pos = 0; | |
| 2657 | + end = -1; | |
| 2658 | + unread = 0; | |
| 2659 | + } | |
| 2660 | + in.close(); | |
| 2661 | + } | |
| 2662 | + | |
| 2663 | + /** | |
| 2664 | + * Attempts to read len bytes into byte array b at offset off. Returns | |
| 2665 | + * the number of bytes read, or -1 if the end of stream/block data has | |
| 2666 | + * been reached. If copy is true, reads values into an intermediate | |
| 2667 | + * buffer before copying them to b (to avoid exposing a reference to | |
| 2668 | + * b). | |
| 2669 | + */ | |
| 2670 | + int read(byte[] b, int off, int len, boolean copy) throws IOException { | |
| 2671 | + if (len == 0) { | |
| 2672 | + return 0; | |
| 2673 | + } else if (blkmode) { | |
| 2674 | + if (pos == end) { | |
| 2675 | + refill(); | |
| 2676 | + } | |
| 2677 | + if (end < 0) { | |
| 2678 | + return -1; | |
| 2679 | + } | |
| 2680 | + int nread = Math.min(len, end - pos); | |
| 2681 | + System.arraycopy(buf, pos, b, off, nread); | |
| 2682 | + pos += nread; | |
| 2683 | + return nread; | |
| 2684 | + } else if (copy) { | |
| 2685 | + int nread = in.read(buf, 0, Math.min(len, MAX_BLOCK_SIZE)); | |
| 2686 | + if (nread > 0) { | |
| 2687 | + System.arraycopy(buf, 0, b, off, nread); | |
| 2688 | + } | |
| 2689 | + return nread; | |
| 2690 | + } else { | |
| 2691 | + return in.read(b, off, len); | |
| 2692 | + } | |
| 2693 | + } | |
| 2694 | + | |
| 2695 | + /* ----------------- primitive data input methods ------------------ */ | |
| 2696 | + /* | |
| 2697 | + * The following methods are equivalent to their counterparts in | |
| 2698 | + * DataInputStream, except that they interpret data block boundaries | |
| 2699 | + * and read the requested data from within data blocks when in block | |
| 2700 | + * data mode. | |
| 2701 | + */ | |
| 2702 | + | |
| 2703 | + public void readFully(byte[] b) throws IOException { | |
| 2704 | + readFully(b, 0, b.length, false); | |
| 2705 | + } | |
| 2706 | + | |
| 2707 | + public void readFully(byte[] b, int off, int len) throws IOException { | |
| 2708 | + readFully(b, off, len, false); | |
| 2709 | + } | |
| 2710 | + | |
| 2711 | + public void readFully(byte[] b, int off, int len, boolean copy) | |
| 2712 | + throws IOException | |
| 2713 | + { | |
| 2714 | + while (len > 0) { | |
| 2715 | + int n = read(b, off, len, copy); | |
| 2716 | + if (n < 0) { | |
| 2717 | + throw new EOFException(); | |
| 2718 | + } | |
| 2719 | + off += n; | |
| 2720 | + len -= n; | |
| 2721 | + } | |
| 2722 | + } | |
| 2723 | + | |
| 2724 | + public int skipBytes(int n) throws IOException { | |
| 2725 | + return din.skipBytes(n); | |
| 2726 | + } | |
| 2727 | + | |
| 2728 | + public boolean readBoolean() throws IOException { | |
| 2729 | + int v = read(); | |
| 2730 | + if (v < 0) { | |
| 2731 | + throw new EOFException(); | |
| 2732 | + } | |
| 2733 | + return (v != 0); | |
| 2734 | + } | |
| 2735 | + | |
| 2736 | + public byte readByte() throws IOException { | |
| 2737 | + int v = read(); | |
| 2738 | + if (v < 0) { | |
| 2739 | + throw new EOFException(); | |
| 2740 | + } | |
| 2741 | + return (byte) v; | |
| 2742 | + } | |
| 2743 | + | |
| 2744 | + public int readUnsignedByte() throws IOException { | |
| 2745 | + int v = read(); | |
| 2746 | + if (v < 0) { | |
| 2747 | + throw new EOFException(); | |
| 2748 | + } | |
| 2749 | + return v; | |
| 2750 | + } | |
| 2751 | + | |
| 2752 | + public char readChar() throws IOException { | |
| 2753 | + if (!blkmode) { | |
| 2754 | + pos = 0; | |
| 2755 | + in.readFully(buf, 0, 2); | |
| 2756 | + } else if (end - pos < 2) { | |
| 2757 | + return din.readChar(); | |
| 2758 | + } | |
| 2759 | + char v = Bits.getChar(buf, pos); | |
| 2760 | + pos += 2; | |
| 2761 | + return v; | |
| 2762 | + } | |
| 2763 | + | |
| 2764 | + public short readShort() throws IOException { | |
| 2765 | + if (!blkmode) { | |
| 2766 | + pos = 0; | |
| 2767 | + in.readFully(buf, 0, 2); | |
| 2768 | + } else if (end - pos < 2) { | |
| 2769 | + return din.readShort(); | |
| 2770 | + } | |
| 2771 | + short v = Bits.getShort(buf, pos); | |
| 2772 | + pos += 2; | |
| 2773 | + return v; | |
| 2774 | + } | |
| 2775 | + | |
| 2776 | + public int readUnsignedShort() throws IOException { | |
| 2777 | + if (!blkmode) { | |
| 2778 | + pos = 0; | |
| 2779 | + in.readFully(buf, 0, 2); | |
| 2780 | + } else if (end - pos < 2) { | |
| 2781 | + return din.readUnsignedShort(); | |
| 2782 | + } | |
| 2783 | + int v = Bits.getShort(buf, pos) & 0xFFFF; | |
| 2784 | + pos += 2; | |
| 2785 | + return v; | |
| 2786 | + } | |
| 2787 | + | |
| 2788 | + public int readInt() throws IOException { | |
| 2789 | + if (!blkmode) { | |
| 2790 | + pos = 0; | |
| 2791 | + in.readFully(buf, 0, 4); | |
| 2792 | + } else if (end - pos < 4) { | |
| 2793 | + return din.readInt(); | |
| 2794 | + } | |
| 2795 | + int v = Bits.getInt(buf, pos); | |
| 2796 | + pos += 4; | |
| 2797 | + return v; | |
| 2798 | + } | |
| 2799 | + | |
| 2800 | + public float readFloat() throws IOException { | |
| 2801 | + if (!blkmode) { | |
| 2802 | + pos = 0; | |
| 2803 | + in.readFully(buf, 0, 4); | |
| 2804 | + } else if (end - pos < 4) { | |
| 2805 | + return din.readFloat(); | |
| 2806 | + } | |
| 2807 | + float v = Bits.getFloat(buf, pos); | |
| 2808 | + pos += 4; | |
| 2809 | + return v; | |
| 2810 | + } | |
| 2811 | + | |
| 2812 | + public long readLong() throws IOException { | |
| 2813 | + if (!blkmode) { | |
| 2814 | + pos = 0; | |
| 2815 | + in.readFully(buf, 0, 8); | |
| 2816 | + } else if (end - pos < 8) { | |
| 2817 | + return din.readLong(); | |
| 2818 | + } | |
| 2819 | + long v = Bits.getLong(buf, pos); | |
| 2820 | + pos += 8; | |
| 2821 | + return v; | |
| 2822 | + } | |
| 2823 | + | |
| 2824 | + public double readDouble() throws IOException { | |
| 2825 | + if (!blkmode) { | |
| 2826 | + pos = 0; | |
| 2827 | + in.readFully(buf, 0, 8); | |
| 2828 | + } else if (end - pos < 8) { | |
| 2829 | + return din.readDouble(); | |
| 2830 | + } | |
| 2831 | + double v = Bits.getDouble(buf, pos); | |
| 2832 | + pos += 8; | |
| 2833 | + return v; | |
| 2834 | + } | |
| 2835 | + | |
| 2836 | + public String readUTF() throws IOException { | |
| 2837 | + return readUTFBody(readUnsignedShort()); | |
| 2838 | + } | |
| 2839 | + | |
| 2840 | + public String readLine() throws IOException { | |
| 2841 | + return din.readLine(); // deprecated, not worth optimizing | |
| 2842 | + } | |
| 2843 | + | |
| 2844 | + /* -------------- primitive data array input methods --------------- */ | |
| 2845 | + /* | |
| 2846 | + * The following methods read in spans of primitive data values. | |
| 2847 | + * Though equivalent to calling the corresponding primitive read | |
| 2848 | + * methods repeatedly, these methods are optimized for reading groups | |
| 2849 | + * of primitive data values more efficiently. | |
| 2850 | + */ | |
| 2851 | + | |
| 2852 | + void readBooleans(boolean[] v, int off, int len) throws IOException { | |
| 2853 | + int stop, endoff = off + len; | |
| 2854 | + while (off < endoff) { | |
| 2855 | + if (!blkmode) { | |
| 2856 | + int span = Math.min(endoff - off, MAX_BLOCK_SIZE); | |
| 2857 | + in.readFully(buf, 0, span); | |
| 2858 | + stop = off + span; | |
| 2859 | + pos = 0; | |
| 2860 | + } else if (end - pos < 1) { | |
| 2861 | + v[off++] = din.readBoolean(); | |
| 2862 | + continue; | |
| 2863 | + } else { | |
| 2864 | + stop = Math.min(endoff, off + end - pos); | |
| 2865 | + } | |
| 2866 | + | |
| 2867 | + while (off < stop) { | |
| 2868 | + v[off++] = Bits.getBoolean(buf, pos++); | |
| 2869 | + } | |
| 2870 | + } | |
| 2871 | + } | |
| 2872 | + | |
| 2873 | + void readChars(char[] v, int off, int len) throws IOException { | |
| 2874 | + int stop, endoff = off + len; | |
| 2875 | + while (off < endoff) { | |
| 2876 | + if (!blkmode) { | |
| 2877 | + int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1); | |
| 2878 | + in.readFully(buf, 0, span << 1); | |
| 2879 | + stop = off + span; | |
| 2880 | + pos = 0; | |
| 2881 | + } else if (end - pos < 2) { | |
| 2882 | + v[off++] = din.readChar(); | |
| 2883 | + continue; | |
| 2884 | + } else { | |
| 2885 | + stop = Math.min(endoff, off + ((end - pos) >> 1)); | |
| 2886 | + } | |
| 2887 | + | |
| 2888 | + while (off < stop) { | |
| 2889 | + v[off++] = Bits.getChar(buf, pos); | |
| 2890 | + pos += 2; | |
| 2891 | + } | |
| 2892 | + } | |
| 2893 | + } | |
| 2894 | + | |
| 2895 | + void readShorts(short[] v, int off, int len) throws IOException { | |
| 2896 | + int stop, endoff = off + len; | |
| 2897 | + while (off < endoff) { | |
| 2898 | + if (!blkmode) { | |
| 2899 | + int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1); | |
| 2900 | + in.readFully(buf, 0, span << 1); | |
| 2901 | + stop = off + span; | |
| 2902 | + pos = 0; | |
| 2903 | + } else if (end - pos < 2) { | |
| 2904 | + v[off++] = din.readShort(); | |
| 2905 | + continue; | |
| 2906 | + } else { | |
| 2907 | + stop = Math.min(endoff, off + ((end - pos) >> 1)); | |
| 2908 | + } | |
| 2909 | + | |
| 2910 | + while (off < stop) { | |
| 2911 | + v[off++] = Bits.getShort(buf, pos); | |
| 2912 | + pos += 2; | |
| 2913 | + } | |
| 2914 | + } | |
| 2915 | + } | |
| 2916 | + | |
| 2917 | + void readInts(int[] v, int off, int len) throws IOException { | |
| 2918 | + int stop, endoff = off + len; | |
| 2919 | + while (off < endoff) { | |
| 2920 | + if (!blkmode) { | |
| 2921 | + int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2); | |
| 2922 | + in.readFully(buf, 0, span << 2); | |
| 2923 | + stop = off + span; | |
| 2924 | + pos = 0; | |
| 2925 | + } else if (end - pos < 4) { | |
| 2926 | + v[off++] = din.readInt(); | |
| 2927 | + continue; | |
| 2928 | + } else { | |
| 2929 | + stop = Math.min(endoff, off + ((end - pos) >> 2)); | |
| 2930 | + } | |
| 2931 | + | |
| 2932 | + while (off < stop) { | |
| 2933 | + v[off++] = Bits.getInt(buf, pos); | |
| 2934 | + pos += 4; | |
| 2935 | + } | |
| 2936 | + } | |
| 2937 | + } | |
| 2938 | + | |
| 2939 | + void readFloats(float[] v, int off, int len) throws IOException { | |
| 2940 | + int span, endoff = off + len; | |
| 2941 | + while (off < endoff) { | |
| 2942 | + if (!blkmode) { | |
| 2943 | + span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2); | |
| 2944 | + in.readFully(buf, 0, span << 2); | |
| 2945 | + pos = 0; | |
| 2946 | + } else if (end - pos < 4) { | |
| 2947 | + v[off++] = din.readFloat(); | |
| 2948 | + continue; | |
| 2949 | + } else { | |
| 2950 | + span = Math.min(endoff - off, ((end - pos) >> 2)); | |
| 2951 | + } | |
| 2952 | + | |
| 2953 | + bytesToFloats(buf, pos, v, off, span); | |
| 2954 | + off += span; | |
| 2955 | + pos += span << 2; | |
| 2956 | + } | |
| 2957 | + } | |
| 2958 | + | |
| 2959 | + void readLongs(long[] v, int off, int len) throws IOException { | |
| 2960 | + int stop, endoff = off + len; | |
| 2961 | + while (off < endoff) { | |
| 2962 | + if (!blkmode) { | |
| 2963 | + int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3); | |
| 2964 | + in.readFully(buf, 0, span << 3); | |
| 2965 | + stop = off + span; | |
| 2966 | + pos = 0; | |
| 2967 | + } else if (end - pos < 8) { | |
| 2968 | + v[off++] = din.readLong(); | |
| 2969 | + continue; | |
| 2970 | + } else { | |
| 2971 | + stop = Math.min(endoff, off + ((end - pos) >> 3)); | |
| 2972 | + } | |
| 2973 | + | |
| 2974 | + while (off < stop) { | |
| 2975 | + v[off++] = Bits.getLong(buf, pos); | |
| 2976 | + pos += 8; | |
| 2977 | + } | |
| 2978 | + } | |
| 2979 | + } | |
| 2980 | + | |
| 2981 | + void readDoubles(double[] v, int off, int len) throws IOException { | |
| 2982 | + int span, endoff = off + len; | |
| 2983 | + while (off < endoff) { | |
| 2984 | + if (!blkmode) { | |
| 2985 | + span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3); | |
| 2986 | + in.readFully(buf, 0, span << 3); | |
| 2987 | + pos = 0; | |
| 2988 | + } else if (end - pos < 8) { | |
| 2989 | + v[off++] = din.readDouble(); | |
| 2990 | + continue; | |
| 2991 | + } else { | |
| 2992 | + span = Math.min(endoff - off, ((end - pos) >> 3)); | |
| 2993 | + } | |
| 2994 | + | |
| 2995 | + bytesToDoubles(buf, pos, v, off, span); | |
| 2996 | + off += span; | |
| 2997 | + pos += span << 3; | |
| 2998 | + } | |
| 2999 | + } | |
| 3000 | + | |
| 3001 | + /** | |
| 3002 | + * Reads in string written in "long" UTF format. "Long" UTF format is | |
| 3003 | + * identical to standard UTF, except that it uses an 8 byte header | |
| 3004 | + * (instead of the standard 2 bytes) to convey the UTF encoding length. | |
| 3005 | + */ | |
| 3006 | + String readLongUTF() throws IOException { | |
| 3007 | + return readUTFBody(readLong()); | |
| 3008 | + } | |
| 3009 | + | |
| 3010 | + /** | |
| 3011 | + * Reads in the "body" (i.e., the UTF representation minus the 2-byte | |
| 3012 | + * or 8-byte length header) of a UTF encoding, which occupies the next | |
| 3013 | + * utflen bytes. | |
| 3014 | + */ | |
| 3015 | + private String readUTFBody(long utflen) throws IOException { | |
| 3016 | + StringBuilder sbuf = new StringBuilder(); | |
| 3017 | + if (!blkmode) { | |
| 3018 | + end = pos = 0; | |
| 3019 | + } | |
| 3020 | + | |
| 3021 | + while (utflen > 0) { | |
| 3022 | + int avail = end - pos; | |
| 3023 | + if (avail >= 3 || (long) avail == utflen) { | |
| 3024 | + utflen -= readUTFSpan(sbuf, utflen); | |
| 3025 | + } else { | |
| 3026 | + if (blkmode) { | |
| 3027 | + // near block boundary, read one byte at a time | |
| 3028 | + utflen -= readUTFChar(sbuf, utflen); | |
| 3029 | + } else { | |
| 3030 | + // shift and refill buffer manually | |
| 3031 | + if (avail > 0) { | |
| 3032 | + System.arraycopy(buf, pos, buf, 0, avail); | |
| 3033 | + } | |
| 3034 | + pos = 0; | |
| 3035 | + end = (int) Math.min(MAX_BLOCK_SIZE, utflen); | |
| 3036 | + in.readFully(buf, avail, end - avail); | |
| 3037 | + } | |
| 3038 | + } | |
| 3039 | + } | |
| 3040 | + | |
| 3041 | + return sbuf.toString(); | |
| 3042 | + } | |
| 3043 | + | |
| 3044 | + /** | |
| 3045 | + * Reads span of UTF-encoded characters out of internal buffer | |
| 3046 | + * (starting at offset pos and ending at or before offset end), | |
| 3047 | + * consuming no more than utflen bytes. Appends read characters to | |
| 3048 | + * sbuf. Returns the number of bytes consumed. | |
| 3049 | + */ | |
| 3050 | + private long readUTFSpan(StringBuilder sbuf, long utflen) | |
| 3051 | + throws IOException | |
| 3052 | + { | |
| 3053 | + int cpos = 0; | |
| 3054 | + int start = pos; | |
| 3055 | + int avail = Math.min(end - pos, CHAR_BUF_SIZE); | |
| 3056 | + // stop short of last char unless all of utf bytes in buffer | |
| 3057 | + int stop = pos + ((utflen > avail) ? avail - 2 : (int) utflen); | |
| 3058 | + boolean outOfBounds = false; | |
| 3059 | + | |
| 3060 | + try { | |
| 3061 | + while (pos < stop) { | |
| 3062 | + int b1, b2, b3; | |
| 3063 | + b1 = buf[pos++] & 0xFF; | |
| 3064 | + switch (b1 >> 4) { | |
| 3065 | + case 0: | |
| 3066 | + case 1: | |
| 3067 | + case 2: | |
| 3068 | + case 3: | |
| 3069 | + case 4: | |
| 3070 | + case 5: | |
| 3071 | + case 6: | |
| 3072 | + case 7: // 1 byte format: 0xxxxxxx | |
| 3073 | + cbuf[cpos++] = (char) b1; | |
| 3074 | + break; | |
| 3075 | + | |
| 3076 | + case 12: | |
| 3077 | + case 13: // 2 byte format: 110xxxxx 10xxxxxx | |
| 3078 | + b2 = buf[pos++]; | |
| 3079 | + if ((b2 & 0xC0) != 0x80) { | |
| 3080 | + throw new UTFDataFormatException(); | |
| 3081 | + } | |
| 3082 | + cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) | | |
| 3083 | + ((b2 & 0x3F) << 0)); | |
| 3084 | + break; | |
| 3085 | + | |
| 3086 | + case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx | |
| 3087 | + b3 = buf[pos + 1]; | |
| 3088 | + b2 = buf[pos + 0]; | |
| 3089 | + pos += 2; | |
| 3090 | + if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) { | |
| 3091 | + throw new UTFDataFormatException(); | |
| 3092 | + } | |
| 3093 | + cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) | | |
| 3094 | + ((b2 & 0x3F) << 6) | | |
| 3095 | + ((b3 & 0x3F) << 0)); | |
| 3096 | + break; | |
| 3097 | + | |
| 3098 | + default: // 10xx xxxx, 1111 xxxx | |
| 3099 | + throw new UTFDataFormatException(); | |
| 3100 | + } | |
| 3101 | + } | |
| 3102 | + } catch (ArrayIndexOutOfBoundsException ex) { | |
| 3103 | + outOfBounds = true; | |
| 3104 | + } finally { | |
| 3105 | + if (outOfBounds || (pos - start) > utflen) { | |
| 3106 | + /* | |
| 3107 | + * Fix for 4450867: if a malformed utf char causes the | |
| 3108 | + * conversion loop to scan past the expected end of the utf | |
| 3109 | + * string, only consume the expected number of utf bytes. | |
| 3110 | + */ | |
| 3111 | + pos = start + (int) utflen; | |
| 3112 | + throw new UTFDataFormatException(); | |
| 3113 | + } | |
| 3114 | + } | |
| 3115 | + | |
| 3116 | + sbuf.append(cbuf, 0, cpos); | |
| 3117 | + return pos - start; | |
| 3118 | + } | |
| 3119 | + | |
| 3120 | + /** | |
| 3121 | + * Reads in single UTF-encoded character one byte at a time, appends | |
| 3122 | + * the character to sbuf, and returns the number of bytes consumed. | |
| 3123 | + * This method is used when reading in UTF strings written in block | |
| 3124 | + * data mode to handle UTF-encoded characters which (potentially) | |
| 3125 | + * straddle block-data boundaries. | |
| 3126 | + */ | |
| 3127 | + private int readUTFChar(StringBuilder sbuf, long utflen) | |
| 3128 | + throws IOException | |
| 3129 | + { | |
| 3130 | + int b1, b2, b3; | |
| 3131 | + b1 = readByte() & 0xFF; | |
| 3132 | + switch (b1 >> 4) { | |
| 3133 | + case 0: | |
| 3134 | + case 1: | |
| 3135 | + case 2: | |
| 3136 | + case 3: | |
| 3137 | + case 4: | |
| 3138 | + case 5: | |
| 3139 | + case 6: | |
| 3140 | + case 7: // 1 byte format: 0xxxxxxx | |
| 3141 | + sbuf.append((char) b1); | |
| 3142 | + return 1; | |
| 3143 | + | |
| 3144 | + case 12: | |
| 3145 | + case 13: // 2 byte format: 110xxxxx 10xxxxxx | |
| 3146 | + if (utflen < 2) { | |
| 3147 | + throw new UTFDataFormatException(); | |
| 3148 | + } | |
| 3149 | + b2 = readByte(); | |
| 3150 | + if ((b2 & 0xC0) != 0x80) { | |
| 3151 | + throw new UTFDataFormatException(); | |
| 3152 | + } | |
| 3153 | + sbuf.append((char) (((b1 & 0x1F) << 6) | | |
| 3154 | + ((b2 & 0x3F) << 0))); | |
| 3155 | + return 2; | |
| 3156 | + | |
| 3157 | + case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx | |
| 3158 | + if (utflen < 3) { | |
| 3159 | + if (utflen == 2) { | |
| 3160 | + readByte(); // consume remaining byte | |
| 3161 | + } | |
| 3162 | + throw new UTFDataFormatException(); | |
| 3163 | + } | |
| 3164 | + b2 = readByte(); | |
| 3165 | + b3 = readByte(); | |
| 3166 | + if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) { | |
| 3167 | + throw new UTFDataFormatException(); | |
| 3168 | + } | |
| 3169 | + sbuf.append((char) (((b1 & 0x0F) << 12) | | |
| 3170 | + ((b2 & 0x3F) << 6) | | |
| 3171 | + ((b3 & 0x3F) << 0))); | |
| 3172 | + return 3; | |
| 3173 | + | |
| 3174 | + default: // 10xx xxxx, 1111 xxxx | |
| 3175 | + throw new UTFDataFormatException(); | |
| 3176 | + } | |
| 3177 | + } | |
| 3178 | + } | |
| 3179 | + | |
| 3180 | + /** | |
| 3181 | + * Unsynchronized table which tracks wire handle to object mappings, as | |
| 3182 | + * well as ClassNotFoundExceptions associated with deserialized objects. | |
| 3183 | + * This class implements an exception-propagation algorithm for | |
| 3184 | + * determining which objects should have ClassNotFoundExceptions associated | |
| 3185 | + * with them, taking into account cycles and discontinuities (e.g., skipped | |
| 3186 | + * fields) in the object graph. | |
| 3187 | + * | |
| 3188 | + * <p>General use of the table is as follows: during deserialization, a | |
| 3189 | + * given object is first assigned a handle by calling the assign method. | |
| 3190 | + * This method leaves the assigned handle in an "open" state, wherein | |
| 3191 | + * dependencies on the exception status of other handles can be registered | |
| 3192 | + * by calling the markDependency method, or an exception can be directly | |
| 3193 | + * associated with the handle by calling markException. When a handle is | |
| 3194 | + * tagged with an exception, the HandleTable assumes responsibility for | |
| 3195 | + * propagating the exception to any other objects which depend | |
| 3196 | + * (transitively) on the exception-tagged object. | |
| 3197 | + * | |
| 3198 | + * <p>Once all exception information/dependencies for the handle have been | |
| 3199 | + * registered, the handle should be "closed" by calling the finish method | |
| 3200 | + * on it. The act of finishing a handle allows the exception propagation | |
| 3201 | + * algorithm to aggressively prune dependency links, lessening the | |
| 3202 | + * performance/memory impact of exception tracking. | |
| 3203 | + * | |
| 3204 | + * <p>Note that the exception propagation algorithm used depends on handles | |
| 3205 | + * being assigned/finished in LIFO order; however, for simplicity as well | |
| 3206 | + * as memory conservation, it does not enforce this constraint. | |
| 3207 | + */ | |
| 3208 | + // REMIND: add full description of exception propagation algorithm? | |
| 3209 | + private static class HandleTable { | |
| 3210 | + | |
| 3211 | + /* status codes indicating whether object has associated exception */ | |
| 3212 | + private static final byte STATUS_OK = 1; | |
| 3213 | + private static final byte STATUS_UNKNOWN = 2; | |
| 3214 | + private static final byte STATUS_EXCEPTION = 3; | |
| 3215 | + | |
| 3216 | + /** array mapping handle -> object status */ | |
| 3217 | + byte[] status; | |
| 3218 | + /** array mapping handle -> object/exception (depending on status) */ | |
| 3219 | + Object[] entries; | |
| 3220 | + /** array mapping handle -> list of dependent handles (if any) */ | |
| 3221 | + HandleList[] deps; | |
| 3222 | + /** lowest unresolved dependency */ | |
| 3223 | + int lowDep = -1; | |
| 3224 | + /** number of handles in table */ | |
| 3225 | + int size = 0; | |
| 3226 | + | |
| 3227 | + /** | |
| 3228 | + * Creates handle table with the given initial capacity. | |
| 3229 | + */ | |
| 3230 | + HandleTable(int initialCapacity) { | |
| 3231 | + status = new byte[initialCapacity]; | |
| 3232 | + entries = new Object[initialCapacity]; | |
| 3233 | + deps = new HandleList[initialCapacity]; | |
| 3234 | + } | |
| 3235 | + | |
| 3236 | + /** | |
| 3237 | + * Assigns next available handle to given object, and returns assigned | |
| 3238 | + * handle. Once object has been completely deserialized (and all | |
| 3239 | + * dependencies on other objects identified), the handle should be | |
| 3240 | + * "closed" by passing it to finish(). | |
| 3241 | + */ | |
| 3242 | + int assign(Object obj) { | |
| 3243 | + if (size >= entries.length) { | |
| 3244 | + grow(); | |
| 3245 | + } | |
| 3246 | + status[size] = STATUS_UNKNOWN; | |
| 3247 | + entries[size] = obj; | |
| 3248 | + return size++; | |
| 3249 | + } | |
| 3250 | + | |
| 3251 | + /** | |
| 3252 | + * Registers a dependency (in exception status) of one handle on | |
| 3253 | + * another. The dependent handle must be "open" (i.e., assigned, but | |
| 3254 | + * not finished yet). No action is taken if either dependent or target | |
| 3255 | + * handle is NULL_HANDLE. | |
| 3256 | + */ | |
| 3257 | + void markDependency(int dependent, int target) { | |
| 3258 | + if (dependent == NULL_HANDLE || target == NULL_HANDLE) { | |
| 3259 | + return; | |
| 3260 | + } | |
| 3261 | + switch (status[dependent]) { | |
| 3262 | + | |
| 3263 | + case STATUS_UNKNOWN: | |
| 3264 | + switch (status[target]) { | |
| 3265 | + case STATUS_OK: | |
| 3266 | + // ignore dependencies on objs with no exception | |
| 3267 | + break; | |
| 3268 | + | |
| 3269 | + case STATUS_EXCEPTION: | |
| 3270 | + // eagerly propagate exception | |
| 3271 | + markException(dependent, | |
| 3272 | + (ClassNotFoundException) entries[target]); | |
| 3273 | + break; | |
| 3274 | + | |
| 3275 | + case STATUS_UNKNOWN: | |
| 3276 | + // add to dependency list of target | |
| 3277 | + if (deps[target] == null) { | |
| 3278 | + deps[target] = new HandleList(); | |
| 3279 | + } | |
| 3280 | + deps[target].add(dependent); | |
| 3281 | + | |
| 3282 | + // remember lowest unresolved target seen | |
| 3283 | + if (lowDep < 0 || lowDep > target) { | |
| 3284 | + lowDep = target; | |
| 3285 | + } | |
| 3286 | + break; | |
| 3287 | + | |
| 3288 | + default: | |
| 3289 | + throw new InternalError(); | |
| 3290 | + } | |
| 3291 | + break; | |
| 3292 | + | |
| 3293 | + case STATUS_EXCEPTION: | |
| 3294 | + break; | |
| 3295 | + | |
| 3296 | + default: | |
| 3297 | + throw new InternalError(); | |
| 3298 | + } | |
| 3299 | + } | |
| 3300 | + | |
| 3301 | + /** | |
| 3302 | + * Associates a ClassNotFoundException (if one not already associated) | |
| 3303 | + * with the currently active handle and propagates it to other | |
| 3304 | + * referencing objects as appropriate. The specified handle must be | |
| 3305 | + * "open" (i.e., assigned, but not finished yet). | |
| 3306 | + */ | |
| 3307 | + void markException(int handle, ClassNotFoundException ex) { | |
| 3308 | + switch (status[handle]) { | |
| 3309 | + case STATUS_UNKNOWN: | |
| 3310 | + status[handle] = STATUS_EXCEPTION; | |
| 3311 | + entries[handle] = ex; | |
| 3312 | + | |
| 3313 | + // propagate exception to dependents | |
| 3314 | + HandleList dlist = deps[handle]; | |
| 3315 | + if (dlist != null) { | |
| 3316 | + int ndeps = dlist.size(); | |
| 3317 | + for (int i = 0; i < ndeps; i++) { | |
| 3318 | + markException(dlist.get(i), ex); | |
| 3319 | + } | |
| 3320 | + deps[handle] = null; | |
| 3321 | + } | |
| 3322 | + break; | |
| 3323 | + | |
| 3324 | + case STATUS_EXCEPTION: | |
| 3325 | + break; | |
| 3326 | + | |
| 3327 | + default: | |
| 3328 | + throw new InternalError(); | |
| 3329 | + } | |
| 3330 | + } | |
| 3331 | + | |
| 3332 | + /** | |
| 3333 | + * Marks given handle as finished, meaning that no new dependencies | |
| 3334 | + * will be marked for handle. Calls to the assign and finish methods | |
| 3335 | + * must occur in LIFO order. | |
| 3336 | + */ | |
| 3337 | + void finish(int handle) { | |
| 3338 | + int end; | |
| 3339 | + if (lowDep < 0) { | |
| 3340 | + // no pending unknowns, only resolve current handle | |
| 3341 | + end = handle + 1; | |
| 3342 | + } else if (lowDep >= handle) { | |
| 3343 | + // pending unknowns now clearable, resolve all upward handles | |
| 3344 | + end = size; | |
| 3345 | + lowDep = -1; | |
| 3346 | + } else { | |
| 3347 | + // unresolved backrefs present, can't resolve anything yet | |
| 3348 | + return; | |
| 3349 | + } | |
| 3350 | + | |
| 3351 | + // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles | |
| 3352 | + for (int i = handle; i < end; i++) { | |
| 3353 | + switch (status[i]) { | |
| 3354 | + case STATUS_UNKNOWN: | |
| 3355 | + status[i] = STATUS_OK; | |
| 3356 | + deps[i] = null; | |
| 3357 | + break; | |
| 3358 | + | |
| 3359 | + case STATUS_OK: | |
| 3360 | + case STATUS_EXCEPTION: | |
| 3361 | + break; | |
| 3362 | + | |
| 3363 | + default: | |
| 3364 | + throw new InternalError(); | |
| 3365 | + } | |
| 3366 | + } | |
| 3367 | + } | |
| 3368 | + | |
| 3369 | + /** | |
| 3370 | + * Assigns a new object to the given handle. The object previously | |
| 3371 | + * associated with the handle is forgotten. This method has no effect | |
| 3372 | + * if the given handle already has an exception associated with it. | |
| 3373 | + * This method may be called at any time after the handle is assigned. | |
| 3374 | + */ | |
| 3375 | + void setObject(int handle, Object obj) { | |
| 3376 | + switch (status[handle]) { | |
| 3377 | + case STATUS_UNKNOWN: | |
| 3378 | + case STATUS_OK: | |
| 3379 | + entries[handle] = obj; | |
| 3380 | + break; | |
| 3381 | + | |
| 3382 | + case STATUS_EXCEPTION: | |
| 3383 | + break; | |
| 3384 | + | |
| 3385 | + default: | |
| 3386 | + throw new InternalError(); | |
| 3387 | + } | |
| 3388 | + } | |
| 3389 | + | |
| 3390 | + /** | |
| 3391 | + * Looks up and returns object associated with the given handle. | |
| 3392 | + * Returns null if the given handle is NULL_HANDLE, or if it has an | |
| 3393 | + * associated ClassNotFoundException. | |
| 3394 | + */ | |
| 3395 | + Object lookupObject(int handle) { | |
| 3396 | + return (handle != NULL_HANDLE && | |
| 3397 | + status[handle] != STATUS_EXCEPTION) ? | |
| 3398 | + entries[handle] : null; | |
| 3399 | + } | |
| 3400 | + | |
| 3401 | + /** | |
| 3402 | + * Looks up and returns ClassNotFoundException associated with the | |
| 3403 | + * given handle. Returns null if the given handle is NULL_HANDLE, or | |
| 3404 | + * if there is no ClassNotFoundException associated with the handle. | |
| 3405 | + */ | |
| 3406 | + ClassNotFoundException lookupException(int handle) { | |
| 3407 | + return (handle != NULL_HANDLE && | |
| 3408 | + status[handle] == STATUS_EXCEPTION) ? | |
| 3409 | + (ClassNotFoundException) entries[handle] : null; | |
| 3410 | + } | |
| 3411 | + | |
| 3412 | + /** | |
| 3413 | + * Resets table to its initial state. | |
| 3414 | + */ | |
| 3415 | + void clear() { | |
| 3416 | + Arrays.fill(status, 0, size, (byte) 0); | |
| 3417 | + Arrays.fill(entries, 0, size, null); | |
| 3418 | + Arrays.fill(deps, 0, size, null); | |
| 3419 | + lowDep = -1; | |
| 3420 | + size = 0; | |
| 3421 | + } | |
| 3422 | + | |
| 3423 | + /** | |
| 3424 | + * Returns number of handles registered in table. | |
| 3425 | + */ | |
| 3426 | + int size() { | |
| 3427 | + return size; | |
| 3428 | + } | |
| 3429 | + | |
| 3430 | + /** | |
| 3431 | + * Expands capacity of internal arrays. | |
| 3432 | + */ | |
| 3433 | + private void grow() { | |
| 3434 | + int newCapacity = (entries.length << 1) + 1; | |
| 3435 | + | |
| 3436 | + byte[] newStatus = new byte[newCapacity]; | |
| 3437 | + Object[] newEntries = new Object[newCapacity]; | |
| 3438 | + HandleList[] newDeps = new HandleList[newCapacity]; | |
| 3439 | + | |
| 3440 | + System.arraycopy(status, 0, newStatus, 0, size); | |
| 3441 | + System.arraycopy(entries, 0, newEntries, 0, size); | |
| 3442 | + System.arraycopy(deps, 0, newDeps, 0, size); | |
| 3443 | + | |
| 3444 | + status = newStatus; | |
| 3445 | + entries = newEntries; | |
| 3446 | + deps = newDeps; | |
| 3447 | + } | |
| 3448 | + | |
| 3449 | + /** | |
| 3450 | + * Simple growable list of (integer) handles. | |
| 3451 | + */ | |
| 3452 | + private static class HandleList { | |
| 3453 | + private int[] list = new int[4]; | |
| 3454 | + private int size = 0; | |
| 3455 | + | |
| 3456 | + public HandleList() { | |
| 3457 | + } | |
| 3458 | + | |
| 3459 | + public void add(int handle) { | |
| 3460 | + if (size >= list.length) { | |
| 3461 | + int[] newList = new int[list.length << 1]; | |
| 3462 | + System.arraycopy(list, 0, newList, 0, list.length); | |
| 3463 | + list = newList; | |
| 3464 | + } | |
| 3465 | + list[size++] = handle; | |
| 3466 | + } | |
| 3467 | + | |
| 3468 | + public int get(int index) { | |
| 3469 | + if (index >= size) { | |
| 3470 | + throw new ArrayIndexOutOfBoundsException(); | |
| 3471 | + } | |
| 3472 | + return list[index]; | |
| 3473 | + } | |
| 3474 | + | |
| 3475 | + public int size() { | |
| 3476 | + return size; | |
| 3477 | + } | |
| 3478 | + } | |
| 3479 | + } | |
| 3480 | + | |
| 3481 | + /** | |
| 3482 | + * Method for cloning arrays in case of using unsharing reading | |
| 3483 | + */ | |
| 3484 | + private static Object cloneArray(Object array) { | |
| 3485 | + if (array instanceof Object[]) { | |
| 3486 | + return ((Object[]) array).clone(); | |
| 3487 | + } else if (array instanceof boolean[]) { | |
| 3488 | + return ((boolean[]) array).clone(); | |
| 3489 | + } else if (array instanceof byte[]) { | |
| 3490 | + return ((byte[]) array).clone(); | |
| 3491 | + } else if (array instanceof char[]) { | |
| 3492 | + return ((char[]) array).clone(); | |
| 3493 | + } else if (array instanceof double[]) { | |
| 3494 | + return ((double[]) array).clone(); | |
| 3495 | + } else if (array instanceof float[]) { | |
| 3496 | + return ((float[]) array).clone(); | |
| 3497 | + } else if (array instanceof int[]) { | |
| 3498 | + return ((int[]) array).clone(); | |
| 3499 | + } else if (array instanceof long[]) { | |
| 3500 | + return ((long[]) array).clone(); | |
| 3501 | + } else if (array instanceof short[]) { | |
| 3502 | + return ((short[]) array).clone(); | |
| 3503 | + } else { | |
| 3504 | + throw new AssertionError(); | |
| 3505 | + } | |
| 3506 | + } | |
| 3507 | + | |
| 3508 | +} | |
Binary file not shown.
| @@ -0,0 +1,45 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Callback interface to allow validation of objects within a graph. | |
| 30 | + * Allows an object to be called when a complete graph of objects has | |
| 31 | + * been deserialized. | |
| 32 | + * | |
| 33 | + * @author unascribed | |
| 34 | + * @see ObjectInputStream | |
| 35 | + * @see ObjectInputStream#registerValidation(java.io.ObjectInputValidation, int) | |
| 36 | + * @since JDK1.1 | |
| 37 | + */ | |
| 38 | +public interface ObjectInputValidation { | |
| 39 | + /** | |
| 40 | + * Validates the object. | |
| 41 | + * | |
| 42 | + * @exception InvalidObjectException If the object cannot validate itself. | |
| 43 | + */ | |
| 44 | + public void validateObject() throws InvalidObjectException; | |
| 45 | +} | |
Binary file not shown.
| @@ -0,0 +1,90 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * ObjectOutput extends the DataOutput interface to include writing of objects. | |
| 30 | + * DataOutput includes methods for output of primitive types, ObjectOutput | |
| 31 | + * extends that interface to include objects, arrays, and Strings. | |
| 32 | + * | |
| 33 | + * @author unascribed | |
| 34 | + * @see java.io.InputStream | |
| 35 | + * @see java.io.ObjectOutputStream | |
| 36 | + * @see java.io.ObjectInputStream | |
| 37 | + * @since JDK1.1 | |
| 38 | + */ | |
| 39 | +public interface ObjectOutput extends DataOutput, AutoCloseable { | |
| 40 | + /** | |
| 41 | + * Write an object to the underlying storage or stream. The | |
| 42 | + * class that implements this interface defines how the object is | |
| 43 | + * written. | |
| 44 | + * | |
| 45 | + * @param obj the object to be written | |
| 46 | + * @exception IOException Any of the usual Input/Output related exceptions. | |
| 47 | + */ | |
| 48 | + public void writeObject(Object obj) | |
| 49 | + throws IOException; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * Writes a byte. This method will block until the byte is actually | |
| 53 | + * written. | |
| 54 | + * @param b the byte | |
| 55 | + * @exception IOException If an I/O error has occurred. | |
| 56 | + */ | |
| 57 | + public void write(int b) throws IOException; | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * Writes an array of bytes. This method will block until the bytes | |
| 61 | + * are actually written. | |
| 62 | + * @param b the data to be written | |
| 63 | + * @exception IOException If an I/O error has occurred. | |
| 64 | + */ | |
| 65 | + public void write(byte b[]) throws IOException; | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * Writes a sub array of bytes. | |
| 69 | + * @param b the data to be written | |
| 70 | + * @param off the start offset in the data | |
| 71 | + * @param len the number of bytes that are written | |
| 72 | + * @exception IOException If an I/O error has occurred. | |
| 73 | + */ | |
| 74 | + public void write(byte b[], int off, int len) throws IOException; | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * Flushes the stream. This will write any buffered | |
| 78 | + * output bytes. | |
| 79 | + * @exception IOException If an I/O error has occurred. | |
| 80 | + */ | |
| 81 | + public void flush() throws IOException; | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * Closes the stream. This method must be called | |
| 85 | + * to release any resources associated with the | |
| 86 | + * stream. | |
| 87 | + * @exception IOException If an I/O error has occurred. | |
| 88 | + */ | |
| 89 | + public void close() throws IOException; | |
| 90 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,2454 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.io.ObjectStreamClass.WeakClassKey; | |
| 29 | +import java.lang.ref.ReferenceQueue; | |
| 30 | +import java.security.AccessController; | |
| 31 | +import java.security.PrivilegedAction; | |
| 32 | +import java.util.ArrayList; | |
| 33 | +import java.util.Arrays; | |
| 34 | +import java.util.List; | |
| 35 | +import java.util.concurrent.ConcurrentHashMap; | |
| 36 | +import java.util.concurrent.ConcurrentMap; | |
| 37 | +import static java.io.ObjectStreamClass.processQueue; | |
| 38 | +import java.io.SerialCallbackContext; | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * An ObjectOutputStream writes primitive data types and graphs of Java objects | |
| 42 | + * to an OutputStream. The objects can be read (reconstituted) using an | |
| 43 | + * ObjectInputStream. Persistent storage of objects can be accomplished by | |
| 44 | + * using a file for the stream. If the stream is a network socket stream, the | |
| 45 | + * objects can be reconstituted on another host or in another process. | |
| 46 | + * | |
| 47 | + * <p>Only objects that support the java.io.Serializable interface can be | |
| 48 | + * written to streams. The class of each serializable object is encoded | |
| 49 | + * including the class name and signature of the class, the values of the | |
| 50 | + * object's fields and arrays, and the closure of any other objects referenced | |
| 51 | + * from the initial objects. | |
| 52 | + * | |
| 53 | + * <p>The method writeObject is used to write an object to the stream. Any | |
| 54 | + * object, including Strings and arrays, is written with writeObject. Multiple | |
| 55 | + * objects or primitives can be written to the stream. The objects must be | |
| 56 | + * read back from the corresponding ObjectInputstream with the same types and | |
| 57 | + * in the same order as they were written. | |
| 58 | + * | |
| 59 | + * <p>Primitive data types can also be written to the stream using the | |
| 60 | + * appropriate methods from DataOutput. Strings can also be written using the | |
| 61 | + * writeUTF method. | |
| 62 | + * | |
| 63 | + * <p>The default serialization mechanism for an object writes the class of the | |
| 64 | + * object, the class signature, and the values of all non-transient and | |
| 65 | + * non-static fields. References to other objects (except in transient or | |
| 66 | + * static fields) cause those objects to be written also. Multiple references | |
| 67 | + * to a single object are encoded using a reference sharing mechanism so that | |
| 68 | + * graphs of objects can be restored to the same shape as when the original was | |
| 69 | + * written. | |
| 70 | + * | |
| 71 | + * <p>For example to write an object that can be read by the example in | |
| 72 | + * ObjectInputStream: | |
| 73 | + * <br> | |
| 74 | + * <pre> | |
| 75 | + * FileOutputStream fos = new FileOutputStream("t.tmp"); | |
| 76 | + * ObjectOutputStream oos = new ObjectOutputStream(fos); | |
| 77 | + * | |
| 78 | + * oos.writeInt(12345); | |
| 79 | + * oos.writeObject("Today"); | |
| 80 | + * oos.writeObject(new Date()); | |
| 81 | + * | |
| 82 | + * oos.close(); | |
| 83 | + * </pre> | |
| 84 | + * | |
| 85 | + * <p>Classes that require special handling during the serialization and | |
| 86 | + * deserialization process must implement special methods with these exact | |
| 87 | + * signatures: | |
| 88 | + * <br> | |
| 89 | + * <pre> | |
| 90 | + * private void readObject(java.io.ObjectInputStream stream) | |
| 91 | + * throws IOException, ClassNotFoundException; | |
| 92 | + * private void writeObject(java.io.ObjectOutputStream stream) | |
| 93 | + * throws IOException | |
| 94 | + * private void readObjectNoData() | |
| 95 | + * throws ObjectStreamException; | |
| 96 | + * </pre> | |
| 97 | + * | |
| 98 | + * <p>The writeObject method is responsible for writing the state of the object | |
| 99 | + * for its particular class so that the corresponding readObject method can | |
| 100 | + * restore it. The method does not need to concern itself with the state | |
| 101 | + * belonging to the object's superclasses or subclasses. State is saved by | |
| 102 | + * writing the individual fields to the ObjectOutputStream using the | |
| 103 | + * writeObject method or by using the methods for primitive data types | |
| 104 | + * supported by DataOutput. | |
| 105 | + * | |
| 106 | + * <p>Serialization does not write out the fields of any object that does not | |
| 107 | + * implement the java.io.Serializable interface. Subclasses of Objects that | |
| 108 | + * are not serializable can be serializable. In this case the non-serializable | |
| 109 | + * class must have a no-arg constructor to allow its fields to be initialized. | |
| 110 | + * In this case it is the responsibility of the subclass to save and restore | |
| 111 | + * the state of the non-serializable class. It is frequently the case that the | |
| 112 | + * fields of that class are accessible (public, package, or protected) or that | |
| 113 | + * there are get and set methods that can be used to restore the state. | |
| 114 | + * | |
| 115 | + * <p>Serialization of an object can be prevented by implementing writeObject | |
| 116 | + * and readObject methods that throw the NotSerializableException. The | |
| 117 | + * exception will be caught by the ObjectOutputStream and abort the | |
| 118 | + * serialization process. | |
| 119 | + * | |
| 120 | + * <p>Implementing the Externalizable interface allows the object to assume | |
| 121 | + * complete control over the contents and format of the object's serialized | |
| 122 | + * form. The methods of the Externalizable interface, writeExternal and | |
| 123 | + * readExternal, are called to save and restore the objects state. When | |
| 124 | + * implemented by a class they can write and read their own state using all of | |
| 125 | + * the methods of ObjectOutput and ObjectInput. It is the responsibility of | |
| 126 | + * the objects to handle any versioning that occurs. | |
| 127 | + * | |
| 128 | + * <p>Enum constants are serialized differently than ordinary serializable or | |
| 129 | + * externalizable objects. The serialized form of an enum constant consists | |
| 130 | + * solely of its name; field values of the constant are not transmitted. To | |
| 131 | + * serialize an enum constant, ObjectOutputStream writes the string returned by | |
| 132 | + * the constant's name method. Like other serializable or externalizable | |
| 133 | + * objects, enum constants can function as the targets of back references | |
| 134 | + * appearing subsequently in the serialization stream. The process by which | |
| 135 | + * enum constants are serialized cannot be customized; any class-specific | |
| 136 | + * writeObject and writeReplace methods defined by enum types are ignored | |
| 137 | + * during serialization. Similarly, any serialPersistentFields or | |
| 138 | + * serialVersionUID field declarations are also ignored--all enum types have a | |
| 139 | + * fixed serialVersionUID of 0L. | |
| 140 | + * | |
| 141 | + * <p>Primitive data, excluding serializable fields and externalizable data, is | |
| 142 | + * written to the ObjectOutputStream in block-data records. A block data record | |
| 143 | + * is composed of a header and data. The block data header consists of a marker | |
| 144 | + * and the number of bytes to follow the header. Consecutive primitive data | |
| 145 | + * writes are merged into one block-data record. The blocking factor used for | |
| 146 | + * a block-data record will be 1024 bytes. Each block-data record will be | |
| 147 | + * filled up to 1024 bytes, or be written whenever there is a termination of | |
| 148 | + * block-data mode. Calls to the ObjectOutputStream methods writeObject, | |
| 149 | + * defaultWriteObject and writeFields initially terminate any existing | |
| 150 | + * block-data record. | |
| 151 | + * | |
| 152 | + * @author Mike Warres | |
| 153 | + * @author Roger Riggs | |
| 154 | + * @see java.io.DataOutput | |
| 155 | + * @see java.io.ObjectInputStream | |
| 156 | + * @see java.io.Serializable | |
| 157 | + * @see java.io.Externalizable | |
| 158 | + * @see <a href="../../../platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a> | |
| 159 | + * @since JDK1.1 | |
| 160 | + */ | |
| 161 | +public class ObjectOutputStream | |
| 162 | + extends OutputStream implements ObjectOutput, ObjectStreamConstants | |
| 163 | +{ | |
| 164 | + | |
| 165 | + private static class Caches { | |
| 166 | + /** cache of subclass security audit results */ | |
| 167 | + static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits = | |
| 168 | + new ConcurrentHashMap<>(); | |
| 169 | + | |
| 170 | + /** queue for WeakReferences to audited subclasses */ | |
| 171 | + static final ReferenceQueue<Class<?>> subclassAuditsQueue = | |
| 172 | + new ReferenceQueue<>(); | |
| 173 | + } | |
| 174 | + | |
| 175 | + /** filter stream for handling block data conversion */ | |
| 176 | + private final BlockDataOutputStream bout; | |
| 177 | + /** obj -> wire handle map */ | |
| 178 | + private final HandleTable handles; | |
| 179 | + /** obj -> replacement obj map */ | |
| 180 | + private final ReplaceTable subs; | |
| 181 | + /** stream protocol version */ | |
| 182 | + private int protocol = PROTOCOL_VERSION_2; | |
| 183 | + /** recursion depth */ | |
| 184 | + private int depth; | |
| 185 | + | |
| 186 | + /** buffer for writing primitive field values */ | |
| 187 | + private byte[] primVals; | |
| 188 | + | |
| 189 | + /** if true, invoke writeObjectOverride() instead of writeObject() */ | |
| 190 | + private final boolean enableOverride; | |
| 191 | + /** if true, invoke replaceObject() */ | |
| 192 | + private boolean enableReplace; | |
| 193 | + | |
| 194 | + // values below valid only during upcalls to writeObject()/writeExternal() | |
| 195 | + /** | |
| 196 | + * Context during upcalls to class-defined writeObject methods; holds | |
| 197 | + * object currently being serialized and descriptor for current class. | |
| 198 | + * Null when not during writeObject upcall. | |
| 199 | + */ | |
| 200 | + private SerialCallbackContext curContext; | |
| 201 | + /** current PutField object */ | |
| 202 | + private PutFieldImpl curPut; | |
| 203 | + | |
| 204 | + /** custom storage for debug trace info */ | |
| 205 | + private final DebugTraceInfoStack debugInfoStack; | |
| 206 | + | |
| 207 | + /** | |
| 208 | + * value of "sun.io.serialization.extendedDebugInfo" property, | |
| 209 | + * as true or false for extended information about exception's place | |
| 210 | + */ | |
| 211 | + private static final boolean extendedDebugInfo = | |
| 212 | + java.security.AccessController.doPrivileged( | |
| 213 | + new sun.security.action.GetBooleanAction( | |
| 214 | + "sun.io.serialization.extendedDebugInfo")).booleanValue(); | |
| 215 | + | |
| 216 | + /** | |
| 217 | + * Creates an ObjectOutputStream that writes to the specified OutputStream. | |
| 218 | + * This constructor writes the serialization stream header to the | |
| 219 | + * underlying stream; callers may wish to flush the stream immediately to | |
| 220 | + * ensure that constructors for receiving ObjectInputStreams will not block | |
| 221 | + * when reading the header. | |
| 222 | + * | |
| 223 | + * <p>If a security manager is installed, this constructor will check for | |
| 224 | + * the "enableSubclassImplementation" SerializablePermission when invoked | |
| 225 | + * directly or indirectly by the constructor of a subclass which overrides | |
| 226 | + * the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared | |
| 227 | + * methods. | |
| 228 | + * | |
| 229 | + * @param out output stream to write to | |
| 230 | + * @throws IOException if an I/O error occurs while writing stream header | |
| 231 | + * @throws SecurityException if untrusted subclass illegally overrides | |
| 232 | + * security-sensitive methods | |
| 233 | + * @throws NullPointerException if <code>out</code> is <code>null</code> | |
| 234 | + * @since 1.4 | |
| 235 | + * @see ObjectOutputStream#ObjectOutputStream() | |
| 236 | + * @see ObjectOutputStream#putFields() | |
| 237 | + * @see ObjectInputStream#ObjectInputStream(InputStream) | |
| 238 | + */ | |
| 239 | + public ObjectOutputStream(OutputStream out) throws IOException { | |
| 240 | + verifySubclass(); | |
| 241 | + bout = new BlockDataOutputStream(out); | |
| 242 | + handles = new HandleTable(10, (float) 3.00); | |
| 243 | + subs = new ReplaceTable(10, (float) 3.00); | |
| 244 | + enableOverride = false; | |
| 245 | + writeStreamHeader(); | |
| 246 | + bout.setBlockDataMode(true); | |
| 247 | + if (extendedDebugInfo) { | |
| 248 | + debugInfoStack = new DebugTraceInfoStack(); | |
| 249 | + } else { | |
| 250 | + debugInfoStack = null; | |
| 251 | + } | |
| 252 | + } | |
| 253 | + | |
| 254 | + /** | |
| 255 | + * Provide a way for subclasses that are completely reimplementing | |
| 256 | + * ObjectOutputStream to not have to allocate private data just used by | |
| 257 | + * this implementation of ObjectOutputStream. | |
| 258 | + * | |
| 259 | + * <p>If there is a security manager installed, this method first calls the | |
| 260 | + * security manager's <code>checkPermission</code> method with a | |
| 261 | + * <code>SerializablePermission("enableSubclassImplementation")</code> | |
| 262 | + * permission to ensure it's ok to enable subclassing. | |
| 263 | + * | |
| 264 | + * @throws SecurityException if a security manager exists and its | |
| 265 | + * <code>checkPermission</code> method denies enabling | |
| 266 | + * subclassing. | |
| 267 | + * @see SecurityManager#checkPermission | |
| 268 | + * @see java.io.SerializablePermission | |
| 269 | + */ | |
| 270 | + protected ObjectOutputStream() throws IOException, SecurityException { | |
| 271 | + SecurityManager sm = System.getSecurityManager(); | |
| 272 | + if (sm != null) { | |
| 273 | + sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); | |
| 274 | + } | |
| 275 | + bout = null; | |
| 276 | + handles = null; | |
| 277 | + subs = null; | |
| 278 | + enableOverride = true; | |
| 279 | + debugInfoStack = null; | |
| 280 | + } | |
| 281 | + | |
| 282 | + /** | |
| 283 | + * Specify stream protocol version to use when writing the stream. | |
| 284 | + * | |
| 285 | + * <p>This routine provides a hook to enable the current version of | |
| 286 | + * Serialization to write in a format that is backwards compatible to a | |
| 287 | + * previous version of the stream format. | |
| 288 | + * | |
| 289 | + * <p>Every effort will be made to avoid introducing additional | |
| 290 | + * backwards incompatibilities; however, sometimes there is no | |
| 291 | + * other alternative. | |
| 292 | + * | |
| 293 | + * @param version use ProtocolVersion from java.io.ObjectStreamConstants. | |
| 294 | + * @throws IllegalStateException if called after any objects | |
| 295 | + * have been serialized. | |
| 296 | + * @throws IllegalArgumentException if invalid version is passed in. | |
| 297 | + * @throws IOException if I/O errors occur | |
| 298 | + * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1 | |
| 299 | + * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2 | |
| 300 | + * @since 1.2 | |
| 301 | + */ | |
| 302 | + public void useProtocolVersion(int version) throws IOException { | |
| 303 | + if (handles.size() != 0) { | |
| 304 | + // REMIND: implement better check for pristine stream? | |
| 305 | + throw new IllegalStateException("stream non-empty"); | |
| 306 | + } | |
| 307 | + switch (version) { | |
| 308 | + case PROTOCOL_VERSION_1: | |
| 309 | + case PROTOCOL_VERSION_2: | |
| 310 | + protocol = version; | |
| 311 | + break; | |
| 312 | + | |
| 313 | + default: | |
| 314 | + throw new IllegalArgumentException( | |
| 315 | + "unknown version: " + version); | |
| 316 | + } | |
| 317 | + } | |
| 318 | + | |
| 319 | + /** | |
| 320 | + * Write the specified object to the ObjectOutputStream. The class of the | |
| 321 | + * object, the signature of the class, and the values of the non-transient | |
| 322 | + * and non-static fields of the class and all of its supertypes are | |
| 323 | + * written. Default serialization for a class can be overridden using the | |
| 324 | + * writeObject and the readObject methods. Objects referenced by this | |
| 325 | + * object are written transitively so that a complete equivalent graph of | |
| 326 | + * objects can be reconstructed by an ObjectInputStream. | |
| 327 | + * | |
| 328 | + * <p>Exceptions are thrown for problems with the OutputStream and for | |
| 329 | + * classes that should not be serialized. All exceptions are fatal to the | |
| 330 | + * OutputStream, which is left in an indeterminate state, and it is up to | |
| 331 | + * the caller to ignore or recover the stream state. | |
| 332 | + * | |
| 333 | + * @throws InvalidClassException Something is wrong with a class used by | |
| 334 | + * serialization. | |
| 335 | + * @throws NotSerializableException Some object to be serialized does not | |
| 336 | + * implement the java.io.Serializable interface. | |
| 337 | + * @throws IOException Any exception thrown by the underlying | |
| 338 | + * OutputStream. | |
| 339 | + */ | |
| 340 | + public final void writeObject(Object obj) throws IOException { | |
| 341 | + if (enableOverride) { | |
| 342 | + writeObjectOverride(obj); | |
| 343 | + return; | |
| 344 | + } | |
| 345 | + try { | |
| 346 | + writeObject0(obj, false); | |
| 347 | + } catch (IOException ex) { | |
| 348 | + if (depth == 0) { | |
| 349 | + writeFatalException(ex); | |
| 350 | + } | |
| 351 | + throw ex; | |
| 352 | + } | |
| 353 | + } | |
| 354 | + | |
| 355 | + /** | |
| 356 | + * Method used by subclasses to override the default writeObject method. | |
| 357 | + * This method is called by trusted subclasses of ObjectInputStream that | |
| 358 | + * constructed ObjectInputStream using the protected no-arg constructor. | |
| 359 | + * The subclass is expected to provide an override method with the modifier | |
| 360 | + * "final". | |
| 361 | + * | |
| 362 | + * @param obj object to be written to the underlying stream | |
| 363 | + * @throws IOException if there are I/O errors while writing to the | |
| 364 | + * underlying stream | |
| 365 | + * @see #ObjectOutputStream() | |
| 366 | + * @see #writeObject(Object) | |
| 367 | + * @since 1.2 | |
| 368 | + */ | |
| 369 | + protected void writeObjectOverride(Object obj) throws IOException { | |
| 370 | + } | |
| 371 | + | |
| 372 | + /** | |
| 373 | + * Writes an "unshared" object to the ObjectOutputStream. This method is | |
| 374 | + * identical to writeObject, except that it always writes the given object | |
| 375 | + * as a new, unique object in the stream (as opposed to a back-reference | |
| 376 | + * pointing to a previously serialized instance). Specifically: | |
| 377 | + * <ul> | |
| 378 | + * <li>An object written via writeUnshared is always serialized in the | |
| 379 | + * same manner as a newly appearing object (an object that has not | |
| 380 | + * been written to the stream yet), regardless of whether or not the | |
| 381 | + * object has been written previously. | |
| 382 | + * | |
| 383 | + * <li>If writeObject is used to write an object that has been previously | |
| 384 | + * written with writeUnshared, the previous writeUnshared operation | |
| 385 | + * is treated as if it were a write of a separate object. In other | |
| 386 | + * words, ObjectOutputStream will never generate back-references to | |
| 387 | + * object data written by calls to writeUnshared. | |
| 388 | + * </ul> | |
| 389 | + * While writing an object via writeUnshared does not in itself guarantee a | |
| 390 | + * unique reference to the object when it is deserialized, it allows a | |
| 391 | + * single object to be defined multiple times in a stream, so that multiple | |
| 392 | + * calls to readUnshared by the receiver will not conflict. Note that the | |
| 393 | + * rules described above only apply to the base-level object written with | |
| 394 | + * writeUnshared, and not to any transitively referenced sub-objects in the | |
| 395 | + * object graph to be serialized. | |
| 396 | + * | |
| 397 | + * <p>ObjectOutputStream subclasses which override this method can only be | |
| 398 | + * constructed in security contexts possessing the | |
| 399 | + * "enableSubclassImplementation" SerializablePermission; any attempt to | |
| 400 | + * instantiate such a subclass without this permission will cause a | |
| 401 | + * SecurityException to be thrown. | |
| 402 | + * | |
| 403 | + * @param obj object to write to stream | |
| 404 | + * @throws NotSerializableException if an object in the graph to be | |
| 405 | + * serialized does not implement the Serializable interface | |
| 406 | + * @throws InvalidClassException if a problem exists with the class of an | |
| 407 | + * object to be serialized | |
| 408 | + * @throws IOException if an I/O error occurs during serialization | |
| 409 | + * @since 1.4 | |
| 410 | + */ | |
| 411 | + public void writeUnshared(Object obj) throws IOException { | |
| 412 | + try { | |
| 413 | + writeObject0(obj, true); | |
| 414 | + } catch (IOException ex) { | |
| 415 | + if (depth == 0) { | |
| 416 | + writeFatalException(ex); | |
| 417 | + } | |
| 418 | + throw ex; | |
| 419 | + } | |
| 420 | + } | |
| 421 | + | |
| 422 | + /** | |
| 423 | + * Write the non-static and non-transient fields of the current class to | |
| 424 | + * this stream. This may only be called from the writeObject method of the | |
| 425 | + * class being serialized. It will throw the NotActiveException if it is | |
| 426 | + * called otherwise. | |
| 427 | + * | |
| 428 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 429 | + * <code>OutputStream</code> | |
| 430 | + */ | |
| 431 | + public void defaultWriteObject() throws IOException { | |
| 432 | + if ( curContext == null ) { | |
| 433 | + throw new NotActiveException("not in call to writeObject"); | |
| 434 | + } | |
| 435 | + Object curObj = curContext.getObj(); | |
| 436 | + ObjectStreamClass curDesc = curContext.getDesc(); | |
| 437 | + bout.setBlockDataMode(false); | |
| 438 | + defaultWriteFields(curObj, curDesc); | |
| 439 | + bout.setBlockDataMode(true); | |
| 440 | + } | |
| 441 | + | |
| 442 | + /** | |
| 443 | + * Retrieve the object used to buffer persistent fields to be written to | |
| 444 | + * the stream. The fields will be written to the stream when writeFields | |
| 445 | + * method is called. | |
| 446 | + * | |
| 447 | + * @return an instance of the class Putfield that holds the serializable | |
| 448 | + * fields | |
| 449 | + * @throws IOException if I/O errors occur | |
| 450 | + * @since 1.2 | |
| 451 | + */ | |
| 452 | + public ObjectOutputStream.PutField putFields() throws IOException { | |
| 453 | + if (curPut == null) { | |
| 454 | + if (curContext == null) { | |
| 455 | + throw new NotActiveException("not in call to writeObject"); | |
| 456 | + } | |
| 457 | + Object curObj = curContext.getObj(); | |
| 458 | + ObjectStreamClass curDesc = curContext.getDesc(); | |
| 459 | + curPut = new PutFieldImpl(curDesc); | |
| 460 | + } | |
| 461 | + return curPut; | |
| 462 | + } | |
| 463 | + | |
| 464 | + /** | |
| 465 | + * Write the buffered fields to the stream. | |
| 466 | + * | |
| 467 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 468 | + * stream | |
| 469 | + * @throws NotActiveException Called when a classes writeObject method was | |
| 470 | + * not called to write the state of the object. | |
| 471 | + * @since 1.2 | |
| 472 | + */ | |
| 473 | + public void writeFields() throws IOException { | |
| 474 | + if (curPut == null) { | |
| 475 | + throw new NotActiveException("no current PutField object"); | |
| 476 | + } | |
| 477 | + bout.setBlockDataMode(false); | |
| 478 | + curPut.writeFields(); | |
| 479 | + bout.setBlockDataMode(true); | |
| 480 | + } | |
| 481 | + | |
| 482 | + /** | |
| 483 | + * Reset will disregard the state of any objects already written to the | |
| 484 | + * stream. The state is reset to be the same as a new ObjectOutputStream. | |
| 485 | + * The current point in the stream is marked as reset so the corresponding | |
| 486 | + * ObjectInputStream will be reset at the same point. Objects previously | |
| 487 | + * written to the stream will not be refered to as already being in the | |
| 488 | + * stream. They will be written to the stream again. | |
| 489 | + * | |
| 490 | + * @throws IOException if reset() is invoked while serializing an object. | |
| 491 | + */ | |
| 492 | + public void reset() throws IOException { | |
| 493 | + if (depth != 0) { | |
| 494 | + throw new IOException("stream active"); | |
| 495 | + } | |
| 496 | + bout.setBlockDataMode(false); | |
| 497 | + bout.writeByte(TC_RESET); | |
| 498 | + clear(); | |
| 499 | + bout.setBlockDataMode(true); | |
| 500 | + } | |
| 501 | + | |
| 502 | + /** | |
| 503 | + * Subclasses may implement this method to allow class data to be stored in | |
| 504 | + * the stream. By default this method does nothing. The corresponding | |
| 505 | + * method in ObjectInputStream is resolveClass. This method is called | |
| 506 | + * exactly once for each unique class in the stream. The class name and | |
| 507 | + * signature will have already been written to the stream. This method may | |
| 508 | + * make free use of the ObjectOutputStream to save any representation of | |
| 509 | + * the class it deems suitable (for example, the bytes of the class file). | |
| 510 | + * The resolveClass method in the corresponding subclass of | |
| 511 | + * ObjectInputStream must read and use any data or objects written by | |
| 512 | + * annotateClass. | |
| 513 | + * | |
| 514 | + * @param cl the class to annotate custom data for | |
| 515 | + * @throws IOException Any exception thrown by the underlying | |
| 516 | + * OutputStream. | |
| 517 | + */ | |
| 518 | + protected void annotateClass(Class<?> cl) throws IOException { | |
| 519 | + } | |
| 520 | + | |
| 521 | + /** | |
| 522 | + * Subclasses may implement this method to store custom data in the stream | |
| 523 | + * along with descriptors for dynamic proxy classes. | |
| 524 | + * | |
| 525 | + * <p>This method is called exactly once for each unique proxy class | |
| 526 | + * descriptor in the stream. The default implementation of this method in | |
| 527 | + * <code>ObjectOutputStream</code> does nothing. | |
| 528 | + * | |
| 529 | + * <p>The corresponding method in <code>ObjectInputStream</code> is | |
| 530 | + * <code>resolveProxyClass</code>. For a given subclass of | |
| 531 | + * <code>ObjectOutputStream</code> that overrides this method, the | |
| 532 | + * <code>resolveProxyClass</code> method in the corresponding subclass of | |
| 533 | + * <code>ObjectInputStream</code> must read any data or objects written by | |
| 534 | + * <code>annotateProxyClass</code>. | |
| 535 | + * | |
| 536 | + * @param cl the proxy class to annotate custom data for | |
| 537 | + * @throws IOException any exception thrown by the underlying | |
| 538 | + * <code>OutputStream</code> | |
| 539 | + * @see ObjectInputStream#resolveProxyClass(String[]) | |
| 540 | + * @since 1.3 | |
| 541 | + */ | |
| 542 | + protected void annotateProxyClass(Class<?> cl) throws IOException { | |
| 543 | + } | |
| 544 | + | |
| 545 | + /** | |
| 546 | + * This method will allow trusted subclasses of ObjectOutputStream to | |
| 547 | + * substitute one object for another during serialization. Replacing | |
| 548 | + * objects is disabled until enableReplaceObject is called. The | |
| 549 | + * enableReplaceObject method checks that the stream requesting to do | |
| 550 | + * replacement can be trusted. The first occurrence of each object written | |
| 551 | + * into the serialization stream is passed to replaceObject. Subsequent | |
| 552 | + * references to the object are replaced by the object returned by the | |
| 553 | + * original call to replaceObject. To ensure that the private state of | |
| 554 | + * objects is not unintentionally exposed, only trusted streams may use | |
| 555 | + * replaceObject. | |
| 556 | + * | |
| 557 | + * <p>The ObjectOutputStream.writeObject method takes a parameter of type | |
| 558 | + * Object (as opposed to type Serializable) to allow for cases where | |
| 559 | + * non-serializable objects are replaced by serializable ones. | |
| 560 | + * | |
| 561 | + * <p>When a subclass is replacing objects it must insure that either a | |
| 562 | + * complementary substitution must be made during deserialization or that | |
| 563 | + * the substituted object is compatible with every field where the | |
| 564 | + * reference will be stored. Objects whose type is not a subclass of the | |
| 565 | + * type of the field or array element abort the serialization by raising an | |
| 566 | + * exception and the object is not be stored. | |
| 567 | + * | |
| 568 | + * <p>This method is called only once when each object is first | |
| 569 | + * encountered. All subsequent references to the object will be redirected | |
| 570 | + * to the new object. This method should return the object to be | |
| 571 | + * substituted or the original object. | |
| 572 | + * | |
| 573 | + * <p>Null can be returned as the object to be substituted, but may cause | |
| 574 | + * NullReferenceException in classes that contain references to the | |
| 575 | + * original object since they may be expecting an object instead of | |
| 576 | + * null. | |
| 577 | + * | |
| 578 | + * @param obj the object to be replaced | |
| 579 | + * @return the alternate object that replaced the specified one | |
| 580 | + * @throws IOException Any exception thrown by the underlying | |
| 581 | + * OutputStream. | |
| 582 | + */ | |
| 583 | + protected Object replaceObject(Object obj) throws IOException { | |
| 584 | + return obj; | |
| 585 | + } | |
| 586 | + | |
| 587 | + /** | |
| 588 | + * Enable the stream to do replacement of objects in the stream. When | |
| 589 | + * enabled, the replaceObject method is called for every object being | |
| 590 | + * serialized. | |
| 591 | + * | |
| 592 | + * <p>If <code>enable</code> is true, and there is a security manager | |
| 593 | + * installed, this method first calls the security manager's | |
| 594 | + * <code>checkPermission</code> method with a | |
| 595 | + * <code>SerializablePermission("enableSubstitution")</code> permission to | |
| 596 | + * ensure it's ok to enable the stream to do replacement of objects in the | |
| 597 | + * stream. | |
| 598 | + * | |
| 599 | + * @param enable boolean parameter to enable replacement of objects | |
| 600 | + * @return the previous setting before this method was invoked | |
| 601 | + * @throws SecurityException if a security manager exists and its | |
| 602 | + * <code>checkPermission</code> method denies enabling the stream | |
| 603 | + * to do replacement of objects in the stream. | |
| 604 | + * @see SecurityManager#checkPermission | |
| 605 | + * @see java.io.SerializablePermission | |
| 606 | + */ | |
| 607 | + protected boolean enableReplaceObject(boolean enable) | |
| 608 | + throws SecurityException | |
| 609 | + { | |
| 610 | + if (enable == enableReplace) { | |
| 611 | + return enable; | |
| 612 | + } | |
| 613 | + if (enable) { | |
| 614 | + SecurityManager sm = System.getSecurityManager(); | |
| 615 | + if (sm != null) { | |
| 616 | + sm.checkPermission(SUBSTITUTION_PERMISSION); | |
| 617 | + } | |
| 618 | + } | |
| 619 | + enableReplace = enable; | |
| 620 | + return !enableReplace; | |
| 621 | + } | |
| 622 | + | |
| 623 | + /** | |
| 624 | + * The writeStreamHeader method is provided so subclasses can append or | |
| 625 | + * prepend their own header to the stream. It writes the magic number and | |
| 626 | + * version to the stream. | |
| 627 | + * | |
| 628 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 629 | + * stream | |
| 630 | + */ | |
| 631 | + protected void writeStreamHeader() throws IOException { | |
| 632 | + bout.writeShort(STREAM_MAGIC); | |
| 633 | + bout.writeShort(STREAM_VERSION); | |
| 634 | + } | |
| 635 | + | |
| 636 | + /** | |
| 637 | + * Write the specified class descriptor to the ObjectOutputStream. Class | |
| 638 | + * descriptors are used to identify the classes of objects written to the | |
| 639 | + * stream. Subclasses of ObjectOutputStream may override this method to | |
| 640 | + * customize the way in which class descriptors are written to the | |
| 641 | + * serialization stream. The corresponding method in ObjectInputStream, | |
| 642 | + * <code>readClassDescriptor</code>, should then be overridden to | |
| 643 | + * reconstitute the class descriptor from its custom stream representation. | |
| 644 | + * By default, this method writes class descriptors according to the format | |
| 645 | + * defined in the Object Serialization specification. | |
| 646 | + * | |
| 647 | + * <p>Note that this method will only be called if the ObjectOutputStream | |
| 648 | + * is not using the old serialization stream format (set by calling | |
| 649 | + * ObjectOutputStream's <code>useProtocolVersion</code> method). If this | |
| 650 | + * serialization stream is using the old format | |
| 651 | + * (<code>PROTOCOL_VERSION_1</code>), the class descriptor will be written | |
| 652 | + * internally in a manner that cannot be overridden or customized. | |
| 653 | + * | |
| 654 | + * @param desc class descriptor to write to the stream | |
| 655 | + * @throws IOException If an I/O error has occurred. | |
| 656 | + * @see java.io.ObjectInputStream#readClassDescriptor() | |
| 657 | + * @see #useProtocolVersion(int) | |
| 658 | + * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1 | |
| 659 | + * @since 1.3 | |
| 660 | + */ | |
| 661 | + protected void writeClassDescriptor(ObjectStreamClass desc) | |
| 662 | + throws IOException | |
| 663 | + { | |
| 664 | + desc.writeNonProxy(this); | |
| 665 | + } | |
| 666 | + | |
| 667 | + /** | |
| 668 | + * Writes a byte. This method will block until the byte is actually | |
| 669 | + * written. | |
| 670 | + * | |
| 671 | + * @param val the byte to be written to the stream | |
| 672 | + * @throws IOException If an I/O error has occurred. | |
| 673 | + */ | |
| 674 | + public void write(int val) throws IOException { | |
| 675 | + bout.write(val); | |
| 676 | + } | |
| 677 | + | |
| 678 | + /** | |
| 679 | + * Writes an array of bytes. This method will block until the bytes are | |
| 680 | + * actually written. | |
| 681 | + * | |
| 682 | + * @param buf the data to be written | |
| 683 | + * @throws IOException If an I/O error has occurred. | |
| 684 | + */ | |
| 685 | + public void write(byte[] buf) throws IOException { | |
| 686 | + bout.write(buf, 0, buf.length, false); | |
| 687 | + } | |
| 688 | + | |
| 689 | + /** | |
| 690 | + * Writes a sub array of bytes. | |
| 691 | + * | |
| 692 | + * @param buf the data to be written | |
| 693 | + * @param off the start offset in the data | |
| 694 | + * @param len the number of bytes that are written | |
| 695 | + * @throws IOException If an I/O error has occurred. | |
| 696 | + */ | |
| 697 | + public void write(byte[] buf, int off, int len) throws IOException { | |
| 698 | + if (buf == null) { | |
| 699 | + throw new NullPointerException(); | |
| 700 | + } | |
| 701 | + int endoff = off + len; | |
| 702 | + if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) { | |
| 703 | + throw new IndexOutOfBoundsException(); | |
| 704 | + } | |
| 705 | + bout.write(buf, off, len, false); | |
| 706 | + } | |
| 707 | + | |
| 708 | + /** | |
| 709 | + * Flushes the stream. This will write any buffered output bytes and flush | |
| 710 | + * through to the underlying stream. | |
| 711 | + * | |
| 712 | + * @throws IOException If an I/O error has occurred. | |
| 713 | + */ | |
| 714 | + public void flush() throws IOException { | |
| 715 | + bout.flush(); | |
| 716 | + } | |
| 717 | + | |
| 718 | + /** | |
| 719 | + * Drain any buffered data in ObjectOutputStream. Similar to flush but | |
| 720 | + * does not propagate the flush to the underlying stream. | |
| 721 | + * | |
| 722 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 723 | + * stream | |
| 724 | + */ | |
| 725 | + protected void drain() throws IOException { | |
| 726 | + bout.drain(); | |
| 727 | + } | |
| 728 | + | |
| 729 | + /** | |
| 730 | + * Closes the stream. This method must be called to release any resources | |
| 731 | + * associated with the stream. | |
| 732 | + * | |
| 733 | + * @throws IOException If an I/O error has occurred. | |
| 734 | + */ | |
| 735 | + public void close() throws IOException { | |
| 736 | + flush(); | |
| 737 | + clear(); | |
| 738 | + bout.close(); | |
| 739 | + } | |
| 740 | + | |
| 741 | + /** | |
| 742 | + * Writes a boolean. | |
| 743 | + * | |
| 744 | + * @param val the boolean to be written | |
| 745 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 746 | + * stream | |
| 747 | + */ | |
| 748 | + public void writeBoolean(boolean val) throws IOException { | |
| 749 | + bout.writeBoolean(val); | |
| 750 | + } | |
| 751 | + | |
| 752 | + /** | |
| 753 | + * Writes an 8 bit byte. | |
| 754 | + * | |
| 755 | + * @param val the byte value to be written | |
| 756 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 757 | + * stream | |
| 758 | + */ | |
| 759 | + public void writeByte(int val) throws IOException { | |
| 760 | + bout.writeByte(val); | |
| 761 | + } | |
| 762 | + | |
| 763 | + /** | |
| 764 | + * Writes a 16 bit short. | |
| 765 | + * | |
| 766 | + * @param val the short value to be written | |
| 767 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 768 | + * stream | |
| 769 | + */ | |
| 770 | + public void writeShort(int val) throws IOException { | |
| 771 | + bout.writeShort(val); | |
| 772 | + } | |
| 773 | + | |
| 774 | + /** | |
| 775 | + * Writes a 16 bit char. | |
| 776 | + * | |
| 777 | + * @param val the char value to be written | |
| 778 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 779 | + * stream | |
| 780 | + */ | |
| 781 | + public void writeChar(int val) throws IOException { | |
| 782 | + bout.writeChar(val); | |
| 783 | + } | |
| 784 | + | |
| 785 | + /** | |
| 786 | + * Writes a 32 bit int. | |
| 787 | + * | |
| 788 | + * @param val the integer value to be written | |
| 789 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 790 | + * stream | |
| 791 | + */ | |
| 792 | + public void writeInt(int val) throws IOException { | |
| 793 | + bout.writeInt(val); | |
| 794 | + } | |
| 795 | + | |
| 796 | + /** | |
| 797 | + * Writes a 64 bit long. | |
| 798 | + * | |
| 799 | + * @param val the long value to be written | |
| 800 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 801 | + * stream | |
| 802 | + */ | |
| 803 | + public void writeLong(long val) throws IOException { | |
| 804 | + bout.writeLong(val); | |
| 805 | + } | |
| 806 | + | |
| 807 | + /** | |
| 808 | + * Writes a 32 bit float. | |
| 809 | + * | |
| 810 | + * @param val the float value to be written | |
| 811 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 812 | + * stream | |
| 813 | + */ | |
| 814 | + public void writeFloat(float val) throws IOException { | |
| 815 | + bout.writeFloat(val); | |
| 816 | + } | |
| 817 | + | |
| 818 | + /** | |
| 819 | + * Writes a 64 bit double. | |
| 820 | + * | |
| 821 | + * @param val the double value to be written | |
| 822 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 823 | + * stream | |
| 824 | + */ | |
| 825 | + public void writeDouble(double val) throws IOException { | |
| 826 | + bout.writeDouble(val); | |
| 827 | + } | |
| 828 | + | |
| 829 | + /** | |
| 830 | + * Writes a String as a sequence of bytes. | |
| 831 | + * | |
| 832 | + * @param str the String of bytes to be written | |
| 833 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 834 | + * stream | |
| 835 | + */ | |
| 836 | + public void writeBytes(String str) throws IOException { | |
| 837 | + bout.writeBytes(str); | |
| 838 | + } | |
| 839 | + | |
| 840 | + /** | |
| 841 | + * Writes a String as a sequence of chars. | |
| 842 | + * | |
| 843 | + * @param str the String of chars to be written | |
| 844 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 845 | + * stream | |
| 846 | + */ | |
| 847 | + public void writeChars(String str) throws IOException { | |
| 848 | + bout.writeChars(str); | |
| 849 | + } | |
| 850 | + | |
| 851 | + /** | |
| 852 | + * Primitive data write of this String in | |
| 853 | + * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> | |
| 854 | + * format. Note that there is a | |
| 855 | + * significant difference between writing a String into the stream as | |
| 856 | + * primitive data or as an Object. A String instance written by writeObject | |
| 857 | + * is written into the stream as a String initially. Future writeObject() | |
| 858 | + * calls write references to the string into the stream. | |
| 859 | + * | |
| 860 | + * @param str the String to be written | |
| 861 | + * @throws IOException if I/O errors occur while writing to the underlying | |
| 862 | + * stream | |
| 863 | + */ | |
| 864 | + public void writeUTF(String str) throws IOException { | |
| 865 | + bout.writeUTF(str); | |
| 866 | + } | |
| 867 | + | |
| 868 | + /** | |
| 869 | + * Provide programmatic access to the persistent fields to be written | |
| 870 | + * to ObjectOutput. | |
| 871 | + * | |
| 872 | + * @since 1.2 | |
| 873 | + */ | |
| 874 | + public static abstract class PutField { | |
| 875 | + | |
| 876 | + /** | |
| 877 | + * Put the value of the named boolean field into the persistent field. | |
| 878 | + * | |
| 879 | + * @param name the name of the serializable field | |
| 880 | + * @param val the value to assign to the field | |
| 881 | + * @throws IllegalArgumentException if <code>name</code> does not | |
| 882 | + * match the name of a serializable field for the class whose fields | |
| 883 | + * are being written, or if the type of the named field is not | |
| 884 | + * <code>boolean</code> | |
| 885 | + */ | |
| 886 | + public abstract void put(String name, boolean val); | |
| 887 | + | |
| 888 | + /** | |
| 889 | + * Put the value of the named byte field into the persistent field. | |
| 890 | + * | |
| 891 | + * @param name the name of the serializable field | |
| 892 | + * @param val the value to assign to the field | |
| 893 | + * @throws IllegalArgumentException if <code>name</code> does not | |
| 894 | + * match the name of a serializable field for the class whose fields | |
| 895 | + * are being written, or if the type of the named field is not | |
| 896 | + * <code>byte</code> | |
| 897 | + */ | |
| 898 | + public abstract void put(String name, byte val); | |
| 899 | + | |
| 900 | + /** | |
| 901 | + * Put the value of the named char field into the persistent field. | |
| 902 | + * | |
| 903 | + * @param name the name of the serializable field | |
| 904 | + * @param val the value to assign to the field | |
| 905 | + * @throws IllegalArgumentException if <code>name</code> does not | |
| 906 | + * match the name of a serializable field for the class whose fields | |
| 907 | + * are being written, or if the type of the named field is not | |
| 908 | + * <code>char</code> | |
| 909 | + */ | |
| 910 | + public abstract void put(String name, char val); | |
| 911 | + | |
| 912 | + /** | |
| 913 | + * Put the value of the named short field into the persistent field. | |
| 914 | + * | |
| 915 | + * @param name the name of the serializable field | |
| 916 | + * @param val the value to assign to the field | |
| 917 | + * @throws IllegalArgumentException if <code>name</code> does not | |
| 918 | + * match the name of a serializable field for the class whose fields | |
| 919 | + * are being written, or if the type of the named field is not | |
| 920 | + * <code>short</code> | |
| 921 | + */ | |
| 922 | + public abstract void put(String name, short val); | |
| 923 | + | |
| 924 | + /** | |
| 925 | + * Put the value of the named int field into the persistent field. | |
| 926 | + * | |
| 927 | + * @param name the name of the serializable field | |
| 928 | + * @param val the value to assign to the field | |
| 929 | + * @throws IllegalArgumentException if <code>name</code> does not | |
| 930 | + * match the name of a serializable field for the class whose fields | |
| 931 | + * are being written, or if the type of the named field is not | |
| 932 | + * <code>int</code> | |
| 933 | + */ | |
| 934 | + public abstract void put(String name, int val); | |
| 935 | + | |
| 936 | + /** | |
| 937 | + * Put the value of the named long field into the persistent field. | |
| 938 | + * | |
| 939 | + * @param name the name of the serializable field | |
| 940 | + * @param val the value to assign to the field | |
| 941 | + * @throws IllegalArgumentException if <code>name</code> does not | |
| 942 | + * match the name of a serializable field for the class whose fields | |
| 943 | + * are being written, or if the type of the named field is not | |
| 944 | + * <code>long</code> | |
| 945 | + */ | |
| 946 | + public abstract void put(String name, long val); | |
| 947 | + | |
| 948 | + /** | |
| 949 | + * Put the value of the named float field into the persistent field. | |
| 950 | + * | |
| 951 | + * @param name the name of the serializable field | |
| 952 | + * @param val the value to assign to the field | |
| 953 | + * @throws IllegalArgumentException if <code>name</code> does not | |
| 954 | + * match the name of a serializable field for the class whose fields | |
| 955 | + * are being written, or if the type of the named field is not | |
| 956 | + * <code>float</code> | |
| 957 | + */ | |
| 958 | + public abstract void put(String name, float val); | |
| 959 | + | |
| 960 | + /** | |
| 961 | + * Put the value of the named double field into the persistent field. | |
| 962 | + * | |
| 963 | + * @param name the name of the serializable field | |
| 964 | + * @param val the value to assign to the field | |
| 965 | + * @throws IllegalArgumentException if <code>name</code> does not | |
| 966 | + * match the name of a serializable field for the class whose fields | |
| 967 | + * are being written, or if the type of the named field is not | |
| 968 | + * <code>double</code> | |
| 969 | + */ | |
| 970 | + public abstract void put(String name, double val); | |
| 971 | + | |
| 972 | + /** | |
| 973 | + * Put the value of the named Object field into the persistent field. | |
| 974 | + * | |
| 975 | + * @param name the name of the serializable field | |
| 976 | + * @param val the value to assign to the field | |
| 977 | + * (which may be <code>null</code>) | |
| 978 | + * @throws IllegalArgumentException if <code>name</code> does not | |
| 979 | + * match the name of a serializable field for the class whose fields | |
| 980 | + * are being written, or if the type of the named field is not a | |
| 981 | + * reference type | |
| 982 | + */ | |
| 983 | + public abstract void put(String name, Object val); | |
| 984 | + | |
| 985 | + /** | |
| 986 | + * Write the data and fields to the specified ObjectOutput stream, | |
| 987 | + * which must be the same stream that produced this | |
| 988 | + * <code>PutField</code> object. | |
| 989 | + * | |
| 990 | + * @param out the stream to write the data and fields to | |
| 991 | + * @throws IOException if I/O errors occur while writing to the | |
| 992 | + * underlying stream | |
| 993 | + * @throws IllegalArgumentException if the specified stream is not | |
| 994 | + * the same stream that produced this <code>PutField</code> | |
| 995 | + * object | |
| 996 | + * @deprecated This method does not write the values contained by this | |
| 997 | + * <code>PutField</code> object in a proper format, and may | |
| 998 | + * result in corruption of the serialization stream. The | |
| 999 | + * correct way to write <code>PutField</code> data is by | |
| 1000 | + * calling the {@link java.io.ObjectOutputStream#writeFields()} | |
| 1001 | + * method. | |
| 1002 | + */ | |
| 1003 | + @Deprecated | |
| 1004 | + public abstract void write(ObjectOutput out) throws IOException; | |
| 1005 | + } | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + /** | |
| 1009 | + * Returns protocol version in use. | |
| 1010 | + */ | |
| 1011 | + int getProtocolVersion() { | |
| 1012 | + return protocol; | |
| 1013 | + } | |
| 1014 | + | |
| 1015 | + /** | |
| 1016 | + * Writes string without allowing it to be replaced in stream. Used by | |
| 1017 | + * ObjectStreamClass to write class descriptor type strings. | |
| 1018 | + */ | |
| 1019 | + void writeTypeString(String str) throws IOException { | |
| 1020 | + int handle; | |
| 1021 | + if (str == null) { | |
| 1022 | + writeNull(); | |
| 1023 | + } else if ((handle = handles.lookup(str)) != -1) { | |
| 1024 | + writeHandle(handle); | |
| 1025 | + } else { | |
| 1026 | + writeString(str, false); | |
| 1027 | + } | |
| 1028 | + } | |
| 1029 | + | |
| 1030 | + /** | |
| 1031 | + * Verifies that this (possibly subclass) instance can be constructed | |
| 1032 | + * without violating security constraints: the subclass must not override | |
| 1033 | + * security-sensitive non-final methods, or else the | |
| 1034 | + * "enableSubclassImplementation" SerializablePermission is checked. | |
| 1035 | + */ | |
| 1036 | + private void verifySubclass() { | |
| 1037 | + Class cl = getClass(); | |
| 1038 | + if (cl == ObjectOutputStream.class) { | |
| 1039 | + return; | |
| 1040 | + } | |
| 1041 | + SecurityManager sm = System.getSecurityManager(); | |
| 1042 | + if (sm == null) { | |
| 1043 | + return; | |
| 1044 | + } | |
| 1045 | + processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); | |
| 1046 | + WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); | |
| 1047 | + Boolean result = Caches.subclassAudits.get(key); | |
| 1048 | + if (result == null) { | |
| 1049 | + result = Boolean.valueOf(auditSubclass(cl)); | |
| 1050 | + Caches.subclassAudits.putIfAbsent(key, result); | |
| 1051 | + } | |
| 1052 | + if (result.booleanValue()) { | |
| 1053 | + return; | |
| 1054 | + } | |
| 1055 | + sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); | |
| 1056 | + } | |
| 1057 | + | |
| 1058 | + /** | |
| 1059 | + * Performs reflective checks on given subclass to verify that it doesn't | |
| 1060 | + * override security-sensitive non-final methods. Returns true if subclass | |
| 1061 | + * is "safe", false otherwise. | |
| 1062 | + */ | |
| 1063 | + private static boolean auditSubclass(final Class subcl) { | |
| 1064 | + Boolean result = AccessController.doPrivileged( | |
| 1065 | + new PrivilegedAction<Boolean>() { | |
| 1066 | + public Boolean run() { | |
| 1067 | + for (Class cl = subcl; | |
| 1068 | + cl != ObjectOutputStream.class; | |
| 1069 | + cl = cl.getSuperclass()) | |
| 1070 | + { | |
| 1071 | + try { | |
| 1072 | + cl.getDeclaredMethod( | |
| 1073 | + "writeUnshared", new Class[] { Object.class }); | |
| 1074 | + return Boolean.FALSE; | |
| 1075 | + } catch (NoSuchMethodException ex) { | |
| 1076 | + } | |
| 1077 | + try { | |
| 1078 | + cl.getDeclaredMethod("putFields", (Class[]) null); | |
| 1079 | + return Boolean.FALSE; | |
| 1080 | + } catch (NoSuchMethodException ex) { | |
| 1081 | + } | |
| 1082 | + } | |
| 1083 | + return Boolean.TRUE; | |
| 1084 | + } | |
| 1085 | + } | |
| 1086 | + ); | |
| 1087 | + return result.booleanValue(); | |
| 1088 | + } | |
| 1089 | + | |
| 1090 | + /** | |
| 1091 | + * Clears internal data structures. | |
| 1092 | + */ | |
| 1093 | + private void clear() { | |
| 1094 | + subs.clear(); | |
| 1095 | + handles.clear(); | |
| 1096 | + } | |
| 1097 | + | |
| 1098 | + /** | |
| 1099 | + * Underlying writeObject/writeUnshared implementation. | |
| 1100 | + */ | |
| 1101 | + private void writeObject0(Object obj, boolean unshared) | |
| 1102 | + throws IOException | |
| 1103 | + { | |
| 1104 | + boolean oldMode = bout.setBlockDataMode(false); | |
| 1105 | + depth++; | |
| 1106 | + try { | |
| 1107 | + // handle previously written and non-replaceable objects | |
| 1108 | + int h; | |
| 1109 | + if ((obj = subs.lookup(obj)) == null) { | |
| 1110 | + writeNull(); | |
| 1111 | + return; | |
| 1112 | + } else if (!unshared && (h = handles.lookup(obj)) != -1) { | |
| 1113 | + writeHandle(h); | |
| 1114 | + return; | |
| 1115 | + } else if (obj instanceof Class) { | |
| 1116 | + writeClass((Class) obj, unshared); | |
| 1117 | + return; | |
| 1118 | + } else if (obj instanceof ObjectStreamClass) { | |
| 1119 | + writeClassDesc((ObjectStreamClass) obj, unshared); | |
| 1120 | + return; | |
| 1121 | + } | |
| 1122 | + | |
| 1123 | + // check for replacement object | |
| 1124 | + Object orig = obj; | |
| 1125 | + Class cl = obj.getClass(); | |
| 1126 | + ObjectStreamClass desc; | |
| 1127 | + for (;;) { | |
| 1128 | + // REMIND: skip this check for strings/arrays? | |
| 1129 | + Class repCl; | |
| 1130 | + desc = ObjectStreamClass.lookup(cl, true); | |
| 1131 | + if (!desc.hasWriteReplaceMethod() || | |
| 1132 | + (obj = desc.invokeWriteReplace(obj)) == null || | |
| 1133 | + (repCl = obj.getClass()) == cl) | |
| 1134 | + { | |
| 1135 | + break; | |
| 1136 | + } | |
| 1137 | + cl = repCl; | |
| 1138 | + } | |
| 1139 | + if (enableReplace) { | |
| 1140 | + Object rep = replaceObject(obj); | |
| 1141 | + if (rep != obj && rep != null) { | |
| 1142 | + cl = rep.getClass(); | |
| 1143 | + desc = ObjectStreamClass.lookup(cl, true); | |
| 1144 | + } | |
| 1145 | + obj = rep; | |
| 1146 | + } | |
| 1147 | + | |
| 1148 | + // if object replaced, run through original checks a second time | |
| 1149 | + if (obj != orig) { | |
| 1150 | + subs.assign(orig, obj); | |
| 1151 | + if (obj == null) { | |
| 1152 | + writeNull(); | |
| 1153 | + return; | |
| 1154 | + } else if (!unshared && (h = handles.lookup(obj)) != -1) { | |
| 1155 | + writeHandle(h); | |
| 1156 | + return; | |
| 1157 | + } else if (obj instanceof Class) { | |
| 1158 | + writeClass((Class) obj, unshared); | |
| 1159 | + return; | |
| 1160 | + } else if (obj instanceof ObjectStreamClass) { | |
| 1161 | + writeClassDesc((ObjectStreamClass) obj, unshared); | |
| 1162 | + return; | |
| 1163 | + } | |
| 1164 | + } | |
| 1165 | + | |
| 1166 | + // remaining cases | |
| 1167 | + if (obj instanceof String) { | |
| 1168 | + writeString((String) obj, unshared); | |
| 1169 | + } else if (cl.isArray()) { | |
| 1170 | + writeArray(obj, desc, unshared); | |
| 1171 | + } else if (obj instanceof Enum) { | |
| 1172 | + writeEnum((Enum) obj, desc, unshared); | |
| 1173 | + } else if (obj instanceof Serializable) { | |
| 1174 | + writeOrdinaryObject(obj, desc, unshared); | |
| 1175 | + } else { | |
| 1176 | + if (extendedDebugInfo) { | |
| 1177 | + throw new NotSerializableException( | |
| 1178 | + cl.getName() + "\n" + debugInfoStack.toString()); | |
| 1179 | + } else { | |
| 1180 | + throw new NotSerializableException(cl.getName()); | |
| 1181 | + } | |
| 1182 | + } | |
| 1183 | + } finally { | |
| 1184 | + depth--; | |
| 1185 | + bout.setBlockDataMode(oldMode); | |
| 1186 | + } | |
| 1187 | + } | |
| 1188 | + | |
| 1189 | + /** | |
| 1190 | + * Writes null code to stream. | |
| 1191 | + */ | |
| 1192 | + private void writeNull() throws IOException { | |
| 1193 | + bout.writeByte(TC_NULL); | |
| 1194 | + } | |
| 1195 | + | |
| 1196 | + /** | |
| 1197 | + * Writes given object handle to stream. | |
| 1198 | + */ | |
| 1199 | + private void writeHandle(int handle) throws IOException { | |
| 1200 | + bout.writeByte(TC_REFERENCE); | |
| 1201 | + bout.writeInt(baseWireHandle + handle); | |
| 1202 | + } | |
| 1203 | + | |
| 1204 | + /** | |
| 1205 | + * Writes representation of given class to stream. | |
| 1206 | + */ | |
| 1207 | + private void writeClass(Class cl, boolean unshared) throws IOException { | |
| 1208 | + bout.writeByte(TC_CLASS); | |
| 1209 | + writeClassDesc(ObjectStreamClass.lookup(cl, true), false); | |
| 1210 | + handles.assign(unshared ? null : cl); | |
| 1211 | + } | |
| 1212 | + | |
| 1213 | + /** | |
| 1214 | + * Writes representation of given class descriptor to stream. | |
| 1215 | + */ | |
| 1216 | + private void writeClassDesc(ObjectStreamClass desc, boolean unshared) | |
| 1217 | + throws IOException | |
| 1218 | + { | |
| 1219 | + int handle; | |
| 1220 | + if (desc == null) { | |
| 1221 | + writeNull(); | |
| 1222 | + } else if (!unshared && (handle = handles.lookup(desc)) != -1) { | |
| 1223 | + writeHandle(handle); | |
| 1224 | + } else if (desc.isProxy()) { | |
| 1225 | + writeProxyDesc(desc, unshared); | |
| 1226 | + } else { | |
| 1227 | + writeNonProxyDesc(desc, unshared); | |
| 1228 | + } | |
| 1229 | + } | |
| 1230 | + | |
| 1231 | + /** | |
| 1232 | + * Writes class descriptor representing a dynamic proxy class to stream. | |
| 1233 | + */ | |
| 1234 | + private void writeProxyDesc(ObjectStreamClass desc, boolean unshared) | |
| 1235 | + throws IOException | |
| 1236 | + { | |
| 1237 | + bout.writeByte(TC_PROXYCLASSDESC); | |
| 1238 | + handles.assign(unshared ? null : desc); | |
| 1239 | + | |
| 1240 | + Class cl = desc.forClass(); | |
| 1241 | + Class[] ifaces = cl.getInterfaces(); | |
| 1242 | + bout.writeInt(ifaces.length); | |
| 1243 | + for (int i = 0; i < ifaces.length; i++) { | |
| 1244 | + bout.writeUTF(ifaces[i].getName()); | |
| 1245 | + } | |
| 1246 | + | |
| 1247 | + bout.setBlockDataMode(true); | |
| 1248 | + annotateProxyClass(cl); | |
| 1249 | + bout.setBlockDataMode(false); | |
| 1250 | + bout.writeByte(TC_ENDBLOCKDATA); | |
| 1251 | + | |
| 1252 | + writeClassDesc(desc.getSuperDesc(), false); | |
| 1253 | + } | |
| 1254 | + | |
| 1255 | + /** | |
| 1256 | + * Writes class descriptor representing a standard (i.e., not a dynamic | |
| 1257 | + * proxy) class to stream. | |
| 1258 | + */ | |
| 1259 | + private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared) | |
| 1260 | + throws IOException | |
| 1261 | + { | |
| 1262 | + bout.writeByte(TC_CLASSDESC); | |
| 1263 | + handles.assign(unshared ? null : desc); | |
| 1264 | + | |
| 1265 | + if (protocol == PROTOCOL_VERSION_1) { | |
| 1266 | + // do not invoke class descriptor write hook with old protocol | |
| 1267 | + desc.writeNonProxy(this); | |
| 1268 | + } else { | |
| 1269 | + writeClassDescriptor(desc); | |
| 1270 | + } | |
| 1271 | + | |
| 1272 | + Class cl = desc.forClass(); | |
| 1273 | + bout.setBlockDataMode(true); | |
| 1274 | + annotateClass(cl); | |
| 1275 | + bout.setBlockDataMode(false); | |
| 1276 | + bout.writeByte(TC_ENDBLOCKDATA); | |
| 1277 | + | |
| 1278 | + writeClassDesc(desc.getSuperDesc(), false); | |
| 1279 | + } | |
| 1280 | + | |
| 1281 | + /** | |
| 1282 | + * Writes given string to stream, using standard or long UTF format | |
| 1283 | + * depending on string length. | |
| 1284 | + */ | |
| 1285 | + private void writeString(String str, boolean unshared) throws IOException { | |
| 1286 | + handles.assign(unshared ? null : str); | |
| 1287 | + long utflen = bout.getUTFLength(str); | |
| 1288 | + if (utflen <= 0xFFFF) { | |
| 1289 | + bout.writeByte(TC_STRING); | |
| 1290 | + bout.writeUTF(str, utflen); | |
| 1291 | + } else { | |
| 1292 | + bout.writeByte(TC_LONGSTRING); | |
| 1293 | + bout.writeLongUTF(str, utflen); | |
| 1294 | + } | |
| 1295 | + } | |
| 1296 | + | |
| 1297 | + /** | |
| 1298 | + * Writes given array object to stream. | |
| 1299 | + */ | |
| 1300 | + private void writeArray(Object array, | |
| 1301 | + ObjectStreamClass desc, | |
| 1302 | + boolean unshared) | |
| 1303 | + throws IOException | |
| 1304 | + { | |
| 1305 | + bout.writeByte(TC_ARRAY); | |
| 1306 | + writeClassDesc(desc, false); | |
| 1307 | + handles.assign(unshared ? null : array); | |
| 1308 | + | |
| 1309 | + Class ccl = desc.forClass().getComponentType(); | |
| 1310 | + if (ccl.isPrimitive()) { | |
| 1311 | + if (ccl == Integer.TYPE) { | |
| 1312 | + int[] ia = (int[]) array; | |
| 1313 | + bout.writeInt(ia.length); | |
| 1314 | + bout.writeInts(ia, 0, ia.length); | |
| 1315 | + } else if (ccl == Byte.TYPE) { | |
| 1316 | + byte[] ba = (byte[]) array; | |
| 1317 | + bout.writeInt(ba.length); | |
| 1318 | + bout.write(ba, 0, ba.length, true); | |
| 1319 | + } else if (ccl == Long.TYPE) { | |
| 1320 | + long[] ja = (long[]) array; | |
| 1321 | + bout.writeInt(ja.length); | |
| 1322 | + bout.writeLongs(ja, 0, ja.length); | |
| 1323 | + } else if (ccl == Float.TYPE) { | |
| 1324 | + float[] fa = (float[]) array; | |
| 1325 | + bout.writeInt(fa.length); | |
| 1326 | + bout.writeFloats(fa, 0, fa.length); | |
| 1327 | + } else if (ccl == Double.TYPE) { | |
| 1328 | + double[] da = (double[]) array; | |
| 1329 | + bout.writeInt(da.length); | |
| 1330 | + bout.writeDoubles(da, 0, da.length); | |
| 1331 | + } else if (ccl == Short.TYPE) { | |
| 1332 | + short[] sa = (short[]) array; | |
| 1333 | + bout.writeInt(sa.length); | |
| 1334 | + bout.writeShorts(sa, 0, sa.length); | |
| 1335 | + } else if (ccl == Character.TYPE) { | |
| 1336 | + char[] ca = (char[]) array; | |
| 1337 | + bout.writeInt(ca.length); | |
| 1338 | + bout.writeChars(ca, 0, ca.length); | |
| 1339 | + } else if (ccl == Boolean.TYPE) { | |
| 1340 | + boolean[] za = (boolean[]) array; | |
| 1341 | + bout.writeInt(za.length); | |
| 1342 | + bout.writeBooleans(za, 0, za.length); | |
| 1343 | + } else { | |
| 1344 | + throw new InternalError(); | |
| 1345 | + } | |
| 1346 | + } else { | |
| 1347 | + Object[] objs = (Object[]) array; | |
| 1348 | + int len = objs.length; | |
| 1349 | + bout.writeInt(len); | |
| 1350 | + if (extendedDebugInfo) { | |
| 1351 | + debugInfoStack.push( | |
| 1352 | + "array (class \"" + array.getClass().getName() + | |
| 1353 | + "\", size: " + len + ")"); | |
| 1354 | + } | |
| 1355 | + try { | |
| 1356 | + for (int i = 0; i < len; i++) { | |
| 1357 | + if (extendedDebugInfo) { | |
| 1358 | + debugInfoStack.push( | |
| 1359 | + "element of array (index: " + i + ")"); | |
| 1360 | + } | |
| 1361 | + try { | |
| 1362 | + writeObject0(objs[i], false); | |
| 1363 | + } finally { | |
| 1364 | + if (extendedDebugInfo) { | |
| 1365 | + debugInfoStack.pop(); | |
| 1366 | + } | |
| 1367 | + } | |
| 1368 | + } | |
| 1369 | + } finally { | |
| 1370 | + if (extendedDebugInfo) { | |
| 1371 | + debugInfoStack.pop(); | |
| 1372 | + } | |
| 1373 | + } | |
| 1374 | + } | |
| 1375 | + } | |
| 1376 | + | |
| 1377 | + /** | |
| 1378 | + * Writes given enum constant to stream. | |
| 1379 | + */ | |
| 1380 | + private void writeEnum(Enum en, | |
| 1381 | + ObjectStreamClass desc, | |
| 1382 | + boolean unshared) | |
| 1383 | + throws IOException | |
| 1384 | + { | |
| 1385 | + bout.writeByte(TC_ENUM); | |
| 1386 | + ObjectStreamClass sdesc = desc.getSuperDesc(); | |
| 1387 | + writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false); | |
| 1388 | + handles.assign(unshared ? null : en); | |
| 1389 | + writeString(en.name(), false); | |
| 1390 | + } | |
| 1391 | + | |
| 1392 | + /** | |
| 1393 | + * Writes representation of a "ordinary" (i.e., not a String, Class, | |
| 1394 | + * ObjectStreamClass, array, or enum constant) serializable object to the | |
| 1395 | + * stream. | |
| 1396 | + */ | |
| 1397 | + private void writeOrdinaryObject(Object obj, | |
| 1398 | + ObjectStreamClass desc, | |
| 1399 | + boolean unshared) | |
| 1400 | + throws IOException | |
| 1401 | + { | |
| 1402 | + if (extendedDebugInfo) { | |
| 1403 | + debugInfoStack.push( | |
| 1404 | + (depth == 1 ? "root " : "") + "object (class \"" + | |
| 1405 | + obj.getClass().getName() + "\", " + obj.toString() + ")"); | |
| 1406 | + } | |
| 1407 | + try { | |
| 1408 | + desc.checkSerialize(); | |
| 1409 | + | |
| 1410 | + bout.writeByte(TC_OBJECT); | |
| 1411 | + writeClassDesc(desc, false); | |
| 1412 | + handles.assign(unshared ? null : obj); | |
| 1413 | + if (desc.isExternalizable() && !desc.isProxy()) { | |
| 1414 | + writeExternalData((Externalizable) obj); | |
| 1415 | + } else { | |
| 1416 | + writeSerialData(obj, desc); | |
| 1417 | + } | |
| 1418 | + } finally { | |
| 1419 | + if (extendedDebugInfo) { | |
| 1420 | + debugInfoStack.pop(); | |
| 1421 | + } | |
| 1422 | + } | |
| 1423 | + } | |
| 1424 | + | |
| 1425 | + /** | |
| 1426 | + * Writes externalizable data of given object by invoking its | |
| 1427 | + * writeExternal() method. | |
| 1428 | + */ | |
| 1429 | + private void writeExternalData(Externalizable obj) throws IOException { | |
| 1430 | + PutFieldImpl oldPut = curPut; | |
| 1431 | + curPut = null; | |
| 1432 | + | |
| 1433 | + if (extendedDebugInfo) { | |
| 1434 | + debugInfoStack.push("writeExternal data"); | |
| 1435 | + } | |
| 1436 | + SerialCallbackContext oldContext = curContext; | |
| 1437 | + try { | |
| 1438 | + curContext = null; | |
| 1439 | + if (protocol == PROTOCOL_VERSION_1) { | |
| 1440 | + obj.writeExternal(this); | |
| 1441 | + } else { | |
| 1442 | + bout.setBlockDataMode(true); | |
| 1443 | + obj.writeExternal(this); | |
| 1444 | + bout.setBlockDataMode(false); | |
| 1445 | + bout.writeByte(TC_ENDBLOCKDATA); | |
| 1446 | + } | |
| 1447 | + } finally { | |
| 1448 | + curContext = oldContext; | |
| 1449 | + if (extendedDebugInfo) { | |
| 1450 | + debugInfoStack.pop(); | |
| 1451 | + } | |
| 1452 | + } | |
| 1453 | + | |
| 1454 | + curPut = oldPut; | |
| 1455 | + } | |
| 1456 | + | |
| 1457 | + /** | |
| 1458 | + * Writes instance data for each serializable class of given object, from | |
| 1459 | + * superclass to subclass. | |
| 1460 | + */ | |
| 1461 | + private void writeSerialData(Object obj, ObjectStreamClass desc) | |
| 1462 | + throws IOException | |
| 1463 | + { | |
| 1464 | + ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); | |
| 1465 | + for (int i = 0; i < slots.length; i++) { | |
| 1466 | + ObjectStreamClass slotDesc = slots[i].desc; | |
| 1467 | + if (slotDesc.hasWriteObjectMethod()) { | |
| 1468 | + PutFieldImpl oldPut = curPut; | |
| 1469 | + curPut = null; | |
| 1470 | + SerialCallbackContext oldContext = curContext; | |
| 1471 | + | |
| 1472 | + if (extendedDebugInfo) { | |
| 1473 | + debugInfoStack.push( | |
| 1474 | + "custom writeObject data (class \"" + | |
| 1475 | + slotDesc.getName() + "\")"); | |
| 1476 | + } | |
| 1477 | + try { | |
| 1478 | + curContext = new SerialCallbackContext(obj, slotDesc); | |
| 1479 | + bout.setBlockDataMode(true); | |
| 1480 | + slotDesc.invokeWriteObject(obj, this); | |
| 1481 | + bout.setBlockDataMode(false); | |
| 1482 | + bout.writeByte(TC_ENDBLOCKDATA); | |
| 1483 | + } finally { | |
| 1484 | + curContext.setUsed(); | |
| 1485 | + curContext = oldContext; | |
| 1486 | + if (extendedDebugInfo) { | |
| 1487 | + debugInfoStack.pop(); | |
| 1488 | + } | |
| 1489 | + } | |
| 1490 | + | |
| 1491 | + curPut = oldPut; | |
| 1492 | + } else { | |
| 1493 | + defaultWriteFields(obj, slotDesc); | |
| 1494 | + } | |
| 1495 | + } | |
| 1496 | + } | |
| 1497 | + | |
| 1498 | + /** | |
| 1499 | + * Fetches and writes values of serializable fields of given object to | |
| 1500 | + * stream. The given class descriptor specifies which field values to | |
| 1501 | + * write, and in which order they should be written. | |
| 1502 | + */ | |
| 1503 | + private void defaultWriteFields(Object obj, ObjectStreamClass desc) | |
| 1504 | + throws IOException | |
| 1505 | + { | |
| 1506 | + // REMIND: perform conservative isInstance check here? | |
| 1507 | + desc.checkDefaultSerialize(); | |
| 1508 | + | |
| 1509 | + int primDataSize = desc.getPrimDataSize(); | |
| 1510 | + if (primVals == null || primVals.length < primDataSize) { | |
| 1511 | + primVals = new byte[primDataSize]; | |
| 1512 | + } | |
| 1513 | + desc.getPrimFieldValues(obj, primVals); | |
| 1514 | + bout.write(primVals, 0, primDataSize, false); | |
| 1515 | + | |
| 1516 | + ObjectStreamField[] fields = desc.getFields(false); | |
| 1517 | + Object[] objVals = new Object[desc.getNumObjFields()]; | |
| 1518 | + int numPrimFields = fields.length - objVals.length; | |
| 1519 | + desc.getObjFieldValues(obj, objVals); | |
| 1520 | + for (int i = 0; i < objVals.length; i++) { | |
| 1521 | + if (extendedDebugInfo) { | |
| 1522 | + debugInfoStack.push( | |
| 1523 | + "field (class \"" + desc.getName() + "\", name: \"" + | |
| 1524 | + fields[numPrimFields + i].getName() + "\", type: \"" + | |
| 1525 | + fields[numPrimFields + i].getType() + "\")"); | |
| 1526 | + } | |
| 1527 | + try { | |
| 1528 | + writeObject0(objVals[i], | |
| 1529 | + fields[numPrimFields + i].isUnshared()); | |
| 1530 | + } finally { | |
| 1531 | + if (extendedDebugInfo) { | |
| 1532 | + debugInfoStack.pop(); | |
| 1533 | + } | |
| 1534 | + } | |
| 1535 | + } | |
| 1536 | + } | |
| 1537 | + | |
| 1538 | + /** | |
| 1539 | + * Attempts to write to stream fatal IOException that has caused | |
| 1540 | + * serialization to abort. | |
| 1541 | + */ | |
| 1542 | + private void writeFatalException(IOException ex) throws IOException { | |
| 1543 | + /* | |
| 1544 | + * Note: the serialization specification states that if a second | |
| 1545 | + * IOException occurs while attempting to serialize the original fatal | |
| 1546 | + * exception to the stream, then a StreamCorruptedException should be | |
| 1547 | + * thrown (section 2.1). However, due to a bug in previous | |
| 1548 | + * implementations of serialization, StreamCorruptedExceptions were | |
| 1549 | + * rarely (if ever) actually thrown--the "root" exceptions from | |
| 1550 | + * underlying streams were thrown instead. This historical behavior is | |
| 1551 | + * followed here for consistency. | |
| 1552 | + */ | |
| 1553 | + clear(); | |
| 1554 | + boolean oldMode = bout.setBlockDataMode(false); | |
| 1555 | + try { | |
| 1556 | + bout.writeByte(TC_EXCEPTION); | |
| 1557 | + writeObject0(ex, false); | |
| 1558 | + clear(); | |
| 1559 | + } finally { | |
| 1560 | + bout.setBlockDataMode(oldMode); | |
| 1561 | + } | |
| 1562 | + } | |
| 1563 | + | |
| 1564 | + /** | |
| 1565 | + * Converts specified span of float values into byte values. | |
| 1566 | + */ | |
| 1567 | + // REMIND: remove once hotspot inlines Float.floatToIntBits | |
| 1568 | + private static native void floatsToBytes(float[] src, int srcpos, | |
| 1569 | + byte[] dst, int dstpos, | |
| 1570 | + int nfloats); | |
| 1571 | + | |
| 1572 | + /** | |
| 1573 | + * Converts specified span of double values into byte values. | |
| 1574 | + */ | |
| 1575 | + // REMIND: remove once hotspot inlines Double.doubleToLongBits | |
| 1576 | + private static native void doublesToBytes(double[] src, int srcpos, | |
| 1577 | + byte[] dst, int dstpos, | |
| 1578 | + int ndoubles); | |
| 1579 | + | |
| 1580 | + /** | |
| 1581 | + * Default PutField implementation. | |
| 1582 | + */ | |
| 1583 | + private class PutFieldImpl extends PutField { | |
| 1584 | + | |
| 1585 | + /** class descriptor describing serializable fields */ | |
| 1586 | + private final ObjectStreamClass desc; | |
| 1587 | + /** primitive field values */ | |
| 1588 | + private final byte[] primVals; | |
| 1589 | + /** object field values */ | |
| 1590 | + private final Object[] objVals; | |
| 1591 | + | |
| 1592 | + /** | |
| 1593 | + * Creates PutFieldImpl object for writing fields defined in given | |
| 1594 | + * class descriptor. | |
| 1595 | + */ | |
| 1596 | + PutFieldImpl(ObjectStreamClass desc) { | |
| 1597 | + this.desc = desc; | |
| 1598 | + primVals = new byte[desc.getPrimDataSize()]; | |
| 1599 | + objVals = new Object[desc.getNumObjFields()]; | |
| 1600 | + } | |
| 1601 | + | |
| 1602 | + public void put(String name, boolean val) { | |
| 1603 | + Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val); | |
| 1604 | + } | |
| 1605 | + | |
| 1606 | + public void put(String name, byte val) { | |
| 1607 | + primVals[getFieldOffset(name, Byte.TYPE)] = val; | |
| 1608 | + } | |
| 1609 | + | |
| 1610 | + public void put(String name, char val) { | |
| 1611 | + Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val); | |
| 1612 | + } | |
| 1613 | + | |
| 1614 | + public void put(String name, short val) { | |
| 1615 | + Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val); | |
| 1616 | + } | |
| 1617 | + | |
| 1618 | + public void put(String name, int val) { | |
| 1619 | + Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val); | |
| 1620 | + } | |
| 1621 | + | |
| 1622 | + public void put(String name, float val) { | |
| 1623 | + Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val); | |
| 1624 | + } | |
| 1625 | + | |
| 1626 | + public void put(String name, long val) { | |
| 1627 | + Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val); | |
| 1628 | + } | |
| 1629 | + | |
| 1630 | + public void put(String name, double val) { | |
| 1631 | + Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val); | |
| 1632 | + } | |
| 1633 | + | |
| 1634 | + public void put(String name, Object val) { | |
| 1635 | + objVals[getFieldOffset(name, Object.class)] = val; | |
| 1636 | + } | |
| 1637 | + | |
| 1638 | + // deprecated in ObjectOutputStream.PutField | |
| 1639 | + public void write(ObjectOutput out) throws IOException { | |
| 1640 | + /* | |
| 1641 | + * Applications should *not* use this method to write PutField | |
| 1642 | + * data, as it will lead to stream corruption if the PutField | |
| 1643 | + * object writes any primitive data (since block data mode is not | |
| 1644 | + * unset/set properly, as is done in OOS.writeFields()). This | |
| 1645 | + * broken implementation is being retained solely for behavioral | |
| 1646 | + * compatibility, in order to support applications which use | |
| 1647 | + * OOS.PutField.write() for writing only non-primitive data. | |
| 1648 | + * | |
| 1649 | + * Serialization of unshared objects is not implemented here since | |
| 1650 | + * it is not necessary for backwards compatibility; also, unshared | |
| 1651 | + * semantics may not be supported by the given ObjectOutput | |
| 1652 | + * instance. Applications which write unshared objects using the | |
| 1653 | + * PutField API must use OOS.writeFields(). | |
| 1654 | + */ | |
| 1655 | + if (ObjectOutputStream.this != out) { | |
| 1656 | + throw new IllegalArgumentException("wrong stream"); | |
| 1657 | + } | |
| 1658 | + out.write(primVals, 0, primVals.length); | |
| 1659 | + | |
| 1660 | + ObjectStreamField[] fields = desc.getFields(false); | |
| 1661 | + int numPrimFields = fields.length - objVals.length; | |
| 1662 | + // REMIND: warn if numPrimFields > 0? | |
| 1663 | + for (int i = 0; i < objVals.length; i++) { | |
| 1664 | + if (fields[numPrimFields + i].isUnshared()) { | |
| 1665 | + throw new IOException("cannot write unshared object"); | |
| 1666 | + } | |
| 1667 | + out.writeObject(objVals[i]); | |
| 1668 | + } | |
| 1669 | + } | |
| 1670 | + | |
| 1671 | + /** | |
| 1672 | + * Writes buffered primitive data and object fields to stream. | |
| 1673 | + */ | |
| 1674 | + void writeFields() throws IOException { | |
| 1675 | + bout.write(primVals, 0, primVals.length, false); | |
| 1676 | + | |
| 1677 | + ObjectStreamField[] fields = desc.getFields(false); | |
| 1678 | + int numPrimFields = fields.length - objVals.length; | |
| 1679 | + for (int i = 0; i < objVals.length; i++) { | |
| 1680 | + if (extendedDebugInfo) { | |
| 1681 | + debugInfoStack.push( | |
| 1682 | + "field (class \"" + desc.getName() + "\", name: \"" + | |
| 1683 | + fields[numPrimFields + i].getName() + "\", type: \"" + | |
| 1684 | + fields[numPrimFields + i].getType() + "\")"); | |
| 1685 | + } | |
| 1686 | + try { | |
| 1687 | + writeObject0(objVals[i], | |
| 1688 | + fields[numPrimFields + i].isUnshared()); | |
| 1689 | + } finally { | |
| 1690 | + if (extendedDebugInfo) { | |
| 1691 | + debugInfoStack.pop(); | |
| 1692 | + } | |
| 1693 | + } | |
| 1694 | + } | |
| 1695 | + } | |
| 1696 | + | |
| 1697 | + /** | |
| 1698 | + * Returns offset of field with given name and type. A specified type | |
| 1699 | + * of null matches all types, Object.class matches all non-primitive | |
| 1700 | + * types, and any other non-null type matches assignable types only. | |
| 1701 | + * Throws IllegalArgumentException if no matching field found. | |
| 1702 | + */ | |
| 1703 | + private int getFieldOffset(String name, Class type) { | |
| 1704 | + ObjectStreamField field = desc.getField(name, type); | |
| 1705 | + if (field == null) { | |
| 1706 | + throw new IllegalArgumentException("no such field " + name + | |
| 1707 | + " with type " + type); | |
| 1708 | + } | |
| 1709 | + return field.getOffset(); | |
| 1710 | + } | |
| 1711 | + } | |
| 1712 | + | |
| 1713 | + /** | |
| 1714 | + * Buffered output stream with two modes: in default mode, outputs data in | |
| 1715 | + * same format as DataOutputStream; in "block data" mode, outputs data | |
| 1716 | + * bracketed by block data markers (see object serialization specification | |
| 1717 | + * for details). | |
| 1718 | + */ | |
| 1719 | + private static class BlockDataOutputStream | |
| 1720 | + extends OutputStream implements DataOutput | |
| 1721 | + { | |
| 1722 | + /** maximum data block length */ | |
| 1723 | + private static final int MAX_BLOCK_SIZE = 1024; | |
| 1724 | + /** maximum data block header length */ | |
| 1725 | + private static final int MAX_HEADER_SIZE = 5; | |
| 1726 | + /** (tunable) length of char buffer (for writing strings) */ | |
| 1727 | + private static final int CHAR_BUF_SIZE = 256; | |
| 1728 | + | |
| 1729 | + /** buffer for writing general/block data */ | |
| 1730 | + private final byte[] buf = new byte[MAX_BLOCK_SIZE]; | |
| 1731 | + /** buffer for writing block data headers */ | |
| 1732 | + private final byte[] hbuf = new byte[MAX_HEADER_SIZE]; | |
| 1733 | + /** char buffer for fast string writes */ | |
| 1734 | + private final char[] cbuf = new char[CHAR_BUF_SIZE]; | |
| 1735 | + | |
| 1736 | + /** block data mode */ | |
| 1737 | + private boolean blkmode = false; | |
| 1738 | + /** current offset into buf */ | |
| 1739 | + private int pos = 0; | |
| 1740 | + | |
| 1741 | + /** underlying output stream */ | |
| 1742 | + private final OutputStream out; | |
| 1743 | + /** loopback stream (for data writes that span data blocks) */ | |
| 1744 | + private final DataOutputStream dout; | |
| 1745 | + | |
| 1746 | + /** | |
| 1747 | + * Creates new BlockDataOutputStream on top of given underlying stream. | |
| 1748 | + * Block data mode is turned off by default. | |
| 1749 | + */ | |
| 1750 | + BlockDataOutputStream(OutputStream out) { | |
| 1751 | + this.out = out; | |
| 1752 | + dout = new DataOutputStream(this); | |
| 1753 | + } | |
| 1754 | + | |
| 1755 | + /** | |
| 1756 | + * Sets block data mode to the given mode (true == on, false == off) | |
| 1757 | + * and returns the previous mode value. If the new mode is the same as | |
| 1758 | + * the old mode, no action is taken. If the new mode differs from the | |
| 1759 | + * old mode, any buffered data is flushed before switching to the new | |
| 1760 | + * mode. | |
| 1761 | + */ | |
| 1762 | + boolean setBlockDataMode(boolean mode) throws IOException { | |
| 1763 | + if (blkmode == mode) { | |
| 1764 | + return blkmode; | |
| 1765 | + } | |
| 1766 | + drain(); | |
| 1767 | + blkmode = mode; | |
| 1768 | + return !blkmode; | |
| 1769 | + } | |
| 1770 | + | |
| 1771 | + /** | |
| 1772 | + * Returns true if the stream is currently in block data mode, false | |
| 1773 | + * otherwise. | |
| 1774 | + */ | |
| 1775 | + boolean getBlockDataMode() { | |
| 1776 | + return blkmode; | |
| 1777 | + } | |
| 1778 | + | |
| 1779 | + /* ----------------- generic output stream methods ----------------- */ | |
| 1780 | + /* | |
| 1781 | + * The following methods are equivalent to their counterparts in | |
| 1782 | + * OutputStream, except that they partition written data into data | |
| 1783 | + * blocks when in block data mode. | |
| 1784 | + */ | |
| 1785 | + | |
| 1786 | + public void write(int b) throws IOException { | |
| 1787 | + if (pos >= MAX_BLOCK_SIZE) { | |
| 1788 | + drain(); | |
| 1789 | + } | |
| 1790 | + buf[pos++] = (byte) b; | |
| 1791 | + } | |
| 1792 | + | |
| 1793 | + public void write(byte[] b) throws IOException { | |
| 1794 | + write(b, 0, b.length, false); | |
| 1795 | + } | |
| 1796 | + | |
| 1797 | + public void write(byte[] b, int off, int len) throws IOException { | |
| 1798 | + write(b, off, len, false); | |
| 1799 | + } | |
| 1800 | + | |
| 1801 | + public void flush() throws IOException { | |
| 1802 | + drain(); | |
| 1803 | + out.flush(); | |
| 1804 | + } | |
| 1805 | + | |
| 1806 | + public void close() throws IOException { | |
| 1807 | + flush(); | |
| 1808 | + out.close(); | |
| 1809 | + } | |
| 1810 | + | |
| 1811 | + /** | |
| 1812 | + * Writes specified span of byte values from given array. If copy is | |
| 1813 | + * true, copies the values to an intermediate buffer before writing | |
| 1814 | + * them to underlying stream (to avoid exposing a reference to the | |
| 1815 | + * original byte array). | |
| 1816 | + */ | |
| 1817 | + void write(byte[] b, int off, int len, boolean copy) | |
| 1818 | + throws IOException | |
| 1819 | + { | |
| 1820 | + if (!(copy || blkmode)) { // write directly | |
| 1821 | + drain(); | |
| 1822 | + out.write(b, off, len); | |
| 1823 | + return; | |
| 1824 | + } | |
| 1825 | + | |
| 1826 | + while (len > 0) { | |
| 1827 | + if (pos >= MAX_BLOCK_SIZE) { | |
| 1828 | + drain(); | |
| 1829 | + } | |
| 1830 | + if (len >= MAX_BLOCK_SIZE && !copy && pos == 0) { | |
| 1831 | + // avoid unnecessary copy | |
| 1832 | + writeBlockHeader(MAX_BLOCK_SIZE); | |
| 1833 | + out.write(b, off, MAX_BLOCK_SIZE); | |
| 1834 | + off += MAX_BLOCK_SIZE; | |
| 1835 | + len -= MAX_BLOCK_SIZE; | |
| 1836 | + } else { | |
| 1837 | + int wlen = Math.min(len, MAX_BLOCK_SIZE - pos); | |
| 1838 | + System.arraycopy(b, off, buf, pos, wlen); | |
| 1839 | + pos += wlen; | |
| 1840 | + off += wlen; | |
| 1841 | + len -= wlen; | |
| 1842 | + } | |
| 1843 | + } | |
| 1844 | + } | |
| 1845 | + | |
| 1846 | + /** | |
| 1847 | + * Writes all buffered data from this stream to the underlying stream, | |
| 1848 | + * but does not flush underlying stream. | |
| 1849 | + */ | |
| 1850 | + void drain() throws IOException { | |
| 1851 | + if (pos == 0) { | |
| 1852 | + return; | |
| 1853 | + } | |
| 1854 | + if (blkmode) { | |
| 1855 | + writeBlockHeader(pos); | |
| 1856 | + } | |
| 1857 | + out.write(buf, 0, pos); | |
| 1858 | + pos = 0; | |
| 1859 | + } | |
| 1860 | + | |
| 1861 | + /** | |
| 1862 | + * Writes block data header. Data blocks shorter than 256 bytes are | |
| 1863 | + * prefixed with a 2-byte header; all others start with a 5-byte | |
| 1864 | + * header. | |
| 1865 | + */ | |
| 1866 | + private void writeBlockHeader(int len) throws IOException { | |
| 1867 | + if (len <= 0xFF) { | |
| 1868 | + hbuf[0] = TC_BLOCKDATA; | |
| 1869 | + hbuf[1] = (byte) len; | |
| 1870 | + out.write(hbuf, 0, 2); | |
| 1871 | + } else { | |
| 1872 | + hbuf[0] = TC_BLOCKDATALONG; | |
| 1873 | + Bits.putInt(hbuf, 1, len); | |
| 1874 | + out.write(hbuf, 0, 5); | |
| 1875 | + } | |
| 1876 | + } | |
| 1877 | + | |
| 1878 | + | |
| 1879 | + /* ----------------- primitive data output methods ----------------- */ | |
| 1880 | + /* | |
| 1881 | + * The following methods are equivalent to their counterparts in | |
| 1882 | + * DataOutputStream, except that they partition written data into data | |
| 1883 | + * blocks when in block data mode. | |
| 1884 | + */ | |
| 1885 | + | |
| 1886 | + public void writeBoolean(boolean v) throws IOException { | |
| 1887 | + if (pos >= MAX_BLOCK_SIZE) { | |
| 1888 | + drain(); | |
| 1889 | + } | |
| 1890 | + Bits.putBoolean(buf, pos++, v); | |
| 1891 | + } | |
| 1892 | + | |
| 1893 | + public void writeByte(int v) throws IOException { | |
| 1894 | + if (pos >= MAX_BLOCK_SIZE) { | |
| 1895 | + drain(); | |
| 1896 | + } | |
| 1897 | + buf[pos++] = (byte) v; | |
| 1898 | + } | |
| 1899 | + | |
| 1900 | + public void writeChar(int v) throws IOException { | |
| 1901 | + if (pos + 2 <= MAX_BLOCK_SIZE) { | |
| 1902 | + Bits.putChar(buf, pos, (char) v); | |
| 1903 | + pos += 2; | |
| 1904 | + } else { | |
| 1905 | + dout.writeChar(v); | |
| 1906 | + } | |
| 1907 | + } | |
| 1908 | + | |
| 1909 | + public void writeShort(int v) throws IOException { | |
| 1910 | + if (pos + 2 <= MAX_BLOCK_SIZE) { | |
| 1911 | + Bits.putShort(buf, pos, (short) v); | |
| 1912 | + pos += 2; | |
| 1913 | + } else { | |
| 1914 | + dout.writeShort(v); | |
| 1915 | + } | |
| 1916 | + } | |
| 1917 | + | |
| 1918 | + public void writeInt(int v) throws IOException { | |
| 1919 | + if (pos + 4 <= MAX_BLOCK_SIZE) { | |
| 1920 | + Bits.putInt(buf, pos, v); | |
| 1921 | + pos += 4; | |
| 1922 | + } else { | |
| 1923 | + dout.writeInt(v); | |
| 1924 | + } | |
| 1925 | + } | |
| 1926 | + | |
| 1927 | + public void writeFloat(float v) throws IOException { | |
| 1928 | + if (pos + 4 <= MAX_BLOCK_SIZE) { | |
| 1929 | + Bits.putFloat(buf, pos, v); | |
| 1930 | + pos += 4; | |
| 1931 | + } else { | |
| 1932 | + dout.writeFloat(v); | |
| 1933 | + } | |
| 1934 | + } | |
| 1935 | + | |
| 1936 | + public void writeLong(long v) throws IOException { | |
| 1937 | + if (pos + 8 <= MAX_BLOCK_SIZE) { | |
| 1938 | + Bits.putLong(buf, pos, v); | |
| 1939 | + pos += 8; | |
| 1940 | + } else { | |
| 1941 | + dout.writeLong(v); | |
| 1942 | + } | |
| 1943 | + } | |
| 1944 | + | |
| 1945 | + public void writeDouble(double v) throws IOException { | |
| 1946 | + if (pos + 8 <= MAX_BLOCK_SIZE) { | |
| 1947 | + Bits.putDouble(buf, pos, v); | |
| 1948 | + pos += 8; | |
| 1949 | + } else { | |
| 1950 | + dout.writeDouble(v); | |
| 1951 | + } | |
| 1952 | + } | |
| 1953 | + | |
| 1954 | + public void writeBytes(String s) throws IOException { | |
| 1955 | + int endoff = s.length(); | |
| 1956 | + int cpos = 0; | |
| 1957 | + int csize = 0; | |
| 1958 | + for (int off = 0; off < endoff; ) { | |
| 1959 | + if (cpos >= csize) { | |
| 1960 | + cpos = 0; | |
| 1961 | + csize = Math.min(endoff - off, CHAR_BUF_SIZE); | |
| 1962 | + s.getChars(off, off + csize, cbuf, 0); | |
| 1963 | + } | |
| 1964 | + if (pos >= MAX_BLOCK_SIZE) { | |
| 1965 | + drain(); | |
| 1966 | + } | |
| 1967 | + int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos); | |
| 1968 | + int stop = pos + n; | |
| 1969 | + while (pos < stop) { | |
| 1970 | + buf[pos++] = (byte) cbuf[cpos++]; | |
| 1971 | + } | |
| 1972 | + off += n; | |
| 1973 | + } | |
| 1974 | + } | |
| 1975 | + | |
| 1976 | + public void writeChars(String s) throws IOException { | |
| 1977 | + int endoff = s.length(); | |
| 1978 | + for (int off = 0; off < endoff; ) { | |
| 1979 | + int csize = Math.min(endoff - off, CHAR_BUF_SIZE); | |
| 1980 | + s.getChars(off, off + csize, cbuf, 0); | |
| 1981 | + writeChars(cbuf, 0, csize); | |
| 1982 | + off += csize; | |
| 1983 | + } | |
| 1984 | + } | |
| 1985 | + | |
| 1986 | + public void writeUTF(String s) throws IOException { | |
| 1987 | + writeUTF(s, getUTFLength(s)); | |
| 1988 | + } | |
| 1989 | + | |
| 1990 | + | |
| 1991 | + /* -------------- primitive data array output methods -------------- */ | |
| 1992 | + /* | |
| 1993 | + * The following methods write out spans of primitive data values. | |
| 1994 | + * Though equivalent to calling the corresponding primitive write | |
| 1995 | + * methods repeatedly, these methods are optimized for writing groups | |
| 1996 | + * of primitive data values more efficiently. | |
| 1997 | + */ | |
| 1998 | + | |
| 1999 | + void writeBooleans(boolean[] v, int off, int len) throws IOException { | |
| 2000 | + int endoff = off + len; | |
| 2001 | + while (off < endoff) { | |
| 2002 | + if (pos >= MAX_BLOCK_SIZE) { | |
| 2003 | + drain(); | |
| 2004 | + } | |
| 2005 | + int stop = Math.min(endoff, off + (MAX_BLOCK_SIZE - pos)); | |
| 2006 | + while (off < stop) { | |
| 2007 | + Bits.putBoolean(buf, pos++, v[off++]); | |
| 2008 | + } | |
| 2009 | + } | |
| 2010 | + } | |
| 2011 | + | |
| 2012 | + void writeChars(char[] v, int off, int len) throws IOException { | |
| 2013 | + int limit = MAX_BLOCK_SIZE - 2; | |
| 2014 | + int endoff = off + len; | |
| 2015 | + while (off < endoff) { | |
| 2016 | + if (pos <= limit) { | |
| 2017 | + int avail = (MAX_BLOCK_SIZE - pos) >> 1; | |
| 2018 | + int stop = Math.min(endoff, off + avail); | |
| 2019 | + while (off < stop) { | |
| 2020 | + Bits.putChar(buf, pos, v[off++]); | |
| 2021 | + pos += 2; | |
| 2022 | + } | |
| 2023 | + } else { | |
| 2024 | + dout.writeChar(v[off++]); | |
| 2025 | + } | |
| 2026 | + } | |
| 2027 | + } | |
| 2028 | + | |
| 2029 | + void writeShorts(short[] v, int off, int len) throws IOException { | |
| 2030 | + int limit = MAX_BLOCK_SIZE - 2; | |
| 2031 | + int endoff = off + len; | |
| 2032 | + while (off < endoff) { | |
| 2033 | + if (pos <= limit) { | |
| 2034 | + int avail = (MAX_BLOCK_SIZE - pos) >> 1; | |
| 2035 | + int stop = Math.min(endoff, off + avail); | |
| 2036 | + while (off < stop) { | |
| 2037 | + Bits.putShort(buf, pos, v[off++]); | |
| 2038 | + pos += 2; | |
| 2039 | + } | |
| 2040 | + } else { | |
| 2041 | + dout.writeShort(v[off++]); | |
| 2042 | + } | |
| 2043 | + } | |
| 2044 | + } | |
| 2045 | + | |
| 2046 | + void writeInts(int[] v, int off, int len) throws IOException { | |
| 2047 | + int limit = MAX_BLOCK_SIZE - 4; | |
| 2048 | + int endoff = off + len; | |
| 2049 | + while (off < endoff) { | |
| 2050 | + if (pos <= limit) { | |
| 2051 | + int avail = (MAX_BLOCK_SIZE - pos) >> 2; | |
| 2052 | + int stop = Math.min(endoff, off + avail); | |
| 2053 | + while (off < stop) { | |
| 2054 | + Bits.putInt(buf, pos, v[off++]); | |
| 2055 | + pos += 4; | |
| 2056 | + } | |
| 2057 | + } else { | |
| 2058 | + dout.writeInt(v[off++]); | |
| 2059 | + } | |
| 2060 | + } | |
| 2061 | + } | |
| 2062 | + | |
| 2063 | + void writeFloats(float[] v, int off, int len) throws IOException { | |
| 2064 | + int limit = MAX_BLOCK_SIZE - 4; | |
| 2065 | + int endoff = off + len; | |
| 2066 | + while (off < endoff) { | |
| 2067 | + if (pos <= limit) { | |
| 2068 | + int avail = (MAX_BLOCK_SIZE - pos) >> 2; | |
| 2069 | + int chunklen = Math.min(endoff - off, avail); | |
| 2070 | + floatsToBytes(v, off, buf, pos, chunklen); | |
| 2071 | + off += chunklen; | |
| 2072 | + pos += chunklen << 2; | |
| 2073 | + } else { | |
| 2074 | + dout.writeFloat(v[off++]); | |
| 2075 | + } | |
| 2076 | + } | |
| 2077 | + } | |
| 2078 | + | |
| 2079 | + void writeLongs(long[] v, int off, int len) throws IOException { | |
| 2080 | + int limit = MAX_BLOCK_SIZE - 8; | |
| 2081 | + int endoff = off + len; | |
| 2082 | + while (off < endoff) { | |
| 2083 | + if (pos <= limit) { | |
| 2084 | + int avail = (MAX_BLOCK_SIZE - pos) >> 3; | |
| 2085 | + int stop = Math.min(endoff, off + avail); | |
| 2086 | + while (off < stop) { | |
| 2087 | + Bits.putLong(buf, pos, v[off++]); | |
| 2088 | + pos += 8; | |
| 2089 | + } | |
| 2090 | + } else { | |
| 2091 | + dout.writeLong(v[off++]); | |
| 2092 | + } | |
| 2093 | + } | |
| 2094 | + } | |
| 2095 | + | |
| 2096 | + void writeDoubles(double[] v, int off, int len) throws IOException { | |
| 2097 | + int limit = MAX_BLOCK_SIZE - 8; | |
| 2098 | + int endoff = off + len; | |
| 2099 | + while (off < endoff) { | |
| 2100 | + if (pos <= limit) { | |
| 2101 | + int avail = (MAX_BLOCK_SIZE - pos) >> 3; | |
| 2102 | + int chunklen = Math.min(endoff - off, avail); | |
| 2103 | + doublesToBytes(v, off, buf, pos, chunklen); | |
| 2104 | + off += chunklen; | |
| 2105 | + pos += chunklen << 3; | |
| 2106 | + } else { | |
| 2107 | + dout.writeDouble(v[off++]); | |
| 2108 | + } | |
| 2109 | + } | |
| 2110 | + } | |
| 2111 | + | |
| 2112 | + /** | |
| 2113 | + * Returns the length in bytes of the UTF encoding of the given string. | |
| 2114 | + */ | |
| 2115 | + long getUTFLength(String s) { | |
| 2116 | + int len = s.length(); | |
| 2117 | + long utflen = 0; | |
| 2118 | + for (int off = 0; off < len; ) { | |
| 2119 | + int csize = Math.min(len - off, CHAR_BUF_SIZE); | |
| 2120 | + s.getChars(off, off + csize, cbuf, 0); | |
| 2121 | + for (int cpos = 0; cpos < csize; cpos++) { | |
| 2122 | + char c = cbuf[cpos]; | |
| 2123 | + if (c >= 0x0001 && c <= 0x007F) { | |
| 2124 | + utflen++; | |
| 2125 | + } else if (c > 0x07FF) { | |
| 2126 | + utflen += 3; | |
| 2127 | + } else { | |
| 2128 | + utflen += 2; | |
| 2129 | + } | |
| 2130 | + } | |
| 2131 | + off += csize; | |
| 2132 | + } | |
| 2133 | + return utflen; | |
| 2134 | + } | |
| 2135 | + | |
| 2136 | + /** | |
| 2137 | + * Writes the given string in UTF format. This method is used in | |
| 2138 | + * situations where the UTF encoding length of the string is already | |
| 2139 | + * known; specifying it explicitly avoids a prescan of the string to | |
| 2140 | + * determine its UTF length. | |
| 2141 | + */ | |
| 2142 | + void writeUTF(String s, long utflen) throws IOException { | |
| 2143 | + if (utflen > 0xFFFFL) { | |
| 2144 | + throw new UTFDataFormatException(); | |
| 2145 | + } | |
| 2146 | + writeShort((int) utflen); | |
| 2147 | + if (utflen == (long) s.length()) { | |
| 2148 | + writeBytes(s); | |
| 2149 | + } else { | |
| 2150 | + writeUTFBody(s); | |
| 2151 | + } | |
| 2152 | + } | |
| 2153 | + | |
| 2154 | + /** | |
| 2155 | + * Writes given string in "long" UTF format. "Long" UTF format is | |
| 2156 | + * identical to standard UTF, except that it uses an 8 byte header | |
| 2157 | + * (instead of the standard 2 bytes) to convey the UTF encoding length. | |
| 2158 | + */ | |
| 2159 | + void writeLongUTF(String s) throws IOException { | |
| 2160 | + writeLongUTF(s, getUTFLength(s)); | |
| 2161 | + } | |
| 2162 | + | |
| 2163 | + /** | |
| 2164 | + * Writes given string in "long" UTF format, where the UTF encoding | |
| 2165 | + * length of the string is already known. | |
| 2166 | + */ | |
| 2167 | + void writeLongUTF(String s, long utflen) throws IOException { | |
| 2168 | + writeLong(utflen); | |
| 2169 | + if (utflen == (long) s.length()) { | |
| 2170 | + writeBytes(s); | |
| 2171 | + } else { | |
| 2172 | + writeUTFBody(s); | |
| 2173 | + } | |
| 2174 | + } | |
| 2175 | + | |
| 2176 | + /** | |
| 2177 | + * Writes the "body" (i.e., the UTF representation minus the 2-byte or | |
| 2178 | + * 8-byte length header) of the UTF encoding for the given string. | |
| 2179 | + */ | |
| 2180 | + private void writeUTFBody(String s) throws IOException { | |
| 2181 | + int limit = MAX_BLOCK_SIZE - 3; | |
| 2182 | + int len = s.length(); | |
| 2183 | + for (int off = 0; off < len; ) { | |
| 2184 | + int csize = Math.min(len - off, CHAR_BUF_SIZE); | |
| 2185 | + s.getChars(off, off + csize, cbuf, 0); | |
| 2186 | + for (int cpos = 0; cpos < csize; cpos++) { | |
| 2187 | + char c = cbuf[cpos]; | |
| 2188 | + if (pos <= limit) { | |
| 2189 | + if (c <= 0x007F && c != 0) { | |
| 2190 | + buf[pos++] = (byte) c; | |
| 2191 | + } else if (c > 0x07FF) { | |
| 2192 | + buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F)); | |
| 2193 | + buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F)); | |
| 2194 | + buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F)); | |
| 2195 | + pos += 3; | |
| 2196 | + } else { | |
| 2197 | + buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F)); | |
| 2198 | + buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F)); | |
| 2199 | + pos += 2; | |
| 2200 | + } | |
| 2201 | + } else { // write one byte at a time to normalize block | |
| 2202 | + if (c <= 0x007F && c != 0) { | |
| 2203 | + write(c); | |
| 2204 | + } else if (c > 0x07FF) { | |
| 2205 | + write(0xE0 | ((c >> 12) & 0x0F)); | |
| 2206 | + write(0x80 | ((c >> 6) & 0x3F)); | |
| 2207 | + write(0x80 | ((c >> 0) & 0x3F)); | |
| 2208 | + } else { | |
| 2209 | + write(0xC0 | ((c >> 6) & 0x1F)); | |
| 2210 | + write(0x80 | ((c >> 0) & 0x3F)); | |
| 2211 | + } | |
| 2212 | + } | |
| 2213 | + } | |
| 2214 | + off += csize; | |
| 2215 | + } | |
| 2216 | + } | |
| 2217 | + } | |
| 2218 | + | |
| 2219 | + /** | |
| 2220 | + * Lightweight identity hash table which maps objects to integer handles, | |
| 2221 | + * assigned in ascending order. | |
| 2222 | + */ | |
| 2223 | + private static class HandleTable { | |
| 2224 | + | |
| 2225 | + /* number of mappings in table/next available handle */ | |
| 2226 | + private int size; | |
| 2227 | + /* size threshold determining when to expand hash spine */ | |
| 2228 | + private int threshold; | |
| 2229 | + /* factor for computing size threshold */ | |
| 2230 | + private final float loadFactor; | |
| 2231 | + /* maps hash value -> candidate handle value */ | |
| 2232 | + private int[] spine; | |
| 2233 | + /* maps handle value -> next candidate handle value */ | |
| 2234 | + private int[] next; | |
| 2235 | + /* maps handle value -> associated object */ | |
| 2236 | + private Object[] objs; | |
| 2237 | + | |
| 2238 | + /** | |
| 2239 | + * Creates new HandleTable with given capacity and load factor. | |
| 2240 | + */ | |
| 2241 | + HandleTable(int initialCapacity, float loadFactor) { | |
| 2242 | + this.loadFactor = loadFactor; | |
| 2243 | + spine = new int[initialCapacity]; | |
| 2244 | + next = new int[initialCapacity]; | |
| 2245 | + objs = new Object[initialCapacity]; | |
| 2246 | + threshold = (int) (initialCapacity * loadFactor); | |
| 2247 | + clear(); | |
| 2248 | + } | |
| 2249 | + | |
| 2250 | + /** | |
| 2251 | + * Assigns next available handle to given object, and returns handle | |
| 2252 | + * value. Handles are assigned in ascending order starting at 0. | |
| 2253 | + */ | |
| 2254 | + int assign(Object obj) { | |
| 2255 | + if (size >= next.length) { | |
| 2256 | + growEntries(); | |
| 2257 | + } | |
| 2258 | + if (size >= threshold) { | |
| 2259 | + growSpine(); | |
| 2260 | + } | |
| 2261 | + insert(obj, size); | |
| 2262 | + return size++; | |
| 2263 | + } | |
| 2264 | + | |
| 2265 | + /** | |
| 2266 | + * Looks up and returns handle associated with given object, or -1 if | |
| 2267 | + * no mapping found. | |
| 2268 | + */ | |
| 2269 | + int lookup(Object obj) { | |
| 2270 | + if (size == 0) { | |
| 2271 | + return -1; | |
| 2272 | + } | |
| 2273 | + int index = hash(obj) % spine.length; | |
| 2274 | + for (int i = spine[index]; i >= 0; i = next[i]) { | |
| 2275 | + if (objs[i] == obj) { | |
| 2276 | + return i; | |
| 2277 | + } | |
| 2278 | + } | |
| 2279 | + return -1; | |
| 2280 | + } | |
| 2281 | + | |
| 2282 | + /** | |
| 2283 | + * Resets table to its initial (empty) state. | |
| 2284 | + */ | |
| 2285 | + void clear() { | |
| 2286 | + Arrays.fill(spine, -1); | |
| 2287 | + Arrays.fill(objs, 0, size, null); | |
| 2288 | + size = 0; | |
| 2289 | + } | |
| 2290 | + | |
| 2291 | + /** | |
| 2292 | + * Returns the number of mappings currently in table. | |
| 2293 | + */ | |
| 2294 | + int size() { | |
| 2295 | + return size; | |
| 2296 | + } | |
| 2297 | + | |
| 2298 | + /** | |
| 2299 | + * Inserts mapping object -> handle mapping into table. Assumes table | |
| 2300 | + * is large enough to accommodate new mapping. | |
| 2301 | + */ | |
| 2302 | + private void insert(Object obj, int handle) { | |
| 2303 | + int index = hash(obj) % spine.length; | |
| 2304 | + objs[handle] = obj; | |
| 2305 | + next[handle] = spine[index]; | |
| 2306 | + spine[index] = handle; | |
| 2307 | + } | |
| 2308 | + | |
| 2309 | + /** | |
| 2310 | + * Expands the hash "spine" -- equivalent to increasing the number of | |
| 2311 | + * buckets in a conventional hash table. | |
| 2312 | + */ | |
| 2313 | + private void growSpine() { | |
| 2314 | + spine = new int[(spine.length << 1) + 1]; | |
| 2315 | + threshold = (int) (spine.length * loadFactor); | |
| 2316 | + Arrays.fill(spine, -1); | |
| 2317 | + for (int i = 0; i < size; i++) { | |
| 2318 | + insert(objs[i], i); | |
| 2319 | + } | |
| 2320 | + } | |
| 2321 | + | |
| 2322 | + /** | |
| 2323 | + * Increases hash table capacity by lengthening entry arrays. | |
| 2324 | + */ | |
| 2325 | + private void growEntries() { | |
| 2326 | + int newLength = (next.length << 1) + 1; | |
| 2327 | + int[] newNext = new int[newLength]; | |
| 2328 | + System.arraycopy(next, 0, newNext, 0, size); | |
| 2329 | + next = newNext; | |
| 2330 | + | |
| 2331 | + Object[] newObjs = new Object[newLength]; | |
| 2332 | + System.arraycopy(objs, 0, newObjs, 0, size); | |
| 2333 | + objs = newObjs; | |
| 2334 | + } | |
| 2335 | + | |
| 2336 | + /** | |
| 2337 | + * Returns hash value for given object. | |
| 2338 | + */ | |
| 2339 | + private int hash(Object obj) { | |
| 2340 | + return System.identityHashCode(obj) & 0x7FFFFFFF; | |
| 2341 | + } | |
| 2342 | + } | |
| 2343 | + | |
| 2344 | + /** | |
| 2345 | + * Lightweight identity hash table which maps objects to replacement | |
| 2346 | + * objects. | |
| 2347 | + */ | |
| 2348 | + private static class ReplaceTable { | |
| 2349 | + | |
| 2350 | + /* maps object -> index */ | |
| 2351 | + private final HandleTable htab; | |
| 2352 | + /* maps index -> replacement object */ | |
| 2353 | + private Object[] reps; | |
| 2354 | + | |
| 2355 | + /** | |
| 2356 | + * Creates new ReplaceTable with given capacity and load factor. | |
| 2357 | + */ | |
| 2358 | + ReplaceTable(int initialCapacity, float loadFactor) { | |
| 2359 | + htab = new HandleTable(initialCapacity, loadFactor); | |
| 2360 | + reps = new Object[initialCapacity]; | |
| 2361 | + } | |
| 2362 | + | |
| 2363 | + /** | |
| 2364 | + * Enters mapping from object to replacement object. | |
| 2365 | + */ | |
| 2366 | + void assign(Object obj, Object rep) { | |
| 2367 | + int index = htab.assign(obj); | |
| 2368 | + while (index >= reps.length) { | |
| 2369 | + grow(); | |
| 2370 | + } | |
| 2371 | + reps[index] = rep; | |
| 2372 | + } | |
| 2373 | + | |
| 2374 | + /** | |
| 2375 | + * Looks up and returns replacement for given object. If no | |
| 2376 | + * replacement is found, returns the lookup object itself. | |
| 2377 | + */ | |
| 2378 | + Object lookup(Object obj) { | |
| 2379 | + int index = htab.lookup(obj); | |
| 2380 | + return (index >= 0) ? reps[index] : obj; | |
| 2381 | + } | |
| 2382 | + | |
| 2383 | + /** | |
| 2384 | + * Resets table to its initial (empty) state. | |
| 2385 | + */ | |
| 2386 | + void clear() { | |
| 2387 | + Arrays.fill(reps, 0, htab.size(), null); | |
| 2388 | + htab.clear(); | |
| 2389 | + } | |
| 2390 | + | |
| 2391 | + /** | |
| 2392 | + * Returns the number of mappings currently in table. | |
| 2393 | + */ | |
| 2394 | + int size() { | |
| 2395 | + return htab.size(); | |
| 2396 | + } | |
| 2397 | + | |
| 2398 | + /** | |
| 2399 | + * Increases table capacity. | |
| 2400 | + */ | |
| 2401 | + private void grow() { | |
| 2402 | + Object[] newReps = new Object[(reps.length << 1) + 1]; | |
| 2403 | + System.arraycopy(reps, 0, newReps, 0, reps.length); | |
| 2404 | + reps = newReps; | |
| 2405 | + } | |
| 2406 | + } | |
| 2407 | + | |
| 2408 | + /** | |
| 2409 | + * Stack to keep debug information about the state of the | |
| 2410 | + * serialization process, for embedding in exception messages. | |
| 2411 | + */ | |
| 2412 | + private static class DebugTraceInfoStack { | |
| 2413 | + private final List<String> stack; | |
| 2414 | + | |
| 2415 | + DebugTraceInfoStack() { | |
| 2416 | + stack = new ArrayList<>(); | |
| 2417 | + } | |
| 2418 | + | |
| 2419 | + /** | |
| 2420 | + * Removes all of the elements from enclosed list. | |
| 2421 | + */ | |
| 2422 | + void clear() { | |
| 2423 | + stack.clear(); | |
| 2424 | + } | |
| 2425 | + | |
| 2426 | + /** | |
| 2427 | + * Removes the object at the top of enclosed list. | |
| 2428 | + */ | |
| 2429 | + void pop() { | |
| 2430 | + stack.remove(stack.size()-1); | |
| 2431 | + } | |
| 2432 | + | |
| 2433 | + /** | |
| 2434 | + * Pushes a String onto the top of enclosed list. | |
| 2435 | + */ | |
| 2436 | + void push(String entry) { | |
| 2437 | + stack.add("\t- " + entry); | |
| 2438 | + } | |
| 2439 | + | |
| 2440 | + /** | |
| 2441 | + * Returns a string representation of this object | |
| 2442 | + */ | |
| 2443 | + public String toString() { | |
| 2444 | + StringBuilder buffer = new StringBuilder(); | |
| 2445 | + if (!stack.isEmpty()) { | |
| 2446 | + for(int i = stack.size(); i > 0; i-- ) { | |
| 2447 | + buffer.append(stack.get(i-1) + ((i != 1) ? "\n" : "")); | |
| 2448 | + } | |
| 2449 | + } | |
| 2450 | + return buffer.toString(); | |
| 2451 | + } | |
| 2452 | + } | |
| 2453 | + | |
| 2454 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,2304 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. | |
| 3 | + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| 4 | + * | |
| 5 | + * This code is free software; you can redistribute it and/or modify it | |
| 6 | + * under the terms of the GNU General Public License version 2 only, as | |
| 7 | + * published by the Free Software Foundation. Oracle designates this | |
| 8 | + * particular file as subject to the "Classpath" exception as provided | |
| 9 | + * by Oracle in the LICENSE file that accompanied this code. | |
| 10 | + * | |
| 11 | + * This code is distributed in the hope that it will be useful, but WITHOUT | |
| 12 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 | + * version 2 for more details (a copy is included in the LICENSE file that | |
| 15 | + * accompanied this code). | |
| 16 | + * | |
| 17 | + * You should have received a copy of the GNU General Public License version | |
| 18 | + * 2 along with this work; if not, write to the Free Software Foundation, | |
| 19 | + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 20 | + * | |
| 21 | + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| 22 | + * or visit www.oracle.com if you need additional information or have any | |
| 23 | + * questions. | |
| 24 | + */ | |
| 25 | + | |
| 26 | +package java.io; | |
| 27 | + | |
| 28 | +import java.lang.ref.Reference; | |
| 29 | +import java.lang.ref.ReferenceQueue; | |
| 30 | +import java.lang.ref.SoftReference; | |
| 31 | +import java.lang.ref.WeakReference; | |
| 32 | +import java.lang.reflect.Constructor; | |
| 33 | +import java.lang.reflect.Field; | |
| 34 | +import java.lang.reflect.InvocationTargetException; | |
| 35 | +import java.lang.reflect.Member; | |
| 36 | +import java.lang.reflect.Method; | |
| 37 | +import java.lang.reflect.Modifier; | |
| 38 | +import java.lang.reflect.Proxy; | |
| 39 | +import java.security.AccessController; | |
| 40 | +import java.security.MessageDigest; | |
| 41 | +import java.security.NoSuchAlgorithmException; | |
| 42 | +import java.security.PrivilegedAction; | |
| 43 | +import java.util.ArrayList; | |
| 44 | +import java.util.Arrays; | |
| 45 | +import java.util.Collections; | |
| 46 | +import java.util.Comparator; | |
| 47 | +import java.util.HashSet; | |
| 48 | +import java.util.Set; | |
| 49 | +import java.util.concurrent.ConcurrentHashMap; | |
| 50 | +import java.util.concurrent.ConcurrentMap; | |
| 51 | +import sun.misc.Unsafe; | |
| 52 | +import sun.reflect.ReflectionFactory; | |
| 53 | + | |
| 54 | +/** | |
| 55 | + * Serialization's descriptor for classes. It contains the name and | |
| 56 | + * serialVersionUID of the class. The ObjectStreamClass for a specific class | |
| 57 | + * loaded in this Java VM can be found/created using the lookup method. | |
| 58 | + * | |
| 59 | + * <p>The algorithm to compute the SerialVersionUID is described in | |
| 60 | + * <a href="../../../platform/serialization/spec/class.html#4100">Object | |
| 61 | + * Serialization Specification, Section 4.6, Stream Unique Identifiers</a>. | |
| 62 | + * | |
| 63 | + * @author Mike Warres | |
| 64 | + * @author Roger Riggs | |
| 65 | + * @see ObjectStreamField | |
| 66 | + * @see <a href="../../../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a> | |
| 67 | + * @since JDK1.1 | |
| 68 | + */ | |
| 69 | +public class ObjectStreamClass implements Serializable { | |
| 70 | + | |
| 71 | + /** serialPersistentFields value indicating no serializable fields */ | |
| 72 | + public static final ObjectStreamField[] NO_FIELDS = | |
| 73 | + new ObjectStreamField[0]; | |
| 74 | + | |
| 75 | + private static final long serialVersionUID = -6120832682080437368L; | |
| 76 | + private static final ObjectStreamField[] serialPersistentFields = | |
| 77 | + NO_FIELDS; | |
| 78 | + | |
| 79 | + /** reflection factory for obtaining serialization constructors */ | |
| 80 | + private static final ReflectionFactory reflFactory = | |
| 81 | + AccessController.doPrivileged( | |
| 82 | + new ReflectionFactory.GetReflectionFactoryAction()); | |
| 83 | + | |
| 84 | + private static class Caches { | |
| 85 | + /** cache mapping local classes -> descriptors */ | |
| 86 | + static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs = | |
| 87 | + new ConcurrentHashMap<>(); | |
| 88 | + | |
| 89 | + /** cache mapping field group/local desc pairs -> field reflectors */ | |
| 90 | + static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors = | |
| 91 | + new ConcurrentHashMap<>(); | |
| 92 | + | |
| 93 | + /** queue for WeakReferences to local classes */ | |
| 94 | + private static final ReferenceQueue<Class<?>> localDescsQueue = | |
| 95 | + new ReferenceQueue<>(); | |
| 96 | + /** queue for WeakReferences to field reflectors keys */ | |
| 97 | + private static final ReferenceQueue<Class<?>> reflectorsQueue = | |
| 98 | + new ReferenceQueue<>(); | |
| 99 | + } | |
| 100 | + | |
| 101 | + /** class associated with this descriptor (if any) */ | |
| 102 | + private Class<?> cl; | |
| 103 | + /** name of class represented by this descriptor */ | |
| 104 | + private String name; | |
| 105 | + /** serialVersionUID of represented class (null if not computed yet) */ | |
| 106 | + private volatile Long suid; | |
| 107 | + | |
| 108 | + /** true if represents dynamic proxy class */ | |
| 109 | + private boolean isProxy; | |
| 110 | + /** true if represents enum type */ | |
| 111 | + private boolean isEnum; | |
| 112 | + /** true if represented class implements Serializable */ | |
| 113 | + private boolean serializable; | |
| 114 | + /** true if represented class implements Externalizable */ | |
| 115 | + private boolean externalizable; | |
| 116 | + /** true if desc has data written by class-defined writeObject method */ | |
| 117 | + private boolean hasWriteObjectData; | |
| 118 | + /** | |
| 119 | + * true if desc has externalizable data written in block data format; this | |
| 120 | + * must be true by default to accommodate ObjectInputStream subclasses which | |
| 121 | + * override readClassDescriptor() to return class descriptors obtained from | |
| 122 | + * ObjectStreamClass.lookup() (see 4461737) | |
| 123 | + */ | |
| 124 | + private boolean hasBlockExternalData = true; | |
| 125 | + | |
| 126 | + /** exception (if any) thrown while attempting to resolve class */ | |
| 127 | + private ClassNotFoundException resolveEx; | |
| 128 | + /** exception (if any) to throw if non-enum deserialization attempted */ | |
| 129 | + private InvalidClassException deserializeEx; | |
| 130 | + /** exception (if any) to throw if non-enum serialization attempted */ | |
| 131 | + private InvalidClassException serializeEx; | |
| 132 | + /** exception (if any) to throw if default serialization attempted */ | |
| 133 | + private InvalidClassException defaultSerializeEx; | |
| 134 | + | |
| 135 | + /** serializable fields */ | |
| 136 | + private ObjectStreamField[] fields; | |
| 137 | + /** aggregate marshalled size of primitive fields */ | |
| 138 | + private int primDataSize; | |
| 139 | + /** number of non-primitive fields */ | |
| 140 | + private int numObjFields; | |
| 141 | + /** reflector for setting/getting serializable field values */ | |
| 142 | + private FieldReflector fieldRefl; | |
| 143 | + /** data layout of serialized objects described by this class desc */ | |
| 144 | + private volatile ClassDataSlot[] dataLayout; | |
| 145 | + | |
| 146 | + /** serialization-appropriate constructor, or null if none */ | |
| 147 | + private Constructor cons; | |
| 148 | + /** class-defined writeObject method, or null if none */ | |
| 149 | + private Method writeObjectMethod; | |
| 150 | + /** class-defined readObject method, or null if none */ | |
| 151 | + private Method readObjectMethod; | |
| 152 | + /** class-defined readObjectNoData method, or null if none */ | |
| 153 | + private Method readObjectNoDataMethod; | |
| 154 | + /** class-defined writeReplace method, or null if none */ | |
| 155 | + private Method writeReplaceMethod; | |
| 156 | + /** class-defined readResolve method, or null if none */ | |
| 157 | + private Method readResolveMethod; | |
| 158 | + | |
| 159 | + /** local class descriptor for represented class (may point to self) */ | |
| 160 | + private ObjectStreamClass localDesc; | |
| 161 | + /** superclass descriptor appearing in stream */ | |
| 162 | + private ObjectStreamClass superDesc; | |
| 163 | + | |
| 164 | + /** | |
| 165 | + * Initializes native code. | |
| 166 | + */ | |
| 167 | + private static native void initNative(); | |
| 168 | + static { | |
| 169 | + initNative(); | |
| 170 | + } | |
| 171 | + | |
| 172 | + /** | |
| 173 | + * Find the descriptor for a class that can be serialized. Creates an | |
| 174 | + * ObjectStreamClass instance if one does not exist yet for class. Null is | |
| 175 | + * returned if the specified class does not implement java.io.Serializable | |
| 176 | + * or java.io.Externalizable. | |
| 177 | + * | |
| 178 | + * @param cl class for which to get the descriptor | |
| 179 | + * @return the class descriptor for the specified class | |
| 180 | + */ | |
| 181 | + public static ObjectStreamClass lookup(Class<?> cl) { | |
| 182 | + return lookup(cl, false); | |
| 183 | + } | |
| 184 | + | |
| 185 | + /** | |
| 186 | + * Returns the descriptor for any class, regardless of whether it | |
| 187 | + * implements {@link Serializable}. | |
| 188 | + * | |
| 189 | + * @param cl class for which to get the descriptor | |
| 190 | + * @return the class descriptor for the specified class | |
| 191 | + * @since 1.6 | |
| 192 | + */ | |
| 193 | + public static ObjectStreamClass lookupAny(Class<?> cl) { | |
| 194 | + return lookup(cl, true); | |
| 195 | + } | |
| 196 | + | |
| 197 | + /** | |
| 198 | + * Returns the name of the class described by this descriptor. | |
| 199 | + * This method returns the name of the class in the format that | |
| 200 | + * is used by the {@link Class#getName} method. | |
| 201 | + * | |
| 202 | + * @return a string representing the name of the class | |
| 203 | + */ | |
| 204 | + public String getName() { | |
| 205 | + return name; | |
| 206 | + } | |
| 207 | + | |
| 208 | + /** | |
| 209 | + * Return the serialVersionUID for this class. The serialVersionUID | |
| 210 | + * defines a set of classes all with the same name that have evolved from a | |
| 211 | + * common root class and agree to be serialized and deserialized using a | |
| 212 | + * common format. NonSerializable classes have a serialVersionUID of 0L. | |
| 213 | + * | |
| 214 | + * @return the SUID of the class described by this descriptor | |
| 215 | + */ | |
| 216 | + public long getSerialVersionUID() { | |
| 217 | + // REMIND: synchronize instead of relying on volatile? | |
| 218 | + if (suid == null) { | |
| 219 | + suid = AccessController.doPrivileged( | |
| 220 | + new PrivilegedAction<Long>() { | |
| 221 | + public Long run() { | |
| 222 | + return computeDefaultSUID(cl); | |
| 223 | + } | |
| 224 | + } | |
| 225 | + ); | |
| 226 | + } | |
| 227 | + return suid.longValue(); | |
| 228 | + } | |
| 229 | + | |
| 230 | + /** | |
| 231 | + * Return the class in the local VM that this version is mapped to. Null | |
| 232 | + * is returned if there is no corresponding local class. | |
| 233 | + * | |
| 234 | + * @return the <code>Class</code> instance that this descriptor represents | |
| 235 | + */ | |
| 236 | + public Class<?> forClass() { | |
| 237 | + return cl; | |
| 238 | + } | |
| 239 | + | |
| 240 | + /** | |
| 241 | + * Return an array of the fields of this serializable class. | |
| 242 | + * | |
| 243 | + * @return an array containing an element for each persistent field of | |
| 244 | + * this class. Returns an array of length zero if there are no | |
| 245 | + * fields. | |
| 246 | + * @since 1.2 | |
| 247 | + */ | |
| 248 | + public ObjectStreamField[] getFields() { | |
| 249 | + return getFields(true); | |
| 250 | + } | |
| 251 | + | |
| 252 | + /** | |
| 253 | + * Get the field of this class by name. | |
| 254 | + * | |
| 255 | + * @param name the name of the data field to look for | |
| 256 | + * @return The ObjectStreamField object of the named field or null if | |
| 257 | + * there is no such named field. | |
| 258 | + */ | |
| 259 | + public ObjectStreamField getField(String name) { | |
| 260 | + return getField(name, null); | |
| 261 | + } | |
| 262 | + | |
| 263 | + /** | |
| 264 | + * Return a string describing this ObjectStreamClass. | |
| 265 | + */ | |
| 266 | + public String toString() { | |
| 267 | + return name + ": static final long serialVersionUID = " + | |
| 268 | + getSerialVersionUID() + "L;"; | |
| 269 | + } | |
| 270 | + | |
| 271 | + /** | |
| 272 | + * Looks up and returns class descriptor for given class, or null if class | |
| 273 | + * is non-serializable and "all" is set to false. | |
| 274 | + * | |
| 275 | + * @param cl class to look up | |
| 276 | + * @param all if true, return descriptors for all classes; if false, only | |
| 277 | + * return descriptors for serializable classes | |
| 278 | + */ | |
| 279 | + static ObjectStreamClass lookup(Class<?> cl, boolean all) { | |
| 280 | + if (!(all || Serializable.class.isAssignableFrom(cl))) { | |
| 281 | + return null; | |
| 282 | + } | |
| 283 | + processQueue(Caches.localDescsQueue, Caches.localDescs); | |
| 284 | + WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue); | |
| 285 | + Reference<?> ref = Caches.localDescs.get(key); | |
| 286 | + Object entry = null; | |
| 287 | + if (ref != null) { | |
| 288 | + entry = ref.get(); | |
| 289 | + } | |
| 290 | + EntryFuture future = null; | |
| 291 | + if (entry == null) { | |
| 292 | + EntryFuture newEntry = new EntryFuture(); | |
| 293 | + Reference<?> newRef = new SoftReference<>(newEntry); | |
| 294 | + do { | |
| 295 | + if (ref != null) { | |
| 296 | + Caches.localDescs.remove(key, ref); | |
| 297 | + } | |
| 298 | + ref = Caches.localDescs.putIfAbsent(key, newRef); | |
| 299 | + if (ref != null) { | |
| 300 | + entry = ref.get(); | |
| 301 | + } | |
| 302 | + } while (ref != null && entry == null); | |
| 303 | + if (entry == null) { | |
| 304 | + future = newEntry; | |
| 305 | + } | |
| 306 | + } | |
| 307 | + | |
| 308 | + if (entry instanceof ObjectStreamClass) { // check common case first | |
| 309 | + return (ObjectStreamClass) entry; | |
| 310 | + } | |
| 311 | + if (entry instanceof EntryFuture) { | |
| 312 | + future = (EntryFuture) entry; | |
| 313 | + if (future.getOwner() == Thread.currentThread()) { | |
| 314 | + /* | |
| 315 | + * Handle nested call situation described by 4803747: waiting | |
| 316 | + * for future value to be set by a lookup() call further up the | |
| 317 | + * stack will result in deadlock, so calculate and set the | |
| 318 | + * future value here instead. | |
| 319 | + */ | |
| 320 | + entry = null; | |
| 321 | + } else { | |
| 322 | + entry = future.get(); | |
| 323 | + } | |
| 324 | + } | |
| 325 | + if (entry == null) { | |
| 326 | + try { | |
| 327 | + entry = new ObjectStreamClass(cl); | |
| 328 | + } catch (Throwable th) { | |
| 329 | + entry = th; | |
| 330 | + } | |
| 331 | + if (future.set(entry)) { | |
| 332 | + Caches.localDescs.put(key, new SoftReference<Object>(entry)); | |
| 333 | + } else { | |
| 334 | + // nested lookup call already set future | |
| 335 | + entry = future.get(); | |
| 336 | + } | |
| 337 | + } | |
| 338 | + | |
| 339 | + if (entry instanceof ObjectStreamClass) { | |
| 340 | + return (ObjectStreamClass) entry; | |
| 341 | + } else if (entry instanceof RuntimeException) { | |
| 342 | + throw (RuntimeException) entry; | |
| 343 | + } else if (entry instanceof Error) { | |
| 344 | + throw (Error) entry; | |
| 345 | + } else { | |
| 346 | + throw new InternalError("unexpected entry: " + entry); | |
| 347 | + } | |
| 348 | + } | |
| 349 | + | |
| 350 | + /** | |
| 351 | + * Placeholder used in class descriptor and field reflector lookup tables | |
| 352 | + * for an entry in the process of being initialized. (Internal) callers | |
| 353 | + * which receive an EntryFuture belonging to another thread as the result | |
| 354 | + * of a lookup should call the get() method of the EntryFuture; this will | |
| 355 | + * return the actual entry once it is ready for use and has been set(). To | |
| 356 | + * conserve objects, EntryFutures synchronize on themselves. | |
| 357 | + */ | |
| 358 | + private static class EntryFuture { | |
| 359 | + | |
| 360 | + private static final Object unset = new Object(); | |
| 361 | + private final Thread owner = Thread.currentThread(); | |
| 362 | + private Object entry = unset; | |
| 363 | + | |
| 364 | + /** | |
| 365 | + * Attempts to set the value contained by this EntryFuture. If the | |
| 366 | + * EntryFuture's value has not been set already, then the value is | |
| 367 | + * saved, any callers blocked in the get() method are notified, and | |
| 368 | + * true is returned. If the value has already been set, then no saving | |
| 369 | + * or notification occurs, and false is returned. | |
| 370 | + */ | |
| 371 | + synchronized boolean set(Object entry) { | |
| 372 | + if (this.entry != unset) { | |
| 373 | + return false; | |
| 374 | + } | |
| 375 | + this.entry = entry; | |
| 376 | + notifyAll(); | |
| 377 | + return true; | |
| 378 | + } | |
| 379 | + | |
| 380 | + /** | |
| 381 | + * Returns the value contained by this EntryFuture, blocking if | |
| 382 | + * necessary until a value is set. | |
| 383 | + */ | |
| 384 | + synchronized Object get() { | |
| 385 | + boolean interrupted = false; | |
| 386 | + while (entry == unset) { | |
| 387 | + try { | |
| 388 | + wait(); | |
| 389 | + } catch (InterruptedException ex) { | |
| 390 | + interrupted = true; | |
| 391 | + } | |
| 392 | + } | |
| 393 | + if (interrupted) { | |
| 394 | + AccessController.doPrivileged( | |
| 395 | + new PrivilegedAction<Void>() { | |
| 396 | + public Void run() { | |
| 397 | + Thread.currentThread().interrupt(); | |
| 398 | + return null; | |
| 399 | + } | |
| 400 | + } | |
| 401 | + ); | |
| 402 | + } | |
| 403 | + return entry; | |
| 404 | + } | |
| 405 | + | |
| 406 | + /** | |
| 407 | + * Returns the thread that created this EntryFuture. | |
| 408 | + */ | |
| 409 | + Thread getOwner() { | |
| 410 | + return owner; | |
| 411 | + } | |
| 412 | + } | |
| 413 | + | |
| 414 | + /** | |
| 415 | + * Creates local class descriptor representing given class. | |
| 416 | + */ | |
| 417 | + private ObjectStreamClass(final Class<?> cl) { | |
| 418 | + this.cl = cl; | |
| 419 | + name = cl.getName(); | |
| 420 | + isProxy = Proxy.isProxyClass(cl); | |
| 421 | + isEnum = Enum.class.isAssignableFrom(cl); | |
| 422 | + serializable = Serializable.class.isAssignableFrom(cl); | |
| 423 | + externalizable = Externalizable.class.isAssignableFrom(cl); | |
| 424 | + | |
| 425 | + Class<?> superCl = cl.getSuperclass(); | |
| 426 | + superDesc = (superCl != null) ? lookup(superCl, false) : null; | |
| 427 | + localDesc = this; | |
| 428 | + | |
| 429 | + if (serializable) { | |
| 430 | + AccessController.doPrivileged(new PrivilegedAction<Void>() { | |
| 431 | + public Void run() { | |
| 432 | + if (isEnum) { | |
| 433 | + suid = Long.valueOf(0); | |
| 434 | + fields = NO_FIELDS; | |
| 435 | + return null; | |
| 436 | + } | |
| 437 | + if (cl.isArray()) { | |
| 438 | + fields = NO_FIELDS; | |
| 439 | + return null; | |
| 440 | + } | |
| 441 | + | |
| 442 | + suid = getDeclaredSUID(cl); | |
| 443 | + try { | |
| 444 | + fields = getSerialFields(cl); | |
| 445 | + computeFieldOffsets(); | |
| 446 | + } catch (InvalidClassException e) { | |
| 447 | + serializeEx = deserializeEx = e; | |
| 448 | + fields = NO_FIELDS; | |
| 449 | + } | |
| 450 | + | |
| 451 | + if (externalizable) { | |
| 452 | + cons = getExternalizableConstructor(cl); | |
| 453 | + } else { | |
| 454 | + cons = getSerializableConstructor(cl); | |
| 455 | + writeObjectMethod = getPrivateMethod(cl, "writeObject", | |
| 456 | + new Class<?>[] { ObjectOutputStream.class }, | |
| 457 | + Void.TYPE); | |
| 458 | + readObjectMethod = getPrivateMethod(cl, "readObject", | |
| 459 | + new Class<?>[] { ObjectInputStream.class }, | |
| 460 | + Void.TYPE); | |
| 461 | + readObjectNoDataMethod = getPrivateMethod( | |
| 462 | + cl, "readObjectNoData", null, Void.TYPE); | |
| 463 | + hasWriteObjectData = (writeObjectMethod != null); | |
| 464 | + } | |
| 465 | + writeReplaceMethod = getInheritableMethod( | |
| 466 | + cl, "writeReplace", null, Object.class); | |
| 467 | + readResolveMethod = getInheritableMethod( | |
| 468 | + cl, "readResolve", null, Object.class); | |
| 469 | + return null; | |
| 470 | + } | |
| 471 | + }); | |
| 472 | + } else { | |
| 473 | + suid = Long.valueOf(0); | |
| 474 | + fields = NO_FIELDS; | |
| 475 | + } | |
| 476 | + | |
| 477 | + try { | |
| 478 | + fieldRefl = getReflector(fields, this); | |
| 479 | + } catch (InvalidClassException ex) { | |
| 480 | + // field mismatches impossible when matching local fields vs. self | |
| 481 | + throw new InternalError(); | |
| 482 | + } | |
| 483 | + | |
| 484 | + if (deserializeEx == null) { | |
| 485 | + if (isEnum) { | |
| 486 | + deserializeEx = new InvalidClassException(name, "enum type"); | |
| 487 | + } else if (cons == null) { | |
| 488 | + deserializeEx = new InvalidClassException( | |
| 489 | + name, "no valid constructor"); | |
| 490 | + } | |
| 491 | + } | |
| 492 | + for (int i = 0; i < fields.length; i++) { | |
| 493 | + if (fields[i].getField() == null) { | |
| 494 | + defaultSerializeEx = new InvalidClassException( | |
| 495 | + name, "unmatched serializable field(s) declared"); | |
| 496 | + } | |
| 497 | + } | |
| 498 | + } | |
| 499 | + | |
| 500 | + /** | |
| 501 | + * Creates blank class descriptor which should be initialized via a | |
| 502 | + * subsequent call to initProxy(), initNonProxy() or readNonProxy(). | |
| 503 | + */ | |
| 504 | + ObjectStreamClass() { | |
| 505 | + } | |
| 506 | + | |
| 507 | + /** | |
| 508 | + * Initializes class descriptor representing a proxy class. | |
| 509 | + */ | |
| 510 | + void initProxy(Class<?> cl, | |
| 511 | + ClassNotFoundException resolveEx, | |
| 512 | + ObjectStreamClass superDesc) | |
| 513 | + throws InvalidClassException | |
| 514 | + { | |
| 515 | + this.cl = cl; | |
| 516 | + this.resolveEx = resolveEx; | |
| 517 | + this.superDesc = superDesc; | |
| 518 | + isProxy = true; | |
| 519 | + serializable = true; | |
| 520 | + suid = Long.valueOf(0); | |
| 521 | + fields = NO_FIELDS; | |
| 522 | + | |
| 523 | + if (cl != null) { | |
| 524 | + localDesc = lookup(cl, true); | |
| 525 | + if (!localDesc.isProxy) { | |
| 526 | + throw new InvalidClassException( | |
| 527 | + "cannot bind proxy descriptor to a non-proxy class"); | |
| 528 | + } | |
| 529 | + name = localDesc.name; | |
| 530 | + externalizable = localDesc.externalizable; | |
| 531 | + cons = localDesc.cons; | |
| 532 | + writeReplaceMethod = localDesc.writeReplaceMethod; | |
| 533 | + readResolveMethod = localDesc.readResolveMethod; | |
| 534 | + deserializeEx = localDesc.deserializeEx; | |
| 535 | + } | |
| 536 | + fieldRefl = getReflector(fields, localDesc); | |
| 537 | + } | |
| 538 | + | |
| 539 | + /** | |
| 540 | + * Initializes class descriptor representing a non-proxy class. | |
| 541 | + */ | |
| 542 | + void initNonProxy(ObjectStreamClass model, | |
| 543 | + Class<?> cl, | |
| 544 | + ClassNotFoundException resolveEx, | |
| 545 | + ObjectStreamClass superDesc) | |
| 546 | + throws InvalidClassException | |
| 547 | + { | |
| 548 | + this.cl = cl; | |
| 549 | + this.resolveEx = resolveEx; | |
| 550 | + this.superDesc = superDesc; | |
| 551 | + name = model.name; | |
| 552 | + suid = Long.valueOf(model.getSerialVersionUID()); | |
| 553 | + isProxy = false; | |
| 554 | + isEnum = model.isEnum; | |
| 555 | + serializable = model.serializable; | |
| 556 | + externalizable = model.externalizable; | |
| 557 | + hasBlockExternalData = model.hasBlockExternalData; | |
| 558 | + hasWriteObjectData = model.hasWriteObjectData; | |
| 559 | + fields = model.fields; | |
| 560 | + primDataSize = model.primDataSize; | |
| 561 | + numObjFields = model.numObjFields; | |
| 562 | + | |
| 563 | + if (cl != null) { | |
| 564 | + localDesc = lookup(cl, true); | |
| 565 | + if (localDesc.isProxy) { | |
| 566 | + throw new InvalidClassException( | |
| 567 | + "cannot bind non-proxy descriptor to a proxy class"); | |
| 568 | + } | |
| 569 | + if (isEnum != localDesc.isEnum) { | |
| 570 | + throw new InvalidClassException(isEnum ? | |
| 571 | + "cannot bind enum descriptor to a non-enum class" : | |
| 572 | + "cannot bind non-enum descriptor to an enum class"); | |
| 573 | + } | |
| 574 | + | |
| 575 | + if (serializable == localDesc.serializable && | |
| 576 | + !cl.isArray() && | |
| 577 | + suid.longValue() != localDesc.getSerialVersionUID()) | |
| 578 | + { | |
| 579 | + throw new InvalidClassException(localDesc.name, | |
| 580 | + "local class incompatible: " + | |
| 581 | + "stream classdesc serialVersionUID = " + suid + | |
| 582 | + ", local class serialVersionUID = " + | |
| 583 | + localDesc.getSerialVersionUID()); | |
| 584 | + } | |
| 585 | + | |
| 586 | + if (!classNamesEqual(name, localDesc.name)) { | |
| 587 | + throw new InvalidClassException(localDesc.name, | |
| 588 | + "local class name incompatible with stream class " + | |
| 589 | + "name \"" + name + "\""); | |
| 590 | + } | |
| 591 | + | |
| 592 | + if (!isEnum) { | |
| 593 | + if ((serializable == localDesc.serializable) && | |
| 594 | + (externalizable != localDesc.externalizable)) | |
| 595 | + { | |
| 596 | + throw new InvalidClassException(localDesc.name, | |
| 597 | + "Serializable incompatible with Externalizable"); | |
| 598 | + } | |
| 599 | + | |
| 600 | + if ((serializable != localDesc.serializable) || | |
| 601 | + (externalizable != localDesc.externalizable) || | |
| 602 | + !(serializable || externalizable)) | |
| 603 | + { | |
| 604 | + deserializeEx = new InvalidClassException(localDesc.name, | |
| 605 | + "class invalid for deserialization"); | |
| 606 | + } | |
| 607 | + } | |
| 608 | + | |
| 609 | + cons = localDesc.cons; | |
| 610 | + writeObjectMethod = localDesc.writeObjectMethod; | |
| 611 | + readObjectMethod = localDesc.readObjectMethod; | |
| 612 | + readObjectNoDataMethod = localDesc.readObjectNoDataMethod; | |
| 613 | + writeReplaceMethod = localDesc.writeReplaceMethod; | |
| 614 | + readResolveMethod = localDesc.readResolveMethod; | |
| 615 | + if (deserializeEx == null) { | |
| 616 | + deserializeEx = localDesc.deserializeEx; | |
| 617 | + } | |
| 618 | + } | |
| 619 | + fieldRefl = getReflector(fields, localDesc); | |
| 620 | + // reassign to matched fields so as to reflect local unshared settings | |
| 621 | + fields = fieldRefl.getFields(); | |
| 622 | + } | |
| 623 | + | |
| 624 | + /** | |
| 625 | + * Reads non-proxy class descriptor information from given input stream. | |
| 626 | + * The resulting class descriptor is not fully functional; it can only be | |
| 627 | + * used as input to the ObjectInputStream.resolveClass() and | |
| 628 | + * ObjectStreamClass.initNonProxy() methods. | |
| 629 | + */ | |
| 630 | + void readNonProxy(ObjectInputStream in) | |
| 631 | + throws IOException, ClassNotFoundException | |
| 632 | + { | |
| 633 | + name = in.readUTF(); | |
| 634 | + suid = Long.valueOf(in.readLong()); | |
| 635 | + isProxy = false; | |
| 636 | + | |
| 637 | + byte flags = in.readByte(); | |
| 638 | + hasWriteObjectData = | |
| 639 | + ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0); | |
| 640 | + hasBlockExternalData = | |
| 641 | + ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0); | |
| 642 | + externalizable = | |
| 643 | + ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0); | |
| 644 | + boolean sflag = | |
| 645 | + ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0); | |
| 646 | + if (externalizable && sflag) { | |
| 647 | + throw new InvalidClassException( | |
| 648 | + name, "serializable and externalizable flags conflict"); | |
| 649 | + } | |
| 650 | + serializable = externalizable || sflag; | |
| 651 | + isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0); | |
| 652 | + if (isEnum && suid.longValue() != 0L) { | |
| 653 | + throw new InvalidClassException(name, | |
| 654 | + "enum descriptor has non-zero serialVersionUID: " + suid); | |
| 655 | + } | |
| 656 | + | |
| 657 | + int numFields = in.readShort(); | |
| 658 | + if (isEnum && numFields != 0) { | |
| 659 | + throw new InvalidClassException(name, | |
| 660 | + "enum descriptor has non-zero field count: " + numFields); | |
| 661 | + } | |
| 662 | + fields = (numFields > 0) ? | |
| 663 | + new ObjectStreamField[numFields] : NO_FIELDS; | |
| 664 | + for (int i = 0; i < numFields; i++) { | |
| 665 | + char tcode = (char) in.readByte(); | |
| 666 | + String fname = in.readUTF(); | |
| 667 | + String signature = ((tcode == 'L') || (tcode == '[')) ? | |
| 668 | + in.readTypeString() : new String(new char[] { tcode }); | |
| 669 | + try { | |
| 670 | + fields[i] = new ObjectStreamField(fname, signature, false); | |
| 671 | + } catch (RuntimeException e) { | |
| 672 | + throw (IOException) new InvalidClassException(name, | |
| 673 | + "invalid descriptor for field " + fname).initCause(e); | |
| 674 | + } | |
| 675 | + } | |
| 676 | + computeFieldOffsets(); | |
| 677 | + } | |
| 678 | + | |
| 679 | + /** | |
| 680 | + * Writes non-proxy class descriptor information to given output stream. | |
| 681 | + */ | |
| 682 | + void writeNonProxy(ObjectOutputStream out) throws IOException { | |
| 683 | + out.writeUTF(name); | |
| 684 | + out.writeLong(getSerialVersionUID()); | |
| 685 | + | |
| 686 | + byte flags = 0; | |
| 687 | + if (externalizable) { | |
| 688 | + flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; | |
| 689 | + int protocol = out.getProtocolVersion(); | |
| 690 | + if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { | |
| 691 | + flags |= ObjectStreamConstants.SC_BLOCK_DATA; | |
| 692 | + } | |
| 693 | + } else if (serializable) { | |
| 694 | + flags |= ObjectStreamConstants.SC_SERIALIZABLE; | |
| 695 | + } | |
| 696 | + if (hasWriteObjectData) { | |
| 697 | + flags |= ObjectStreamConstants.SC_WRITE_METHOD; | |
| 698 | + } | |
| 699 | + if (isEnum) { | |
| 700 | + flags |= ObjectStreamConstants.SC_ENUM; | |
| 701 | + } | |
| 702 | + out.writeByte(flags); | |
| 703 | + | |
| 704 | + out.writeShort(fields.length); | |
| 705 | + for (int i = 0; i < fields.length; i++) { | |
| 706 | + ObjectStreamField f = fields[i]; | |
| 707 | + out.writeByte(f.getTypeCode()); | |
| 708 | + out.writeUTF(f.getName()); | |
| 709 | + if (!f.isPrimitive()) { | |
| 710 | + out.writeTypeString(f.getTypeString()); | |
| 711 | + } | |
| 712 | + } | |
| 713 | + } | |
| 714 | + | |
| 715 | + /** | |
| 716 | + * Returns ClassNotFoundException (if any) thrown while attempting to | |
| 717 | + * resolve local class corresponding to this class descriptor. | |
| 718 | + */ | |
| 719 | + ClassNotFoundException getResolveException() { | |
| 720 | + return resolveEx; | |
| 721 | + } | |
| 722 | + | |
| 723 | + /** | |
| 724 | + * Throws an InvalidClassException if object instances referencing this | |
| 725 | + * class descriptor should not be allowed to deserialize. This method does | |
| 726 | + * not apply to deserialization of enum constants. | |
| 727 | + */ | |
| 728 | + void checkDeserialize() throws InvalidClassException { | |
| 729 | + if (deserializeEx != null) { | |
| 730 | + InvalidClassException ice = | |
| 731 | + new InvalidClassException(deserializeEx.classname, | |
| 732 | + deserializeEx.getMessage()); | |
| 733 | + ice.initCause(deserializeEx); | |
| 734 | + throw ice; | |
| 735 | + } | |
| 736 | + } | |
| 737 | + | |
| 738 | + /** | |
| 739 | + * Throws an InvalidClassException if objects whose class is represented by | |
| 740 | + * this descriptor should not be allowed to serialize. This method does | |
| 741 | + * not apply to serialization of enum constants. | |
| 742 | + */ | |
| 743 | + void checkSerialize() throws InvalidClassException { | |
| 744 | + if (serializeEx != null) { | |
| 745 | + InvalidClassException ice = | |
| 746 | + new InvalidClassException(serializeEx.classname, | |
| 747 | + serializeEx.getMessage()); | |
| 748 | + ice.initCause(serializeEx); | |
| 749 | + throw ice; | |
| 750 | + } | |
| 751 | + } | |
| 752 | + | |
| 753 | + /** | |
| 754 | + * Throws an InvalidClassException if objects whose class is represented by | |
| 755 | + * this descriptor should not be permitted to use default serialization | |
| 756 | + * (e.g., if the class declares serializable fields that do not correspond | |
| 757 | + * to actual fields, and hence must use the GetField API). This method | |
| 758 | + * does not apply to deserialization of enum constants. | |
| 759 | + */ | |
| 760 | + void checkDefaultSerialize() throws InvalidClassException { | |
| 761 | + if (defaultSerializeEx != null) { | |
| 762 | + InvalidClassException ice = | |
| 763 | + new InvalidClassException(defaultSerializeEx.classname, | |
| 764 | + defaultSerializeEx.getMessage()); | |
| 765 | + ice.initCause(defaultSerializeEx); | |
| 766 | + throw ice; | |
| 767 | + } | |
| 768 | + } | |
| 769 | + | |
| 770 | + /** | |
| 771 | + * Returns superclass descriptor. Note that on the receiving side, the | |
| 772 | + * superclass descriptor may be bound to a class that is not a superclass | |
| 773 | + * of the subclass descriptor's bound class. | |
| 774 | + */ | |
| 775 | + ObjectStreamClass getSuperDesc() { | |
| 776 | + return superDesc; | |
| 777 | + } | |
| 778 | + | |
| 779 | + /** | |
| 780 | + * Returns the "local" class descriptor for the class associated with this | |
| 781 | + * class descriptor (i.e., the result of | |
| 782 | + * ObjectStreamClass.lookup(this.forClass())) or null if there is no class | |
| 783 | + * associated with this descriptor. | |
| 784 | + */ | |
| 785 | + ObjectStreamClass getLocalDesc() { | |
| 786 | + return localDesc; | |
| 787 | + } | |
| 788 | + | |
| 789 | + /** | |
| 790 | + * Returns arrays of ObjectStreamFields representing the serializable | |
| 791 | + * fields of the represented class. If copy is true, a clone of this class | |
| 792 | + * descriptor's field array is returned, otherwise the array itself is | |
| 793 | + * returned. | |
| 794 | + */ | |
| 795 | + ObjectStreamField[] getFields(boolean copy) { | |
| 796 | + return copy ? fields.clone() : fields; | |
| 797 | + } | |
| 798 | + | |
| 799 | + /** | |
| 800 | + * Looks up a serializable field of the represented class by name and type. | |
| 801 | + * A specified type of null matches all types, Object.class matches all | |
| 802 | + * non-primitive types, and any other non-null type matches assignable | |
| 803 | + * types only. Returns matching field, or null if no match found. | |
| 804 | + */ | |
| 805 | + ObjectStreamField getField(String name, Class<?> type) { | |
| 806 | + for (int i = 0; i < fields.length; i++) { | |
| 807 | + ObjectStreamField f = fields[i]; | |
| 808 | + if (f.getName().equals(name)) { | |
| 809 | + if (type == null || | |
| 810 | + (type == Object.class && !f.isPrimitive())) | |
| 811 | + { | |
| 812 | + return f; | |
| 813 | + } | |
| 814 | + Class<?> ftype = f.getType(); | |
| 815 | + if (ftype != null && type.isAssignableFrom(ftype)) { | |
| 816 | + return f; | |
| 817 | + } | |
| 818 | + } | |
| 819 | + } | |
| 820 | + return null; | |
| 821 | + } | |
| 822 | + | |
| 823 | + /** | |
| 824 | + * Returns true if class descriptor represents a dynamic proxy class, false | |
| 825 | + * otherwise. | |
| 826 | + */ | |
| 827 | + boolean isProxy() { | |
| 828 | + return isProxy; | |
| 829 | + } | |
| 830 | + | |
| 831 | + /** | |
| 832 | + * Returns true if class descriptor represents an enum type, false | |
| 833 | + * otherwise. | |
| 834 | + */ | |
| 835 | + boolean isEnum() { | |
| 836 | + return isEnum; | |
| 837 | + } | |
| 838 | + | |
| 839 | + /** | |
| 840 | + * Returns true if represented class implements Externalizable, false | |
| 841 | + * otherwise. | |
| 842 | + */ | |
| 843 | + boolean isExternalizable() { | |
| 844 | + return externalizable; | |
| 845 | + } | |
| 846 | + | |
| 847 | + /** | |
| 848 | + * Returns true if represented class implements Serializable, false | |
| 849 | + * otherwise. | |
| 850 | + */ | |
| 851 | + boolean isSerializable() { | |
| 852 | + return serializable; | |
| 853 | + } | |
| 854 | + | |
| 855 | + /** | |
| 856 | + * Returns true if class descriptor represents externalizable class that | |
| 857 | + * has written its data in 1.2 (block data) format, false otherwise. | |
| 858 | + */ | |
| 859 | + boolean hasBlockExternalData() { | |
| 860 | + return hasBlockExternalData; | |
| 861 | + } | |
| 862 | + | |
| 863 | + /** | |
| 864 | + * Returns true if class descriptor represents serializable (but not | |
| 865 | + * externalizable) class which has written its data via a custom | |
| 866 | + * writeObject() method, false otherwise. | |
| 867 | + */ | |
| 868 | + boolean hasWriteObjectData() { | |
| 869 | + return hasWriteObjectData; | |
| 870 | + } | |
| 871 | + | |
| 872 | + /** | |
| 873 | + * Returns true if represented class is serializable/externalizable and can | |
| 874 | + * be instantiated by the serialization runtime--i.e., if it is | |
| 875 | + * externalizable and defines a public no-arg constructor, or if it is | |
| 876 | + * non-externalizable and its first non-serializable superclass defines an | |
| 877 | + * accessible no-arg constructor. Otherwise, returns false. | |
| 878 | + */ | |
| 879 | + boolean isInstantiable() { | |
| 880 | + return (cons != null); | |
| 881 | + } | |
| 882 | + | |
| 883 | + /** | |
| 884 | + * Returns true if represented class is serializable (but not | |
| 885 | + * externalizable) and defines a conformant writeObject method. Otherwise, | |
| 886 | + * returns false. | |
| 887 | + */ | |
| 888 | + boolean hasWriteObjectMethod() { | |
| 889 | + return (writeObjectMethod != null); | |
| 890 | + } | |
| 891 | + | |
| 892 | + /** | |
| 893 | + * Returns true if represented class is serializable (but not | |
| 894 | + * externalizable) and defines a conformant readObject method. Otherwise, | |
| 895 | + * returns false. | |
| 896 | + */ | |
| 897 | + boolean hasReadObjectMethod() { | |
| 898 | + return (readObjectMethod != null); | |
| 899 | + } | |
| 900 | + | |
| 901 | + /** | |
| 902 | + * Returns true if represented class is serializable (but not | |
| 903 | + * externalizable) and defines a conformant readObjectNoData method. | |
| 904 | + * Otherwise, returns false. | |
| 905 | + */ | |
| 906 | + boolean hasReadObjectNoDataMethod() { | |
| 907 | + return (readObjectNoDataMethod != null); | |
| 908 | + } | |
| 909 | + | |
| 910 | + /** | |
| 911 | + * Returns true if represented class is serializable or externalizable and | |
| 912 | + * defines a conformant writeReplace method. Otherwise, returns false. | |
| 913 | + */ | |
| 914 | + boolean hasWriteReplaceMethod() { | |
| 915 | + return (writeReplaceMethod != null); | |
| 916 | + } | |
| 917 | + | |
| 918 | + /** | |
| 919 | + * Returns true if represented class is serializable or externalizable and | |
| 920 | + * defines a conformant readResolve method. Otherwise, returns false. | |
| 921 | + */ | |
| 922 | + boolean hasReadResolveMethod() { | |
| 923 | + return (readResolveMethod != null); | |
| 924 | + } | |
| 925 | + | |
| 926 | + /** | |
| 927 | + * Creates a new instance of the represented class. If the class is | |
| 928 | + * externalizable, invokes its public no-arg constructor; otherwise, if the | |
| 929 | + * class is serializable, invokes the no-arg constructor of the first | |
| 930 | + * non-serializable superclass. Throws UnsupportedOperationException if | |
| 931 | + * this class descriptor is not associated with a class, if the associated | |
| 932 | + * class is non-serializable or if the appropriate no-arg constructor is | |
| 933 | + * inaccessible/unavailable. | |
| 934 | + */ | |
| 935 | + Object newInstance() | |
| 936 | + throws InstantiationException, InvocationTargetException, | |
| 937 | + UnsupportedOperationException | |
| 938 | + { | |
| 939 | + if (cons != null) { | |
| 940 | + try { | |
| 941 | + return cons.newInstance(); | |
| 942 | + } catch (IllegalAccessException ex) { | |
| 943 | + // should not occur, as access checks have been suppressed | |
| 944 | + throw new InternalError(); | |
| 945 | + } | |
| 946 | + } else { | |
| 947 | + throw new UnsupportedOperationException(); | |
| 948 | + } | |
| 949 | + } | |
| 950 | + | |
| 951 | + /** | |
| 952 | + * Invokes the writeObject method of the represented serializable class. | |
| 953 | + * Throws UnsupportedOperationException if this class descriptor is not | |
| 954 | + * associated with a class, or if the class is externalizable, | |
| 955 | + * non-serializable or does not define writeObject. | |
| 956 | + */ | |
| 957 | + void invokeWriteObject(Object obj, ObjectOutputStream out) | |
| 958 | + throws IOException, UnsupportedOperationException | |
| 959 | + { | |
| 960 | + if (writeObjectMethod != null) { | |
| 961 | + try { | |
| 962 | + writeObjectMethod.invoke(obj, new Object[]{ out }); | |
| 963 | + } catch (InvocationTargetException ex) { | |
| 964 | + Throwable th = ex.getTargetException(); | |
| 965 | + if (th instanceof IOException) { | |
| 966 | + throw (IOException) th; | |
| 967 | + } else { | |
| 968 | + throwMiscException(th); | |
| 969 | + } | |
| 970 | + } catch (IllegalAccessException ex) { | |
| 971 | + // should not occur, as access checks have been suppressed | |
| 972 | + throw new InternalError(); | |
| 973 | + } | |
| 974 | + } else { | |
| 975 | + throw new UnsupportedOperationException(); | |
| 976 | + } | |
| 977 | + } | |
| 978 | + | |
| 979 | + /** | |
| 980 | + * Invokes the readObject method of the represented serializable class. | |
| 981 | + * Throws UnsupportedOperationException if this class descriptor is not | |
| 982 | + * associated with a class, or if the class is externalizable, | |
| 983 | + * non-serializable or does not define readObject. | |
| 984 | + */ | |
| 985 | + void invokeReadObject(Object obj, ObjectInputStream in) | |
| 986 | + throws ClassNotFoundException, IOException, | |
| 987 | + UnsupportedOperationException | |
| 988 | + { | |
| 989 | + if (readObjectMethod != null) { | |
| 990 | + try { | |
| 991 | + readObjectMethod.invoke(obj, new Object[]{ in }); | |
| 992 | + } catch (InvocationTargetException ex) { | |
| 993 | + Throwable th = ex.getTargetException(); | |
| 994 | + if (th instanceof ClassNotFoundException) { | |
| 995 | + throw (ClassNotFoundException) th; | |
| 996 | + } else if (th instanceof IOException) { | |
| 997 | + throw (IOException) th; | |
| 998 | + } else { | |
| 999 | + throwMiscException(th); | |
| 1000 | + } | |
| 1001 | + } catch (IllegalAccessException ex) { | |
| 1002 | + // should not occur, as access checks have been suppressed | |
| 1003 | + throw new InternalError(); | |
| 1004 | + } | |
| 1005 | + } else { | |
| 1006 | + throw new UnsupportedOperationException(); | |
| 1007 | + } | |
| 1008 | + } | |
| 1009 | + | |
| 1010 | + /** | |
| 1011 | + * Invokes the readObjectNoData method of the represented serializable | |
| 1012 | + * class. Throws UnsupportedOperationException if this class descriptor is | |
| 1013 | + * not associated with a class, or if the class is externalizable, | |
| 1014 | + * non-serializable or does not define readObjectNoData. | |
| 1015 | + */ | |
| 1016 | + void invokeReadObjectNoData(Object obj) | |
| 1017 | + throws IOException, UnsupportedOperationException | |
| 1018 | + { | |
| 1019 | + if (readObjectNoDataMethod != null) { | |
| 1020 | + try { | |
| 1021 | + readObjectNoDataMethod.invoke(obj, (Object[]) null); | |
| 1022 | + } catch (InvocationTargetException ex) { | |
| 1023 | + Throwable th = ex.getTargetException(); | |
| 1024 | + if (th instanceof ObjectStreamException) { | |
| 1025 | + throw (ObjectStreamException) th; | |
| 1026 | + } else { | |
| 1027 | + throwMiscException(th); | |
| 1028 | + } | |
| 1029 | + } catch (IllegalAccessException ex) { | |
| 1030 | + // should not occur, as access checks have been suppressed | |
| 1031 | + throw new InternalError(); | |
| 1032 | + } | |
| 1033 | + } else { | |
| 1034 | + throw new UnsupportedOperationException(); | |
| 1035 | + } | |
| 1036 | + } | |
| 1037 | + | |
| 1038 | + /** | |
| 1039 | + * Invokes the writeReplace method of the represented serializable class and | |
| 1040 | + * returns the result. Throws UnsupportedOperationException if this class | |
| 1041 | + * descriptor is not associated with a class, or if the class is | |
| 1042 | + * non-serializable or does not define writeReplace. | |
| 1043 | + */ | |
| 1044 | + Object invokeWriteReplace(Object obj) | |
| 1045 | + throws IOException, UnsupportedOperationException | |
| 1046 | + { | |
| 1047 | + if (writeReplaceMethod != null) { | |
| 1048 | + try { | |
| 1049 | + return writeReplaceMethod.invoke(obj, (Object[]) null); | |
| 1050 | + } catch (InvocationTargetException ex) { | |
| 1051 | + Throwable th = ex.getTargetException(); | |
| 1052 | + if (th instanceof ObjectStreamException) { | |
| 1053 | + throw (ObjectStreamException) th; | |
| 1054 | + } else { | |
| 1055 | + throwMiscException(th); | |
| 1056 | + throw new InternalError(); // never reached | |
| 1057 | + } | |
| 1058 | + } catch (IllegalAccessException ex) { | |
| 1059 | + // should not occur, as access checks have been suppressed | |
| 1060 | + throw new InternalError(); | |
| 1061 | + } | |
| 1062 | + } else { | |
| 1063 | + throw new UnsupportedOperationException(); | |
| 1064 | + } | |
| 1065 | + } | |
| 1066 | + | |
| 1067 | + /** | |
| 1068 | + * Invokes the readResolve method of the represented serializable class and | |
| 1069 | + * returns the result. Throws UnsupportedOperationException if this class | |
| 1070 | + * descriptor is not associated with a class, or if the class is | |
| 1071 | + * non-serializable or does not define readResolve. | |
| 1072 | + */ | |
| 1073 | + Object invokeReadResolve(Object obj) | |
| 1074 | + throws IOException, UnsupportedOperationException | |
| 1075 | + { | |
| 1076 | + if (readResolveMethod != null) { | |
| 1077 | + try { | |
| 1078 | + return readResolveMethod.invoke(obj, (Object[]) null); | |
| 1079 | + } catch (InvocationTargetException ex) { | |
| 1080 | + Throwable th = ex.getTargetException(); | |
| 1081 | + if (th instanceof ObjectStreamException) { | |
| 1082 | + throw (ObjectStreamException) th; | |
| 1083 | + } else { | |
| 1084 | + throwMiscException(th); | |
| 1085 | + throw new InternalError(); // never reached | |
| 1086 | + } | |
| 1087 | + } catch (IllegalAccessException ex) { | |
| 1088 | + // should not occur, as access checks have been suppressed | |
| 1089 | + throw new InternalError(); | |
| 1090 | + } | |
| 1091 | + } else { | |
| 1092 | + throw new UnsupportedOperationException(); | |
| 1093 | + } | |
| 1094 | + } | |
| 1095 | + | |
| 1096 | + /** | |
| 1097 | + * Class representing the portion of an object's serialized form allotted | |
| 1098 | + * to data described by a given class descriptor. If "hasData" is false, | |
| 1099 | + * the object's serialized form does not contain data associated with the | |
| 1100 | + * class descriptor. | |
| 1101 | + */ | |
| 1102 | + static class ClassDataSlot { | |
| 1103 | + | |
| 1104 | + /** class descriptor "occupying" this slot */ | |
| 1105 | + final ObjectStreamClass desc; | |
| 1106 | + /** true if serialized form includes data for this slot's descriptor */ | |
| 1107 | + final boolean hasData; | |
| 1108 | + | |
| 1109 | + ClassDataSlot(ObjectStreamClass desc, boolean hasData) { | |
| 1110 | + this.desc = desc; | |
| 1111 | + this.hasData = hasData; | |
| 1112 | + } | |
| 1113 | + } | |
| 1114 | + | |
| 1115 | + /** | |
| 1116 | + * Returns array of ClassDataSlot instances representing the data layout | |
| 1117 | + * (including superclass data) for serialized objects described by this | |
| 1118 | + * class descriptor. ClassDataSlots are ordered by inheritance with those | |
| 1119 | + * containing "higher" superclasses appearing first. The final | |
| 1120 | + * ClassDataSlot contains a reference to this descriptor. | |
| 1121 | + */ | |
| 1122 | + ClassDataSlot[] getClassDataLayout() throws InvalidClassException { | |
| 1123 | + // REMIND: synchronize instead of relying on volatile? | |
| 1124 | + if (dataLayout == null) { | |
| 1125 | + dataLayout = getClassDataLayout0(); | |
| 1126 | + } | |
| 1127 | + return dataLayout; | |
| 1128 | + } | |
| 1129 | + | |
| 1130 | + private ClassDataSlot[] getClassDataLayout0() | |
| 1131 | + throws InvalidClassException | |
| 1132 | + { | |
| 1133 | + ArrayList<ClassDataSlot> slots = new ArrayList<>(); | |
| 1134 | + Class<?> start = cl, end = cl; | |
| 1135 | + | |
| 1136 | + // locate closest non-serializable superclass | |
| 1137 | + while (end != null && Serializable.class.isAssignableFrom(end)) { | |
| 1138 | + end = end.getSuperclass(); | |
| 1139 | + } | |
| 1140 | + | |
| 1141 | + for (ObjectStreamClass d = this; d != null; d = d.superDesc) { | |
| 1142 | + | |
| 1143 | + // search up inheritance hierarchy for class with matching name | |
| 1144 | + String searchName = (d.cl != null) ? d.cl.getName() : d.name; | |
| 1145 | + Class<?> match = null; | |
| 1146 | + for (Class<?> c = start; c != end; c = c.getSuperclass()) { | |
| 1147 | + if (searchName.equals(c.getName())) { | |
| 1148 | + match = c; | |
| 1149 | + break; | |
| 1150 | + } | |
| 1151 | + } | |
| 1152 | + | |
| 1153 | + // add "no data" slot for each unmatched class below match | |
| 1154 | + if (match != null) { | |
| 1155 | + for (Class<?> c = start; c != match; c = c.getSuperclass()) { | |
| 1156 | + slots.add(new ClassDataSlot( | |
| 1157 | + ObjectStreamClass.lookup(c, true), false)); | |
| 1158 | + } | |
| 1159 | + start = match.getSuperclass(); | |
| 1160 | + } | |
| 1161 | + | |
| 1162 | + // record descriptor/class pairing | |
| 1163 | + slots.add(new ClassDataSlot(d.getVariantFor(match), true)); | |
| 1164 | + } | |
| 1165 | + | |
| 1166 | + // add "no data" slot for any leftover unmatched classes | |
| 1167 | + for (Class<?> c = start; c != end; c = c.getSuperclass()) { | |
| 1168 | + slots.add(new ClassDataSlot( | |
| 1169 | + ObjectStreamClass.lookup(c, true), false)); | |
| 1170 | + } | |
| 1171 | + | |
| 1172 | + // order slots from superclass -> subclass | |
| 1173 | + Collections.reverse(slots); | |
| 1174 | + return slots.toArray(new ClassDataSlot[slots.size()]); | |
| 1175 | + } | |
| 1176 | + | |
| 1177 | + /** | |
| 1178 | + * Returns aggregate size (in bytes) of marshalled primitive field values | |
| 1179 | + * for represented class. | |
| 1180 | + */ | |
| 1181 | + int getPrimDataSize() { | |
| 1182 | + return primDataSize; | |
| 1183 | + } | |
| 1184 | + | |
| 1185 | + /** | |
| 1186 | + * Returns number of non-primitive serializable fields of represented | |
| 1187 | + * class. | |
| 1188 | + */ | |
| 1189 | + int getNumObjFields() { | |
| 1190 | + return numObjFields; | |
| 1191 | + } | |
| 1192 | + | |
| 1193 | + /** | |
| 1194 | + * Fetches the serializable primitive field values of object obj and | |
| 1195 | + * marshals them into byte array buf starting at offset 0. It is the | |
| 1196 | + * responsibility of the caller to ensure that obj is of the proper type if | |
| 1197 | + * non-null. | |
| 1198 | + */ | |
| 1199 | + void getPrimFieldValues(Object obj, byte[] buf) { | |
| 1200 | + fieldRefl.getPrimFieldValues(obj, buf); | |
| 1201 | + } | |
| 1202 | + | |
| 1203 | + /** | |
| 1204 | + * Sets the serializable primitive fields of object obj using values | |
| 1205 | + * unmarshalled from byte array buf starting at offset 0. It is the | |
| 1206 | + * responsibility of the caller to ensure that obj is of the proper type if | |
| 1207 | + * non-null. | |
| 1208 | + */ | |
| 1209 | + void setPrimFieldValues(Object obj, byte[] buf) { | |
| 1210 | + fieldRefl.setPrimFieldValues(obj, buf); | |
| 1211 | + } | |
| 1212 | + | |
| 1213 | + /** | |
| 1214 | + * Fetches the serializable object field values of object obj and stores | |
| 1215 | + * them in array vals starting at offset 0. It is the responsibility of | |
| 1216 | + * the caller to ensure that obj is of the proper type if non-null. | |
| 1217 | + */ | |
| 1218 | + void getObjFieldValues(Object obj, Object[] vals) { | |
| 1219 | + fieldRefl.getObjFieldValues(obj, vals); | |
| 1220 | + } | |
| 1221 | + | |
| 1222 | + /** | |
| 1223 | + * Sets the serializable object fields of object obj using values from | |
| 1224 | + * array vals starting at offset 0. It is the responsibility of the caller | |
| 1225 | + * to ensure that obj is of the proper type if non-null. | |
| 1226 | + */ | |
| 1227 | + void setObjFieldValues(Object obj, Object[] vals) { | |
| 1228 | + fieldRefl.setObjFieldValues(obj, vals); | |
| 1229 | + } | |
| 1230 | + | |
| 1231 | + /** | |
| 1232 | + * Calculates and sets serializable field offsets, as well as primitive | |
| 1233 | + * data size and object field count totals. Throws InvalidClassException | |
| 1234 | + * if fields are illegally ordered. | |
| 1235 | + */ | |
| 1236 | + private void computeFieldOffsets() throws InvalidClassException { | |
| 1237 | + primDataSize = 0; | |
| 1238 | + numObjFields = 0; | |
| 1239 | + int firstObjIndex = -1; | |
| 1240 | + | |
| 1241 | + for (int i = 0; i < fields.length; i++) { | |
| 1242 | + ObjectStreamField f = fields[i]; | |
| 1243 | + switch (f.getTypeCode()) { | |
| 1244 | + case 'Z': | |
| 1245 | + case 'B': | |
| 1246 | + f.setOffset(primDataSize++); | |
| 1247 | + break; | |
| 1248 | + | |
| 1249 | + case 'C': | |
| 1250 | + case 'S': | |
| 1251 | + f.setOffset(primDataSize); | |
| 1252 | + primDataSize += 2; | |
| 1253 | + break; | |
| 1254 | + | |
| 1255 | + case 'I': | |
| 1256 | + case 'F': | |
| 1257 | + f.setOffset(primDataSize); | |
| 1258 | + primDataSize += 4; | |
| 1259 | + break; | |
| 1260 | + | |
| 1261 | + case 'J': | |
| 1262 | + case 'D': | |
| 1263 | + f.setOffset(primDataSize); | |
| 1264 | + primDataSize += 8; | |
| 1265 | + break; | |
| 1266 | + | |
| 1267 | + case '[': | |
| 1268 | + case 'L': | |
| 1269 | + f.setOffset(numObjFields++); | |
| 1270 | + if (firstObjIndex == -1) { | |
| 1271 | + firstObjIndex = i; | |
| 1272 | + } | |
| 1273 | + break; | |
| 1274 | + | |
| 1275 | + default: | |
| 1276 | + throw new InternalError(); | |
| 1277 | + } | |
| 1278 | + } | |
| 1279 | + if (firstObjIndex != -1 && | |
| 1280 | + firstObjIndex + numObjFields != fields.length) | |
| 1281 | + { | |
| 1282 | + throw new InvalidClassException(name, "illegal field order"); | |
| 1283 | + } | |
| 1284 | + } | |
| 1285 | + | |
| 1286 | + /** | |
| 1287 | + * If given class is the same as the class associated with this class | |
| 1288 | + * descriptor, returns reference to this class descriptor. Otherwise, | |
| 1289 | + * returns variant of this class descriptor bound to given class. | |
| 1290 | + */ | |
| 1291 | + private ObjectStreamClass getVariantFor(Class<?> cl) | |
| 1292 | + throws InvalidClassException | |
| 1293 | + { | |
1011 more lines aren’t shown here.
Binary file not shown.
This diff is large: its 236 lines aren’t shown here.
Binary file not shown.
This diff is large: its 54 lines aren’t shown here.
Binary file not shown.
This diff is large: its 315 lines aren’t shown here.
Binary file not shown.
This diff is large: its 84 lines aren’t shown here.
Binary file not shown.
This diff is large: its 155 lines aren’t shown here.
Binary file not shown.
This diff is large: its 236 lines aren’t shown here.
Binary file not shown.
This diff is large: its 451 lines aren’t shown here.
Binary file not shown.
This diff is large: its 180 lines aren’t shown here.
Binary file not shown.
This diff is large: its 364 lines aren’t shown here.
Binary file not shown.
This diff is large: its 185 lines aren’t shown here.
Binary file not shown.
This diff is large: its 1130 lines aren’t shown here.
Binary file not shown.
This diff is large: its 1067 lines aren’t shown here.
Binary file not shown.
This diff is large: its 384 lines aren’t shown here.
Binary file not shown.
This diff is large: its 282 lines aren’t shown here.
Binary file not shown.
This diff is large: its 1126 lines aren’t shown here.
Binary file not shown.
This diff is large: its 263 lines aren’t shown here.
Binary file not shown.
This diff is large: its 236 lines aren’t shown here.
Binary file not shown.
This diff is large: its 55 lines aren’t shown here.
Binary file not shown.
This diff is large: its 171 lines aren’t shown here.
Binary file not shown.
This diff is large: its 133 lines aren’t shown here.
Binary file not shown.
This diff is large: its 55 lines aren’t shown here.
Binary file not shown.
This diff is large: its 835 lines aren’t shown here.
Binary file not shown.
This diff is large: its 173 lines aren’t shown here.
Binary file not shown.
This diff is large: its 202 lines aren’t shown here.
Binary file not shown.
This diff is large: its 237 lines aren’t shown here.
Binary file not shown.
This diff is large: its 49 lines aren’t shown here.
Binary file not shown.
This diff is large: its 70 lines aren’t shown here.
Binary file not shown.
This diff is large: its 53 lines aren’t shown here.
Binary file not shown.
This diff is large: its 94 lines aren’t shown here.
Binary file not shown.
This diff is large: its 326 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.