J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 1996-2006 Sun Microsystems, Inc. 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. Sun designates this |
| 8 | * particular file as subject to the "Classpath" exception as provided |
| 9 | * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 23 | * have any 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 primClasses = new HashMap(8, 1.0F); |
| 216 | static { |
| 217 | primClasses.put("boolean", boolean.class); |
| 218 | primClasses.put("byte", byte.class); |
| 219 | primClasses.put("char", char.class); |
| 220 | primClasses.put("short", short.class); |
| 221 | primClasses.put("int", int.class); |
| 222 | primClasses.put("long", long.class); |
| 223 | primClasses.put("float", float.class); |
| 224 | primClasses.put("double", double.class); |
| 225 | primClasses.put("void", void.class); |
| 226 | } |
| 227 | |
| 228 | private static class Caches { |
| 229 | /** cache of subclass security audit results */ |
| 230 | static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits = |
| 231 | new ConcurrentHashMap<WeakClassKey,Boolean>(); |
| 232 | |
| 233 | /** queue for WeakReferences to audited subclasses */ |
| 234 | static final ReferenceQueue<Class<?>> subclassAuditsQueue = |
| 235 | new ReferenceQueue<Class<?>>(); |
| 236 | } |
| 237 | |
| 238 | /** filter stream for handling block data conversion */ |
| 239 | private final BlockDataInputStream bin; |
| 240 | /** validation callback list */ |
| 241 | private final ValidationList vlist; |
| 242 | /** recursion depth */ |
| 243 | private int depth; |
| 244 | /** whether stream is closed */ |
| 245 | private boolean closed; |
| 246 | |
| 247 | /** wire handle -> obj/exception map */ |
| 248 | private final HandleTable handles; |
| 249 | /** scratch field for passing handle values up/down call stack */ |
| 250 | private int passHandle = NULL_HANDLE; |
| 251 | /** flag set when at end of field value block with no TC_ENDBLOCKDATA */ |
| 252 | private boolean defaultDataEnd = false; |
| 253 | |
| 254 | /** buffer for reading primitive field values */ |
| 255 | private byte[] primVals; |
| 256 | |
| 257 | /** if true, invoke readObjectOverride() instead of readObject() */ |
| 258 | private final boolean enableOverride; |
| 259 | /** if true, invoke resolveObject() */ |
| 260 | private boolean enableResolve; |
| 261 | |
| 262 | /** |
| 263 | * Context during upcalls to class-defined readObject methods; holds |
| 264 | * object currently being deserialized and descriptor for current class. |
| 265 | * Null when not during readObject upcall. |
| 266 | */ |
| 267 | private CallbackContext curContext; |
| 268 | |
| 269 | /** |
| 270 | * Creates an ObjectInputStream that reads from the specified InputStream. |
| 271 | * A serialization stream header is read from the stream and verified. |
| 272 | * This constructor will block until the corresponding ObjectOutputStream |
| 273 | * has written and flushed the header. |
| 274 | * |
| 275 | * <p>If a security manager is installed, this constructor will check for |
| 276 | * the "enableSubclassImplementation" SerializablePermission when invoked |
| 277 | * directly or indirectly by the constructor of a subclass which overrides |
| 278 | * the ObjectInputStream.readFields or ObjectInputStream.readUnshared |
| 279 | * methods. |
| 280 | * |
| 281 | * @param in input stream to read from |
| 282 | * @throws StreamCorruptedException if the stream header is incorrect |
| 283 | * @throws IOException if an I/O error occurs while reading stream header |
| 284 | * @throws SecurityException if untrusted subclass illegally overrides |
| 285 | * security-sensitive methods |
| 286 | * @throws NullPointerException if <code>in</code> is <code>null</code> |
| 287 | * @see ObjectInputStream#ObjectInputStream() |
| 288 | * @see ObjectInputStream#readFields() |
| 289 | * @see ObjectOutputStream#ObjectOutputStream(OutputStream) |
| 290 | */ |
| 291 | public ObjectInputStream(InputStream in) throws IOException { |
| 292 | verifySubclass(); |
| 293 | bin = new BlockDataInputStream(in); |
| 294 | handles = new HandleTable(10); |
| 295 | vlist = new ValidationList(); |
| 296 | enableOverride = false; |
| 297 | readStreamHeader(); |
| 298 | bin.setBlockDataMode(true); |
| 299 | } |
| 300 | |
| 301 | /** |
| 302 | * Provide a way for subclasses that are completely reimplementing |
| 303 | * ObjectInputStream to not have to allocate private data just used by this |
| 304 | * implementation of ObjectInputStream. |
| 305 | * |
| 306 | * <p>If there is a security manager installed, this method first calls the |
| 307 | * security manager's <code>checkPermission</code> method with the |
| 308 | * <code>SerializablePermission("enableSubclassImplementation")</code> |
| 309 | * permission to ensure it's ok to enable subclassing. |
| 310 | * |
| 311 | * @throws SecurityException if a security manager exists and its |
| 312 | * <code>checkPermission</code> method denies enabling |
| 313 | * subclassing. |
| 314 | * @see SecurityManager#checkPermission |
| 315 | * @see java.io.SerializablePermission |
| 316 | */ |
| 317 | protected ObjectInputStream() throws IOException, SecurityException { |
| 318 | SecurityManager sm = System.getSecurityManager(); |
| 319 | if (sm != null) { |
| 320 | sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); |
| 321 | } |
| 322 | bin = null; |
| 323 | handles = null; |
| 324 | vlist = null; |
| 325 | enableOverride = true; |
| 326 | } |
| 327 | |
| 328 | /** |
| 329 | * Read an object from the ObjectInputStream. The class of the object, the |
| 330 | * signature of the class, and the values of the non-transient and |
| 331 | * non-static fields of the class and all of its supertypes are read. |
| 332 | * Default deserializing for a class can be overriden using the writeObject |
| 333 | * and readObject methods. Objects referenced by this object are read |
| 334 | * transitively so that a complete equivalent graph of objects is |
| 335 | * reconstructed by readObject. |
| 336 | * |
| 337 | * <p>The root object is completely restored when all of its fields and the |
| 338 | * objects it references are completely restored. At this point the object |
| 339 | * validation callbacks are executed in order based on their registered |
| 340 | * priorities. The callbacks are registered by objects (in the readObject |
| 341 | * special methods) as they are individually restored. |
| 342 | * |
| 343 | * <p>Exceptions are thrown for problems with the InputStream and for |
| 344 | * classes that should not be deserialized. All exceptions are fatal to |
| 345 | * the InputStream and leave it in an indeterminate state; it is up to the |
| 346 | * caller to ignore or recover the stream state. |
| 347 | * |
| 348 | * @throws ClassNotFoundException Class of a serialized object cannot be |
| 349 | * found. |
| 350 | * @throws InvalidClassException Something is wrong with a class used by |
| 351 | * serialization. |
| 352 | * @throws StreamCorruptedException Control information in the |
| 353 | * stream is inconsistent. |
| 354 | * @throws OptionalDataException Primitive data was found in the |
| 355 | * stream instead of objects. |
| 356 | * @throws IOException Any of the usual Input/Output related exceptions. |
| 357 | */ |
| 358 | public final Object readObject() |
| 359 | throws IOException, ClassNotFoundException |
| 360 | { |
| 361 | if (enableOverride) { |
| 362 | return readObjectOverride(); |
| 363 | } |
| 364 | |
| 365 | // if nested read, passHandle contains handle of enclosing object |
| 366 | int outerHandle = passHandle; |
| 367 | try { |
| 368 | Object obj = readObject0(false); |
| 369 | handles.markDependency(outerHandle, passHandle); |
| 370 | ClassNotFoundException ex = handles.lookupException(passHandle); |
| 371 | if (ex != null) { |
| 372 | throw ex; |
| 373 | } |
| 374 | if (depth == 0) { |
| 375 | vlist.doCallbacks(); |
| 376 | } |
| 377 | return obj; |
| 378 | } finally { |
| 379 | passHandle = outerHandle; |
| 380 | if (closed && depth == 0) { |
| 381 | clear(); |
| 382 | } |
| 383 | } |
| 384 | } |
| 385 | |
| 386 | /** |
| 387 | * This method is called by trusted subclasses of ObjectOutputStream that |
| 388 | * constructed ObjectOutputStream using the protected no-arg constructor. |
| 389 | * The subclass is expected to provide an override method with the modifier |
| 390 | * "final". |
| 391 | * |
| 392 | * @return the Object read from the stream. |
| 393 | * @throws ClassNotFoundException Class definition of a serialized object |
| 394 | * cannot be found. |
| 395 | * @throws OptionalDataException Primitive data was found in the stream |
| 396 | * instead of objects. |
| 397 | * @throws IOException if I/O errors occurred while reading from the |
| 398 | * underlying stream |
| 399 | * @see #ObjectInputStream() |
| 400 | * @see #readObject() |
| 401 | * @since 1.2 |
| 402 | */ |
| 403 | protected Object readObjectOverride() |
| 404 | throws IOException, ClassNotFoundException |
| 405 | { |
| 406 | return null; |
| 407 | } |
| 408 | |
| 409 | /** |
| 410 | * Reads an "unshared" object from the ObjectInputStream. This method is |
| 411 | * identical to readObject, except that it prevents subsequent calls to |
| 412 | * readObject and readUnshared from returning additional references to the |
| 413 | * deserialized instance obtained via this call. Specifically: |
| 414 | * <ul> |
| 415 | * <li>If readUnshared is called to deserialize a back-reference (the |
| 416 | * stream representation of an object which has been written |
| 417 | * previously to the stream), an ObjectStreamException will be |
| 418 | * thrown. |
| 419 | * |
| 420 | * <li>If readUnshared returns successfully, then any subsequent attempts |
| 421 | * to deserialize back-references to the stream handle deserialized |
| 422 | * by readUnshared will cause an ObjectStreamException to be thrown. |
| 423 | * </ul> |
| 424 | * Deserializing an object via readUnshared invalidates the stream handle |
| 425 | * associated with the returned object. Note that this in itself does not |
| 426 | * always guarantee that the reference returned by readUnshared is unique; |
| 427 | * the deserialized object may define a readResolve method which returns an |
| 428 | * object visible to other parties, or readUnshared may return a Class |
| 429 | * object or enum constant obtainable elsewhere in the stream or through |
| 430 | * external means. If the deserialized object defines a readResolve method |
| 431 | * and the invocation of that method returns an array, then readUnshared |
| 432 | * returns a shallow clone of that array; this guarantees that the returned |
| 433 | * array object is unique and cannot be obtained a second time from an |
| 434 | * invocation of readObject or readUnshared on the ObjectInputStream, |
| 435 | * even if the underlying data stream has been manipulated. |
| 436 | * |
| 437 | * <p>ObjectInputStream subclasses which override this method can only be |
| 438 | * constructed in security contexts possessing the |
| 439 | * "enableSubclassImplementation" SerializablePermission; any attempt to |
| 440 | * instantiate such a subclass without this permission will cause a |
| 441 | * SecurityException to be thrown. |
| 442 | * |
| 443 | * @return reference to deserialized object |
| 444 | * @throws ClassNotFoundException if class of an object to deserialize |
| 445 | * cannot be found |
| 446 | * @throws StreamCorruptedException if control information in the stream |
| 447 | * is inconsistent |
| 448 | * @throws ObjectStreamException if object to deserialize has already |
| 449 | * appeared in stream |
| 450 | * @throws OptionalDataException if primitive data is next in stream |
| 451 | * @throws IOException if an I/O error occurs during deserialization |
| 452 | * @since 1.4 |
| 453 | */ |
| 454 | public Object readUnshared() throws IOException, ClassNotFoundException { |
| 455 | // if nested read, passHandle contains handle of enclosing object |
| 456 | int outerHandle = passHandle; |
| 457 | try { |
| 458 | Object obj = readObject0(true); |
| 459 | handles.markDependency(outerHandle, passHandle); |
| 460 | ClassNotFoundException ex = handles.lookupException(passHandle); |
| 461 | if (ex != null) { |
| 462 | throw ex; |
| 463 | } |
| 464 | if (depth == 0) { |
| 465 | vlist.doCallbacks(); |
| 466 | } |
| 467 | return obj; |
| 468 | } finally { |
| 469 | passHandle = outerHandle; |
| 470 | if (closed && depth == 0) { |
| 471 | clear(); |
| 472 | } |
| 473 | } |
| 474 | } |
| 475 | |
| 476 | /** |
| 477 | * Read the non-static and non-transient fields of the current class from |
| 478 | * this stream. This may only be called from the readObject method of the |
| 479 | * class being deserialized. It will throw the NotActiveException if it is |
| 480 | * called otherwise. |
| 481 | * |
| 482 | * @throws ClassNotFoundException if the class of a serialized object |
| 483 | * could not be found. |
| 484 | * @throws IOException if an I/O error occurs. |
| 485 | * @throws NotActiveException if the stream is not currently reading |
| 486 | * objects. |
| 487 | */ |
| 488 | public void defaultReadObject() |
| 489 | throws IOException, ClassNotFoundException |
| 490 | { |
| 491 | if (curContext == null) { |
| 492 | throw new NotActiveException("not in call to readObject"); |
| 493 | } |
| 494 | Object curObj = curContext.getObj(); |
| 495 | ObjectStreamClass curDesc = curContext.getDesc(); |
| 496 | bin.setBlockDataMode(false); |
| 497 | defaultReadFields(curObj, curDesc); |
| 498 | bin.setBlockDataMode(true); |
| 499 | if (!curDesc.hasWriteObjectData()) { |
| 500 | /* |
| 501 | * Fix for 4360508: since stream does not contain terminating |
| 502 | * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere |
| 503 | * knows to simulate end-of-custom-data behavior. |
| 504 | */ |
| 505 | defaultDataEnd = true; |
| 506 | } |
| 507 | ClassNotFoundException ex = handles.lookupException(passHandle); |
| 508 | if (ex != null) { |
| 509 | throw ex; |
| 510 | } |
| 511 | } |
| 512 | |
| 513 | /** |
| 514 | * Reads the persistent fields from the stream and makes them available by |
| 515 | * name. |
| 516 | * |
| 517 | * @return the <code>GetField</code> object representing the persistent |
| 518 | * fields of the object being deserialized |
| 519 | * @throws ClassNotFoundException if the class of a serialized object |
| 520 | * could not be found. |
| 521 | * @throws IOException if an I/O error occurs. |
| 522 | * @throws NotActiveException if the stream is not currently reading |
| 523 | * objects. |
| 524 | * @since 1.2 |
| 525 | */ |
| 526 | public ObjectInputStream.GetField readFields() |
| 527 | throws IOException, ClassNotFoundException |
| 528 | { |
| 529 | if (curContext == null) { |
| 530 | throw new NotActiveException("not in call to readObject"); |
| 531 | } |
| 532 | Object curObj = curContext.getObj(); |
| 533 | ObjectStreamClass curDesc = curContext.getDesc(); |
| 534 | bin.setBlockDataMode(false); |
| 535 | GetFieldImpl getField = new GetFieldImpl(curDesc); |
| 536 | getField.readFields(); |
| 537 | bin.setBlockDataMode(true); |
| 538 | if (!curDesc.hasWriteObjectData()) { |
| 539 | /* |
| 540 | * Fix for 4360508: since stream does not contain terminating |
| 541 | * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere |
| 542 | * knows to simulate end-of-custom-data behavior. |
| 543 | */ |
| 544 | defaultDataEnd = true; |
| 545 | } |
| 546 | |
| 547 | return getField; |
| 548 | } |
| 549 | |
| 550 | /** |
| 551 | * Register an object to be validated before the graph is returned. While |
| 552 | * similar to resolveObject these validations are called after the entire |
| 553 | * graph has been reconstituted. Typically, a readObject method will |
| 554 | * register the object with the stream so that when all of the objects are |
| 555 | * restored a final set of validations can be performed. |
| 556 | * |
| 557 | * @param obj the object to receive the validation callback. |
| 558 | * @param prio controls the order of callbacks;zero is a good default. |
| 559 | * Use higher numbers to be called back earlier, lower numbers for |
| 560 | * later callbacks. Within a priority, callbacks are processed in |
| 561 | * no particular order. |
| 562 | * @throws NotActiveException The stream is not currently reading objects |
| 563 | * so it is invalid to register a callback. |
| 564 | * @throws InvalidObjectException The validation object is null. |
| 565 | */ |
| 566 | public void registerValidation(ObjectInputValidation obj, int prio) |
| 567 | throws NotActiveException, InvalidObjectException |
| 568 | { |
| 569 | if (depth == 0) { |
| 570 | throw new NotActiveException("stream inactive"); |
| 571 | } |
| 572 | vlist.register(obj, prio); |
| 573 | } |
| 574 | |
| 575 | /** |
| 576 | * Load the local class equivalent of the specified stream class |
| 577 | * description. Subclasses may implement this method to allow classes to |
| 578 | * be fetched from an alternate source. |
| 579 | * |
| 580 | * <p>The corresponding method in <code>ObjectOutputStream</code> is |
| 581 | * <code>annotateClass</code>. This method will be invoked only once for |
| 582 | * each unique class in the stream. This method can be implemented by |
| 583 | * subclasses to use an alternate loading mechanism but must return a |
| 584 | * <code>Class</code> object. Once returned, if the class is not an array |
| 585 | * class, its serialVersionUID is compared to the serialVersionUID of the |
| 586 | * serialized class, and if there is a mismatch, the deserialization fails |
| 587 | * and an {@link InvalidClassException} is thrown. |
| 588 | * |
| 589 | * <p>The default implementation of this method in |
| 590 | * <code>ObjectInputStream</code> returns the result of calling |
| 591 | * <pre> |
| 592 | * Class.forName(desc.getName(), false, loader) |
| 593 | * </pre> |
| 594 | * where <code>loader</code> is determined as follows: if there is a |
| 595 | * method on the current thread's stack whose declaring class was |
| 596 | * defined by a user-defined class loader (and was not a generated to |
| 597 | * implement reflective invocations), then <code>loader</code> is class |
| 598 | * loader corresponding to the closest such method to the currently |
| 599 | * executing frame; otherwise, <code>loader</code> is |
| 600 | * <code>null</code>. If this call results in a |
| 601 | * <code>ClassNotFoundException</code> and the name of the passed |
| 602 | * <code>ObjectStreamClass</code> instance is the Java language keyword |
| 603 | * for a primitive type or void, then the <code>Class</code> object |
| 604 | * representing that primitive type or void will be returned |
| 605 | * (e.g., an <code>ObjectStreamClass</code> with the name |
| 606 | * <code>"int"</code> will be resolved to <code>Integer.TYPE</code>). |
| 607 | * Otherwise, the <code>ClassNotFoundException</code> will be thrown to |
| 608 | * the caller of this method. |
| 609 | * |
| 610 | * @param desc an instance of class <code>ObjectStreamClass</code> |
| 611 | * @return a <code>Class</code> object corresponding to <code>desc</code> |
| 612 | * @throws IOException any of the usual Input/Output exceptions. |
| 613 | * @throws ClassNotFoundException if class of a serialized object cannot |
| 614 | * be found. |
| 615 | */ |
| 616 | protected Class<?> resolveClass(ObjectStreamClass desc) |
| 617 | throws IOException, ClassNotFoundException |
| 618 | { |
| 619 | String name = desc.getName(); |
| 620 | try { |
| 621 | return Class.forName(name, false, latestUserDefinedLoader()); |
| 622 | } catch (ClassNotFoundException ex) { |
| 623 | Class cl = (Class) primClasses.get(name); |
| 624 | if (cl != null) { |
| 625 | return cl; |
| 626 | } else { |
| 627 | throw ex; |
| 628 | } |
| 629 | } |
| 630 | } |
| 631 | |
| 632 | /** |
| 633 | * Returns a proxy class that implements the interfaces named in a proxy |
| 634 | * class descriptor; subclasses may implement this method to read custom |
| 635 | * data from the stream along with the descriptors for dynamic proxy |
| 636 | * classes, allowing them to use an alternate loading mechanism for the |
| 637 | * interfaces and the proxy class. |
| 638 | * |
| 639 | * <p>This method is called exactly once for each unique proxy class |
| 640 | * descriptor in the stream. |
| 641 | * |
| 642 | * <p>The corresponding method in <code>ObjectOutputStream</code> is |
| 643 | * <code>annotateProxyClass</code>. For a given subclass of |
| 644 | * <code>ObjectInputStream</code> that overrides this method, the |
| 645 | * <code>annotateProxyClass</code> method in the corresponding subclass of |
| 646 | * <code>ObjectOutputStream</code> must write any data or objects read by |
| 647 | * this method. |
| 648 | * |
| 649 | * <p>The default implementation of this method in |
| 650 | * <code>ObjectInputStream</code> returns the result of calling |
| 651 | * <code>Proxy.getProxyClass</code> with the list of <code>Class</code> |
| 652 | * objects for the interfaces that are named in the <code>interfaces</code> |
| 653 | * parameter. The <code>Class</code> object for each interface name |
| 654 | * <code>i</code> is the value returned by calling |
| 655 | * <pre> |
| 656 | * Class.forName(i, false, loader) |
| 657 | * </pre> |
| 658 | * where <code>loader</code> is that of the first non-<code>null</code> |
| 659 | * class loader up the execution stack, or <code>null</code> if no |
| 660 | * non-<code>null</code> class loaders are on the stack (the same class |
| 661 | * loader choice used by the <code>resolveClass</code> method). Unless any |
| 662 | * of the resolved interfaces are non-public, this same value of |
| 663 | * <code>loader</code> is also the class loader passed to |
| 664 | * <code>Proxy.getProxyClass</code>; if non-public interfaces are present, |
| 665 | * their class loader is passed instead (if more than one non-public |
| 666 | * interface class loader is encountered, an |
| 667 | * <code>IllegalAccessError</code> is thrown). |
| 668 | * If <code>Proxy.getProxyClass</code> throws an |
| 669 | * <code>IllegalArgumentException</code>, <code>resolveProxyClass</code> |
| 670 | * will throw a <code>ClassNotFoundException</code> containing the |
| 671 | * <code>IllegalArgumentException</code>. |
| 672 | * |
| 673 | * @param interfaces the list of interface names that were |
| 674 | * deserialized in the proxy class descriptor |
| 675 | * @return a proxy class for the specified interfaces |
| 676 | * @throws IOException any exception thrown by the underlying |
| 677 | * <code>InputStream</code> |
| 678 | * @throws ClassNotFoundException if the proxy class or any of the |
| 679 | * named interfaces could not be found |
| 680 | * @see ObjectOutputStream#annotateProxyClass(Class) |
| 681 | * @since 1.3 |
| 682 | */ |
| 683 | protected Class<?> resolveProxyClass(String[] interfaces) |
| 684 | throws IOException, ClassNotFoundException |
| 685 | { |
| 686 | ClassLoader latestLoader = latestUserDefinedLoader(); |
| 687 | ClassLoader nonPublicLoader = null; |
| 688 | boolean hasNonPublicInterface = false; |
| 689 | |
| 690 | // define proxy in class loader of non-public interface(s), if any |
| 691 | Class[] classObjs = new Class[interfaces.length]; |
| 692 | for (int i = 0; i < interfaces.length; i++) { |
| 693 | Class cl = Class.forName(interfaces[i], false, latestLoader); |
| 694 | if ((cl.getModifiers() & Modifier.PUBLIC) == 0) { |
| 695 | if (hasNonPublicInterface) { |
| 696 | if (nonPublicLoader != cl.getClassLoader()) { |
| 697 | throw new IllegalAccessError( |
| 698 | "conflicting non-public interface class loaders"); |
| 699 | } |
| 700 | } else { |
| 701 | nonPublicLoader = cl.getClassLoader(); |
| 702 | hasNonPublicInterface = true; |
| 703 | } |
| 704 | } |
| 705 | classObjs[i] = cl; |
| 706 | } |
| 707 | try { |
| 708 | return Proxy.getProxyClass( |
| 709 | hasNonPublicInterface ? nonPublicLoader : latestLoader, |
| 710 | classObjs); |
| 711 | } catch (IllegalArgumentException e) { |
| 712 | throw new ClassNotFoundException(null, e); |
| 713 | } |
| 714 | } |
| 715 | |
| 716 | /** |
| 717 | * This method will allow trusted subclasses of ObjectInputStream to |
| 718 | * substitute one object for another during deserialization. Replacing |
| 719 | * objects is disabled until enableResolveObject is called. The |
| 720 | * enableResolveObject method checks that the stream requesting to resolve |
| 721 | * object can be trusted. Every reference to serializable objects is passed |
| 722 | * to resolveObject. To insure that the private state of objects is not |
| 723 | * unintentionally exposed only trusted streams may use resolveObject. |
| 724 | * |
| 725 | * <p>This method is called after an object has been read but before it is |
| 726 | * returned from readObject. The default resolveObject method just returns |
| 727 | * the same object. |
| 728 | * |
| 729 | * <p>When a subclass is replacing objects it must insure that the |
| 730 | * substituted object is compatible with every field where the reference |
| 731 | * will be stored. Objects whose type is not a subclass of the type of the |
| 732 | * field or array element abort the serialization by raising an exception |
| 733 | * and the object is not be stored. |
| 734 | * |
| 735 | * <p>This method is called only once when each object is first |
| 736 | * encountered. All subsequent references to the object will be redirected |
| 737 | * to the new object. |
| 738 | * |
| 739 | * @param obj object to be substituted |
| 740 | * @return the substituted object |
| 741 | * @throws IOException Any of the usual Input/Output exceptions. |
| 742 | */ |
| 743 | protected Object resolveObject(Object obj) throws IOException { |
| 744 | return obj; |
| 745 | } |
| 746 | |
| 747 | /** |
| 748 | * Enable the stream to allow objects read from the stream to be replaced. |
| 749 | * When enabled, the resolveObject method is called for every object being |
| 750 | * deserialized. |
| 751 | * |
| 752 | * <p>If <i>enable</i> is true, and there is a security manager installed, |
| 753 | * this method first calls the security manager's |
| 754 | * <code>checkPermission</code> method with the |
| 755 | * <code>SerializablePermission("enableSubstitution")</code> permission to |
| 756 | * ensure it's ok to enable the stream to allow objects read from the |
| 757 | * stream to be replaced. |
| 758 | * |
| 759 | * @param enable true for enabling use of <code>resolveObject</code> for |
| 760 | * every object being deserialized |
| 761 | * @return the previous setting before this method was invoked |
| 762 | * @throws SecurityException if a security manager exists and its |
| 763 | * <code>checkPermission</code> method denies enabling the stream |
| 764 | * to allow objects read from the stream to be replaced. |
| 765 | * @see SecurityManager#checkPermission |
| 766 | * @see java.io.SerializablePermission |
| 767 | */ |
| 768 | protected boolean enableResolveObject(boolean enable) |
| 769 | throws SecurityException |
| 770 | { |
| 771 | if (enable == enableResolve) { |
| 772 | return enable; |
| 773 | } |
| 774 | if (enable) { |
| 775 | SecurityManager sm = System.getSecurityManager(); |
| 776 | if (sm != null) { |
| 777 | sm.checkPermission(SUBSTITUTION_PERMISSION); |
| 778 | } |
| 779 | } |
| 780 | enableResolve = enable; |
| 781 | return !enableResolve; |
| 782 | } |
| 783 | |
| 784 | /** |
| 785 | * The readStreamHeader method is provided to allow subclasses to read and |
| 786 | * verify their own stream headers. It reads and verifies the magic number |
| 787 | * and version number. |
| 788 | * |
| 789 | * @throws IOException if there are I/O errors while reading from the |
| 790 | * underlying <code>InputStream</code> |
| 791 | * @throws StreamCorruptedException if control information in the stream |
| 792 | * is inconsistent |
| 793 | */ |
| 794 | protected void readStreamHeader() |
| 795 | throws IOException, StreamCorruptedException |
| 796 | { |
| 797 | short s0 = bin.readShort(); |
| 798 | short s1 = bin.readShort(); |
| 799 | if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) { |
| 800 | throw new StreamCorruptedException( |
| 801 | String.format("invalid stream header: %04X%04X", s0, s1)); |
| 802 | } |
| 803 | } |
| 804 | |
| 805 | /** |
| 806 | * Read a class descriptor from the serialization stream. This method is |
| 807 | * called when the ObjectInputStream expects a class descriptor as the next |
| 808 | * item in the serialization stream. Subclasses of ObjectInputStream may |
| 809 | * override this method to read in class descriptors that have been written |
| 810 | * in non-standard formats (by subclasses of ObjectOutputStream which have |
| 811 | * overridden the <code>writeClassDescriptor</code> method). By default, |
| 812 | * this method reads class descriptors according to the format defined in |
| 813 | * the Object Serialization specification. |
| 814 | * |
| 815 | * @return the class descriptor read |
| 816 | * @throws IOException If an I/O error has occurred. |
| 817 | * @throws ClassNotFoundException If the Class of a serialized object used |
| 818 | * in the class descriptor representation cannot be found |
| 819 | * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass) |
| 820 | * @since 1.3 |
| 821 | */ |
| 822 | protected ObjectStreamClass readClassDescriptor() |
| 823 | throws IOException, ClassNotFoundException |
| 824 | { |
| 825 | ObjectStreamClass desc = new ObjectStreamClass(); |
| 826 | desc.readNonProxy(this); |
| 827 | return desc; |
| 828 | } |
| 829 | |
| 830 | /** |
| 831 | * Reads a byte of data. This method will block if no input is available. |
| 832 | * |
| 833 | * @return the byte read, or -1 if the end of the stream is reached. |
| 834 | * @throws IOException If an I/O error has occurred. |
| 835 | */ |
| 836 | public int read() throws IOException { |
| 837 | return bin.read(); |
| 838 | } |
| 839 | |
| 840 | /** |
| 841 | * Reads into an array of bytes. This method will block until some input |
| 842 | * is available. Consider using java.io.DataInputStream.readFully to read |
| 843 | * exactly 'length' bytes. |
| 844 | * |
| 845 | * @param buf the buffer into which the data is read |
| 846 | * @param off the start offset of the data |
| 847 | * @param len the maximum number of bytes read |
| 848 | * @return the actual number of bytes read, -1 is returned when the end of |
| 849 | * the stream is reached. |
| 850 | * @throws IOException If an I/O error has occurred. |
| 851 | * @see java.io.DataInputStream#readFully(byte[],int,int) |
| 852 | */ |
| 853 | public int read(byte[] buf, int off, int len) throws IOException { |
| 854 | if (buf == null) { |
| 855 | throw new NullPointerException(); |
| 856 | } |
| 857 | int endoff = off + len; |
| 858 | if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) { |
| 859 | throw new IndexOutOfBoundsException(); |
| 860 | } |
| 861 | return bin.read(buf, off, len, false); |
| 862 | } |
| 863 | |
| 864 | /** |
| 865 | * Returns the number of bytes that can be read without blocking. |
| 866 | * |
| 867 | * @return the number of available bytes. |
| 868 | * @throws IOException if there are I/O errors while reading from the |
| 869 | * underlying <code>InputStream</code> |
| 870 | */ |
| 871 | public int available() throws IOException { |
| 872 | return bin.available(); |
| 873 | } |
| 874 | |
| 875 | /** |
| 876 | * Closes the input stream. Must be called to release any resources |
| 877 | * associated with the stream. |
| 878 | * |
| 879 | * @throws IOException If an I/O error has occurred. |
| 880 | */ |
| 881 | public void close() throws IOException { |
| 882 | /* |
| 883 | * Even if stream already closed, propagate redundant close to |
| 884 | * underlying stream to stay consistent with previous implementations. |
| 885 | */ |
| 886 | closed = true; |
| 887 | if (depth == 0) { |
| 888 | clear(); |
| 889 | } |
| 890 | bin.close(); |
| 891 | } |
| 892 | |
| 893 | /** |
| 894 | * Reads in a boolean. |
| 895 | * |
| 896 | * @return the boolean read. |
| 897 | * @throws EOFException If end of file is reached. |
| 898 | * @throws IOException If other I/O error has occurred. |
| 899 | */ |
| 900 | public boolean readBoolean() throws IOException { |
| 901 | return bin.readBoolean(); |
| 902 | } |
| 903 | |
| 904 | /** |
| 905 | * Reads an 8 bit byte. |
| 906 | * |
| 907 | * @return the 8 bit byte read. |
| 908 | * @throws EOFException If end of file is reached. |
| 909 | * @throws IOException If other I/O error has occurred. |
| 910 | */ |
| 911 | public byte readByte() throws IOException { |
| 912 | return bin.readByte(); |
| 913 | } |
| 914 | |
| 915 | /** |
| 916 | * Reads an unsigned 8 bit byte. |
| 917 | * |
| 918 | * @return the 8 bit byte read. |
| 919 | * @throws EOFException If end of file is reached. |
| 920 | * @throws IOException If other I/O error has occurred. |
| 921 | */ |
| 922 | public int readUnsignedByte() throws IOException { |
| 923 | return bin.readUnsignedByte(); |
| 924 | } |
| 925 | |
| 926 | /** |
| 927 | * Reads a 16 bit char. |
| 928 | * |
| 929 | * @return the 16 bit char read. |
| 930 | * @throws EOFException If end of file is reached. |
| 931 | * @throws IOException If other I/O error has occurred. |
| 932 | */ |
| 933 | public char readChar() throws IOException { |
| 934 | return bin.readChar(); |
| 935 | } |
| 936 | |
| 937 | /** |
| 938 | * Reads a 16 bit short. |
| 939 | * |
| 940 | * @return the 16 bit short read. |
| 941 | * @throws EOFException If end of file is reached. |
| 942 | * @throws IOException If other I/O error has occurred. |
| 943 | */ |
| 944 | public short readShort() throws IOException { |
| 945 | return bin.readShort(); |
| 946 | } |
| 947 | |
| 948 | /** |
| 949 | * Reads an unsigned 16 bit short. |
| 950 | * |
| 951 | * @return the 16 bit short read. |
| 952 | * @throws EOFException If end of file is reached. |
| 953 | * @throws IOException If other I/O error has occurred. |
| 954 | */ |
| 955 | public int readUnsignedShort() throws IOException { |
| 956 | return bin.readUnsignedShort(); |
| 957 | } |
| 958 | |
| 959 | /** |
| 960 | * Reads a 32 bit int. |
| 961 | * |
| 962 | * @return the 32 bit integer read. |
| 963 | * @throws EOFException If end of file is reached. |
| 964 | * @throws IOException If other I/O error has occurred. |
| 965 | */ |
| 966 | public int readInt() throws IOException { |
| 967 | return bin.readInt(); |
| 968 | } |
| 969 | |
| 970 | /** |
| 971 | * Reads a 64 bit long. |
| 972 | * |
| 973 | * @return the read 64 bit long. |
| 974 | * @throws EOFException If end of file is reached. |
| 975 | * @throws IOException If other I/O error has occurred. |
| 976 | */ |
| 977 | public long readLong() throws IOException { |
| 978 | return bin.readLong(); |
| 979 | } |
| 980 | |
| 981 | /** |
| 982 | * Reads a 32 bit float. |
| 983 | * |
| 984 | * @return the 32 bit float read. |
| 985 | * @throws EOFException If end of file is reached. |
| 986 | * @throws IOException If other I/O error has occurred. |
| 987 | */ |
| 988 | public float readFloat() throws IOException { |
| 989 | return bin.readFloat(); |
| 990 | } |
| 991 | |
| 992 | /** |
| 993 | * Reads a 64 bit double. |
| 994 | * |
| 995 | * @return the 64 bit double read. |
| 996 | * @throws EOFException If end of file is reached. |
| 997 | * @throws IOException If other I/O error has occurred. |
| 998 | */ |
| 999 | public double readDouble() throws IOException { |
| 1000 | return bin.readDouble(); |
| 1001 | } |
| 1002 | |
| 1003 | /** |
| 1004 | * Reads bytes, blocking until all bytes are read. |
| 1005 | * |
| 1006 | * @param buf the buffer into which the data is read |
| 1007 | * @throws EOFException If end of file is reached. |
| 1008 | * @throws IOException If other I/O error has occurred. |
| 1009 | */ |
| 1010 | public void readFully(byte[] buf) throws IOException { |
| 1011 | bin.readFully(buf, 0, buf.length, false); |
| 1012 | } |
| 1013 | |
| 1014 | /** |
| 1015 | * Reads bytes, blocking until all bytes are read. |
| 1016 | * |
| 1017 | * @param buf the buffer into which the data is read |
| 1018 | * @param off the start offset of the data |
| 1019 | * @param len the maximum number of bytes to read |
| 1020 | * @throws EOFException If end of file is reached. |
| 1021 | * @throws IOException If other I/O error has occurred. |
| 1022 | */ |
| 1023 | public void readFully(byte[] buf, int off, int len) throws IOException { |
| 1024 | int endoff = off + len; |
| 1025 | if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) { |
| 1026 | throw new IndexOutOfBoundsException(); |
| 1027 | } |
| 1028 | bin.readFully(buf, off, len, false); |
| 1029 | } |
| 1030 | |
| 1031 | /** |
| 1032 | * Skips bytes. |
| 1033 | * |
| 1034 | * @param len the number of bytes to be skipped |
| 1035 | * @return the actual number of bytes skipped. |
| 1036 | * @throws IOException If an I/O error has occurred. |
| 1037 | */ |
| 1038 | public int skipBytes(int len) throws IOException { |
| 1039 | return bin.skipBytes(len); |
| 1040 | } |
| 1041 | |
| 1042 | /** |
| 1043 | * Reads in a line that has been terminated by a \n, \r, \r\n or EOF. |
| 1044 | * |
| 1045 | * @return a String copy of the line. |
| 1046 | * @throws IOException if there are I/O errors while reading from the |
| 1047 | * underlying <code>InputStream</code> |
| 1048 | * @deprecated This method does not properly convert bytes to characters. |
| 1049 | * see DataInputStream for the details and alternatives. |
| 1050 | */ |
| 1051 | @Deprecated |
| 1052 | public String readLine() throws IOException { |
| 1053 | return bin.readLine(); |
| 1054 | } |
| 1055 | |
| 1056 | /** |
| 1057 | * Reads a String in |
| 1058 | * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> |
| 1059 | * format. |
| 1060 | * |
| 1061 | * @return the String. |
| 1062 | * @throws IOException if there are I/O errors while reading from the |
| 1063 | * underlying <code>InputStream</code> |
| 1064 | * @throws UTFDataFormatException if read bytes do not represent a valid |
| 1065 | * modified UTF-8 encoding of a string |
| 1066 | */ |
| 1067 | public String readUTF() throws IOException { |
| 1068 | return bin.readUTF(); |
| 1069 | } |
| 1070 | |
| 1071 | /** |
| 1072 | * Provide access to the persistent fields read from the input stream. |
| 1073 | */ |
| 1074 | public static abstract class GetField { |
| 1075 | |
| 1076 | /** |
| 1077 | * Get the ObjectStreamClass that describes the fields in the stream. |
| 1078 | * |
| 1079 | * @return the descriptor class that describes the serializable fields |
| 1080 | */ |
| 1081 | public abstract ObjectStreamClass getObjectStreamClass(); |
| 1082 | |
| 1083 | /** |
| 1084 | * Return true if the named field is defaulted and has no value in this |
| 1085 | * stream. |
| 1086 | * |
| 1087 | * @param name the name of the field |
| 1088 | * @return true, if and only if the named field is defaulted |
| 1089 | * @throws IOException if there are I/O errors while reading from |
| 1090 | * the underlying <code>InputStream</code> |
| 1091 | * @throws IllegalArgumentException if <code>name</code> does not |
| 1092 | * correspond to a serializable field |
| 1093 | */ |
| 1094 | public abstract boolean defaulted(String name) throws IOException; |
| 1095 | |
| 1096 | /** |
| 1097 | * Get the value of the named boolean field from the persistent field. |
| 1098 | * |
| 1099 | * @param name the name of the field |
| 1100 | * @param val the default value to use if <code>name</code> does not |
| 1101 | * have a value |
| 1102 | * @return the value of the named <code>boolean</code> field |
| 1103 | * @throws IOException if there are I/O errors while reading from the |
| 1104 | * underlying <code>InputStream</code> |
| 1105 | * @throws IllegalArgumentException if type of <code>name</code> is |
| 1106 | * not serializable or if the field type is incorrect |
| 1107 | */ |
| 1108 | public abstract boolean get(String name, boolean val) |
| 1109 | throws IOException; |
| 1110 | |
| 1111 | /** |
| 1112 | * Get the value of the named byte field from the persistent field. |
| 1113 | * |
| 1114 | * @param name the name of the field |
| 1115 | * @param val the default value to use if <code>name</code> does not |
| 1116 | * have a value |
| 1117 | * @return the value of the named <code>byte</code> field |
| 1118 | * @throws IOException if there are I/O errors while reading from the |
| 1119 | * underlying <code>InputStream</code> |
| 1120 | * @throws IllegalArgumentException if type of <code>name</code> is |
| 1121 | * not serializable or if the field type is incorrect |
| 1122 | */ |
| 1123 | public abstract byte get(String name, byte val) throws IOException; |
| 1124 | |
| 1125 | /** |
| 1126 | * Get the value of the named char field from the persistent field. |
| 1127 | * |
| 1128 | * @param name the name of the field |
| 1129 | * @param val the default value to use if <code>name</code> does not |
| 1130 | * have a value |
| 1131 | * @return the value of the named <code>char</code> field |
| 1132 | * @throws IOException if there are I/O errors while reading from the |
| 1133 | * underlying <code>InputStream</code> |
| 1134 | * @throws IllegalArgumentException if type of <code>name</code> is |
| 1135 | * not serializable or if the field type is incorrect |
| 1136 | */ |
| 1137 | public abstract char get(String name, char val) throws IOException; |
| 1138 | |
| 1139 | /** |
| 1140 | * Get the value of the named short field from the persistent field. |
| 1141 | * |
| 1142 | * @param name the name of the field |
| 1143 | * @param val the default value to use if <code>name</code> does not |
| 1144 | * have a value |
| 1145 | * @return the value of the named <code>short</code> field |
| 1146 | * @throws IOException if there are I/O errors while reading from the |
| 1147 | * underlying <code>InputStream</code> |
| 1148 | * @throws IllegalArgumentException if type of <code>name</code> is |
| 1149 | * not serializable or if the field type is incorrect |
| 1150 | */ |
| 1151 | public abstract short get(String name, short val) throws IOException; |
| 1152 | |
| 1153 | /** |
| 1154 | * Get the value of the named int field from the persistent field. |
| 1155 | * |
| 1156 | * @param name the name of the field |
| 1157 | * @param val the default value to use if <code>name</code> does not |
| 1158 | * have a value |
| 1159 | * @return the value of the named <code>int</code> field |
| 1160 | * @throws IOException if there are I/O errors while reading from the |
| 1161 | * underlying <code>InputStream</code> |
| 1162 | * @throws IllegalArgumentException if type of <code>name</code> is |
| 1163 | * not serializable or if the field type is incorrect |
| 1164 | */ |
| 1165 | public abstract int get(String name, int val) throws IOException; |
| 1166 | |
| 1167 | /** |
| 1168 | * Get the value of the named long field from the persistent field. |
| 1169 | * |
| 1170 | * @param name the name of the field |
| 1171 | * @param val the default value to use if <code>name</code> does not |
| 1172 | * have a value |
| 1173 | * @return the value of the named <code>long</code> field |
| 1174 | * @throws IOException if there are I/O errors while reading from the |
| 1175 | * underlying <code>InputStream</code> |
| 1176 | * @throws IllegalArgumentException if type of <code>name</code> is |
| 1177 | * not serializable or if the field type is incorrect |
| 1178 | */ |
| 1179 | public abstract long get(String name, long val) throws IOException; |
| 1180 | |
| 1181 | /** |
| 1182 | * Get the value of the named float field from the persistent field. |
| 1183 | * |
| 1184 | * @param name the name of the field |
| 1185 | * @param val the default value to use if <code>name</code> does not |
| 1186 | * have a value |
| 1187 | * @return the value of the named <code>float</code> field |
| 1188 | * @throws IOException if there are I/O errors while reading from the |
| 1189 | * underlying <code>InputStream</code> |
| 1190 | * @throws IllegalArgumentException if type of <code>name</code> is |
| 1191 | * not serializable or if the field type is incorrect |
| 1192 | */ |
| 1193 | public abstract float get(String name, float val) throws IOException; |
| 1194 | |
| 1195 | /** |
| 1196 | * Get the value of the named double field from the persistent field. |
| 1197 | * |
| 1198 | * @param name the name of the field |
| 1199 | * @param val the default value to use if <code>name</code> does not |
| 1200 | * have a value |
| 1201 | * @return the value of the named <code>double</code> field |
| 1202 | * @throws IOException if there are I/O errors while reading from the |
| 1203 | * underlying <code>InputStream</code> |
| 1204 | * @throws IllegalArgumentException if type of <code>name</code> is |
| 1205 | * not serializable or if the field type is incorrect |
| 1206 | */ |
| 1207 | public abstract double get(String name, double val) throws IOException; |
| 1208 | |
| 1209 | /** |
| 1210 | * Get the value of the named Object field from the persistent field. |
| 1211 | * |
| 1212 | * @param name the name of the field |
| 1213 | * @param val the default value to use if <code>name</code> does not |
| 1214 | * have a value |
| 1215 | * @return the value of the named <code>Object</code> field |
| 1216 | * @throws IOException if there are I/O errors while reading from the |
| 1217 | * underlying <code>InputStream</code> |
| 1218 | * @throws IllegalArgumentException if type of <code>name</code> is |
| 1219 | * not serializable or if the field type is incorrect |
| 1220 | */ |
| 1221 | public abstract Object get(String name, Object val) throws IOException; |
| 1222 | } |
| 1223 | |
| 1224 | /** |
| 1225 | * Verifies that this (possibly subclass) instance can be constructed |
| 1226 | * without violating security constraints: the subclass must not override |
| 1227 | * security-sensitive non-final methods, or else the |
| 1228 | * "enableSubclassImplementation" SerializablePermission is checked. |
| 1229 | */ |
| 1230 | private void verifySubclass() { |
| 1231 | Class cl = getClass(); |
| 1232 | if (cl == ObjectInputStream.class) { |
| 1233 | return; |
| 1234 | } |
| 1235 | SecurityManager sm = System.getSecurityManager(); |
| 1236 | if (sm == null) { |
| 1237 | return; |
| 1238 | } |
| 1239 | processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); |
| 1240 | WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); |
| 1241 | Boolean result = Caches.subclassAudits.get(key); |
| 1242 | if (result == null) { |
| 1243 | result = Boolean.valueOf(auditSubclass(cl)); |
| 1244 | Caches.subclassAudits.putIfAbsent(key, result); |
| 1245 | } |
| 1246 | if (result.booleanValue()) { |
| 1247 | return; |
| 1248 | } |
| 1249 | sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); |
| 1250 | } |
| 1251 | |
| 1252 | /** |
| 1253 | * Performs reflective checks on given subclass to verify that it doesn't |
| 1254 | * override security-sensitive non-final methods. Returns true if subclass |
| 1255 | * is "safe", false otherwise. |
| 1256 | */ |
| 1257 | private static boolean auditSubclass(final Class subcl) { |
| 1258 | Boolean result = AccessController.doPrivileged( |
| 1259 | new PrivilegedAction<Boolean>() { |
| 1260 | public Boolean run() { |
| 1261 | for (Class cl = subcl; |
| 1262 | cl != ObjectInputStream.class; |
| 1263 | cl = cl.getSuperclass()) |
| 1264 | { |
| 1265 | try { |
| 1266 | cl.getDeclaredMethod( |
| 1267 | "readUnshared", (Class[]) null); |
| 1268 | return Boolean.FALSE; |
| 1269 | } catch (NoSuchMethodException ex) { |
| 1270 | } |
| 1271 | try { |
| 1272 | cl.getDeclaredMethod("readFields", (Class[]) null); |
| 1273 | return Boolean.FALSE; |
| 1274 | } catch (NoSuchMethodException ex) { |
| 1275 | } |
| 1276 | } |
| 1277 | return Boolean.TRUE; |
| 1278 | } |
| 1279 | } |
| 1280 | ); |
| 1281 | return result.booleanValue(); |
| 1282 | } |
| 1283 | |
| 1284 | /** |
| 1285 | * Clears internal data structures. |
| 1286 | */ |
| 1287 | private void clear() { |
| 1288 | handles.clear(); |
| 1289 | vlist.clear(); |
| 1290 | } |
| 1291 | |
| 1292 | /** |
| 1293 | * Underlying readObject implementation. |
| 1294 | */ |
| 1295 | private Object readObject0(boolean unshared) throws IOException { |
| 1296 | boolean oldMode = bin.getBlockDataMode(); |
| 1297 | if (oldMode) { |
| 1298 | int remain = bin.currentBlockRemaining(); |
| 1299 | if (remain > 0) { |
| 1300 | throw new OptionalDataException(remain); |
| 1301 | } else if (defaultDataEnd) { |
| 1302 | /* |
| 1303 | * Fix for 4360508: stream is currently at the end of a field |
| 1304 | * value block written via default serialization; since there |
| 1305 | * is no terminating TC_ENDBLOCKDATA tag, simulate |
| 1306 | * end-of-custom-data behavior explicitly. |
| 1307 | */ |
| 1308 | throw new OptionalDataException(true); |
| 1309 | } |
| 1310 | bin.setBlockDataMode(false); |
| 1311 | } |
| 1312 | |
| 1313 | byte tc; |
| 1314 | while ((tc = bin.peekByte()) == TC_RESET) { |
| 1315 | bin.readByte(); |
| 1316 | handleReset(); |
| 1317 | } |
| 1318 | |
| 1319 | depth++; |
| 1320 | try { |
| 1321 | switch (tc) { |
| 1322 | case TC_NULL: |
| 1323 | return readNull(); |
| 1324 | |
| 1325 | case TC_REFERENCE: |
| 1326 | return readHandle(unshared); |
| 1327 | |
| 1328 | case TC_CLASS: |
| 1329 | return readClass(unshared); |
| 1330 | |
| 1331 | case TC_CLASSDESC: |
| 1332 | case TC_PROXYCLASSDESC: |
| 1333 | return readClassDesc(unshared); |
| 1334 | |
| 1335 | case TC_STRING: |
| 1336 | case TC_LONGSTRING: |
| 1337 | return checkResolve(readString(unshared)); |
| 1338 | |
| 1339 | case TC_ARRAY: |
| 1340 | return checkResolve(readArray(unshared)); |
| 1341 | |
| 1342 | case TC_ENUM: |
| 1343 | return checkResolve(readEnum(unshared)); |
| 1344 | |
| 1345 | case TC_OBJECT: |
| 1346 | return checkResolve(readOrdinaryObject(unshared)); |
| 1347 | |
| 1348 | case TC_EXCEPTION: |
| 1349 | IOException ex = readFatalException(); |
| 1350 | throw new WriteAbortedException("writing aborted", ex); |
| 1351 | |
| 1352 | case TC_BLOCKDATA: |
| 1353 | case TC_BLOCKDATALONG: |
| 1354 | if (oldMode) { |
| 1355 | bin.setBlockDataMode(true); |
| 1356 | bin.peek(); // force header read |
| 1357 | throw new OptionalDataException( |
| 1358 | bin.currentBlockRemaining()); |
| 1359 | } else { |
| 1360 | throw new StreamCorruptedException( |
| 1361 | "unexpected block data"); |
| 1362 | } |
| 1363 | |
| 1364 | case TC_ENDBLOCKDATA: |
| 1365 | if (oldMode) { |
| 1366 | throw new OptionalDataException(true); |
| 1367 | } else { |
| 1368 | throw new StreamCorruptedException( |
| 1369 | "unexpected end of block data"); |
| 1370 | } |
| 1371 | |
| 1372 | default: |
| 1373 | throw new StreamCorruptedException( |
| 1374 | String.format("invalid type code: %02X", tc)); |
| 1375 | } |
| 1376 | } finally { |
| 1377 | depth--; |
| 1378 | bin.setBlockDataMode(oldMode); |
| 1379 | } |
| 1380 | } |
| 1381 | |
| 1382 | /** |
| 1383 | * If resolveObject has been enabled and given object does not have an |
| 1384 | * exception associated with it, calls resolveObject to determine |
| 1385 | * replacement for object, and updates handle table accordingly. Returns |
| 1386 | * replacement object, or echoes provided object if no replacement |
| 1387 | * occurred. Expects that passHandle is set to given object's handle prior |
| 1388 | * to calling this method. |
| 1389 | */ |
| 1390 | private Object checkResolve(Object obj) throws IOException { |
| 1391 | if (!enableResolve || handles.lookupException(passHandle) != null) { |
| 1392 | return obj; |
| 1393 | } |
| 1394 | Object rep = resolveObject(obj); |
| 1395 | if (rep != obj) { |
| 1396 | handles.setObject(passHandle, rep); |
| 1397 | } |
| 1398 | return rep; |
| 1399 | } |
| 1400 | |
| 1401 | /** |
| 1402 | * Reads string without allowing it to be replaced in stream. Called from |
| 1403 | * within ObjectStreamClass.read(). |
| 1404 | */ |
| 1405 | String readTypeString() throws IOException { |
| 1406 | int oldHandle = passHandle; |
| 1407 | try { |
| 1408 | byte tc = bin.peekByte(); |
| 1409 | switch (tc) { |
| 1410 | case TC_NULL: |
| 1411 | return (String) readNull(); |
| 1412 | |
| 1413 | case TC_REFERENCE: |
| 1414 | return (String) readHandle(false); |
| 1415 | |
| 1416 | case TC_STRING: |
| 1417 | case TC_LONGSTRING: |
| 1418 | return readString(false); |
| 1419 | |
| 1420 | default: |
| 1421 | throw new StreamCorruptedException( |
| 1422 | String.format("invalid type code: %02X", tc)); |
| 1423 | } |
| 1424 | } finally { |
| 1425 | passHandle = oldHandle; |
| 1426 | } |
| 1427 | } |
| 1428 | |
| 1429 | /** |
| 1430 | * Reads in null code, sets passHandle to NULL_HANDLE and returns null. |
| 1431 | */ |
| 1432 | private Object readNull() throws IOException { |
| 1433 | if (bin.readByte() != TC_NULL) { |
| 1434 | throw new InternalError(); |
| 1435 | } |
| 1436 | passHandle = NULL_HANDLE; |
| 1437 | return null; |
| 1438 | } |
| 1439 | |
| 1440 | /** |
| 1441 | * Reads in object handle, sets passHandle to the read handle, and returns |
| 1442 | * object associated with the handle. |
| 1443 | */ |
| 1444 | private Object readHandle(boolean unshared) throws IOException { |
| 1445 | if (bin.readByte() != TC_REFERENCE) { |
| 1446 | throw new InternalError(); |
| 1447 | } |
| 1448 | passHandle = bin.readInt() - baseWireHandle; |
| 1449 | if (passHandle < 0 || passHandle >= handles.size()) { |
| 1450 | throw new StreamCorruptedException( |
| 1451 | String.format("invalid handle value: %08X", passHandle + |
| 1452 | baseWireHandle)); |
| 1453 | } |
| 1454 | if (unshared) { |
| 1455 | // REMIND: what type of exception to throw here? |
| 1456 | throw new InvalidObjectException( |
| 1457 | "cannot read back reference as unshared"); |
| 1458 | } |
| 1459 | |
| 1460 | Object obj = handles.lookupObject(passHandle); |
| 1461 | if (obj == unsharedMarker) { |
| 1462 | // REMIND: what type of exception to throw here? |
| 1463 | throw new InvalidObjectException( |
| 1464 | "cannot read back reference to unshared object"); |
| 1465 | } |
| 1466 | return obj; |
| 1467 | } |
| 1468 | |
| 1469 | /** |
| 1470 | * Reads in and returns class object. Sets passHandle to class object's |
| 1471 | * assigned handle. Returns null if class is unresolvable (in which case a |
| 1472 | * ClassNotFoundException will be associated with the class' handle in the |
| 1473 | * handle table). |
| 1474 | */ |
| 1475 | private Class readClass(boolean unshared) throws IOException { |
| 1476 | if (bin.readByte() != TC_CLASS) { |
| 1477 | throw new InternalError(); |
| 1478 | } |
| 1479 | ObjectStreamClass desc = readClassDesc(false); |
| 1480 | Class cl = desc.forClass(); |
| 1481 | passHandle = handles.assign(unshared ? unsharedMarker : cl); |
| 1482 | |
| 1483 | ClassNotFoundException resolveEx = desc.getResolveException(); |
| 1484 | if (resolveEx != null) { |
| 1485 | handles.markException(passHandle, resolveEx); |
| 1486 | } |
| 1487 | |
| 1488 | handles.finish(passHandle); |
| 1489 | return cl; |
| 1490 | } |
| 1491 | |
| 1492 | /** |
| 1493 | * Reads in and returns (possibly null) class descriptor. Sets passHandle |
| 1494 | * to class descriptor's assigned handle. If class descriptor cannot be |
| 1495 | * resolved to a class in the local VM, a ClassNotFoundException is |
| 1496 | * associated with the class descriptor's handle. |
| 1497 | */ |
| 1498 | private ObjectStreamClass readClassDesc(boolean unshared) |
| 1499 | throws IOException |
| 1500 | { |
| 1501 | byte tc = bin.peekByte(); |
| 1502 | switch (tc) { |
| 1503 | case TC_NULL: |
| 1504 | return (ObjectStreamClass) readNull(); |
| 1505 | |
| 1506 | case TC_REFERENCE: |
| 1507 | return (ObjectStreamClass) readHandle(unshared); |
| 1508 | |
| 1509 | case TC_PROXYCLASSDESC: |
| 1510 | return readProxyDesc(unshared); |
| 1511 | |
| 1512 | case TC_CLASSDESC: |
| 1513 | return readNonProxyDesc(unshared); |
| 1514 | |
| 1515 | default: |
| 1516 | throw new StreamCorruptedException( |
| 1517 | String.format("invalid type code: %02X", tc)); |
| 1518 | } |
| 1519 | } |
| 1520 | |
| 1521 | /** |
| 1522 | * Reads in and returns class descriptor for a dynamic proxy class. Sets |
| 1523 | * passHandle to proxy class descriptor's assigned handle. If proxy class |
| 1524 | * descriptor cannot be resolved to a class in the local VM, a |
| 1525 | * ClassNotFoundException is associated with the descriptor's handle. |
| 1526 | */ |
| 1527 | private ObjectStreamClass readProxyDesc(boolean unshared) |
| 1528 | throws IOException |
| 1529 | { |
| 1530 | if (bin.readByte() != TC_PROXYCLASSDESC) { |
| 1531 | throw new InternalError(); |
| 1532 | } |
| 1533 | |
| 1534 | ObjectStreamClass desc = new ObjectStreamClass(); |
| 1535 | int descHandle = handles.assign(unshared ? unsharedMarker : desc); |
| 1536 | passHandle = NULL_HANDLE; |
| 1537 | |
| 1538 | int numIfaces = bin.readInt(); |
| 1539 | String[] ifaces = new String[numIfaces]; |
| 1540 | for (int i = 0; i < numIfaces; i++) { |
| 1541 | ifaces[i] = bin.readUTF(); |
| 1542 | } |
| 1543 | |
| 1544 | Class cl = null; |
| 1545 | ClassNotFoundException resolveEx = null; |
| 1546 | bin.setBlockDataMode(true); |
| 1547 | try { |
| 1548 | if ((cl = resolveProxyClass(ifaces)) == null) { |
| 1549 | resolveEx = new ClassNotFoundException("null class"); |
| 1550 | } |
| 1551 | } catch (ClassNotFoundException ex) { |
| 1552 | resolveEx = ex; |
| 1553 | } |
| 1554 | skipCustomData(); |
| 1555 | |
| 1556 | desc.initProxy(cl, resolveEx, readClassDesc(false)); |
| 1557 | |
| 1558 | handles.finish(descHandle); |
| 1559 | passHandle = descHandle; |
| 1560 | return desc; |
| 1561 | } |
| 1562 | |
| 1563 | /** |
| 1564 | * Reads in and returns class descriptor for a class that is not a dynamic |
| 1565 | * proxy class. Sets passHandle to class descriptor's assigned handle. If |
| 1566 | * class descriptor cannot be resolved to a class in the local VM, a |
| 1567 | * ClassNotFoundException is associated with the descriptor's handle. |
| 1568 | */ |
| 1569 | private ObjectStreamClass readNonProxyDesc(boolean unshared) |
| 1570 | throws IOException |
| 1571 | { |
| 1572 | if (bin.readByte() != TC_CLASSDESC) { |
| 1573 | throw new InternalError(); |
| 1574 | } |
| 1575 | |
| 1576 | ObjectStreamClass desc = new ObjectStreamClass(); |
| 1577 | int descHandle = handles.assign(unshared ? unsharedMarker : desc); |
| 1578 | passHandle = NULL_HANDLE; |
| 1579 | |
| 1580 | ObjectStreamClass readDesc = null; |
| 1581 | try { |
| 1582 | readDesc = readClassDescriptor(); |
| 1583 | } catch (ClassNotFoundException ex) { |
| 1584 | throw (IOException) new InvalidClassException( |
| 1585 | "failed to read class descriptor").initCause(ex); |
| 1586 | } |
| 1587 | |
| 1588 | Class cl = null; |
| 1589 | ClassNotFoundException resolveEx = null; |
| 1590 | bin.setBlockDataMode(true); |
| 1591 | try { |
| 1592 | if ((cl = resolveClass(readDesc)) == null) { |
| 1593 | resolveEx = new ClassNotFoundException("null class"); |
| 1594 | } |
| 1595 | } catch (ClassNotFoundException ex) { |
| 1596 | resolveEx = ex; |
| 1597 | } |
| 1598 | skipCustomData(); |
| 1599 | |
| 1600 | desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false)); |
| 1601 | |
| 1602 | handles.finish(descHandle); |
| 1603 | passHandle = descHandle; |
| 1604 | return desc; |
| 1605 | } |
| 1606 | |
| 1607 | /** |
| 1608 | * Reads in and returns new string. Sets passHandle to new string's |
| 1609 | * assigned handle. |
| 1610 | */ |
| 1611 | private String readString(boolean unshared) throws IOException { |
| 1612 | String str; |
| 1613 | byte tc = bin.readByte(); |
| 1614 | switch (tc) { |
| 1615 | case TC_STRING: |
| 1616 | str = bin.readUTF(); |
| 1617 | break; |
| 1618 | |
| 1619 | case TC_LONGSTRING: |
| 1620 | str = bin.readLongUTF(); |
| 1621 | break; |
| 1622 | |
| 1623 | default: |
| 1624 | throw new StreamCorruptedException( |
| 1625 | String.format("invalid type code: %02X", tc)); |
| 1626 | } |
| 1627 | passHandle = handles.assign(unshared ? unsharedMarker : str); |
| 1628 | handles.finish(passHandle); |
| 1629 | return str; |
| 1630 | } |
| 1631 | |
| 1632 | /** |
| 1633 | * Reads in and returns array object, or null if array class is |
| 1634 | * unresolvable. Sets passHandle to array's assigned handle. |
| 1635 | */ |
| 1636 | private Object readArray(boolean unshared) throws IOException { |
| 1637 | if (bin.readByte() != TC_ARRAY) { |
| 1638 | throw new InternalError(); |
| 1639 | } |
| 1640 | |
| 1641 | ObjectStreamClass desc = readClassDesc(false); |
| 1642 | int len = bin.readInt(); |
| 1643 | |
| 1644 | Object array = null; |
| 1645 | Class cl, ccl = null; |
| 1646 | if ((cl = desc.forClass()) != null) { |
| 1647 | ccl = cl.getComponentType(); |
| 1648 | array = Array.newInstance(ccl, len); |
| 1649 | } |
| 1650 | |
| 1651 | int arrayHandle = handles.assign(unshared ? unsharedMarker : array); |
| 1652 | ClassNotFoundException resolveEx = desc.getResolveException(); |
| 1653 | if (resolveEx != null) { |
| 1654 | handles.markException(arrayHandle, resolveEx); |
| 1655 | } |
| 1656 | |
| 1657 | if (ccl == null) { |
| 1658 | for (int i = 0; i < len; i++) { |
| 1659 | readObject0(false); |
| 1660 | } |
| 1661 | } else if (ccl.isPrimitive()) { |
| 1662 | if (ccl == Integer.TYPE) { |
| 1663 | bin.readInts((int[]) array, 0, len); |
| 1664 | } else if (ccl == Byte.TYPE) { |
| 1665 | bin.readFully((byte[]) array, 0, len, true); |
| 1666 | } else if (ccl == Long.TYPE) { |
| 1667 | bin.readLongs((long[]) array, 0, len); |
| 1668 | } else if (ccl == Float.TYPE) { |
| 1669 | bin.readFloats((float[]) array, 0, len); |
| 1670 | } else if (ccl == Double.TYPE) { |
| 1671 | bin.readDoubles((double[]) array, 0, len); |
| 1672 | } else if (ccl == Short.TYPE) { |
| 1673 | bin.readShorts((short[]) array, 0, len); |
| 1674 | } else if (ccl == Character.TYPE) { |
| 1675 | bin.readChars((char[]) array, 0, len); |
| 1676 | } else if (ccl == Boolean.TYPE) { |
| 1677 | bin.readBooleans((boolean[]) array, 0, len); |
| 1678 | } else { |
| 1679 | throw new InternalError(); |
| 1680 | } |
| 1681 | } else { |
| 1682 | Object[] oa = (Object[]) array; |
| 1683 | for (int i = 0; i < len; i++) { |
| 1684 | oa[i] = readObject0(false); |
| 1685 | handles.markDependency(arrayHandle, passHandle); |
| 1686 | } |
| 1687 | } |
| 1688 | |
| 1689 | handles.finish(arrayHandle); |
| 1690 | passHandle = arrayHandle; |
| 1691 | return array; |
| 1692 | } |
| 1693 | |
| 1694 | /** |
| 1695 | * Reads in and returns enum constant, or null if enum type is |
| 1696 | * unresolvable. Sets passHandle to enum constant's assigned handle. |
| 1697 | */ |
| 1698 | private Enum readEnum(boolean unshared) throws IOException { |
| 1699 | if (bin.readByte() != TC_ENUM) { |
| 1700 | throw new InternalError(); |
| 1701 | } |
| 1702 | |
| 1703 | ObjectStreamClass desc = readClassDesc(false); |
| 1704 | if (!desc.isEnum()) { |
| 1705 | throw new InvalidClassException("non-enum class: " + desc); |
| 1706 | } |
| 1707 | |
| 1708 | int enumHandle = handles.assign(unshared ? unsharedMarker : null); |
| 1709 | ClassNotFoundException resolveEx = desc.getResolveException(); |
| 1710 | if (resolveEx != null) { |
| 1711 | handles.markException(enumHandle, resolveEx); |
| 1712 | } |
| 1713 | |
| 1714 | String name = readString(false); |
| 1715 | Enum en = null; |
| 1716 | Class cl = desc.forClass(); |
| 1717 | if (cl != null) { |
| 1718 | try { |
| 1719 | en = Enum.valueOf(cl, name); |
| 1720 | } catch (IllegalArgumentException ex) { |
| 1721 | throw (IOException) new InvalidObjectException( |
| 1722 | "enum constant " + name + " does not exist in " + |
| 1723 | cl).initCause(ex); |
| 1724 | } |
| 1725 | if (!unshared) { |
| 1726 | handles.setObject(enumHandle, en); |
| 1727 | } |
| 1728 | } |
| 1729 | |
| 1730 | handles.finish(enumHandle); |
| 1731 | passHandle = enumHandle; |
| 1732 | return en; |
| 1733 | } |
| 1734 | |
| 1735 | /** |
| 1736 | * Reads and returns "ordinary" (i.e., not a String, Class, |
| 1737 | * ObjectStreamClass, array, or enum constant) object, or null if object's |
| 1738 | * class is unresolvable (in which case a ClassNotFoundException will be |
| 1739 | * associated with object's handle). Sets passHandle to object's assigned |
| 1740 | * handle. |
| 1741 | */ |
| 1742 | private Object readOrdinaryObject(boolean unshared) |
| 1743 | throws IOException |
| 1744 | { |
| 1745 | if (bin.readByte() != TC_OBJECT) { |
| 1746 | throw new InternalError(); |
| 1747 | } |
| 1748 | |
| 1749 | ObjectStreamClass desc = readClassDesc(false); |
| 1750 | desc.checkDeserialize(); |
| 1751 | |
| 1752 | Object obj; |
| 1753 | try { |
| 1754 | obj = desc.isInstantiable() ? desc.newInstance() : null; |
| 1755 | } catch (Exception ex) { |
| 1756 | throw (IOException) new InvalidClassException( |
| 1757 | desc.forClass().getName(), |
| 1758 | "unable to create instance").initCause(ex); |
| 1759 | } |
| 1760 | |
| 1761 | passHandle = handles.assign(unshared ? unsharedMarker : obj); |
| 1762 | ClassNotFoundException resolveEx = desc.getResolveException(); |
| 1763 | if (resolveEx != null) { |
| 1764 | handles.markException(passHandle, resolveEx); |
| 1765 | } |
| 1766 | |
| 1767 | if (desc.isExternalizable()) { |
| 1768 | readExternalData((Externalizable) obj, desc); |
| 1769 | } else { |
| 1770 | readSerialData(obj, desc); |
| 1771 | } |
| 1772 | |
| 1773 | handles.finish(passHandle); |
| 1774 | |
| 1775 | if (obj != null && |
| 1776 | handles.lookupException(passHandle) == null && |
| 1777 | desc.hasReadResolveMethod()) |
| 1778 | { |
| 1779 | Object rep = desc.invokeReadResolve(obj); |
| 1780 | if (unshared && rep.getClass().isArray()) { |
| 1781 | rep = cloneArray(rep); |
| 1782 | } |
| 1783 | if (rep != obj) { |
| 1784 | handles.setObject(passHandle, obj = rep); |
| 1785 | } |
| 1786 | } |
| 1787 | |
| 1788 | return obj; |
| 1789 | } |
| 1790 | |
| 1791 | /** |
| 1792 | * If obj is non-null, reads externalizable data by invoking readExternal() |
| 1793 | * method of obj; otherwise, attempts to skip over externalizable data. |
| 1794 | * Expects that passHandle is set to obj's handle before this method is |
| 1795 | * called. |
| 1796 | */ |
| 1797 | private void readExternalData(Externalizable obj, ObjectStreamClass desc) |
| 1798 | throws IOException |
| 1799 | { |
| 1800 | CallbackContext oldContext = curContext; |
| 1801 | curContext = null; |
| 1802 | try { |
| 1803 | boolean blocked = desc.hasBlockExternalData(); |
| 1804 | if (blocked) { |
| 1805 | bin.setBlockDataMode(true); |
| 1806 | } |
| 1807 | if (obj != null) { |
| 1808 | try { |
| 1809 | obj.readExternal(this); |
| 1810 | } catch (ClassNotFoundException ex) { |
| 1811 | /* |
| 1812 | * In most cases, the handle table has already propagated |
| 1813 | * a CNFException to passHandle at this point; this mark |
| 1814 | * call is included to address cases where the readExternal |
| 1815 | * method has cons'ed and thrown a new CNFException of its |
| 1816 | * own. |
| 1817 | */ |
| 1818 | handles.markException(passHandle, ex); |
| 1819 | } |
| 1820 | } |
| 1821 | if (blocked) { |
| 1822 | skipCustomData(); |
| 1823 | } |
| 1824 | } finally { |
| 1825 | curContext = oldContext; |
| 1826 | } |
| 1827 | /* |
| 1828 | * At this point, if the externalizable data was not written in |
| 1829 | * block-data form and either the externalizable class doesn't exist |
| 1830 | * locally (i.e., obj == null) or readExternal() just threw a |
| 1831 | * CNFException, then the stream is probably in an inconsistent state, |
| 1832 | * since some (or all) of the externalizable data may not have been |
| 1833 | * consumed. Since there's no "correct" action to take in this case, |
| 1834 | * we mimic the behavior of past serialization implementations and |
| 1835 | * blindly hope that the stream is in sync; if it isn't and additional |
| 1836 | * externalizable data remains in the stream, a subsequent read will |
| 1837 | * most likely throw a StreamCorruptedException. |
| 1838 | */ |
| 1839 | } |
| 1840 | |
| 1841 | /** |
| 1842 | * Reads (or attempts to skip, if obj is null or is tagged with a |
| 1843 | * ClassNotFoundException) instance data for each serializable class of |
| 1844 | * object in stream, from superclass to subclass. Expects that passHandle |
| 1845 | * is set to obj's handle before this method is called. |
| 1846 | */ |
| 1847 | private void readSerialData(Object obj, ObjectStreamClass desc) |
| 1848 | throws IOException |
| 1849 | { |
| 1850 | ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); |
| 1851 | for (int i = 0; i < slots.length; i++) { |
| 1852 | ObjectStreamClass slotDesc = slots[i].desc; |
| 1853 | |
| 1854 | if (slots[i].hasData) { |
| 1855 | if (obj != null && |
| 1856 | slotDesc.hasReadObjectMethod() && |
| 1857 | handles.lookupException(passHandle) == null) |
| 1858 | { |
| 1859 | CallbackContext oldContext = curContext; |
| 1860 | |
| 1861 | try { |
| 1862 | curContext = new CallbackContext(obj, slotDesc); |
| 1863 | |
| 1864 | bin.setBlockDataMode(true); |
| 1865 | slotDesc.invokeReadObject(obj, this); |
| 1866 | } catch (ClassNotFoundException ex) { |
| 1867 | /* |
| 1868 | * In most cases, the handle table has already |
| 1869 | * propagated a CNFException to passHandle at this |
| 1870 | * point; this mark call is included to address cases |
| 1871 | * where the custom readObject method has cons'ed and |
| 1872 | * thrown a new CNFException of its own. |
| 1873 | */ |
| 1874 | handles.markException(passHandle, ex); |
| 1875 | } finally { |
| 1876 | curContext.setUsed(); |
| 1877 | curContext = oldContext; |
| 1878 | } |
| 1879 | |
| 1880 | /* |
| 1881 | * defaultDataEnd may have been set indirectly by custom |
| 1882 | * readObject() method when calling defaultReadObject() or |
| 1883 | * readFields(); clear it to restore normal read behavior. |
| 1884 | */ |
| 1885 | defaultDataEnd = false; |
| 1886 | } else { |
| 1887 | defaultReadFields(obj, slotDesc); |
| 1888 | } |
| 1889 | if (slotDesc.hasWriteObjectData()) { |
| 1890 | skipCustomData(); |
| 1891 | } else { |
| 1892 | bin.setBlockDataMode(false); |
| 1893 | } |
| 1894 | } else { |
| 1895 | if (obj != null && |
| 1896 | slotDesc.hasReadObjectNoDataMethod() && |
| 1897 | handles.lookupException(passHandle) == null) |
| 1898 | { |
| 1899 | slotDesc.invokeReadObjectNoData(obj); |
| 1900 | } |
| 1901 | } |
| 1902 | } |
| 1903 | } |
| 1904 | |
| 1905 | /** |
| 1906 | * Skips over all block data and objects until TC_ENDBLOCKDATA is |
| 1907 | * encountered. |
| 1908 | */ |
| 1909 | private void skipCustomData() throws IOException { |
| 1910 | int oldHandle = passHandle; |
| 1911 | for (;;) { |
| 1912 | if (bin.getBlockDataMode()) { |
| 1913 | bin.skipBlockData(); |
| 1914 | bin.setBlockDataMode(false); |
| 1915 | } |
| 1916 | switch (bin.peekByte()) { |
| 1917 | case TC_BLOCKDATA: |
| 1918 | case TC_BLOCKDATALONG: |
| 1919 | bin.setBlockDataMode(true); |
| 1920 | break; |
| 1921 | |
| 1922 | case TC_ENDBLOCKDATA: |
| 1923 | bin.readByte(); |
| 1924 | passHandle = oldHandle; |
| 1925 | return; |
| 1926 | |
| 1927 | default: |
| 1928 | readObject0(false); |
| 1929 | break; |
| 1930 | } |
| 1931 | } |
| 1932 | } |
| 1933 | |
| 1934 | /** |
| 1935 | * Reads in values of serializable fields declared by given class |
| 1936 | * descriptor. If obj is non-null, sets field values in obj. Expects that |
| 1937 | * passHandle is set to obj's handle before this method is called. |
| 1938 | */ |
| 1939 | private void defaultReadFields(Object obj, ObjectStreamClass desc) |
| 1940 | throws IOException |
| 1941 | { |
| 1942 | // REMIND: is isInstance check necessary? |
| 1943 | Class cl = desc.forClass(); |
| 1944 | if (cl != null && obj != null && !cl.isInstance(obj)) { |
| 1945 | throw new ClassCastException(); |
| 1946 | } |
| 1947 | |
| 1948 | int primDataSize = desc.getPrimDataSize(); |
| 1949 | if (primVals == null || primVals.length < primDataSize) { |
| 1950 | primVals = new byte[primDataSize]; |
| 1951 | } |
| 1952 | bin.readFully(primVals, 0, primDataSize, false); |
| 1953 | if (obj != null) { |
| 1954 | desc.setPrimFieldValues(obj, primVals); |
| 1955 | } |
| 1956 | |
| 1957 | int objHandle = passHandle; |
| 1958 | ObjectStreamField[] fields = desc.getFields(false); |
| 1959 | Object[] objVals = new Object[desc.getNumObjFields()]; |
| 1960 | int numPrimFields = fields.length - objVals.length; |
| 1961 | for (int i = 0; i < objVals.length; i++) { |
| 1962 | ObjectStreamField f = fields[numPrimFields + i]; |
| 1963 | objVals[i] = readObject0(f.isUnshared()); |
| 1964 | if (f.getField() != null) { |
| 1965 | handles.markDependency(objHandle, passHandle); |
| 1966 | } |
| 1967 | } |
| 1968 | if (obj != null) { |
| 1969 | desc.setObjFieldValues(obj, objVals); |
| 1970 | } |
| 1971 | passHandle = objHandle; |
| 1972 | } |
| 1973 | |
| 1974 | /** |
| 1975 | * Reads in and returns IOException that caused serialization to abort. |
| 1976 | * All stream state is discarded prior to reading in fatal exception. Sets |
| 1977 | * passHandle to fatal exception's handle. |
| 1978 | */ |
| 1979 | private IOException readFatalException() throws IOException { |
| 1980 | if (bin.readByte() != TC_EXCEPTION) { |
| 1981 | throw new InternalError(); |
| 1982 | } |
| 1983 | clear(); |
| 1984 | return (IOException) readObject0(false); |
| 1985 | } |
| 1986 | |
| 1987 | /** |
| 1988 | * If recursion depth is 0, clears internal data structures; otherwise, |
| 1989 | * throws a StreamCorruptedException. This method is called when a |
| 1990 | * TC_RESET typecode is encountered. |
| 1991 | */ |
| 1992 | private void handleReset() throws StreamCorruptedException { |
| 1993 | if (depth > 0) { |
| 1994 | throw new StreamCorruptedException( |
| 1995 | "unexpected reset; recursion depth: " + depth); |
| 1996 | } |
| 1997 | clear(); |
| 1998 | } |
| 1999 | |
| 2000 | /** |
| 2001 | * Converts specified span of bytes into float values. |
| 2002 | */ |
| 2003 | // REMIND: remove once hotspot inlines Float.intBitsToFloat |
| 2004 | private static native void bytesToFloats(byte[] src, int srcpos, |
| 2005 | float[] dst, int dstpos, |
| 2006 | int nfloats); |
| 2007 | |
| 2008 | /** |
| 2009 | * Converts specified span of bytes into double values. |
| 2010 | */ |
| 2011 | // REMIND: remove once hotspot inlines Double.longBitsToDouble |
| 2012 | private static native void bytesToDoubles(byte[] src, int srcpos, |
| 2013 | double[] dst, int dstpos, |
| 2014 | int ndoubles); |
| 2015 | |
| 2016 | /** |
| 2017 | * Returns the first non-null class loader (not counting class loaders of |
| 2018 | * generated reflection implementation classes) up the execution stack, or |
| 2019 | * null if only code from the null class loader is on the stack. This |
| 2020 | * method is also called via reflection by the following RMI-IIOP class: |
| 2021 | * |
| 2022 | * com.sun.corba.se.internal.util.JDKClassLoader |
| 2023 | * |
| 2024 | * This method should not be removed or its signature changed without |
| 2025 | * corresponding modifications to the above class. |
| 2026 | */ |
| 2027 | // REMIND: change name to something more accurate? |
| 2028 | private static native ClassLoader latestUserDefinedLoader(); |
| 2029 | |
| 2030 | /** |
| 2031 | * Default GetField implementation. |
| 2032 | */ |
| 2033 | private class GetFieldImpl extends GetField { |
| 2034 | |
| 2035 | /** class descriptor describing serializable fields */ |
| 2036 | private final ObjectStreamClass desc; |
| 2037 | /** primitive field values */ |
| 2038 | private final byte[] primVals; |
| 2039 | /** object field values */ |
| 2040 | private final Object[] objVals; |
| 2041 | /** object field value handles */ |
| 2042 | private final int[] objHandles; |
| 2043 | |
| 2044 | /** |
| 2045 | * Creates GetFieldImpl object for reading fields defined in given |
| 2046 | * class descriptor. |
| 2047 | */ |
| 2048 | GetFieldImpl(ObjectStreamClass desc) { |
| 2049 | this.desc = desc; |
| 2050 | primVals = new byte[desc.getPrimDataSize()]; |
| 2051 | objVals = new Object[desc.getNumObjFields()]; |
| 2052 | objHandles = new int[objVals.length]; |
| 2053 | } |
| 2054 | |
| 2055 | public ObjectStreamClass getObjectStreamClass() { |
| 2056 | return desc; |
| 2057 | } |
| 2058 | |
| 2059 | public boolean defaulted(String name) throws IOException { |
| 2060 | return (getFieldOffset(name, null) < 0); |
| 2061 | } |
| 2062 | |
| 2063 | public boolean get(String name, boolean val) throws IOException { |
| 2064 | int off = getFieldOffset(name, Boolean.TYPE); |
| 2065 | return (off >= 0) ? Bits.getBoolean(primVals, off) : val; |
| 2066 | } |
| 2067 | |
| 2068 | public byte get(String name, byte val) throws IOException { |
| 2069 | int off = getFieldOffset(name, Byte.TYPE); |
| 2070 | return (off >= 0) ? primVals[off] : val; |
| 2071 | } |
| 2072 | |
| 2073 | public char get(String name, char val) throws IOException { |
| 2074 | int off = getFieldOffset(name, Character.TYPE); |
| 2075 | return (off >= 0) ? Bits.getChar(primVals, off) : val; |
| 2076 | } |
| 2077 | |
| 2078 | public short get(String name, short val) throws IOException { |
| 2079 | int off = getFieldOffset(name, Short.TYPE); |
| 2080 | return (off >= 0) ? Bits.getShort(primVals, off) : val; |
| 2081 | } |
| 2082 | |
| 2083 | public int get(String name, int val) throws IOException { |
| 2084 | int off = getFieldOffset(name, Integer.TYPE); |
| 2085 | return (off >= 0) ? Bits.getInt(primVals, off) : val; |
| 2086 | } |
| 2087 | |
| 2088 | public float get(String name, float val) throws IOException { |
| 2089 | int off = getFieldOffset(name, Float.TYPE); |
| 2090 | return (off >= 0) ? Bits.getFloat(primVals, off) : val; |
| 2091 | } |
| 2092 | |
| 2093 | public long get(String name, long val) throws IOException { |
| 2094 | int off = getFieldOffset(name, Long.TYPE); |
| 2095 | return (off >= 0) ? Bits.getLong(primVals, off) : val; |
| 2096 | } |
| 2097 | |
| 2098 | public double get(String name, double val) throws IOException { |
| 2099 | int off = getFieldOffset(name, Double.TYPE); |
| 2100 | return (off >= 0) ? Bits.getDouble(primVals, off) : val; |
| 2101 | } |
| 2102 | |
| 2103 | public Object get(String name, Object val) throws IOException { |
| 2104 | int off = getFieldOffset(name, Object.class); |
| 2105 | if (off >= 0) { |
| 2106 | int objHandle = objHandles[off]; |
| 2107 | handles.markDependency(passHandle, objHandle); |
| 2108 | return (handles.lookupException(objHandle) == null) ? |
| 2109 | objVals[off] : null; |
| 2110 | } else { |
| 2111 | return val; |
| 2112 | } |
| 2113 | } |
| 2114 | |
| 2115 | /** |
| 2116 | * Reads primitive and object field values from stream. |
| 2117 | */ |
| 2118 | void readFields() throws IOException { |
| 2119 | bin.readFully(primVals, 0, primVals.length, false); |
| 2120 | |
| 2121 | int oldHandle = passHandle; |
| 2122 | ObjectStreamField[] fields = desc.getFields(false); |
| 2123 | int numPrimFields = fields.length - objVals.length; |
| 2124 | for (int i = 0; i < objVals.length; i++) { |
| 2125 | objVals[i] = |
| 2126 | readObject0(fields[numPrimFields + i].isUnshared()); |
| 2127 | objHandles[i] = passHandle; |
| 2128 | } |
| 2129 | passHandle = oldHandle; |
| 2130 | } |
| 2131 | |
| 2132 | /** |
| 2133 | * Returns offset of field with given name and type. A specified type |
| 2134 | * of null matches all types, Object.class matches all non-primitive |
| 2135 | * types, and any other non-null type matches assignable types only. |
| 2136 | * If no matching field is found in the (incoming) class |
| 2137 | * descriptor but a matching field is present in the associated local |
| 2138 | * class descriptor, returns -1. Throws IllegalArgumentException if |
| 2139 | * neither incoming nor local class descriptor contains a match. |
| 2140 | */ |
| 2141 | private int getFieldOffset(String name, Class type) { |
| 2142 | ObjectStreamField field = desc.getField(name, type); |
| 2143 | if (field != null) { |
| 2144 | return field.getOffset(); |
| 2145 | } else if (desc.getLocalDesc().getField(name, type) != null) { |
| 2146 | return -1; |
| 2147 | } else { |
| 2148 | throw new IllegalArgumentException("no such field " + name + |
| 2149 | " with type " + type); |
| 2150 | } |
| 2151 | } |
| 2152 | } |
| 2153 | |
| 2154 | /** |
| 2155 | * Prioritized list of callbacks to be performed once object graph has been |
| 2156 | * completely deserialized. |
| 2157 | */ |
| 2158 | private static class ValidationList { |
| 2159 | |
| 2160 | private static class Callback { |
| 2161 | final ObjectInputValidation obj; |
| 2162 | final int priority; |
| 2163 | Callback next; |
| 2164 | final AccessControlContext acc; |
| 2165 | |
| 2166 | Callback(ObjectInputValidation obj, int priority, Callback next, |
| 2167 | AccessControlContext acc) |
| 2168 | { |
| 2169 | this.obj = obj; |
| 2170 | this.priority = priority; |
| 2171 | this.next = next; |
| 2172 | this.acc = acc; |
| 2173 | } |
| 2174 | } |
| 2175 | |
| 2176 | /** linked list of callbacks */ |
| 2177 | private Callback list; |
| 2178 | |
| 2179 | /** |
| 2180 | * Creates new (empty) ValidationList. |
| 2181 | */ |
| 2182 | ValidationList() { |
| 2183 | } |
| 2184 | |
| 2185 | /** |
| 2186 | * Registers callback. Throws InvalidObjectException if callback |
| 2187 | * object is null. |
| 2188 | */ |
| 2189 | void register(ObjectInputValidation obj, int priority) |
| 2190 | throws InvalidObjectException |
| 2191 | { |
| 2192 | if (obj == null) { |
| 2193 | throw new InvalidObjectException("null callback"); |
| 2194 | } |
| 2195 | |
| 2196 | Callback prev = null, cur = list; |
| 2197 | while (cur != null && priority < cur.priority) { |
| 2198 | prev = cur; |
| 2199 | cur = cur.next; |
| 2200 | } |
| 2201 | AccessControlContext acc = AccessController.getContext(); |
| 2202 | if (prev != null) { |
| 2203 | prev.next = new Callback(obj, priority, cur, acc); |
| 2204 | } else { |
| 2205 | list = new Callback(obj, priority, list, acc); |
| 2206 | } |
| 2207 | } |
| 2208 | |
| 2209 | /** |
| 2210 | * Invokes all registered callbacks and clears the callback list. |
| 2211 | * Callbacks with higher priorities are called first; those with equal |
| 2212 | * priorities may be called in any order. If any of the callbacks |
| 2213 | * throws an InvalidObjectException, the callback process is terminated |
| 2214 | * and the exception propagated upwards. |
| 2215 | */ |
| 2216 | void doCallbacks() throws InvalidObjectException { |
| 2217 | try { |
| 2218 | while (list != null) { |
| 2219 | AccessController.doPrivileged( |
| 2220 | new PrivilegedExceptionAction() |
| 2221 | { |
| 2222 | public Object run() throws InvalidObjectException { |
| 2223 | list.obj.validateObject(); |
| 2224 | return null; |
| 2225 | } |
| 2226 | }, list.acc); |
| 2227 | list = list.next; |
| 2228 | } |
| 2229 | } catch (PrivilegedActionException ex) { |
| 2230 | list = null; |
| 2231 | throw (InvalidObjectException) ex.getException(); |
| 2232 | } |
| 2233 | } |
| 2234 | |
| 2235 | /** |
| 2236 | * Resets the callback list to its initial (empty) state. |
| 2237 | */ |
| 2238 | public void clear() { |
| 2239 | list = null; |
| 2240 | } |
| 2241 | } |
| 2242 | |
| 2243 | /** |
| 2244 | * Input stream supporting single-byte peek operations. |
| 2245 | */ |
| 2246 | private static class PeekInputStream extends InputStream { |
| 2247 | |
| 2248 | /** underlying stream */ |
| 2249 | private final InputStream in; |
| 2250 | /** peeked byte */ |
| 2251 | private int peekb = -1; |
| 2252 | |
| 2253 | /** |
| 2254 | * Creates new PeekInputStream on top of given underlying stream. |
| 2255 | */ |
| 2256 | PeekInputStream(InputStream in) { |
| 2257 | this.in = in; |
| 2258 | } |
| 2259 | |
| 2260 | /** |
| 2261 | * Peeks at next byte value in stream. Similar to read(), except |
| 2262 | * that it does not consume the read value. |
| 2263 | */ |
| 2264 | int peek() throws IOException { |
| 2265 | return (peekb >= 0) ? peekb : (peekb = in.read()); |
| 2266 | } |
| 2267 | |
| 2268 | public int read() throws IOException { |
| 2269 | if (peekb >= 0) { |
| 2270 | int v = peekb; |
| 2271 | peekb = -1; |
| 2272 | return v; |
| 2273 | } else { |
| 2274 | return in.read(); |
| 2275 | } |
| 2276 | } |
| 2277 | |
| 2278 | public int read(byte[] b, int off, int len) throws IOException { |
| 2279 | if (len == 0) { |
| 2280 | return 0; |
| 2281 | } else if (peekb < 0) { |
| 2282 | return in.read(b, off, len); |
| 2283 | } else { |
| 2284 | b[off++] = (byte) peekb; |
| 2285 | len--; |
| 2286 | peekb = -1; |
| 2287 | int n = in.read(b, off, len); |
| 2288 | return (n >= 0) ? (n + 1) : 1; |
| 2289 | } |
| 2290 | } |
| 2291 | |
| 2292 | void readFully(byte[] b, int off, int len) throws IOException { |
| 2293 | int n = 0; |
| 2294 | while (n < len) { |
| 2295 | int count = read(b, off + n, len - n); |
| 2296 | if (count < 0) { |
| 2297 | throw new EOFException(); |
| 2298 | } |
| 2299 | n += count; |
| 2300 | } |
| 2301 | } |
| 2302 | |
| 2303 | public long skip(long n) throws IOException { |
| 2304 | if (n <= 0) { |
| 2305 | return 0; |
| 2306 | } |
| 2307 | int skipped = 0; |
| 2308 | if (peekb >= 0) { |
| 2309 | peekb = -1; |
| 2310 | skipped++; |
| 2311 | n--; |
| 2312 | } |
| 2313 | return skipped + skip(n); |
| 2314 | } |
| 2315 | |
| 2316 | public int available() throws IOException { |
| 2317 | return in.available() + ((peekb >= 0) ? 1 : 0); |
| 2318 | } |
| 2319 | |
| 2320 | public void close() throws IOException { |
| 2321 | in.close(); |
| 2322 | } |
| 2323 | } |
| 2324 | |
| 2325 | /** |
| 2326 | * Input stream with two modes: in default mode, inputs data written in the |
| 2327 | * same format as DataOutputStream; in "block data" mode, inputs data |
| 2328 | * bracketed by block data markers (see object serialization specification |
| 2329 | * for details). Buffering depends on block data mode: when in default |
| 2330 | * mode, no data is buffered in advance; when in block data mode, all data |
| 2331 | * for the current data block is read in at once (and buffered). |
| 2332 | */ |
| 2333 | private class BlockDataInputStream |
| 2334 | extends InputStream implements DataInput |
| 2335 | { |
| 2336 | /** maximum data block length */ |
| 2337 | private static final int MAX_BLOCK_SIZE = 1024; |
| 2338 | /** maximum data block header length */ |
| 2339 | private static final int MAX_HEADER_SIZE = 5; |
| 2340 | /** (tunable) length of char buffer (for reading strings) */ |
| 2341 | private static final int CHAR_BUF_SIZE = 256; |
| 2342 | /** readBlockHeader() return value indicating header read may block */ |
| 2343 | private static final int HEADER_BLOCKED = -2; |
| 2344 | |
| 2345 | /** buffer for reading general/block data */ |
| 2346 | private final byte[] buf = new byte[MAX_BLOCK_SIZE]; |
| 2347 | /** buffer for reading block data headers */ |
| 2348 | private final byte[] hbuf = new byte[MAX_HEADER_SIZE]; |
| 2349 | /** char buffer for fast string reads */ |
| 2350 | private final char[] cbuf = new char[CHAR_BUF_SIZE]; |
| 2351 | |
| 2352 | /** block data mode */ |
| 2353 | private boolean blkmode = false; |
| 2354 | |
| 2355 | // block data state fields; values meaningful only when blkmode true |
| 2356 | /** current offset into buf */ |
| 2357 | private int pos = 0; |
| 2358 | /** end offset of valid data in buf, or -1 if no more block data */ |
| 2359 | private int end = -1; |
| 2360 | /** number of bytes in current block yet to be read from stream */ |
| 2361 | private int unread = 0; |
| 2362 | |
| 2363 | /** underlying stream (wrapped in peekable filter stream) */ |
| 2364 | private final PeekInputStream in; |
| 2365 | /** loopback stream (for data reads that span data blocks) */ |
| 2366 | private final DataInputStream din; |
| 2367 | |
| 2368 | /** |
| 2369 | * Creates new BlockDataInputStream on top of given underlying stream. |
| 2370 | * Block data mode is turned off by default. |
| 2371 | */ |
| 2372 | BlockDataInputStream(InputStream in) { |
| 2373 | this.in = new PeekInputStream(in); |
| 2374 | din = new DataInputStream(this); |
| 2375 | } |
| 2376 | |
| 2377 | /** |
| 2378 | * Sets block data mode to the given mode (true == on, false == off) |
| 2379 | * and returns the previous mode value. If the new mode is the same as |
| 2380 | * the old mode, no action is taken. Throws IllegalStateException if |
| 2381 | * block data mode is being switched from on to off while unconsumed |
| 2382 | * block data is still present in the stream. |
| 2383 | */ |
| 2384 | boolean setBlockDataMode(boolean newmode) throws IOException { |
| 2385 | if (blkmode == newmode) { |
| 2386 | return blkmode; |
| 2387 | } |
| 2388 | if (newmode) { |
| 2389 | pos = 0; |
| 2390 | end = 0; |
| 2391 | unread = 0; |
| 2392 | } else if (pos < end) { |
| 2393 | throw new IllegalStateException("unread block data"); |
| 2394 | } |
| 2395 | blkmode = newmode; |
| 2396 | return !blkmode; |
| 2397 | } |
| 2398 | |
| 2399 | /** |
| 2400 | * Returns true if the stream is currently in block data mode, false |
| 2401 | * otherwise. |
| 2402 | */ |
| 2403 | boolean getBlockDataMode() { |
| 2404 | return blkmode; |
| 2405 | } |
| 2406 | |
| 2407 | /** |
| 2408 | * If in block data mode, skips to the end of the current group of data |
| 2409 | * blocks (but does not unset block data mode). If not in block data |
| 2410 | * mode, throws an IllegalStateException. |
| 2411 | */ |
| 2412 | void skipBlockData() throws IOException { |
| 2413 | if (!blkmode) { |
| 2414 | throw new IllegalStateException("not in block data mode"); |
| 2415 | } |
| 2416 | while (end >= 0) { |
| 2417 | refill(); |
| 2418 | } |
| 2419 | } |
| 2420 | |
| 2421 | /** |
| 2422 | * Attempts to read in the next block data header (if any). If |
| 2423 | * canBlock is false and a full header cannot be read without possibly |
| 2424 | * blocking, returns HEADER_BLOCKED, else if the next element in the |
| 2425 | * stream is a block data header, returns the block data length |
| 2426 | * specified by the header, else returns -1. |
| 2427 | */ |
| 2428 | private int readBlockHeader(boolean canBlock) throws IOException { |
| 2429 | if (defaultDataEnd) { |
| 2430 | /* |
| 2431 | * Fix for 4360508: stream is currently at the end of a field |
| 2432 | * value block written via default serialization; since there |
| 2433 | * is no terminating TC_ENDBLOCKDATA tag, simulate |
| 2434 | * end-of-custom-data behavior explicitly. |
| 2435 | */ |
| 2436 | return -1; |
| 2437 | } |
| 2438 | try { |
| 2439 | for (;;) { |
| 2440 | int avail = canBlock ? Integer.MAX_VALUE : in.available(); |
| 2441 | if (avail == 0) { |
| 2442 | return HEADER_BLOCKED; |
| 2443 | } |
| 2444 | |
| 2445 | int tc = in.peek(); |
| 2446 | switch (tc) { |
| 2447 | case TC_BLOCKDATA: |
| 2448 | if (avail < 2) { |
| 2449 | return HEADER_BLOCKED; |
| 2450 | } |
| 2451 | in.readFully(hbuf, 0, 2); |
| 2452 | return hbuf[1] & 0xFF; |
| 2453 | |
| 2454 | case TC_BLOCKDATALONG: |
| 2455 | if (avail < 5) { |
| 2456 | return HEADER_BLOCKED; |
| 2457 | } |
| 2458 | in.readFully(hbuf, 0, 5); |
| 2459 | int len = Bits.getInt(hbuf, 1); |
| 2460 | if (len < 0) { |
| 2461 | throw new StreamCorruptedException( |
| 2462 | "illegal block data header length: " + |
| 2463 | len); |
| 2464 | } |
| 2465 | return len; |
| 2466 | |
| 2467 | /* |
| 2468 | * TC_RESETs may occur in between data blocks. |
| 2469 | * Unfortunately, this case must be parsed at a lower |
| 2470 | * level than other typecodes, since primitive data |
| 2471 | * reads may span data blocks separated by a TC_RESET. |
| 2472 | */ |
| 2473 | case TC_RESET: |
| 2474 | in.read(); |
| 2475 | handleReset(); |
| 2476 | break; |
| 2477 | |
| 2478 | default: |
| 2479 | if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) { |
| 2480 | throw new StreamCorruptedException( |
| 2481 | String.format("invalid type code: %02X", |
| 2482 | tc)); |
| 2483 | } |
| 2484 | return -1; |
| 2485 | } |
| 2486 | } |
| 2487 | } catch (EOFException ex) { |
| 2488 | throw new StreamCorruptedException( |
| 2489 | "unexpected EOF while reading block data header"); |
| 2490 | } |
| 2491 | } |
| 2492 | |
| 2493 | /** |
| 2494 | * Refills internal buffer buf with block data. Any data in buf at the |
| 2495 | * time of the call is considered consumed. Sets the pos, end, and |
| 2496 | * unread fields to reflect the new amount of available block data; if |
| 2497 | * the next element in the stream is not a data block, sets pos and |
| 2498 | * unread to 0 and end to -1. |
| 2499 | */ |
| 2500 | private void refill() throws IOException { |
| 2501 | try { |
| 2502 | do { |
| 2503 | pos = 0; |
| 2504 | if (unread > 0) { |
| 2505 | int n = |
| 2506 | in.read(buf, 0, Math.min(unread, MAX_BLOCK_SIZE)); |
| 2507 | if (n >= 0) { |
| 2508 | end = n; |
| 2509 | unread -= n; |
| 2510 | } else { |
| 2511 | throw new StreamCorruptedException( |
| 2512 | "unexpected EOF in middle of data block"); |
| 2513 | } |
| 2514 | } else { |
| 2515 | int n = readBlockHeader(true); |
| 2516 | if (n >= 0) { |
| 2517 | end = 0; |
| 2518 | unread = n; |
| 2519 | } else { |
| 2520 | end = -1; |
| 2521 | unread = 0; |
| 2522 | } |
| 2523 | } |
| 2524 | } while (pos == end); |
| 2525 | } catch (IOException ex) { |
| 2526 | pos = 0; |
| 2527 | end = -1; |
| 2528 | unread = 0; |
| 2529 | throw ex; |
| 2530 | } |
| 2531 | } |
| 2532 | |
| 2533 | /** |
| 2534 | * If in block data mode, returns the number of unconsumed bytes |
| 2535 | * remaining in the current data block. If not in block data mode, |
| 2536 | * throws an IllegalStateException. |
| 2537 | */ |
| 2538 | int currentBlockRemaining() { |
| 2539 | if (blkmode) { |
| 2540 | return (end >= 0) ? (end - pos) + unread : 0; |
| 2541 | } else { |
| 2542 | throw new IllegalStateException(); |
| 2543 | } |
| 2544 | } |
| 2545 | |
| 2546 | /** |
| 2547 | * Peeks at (but does not consume) and returns the next byte value in |
| 2548 | * the stream, or -1 if the end of the stream/block data (if in block |
| 2549 | * data mode) has been reached. |
| 2550 | */ |
| 2551 | int peek() throws IOException { |
| 2552 | if (blkmode) { |
| 2553 | if (pos == end) { |
| 2554 | refill(); |
| 2555 | } |
| 2556 | return (end >= 0) ? (buf[pos] & 0xFF) : -1; |
| 2557 | } else { |
| 2558 | return in.peek(); |
| 2559 | } |
| 2560 | } |
| 2561 | |
| 2562 | /** |
| 2563 | * Peeks at (but does not consume) and returns the next byte value in |
| 2564 | * the stream, or throws EOFException if end of stream/block data has |
| 2565 | * been reached. |
| 2566 | */ |
| 2567 | byte peekByte() throws IOException { |
| 2568 | int val = peek(); |
| 2569 | if (val < 0) { |
| 2570 | throw new EOFException(); |
| 2571 | } |
| 2572 | return (byte) val; |
| 2573 | } |
| 2574 | |
| 2575 | |
| 2576 | /* ----------------- generic input stream methods ------------------ */ |
| 2577 | /* |
| 2578 | * The following methods are equivalent to their counterparts in |
| 2579 | * InputStream, except that they interpret data block boundaries and |
| 2580 | * read the requested data from within data blocks when in block data |
| 2581 | * mode. |
| 2582 | */ |
| 2583 | |
| 2584 | public int read() throws IOException { |
| 2585 | if (blkmode) { |
| 2586 | if (pos == end) { |
| 2587 | refill(); |
| 2588 | } |
| 2589 | return (end >= 0) ? (buf[pos++] & 0xFF) : -1; |
| 2590 | } else { |
| 2591 | return in.read(); |
| 2592 | } |
| 2593 | } |
| 2594 | |
| 2595 | public int read(byte[] b, int off, int len) throws IOException { |
| 2596 | return read(b, off, len, false); |
| 2597 | } |
| 2598 | |
| 2599 | public long skip(long len) throws IOException { |
| 2600 | long remain = len; |
| 2601 | while (remain > 0) { |
| 2602 | if (blkmode) { |
| 2603 | if (pos == end) { |
| 2604 | refill(); |
| 2605 | } |
| 2606 | if (end < 0) { |
| 2607 | break; |
| 2608 | } |
| 2609 | int nread = (int) Math.min(remain, end - pos); |
| 2610 | remain -= nread; |
| 2611 | pos += nread; |
| 2612 | } else { |
| 2613 | int nread = (int) Math.min(remain, MAX_BLOCK_SIZE); |
| 2614 | if ((nread = in.read(buf, 0, nread)) < 0) { |
| 2615 | break; |
| 2616 | } |
| 2617 | remain -= nread; |
| 2618 | } |
| 2619 | } |
| 2620 | return len - remain; |
| 2621 | } |
| 2622 | |
| 2623 | public int available() throws IOException { |
| 2624 | if (blkmode) { |
| 2625 | if ((pos == end) && (unread == 0)) { |
| 2626 | int n; |
| 2627 | while ((n = readBlockHeader(false)) == 0) ; |
| 2628 | switch (n) { |
| 2629 | case HEADER_BLOCKED: |
| 2630 | break; |
| 2631 | |
| 2632 | case -1: |
| 2633 | pos = 0; |
| 2634 | end = -1; |
| 2635 | break; |
| 2636 | |
| 2637 | default: |
| 2638 | pos = 0; |
| 2639 | end = 0; |
| 2640 | unread = n; |
| 2641 | break; |
| 2642 | } |
| 2643 | } |
| 2644 | // avoid unnecessary call to in.available() if possible |
| 2645 | int unreadAvail = (unread > 0) ? |
| 2646 | Math.min(in.available(), unread) : 0; |
| 2647 | return (end >= 0) ? (end - pos) + unreadAvail : 0; |
| 2648 | } else { |
| 2649 | return in.available(); |
| 2650 | } |
| 2651 | } |
| 2652 | |
| 2653 | public void close() throws IOException { |
| 2654 | if (blkmode) { |
| 2655 | pos = 0; |
| 2656 | end = -1; |
| 2657 | unread = 0; |
| 2658 | } |
| 2659 | in.close(); |
| 2660 | } |
| 2661 | |
| 2662 | /** |
| 2663 | * Attempts to read len bytes into byte array b at offset off. Returns |
| 2664 | * the number of bytes read, or -1 if the end of stream/block data has |
| 2665 | * been reached. If copy is true, reads values into an intermediate |
| 2666 | * buffer before copying them to b (to avoid exposing a reference to |
| 2667 | * b). |
| 2668 | */ |
| 2669 | int read(byte[] b, int off, int len, boolean copy) throws IOException { |
| 2670 | if (len == 0) { |
| 2671 | return 0; |
| 2672 | } else if (blkmode) { |
| 2673 | if (pos == end) { |
| 2674 | refill(); |
| 2675 | } |
| 2676 | if (end < 0) { |
| 2677 | return -1; |
| 2678 | } |
| 2679 | int nread = Math.min(len, end - pos); |
| 2680 | System.arraycopy(buf, pos, b, off, nread); |
| 2681 | pos += nread; |
| 2682 | return nread; |
| 2683 | } else if (copy) { |
| 2684 | int nread = in.read(buf, 0, Math.min(len, MAX_BLOCK_SIZE)); |
| 2685 | if (nread > 0) { |
| 2686 | System.arraycopy(buf, 0, b, off, nread); |
| 2687 | } |
| 2688 | return nread; |
| 2689 | } else { |
| 2690 | return in.read(b, off, len); |
| 2691 | } |
| 2692 | } |
| 2693 | |
| 2694 | /* ----------------- primitive data input methods ------------------ */ |
| 2695 | /* |
| 2696 | * The following methods are equivalent to their counterparts in |
| 2697 | * DataInputStream, except that they interpret data block boundaries |
| 2698 | * and read the requested data from within data blocks when in block |
| 2699 | * data mode. |
| 2700 | */ |
| 2701 | |
| 2702 | public void readFully(byte[] b) throws IOException { |
| 2703 | readFully(b, 0, b.length, false); |
| 2704 | } |
| 2705 | |
| 2706 | public void readFully(byte[] b, int off, int len) throws IOException { |
| 2707 | readFully(b, off, len, false); |
| 2708 | } |
| 2709 | |
| 2710 | public void readFully(byte[] b, int off, int len, boolean copy) |
| 2711 | throws IOException |
| 2712 | { |
| 2713 | while (len > 0) { |
| 2714 | int n = read(b, off, len, copy); |
| 2715 | if (n < 0) { |
| 2716 | throw new EOFException(); |
| 2717 | } |
| 2718 | off += n; |
| 2719 | len -= n; |
| 2720 | } |
| 2721 | } |
| 2722 | |
| 2723 | public int skipBytes(int n) throws IOException { |
| 2724 | return din.skipBytes(n); |
| 2725 | } |
| 2726 | |
| 2727 | public boolean readBoolean() throws IOException { |
| 2728 | int v = read(); |
| 2729 | if (v < 0) { |
| 2730 | throw new EOFException(); |
| 2731 | } |
| 2732 | return (v != 0); |
| 2733 | } |
| 2734 | |
| 2735 | public byte readByte() throws IOException { |
| 2736 | int v = read(); |
| 2737 | if (v < 0) { |
| 2738 | throw new EOFException(); |
| 2739 | } |
| 2740 | return (byte) v; |
| 2741 | } |
| 2742 | |
| 2743 | public int readUnsignedByte() throws IOException { |
| 2744 | int v = read(); |
| 2745 | if (v < 0) { |
| 2746 | throw new EOFException(); |
| 2747 | } |
| 2748 | return v; |
| 2749 | } |
| 2750 | |
| 2751 | public char readChar() throws IOException { |
| 2752 | if (!blkmode) { |
| 2753 | pos = 0; |
| 2754 | in.readFully(buf, 0, 2); |
| 2755 | } else if (end - pos < 2) { |
| 2756 | return din.readChar(); |
| 2757 | } |
| 2758 | char v = Bits.getChar(buf, pos); |
| 2759 | pos += 2; |
| 2760 | return v; |
| 2761 | } |
| 2762 | |
| 2763 | public short readShort() throws IOException { |
| 2764 | if (!blkmode) { |
| 2765 | pos = 0; |
| 2766 | in.readFully(buf, 0, 2); |
| 2767 | } else if (end - pos < 2) { |
| 2768 | return din.readShort(); |
| 2769 | } |
| 2770 | short v = Bits.getShort(buf, pos); |
| 2771 | pos += 2; |
| 2772 | return v; |
| 2773 | } |
| 2774 | |
| 2775 | public int readUnsignedShort() throws IOException { |
| 2776 | if (!blkmode) { |
| 2777 | pos = 0; |
| 2778 | in.readFully(buf, 0, 2); |
| 2779 | } else if (end - pos < 2) { |
| 2780 | return din.readUnsignedShort(); |
| 2781 | } |
| 2782 | int v = Bits.getShort(buf, pos) & 0xFFFF; |
| 2783 | pos += 2; |
| 2784 | return v; |
| 2785 | } |
| 2786 | |
| 2787 | public int readInt() throws IOException { |
| 2788 | if (!blkmode) { |
| 2789 | pos = 0; |
| 2790 | in.readFully(buf, 0, 4); |
| 2791 | } else if (end - pos < 4) { |
| 2792 | return din.readInt(); |
| 2793 | } |
| 2794 | int v = Bits.getInt(buf, pos); |
| 2795 | pos += 4; |
| 2796 | return v; |
| 2797 | } |
| 2798 | |
| 2799 | public float readFloat() throws IOException { |
| 2800 | if (!blkmode) { |
| 2801 | pos = 0; |
| 2802 | in.readFully(buf, 0, 4); |
| 2803 | } else if (end - pos < 4) { |
| 2804 | return din.readFloat(); |
| 2805 | } |
| 2806 | float v = Bits.getFloat(buf, pos); |
| 2807 | pos += 4; |
| 2808 | return v; |
| 2809 | } |
| 2810 | |
| 2811 | public long readLong() throws IOException { |
| 2812 | if (!blkmode) { |
| 2813 | pos = 0; |
| 2814 | in.readFully(buf, 0, 8); |
| 2815 | } else if (end - pos < 8) { |
| 2816 | return din.readLong(); |
| 2817 | } |
| 2818 | long v = Bits.getLong(buf, pos); |
| 2819 | pos += 8; |
| 2820 | return v; |
| 2821 | } |
| 2822 | |
| 2823 | public double readDouble() throws IOException { |
| 2824 | if (!blkmode) { |
| 2825 | pos = 0; |
| 2826 | in.readFully(buf, 0, 8); |
| 2827 | } else if (end - pos < 8) { |
| 2828 | return din.readDouble(); |
| 2829 | } |
| 2830 | double v = Bits.getDouble(buf, pos); |
| 2831 | pos += 8; |
| 2832 | return v; |
| 2833 | } |
| 2834 | |
| 2835 | public String readUTF() throws IOException { |
| 2836 | return readUTFBody(readUnsignedShort()); |
| 2837 | } |
| 2838 | |
| 2839 | public String readLine() throws IOException { |
| 2840 | return din.readLine(); // deprecated, not worth optimizing |
| 2841 | } |
| 2842 | |
| 2843 | /* -------------- primitive data array input methods --------------- */ |
| 2844 | /* |
| 2845 | * The following methods read in spans of primitive data values. |
| 2846 | * Though equivalent to calling the corresponding primitive read |
| 2847 | * methods repeatedly, these methods are optimized for reading groups |
| 2848 | * of primitive data values more efficiently. |
| 2849 | */ |
| 2850 | |
| 2851 | void readBooleans(boolean[] v, int off, int len) throws IOException { |
| 2852 | int stop, endoff = off + len; |
| 2853 | while (off < endoff) { |
| 2854 | if (!blkmode) { |
| 2855 | int span = Math.min(endoff - off, MAX_BLOCK_SIZE); |
| 2856 | in.readFully(buf, 0, span); |
| 2857 | stop = off + span; |
| 2858 | pos = 0; |
| 2859 | } else if (end - pos < 1) { |
| 2860 | v[off++] = din.readBoolean(); |
| 2861 | continue; |
| 2862 | } else { |
| 2863 | stop = Math.min(endoff, off + end - pos); |
| 2864 | } |
| 2865 | |
| 2866 | while (off < stop) { |
| 2867 | v[off++] = Bits.getBoolean(buf, pos++); |
| 2868 | } |
| 2869 | } |
| 2870 | } |
| 2871 | |
| 2872 | void readChars(char[] v, int off, int len) throws IOException { |
| 2873 | int stop, endoff = off + len; |
| 2874 | while (off < endoff) { |
| 2875 | if (!blkmode) { |
| 2876 | int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1); |
| 2877 | in.readFully(buf, 0, span << 1); |
| 2878 | stop = off + span; |
| 2879 | pos = 0; |
| 2880 | } else if (end - pos < 2) { |
| 2881 | v[off++] = din.readChar(); |
| 2882 | continue; |
| 2883 | } else { |
| 2884 | stop = Math.min(endoff, off + ((end - pos) >> 1)); |
| 2885 | } |
| 2886 | |
| 2887 | while (off < stop) { |
| 2888 | v[off++] = Bits.getChar(buf, pos); |
| 2889 | pos += 2; |
| 2890 | } |
| 2891 | } |
| 2892 | } |
| 2893 | |
| 2894 | void readShorts(short[] v, int off, int len) throws IOException { |
| 2895 | int stop, endoff = off + len; |
| 2896 | while (off < endoff) { |
| 2897 | if (!blkmode) { |
| 2898 | int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1); |
| 2899 | in.readFully(buf, 0, span << 1); |
| 2900 | stop = off + span; |
| 2901 | pos = 0; |
| 2902 | } else if (end - pos < 2) { |
| 2903 | v[off++] = din.readShort(); |
| 2904 | continue; |
| 2905 | } else { |
| 2906 | stop = Math.min(endoff, off + ((end - pos) >> 1)); |
| 2907 | } |
| 2908 | |
| 2909 | while (off < stop) { |
| 2910 | v[off++] = Bits.getShort(buf, pos); |
| 2911 | pos += 2; |
| 2912 | } |
| 2913 | } |
| 2914 | } |
| 2915 | |
| 2916 | void readInts(int[] v, int off, int len) throws IOException { |
| 2917 | int stop, endoff = off + len; |
| 2918 | while (off < endoff) { |
| 2919 | if (!blkmode) { |
| 2920 | int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2); |
| 2921 | in.readFully(buf, 0, span << 2); |
| 2922 | stop = off + span; |
| 2923 | pos = 0; |
| 2924 | } else if (end - pos < 4) { |
| 2925 | v[off++] = din.readInt(); |
| 2926 | continue; |
| 2927 | } else { |
| 2928 | stop = Math.min(endoff, off + ((end - pos) >> 2)); |
| 2929 | } |
| 2930 | |
| 2931 | while (off < stop) { |
| 2932 | v[off++] = Bits.getInt(buf, pos); |
| 2933 | pos += 4; |
| 2934 | } |
| 2935 | } |
| 2936 | } |
| 2937 | |
| 2938 | void readFloats(float[] v, int off, int len) throws IOException { |
| 2939 | int span, endoff = off + len; |
| 2940 | while (off < endoff) { |
| 2941 | if (!blkmode) { |
| 2942 | span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2); |
| 2943 | in.readFully(buf, 0, span << 2); |
| 2944 | pos = 0; |
| 2945 | } else if (end - pos < 4) { |
| 2946 | v[off++] = din.readFloat(); |
| 2947 | continue; |
| 2948 | } else { |
| 2949 | span = Math.min(endoff - off, ((end - pos) >> 2)); |
| 2950 | } |
| 2951 | |
| 2952 | bytesToFloats(buf, pos, v, off, span); |
| 2953 | off += span; |
| 2954 | pos += span << 2; |
| 2955 | } |
| 2956 | } |
| 2957 | |
| 2958 | void readLongs(long[] v, int off, int len) throws IOException { |
| 2959 | int stop, endoff = off + len; |
| 2960 | while (off < endoff) { |
| 2961 | if (!blkmode) { |
| 2962 | int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3); |
| 2963 | in.readFully(buf, 0, span << 3); |
| 2964 | stop = off + span; |
| 2965 | pos = 0; |
| 2966 | } else if (end - pos < 8) { |
| 2967 | v[off++] = din.readLong(); |
| 2968 | continue; |
| 2969 | } else { |
| 2970 | stop = Math.min(endoff, off + ((end - pos) >> 3)); |
| 2971 | } |
| 2972 | |
| 2973 | while (off < stop) { |
| 2974 | v[off++] = Bits.getLong(buf, pos); |
| 2975 | pos += 8; |
| 2976 | } |
| 2977 | } |
| 2978 | } |
| 2979 | |
| 2980 | void readDoubles(double[] v, int off, int len) throws IOException { |
| 2981 | int span, endoff = off + len; |
| 2982 | while (off < endoff) { |
| 2983 | if (!blkmode) { |
| 2984 | span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3); |
| 2985 | in.readFully(buf, 0, span << 3); |
| 2986 | pos = 0; |
| 2987 | } else if (end - pos < 8) { |
| 2988 | v[off++] = din.readDouble(); |
| 2989 | continue; |
| 2990 | } else { |
| 2991 | span = Math.min(endoff - off, ((end - pos) >> 3)); |
| 2992 | } |
| 2993 | |
| 2994 | bytesToDoubles(buf, pos, v, off, span); |
| 2995 | off += span; |
| 2996 | pos += span << 3; |
| 2997 | } |
| 2998 | } |
| 2999 | |
| 3000 | /** |
| 3001 | * Reads in string written in "long" UTF format. "Long" UTF format is |
| 3002 | * identical to standard UTF, except that it uses an 8 byte header |
| 3003 | * (instead of the standard 2 bytes) to convey the UTF encoding length. |
| 3004 | */ |
| 3005 | String readLongUTF() throws IOException { |
| 3006 | return readUTFBody(readLong()); |
| 3007 | } |
| 3008 | |
| 3009 | /** |
| 3010 | * Reads in the "body" (i.e., the UTF representation minus the 2-byte |
| 3011 | * or 8-byte length header) of a UTF encoding, which occupies the next |
| 3012 | * utflen bytes. |
| 3013 | */ |
| 3014 | private String readUTFBody(long utflen) throws IOException { |
| 3015 | StringBuilder sbuf = new StringBuilder(); |
| 3016 | if (!blkmode) { |
| 3017 | end = pos = 0; |
| 3018 | } |
| 3019 | |
| 3020 | while (utflen > 0) { |
| 3021 | int avail = end - pos; |
| 3022 | if (avail >= 3 || (long) avail == utflen) { |
| 3023 | utflen -= readUTFSpan(sbuf, utflen); |
| 3024 | } else { |
| 3025 | if (blkmode) { |
| 3026 | // near block boundary, read one byte at a time |
| 3027 | utflen -= readUTFChar(sbuf, utflen); |
| 3028 | } else { |
| 3029 | // shift and refill buffer manually |
| 3030 | if (avail > 0) { |
| 3031 | System.arraycopy(buf, pos, buf, 0, avail); |
| 3032 | } |
| 3033 | pos = 0; |
| 3034 | end = (int) Math.min(MAX_BLOCK_SIZE, utflen); |
| 3035 | in.readFully(buf, avail, end - avail); |
| 3036 | } |
| 3037 | } |
| 3038 | } |
| 3039 | |
| 3040 | return sbuf.toString(); |
| 3041 | } |
| 3042 | |
| 3043 | /** |
| 3044 | * Reads span of UTF-encoded characters out of internal buffer |
| 3045 | * (starting at offset pos and ending at or before offset end), |
| 3046 | * consuming no more than utflen bytes. Appends read characters to |
| 3047 | * sbuf. Returns the number of bytes consumed. |
| 3048 | */ |
| 3049 | private long readUTFSpan(StringBuilder sbuf, long utflen) |
| 3050 | throws IOException |
| 3051 | { |
| 3052 | int cpos = 0; |
| 3053 | int start = pos; |
| 3054 | int avail = Math.min(end - pos, CHAR_BUF_SIZE); |
| 3055 | // stop short of last char unless all of utf bytes in buffer |
| 3056 | int stop = pos + ((utflen > avail) ? avail - 2 : (int) utflen); |
| 3057 | boolean outOfBounds = false; |
| 3058 | |
| 3059 | try { |
| 3060 | while (pos < stop) { |
| 3061 | int b1, b2, b3; |
| 3062 | b1 = buf[pos++] & 0xFF; |
| 3063 | switch (b1 >> 4) { |
| 3064 | case 0: |
| 3065 | case 1: |
| 3066 | case 2: |
| 3067 | case 3: |
| 3068 | case 4: |
| 3069 | case 5: |
| 3070 | case 6: |
| 3071 | case 7: // 1 byte format: 0xxxxxxx |
| 3072 | cbuf[cpos++] = (char) b1; |
| 3073 | break; |
| 3074 | |
| 3075 | case 12: |
| 3076 | case 13: // 2 byte format: 110xxxxx 10xxxxxx |
| 3077 | b2 = buf[pos++]; |
| 3078 | if ((b2 & 0xC0) != 0x80) { |
| 3079 | throw new UTFDataFormatException(); |
| 3080 | } |
| 3081 | cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) | |
| 3082 | ((b2 & 0x3F) << 0)); |
| 3083 | break; |
| 3084 | |
| 3085 | case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx |
| 3086 | b3 = buf[pos + 1]; |
| 3087 | b2 = buf[pos + 0]; |
| 3088 | pos += 2; |
| 3089 | if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) { |
| 3090 | throw new UTFDataFormatException(); |
| 3091 | } |
| 3092 | cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) | |
| 3093 | ((b2 & 0x3F) << 6) | |
| 3094 | ((b3 & 0x3F) << 0)); |
| 3095 | break; |
| 3096 | |
| 3097 | default: // 10xx xxxx, 1111 xxxx |
| 3098 | throw new UTFDataFormatException(); |
| 3099 | } |
| 3100 | } |
| 3101 | } catch (ArrayIndexOutOfBoundsException ex) { |
| 3102 | outOfBounds = true; |
| 3103 | } finally { |
| 3104 | if (outOfBounds || (pos - start) > utflen) { |
| 3105 | /* |
| 3106 | * Fix for 4450867: if a malformed utf char causes the |
| 3107 | * conversion loop to scan past the expected end of the utf |
| 3108 | * string, only consume the expected number of utf bytes. |
| 3109 | */ |
| 3110 | pos = start + (int) utflen; |
| 3111 | throw new UTFDataFormatException(); |
| 3112 | } |
| 3113 | } |
| 3114 | |
| 3115 | sbuf.append(cbuf, 0, cpos); |
| 3116 | return pos - start; |
| 3117 | } |
| 3118 | |
| 3119 | /** |
| 3120 | * Reads in single UTF-encoded character one byte at a time, appends |
| 3121 | * the character to sbuf, and returns the number of bytes consumed. |
| 3122 | * This method is used when reading in UTF strings written in block |
| 3123 | * data mode to handle UTF-encoded characters which (potentially) |
| 3124 | * straddle block-data boundaries. |
| 3125 | */ |
| 3126 | private int readUTFChar(StringBuilder sbuf, long utflen) |
| 3127 | throws IOException |
| 3128 | { |
| 3129 | int b1, b2, b3; |
| 3130 | b1 = readByte() & 0xFF; |
| 3131 | switch (b1 >> 4) { |
| 3132 | case 0: |
| 3133 | case 1: |
| 3134 | case 2: |
| 3135 | case 3: |
| 3136 | case 4: |
| 3137 | case 5: |
| 3138 | case 6: |
| 3139 | case 7: // 1 byte format: 0xxxxxxx |
| 3140 | sbuf.append((char) b1); |
| 3141 | return 1; |
| 3142 | |
| 3143 | case 12: |
| 3144 | case 13: // 2 byte format: 110xxxxx 10xxxxxx |
| 3145 | if (utflen < 2) { |
| 3146 | throw new UTFDataFormatException(); |
| 3147 | } |
| 3148 | b2 = readByte(); |
| 3149 | if ((b2 & 0xC0) != 0x80) { |
| 3150 | throw new UTFDataFormatException(); |
| 3151 | } |
| 3152 | sbuf.append((char) (((b1 & 0x1F) << 6) | |
| 3153 | ((b2 & 0x3F) << 0))); |
| 3154 | return 2; |
| 3155 | |
| 3156 | case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx |
| 3157 | if (utflen < 3) { |
| 3158 | if (utflen == 2) { |
| 3159 | readByte(); // consume remaining byte |
| 3160 | } |
| 3161 | throw new UTFDataFormatException(); |
| 3162 | } |
| 3163 | b2 = readByte(); |
| 3164 | b3 = readByte(); |
| 3165 | if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) { |
| 3166 | throw new UTFDataFormatException(); |
| 3167 | } |
| 3168 | sbuf.append((char) (((b1 & 0x0F) << 12) | |
| 3169 | ((b2 & 0x3F) << 6) | |
| 3170 | ((b3 & 0x3F) << 0))); |
| 3171 | return 3; |
| 3172 | |
| 3173 | default: // 10xx xxxx, 1111 xxxx |
| 3174 | throw new UTFDataFormatException(); |
| 3175 | } |
| 3176 | } |
| 3177 | } |
| 3178 | |
| 3179 | /** |
| 3180 | * Unsynchronized table which tracks wire handle to object mappings, as |
| 3181 | * well as ClassNotFoundExceptions associated with deserialized objects. |
| 3182 | * This class implements an exception-propagation algorithm for |
| 3183 | * determining which objects should have ClassNotFoundExceptions associated |
| 3184 | * with them, taking into account cycles and discontinuities (e.g., skipped |
| 3185 | * fields) in the object graph. |
| 3186 | * |
| 3187 | * <p>General use of the table is as follows: during deserialization, a |
| 3188 | * given object is first assigned a handle by calling the assign method. |
| 3189 | * This method leaves the assigned handle in an "open" state, wherein |
| 3190 | * dependencies on the exception status of other handles can be registered |
| 3191 | * by calling the markDependency method, or an exception can be directly |
| 3192 | * associated with the handle by calling markException. When a handle is |
| 3193 | * tagged with an exception, the HandleTable assumes responsibility for |
| 3194 | * propagating the exception to any other objects which depend |
| 3195 | * (transitively) on the exception-tagged object. |
| 3196 | * |
| 3197 | * <p>Once all exception information/dependencies for the handle have been |
| 3198 | * registered, the handle should be "closed" by calling the finish method |
| 3199 | * on it. The act of finishing a handle allows the exception propagation |
| 3200 | * algorithm to aggressively prune dependency links, lessening the |
| 3201 | * performance/memory impact of exception tracking. |
| 3202 | * |
| 3203 | * <p>Note that the exception propagation algorithm used depends on handles |
| 3204 | * being assigned/finished in LIFO order; however, for simplicity as well |
| 3205 | * as memory conservation, it does not enforce this constraint. |
| 3206 | */ |
| 3207 | // REMIND: add full description of exception propagation algorithm? |
| 3208 | private static class HandleTable { |
| 3209 | |
| 3210 | /* status codes indicating whether object has associated exception */ |
| 3211 | private static final byte STATUS_OK = 1; |
| 3212 | private static final byte STATUS_UNKNOWN = 2; |
| 3213 | private static final byte STATUS_EXCEPTION = 3; |
| 3214 | |
| 3215 | /** array mapping handle -> object status */ |
| 3216 | byte[] status; |
| 3217 | /** array mapping handle -> object/exception (depending on status) */ |
| 3218 | Object[] entries; |
| 3219 | /** array mapping handle -> list of dependent handles (if any) */ |
| 3220 | HandleList[] deps; |
| 3221 | /** lowest unresolved dependency */ |
| 3222 | int lowDep = -1; |
| 3223 | /** number of handles in table */ |
| 3224 | int size = 0; |
| 3225 | |
| 3226 | /** |
| 3227 | * Creates handle table with the given initial capacity. |
| 3228 | */ |
| 3229 | HandleTable(int initialCapacity) { |
| 3230 | status = new byte[initialCapacity]; |
| 3231 | entries = new Object[initialCapacity]; |
| 3232 | deps = new HandleList[initialCapacity]; |
| 3233 | } |
| 3234 | |
| 3235 | /** |
| 3236 | * Assigns next available handle to given object, and returns assigned |
| 3237 | * handle. Once object has been completely deserialized (and all |
| 3238 | * dependencies on other objects identified), the handle should be |
| 3239 | * "closed" by passing it to finish(). |
| 3240 | */ |
| 3241 | int assign(Object obj) { |
| 3242 | if (size >= entries.length) { |
| 3243 | grow(); |
| 3244 | } |
| 3245 | status[size] = STATUS_UNKNOWN; |
| 3246 | entries[size] = obj; |
| 3247 | return size++; |
| 3248 | } |
| 3249 | |
| 3250 | /** |
| 3251 | * Registers a dependency (in exception status) of one handle on |
| 3252 | * another. The dependent handle must be "open" (i.e., assigned, but |
| 3253 | * not finished yet). No action is taken if either dependent or target |
| 3254 | * handle is NULL_HANDLE. |
| 3255 | */ |
| 3256 | void markDependency(int dependent, int target) { |
| 3257 | if (dependent == NULL_HANDLE || target == NULL_HANDLE) { |
| 3258 | return; |
| 3259 | } |
| 3260 | switch (status[dependent]) { |
| 3261 | |
| 3262 | case STATUS_UNKNOWN: |
| 3263 | switch (status[target]) { |
| 3264 | case STATUS_OK: |
| 3265 | // ignore dependencies on objs with no exception |
| 3266 | break; |
| 3267 | |
| 3268 | case STATUS_EXCEPTION: |
| 3269 | // eagerly propagate exception |
| 3270 | markException(dependent, |
| 3271 | (ClassNotFoundException) entries[target]); |
| 3272 | break; |
| 3273 | |
| 3274 | case STATUS_UNKNOWN: |
| 3275 | // add to dependency list of target |
| 3276 | if (deps[target] == null) { |
| 3277 | deps[target] = new HandleList(); |
| 3278 | } |
| 3279 | deps[target].add(dependent); |
| 3280 | |
| 3281 | // remember lowest unresolved target seen |
| 3282 | if (lowDep < 0 || lowDep > target) { |
| 3283 | lowDep = target; |
| 3284 | } |
| 3285 | break; |
| 3286 | |
| 3287 | default: |
| 3288 | throw new InternalError(); |
| 3289 | } |
| 3290 | break; |
| 3291 | |
| 3292 | case STATUS_EXCEPTION: |
| 3293 | break; |
| 3294 | |
| 3295 | default: |
| 3296 | throw new InternalError(); |
| 3297 | } |
| 3298 | } |
| 3299 | |
| 3300 | /** |
| 3301 | * Associates a ClassNotFoundException (if one not already associated) |
| 3302 | * with the currently active handle and propagates it to other |
| 3303 | * referencing objects as appropriate. The specified handle must be |
| 3304 | * "open" (i.e., assigned, but not finished yet). |
| 3305 | */ |
| 3306 | void markException(int handle, ClassNotFoundException ex) { |
| 3307 | switch (status[handle]) { |
| 3308 | case STATUS_UNKNOWN: |
| 3309 | status[handle] = STATUS_EXCEPTION; |
| 3310 | entries[handle] = ex; |
| 3311 | |
| 3312 | // propagate exception to dependents |
| 3313 | HandleList dlist = deps[handle]; |
| 3314 | if (dlist != null) { |
| 3315 | int ndeps = dlist.size(); |
| 3316 | for (int i = 0; i < ndeps; i++) { |
| 3317 | markException(dlist.get(i), ex); |
| 3318 | } |
| 3319 | deps[handle] = null; |
| 3320 | } |
| 3321 | break; |
| 3322 | |
| 3323 | case STATUS_EXCEPTION: |
| 3324 | break; |
| 3325 | |
| 3326 | default: |
| 3327 | throw new InternalError(); |
| 3328 | } |
| 3329 | } |
| 3330 | |
| 3331 | /** |
| 3332 | * Marks given handle as finished, meaning that no new dependencies |
| 3333 | * will be marked for handle. Calls to the assign and finish methods |
| 3334 | * must occur in LIFO order. |
| 3335 | */ |
| 3336 | void finish(int handle) { |
| 3337 | int end; |
| 3338 | if (lowDep < 0) { |
| 3339 | // no pending unknowns, only resolve current handle |
| 3340 | end = handle + 1; |
| 3341 | } else if (lowDep >= handle) { |
| 3342 | // pending unknowns now clearable, resolve all upward handles |
| 3343 | end = size; |
| 3344 | lowDep = -1; |
| 3345 | } else { |
| 3346 | // unresolved backrefs present, can't resolve anything yet |
| 3347 | return; |
| 3348 | } |
| 3349 | |
| 3350 | // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles |
| 3351 | for (int i = handle; i < end; i++) { |
| 3352 | switch (status[i]) { |
| 3353 | case STATUS_UNKNOWN: |
| 3354 | status[i] = STATUS_OK; |
| 3355 | deps[i] = null; |
| 3356 | break; |
| 3357 | |
| 3358 | case STATUS_OK: |
| 3359 | case STATUS_EXCEPTION: |
| 3360 | break; |
| 3361 | |
| 3362 | default: |
| 3363 | throw new InternalError(); |
| 3364 | } |
| 3365 | } |
| 3366 | } |
| 3367 | |
| 3368 | /** |
| 3369 | * Assigns a new object to the given handle. The object previously |
| 3370 | * associated with the handle is forgotten. This method has no effect |
| 3371 | * if the given handle already has an exception associated with it. |
| 3372 | * This method may be called at any time after the handle is assigned. |
| 3373 | */ |
| 3374 | void setObject(int handle, Object obj) { |
| 3375 | switch (status[handle]) { |
| 3376 | case STATUS_UNKNOWN: |
| 3377 | case STATUS_OK: |
| 3378 | entries[handle] = obj; |
| 3379 | break; |
| 3380 | |
| 3381 | case STATUS_EXCEPTION: |
| 3382 | break; |
| 3383 | |
| 3384 | default: |
| 3385 | throw new InternalError(); |
| 3386 | } |
| 3387 | } |
| 3388 | |
| 3389 | /** |
| 3390 | * Looks up and returns object associated with the given handle. |
| 3391 | * Returns null if the given handle is NULL_HANDLE, or if it has an |
| 3392 | * associated ClassNotFoundException. |
| 3393 | */ |
| 3394 | Object lookupObject(int handle) { |
| 3395 | return (handle != NULL_HANDLE && |
| 3396 | status[handle] != STATUS_EXCEPTION) ? |
| 3397 | entries[handle] : null; |
| 3398 | } |
| 3399 | |
| 3400 | /** |
| 3401 | * Looks up and returns ClassNotFoundException associated with the |
| 3402 | * given handle. Returns null if the given handle is NULL_HANDLE, or |
| 3403 | * if there is no ClassNotFoundException associated with the handle. |
| 3404 | */ |
| 3405 | ClassNotFoundException lookupException(int handle) { |
| 3406 | return (handle != NULL_HANDLE && |
| 3407 | status[handle] == STATUS_EXCEPTION) ? |
| 3408 | (ClassNotFoundException) entries[handle] : null; |
| 3409 | } |
| 3410 | |
| 3411 | /** |
| 3412 | * Resets table to its initial state. |
| 3413 | */ |
| 3414 | void clear() { |
| 3415 | Arrays.fill(status, 0, size, (byte) 0); |
| 3416 | Arrays.fill(entries, 0, size, null); |
| 3417 | Arrays.fill(deps, 0, size, null); |
| 3418 | lowDep = -1; |
| 3419 | size = 0; |
| 3420 | } |
| 3421 | |
| 3422 | /** |
| 3423 | * Returns number of handles registered in table. |
| 3424 | */ |
| 3425 | int size() { |
| 3426 | return size; |
| 3427 | } |
| 3428 | |
| 3429 | /** |
| 3430 | * Expands capacity of internal arrays. |
| 3431 | */ |
| 3432 | private void grow() { |
| 3433 | int newCapacity = (entries.length << 1) + 1; |
| 3434 | |
| 3435 | byte[] newStatus = new byte[newCapacity]; |
| 3436 | Object[] newEntries = new Object[newCapacity]; |
| 3437 | HandleList[] newDeps = new HandleList[newCapacity]; |
| 3438 | |
| 3439 | System.arraycopy(status, 0, newStatus, 0, size); |
| 3440 | System.arraycopy(entries, 0, newEntries, 0, size); |
| 3441 | System.arraycopy(deps, 0, newDeps, 0, size); |
| 3442 | |
| 3443 | status = newStatus; |
| 3444 | entries = newEntries; |
| 3445 | deps = newDeps; |
| 3446 | } |
| 3447 | |
| 3448 | /** |
| 3449 | * Simple growable list of (integer) handles. |
| 3450 | */ |
| 3451 | private static class HandleList { |
| 3452 | private int[] list = new int[4]; |
| 3453 | private int size = 0; |
| 3454 | |
| 3455 | public HandleList() { |
| 3456 | } |
| 3457 | |
| 3458 | public void add(int handle) { |
| 3459 | if (size >= list.length) { |
| 3460 | int[] newList = new int[list.length << 1]; |
| 3461 | System.arraycopy(list, 0, newList, 0, list.length); |
| 3462 | list = newList; |
| 3463 | } |
| 3464 | list[size++] = handle; |
| 3465 | } |
| 3466 | |
| 3467 | public int get(int index) { |
| 3468 | if (index >= size) { |
| 3469 | throw new ArrayIndexOutOfBoundsException(); |
| 3470 | } |
| 3471 | return list[index]; |
| 3472 | } |
| 3473 | |
| 3474 | public int size() { |
| 3475 | return size; |
| 3476 | } |
| 3477 | } |
| 3478 | } |
| 3479 | |
| 3480 | /** |
| 3481 | * Method for cloning arrays in case of using unsharing reading |
| 3482 | */ |
| 3483 | private static Object cloneArray(Object array) { |
| 3484 | if (array instanceof Object[]) { |
| 3485 | return ((Object[]) array).clone(); |
| 3486 | } else if (array instanceof boolean[]) { |
| 3487 | return ((boolean[]) array).clone(); |
| 3488 | } else if (array instanceof byte[]) { |
| 3489 | return ((byte[]) array).clone(); |
| 3490 | } else if (array instanceof char[]) { |
| 3491 | return ((char[]) array).clone(); |
| 3492 | } else if (array instanceof double[]) { |
| 3493 | return ((double[]) array).clone(); |
| 3494 | } else if (array instanceof float[]) { |
| 3495 | return ((float[]) array).clone(); |
| 3496 | } else if (array instanceof int[]) { |
| 3497 | return ((int[]) array).clone(); |
| 3498 | } else if (array instanceof long[]) { |
| 3499 | return ((long[]) array).clone(); |
| 3500 | } else if (array instanceof double[]) { |
| 3501 | return ((double[]) array).clone(); |
| 3502 | } else { |
| 3503 | throw new AssertionError(); |
| 3504 | } |
| 3505 | } |
| 3506 | |
| 3507 | /** |
| 3508 | * Context that during upcalls to class-defined readObject methods; holds |
| 3509 | * object currently being deserialized and descriptor for current class. |
| 3510 | * This context keeps a boolean state to indicate that defaultReadObject |
| 3511 | * or readFields has already been invoked with this context or the class's |
| 3512 | * readObject method has returned; if true, the getObj method throws |
| 3513 | * NotActiveException. |
| 3514 | */ |
| 3515 | private static class CallbackContext { |
| 3516 | private final Object obj; |
| 3517 | private final ObjectStreamClass desc; |
| 3518 | private final AtomicBoolean used = new AtomicBoolean(); |
| 3519 | |
| 3520 | public CallbackContext(Object obj, ObjectStreamClass desc) { |
| 3521 | this.obj = obj; |
| 3522 | this.desc = desc; |
| 3523 | } |
| 3524 | |
| 3525 | public Object getObj() throws NotActiveException { |
| 3526 | checkAndSetUsed(); |
| 3527 | return obj; |
| 3528 | } |
| 3529 | |
| 3530 | public ObjectStreamClass getDesc() { |
| 3531 | return desc; |
| 3532 | } |
| 3533 | |
| 3534 | private void checkAndSetUsed() throws NotActiveException { |
| 3535 | if (!used.compareAndSet(false, true)) { |
| 3536 | throw new NotActiveException( |
| 3537 | "not in readObject invocation or fields already read"); |
| 3538 | } |
| 3539 | } |
| 3540 | |
| 3541 | public void setUsed() { |
| 3542 | used.set(true); |
| 3543 | } |
| 3544 | } |
| 3545 | } |