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