KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > io > ObjectInputStream


1 /*
2  * @(#)ObjectInputStream.java 1.157 06/04/05
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.io;
9
10 import java.io.ObjectStreamClass.WeakClassKey JavaDoc;
11 import java.lang.ref.ReferenceQueue JavaDoc;
12 import java.lang.reflect.Array JavaDoc;
13 import java.lang.reflect.Modifier JavaDoc;
14 import java.lang.reflect.Proxy JavaDoc;
15 import java.security.AccessController JavaDoc;
16 import java.security.PrivilegedAction JavaDoc;
17 import java.util.Arrays JavaDoc;
18 import java.util.HashMap JavaDoc;
19 import java.util.concurrent.ConcurrentHashMap JavaDoc;
20 import java.util.concurrent.ConcurrentMap JavaDoc;
21 import java.util.concurrent.atomic.AtomicBoolean JavaDoc;
22 import static java.io.ObjectStreamClass.processQueue JavaDoc;
23
24 /**
25  * An ObjectInputStream deserializes primitive data and objects previously
26  * written using an ObjectOutputStream.
27  *
28  * <p>ObjectOutputStream and ObjectInputStream can provide an application with
29  * persistent storage for graphs of objects when used with a FileOutputStream
30  * and FileInputStream respectively. ObjectInputStream is used to recover
31  * those objects previously serialized. Other uses include passing objects
32  * between hosts using a socket stream or for marshaling and unmarshaling
33  * arguments and parameters in a remote communication system.
34  *
35  * <p>ObjectInputStream ensures that the types of all objects in the graph
36  * created from the stream match the classes present in the Java Virtual
37  * Machine. Classes are loaded as required using the standard mechanisms.
38  *
39  * <p>Only objects that support the java.io.Serializable or
40  * java.io.Externalizable interface can be read from streams.
41  *
42  * <p>The method <code>readObject</code> is used to read an object from the
43  * stream. Java's safe casting should be used to get the desired type. In
44  * Java, strings and arrays are objects and are treated as objects during
45  * serialization. When read they need to be cast to the expected type.
46  *
47  * <p>Primitive data types can be read from the stream using the appropriate
48  * method on DataInput.
49  *
50  * <p>The default deserialization mechanism for objects restores the contents
51  * of each field to the value and type it had when it was written. Fields
52  * declared as transient or static are ignored by the deserialization process.
53  * References to other objects cause those objects to be read from the stream
54  * as necessary. Graphs of objects are restored correctly using a reference
55  * sharing mechanism. New objects are always allocated when deserializing,
56  * which prevents existing objects from being overwritten.
57  *
58  * <p>Reading an object is analogous to running the constructors of a new
59  * object. Memory is allocated for the object and initialized to zero (NULL).
60  * No-arg constructors are invoked for the non-serializable classes and then
61  * the fields of the serializable classes are restored from the stream starting
62  * with the serializable class closest to java.lang.object and finishing with
63  * the object's most specific class.
64  *
65  * <p>For example to read from a stream as written by the example in
66  * ObjectOutputStream:
67  * <br>
68  * <pre>
69  * FileInputStream fis = new FileInputStream("t.tmp");
70  * ObjectInputStream ois = new ObjectInputStream(fis);
71  *
72  * int i = ois.readInt();
73  * String today = (String) ois.readObject();
74  * Date date = (Date) ois.readObject();
75  *
76  * ois.close();
77  * </pre>
78  *
79  * <p>Classes control how they are serialized by implementing either the
80  * java.io.Serializable or java.io.Externalizable interfaces.
81  *
82  * <p>Implementing the Serializable interface allows object serialization to
83  * save and restore the entire state of the object and it allows classes to
84  * evolve between the time the stream is written and the time it is read. It
85  * automatically traverses references between objects, saving and restoring
86  * entire graphs.
87  *
88  * <p>Serializable classes that require special handling during the
89  * serialization and deserialization process should implement the following
90  * methods:<p>
91  *
92  * <pre>
93  * private void writeObject(java.io.ObjectOutputStream stream)
94  * throws IOException;
95  * private void readObject(java.io.ObjectInputStream stream)
96  * throws IOException, ClassNotFoundException;
97  * private void readObjectNoData()
98  * throws ObjectStreamException;
99  * </pre>
100  *
101  * <p>The readObject method is responsible for reading and restoring the state
102  * of the object for its particular class using data written to the stream by
103  * the corresponding writeObject method. The method does not need to concern
104  * itself with the state belonging to its superclasses or subclasses. State is
105  * restored by reading data from the ObjectInputStream for the individual
106  * fields and making assignments to the appropriate fields of the object.
107  * Reading primitive data types is supported by DataInput.
108  *
109  * <p>Any attempt to read object data which exceeds the boundaries of the
110  * custom data written by the corresponding writeObject method will cause an
111  * OptionalDataException to be thrown with an eof field value of true.
112  * Non-object reads which exceed the end of the allotted data will reflect the
113  * end of data in the same way that they would indicate the end of the stream:
114  * bytewise reads will return -1 as the byte read or number of bytes read, and
115  * primitive reads will throw EOFExceptions. If there is no corresponding
116  * writeObject method, then the end of default serialized data marks the end of
117  * the allotted data.
118  *
119  * <p>Primitive and object read calls issued from within a readExternal method
120  * behave in the same manner--if the stream is already positioned at the end of
121  * data written by the corresponding writeExternal method, object reads will
122  * throw OptionalDataExceptions with eof set to true, bytewise reads will
123  * return -1, and primitive reads will throw EOFExceptions. Note that this
124  * behavior does not hold for streams written with the old
125  * <code>ObjectStreamConstants.PROTOCOL_VERSION_1</code> protocol, in which the
126  * end of data written by writeExternal methods is not demarcated, and hence
127  * cannot be detected.
128  *
129  * <p>The readObjectNoData method is responsible for initializing the state of
130  * the object for its particular class in the event that the serialization
131  * stream does not list the given class as a superclass of the object being
132  * deserialized. This may occur in cases where the receiving party uses a
133  * different version of the deserialized instance's class than the sending
134  * party, and the receiver's version extends classes that are not extended by
135  * the sender's version. This may also occur if the serialization stream has
136  * been tampered; hence, readObjectNoData is useful for initializing
137  * deserialized objects properly despite a "hostile" or incomplete source
138  * stream.
139  *
140  * <p>Serialization does not read or assign values to the fields of any object
141  * that does not implement the java.io.Serializable interface. Subclasses of
142  * Objects that are not serializable can be serializable. In this case the
143  * non-serializable class must have a no-arg constructor to allow its fields to
144  * be initialized. In this case it is the responsibility of the subclass to
145  * save and restore the state of the non-serializable class. It is frequently
146  * the case that the fields of that class are accessible (public, package, or
147  * protected) or that there are get and set methods that can be used to restore
148  * the state.
149  *
150  * <p>Any exception that occurs while deserializing an object will be caught by
151  * the ObjectInputStream and abort the reading process.
152  *
153  * <p>Implementing the Externalizable interface allows the object to assume
154  * complete control over the contents and format of the object's serialized
155  * form. The methods of the Externalizable interface, writeExternal and
156  * readExternal, are called to save and restore the objects state. When
157  * implemented by a class they can write and read their own state using all of
158  * the methods of ObjectOutput and ObjectInput. It is the responsibility of
159  * the objects to handle any versioning that occurs.
160  *
161  * <p>Enum constants are deserialized differently than ordinary serializable or
162  * externalizable objects. The serialized form of an enum constant consists
163  * solely of its name; field values of the constant are not transmitted. To
164  * deserialize an enum constant, ObjectInputStream reads the constant name from
165  * the stream; the deserialized constant is then obtained by calling the static
166  * method <code>Enum.valueOf(Class, String)</code> with the enum constant's
167  * base type and the received constant name as arguments. Like other
168  * serializable or externalizable objects, enum constants can function as the
169  * targets of back references appearing subsequently in the serialization
170  * stream. The process by which enum constants are deserialized cannot be
171  * customized: any class-specific readObject, readObjectNoData, and readResolve
172  * methods defined by enum types are ignored during deserialization.
173  * Similarly, any serialPersistentFields or serialVersionUID field declarations
174  * are also ignored--all enum types have a fixed serialVersionUID of 0L.
175  *
176  * @author Mike Warres
177  * @author Roger Riggs
178  * @version 1.157, 06/04/05
179  * @see java.io.DataInput
180  * @see java.io.ObjectOutputStream
181  * @see java.io.Serializable
182  * @see <a HREF="../../../guide/serialization/spec/input.doc.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
183  * @since JDK1.1
184  */

185 public class ObjectInputStream
186     extends InputStream JavaDoc implements ObjectInput JavaDoc, ObjectStreamConstants JavaDoc
187 {
188     /** handle value representing null */
189     private static final int NULL_HANDLE = -1;
190     
191     /** marker for unshared objects in internal handle table */
192     private static final Object JavaDoc unsharedMarker = new Object JavaDoc();
193     
194     /** table mapping primitive type names to corresponding class objects */
195     private static final HashMap JavaDoc primClasses = new HashMap JavaDoc(8, 1.0F);
196     static {
197     primClasses.put("boolean", boolean.class);
198     primClasses.put("byte", byte.class);
199     primClasses.put("char", char.class);
200     primClasses.put("short", short.class);
201     primClasses.put("int", int.class);
202     primClasses.put("long", long.class);
203     primClasses.put("float", float.class);
204     primClasses.put("double", double.class);
205     primClasses.put("void", void.class);
206     }
207
208     private static class Caches {
209     /** cache of subclass security audit results */
210     static final ConcurrentMap JavaDoc<WeakClassKey,Boolean JavaDoc> subclassAudits =
211         new ConcurrentHashMap JavaDoc<WeakClassKey,Boolean JavaDoc>();
212
213     /** queue for WeakReferences to audited subclasses */
214     static final ReferenceQueue JavaDoc<Class JavaDoc<?>> subclassAuditsQueue =
215         new ReferenceQueue JavaDoc<Class JavaDoc<?>>();
216     }
217
218     /** filter stream for handling block data conversion */
219     private final BlockDataInputStream bin;
220     /** validation callback list */
221     private final ValidationList vlist;
222     /** recursion depth */
223     private int depth;
224     /** whether stream is closed */
225     private boolean closed;
226     
227     /** wire handle -> obj/exception map */
228     private final HandleTable handles;
229     /** scratch field for passing handle values up/down call stack */
230     private int passHandle = NULL_HANDLE;
231     /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
232     private boolean defaultDataEnd = false;
233
234     /** buffer for reading primitive field values */
235     private byte[] primVals;
236     
237     /** if true, invoke readObjectOverride() instead of readObject() */
238     private final boolean enableOverride;
239     /** if true, invoke resolveObject() */
240     private boolean enableResolve;
241     
242     /**
243      * Context during upcalls to class-defined readObject methods; holds
244      * object currently being deserialized and descriptor for current class.
245      * Null when not during readObject upcall.
246      */

247     private CallbackContext curContext;
248
249     /**
250      * Creates an ObjectInputStream that reads from the specified InputStream.
251      * A serialization stream header is read from the stream and verified.
252      * This constructor will block until the corresponding ObjectOutputStream
253      * has written and flushed the header.
254      *
255      * <p>If a security manager is installed, this constructor will check for
256      * the "enableSubclassImplementation" SerializablePermission when invoked
257      * directly or indirectly by the constructor of a subclass which overrides
258      * the ObjectInputStream.readFields or ObjectInputStream.readUnshared
259      * methods.
260      *
261      * @param in input stream to read from
262      * @throws StreamCorruptedException if the stream header is incorrect
263      * @throws IOException if an I/O error occurs while reading stream header
264      * @throws SecurityException if untrusted subclass illegally overrides
265      * security-sensitive methods
266      * @throws NullPointerException if <code>in</code> is <code>null</code>
267      * @see ObjectInputStream#ObjectInputStream()
268      * @see ObjectInputStream#readFields()
269      * @see ObjectOutputStream#ObjectOutputStream(OutputStream)
270      */

271     public ObjectInputStream(InputStream JavaDoc in) throws IOException JavaDoc {
272     verifySubclass();
273     bin = new BlockDataInputStream(in);
274     handles = new HandleTable(10);
275     vlist = new ValidationList();
276     enableOverride = false;
277     readStreamHeader();
278     bin.setBlockDataMode(true);
279     }
280
281     /**
282      * Provide a way for subclasses that are completely reimplementing
283      * ObjectInputStream to not have to allocate private data just used by this
284      * implementation of ObjectInputStream.
285      *
286      * <p>If there is a security manager installed, this method first calls the
287      * security manager's <code>checkPermission</code> method with the
288      * <code>SerializablePermission("enableSubclassImplementation")</code>
289      * permission to ensure it's ok to enable subclassing.
290      *
291      * @throws SecurityException if a security manager exists and its
292      * <code>checkPermission</code> method denies enabling
293      * subclassing.
294      * @see SecurityManager#checkPermission
295      * @see java.io.SerializablePermission
296      */

297     protected ObjectInputStream() throws IOException JavaDoc, SecurityException JavaDoc {
298     SecurityManager JavaDoc sm = System.getSecurityManager();
299     if (sm != null) {
300         sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
301     }
302     bin = null;
303     handles = null;
304     vlist = null;
305     enableOverride = true;
306     }
307
308     /**
309      * Read an object from the ObjectInputStream. The class of the object, the
310      * signature of the class, and the values of the non-transient and
311      * non-static fields of the class and all of its supertypes are read.
312      * Default deserializing for a class can be overriden using the writeObject
313      * and readObject methods. Objects referenced by this object are read
314      * transitively so that a complete equivalent graph of objects is
315      * reconstructed by readObject.
316      *
317      * <p>The root object is completely restored when all of its fields and the
318      * objects it references are completely restored. At this point the object
319      * validation callbacks are executed in order based on their registered
320      * priorities. The callbacks are registered by objects (in the readObject
321      * special methods) as they are individually restored.
322      *
323      * <p>Exceptions are thrown for problems with the InputStream and for
324      * classes that should not be deserialized. All exceptions are fatal to
325      * the InputStream and leave it in an indeterminate state; it is up to the
326      * caller to ignore or recover the stream state.
327      *
328      * @throws ClassNotFoundException Class of a serialized object cannot be
329      * found.
330      * @throws InvalidClassException Something is wrong with a class used by
331      * serialization.
332      * @throws StreamCorruptedException Control information in the
333      * stream is inconsistent.
334      * @throws OptionalDataException Primitive data was found in the
335      * stream instead of objects.
336      * @throws IOException Any of the usual Input/Output related exceptions.
337      */

338     public final Object JavaDoc readObject()
339     throws IOException JavaDoc, ClassNotFoundException JavaDoc
340     {
341     if (enableOverride) {
342         return readObjectOverride();
343     }
344
345     // if nested read, passHandle contains handle of enclosing object
346
int outerHandle = passHandle;
347     try {
348         Object JavaDoc obj = readObject0(false);
349         handles.markDependency(outerHandle, passHandle);
350         ClassNotFoundException JavaDoc ex = handles.lookupException(passHandle);
351         if (ex != null) {
352         throw ex;
353         }
354         if (depth == 0) {
355         vlist.doCallbacks();
356         }
357         return obj;
358     } finally {
359         passHandle = outerHandle;
360         if (closed && depth == 0) {
361         clear();
362         }
363     }
364     }
365
366     /**
367      * This method is called by trusted subclasses of ObjectOutputStream that
368      * constructed ObjectOutputStream using the protected no-arg constructor.
369      * The subclass is expected to provide an override method with the modifier
370      * "final".
371      *
372      * @return the Object read from the stream.
373      * @throws ClassNotFoundException Class definition of a serialized object
374      * cannot be found.
375      * @throws OptionalDataException Primitive data was found in the stream
376      * instead of objects.
377      * @throws IOException if I/O errors occurred while reading from the
378      * underlying stream
379      * @see #ObjectInputStream()
380      * @see #readObject()
381      * @since 1.2
382      */

383     protected Object JavaDoc readObjectOverride()
384     throws IOException JavaDoc, ClassNotFoundException JavaDoc
385     {
386     return null;
387     }
388  
389     /**
390      * Reads an "unshared" object from the ObjectInputStream. This method is
391      * identical to readObject, except that it prevents subsequent calls to
392      * readObject and readUnshared from returning additional references to the
393      * deserialized instance obtained via this call. Specifically:
394      * <ul>
395      * <li>If readUnshared is called to deserialize a back-reference (the
396      * stream representation of an object which has been written
397      * previously to the stream), an ObjectStreamException will be
398      * thrown.
399      *
400      * <li>If readUnshared returns successfully, then any subsequent attempts
401      * to deserialize back-references to the stream handle deserialized
402      * by readUnshared will cause an ObjectStreamException to be thrown.
403      * </ul>
404      * Deserializing an object via readUnshared invalidates the stream handle
405      * associated with the returned object. Note that this in itself does not
406      * always guarantee that the reference returned by readUnshared is unique;
407      * the deserialized object may define a readResolve method which returns an
408      * object visible to other parties, or readUnshared may return a Class
409      * object or enum constant obtainable elsewhere in the stream or through
410      * external means.
411      *
412      * <p>However, for objects which are not enum constants or instances of
413      * java.lang.Class and do not define readResolve methods, readUnshared
414      * guarantees that the returned object reference is unique and cannot be
415      * obtained a second time from the ObjectInputStream that created it, even
416      * if the underlying data stream has been manipulated. This guarantee
417      * applies only to the base-level object returned by readUnshared, and not
418      * to any transitively referenced sub-objects in the returned object graph.
419      *
420      * <p>ObjectInputStream subclasses which override this method can only be
421      * constructed in security contexts possessing the
422      * "enableSubclassImplementation" SerializablePermission; any attempt to
423      * instantiate such a subclass without this permission will cause a
424      * SecurityException to be thrown.
425      *
426      * @return reference to deserialized object
427      * @throws ClassNotFoundException if class of an object to deserialize
428      * cannot be found
429      * @throws StreamCorruptedException if control information in the stream
430      * is inconsistent
431      * @throws ObjectStreamException if object to deserialize has already
432      * appeared in stream
433      * @throws OptionalDataException if primitive data is next in stream
434      * @throws IOException if an I/O error occurs during deserialization
435      */

436     public Object JavaDoc readUnshared() throws IOException JavaDoc, ClassNotFoundException JavaDoc {
437     // if nested read, passHandle contains handle of enclosing object
438
int outerHandle = passHandle;
439     try {
440         Object JavaDoc obj = readObject0(true);
441         handles.markDependency(outerHandle, passHandle);
442         ClassNotFoundException JavaDoc ex = handles.lookupException(passHandle);
443         if (ex != null) {
444         throw ex;
445         }
446         if (depth == 0) {
447         vlist.doCallbacks();
448         }
449         return obj;
450     } finally {
451         passHandle = outerHandle;
452         if (closed && depth == 0) {
453         clear();
454         }
455     }
456     }
457
458     /**
459      * Read the non-static and non-transient fields of the current class from
460      * this stream. This may only be called from the readObject method of the
461      * class being deserialized. It will throw the NotActiveException if it is
462      * called otherwise.
463      *
464      * @throws ClassNotFoundException if the class of a serialized object
465      * could not be found.
466      * @throws IOException if an I/O error occurs.
467      * @throws NotActiveException if the stream is not currently reading
468      * objects.
469      */

470     public void defaultReadObject()
471     throws IOException JavaDoc, ClassNotFoundException JavaDoc
472     {
473     if (curContext == null) {
474         throw new NotActiveException JavaDoc("not in call to readObject");
475     }
476     Object JavaDoc curObj = curContext.getObj();
477     ObjectStreamClass JavaDoc curDesc = curContext.getDesc();
478     bin.setBlockDataMode(false);
479     defaultReadFields(curObj, curDesc);
480     bin.setBlockDataMode(true);
481     if (!curDesc.hasWriteObjectData()) {
482         /*
483          * Fix for 4360508: since stream does not contain terminating
484          * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
485          * knows to simulate end-of-custom-data behavior.
486          */

487         defaultDataEnd = true;
488     }
489     ClassNotFoundException JavaDoc ex = handles.lookupException(passHandle);
490     if (ex != null) {
491         throw ex;
492     }
493     }
494     
495     /**
496      * Reads the persistent fields from the stream and makes them available by
497      * name.
498      *
499      * @return the <code>GetField</code> object representing the persistent
500      * fields of the object being deserialized
501      * @throws ClassNotFoundException if the class of a serialized object
502      * could not be found.
503      * @throws IOException if an I/O error occurs.
504      * @throws NotActiveException if the stream is not currently reading
505      * objects.
506      * @since 1.2
507      */

508     public ObjectInputStream.GetField JavaDoc readFields()
509         throws IOException JavaDoc, ClassNotFoundException JavaDoc
510     {
511     if (curContext == null) {
512         throw new NotActiveException JavaDoc("not in call to readObject");
513     }
514     Object JavaDoc curObj = curContext.getObj();
515     ObjectStreamClass JavaDoc curDesc = curContext.getDesc();
516     bin.setBlockDataMode(false);
517     GetFieldImpl getField = new GetFieldImpl(curDesc);
518     getField.readFields();
519     bin.setBlockDataMode(true);
520     if (!curDesc.hasWriteObjectData()) {
521         /*
522          * Fix for 4360508: since stream does not contain terminating
523          * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
524          * knows to simulate end-of-custom-data behavior.
525          */

526         defaultDataEnd = true;
527     }
528
529     return getField;
530     }
531
532     /**
533      * Register an object to be validated before the graph is returned. While
534      * similar to resolveObject these validations are called after the entire
535      * graph has been reconstituted. Typically, a readObject method will
536      * register the object with the stream so that when all of the objects are
537      * restored a final set of validations can be performed.
538      *
539      * @param obj the object to receive the validation callback.
540      * @param prio controls the order of callbacks;zero is a good default.
541      * Use higher numbers to be called back earlier, lower numbers for
542      * later callbacks. Within a priority, callbacks are processed in
543      * no particular order.
544      * @throws NotActiveException The stream is not currently reading objects
545      * so it is invalid to register a callback.
546      * @throws InvalidObjectException The validation object is null.
547      */

548     public void registerValidation(ObjectInputValidation JavaDoc obj, int prio)
549     throws NotActiveException JavaDoc, InvalidObjectException JavaDoc
550     {
551     if (depth == 0) {
552         throw new NotActiveException JavaDoc("stream inactive");
553     }
554     vlist.register(obj, prio);
555     }
556
557     /**
558      * Load the local class equivalent of the specified stream class
559      * description. Subclasses may implement this method to allow classes to
560      * be fetched from an alternate source.
561      *
562      * <p>The corresponding method in <code>ObjectOutputStream</code> is
563      * <code>annotateClass</code>. This method will be invoked only once for
564      * each unique class in the stream. This method can be implemented by
565      * subclasses to use an alternate loading mechanism but must return a
566      * <code>Class</code> object. Once returned, the serialVersionUID of the
567      * class is compared to the serialVersionUID of the serialized class. If
568      * there is a mismatch, the deserialization fails and an exception is
569      * raised.
570      *
571      * <p>By default the class name is resolved relative to the class that
572      * called <code>readObject</code>.
573      *
574      * @param desc an instance of class <code>ObjectStreamClass</code>
575      * @return a <code>Class</code> object corresponding to <code>desc</code>
576      * @throws IOException any of the usual input/output exceptions
577      * @throws ClassNotFoundException if class of a serialized object cannot
578      * be found
579      */

580     protected Class JavaDoc<?> resolveClass(ObjectStreamClass JavaDoc desc)
581     throws IOException JavaDoc, ClassNotFoundException JavaDoc
582     {
583     String JavaDoc name = desc.getName();
584     try {
585         return Class.forName(name, false, latestUserDefinedLoader());
586     } catch (ClassNotFoundException JavaDoc ex) {
587         Class JavaDoc cl = (Class JavaDoc) primClasses.get(name);
588         if (cl != null) {
589         return cl;
590         } else {
591         throw ex;
592         }
593     }
594     }
595
596     /**
597      * Returns a proxy class that implements the interfaces named in a proxy
598      * class descriptor; subclasses may implement this method to read custom
599      * data from the stream along with the descriptors for dynamic proxy
600      * classes, allowing them to use an alternate loading mechanism for the
601      * interfaces and the proxy class.
602      *
603      * <p>This method is called exactly once for each unique proxy class
604      * descriptor in the stream.
605      *
606      * <p>The corresponding method in <code>ObjectOutputStream</code> is
607      * <code>annotateProxyClass</code>. For a given subclass of
608      * <code>ObjectInputStream</code> that overrides this method, the
609      * <code>annotateProxyClass</code> method in the corresponding subclass of
610      * <code>ObjectOutputStream</code> must write any data or objects read by
611      * this method.
612      *
613      * <p>The default implementation of this method in
614      * <code>ObjectInputStream</code> returns the result of calling
615      * <code>Proxy.getProxyClass</code> with the list of <code>Class</code>
616      * objects for the interfaces that are named in the <code>interfaces</code>
617      * parameter. The <code>Class</code> object for each interface name
618      * <code>i</code> is the value returned by calling
619      * <pre>
620      * Class.forName(i, false, loader)
621      * </pre>
622      * where <code>loader</code> is that of the first non-<code>null</code>
623      * class loader up the execution stack, or <code>null</code> if no
624      * non-<code>null</code> class loaders are on the stack (the same class
625      * loader choice used by the <code>resolveClass</code> method). Unless any
626      * of the resolved interfaces are non-public, this same value of
627      * <code>loader</code> is also the class loader passed to
628      * <code>Proxy.getProxyClass</code>; if non-public interfaces are present,
629      * their class loader is passed instead (if more than one non-public
630      * interface class loader is encountered, an
631      * <code>IllegalAccessError</code> is thrown).
632      * If <code>Proxy.getProxyClass</code> throws an
633      * <code>IllegalArgumentException</code>, <code>resolveProxyClass</code>
634      * will throw a <code>ClassNotFoundException</code> containing the
635      * <code>IllegalArgumentException</code>.
636      *
637      * @param interfaces the list of interface names that were
638      * deserialized in the proxy class descriptor
639      * @return a proxy class for the specified interfaces
640      * @throws IOException any exception thrown by the underlying
641      * <code>InputStream</code>
642      * @throws ClassNotFoundException if the proxy class or any of the
643      * named interfaces could not be found
644      * @see ObjectOutputStream#annotateProxyClass(Class)
645      * @since 1.3
646      */

647     protected Class JavaDoc<?> resolveProxyClass(String JavaDoc[] interfaces)
648     throws IOException JavaDoc, ClassNotFoundException JavaDoc
649     {
650     ClassLoader JavaDoc latestLoader = latestUserDefinedLoader();
651     ClassLoader JavaDoc nonPublicLoader = null;
652     boolean hasNonPublicInterface = false;
653
654     // define proxy in class loader of non-public interface(s), if any
655
Class JavaDoc[] classObjs = new Class JavaDoc[interfaces.length];
656     for (int i = 0; i < interfaces.length; i++) {
657         Class JavaDoc cl = Class.forName(interfaces[i], false, latestLoader);
658         if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
659         if (hasNonPublicInterface) {
660             if (nonPublicLoader != cl.getClassLoader()) {
661             throw new IllegalAccessError JavaDoc(
662                 "conflicting non-public interface class loaders");
663             }
664         } else {
665             nonPublicLoader = cl.getClassLoader();
666             hasNonPublicInterface = true;
667         }
668         }
669         classObjs[i] = cl;
670     }
671     try {
672         return Proxy.getProxyClass(
673         hasNonPublicInterface ? nonPublicLoader : latestLoader,
674         classObjs);
675     } catch (IllegalArgumentException JavaDoc e) {
676         throw new ClassNotFoundException JavaDoc(null, e);
677     }
678     }
679
680     /**
681      * This method will allow trusted subclasses of ObjectInputStream to
682      * substitute one object for another during deserialization. Replacing
683      * objects is disabled until enableResolveObject is called. The
684      * enableResolveObject method checks that the stream requesting to resolve
685      * object can be trusted. Every reference to serializable objects is passed
686      * to resolveObject. To insure that the private state of objects is not
687      * unintentionally exposed only trusted streams may use resolveObject.
688      *
689      * <p>This method is called after an object has been read but before it is
690      * returned from readObject. The default resolveObject method just returns
691      * the same object.
692      *
693      * <p>When a subclass is replacing objects it must insure that the
694      * substituted object is compatible with every field where the reference
695      * will be stored. Objects whose type is not a subclass of the type of the
696      * field or array element abort the serialization by raising an exception
697      * and the object is not be stored.
698      *
699      * <p>This method is called only once when each object is first
700      * encountered. All subsequent references to the object will be redirected
701      * to the new object.
702      *
703      * @param obj object to be substituted
704      * @return the substituted object
705      * @throws IOException Any of the usual Input/Output exceptions.
706      */

707     protected Object JavaDoc resolveObject(Object JavaDoc obj) throws IOException JavaDoc {
708     return obj;
709     }
710
711     /**
712      * Enable the stream to allow objects read from the stream to be replaced.
713      * When enabled, the resolveObject method is called for every object being
714      * deserialized.
715      *
716      * <p>If <i>enable</i> is true, and there is a security manager installed,
717      * this method first calls the security manager's
718      * <code>checkPermission</code> method with the
719      * <code>SerializablePermission("enableSubstitution")</code> permission to
720      * ensure it's ok to enable the stream to allow objects read from the
721      * stream to be replaced.
722      *
723      * @param enable true for enabling use of <code>resolveObject</code> for
724      * every object being deserialized
725      * @return the previous setting before this method was invoked
726      * @throws SecurityException if a security manager exists and its
727      * <code>checkPermission</code> method denies enabling the stream
728      * to allow objects read from the stream to be replaced.
729      * @see SecurityManager#checkPermission
730      * @see java.io.SerializablePermission
731      */

732     protected boolean enableResolveObject(boolean enable)
733     throws SecurityException JavaDoc
734     {
735     if (enable == enableResolve) {
736         return enable;
737     }
738     if (enable) {
739         SecurityManager JavaDoc sm = System.getSecurityManager();
740         if (sm != null) {
741         sm.checkPermission(SUBSTITUTION_PERMISSION);
742         }
743     }
744     enableResolve = enable;
745     return !enableResolve;
746     }
747
748     /**
749      * The readStreamHeader method is provided to allow subclasses to read and
750      * verify their own stream headers. It reads and verifies the magic number
751      * and version number.
752      *
753      * @throws IOException if there are I/O errors while reading from the
754      * underlying <code>InputStream</code>
755      * @throws StreamCorruptedException if control information in the stream
756      * is inconsistent
757      */

758     protected void readStreamHeader()
759     throws IOException JavaDoc, StreamCorruptedException JavaDoc
760     {
761     if (bin.readShort() != STREAM_MAGIC ||
762         bin.readShort() != STREAM_VERSION)
763     {
764         throw new StreamCorruptedException JavaDoc("invalid stream header");
765     }
766     }
767
768     /**
769      * Read a class descriptor from the serialization stream. This method is
770      * called when the ObjectInputStream expects a class descriptor as the next
771      * item in the serialization stream. Subclasses of ObjectInputStream may
772      * override this method to read in class descriptors that have been written
773      * in non-standard formats (by subclasses of ObjectOutputStream which have
774      * overridden the <code>writeClassDescriptor</code> method). By default,
775      * this method reads class descriptors according to the format defined in
776      * the Object Serialization specification.
777      *
778      * @return the class descriptor read
779      * @throws IOException If an I/O error has occurred.
780      * @throws ClassNotFoundException If the Class of a serialized object used
781      * in the class descriptor representation cannot be found
782      * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass)
783      * @since 1.3
784      */

785     protected ObjectStreamClass JavaDoc readClassDescriptor()
786     throws IOException JavaDoc, ClassNotFoundException JavaDoc
787     {
788     ObjectStreamClass JavaDoc desc = new ObjectStreamClass JavaDoc();
789     desc.readNonProxy(this);
790     return desc;
791     }
792
793     /**
794      * Reads a byte of data. This method will block if no input is available.
795      *
796      * @return the byte read, or -1 if the end of the stream is reached.
797      * @throws IOException If an I/O error has occurred.
798      */

799     public int read() throws IOException JavaDoc {
800     return bin.read();
801     }
802     
803     /**
804      * Reads into an array of bytes. This method will block until some input
805      * is available. Consider using java.io.DataInputStream.readFully to read
806      * exactly 'length' bytes.
807      *
808      * @param buf the buffer into which the data is read
809      * @param off the start offset of the data
810      * @param len the maximum number of bytes read
811      * @return the actual number of bytes read, -1 is returned when the end of
812      * the stream is reached.
813      * @throws IOException If an I/O error has occurred.
814      * @see java.io.DataInputStream#readFully(byte[],int,int)
815      */

816     public int read(byte[] buf, int off, int len) throws IOException JavaDoc {
817     if (buf == null) {
818         throw new NullPointerException JavaDoc();
819     }
820     int endoff = off + len;
821     if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
822         throw new IndexOutOfBoundsException JavaDoc();
823     }
824     return bin.read(buf, off, len, false);
825     }
826
827     /**
828      * Returns the number of bytes that can be read without blocking.
829      *
830      * @return the number of available bytes.
831      * @throws IOException if there are I/O errors while reading from the
832      * underlying <code>InputStream</code>
833      */

834     public int available() throws IOException JavaDoc {
835     return bin.available();
836     }
837
838     /**
839      * Closes the input stream. Must be called to release any resources
840      * associated with the stream.
841      *
842      * @throws IOException If an I/O error has occurred.
843      */

844     public void close() throws IOException JavaDoc {
845     /*
846      * Even if stream already closed, propagate redundant close to
847      * underlying stream to stay consistent with previous implementations.
848      */

849     closed = true;
850     if (depth == 0) {
851         clear();
852     }
853     bin.close();
854     }
855
856     /**
857      * Reads in a boolean.
858      *
859      * @return the boolean read.
860      * @throws EOFException If end of file is reached.
861      * @throws IOException If other I/O error has occurred.
862      */

863     public boolean readBoolean() throws IOException JavaDoc {
864     return bin.readBoolean();
865     }
866
867     /**
868      * Reads an 8 bit byte.
869      *
870      * @return the 8 bit byte read.
871      * @throws EOFException If end of file is reached.
872      * @throws IOException If other I/O error has occurred.
873      */

874     public byte readByte() throws IOException JavaDoc {
875     return bin.readByte();
876     }
877
878     /**
879      * Reads an unsigned 8 bit byte.
880      *
881      * @return the 8 bit byte read.
882      * @throws EOFException If end of file is reached.
883      * @throws IOException If other I/O error has occurred.
884      */

885     public int readUnsignedByte() throws IOException JavaDoc {
886     return bin.readUnsignedByte();
887     }
888
889     /**
890      * Reads a 16 bit char.
891      *
892      * @return the 16 bit char read.
893      * @throws EOFException If end of file is reached.
894      * @throws IOException If other I/O error has occurred.
895      */

896     public char readChar() throws IOException JavaDoc {
897     return bin.readChar();
898     }
899
900     /**
901      * Reads a 16 bit short.
902      *
903      * @return the 16 bit short read.
904      * @throws EOFException If end of file is reached.
905      * @throws IOException If other I/O error has occurred.
906      */

907     public short readShort() throws IOException JavaDoc {
908     return bin.readShort();
909     }
910
911     /**
912      * Reads an unsigned 16 bit short.
913      *
914      * @return the 16 bit short read.
915      * @throws EOFException If end of file is reached.
916      * @throws IOException If other I/O error has occurred.
917      */

918     public int readUnsignedShort() throws IOException JavaDoc {
919     return bin.readUnsignedShort();
920     }
921
922     /**
923      * Reads a 32 bit int.
924      *
925      * @return the 32 bit integer read.
926      * @throws EOFException If end of file is reached.
927      * @throws IOException If other I/O error has occurred.
928      */

929     public int readInt() throws IOException JavaDoc {
930     return bin.readInt();
931     }
932
933     /**
934      * Reads a 64 bit long.
935      *
936      * @return the read 64 bit long.
937      * @throws EOFException If end of file is reached.
938      * @throws IOException If other I/O error has occurred.
939      */

940     public long readLong() throws IOException JavaDoc {
941     return bin.readLong();
942     }
943
944     /**
945      * Reads a 32 bit float.
946      *
947      * @return the 32 bit float read.
948      * @throws EOFException If end of file is reached.
949      * @throws IOException If other I/O error has occurred.
950      */

951     public float readFloat() throws IOException JavaDoc {
952     return bin.readFloat();
953     }
954
955     /**
956      * Reads a 64 bit double.
957      *
958      * @return the 64 bit double read.
959      * @throws EOFException If end of file is reached.
960      * @throws IOException If other I/O error has occurred.
961      */

962     public double readDouble() throws IOException JavaDoc {
963     return bin.readDouble();
964     }
965
966     /**
967      * Reads bytes, blocking until all bytes are read.
968      *
969      * @param buf the buffer into which the data is read
970      * @throws EOFException If end of file is reached.
971      * @throws IOException If other I/O error has occurred.
972      */

973     public void readFully(byte[] buf) throws IOException JavaDoc {
974     bin.readFully(buf, 0, buf.length, false);
975     }
976
977     /**
978      * Reads bytes, blocking until all bytes are read.
979      *
980      * @param buf the buffer into which the data is read
981      * @param off the start offset of the data
982      * @param len the maximum number of bytes to read
983      * @throws EOFException If end of file is reached.
984      * @throws IOException If other I/O error has occurred.
985      */

986     public void readFully(byte[] buf, int off, int len) throws IOException JavaDoc {
987     int endoff = off + len;
988     if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
989         throw new IndexOutOfBoundsException JavaDoc();
990     }
991     bin.readFully(buf, off, len, false);
992     }
993
994     /**
995      * Skips bytes, block until all bytes are skipped.
996      *
997      * @param len the number of bytes to be skipped
998      * @return the actual number of bytes skipped.
999      * @throws EOFException If end of file is reached.
1000     * @throws IOException If other I/O error has occurred.
1001     */

1002    public int skipBytes(int len) throws IOException JavaDoc {
1003    return bin.skipBytes(len);
1004    }
1005
1006    /**
1007     * Reads in a line that has been terminated by a \n, \r, \r\n or EOF.
1008     *
1009     * @return a String copy of the line.
1010     * @throws IOException if there are I/O errors while reading from the
1011     * underlying <code>InputStream</code>
1012     * @deprecated This method does not properly convert bytes to characters.
1013     * see DataInputStream for the details and alternatives.
1014     */

1015    @Deprecated JavaDoc
1016    public String JavaDoc readLine() throws IOException JavaDoc {
1017    return bin.readLine();
1018    }
1019
1020    /**
1021     * Reads a String in
1022     * <a HREF="DataInput.html#modified-utf-8">modified UTF-8</a>
1023     * format.
1024     *
1025     * @return the String.
1026     * @throws IOException if there are I/O errors while reading from the
1027     * underlying <code>InputStream</code>
1028     * @throws UTFDataFormatException if read bytes do not represent a valid
1029     * modified UTF-8 encoding of a string
1030     */

1031    public String JavaDoc readUTF() throws IOException JavaDoc {
1032    return bin.readUTF();
1033    }
1034
1035    /**
1036     * Provide access to the persistent fields read from the input stream.
1037     */

1038    public static abstract class GetField {
1039 
1040    /**
1041     * Get the ObjectStreamClass that describes the fields in the stream.
1042     *
1043     * @return the descriptor class that describes the serializable fields
1044     */

1045    public abstract ObjectStreamClass JavaDoc getObjectStreamClass();
1046 
1047    /**
1048     * Return true if the named field is defaulted and has no value in this
1049     * stream.
1050     *
1051     * @param name the name of the field
1052     * @return true, if and only if the named field is defaulted
1053     * @throws IOException if there are I/O errors while reading from
1054     * the underlying <code>InputStream</code>
1055     * @throws IllegalArgumentException if <code>name</code> does not
1056     * correspond to a serializable field
1057     */

1058    public abstract boolean defaulted(String JavaDoc name) throws IOException JavaDoc;
1059 
1060    /**
1061     * Get the value of the named boolean field from the persistent field.
1062     *
1063     * @param name the name of the field
1064     * @param val the default value to use if <code>name</code> does not
1065     * have a value
1066     * @return the value of the named <code>boolean</code> field
1067     * @throws IOException if there are I/O errors while reading from the
1068     * underlying <code>InputStream</code>
1069     * @throws IllegalArgumentException if type of <code>name</code> is
1070     * not serializable or if the field type is incorrect
1071     */

1072    public abstract boolean get(String JavaDoc name, boolean val)
1073        throws IOException JavaDoc;
1074 
1075    /**
1076     * Get the value of the named byte field from the persistent field.
1077     *
1078     * @param name the name of the field
1079     * @param val the default value to use if <code>name</code> does not
1080     * have a value
1081     * @return the value of the named <code>byte</code> field
1082     * @throws IOException if there are I/O errors while reading from the
1083     * underlying <code>InputStream</code>
1084     * @throws IllegalArgumentException if type of <code>name</code> is
1085     * not serializable or if the field type is incorrect
1086     */

1087    public abstract byte get(String JavaDoc name, byte val) throws IOException JavaDoc;
1088 
1089    /**
1090     * Get the value of the named char field from the persistent field.
1091     *
1092     * @param name the name of the field
1093     * @param val the default value to use if <code>name</code> does not
1094     * have a value
1095     * @return the value of the named <code>char</code> field
1096     * @throws IOException if there are I/O errors while reading from the
1097     * underlying <code>InputStream</code>
1098     * @throws IllegalArgumentException if type of <code>name</code> is
1099     * not serializable or if the field type is incorrect
1100     */

1101    public abstract char get(String JavaDoc name, char val) throws IOException JavaDoc;
1102 
1103    /**
1104     * Get the value of the named short field from the persistent field.
1105     *
1106     * @param name the name of the field
1107     * @param val the default value to use if <code>name</code> does not
1108     * have a value
1109     * @return the value of the named <code>short</code> field
1110     * @throws IOException if there are I/O errors while reading from the
1111     * underlying <code>InputStream</code>
1112     * @throws IllegalArgumentException if type of <code>name</code> is
1113     * not serializable or if the field type is incorrect
1114     */

1115    public abstract short get(String JavaDoc name, short val) throws IOException JavaDoc;
1116 
1117    /**
1118     * Get the value of the named int field from the persistent field.
1119     *
1120     * @param name the name of the field
1121     * @param val the default value to use if <code>name</code> does not
1122     * have a value
1123     * @return the value of the named <code>int</code> field
1124     * @throws IOException if there are I/O errors while reading from the
1125     * underlying <code>InputStream</code>
1126     * @throws IllegalArgumentException if type of <code>name</code> is
1127     * not serializable or if the field type is incorrect
1128     */

1129    public abstract int get(String JavaDoc name, int val) throws IOException JavaDoc;
1130 
1131    /**
1132     * Get the value of the named long field from the persistent field.
1133     *
1134     * @param name the name of the field
1135     * @param val the default value to use if <code>name</code> does not
1136     * have a value
1137     * @return the value of the named <code>long</code> field
1138     * @throws IOException if there are I/O errors while reading from the
1139     * underlying <code>InputStream</code>
1140     * @throws IllegalArgumentException if type of <code>name</code> is
1141     * not serializable or if the field type is incorrect
1142     */

1143    public abstract long get(String JavaDoc name, long val) throws IOException JavaDoc;
1144 
1145    /**
1146     * Get the value of the named float field from the persistent field.
1147     *
1148     * @param name the name of the field
1149     * @param val the default value to use if <code>name</code> does not
1150     * have a value
1151     * @return the value of the named <code>float</code> field
1152     * @throws IOException if there are I/O errors while reading from the
1153     * underlying <code>InputStream</code>
1154     * @throws IllegalArgumentException if type of <code>name</code> is
1155     * not serializable or if the field type is incorrect
1156     */

1157    public abstract float get(String JavaDoc name, float val) throws IOException JavaDoc;
1158 
1159    /**
1160     * Get the value of the named double field from the persistent field.
1161     *
1162     * @param name the name of the field
1163     * @param val the default value to use if <code>name</code> does not
1164     * have a value
1165     * @return the value of the named <code>double</code> field
1166     * @throws IOException if there are I/O errors while reading from the
1167     * underlying <code>InputStream</code>
1168     * @throws IllegalArgumentException if type of <code>name</code> is
1169     * not serializable or if the field type is incorrect
1170     */

1171    public abstract double get(String JavaDoc name, double val) throws IOException JavaDoc;
1172 
1173    /**
1174     * Get the value of the named Object field from the persistent field.
1175     *
1176     * @param name the name of the field
1177     * @param val the default value to use if <code>name</code> does not
1178     * have a value
1179     * @return the value of the named <code>Object</code> field
1180     * @throws IOException if there are I/O errors while reading from the
1181     * underlying <code>InputStream</code>
1182     * @throws IllegalArgumentException if type of <code>name</code> is
1183     * not serializable or if the field type is incorrect
1184     */

1185    public abstract Object JavaDoc get(String JavaDoc name, Object JavaDoc val) throws IOException JavaDoc;
1186    }
1187
1188    /**
1189     * Verifies that this (possibly subclass) instance can be constructed
1190     * without violating security constraints: the subclass must not override
1191     * security-sensitive non-final methods, or else the
1192     * "enableSubclassImplementation" SerializablePermission is checked.
1193     */

1194    private void verifySubclass() {
1195    Class JavaDoc cl = getClass();
1196    processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
1197    WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
1198    Boolean JavaDoc result = Caches.subclassAudits.get(key);
1199    if (result == null) {
1200        result = Boolean.valueOf(auditSubclass(cl));
1201        Caches.subclassAudits.putIfAbsent(key, result);
1202    }
1203    if (result.booleanValue()) {
1204        return;
1205    }
1206    SecurityManager JavaDoc sm = System.getSecurityManager();
1207    if (sm != null) {
1208        sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1209    }
1210    }
1211
1212    /**
1213     * Performs reflective checks on given subclass to verify that it doesn't
1214     * override security-sensitive non-final methods. Returns true if subclass
1215     * is "safe", false otherwise.
1216     */

1217    private static boolean auditSubclass(final Class JavaDoc subcl) {
1218    Boolean JavaDoc result = (Boolean JavaDoc) AccessController.doPrivileged(
1219        new PrivilegedAction JavaDoc() {
1220        public Object JavaDoc run() {
1221            for (Class JavaDoc cl = subcl;
1222             cl != ObjectInputStream JavaDoc.class;
1223             cl = cl.getSuperclass())
1224            {
1225            try {
1226                cl.getDeclaredMethod("readUnshared", new Class JavaDoc[0]);
1227                return Boolean.FALSE;
1228            } catch (NoSuchMethodException JavaDoc ex) {
1229            }
1230            try {
1231                cl.getDeclaredMethod("readFields", new Class JavaDoc[0]);
1232                return Boolean.FALSE;
1233            } catch (NoSuchMethodException JavaDoc ex) {
1234            }
1235            }
1236            return Boolean.TRUE;
1237        }
1238        }
1239    );
1240    return result.booleanValue();
1241    }
1242
1243    /**
1244     * Clears internal data structures.
1245     */

1246    private void clear() {
1247    handles.clear();
1248    vlist.clear();
1249    }
1250
1251    /**
1252     * Underlying readObject implementation.
1253     */

1254    private Object JavaDoc readObject0(boolean unshared) throws IOException JavaDoc {
1255    boolean oldMode = bin.getBlockDataMode();
1256    if (oldMode) {
1257        int remain = bin.currentBlockRemaining();
1258        if (remain > 0) {
1259        throw new OptionalDataException JavaDoc(remain);
1260        } else if (defaultDataEnd) {
1261        /*
1262         * Fix for 4360508: stream is currently at the end of a field
1263         * value block written via default serialization; since there
1264         * is no terminating TC_ENDBLOCKDATA tag, simulate
1265         * end-of-custom-data behavior explicitly.
1266         */

1267        throw new OptionalDataException JavaDoc(true);
1268        }
1269        bin.setBlockDataMode(false);
1270    }
1271    
1272    byte tc;
1273    while ((tc = bin.peekByte()) == TC_RESET) {
1274        bin.readByte();
1275        handleReset();
1276    }
1277
1278    depth++;
1279    try {
1280        switch (tc) {
1281        case TC_NULL:
1282            return readNull();
1283
1284        case TC_REFERENCE:
1285            return readHandle(unshared);
1286
1287        case TC_CLASS:
1288            return readClass(unshared);
1289
1290        case TC_CLASSDESC:
1291        case TC_PROXYCLASSDESC:
1292            return readClassDesc(unshared);
1293
1294        case TC_STRING:
1295        case TC_LONGSTRING:
1296            return checkResolve(readString(unshared));
1297
1298        case TC_ARRAY:
1299            return checkResolve(readArray(unshared));
1300
1301        case TC_ENUM:
1302            return checkResolve(readEnum(unshared));
1303
1304        case TC_OBJECT:
1305            return checkResolve(readOrdinaryObject(unshared));
1306
1307        case TC_EXCEPTION:
1308            IOException JavaDoc ex = readFatalException();
1309            throw new WriteAbortedException JavaDoc("writing aborted", ex);
1310
1311        case TC_BLOCKDATA:
1312        case TC_BLOCKDATALONG:
1313            if (oldMode) {
1314            bin.setBlockDataMode(true);
1315            bin.peek(); // force header read
1316
throw new OptionalDataException JavaDoc(
1317                bin.currentBlockRemaining());
1318            } else {
1319            throw new StreamCorruptedException JavaDoc(
1320                "unexpected block data");
1321            }
1322            
1323        case TC_ENDBLOCKDATA:
1324            if (oldMode) {
1325            throw new OptionalDataException JavaDoc(true);
1326            } else {
1327            throw new StreamCorruptedException JavaDoc(
1328                "unexpected end of block data");
1329            }
1330
1331        default:
1332            throw new StreamCorruptedException JavaDoc();
1333        }
1334    } finally {
1335        depth--;
1336        bin.setBlockDataMode(oldMode);
1337    }
1338    }
1339
1340    /**
1341     * If resolveObject has been enabled and given object does not have an
1342     * exception associated with it, calls resolveObject to determine
1343     * replacement for object, and updates handle table accordingly. Returns
1344     * replacement object, or echoes provided object if no replacement
1345     * occurred. Expects that passHandle is set to given object's handle prior
1346     * to calling this method.
1347     */

1348    private Object JavaDoc checkResolve(Object JavaDoc obj) throws IOException JavaDoc {
1349    if (!enableResolve || handles.lookupException(passHandle) != null) {
1350        return obj;
1351    }
1352    Object JavaDoc rep = resolveObject(obj);
1353    if (rep != obj) {
1354        handles.setObject(passHandle, rep);
1355    }
1356    return rep;
1357    }
1358
1359    /**
1360     * Reads string without allowing it to be replaced in stream. Called from
1361     * within ObjectStreamClass.read().
1362     */

1363    String JavaDoc readTypeString() throws IOException JavaDoc {
1364    int oldHandle = passHandle;
1365    try {
1366        switch (bin.peekByte()) {
1367        case TC_NULL:
1368            return (String JavaDoc) readNull();
1369
1370        case TC_REFERENCE:
1371            return (String JavaDoc) readHandle(false);
1372
1373        case TC_STRING:
1374        case TC_LONGSTRING:
1375            return readString(false);
1376
1377        default:
1378            throw new StreamCorruptedException JavaDoc();
1379        }
1380    } finally {
1381        passHandle = oldHandle;
1382    }
1383    }
1384
1385    /**
1386     * Reads in null code, sets passHandle to NULL_HANDLE and returns null.
1387     */

1388    private Object JavaDoc readNull() throws IOException JavaDoc {
1389    if (bin.readByte() != TC_NULL) {
1390        throw new StreamCorruptedException JavaDoc();
1391    }
1392    passHandle = NULL_HANDLE;
1393    return null;
1394    }
1395
1396    /**
1397     * Reads in object handle, sets passHandle to the read handle, and returns
1398     * object associated with the handle.
1399     */

1400    private Object JavaDoc readHandle(boolean unshared) throws IOException JavaDoc {
1401    if (bin.readByte() != TC_REFERENCE) {
1402        throw new StreamCorruptedException JavaDoc();
1403    }
1404    passHandle = bin.readInt() - baseWireHandle;
1405    if (passHandle < 0 || passHandle >= handles.size()) {
1406        throw new StreamCorruptedException JavaDoc("illegal handle value");
1407    }
1408    if (unshared) {
1409        // REMIND: what type of exception to throw here?
1410
throw new InvalidObjectException JavaDoc(
1411        "cannot read back reference as unshared");
1412    }
1413    
1414    Object JavaDoc obj = handles.lookupObject(passHandle);
1415    if (obj == unsharedMarker) {
1416        // REMIND: what type of exception to throw here?
1417
throw new InvalidObjectException JavaDoc(
1418        "cannot read back reference to unshared object");
1419    }
1420    return obj;
1421    }
1422    
1423    /**
1424     * Reads in and returns class object. Sets passHandle to class object's
1425     * assigned handle. Returns null if class is unresolvable (in which case a
1426     * ClassNotFoundException will be associated with the class' handle in the
1427     * handle table).
1428     */

1429    private Class JavaDoc readClass(boolean unshared) throws IOException JavaDoc {
1430    if (bin.readByte() != TC_CLASS) {
1431        throw new StreamCorruptedException JavaDoc();
1432    }
1433    ObjectStreamClass JavaDoc desc = readClassDesc(false);
1434    Class JavaDoc cl = desc.forClass();
1435    passHandle = handles.assign(unshared ? unsharedMarker : cl);
1436
1437    ClassNotFoundException JavaDoc resolveEx = desc.getResolveException();
1438    if (resolveEx != null) {
1439        handles.markException(passHandle, resolveEx);
1440    }
1441
1442    handles.finish(passHandle);
1443    return cl;
1444    }
1445    
1446    /**
1447     * Reads in and returns (possibly null) class descriptor. Sets passHandle
1448     * to class descriptor's assigned handle. If class descriptor cannot be
1449     * resolved to a class in the local VM, a ClassNotFoundException is
1450     * associated with the class descriptor's handle.
1451     */

1452    private ObjectStreamClass JavaDoc readClassDesc(boolean unshared)
1453    throws IOException JavaDoc
1454    {
1455    switch (bin.peekByte()) {
1456        case TC_NULL:
1457        return (ObjectStreamClass JavaDoc) readNull();
1458
1459        case TC_REFERENCE:
1460        return (ObjectStreamClass JavaDoc) readHandle(unshared);
1461
1462        case TC_PROXYCLASSDESC:
1463        return readProxyDesc(unshared);
1464
1465        case TC_CLASSDESC:
1466        return readNonProxyDesc(unshared);
1467        
1468        default:
1469        throw new StreamCorruptedException JavaDoc();
1470    }
1471    }
1472    
1473    /**
1474     * Reads in and returns class descriptor for a dynamic proxy class. Sets
1475     * passHandle to proxy class descriptor's assigned handle. If proxy class
1476     * descriptor cannot be resolved to a class in the local VM, a
1477     * ClassNotFoundException is associated with the descriptor's handle.
1478     */

1479    private ObjectStreamClass JavaDoc readProxyDesc(boolean unshared)
1480    throws IOException JavaDoc
1481    {
1482    if (bin.readByte() != TC_PROXYCLASSDESC) {
1483        throw new StreamCorruptedException JavaDoc();
1484    }
1485    
1486    ObjectStreamClass JavaDoc desc = new ObjectStreamClass JavaDoc();
1487    int descHandle = handles.assign(unshared ? unsharedMarker : desc);
1488    passHandle = NULL_HANDLE;
1489    
1490    int numIfaces = bin.readInt();
1491    String JavaDoc[] ifaces = new String JavaDoc[numIfaces];
1492    for (int i = 0; i < numIfaces; i++) {
1493        ifaces[i] = bin.readUTF();
1494    }
1495    
1496    Class JavaDoc cl = null;
1497    ClassNotFoundException JavaDoc resolveEx = null;
1498    bin.setBlockDataMode(true);
1499    try {
1500        if ((cl = resolveProxyClass(ifaces)) == null) {
1501        throw new ClassNotFoundException JavaDoc("null class");
1502        }
1503    } catch (ClassNotFoundException JavaDoc ex) {
1504        resolveEx = ex;
1505    }
1506    skipCustomData();
1507    
1508    desc.initProxy(cl, resolveEx, readClassDesc(false));
1509
1510    handles.finish(descHandle);
1511    passHandle = descHandle;
1512    return desc;
1513    }
1514    
1515    /**
1516     * Reads in and returns class descriptor for a class that is not a dynamic
1517     * proxy class. Sets passHandle to class descriptor's assigned handle. If
1518     * class descriptor cannot be resolved to a class in the local VM, a
1519     * ClassNotFoundException is associated with the descriptor's handle.
1520     */

1521    private ObjectStreamClass JavaDoc readNonProxyDesc(boolean unshared)
1522    throws IOException JavaDoc
1523    {
1524    if (bin.readByte() != TC_CLASSDESC) {
1525        throw new StreamCorruptedException JavaDoc();
1526    }
1527    
1528    ObjectStreamClass JavaDoc desc = new ObjectStreamClass JavaDoc();
1529    int descHandle = handles.assign(unshared ? unsharedMarker : desc);
1530    passHandle = NULL_HANDLE;
1531
1532    ObjectStreamClass JavaDoc readDesc = null;
1533    try {
1534        readDesc = readClassDescriptor();
1535    } catch (ClassNotFoundException JavaDoc ex) {
1536        throw (IOException JavaDoc) new InvalidClassException JavaDoc(
1537        "failed to read class descriptor").initCause(ex);
1538    }
1539    
1540    Class JavaDoc cl = null;
1541    ClassNotFoundException JavaDoc resolveEx = null;
1542    bin.setBlockDataMode(true);
1543    try {
1544        if ((cl = resolveClass(readDesc)) == null) {
1545        throw new ClassNotFoundException JavaDoc("null class");
1546        }
1547    } catch (ClassNotFoundException JavaDoc ex) {
1548        resolveEx = ex;
1549    }
1550    skipCustomData();
1551    
1552    desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
1553
1554    handles.finish(descHandle);
1555    passHandle = descHandle;
1556    return desc;
1557    }
1558    
1559    /**
1560     * Reads in and returns new string. Sets passHandle to new string's
1561     * assigned handle.
1562     */

1563    private String JavaDoc readString(boolean unshared) throws IOException JavaDoc {
1564    String JavaDoc str;
1565    switch (bin.readByte()) {
1566        case TC_STRING:
1567        str = bin.readUTF();
1568        break;
1569        
1570        case TC_LONGSTRING:
1571        str = bin.readLongUTF();
1572        break;
1573        
1574        default:
1575        throw new StreamCorruptedException JavaDoc();
1576    }
1577    passHandle = handles.assign(unshared ? unsharedMarker : str);
1578    handles.finish(passHandle);
1579    return str;
1580    }
1581    
1582    /**
1583     * Reads in and returns array object, or null if array class is
1584     * unresolvable. Sets passHandle to array's assigned handle.
1585     */

1586    private Object JavaDoc readArray(boolean unshared) throws IOException JavaDoc {
1587    if (bin.readByte() != TC_ARRAY) {
1588        throw new StreamCorruptedException JavaDoc();
1589    }
1590
1591    ObjectStreamClass JavaDoc desc = readClassDesc(false);
1592    int len = bin.readInt();
1593    
1594    Object JavaDoc array = null;
1595    Class JavaDoc cl, ccl = null;
1596    if ((cl = desc.forClass()) != null) {
1597        ccl = cl.getComponentType();
1598        array = Array.newInstance(ccl, len);
1599    }
1600
1601    int arrayHandle = handles.assign(unshared ? unsharedMarker : array);
1602    ClassNotFoundException JavaDoc resolveEx = desc.getResolveException();
1603    if (resolveEx != null) {
1604        handles.markException(arrayHandle, resolveEx);
1605    }
1606    
1607    if (ccl == null) {
1608        for (int i = 0; i < len; i++) {
1609        readObject0(false);
1610        }
1611    } else if (ccl.isPrimitive()) {
1612        if (ccl == Integer.TYPE) {
1613        bin.readInts((int[]) array, 0, len);
1614        } else if (ccl == Byte.TYPE) {
1615        bin.readFully((byte[]) array, 0, len, true);
1616        } else if (ccl == Long.TYPE) {
1617        bin.readLongs((long[]) array, 0, len);
1618        } else if (ccl == Float.TYPE) {
1619        bin.readFloats((float[]) array, 0, len);
1620        } else if (ccl == Double.TYPE) {
1621        bin.readDoubles((double[]) array, 0, len);
1622        } else if (ccl == Short.TYPE) {
1623        bin.readShorts((short[]) array, 0, len);
1624        } else if (ccl == Character.TYPE) {
1625        bin.readChars((char[]) array, 0, len);
1626        } else if (ccl == Boolean.TYPE) {
1627        bin.readBooleans((boolean[]) array, 0, len);
1628        } else {
1629        throw new InternalError JavaDoc();
1630        }
1631    } else {
1632        Object JavaDoc[] oa = (Object JavaDoc[]) array;
1633        for (int i = 0; i < len; i++) {
1634        oa[i] = readObject0(false);
1635        handles.markDependency(arrayHandle, passHandle);
1636        }
1637    }
1638    
1639    handles.finish(arrayHandle);
1640    passHandle = arrayHandle;
1641    return array;
1642    }
1643
1644    /**
1645     * Reads in and returns enum constant, or null if enum type is
1646     * unresolvable. Sets passHandle to enum constant's assigned handle.
1647     */

1648    private Enum JavaDoc readEnum(boolean unshared) throws IOException JavaDoc {
1649    if (bin.readByte() != TC_ENUM) {
1650        throw new StreamCorruptedException JavaDoc();
1651    }
1652
1653    ObjectStreamClass JavaDoc desc = readClassDesc(false);
1654    if (!desc.isEnum()) {
1655        throw new InvalidClassException JavaDoc("non-enum class: " + desc);
1656    }
1657
1658    int enumHandle = handles.assign(unshared ? unsharedMarker : null);
1659    ClassNotFoundException JavaDoc resolveEx = desc.getResolveException();
1660    if (resolveEx != null) {
1661        handles.markException(enumHandle, resolveEx);
1662    }
1663
1664    String JavaDoc name = readString(false);
1665    Enum JavaDoc en = null;
1666    Class JavaDoc cl = desc.forClass();
1667    if (cl != null) {
1668        try {
1669        en = Enum.valueOf(cl, name);
1670        } catch (IllegalArgumentException JavaDoc ex) {
1671        throw (IOException JavaDoc) new InvalidObjectException JavaDoc(
1672            "enum constant " + name + " does not exist in " +
1673            cl).initCause(ex);
1674        }
1675        if (!unshared) {
1676        handles.setObject(enumHandle, en);
1677        }
1678    }
1679
1680    handles.finish(enumHandle);
1681    passHandle = enumHandle;
1682    return en;
1683    }
1684    
1685    /**
1686     * Reads and returns "ordinary" (i.e., not a String, Class,
1687     * ObjectStreamClass, array, or enum constant) object, or null if object's
1688     * class is unresolvable (in which case a ClassNotFoundException will be
1689     * associated with object's handle). Sets passHandle to object's assigned
1690     * handle.
1691     */

1692    private Object JavaDoc readOrdinaryObject(boolean unshared)
1693    throws IOException JavaDoc
1694    {
1695    if (bin.readByte() != TC_OBJECT) {
1696        throw new StreamCorruptedException JavaDoc();
1697    }
1698
1699    ObjectStreamClass JavaDoc desc = readClassDesc(false);
1700    desc.checkDeserialize();
1701
1702    Object JavaDoc obj;
1703    try {
1704        obj = desc.isInstantiable() ? desc.newInstance() : null;
1705    } catch (Exception JavaDoc ex) {
1706        throw new InvalidClassException JavaDoc(
1707        desc.forClass().getName(), "unable to create instance");
1708    }
1709
1710    passHandle = handles.assign(unshared ? unsharedMarker : obj);
1711    ClassNotFoundException JavaDoc resolveEx = desc.getResolveException();
1712    if (resolveEx != null) {
1713        handles.markException(passHandle, resolveEx);
1714    }
1715    
1716    if (desc.isExternalizable()) {
1717        readExternalData((Externalizable JavaDoc) obj, desc);
1718    } else {
1719        readSerialData(obj, desc);
1720    }
1721
1722    handles.finish(passHandle);
1723    
1724    if (obj != null &&
1725        handles.lookupException(passHandle) == null &&
1726        desc.hasReadResolveMethod())
1727    {
1728        Object JavaDoc rep = desc.invokeReadResolve(obj);
1729        if (rep != obj) {
1730        handles.setObject(passHandle, obj = rep);
1731        }
1732    }
1733
1734    return obj;
1735    }
1736    
1737    /**
1738     * If obj is non-null, reads externalizable data by invoking readExternal()
1739     * method of obj; otherwise, attempts to skip over externalizable data.
1740     * Expects that passHandle is set to obj's handle before this method is
1741     * called.
1742     */

1743    private void readExternalData(Externalizable JavaDoc obj, ObjectStreamClass JavaDoc desc)
1744    throws IOException JavaDoc
1745    {
1746    CallbackContext oldContext = curContext;
1747    curContext = null;
1748
1749    boolean blocked = desc.hasBlockExternalData();
1750    if (blocked) {
1751        bin.setBlockDataMode(true);
1752    }
1753    if (obj != null) {
1754        try {
1755        obj.readExternal(this);
1756        } catch (ClassNotFoundException JavaDoc ex) {
1757        /*
1758         * In most cases, the handle table has already propagated a
1759         * CNFException to passHandle at this point; this mark call is
1760         * included to address cases where the readExternal method has
1761         * cons'ed and thrown a new CNFException of its own.
1762         */

1763        handles.markException(passHandle, ex);
1764        }
1765    }
1766    if (blocked) {
1767        skipCustomData();
1768    }
1769    
1770    /*
1771     * At this point, if the externalizable data was not written in
1772     * block-data form and either the externalizable class doesn't exist
1773     * locally (i.e., obj == null) or readExternal() just threw a
1774     * CNFException, then the stream is probably in an inconsistent state,
1775     * since some (or all) of the externalizable data may not have been
1776     * consumed. Since there's no "correct" action to take in this case,
1777     * we mimic the behavior of past serialization implementations and
1778     * blindly hope that the stream is in sync; if it isn't and additional
1779     * externalizable data remains in the stream, a subsequent read will
1780     * most likely throw a StreamCorruptedException.
1781     */

1782
1783    curContext = oldContext;
1784    }
1785    
1786    /**
1787     * Reads (or attempts to skip, if obj is null or is tagged with a
1788     * ClassNotFoundException) instance data for each serializable class of
1789     * object in stream, from superclass to subclass. Expects that passHandle
1790     * is set to obj's handle before this method is called.
1791     */

1792    private void readSerialData(Object JavaDoc obj, ObjectStreamClass JavaDoc desc)
1793    throws IOException JavaDoc
1794    {
1795    ObjectStreamClass.ClassDataSlot JavaDoc[] slots = desc.getClassDataLayout();
1796    for (int i = 0; i < slots.length; i++) {
1797        ObjectStreamClass JavaDoc slotDesc = slots[i].desc;
1798        
1799        if (slots[i].hasData) {
1800        if (obj != null &&
1801            slotDesc.hasReadObjectMethod() &&
1802            handles.lookupException(passHandle) == null)
1803        {
1804            CallbackContext oldContext = curContext;
1805            curContext = new CallbackContext(obj, slotDesc);
1806
1807            bin.setBlockDataMode(true);
1808            try {
1809            slotDesc.invokeReadObject(obj, this);
1810            } catch (ClassNotFoundException JavaDoc ex) {
1811            /*
1812             * In most cases, the handle table has already
1813             * propagated a CNFException to passHandle at this
1814             * point; this mark call is included to address cases
1815             * where the custom readObject method has cons'ed and
1816             * thrown a new CNFException of its own.
1817             */

1818            handles.markException(passHandle, ex);
1819            } finally {
1820            curContext.setUsed();
1821            }
1822
1823            curContext = oldContext;
1824            
1825            /*
1826             * defaultDataEnd may have been set indirectly by custom
1827             * readObject() method when calling defaultReadObject() or
1828             * readFields(); clear it to restore normal read behavior.
1829             */

1830            defaultDataEnd = false;
1831        } else {
1832            defaultReadFields(obj, slotDesc);
1833        }
1834        if (slotDesc.hasWriteObjectData()) {
1835            skipCustomData();
1836        } else {
1837            bin.setBlockDataMode(false);
1838        }
1839        } else {
1840        if (obj != null &&
1841            slotDesc.hasReadObjectNoDataMethod() &&
1842            handles.lookupException(passHandle) == null)
1843        {
1844            slotDesc.invokeReadObjectNoData(obj);
1845        }
1846        }
1847    }
1848    }
1849    
1850    /**
1851     * Skips over all block data and objects until TC_ENDBLOCKDATA is
1852     * encountered.
1853     */

1854    private void skipCustomData() throws IOException JavaDoc {
1855    int oldHandle = passHandle;
1856    for (;;) {
1857        if (bin.getBlockDataMode()) {
1858        bin.skipBlockData();
1859        bin.setBlockDataMode(false);
1860        }
1861        switch (bin.peekByte()) {
1862        case TC_BLOCKDATA:
1863        case TC_BLOCKDATALONG:
1864            bin.setBlockDataMode(true);
1865            break;
1866            
1867        case TC_ENDBLOCKDATA:
1868            bin.readByte();
1869            passHandle = oldHandle;
1870            return;
1871            
1872        default:
1873            readObject0(false);
1874            break;
1875        }
1876    }
1877    }
1878
1879    /**
1880     * Reads in values of serializable fields declared by given class
1881     * descriptor. If obj is non-null, sets field values in obj. Expects that
1882     * passHandle is set to obj's handle before this method is called.
1883     */

1884    private void defaultReadFields(Object JavaDoc obj, ObjectStreamClass JavaDoc desc)
1885    throws IOException JavaDoc
1886    {
1887    // REMIND: is isInstance check necessary?
1888
Class JavaDoc cl = desc.forClass();
1889    if (cl != null && obj != null && !cl.isInstance(obj)) {
1890        throw new ClassCastException JavaDoc();
1891    }
1892
1893    int primDataSize = desc.getPrimDataSize();
1894    if (primVals == null || primVals.length < primDataSize) {
1895        primVals = new byte[primDataSize];
1896    }
1897    bin.readFully(primVals, 0, primDataSize, false);
1898    if (obj != null) {
1899        desc.setPrimFieldValues(obj, primVals);
1900    }
1901    
1902    int objHandle = passHandle;
1903    ObjectStreamField JavaDoc[] fields = desc.getFields(false);
1904    Object JavaDoc[] objVals = new Object JavaDoc[desc.getNumObjFields()];
1905    int numPrimFields = fields.length - objVals.length;
1906    for (int i = 0; i < objVals.length; i++) {
1907        ObjectStreamField JavaDoc f = fields[numPrimFields + i];
1908        objVals[i] = readObject0(f.isUnshared());
1909        if (f.getField() != null) {
1910        handles.markDependency(objHandle, passHandle);
1911        }
1912    }
1913    if (obj != null) {
1914        desc.setObjFieldValues(obj, objVals);
1915    }
1916    passHandle = objHandle;
1917    }
1918
1919    /**
1920     * Reads in and returns IOException that caused serialization to abort.
1921     * All stream state is discarded prior to reading in fatal exception. Sets
1922     * passHandle to fatal exception's handle.
1923     */

1924    private IOException JavaDoc readFatalException() throws IOException JavaDoc {
1925    if (bin.readByte() != TC_EXCEPTION) {
1926        throw new StreamCorruptedException JavaDoc();
1927    }
1928    clear();
1929    return (IOException JavaDoc) readObject0(false);
1930    }
1931    
1932    /**
1933     * If recursion depth is 0, clears internal data structures; otherwise,
1934     * throws a StreamCorruptedException. This method is called when a
1935     * TC_RESET typecode is encountered.
1936     */

1937    private void handleReset() throws StreamCorruptedException JavaDoc {
1938    if (depth > 0) {
1939        throw new StreamCorruptedException JavaDoc("unexpected reset");
1940    }
1941    clear();
1942    }
1943
1944    /**
1945     * Converts specified span of bytes into float values.
1946     */

1947    // REMIND: remove once hotspot inlines Float.intBitsToFloat
1948
private static native void bytesToFloats(byte[] src, int srcpos,
1949                         float[] dst, int dstpos,
1950                         int nfloats);
1951
1952    /**
1953     * Converts specified span of bytes into double values.
1954     */

1955    // REMIND: remove once hotspot inlines Double.longBitsToDouble
1956
private static native void bytesToDoubles(byte[] src, int srcpos,
1957                          double[] dst, int dstpos,
1958                          int ndoubles);
1959    
1960    /**
1961     * Returns the first non-null class loader (not counting class loaders of
1962     * generated reflection implementation classes) up the execution stack, or
1963     * null if only code from the null class loader is on the stack. This
1964     * method is also called via reflection by the following RMI-IIOP class:
1965     *
1966     * com.sun.corba.se.internal.util.JDKClassLoader
1967     *
1968     * This method should not be removed or its signature changed without
1969     * corresponding modifications to the above class.
1970     */

1971    // REMIND: change name to something more accurate?
1972
private static native ClassLoader JavaDoc latestUserDefinedLoader();
1973
1974    /**
1975     * Default GetField implementation.
1976     */

1977    private class GetFieldImpl extends GetField {
1978 
1979    /** class descriptor describing serializable fields */
1980    private final ObjectStreamClass JavaDoc desc;
1981    /** primitive field values */
1982    private final byte[] primVals;
1983    /** object field values */
1984    private final Object JavaDoc[] objVals;
1985    /** object field value handles */
1986    private final int[] objHandles;
1987
1988    /**
1989     * Creates GetFieldImpl object for reading fields defined in given
1990     * class descriptor.
1991     */

1992    GetFieldImpl(ObjectStreamClass JavaDoc desc) {
1993        this.desc = desc;
1994        primVals = new byte[desc.getPrimDataSize()];
1995        objVals = new Object JavaDoc[desc.getNumObjFields()];
1996        objHandles = new int[objVals.length];
1997    }
1998
1999    public ObjectStreamClass JavaDoc getObjectStreamClass() {
2000        return desc;
2001    }
2002 
2003    public boolean defaulted(String JavaDoc name) throws IOException JavaDoc {
2004        return (getFieldOffset(name, null) < 0);
2005    }
2006 
2007    public boolean get(String JavaDoc name, boolean val) throws IOException JavaDoc {
2008        int off = getFieldOffset(name, Boolean.TYPE);
2009        return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
2010    }
2011 
2012    public byte get(String JavaDoc name, byte val) throws IOException JavaDoc {
2013        int off = getFieldOffset(name, Byte.TYPE);
2014        return (off >= 0) ? primVals[off] : val;
2015    }
2016 
2017    public char get(String JavaDoc name, char val) throws IOException JavaDoc {
2018        int off = getFieldOffset(name, Character.TYPE);
2019        return (off >= 0) ? Bits.getChar(primVals, off) : val;
2020    }
2021 
2022    public short get(String JavaDoc name, short val) throws IOException JavaDoc {
2023        int off = getFieldOffset(name, Short.TYPE);
2024        return (off >= 0) ? Bits.getShort(primVals, off) : val;
2025    }
2026 
2027    public int get(String JavaDoc name, int val) throws IOException JavaDoc {
2028        int off = getFieldOffset(name, Integer.TYPE);
2029        return (off >= 0) ? Bits.getInt(primVals, off) : val;
2030    }
2031 
2032    public float get(String JavaDoc name, float val) throws IOException JavaDoc {
2033        int off = getFieldOffset(name, Float.TYPE);
2034        return (off >= 0) ? Bits.getFloat(primVals, off) : val;
2035    }
2036 
2037    public long get(String JavaDoc name, long val) throws IOException JavaDoc {
2038        int off = getFieldOffset(name, Long.TYPE);
2039        return (off >= 0) ? Bits.getLong(primVals, off) : val;
2040    }
2041 
2042    public double get(String JavaDoc name, double val) throws IOException JavaDoc {
2043        int off = getFieldOffset(name, Double.TYPE);
2044        return (off >= 0) ? Bits.getDouble(primVals, off) : val;
2045    }
2046 
2047    public Object JavaDoc get(String JavaDoc name, Object JavaDoc val) throws IOException JavaDoc {
2048        int off = getFieldOffset(name, Object JavaDoc.class);
2049        if (off >= 0) {
2050        int objHandle = objHandles[off];
2051        handles.markDependency(passHandle, objHandle);
2052        return (handles.lookupException(objHandle) == null) ?
2053            objVals[off] : null;
2054        } else {
2055        return val;
2056        }
2057    }
2058
2059    /**
2060     * Reads primitive and object field values from stream.
2061     */

2062    void readFields() throws IOException JavaDoc {
2063        bin.readFully(primVals, 0, primVals.length, false);
2064        
2065        int oldHandle = passHandle;
2066        ObjectStreamField JavaDoc[] fields = desc.getFields(false);
2067        int numPrimFields = fields.length - objVals.length;
2068        for (int i = 0; i < objVals.length; i++) {
2069        objVals[i] =
2070            readObject0(fields[numPrimFields + i].isUnshared());
2071        objHandles[i] = passHandle;
2072        }
2073        passHandle = oldHandle;
2074    }
2075    
2076    /**
2077     * Returns offset of field with given name and type. A specified type
2078     * of null matches all types, Object.class matches all non-primitive
2079     * types, and any other non-null type matches assignable types only.
2080     * If no matching field is found in the (incoming) class
2081     * descriptor but a matching field is present in the associated local
2082     * class descriptor, returns -1. Throws IllegalArgumentException if
2083     * neither incoming nor local class descriptor contains a match.
2084     */

2085    private int getFieldOffset(String JavaDoc name, Class JavaDoc type) {
2086        ObjectStreamField JavaDoc field = desc.getField(name, type);
2087        if (field != null) {
2088        return field.getOffset();
2089        } else if (desc.getLocalDesc().getField(name, type) != null) {
2090        return -1;
2091        } else {
2092        throw new IllegalArgumentException JavaDoc("no such field");
2093        }
2094    }
2095    }
2096 
2097    /**
2098     * Prioritized list of callbacks to be performed once object graph has been
2099     * completely deserialized.
2100     */

2101    private static class ValidationList {
2102
2103    private static class Callback {
2104        final ObjectInputValidation JavaDoc obj;
2105        final int priority;
2106        Callback next;
2107        
2108        Callback(ObjectInputValidation JavaDoc obj, int priority, Callback next) {
2109        this.obj = obj;
2110        this.priority = priority;
2111        this.next = next;
2112        }
2113    }
2114    
2115    /** linked list of callbacks */
2116    private Callback list;
2117
2118    /**
2119     * Creates new (empty) ValidationList.
2120     */

2121    ValidationList() {
2122    }
2123    
2124    /**
2125     * Registers callback. Throws InvalidObjectException if callback
2126     * object is null.
2127     */

2128    void register(ObjectInputValidation JavaDoc obj, int priority)
2129        throws InvalidObjectException JavaDoc
2130    {
2131        if (obj == null) {
2132        throw new InvalidObjectException JavaDoc("null callback");
2133        }
2134        
2135        Callback prev = null, cur = list;
2136        while (cur != null && priority < cur.priority) {
2137        prev = cur;
2138        cur = cur.next;
2139        }
2140        if (prev != null) {
2141        prev.next = new Callback(obj, priority, cur);
2142        } else {
2143        list = new Callback(obj, priority, list);
2144        }
2145    }
2146    
2147    /**
2148     * Invokes all registered callbacks and clears the callback list.
2149     * Callbacks with higher priorities are called first; those with equal
2150     * priorities may be called in any order. If any of the callbacks
2151     * throws an InvalidObjectException, the callback process is terminated
2152     * and the exception propagated upwards.
2153     */

2154    void doCallbacks() throws InvalidObjectException JavaDoc {
2155        try {
2156        while (list != null) {
2157            list.obj.validateObject();
2158            list = list.next;
2159        }
2160        } catch (InvalidObjectException JavaDoc ex) {
2161        list = null;
2162        throw ex;
2163        }
2164    }
2165    
2166    /**
2167     * Resets the callback list to its initial (empty) state.
2168     */

2169    public void clear() {
2170        list = null;
2171    }
2172    }
2173    
2174    /**
2175     * Input stream supporting single-byte peek operations.
2176     */

2177    private static class PeekInputStream extends InputStream JavaDoc {
2178
2179    /** underlying stream */
2180    private final InputStream JavaDoc in;
2181    /** peeked byte */
2182    private int peekb = -1;
2183
2184    /**
2185     * Creates new PeekInputStream on top of given underlying stream.
2186     */

2187    PeekInputStream(InputStream JavaDoc in) {
2188        this.in = in;
2189    }
2190
2191    /**
2192     * Peeks at next byte value in stream. Similar to read(), except
2193     * that it does not consume the read value.
2194     */

2195    int peek() throws IOException JavaDoc {
2196        return (peekb >= 0) ? peekb : (peekb = in.read());
2197    }
2198
2199    public int read() throws IOException JavaDoc {
2200        if (peekb >= 0) {
2201        int v = peekb;
2202        peekb = -1;
2203        return v;
2204        } else {
2205        return in.read();
2206        }
2207    }
2208
2209    public int read(byte[] b, int off, int len) throws IOException JavaDoc {
2210        if (len == 0) {
2211        return 0;
2212        } else if (peekb < 0) {
2213        return in.read(b, off, len);
2214        } else {
2215        b[off++] = (byte) peekb;
2216        len--;
2217        peekb = -1;
2218        int n = in.read(b, off, len);
2219        return (n >= 0) ? (n + 1) : 1;
2220        }
2221    }
2222
2223    void readFully(byte[] b, int off, int len) throws IOException JavaDoc {
2224        int n = 0;
2225        while (n < len) {
2226        int count = read(b, off + n, len - n);
2227        if (count < 0) {
2228            throw new EOFException JavaDoc();
2229        }
2230        n += count;
2231        }
2232    }
2233
2234    public long skip(long n) throws IOException JavaDoc {
2235        if (n <= 0) {
2236        return 0;
2237        }
2238        int skipped = 0;
2239        if (peekb >= 0) {
2240        peekb = -1;
2241        skipped++;
2242        n--;
2243        }
2244        return skipped + skip(n);
2245    }
2246
2247    public int available() throws IOException JavaDoc {
2248        return in.available() + ((peekb >= 0) ? 1 : 0);
2249    }
2250
2251    public void close() throws IOException JavaDoc {
2252        in.close();
2253    }
2254    }
2255
2256    /**
2257     * Input stream with two modes: in default mode, inputs data written in the
2258     * same format as DataOutputStream; in "block data" mode, inputs data
2259     * bracketed by block data markers (see object serialization specification
2260     * for details). Buffering depends on block data mode: when in default
2261     * mode, no data is buffered in advance; when in block data mode, all data
2262     * for the current data block is read in at once (and buffered).
2263     */

2264    private class BlockDataInputStream
2265    extends InputStream JavaDoc implements DataInput JavaDoc
2266    {
2267    /** maximum data block length */
2268    private static final int MAX_BLOCK_SIZE = 1024;
2269    /** maximum data block header length */
2270    private static final int MAX_HEADER_SIZE = 5;
2271    /** (tunable) length of char buffer (for reading strings) */
2272    private static final int CHAR_BUF_SIZE = 256;
2273    /** readBlockHeader() return value indicating header read may block */
2274    private static final int HEADER_BLOCKED = -2;
2275
2276    /** buffer for reading general/block data */
2277    private final byte[] buf = new byte[MAX_BLOCK_SIZE];
2278    /** buffer for reading block data headers */
2279    private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
2280    /** char buffer for fast string reads */
2281    private final char[] cbuf = new char[CHAR_BUF_SIZE];
2282
2283    /** block data mode */
2284    private boolean blkmode = false;
2285
2286    // block data state fields; values meaningful only when blkmode true
2287
/** current offset into buf */
2288    private int pos = 0;
2289    /** end offset of valid data in buf, or -1 if no more block data */
2290    private int end = -1;
2291    /** number of bytes in current block yet to be read from stream */
2292    private int unread = 0;
2293
2294    /** underlying stream (wrapped in peekable filter stream) */
2295    private final PeekInputStream in;
2296    /** loopback stream (for data reads that span data blocks) */
2297    private final DataInputStream JavaDoc din;
2298
2299    /**
2300     * Creates new BlockDataInputStream on top of given underlying stream.
2301     * Block data mode is turned off by default.
2302     */

2303    BlockDataInputStream(InputStream JavaDoc in) {
2304        this.in = new PeekInputStream(in);
2305        din = new DataInputStream JavaDoc(this);
2306    }
2307
2308    /**
2309     * Sets block data mode to the given mode (true == on, false == off)
2310     * and returns the previous mode value. If the new mode is the same as
2311     * the old mode, no action is taken. Throws IllegalStateException if
2312     * block data mode is being switched from on to off while unconsumed
2313     * block data is still present in the stream.
2314     */

2315    boolean setBlockDataMode(boolean newmode) throws IOException JavaDoc {
2316        if (blkmode == newmode) {
2317        return blkmode;
2318        }
2319        if (newmode) {
2320        pos = 0;
2321        end = 0;
2322        unread = 0;
2323        } else if (pos < end) {
2324        throw new IllegalStateException JavaDoc("unread block data");
2325        }
2326        blkmode = newmode;
2327        return !blkmode;
2328    }
2329
2330    /**
2331     * Returns true if the stream is currently in block data mode, false
2332     * otherwise.
2333     */

2334    boolean getBlockDataMode() {
2335        return blkmode;
2336    }
2337
2338    /**
2339     * If in block data mode, skips to the end of the current group of data
2340     * blocks (but does not unset block data mode). If not in block data
2341     * mode, throws an IllegalStateException.
2342     */

2343    void skipBlockData() throws IOException JavaDoc {
2344        if (!blkmode) {
2345        throw new IllegalStateException JavaDoc("not in block data mode");
2346        }
2347        while (end >= 0) {
2348        refill();
2349        }
2350    }
2351
2352    /**
2353     * Attempts to read in the next block data header (if any). If
2354     * canBlock is false and a full header cannot be read without possibly
2355     * blocking, returns HEADER_BLOCKED, else if the next element in the
2356     * stream is a block data header, returns the block data length
2357     * specified by the header, else returns -1.
2358     */

2359    private int readBlockHeader(boolean canBlock) throws IOException JavaDoc {
2360        if (defaultDataEnd) {
2361        /*
2362         * Fix for 4360508: stream is currently at the end of a field
2363         * value block written via default serialization; since there
2364         * is no terminating TC_ENDBLOCKDATA tag, simulate
2365         * end-of-custom-data behavior explicitly.
2366         */

2367        return -1;
2368        }
2369        try {
2370        for (;;) {
2371            int avail = canBlock ? Integer.MAX_VALUE : in.available();
2372            if (avail == 0) {
2373            return HEADER_BLOCKED;
2374            }
2375            
2376            int tc = in.peek();
2377            switch (tc) {
2378            case TC_BLOCKDATA:
2379                if (avail < 2) {
2380                return HEADER_BLOCKED;
2381                }
2382                in.readFully(hbuf, 0, 2);
2383                return hbuf[1] & 0xFF;
2384                
2385            case TC_BLOCKDATALONG:
2386                if (avail < 5) {
2387                return HEADER_BLOCKED;
2388                }
2389                in.readFully(hbuf, 0, 5);
2390                int len = Bits.getInt(hbuf, 1);
2391                if (len < 0) {
2392                throw new StreamCorruptedException JavaDoc(
2393                    "illegal block data header length");
2394                }
2395                return len;
2396
2397            /*
2398             * TC_RESETs may occur in between data blocks.
2399             * Unfortunately, this case must be parsed at a lower
2400             * level than other typecodes, since primitive data
2401             * reads may span data blocks separated by a TC_RESET.
2402             */

2403            case TC_RESET:
2404                in.read();
2405                handleReset();
2406                break;
2407
2408            default:
2409                if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
2410                throw new StreamCorruptedException JavaDoc();
2411                }
2412                return -1;
2413            }
2414        }
2415        } catch (EOFException JavaDoc ex) {
2416        throw new StreamCorruptedException JavaDoc(
2417            "unexpected EOF while reading block data header");
2418        }
2419    }
2420
2421    /**
2422     * Refills internal buffer buf with block data. Any data in buf at the
2423     * time of the call is considered consumed. Sets the pos, end, and
2424     * unread fields to reflect the new amount of available block data; if
2425     * the next element in the stream is not a data block, sets pos and
2426     * unread to 0 and end to -1.
2427     */

2428    private void refill() throws IOException JavaDoc {
2429        try {
2430        do {
2431            pos = 0;
2432            if (unread > 0) {
2433            int n =
2434                in.read(buf, 0, Math.min(unread, MAX_BLOCK_SIZE));
2435            if (n >= 0) {
2436                end = n;
2437                unread -= n;
2438            } else {
2439                throw new StreamCorruptedException JavaDoc(
2440                "unexpected EOF in middle of data block");
2441            }
2442            } else {
2443            int n = readBlockHeader(true);
2444            if (n >= 0) {
2445                end = 0;
2446                unread = n;
2447            } else {
2448                end = -1;
2449                unread = 0;
2450            }
2451            }
2452        } while (pos == end);
2453        } catch (IOException JavaDoc ex) {
2454        pos = 0;
2455        end = -1;
2456        unread = 0;
2457        throw ex;
2458        }
2459    }
2460    
2461    /**
2462     * If in block data mode, returns the number of unconsumed bytes
2463     * remaining in the current data block. If not in block data mode,
2464     * throws an IllegalStateException.
2465     */

2466    int currentBlockRemaining() {
2467        if (blkmode) {
2468        return (end >= 0) ? (end - pos) + unread : 0;
2469        } else {
2470        throw new IllegalStateException JavaDoc();
2471        }
2472    }
2473
2474    /**
2475     * Peeks at (but does not consume) and returns the next byte value in
2476     * the stream, or -1 if the end of the stream/block data (if in block
2477     * data mode) has been reached.
2478     */

2479    int peek() throws IOException JavaDoc {
2480        if (blkmode) {
2481        if (pos == end) {
2482            refill();
2483        }
2484        return (end >= 0) ? (buf[pos] & 0xFF) : -1;
2485        } else {
2486        return in.peek();
2487        }
2488    }
2489
2490    /**
2491     * Peeks at (but does not consume) and returns the next byte value in
2492     * the stream, or throws EOFException if end of stream/block data has
2493     * been reached.
2494     */

2495    byte peekByte() throws IOException JavaDoc {
2496        int val = peek();
2497        if (val < 0) {
2498        throw new EOFException JavaDoc();
2499        }
2500        return (byte) val;
2501    }
2502
2503
2504    /* ----------------- generic input stream methods ------------------ */
2505    /*
2506     * The following methods are equivalent to their counterparts in
2507     * InputStream, except that they interpret data block boundaries and
2508     * read the requested data from within data blocks when in block data
2509     * mode.
2510     */

2511
2512    public int read() throws IOException JavaDoc {
2513        if (blkmode) {
2514        if (pos == end) {
2515            refill();
2516        }
2517        return (end >= 0) ? (buf[pos++] & 0xFF) : -1;
2518        } else {
2519        return in.read();
2520        }
2521    }
2522
2523    public int read(byte[] b, int off, int len) throws IOException JavaDoc {
2524        return read(b, off, len, false);
2525    }
2526
2527    public long skip(long len) throws IOException JavaDoc {
2528        long remain = len;
2529        while (remain > 0) {
2530        if (blkmode) {
2531            if (pos == end) {
2532            refill();
2533            }
2534            if (end < 0) {
2535            break;
2536            }
2537            int nread = (int) Math.min(remain, end - pos);
2538            remain -= nread;
2539            pos += nread;
2540        } else {
2541            int nread = (int) Math.min(remain, MAX_BLOCK_SIZE);
2542            if ((nread = in.read(buf, 0, nread)) < 0) {
2543            break;
2544            }
2545            remain -= nread;
2546        }
2547        }
2548        return len - remain;
2549    }
2550
2551    public int available() throws IOException JavaDoc {
2552        if (blkmode) {
2553        if ((pos == end) && (unread == 0)) {
2554            int n;
2555            while ((n = readBlockHeader(false)) == 0) ;
2556            switch (n) {
2557            case HEADER_BLOCKED:
2558                break;
2559                
2560            case -1:
2561                pos = 0;
2562                end = -1;
2563                break;
2564                
2565            default:
2566                pos = 0;
2567                end = 0;
2568                unread = n;
2569                break;
2570            }
2571        }
2572        // avoid unnecessary call to in.available() if possible
2573
int unreadAvail = (unread > 0) ?
2574            Math.min(in.available(), unread) : 0;
2575        return (end >= 0) ? (end - pos) + unreadAvail : 0;
2576        } else {
2577        return in.available();
2578        }
2579    }
2580
2581    public void close() throws IOException JavaDoc {
2582        if (blkmode) {
2583        pos = 0;
2584        end = -1;
2585        unread = 0;
2586        }
2587        in.close();
2588    }
2589
2590    /**
2591     * Attempts to read len bytes into byte array b at offset off. Returns
2592     * the number of bytes read, or -1 if the end of stream/block data has
2593     * been reached. If copy is true, reads values into an intermediate
2594     * buffer before copying them to b (to avoid exposing a reference to
2595     * b).
2596     */

2597    int read(byte[] b, int off, int len, boolean copy) throws IOException JavaDoc {
2598        if (len == 0) {
2599        return 0;
2600        } else if (blkmode) {
2601        if (pos == end) {
2602            refill();
2603        }
2604        if (end < 0) {
2605            return -1;
2606        }
2607        int nread = Math.min(len, end - pos);
2608        System.arraycopy(buf, pos, b, off, nread);
2609        pos += nread;
2610        return nread;
2611        } else if (copy) {
2612        int nread = in.read(buf, 0, Math.min(len, MAX_BLOCK_SIZE));
2613        if (nread > 0) {
2614            System.arraycopy(buf, 0, b, off, nread);
2615        }
2616        return nread;
2617        } else {
2618        return in.read(b, off, len);
2619        }
2620    }
2621
2622    /* ----------------- primitive data input methods ------------------ */
2623    /*
2624     * The following methods are equivalent to their counterparts in
2625     * DataInputStream, except that they interpret data block boundaries
2626     * and read the requested data from within data blocks when in block
2627     * data mode.
2628     */

2629
2630    public void readFully(byte[] b) throws IOException JavaDoc {
2631        readFully(b, 0, b.length, false);
2632    }
2633
2634    public void readFully(byte[] b, int off, int len) throws IOException JavaDoc {
2635        readFully(b, off, len, false);
2636    }
2637
2638    public void readFully(byte[] b, int off, int len, boolean copy)
2639        throws IOException JavaDoc
2640    {
2641        while (len > 0) {
2642        int n = read(b, off, len, copy);
2643        if (n < 0) {
2644            throw new EOFException JavaDoc();
2645        }
2646        off += n;
2647        len -= n;
2648        }
2649    }
2650
2651    public int skipBytes(int n) throws IOException JavaDoc {
2652        return din.skipBytes(n);
2653    }
2654
2655    public boolean readBoolean() throws IOException JavaDoc {
2656        int v = read();
2657        if (v < 0) {
2658        throw new EOFException JavaDoc();
2659        }
2660        return (v != 0);
2661    }
2662
2663    public byte readByte() throws IOException JavaDoc {
2664        int v = read();
2665        if (v < 0) {
2666        throw new EOFException JavaDoc();
2667        }
2668        return (byte) v;
2669    }
2670
2671    public int readUnsignedByte() throws IOException JavaDoc {
2672        int v = read();
2673        if (v < 0) {
2674        throw new EOFException JavaDoc();
2675        }
2676        return v;
2677    }
2678
2679    public char readChar() throws IOException JavaDoc {
2680        if (!blkmode) {
2681        pos = 0;
2682        in.readFully(buf, 0, 2);
2683        } else if (end - pos < 2) {
2684        return din.readChar();
2685        }
2686        char v = Bits.getChar(buf, pos);
2687        pos += 2;
2688        return v;
2689    }
2690
2691    public short readShort() throws IOException JavaDoc {
2692        if (!blkmode) {
2693        pos = 0;
2694        in.readFully(buf, 0, 2);
2695        } else if (end - pos < 2) {
2696        return din.readShort();
2697        }
2698        short v = Bits.getShort(buf, pos);
2699        pos += 2;
2700        return v;
2701    }
2702
2703    public int readUnsignedShort() throws IOException JavaDoc {
2704        if (!blkmode) {
2705        pos = 0;
2706        in.readFully(buf, 0, 2);
2707        } else if (end - pos < 2) {
2708        return din.readUnsignedShort();
2709        }
2710        int v = Bits.getShort(buf, pos) & 0xFFFF;
2711        pos += 2;
2712        return v;
2713    }
2714
2715    public int readInt() throws IOException JavaDoc {
2716        if (!blkmode) {
2717        pos = 0;
2718        in.readFully(buf, 0, 4);
2719        } else if (end - pos < 4) {
2720        return din.readInt();
2721        }
2722        int v = Bits.getInt(buf, pos);
2723        pos += 4;
2724        return v;
2725    }
2726
2727    public float readFloat() throws IOException JavaDoc {
2728        if (!blkmode) {
2729        pos = 0;
2730        in.readFully(buf, 0, 4);
2731        } else if (end - pos < 4) {
2732        return din.readFloat();
2733        }
2734        float v = Bits.getFloat(buf, pos);
2735        pos += 4;
2736        return v;
2737    }
2738
2739    public long readLong() throws IOException JavaDoc {
2740        if (!blkmode) {
2741        pos = 0;
2742        in.readFully(buf, 0, 8);
2743        } else if (end - pos < 8) {
2744        return din.readLong();
2745        }
2746        long v = Bits.getLong(buf, pos);
2747        pos += 8;
2748        return v;
2749    }
2750
2751    public double readDouble() throws IOException JavaDoc {
2752        if (!blkmode) {
2753        pos = 0;
2754        in.readFully(buf, 0, 8);
2755        } else if (end - pos < 8) {
2756        return din.readDouble();
2757        }
2758        double v = Bits.getDouble(buf, pos);
2759        pos += 8;
2760        return v;
2761    }
2762
2763    public String JavaDoc readUTF() throws IOException JavaDoc {
2764        return readUTFBody(readUnsignedShort());
2765    }
2766
2767    public String JavaDoc readLine() throws IOException JavaDoc {
2768        return din.readLine(); // deprecated, not worth optimizing
2769
}
2770    
2771    /* -------------- primitive data array input methods --------------- */
2772    /*
2773     * The following methods read in spans of primitive data values.
2774     * Though equivalent to calling the corresponding primitive read
2775     * methods repeatedly, these methods are optimized for reading groups
2776     * of primitive data values more efficiently.
2777     */

2778
2779    void readBooleans(boolean[] v, int off, int len) throws IOException JavaDoc {
2780        int stop, endoff = off + len;
2781        while (off < endoff) {
2782        if (!blkmode) {
2783            int span = Math.min(endoff - off, MAX_BLOCK_SIZE);
2784            in.readFully(buf, 0, span);
2785            stop = off + span;
2786            pos = 0;
2787        } else if (end - pos < 1) {
2788            v[off++] = din.readBoolean();
2789            continue;
2790        } else {
2791            stop = Math.min(endoff, off + end - pos);
2792        }
2793
2794        while (off < stop) {
2795            v[off++] = Bits.getBoolean(buf, pos++);
2796        }
2797        }
2798    }
2799
2800    void readChars(char[] v, int off, int len) throws IOException JavaDoc {
2801        int stop, endoff = off + len;
2802        while (off < endoff) {
2803        if (!blkmode) {
2804            int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
2805            in.readFully(buf, 0, span << 1);
2806            stop = off + span;
2807            pos = 0;
2808        } else if (end - pos < 2) {
2809            v[off++] = din.readChar();
2810            continue;
2811        } else {
2812            stop = Math.min(endoff, off + ((end - pos) >> 1));
2813        }
2814        
2815        while (off < stop) {
2816            v[off++] = Bits.getChar(buf, pos);
2817            pos += 2;
2818        }
2819        }
2820    }
2821
2822    void readShorts(short[] v, int off, int len) throws IOException JavaDoc {
2823        int stop, endoff = off + len;
2824        while (off < endoff) {
2825        if (!blkmode) {
2826            int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
2827            in.readFully(buf, 0, span << 1);
2828            stop = off + span;
2829            pos = 0;
2830        } else if (end - pos < 2) {
2831            v[off++] = din.readShort();
2832            continue;
2833        } else {
2834            stop = Math.min(endoff, off + ((end - pos) >> 1));
2835        }
2836        
2837        while (off < stop) {
2838            v[off++] = Bits.getShort(buf, pos);
2839            pos += 2;
2840        }
2841        }
2842    }
2843
2844    void readInts(int[] v, int off, int len) throws IOException JavaDoc {
2845        int stop, endoff = off + len;
2846        while (off < endoff) {
2847        if (!blkmode) {
2848            int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
2849            in.readFully(buf, 0, span << 2);
2850            stop = off + span;
2851            pos = 0;
2852        } else if (end - pos < 4) {
2853            v[off++] = din.readInt();
2854            continue;
2855        } else {
2856            stop = Math.min(endoff, off + ((end - pos) >> 2));
2857        }
2858        
2859        while (off < stop) {
2860            v[off++] = Bits.getInt(buf, pos);
2861            pos += 4;
2862        }
2863        }
2864    }
2865
2866    void readFloats(float[] v, int off, int len) throws IOException JavaDoc {
2867        int span, endoff = off + len;
2868        while (off < endoff) {
2869        if (!blkmode) {
2870            span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
2871            in.readFully(buf, 0, span << 2);
2872            pos = 0;
2873        } else if (end - pos < 4) {
2874            v[off++] = din.readFloat();
2875            continue;
2876        } else {
2877            span = Math.min(endoff - off, ((end - pos) >> 2));
2878        }
2879        
2880        bytesToFloats(buf, pos, v, off, span);
2881        off += span;
2882        pos += span << 2;
2883        }
2884    }
2885
2886    void readLongs(long[] v, int off, int len) throws IOException JavaDoc {
2887        int stop, endoff = off + len;
2888        while (off < endoff) {
2889        if (!blkmode) {
2890            int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
2891            in.readFully(buf, 0, span << 3);
2892            stop = off + span;
2893            pos = 0;
2894        } else if (end - pos < 8) {
2895            v[off++] = din.readLong();
2896            continue;
2897        } else {
2898            stop = Math.min(endoff, off + ((end - pos) >> 3));
2899        }
2900        
2901        while (off < stop) {
2902            v[off++] = Bits.getLong(buf, pos);
2903            pos += 8;
2904        }
2905        }
2906    }
2907
2908    void readDoubles(double[] v, int off, int len) throws IOException JavaDoc {
2909        int span, endoff = off + len;
2910        while (off < endoff) {
2911        if (!blkmode) {
2912            span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
2913            in.readFully(buf, 0, span << 3);
2914            pos = 0;
2915        } else if (end - pos < 8) {
2916            v[off++] = din.readDouble();
2917            continue;
2918        } else {
2919            span = Math.min(endoff - off, ((end - pos) >> 3));
2920        }
2921        
2922        bytesToDoubles(buf, pos, v, off, span);
2923        off += span;
2924        pos += span << 3;
2925        }
2926    }
2927
2928    /**
2929     * Reads in string written in "long" UTF format. "Long" UTF format is
2930     * identical to standard UTF, except that it uses an 8 byte header
2931     * (instead of the standard 2 bytes) to convey the UTF encoding length.
2932     */

2933    String JavaDoc readLongUTF() throws IOException JavaDoc {
2934        return readUTFBody(readLong());
2935    }
2936
2937    /**
2938     * Reads in the "body" (i.e., the UTF representation minus the 2-byte
2939     * or 8-byte length header) of a UTF encoding, which occupies the next
2940     * utflen bytes.
2941     */

2942    private String JavaDoc readUTFBody(long utflen) throws IOException JavaDoc {
2943        StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
2944        if (!blkmode) {
2945        end = pos = 0;
2946        }
2947
2948        while (utflen > 0) {
2949        int avail = end - pos;
2950        if (avail >= 3 || (long) avail == utflen) {
2951            utflen -= readUTFSpan(sbuf, utflen);
2952        } else {
2953            if (blkmode) {
2954            // near block boundary, read one byte at a time
2955
utflen -= readUTFChar(sbuf, utflen);
2956            } else {
2957            // shift and refill buffer manually
2958
if (avail > 0) {
2959                System.arraycopy(buf, pos, buf, 0, avail);
2960            }
2961            pos = 0;
2962            end = (int) Math.min(MAX_BLOCK_SIZE, utflen);
2963            in.readFully(buf, avail, end - avail);
2964            }
2965        }
2966        }
2967
2968        return sbuf.toString();
2969    }
2970
2971    /**
2972     * Reads span of UTF-encoded characters out of internal buffer
2973     * (starting at offset pos and ending at or before offset end),
2974     * consuming no more than utflen bytes. Appends read characters to
2975     * sbuf. Returns the number of bytes consumed.
2976     */

2977    private long readUTFSpan(StringBuffer JavaDoc sbuf, long utflen)
2978        throws IOException JavaDoc
2979    {
2980        int cpos = 0;
2981        int start = pos;
2982        int avail = Math.min(end - pos, CHAR_BUF_SIZE);
2983        // stop short of last char unless all of utf bytes in buffer
2984
int stop = pos + ((utflen > avail) ? avail - 2 : (int) utflen);
2985        boolean outOfBounds = false;
2986
2987        try {
2988        while (pos < stop) {
2989            int b1, b2, b3;
2990            b1 = buf[pos++] & 0xFF;
2991            switch (b1 >> 4) {
2992            case 0:
2993            case 1:
2994            case 2:
2995            case 3:
2996            case 4:
2997            case 5:
2998            case 6:
2999            case 7: // 1 byte format: 0xxxxxxx
3000
cbuf[cpos++] = (char) b1;
3001                break;
3002
3003            case 12:
3004            case 13: // 2 byte format: 110xxxxx 10xxxxxx
3005
b2 = buf[pos++];
3006                if ((b2 & 0xC0) != 0x80) {
3007                throw new UTFDataFormatException JavaDoc();
3008                }
3009                cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) |
3010                           ((b2 & 0x3F) << 0));
3011                break;
3012
3013            case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3014
b3 = buf[pos + 1];
3015                b2 = buf[pos + 0];
3016                pos += 2;
3017                if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3018                throw new UTFDataFormatException JavaDoc();
3019                }
3020                cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) |
3021                           ((b2 & 0x3F) << 6) |
3022                           ((b3 & 0x3F) << 0));
3023                break;
3024
3025            default: // 10xx xxxx, 1111 xxxx
3026
throw new UTFDataFormatException JavaDoc();
3027            }
3028        }
3029        } catch (ArrayIndexOutOfBoundsException JavaDoc ex) {
3030        outOfBounds = true;
3031        } finally {
3032        if (outOfBounds || (pos - start) > utflen) {
3033            /*
3034             * Fix for 4450867: if a malformed utf char causes the
3035             * conversion loop to scan past the expected end of the utf
3036             * string, only consume the expected number of utf bytes.
3037             */

3038            pos = start + (int) utflen;
3039            throw new UTFDataFormatException JavaDoc();
3040        }
3041        }
3042
3043        sbuf.append(cbuf, 0, cpos);
3044        return pos - start;
3045    }
3046
3047    /**
3048     * Reads in single UTF-encoded character one byte at a time, appends
3049     * the character to sbuf, and returns the number of bytes consumed.
3050     * This method is used when reading in UTF strings written in block
3051     * data mode to handle UTF-encoded characters which (potentially)
3052     * straddle block-data boundaries.
3053     */

3054    private int readUTFChar(StringBuffer JavaDoc sbuf, long utflen)
3055        throws IOException JavaDoc
3056    {
3057        int b1, b2, b3;
3058        b1 = readByte() & 0xFF;
3059        switch (b1 >> 4) {
3060        case 0:
3061        case 1:
3062        case 2:
3063        case 3:
3064        case 4:
3065        case 5:
3066        case 6:
3067        case 7: // 1 byte format: 0xxxxxxx
3068
sbuf.append((char) b1);
3069            return 1;
3070
3071        case 12:
3072        case 13: // 2 byte format: 110xxxxx 10xxxxxx
3073
if (utflen < 2) {
3074            throw new UTFDataFormatException JavaDoc();
3075            }
3076            b2 = readByte();
3077            if ((b2 & 0xC0) != 0x80) {
3078            throw new UTFDataFormatException JavaDoc();
3079            }
3080            sbuf.append((char) (((b1 & 0x1F) << 6) |
3081                    ((b2 & 0x3F) << 0)));
3082            return 2;
3083
3084        case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3085
if (utflen < 3) {
3086            if (utflen == 2) {
3087                readByte(); // consume remaining byte
3088
}
3089            throw new UTFDataFormatException JavaDoc();
3090            }
3091            b2 = readByte();
3092            b3 = readByte();
3093            if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3094            throw new UTFDataFormatException JavaDoc();
3095            }
3096            sbuf.append((char) (((b1 & 0x0F) << 12) |
3097                    ((b2 & 0x3F) << 6) |
3098                    ((b3 & 0x3F) << 0)));
3099            return 3;
3100
3101        default: // 10xx xxxx, 1111 xxxx
3102
throw new UTFDataFormatException JavaDoc();
3103        }
3104    }
3105    }
3106
3107    /**
3108     * Unsynchronized table which tracks wire handle to object mappings, as
3109     * well as ClassNotFoundExceptions associated with deserialized objects.
3110     * This class implements an exception-propagation algorithm for
3111     * determining which objects should have ClassNotFoundExceptions associated
3112     * with them, taking into account cycles and discontinuities (e.g., skipped
3113     * fields) in the object graph.
3114     *
3115     * <p>General use of the table is as follows: during deserialization, a
3116     * given object is first assigned a handle by calling the assign method.
3117     * This method leaves the assigned handle in an "open" state, wherein
3118     * dependencies on the exception status of other handles can be registered
3119     * by calling the markDependency method, or an exception can be directly
3120     * associated with the handle by calling markException. When a handle is
3121     * tagged with an exception, the HandleTable assumes responsibility for
3122     * propagating the exception to any other objects which depend
3123     * (transitively) on the exception-tagged object.
3124     *
3125     * <p>Once all exception information/dependencies for the handle have been
3126     * registered, the handle should be "closed" by calling the finish method
3127     * on it. The act of finishing a handle allows the exception propagation
3128     * algorithm to aggressively prune dependency links, lessening the
3129     * performance/memory impact of exception tracking.
3130     *
3131     * <p>Note that the exception propagation algorithm used depends on handles
3132     * being assigned/finished in LIFO order; however, for simplicity as well
3133     * as memory conservation, it does not enforce this constraint.
3134     */

3135    // REMIND: add full description of exception propagation algorithm?
3136
private static class HandleTable {
3137
3138    /* status codes indicating whether object has associated exception */
3139    private static final byte STATUS_OK = 1;
3140    private static final byte STATUS_UNKNOWN = 2;
3141    private static final byte STATUS_EXCEPTION = 3;
3142    
3143    /** array mapping handle -> object status */
3144    byte[] status;
3145    /** array mapping handle -> object/exception (depending on status) */
3146    Object JavaDoc[] entries;
3147    /** array mapping handle -> list of dependent handles (if any) */
3148    HandleList[] deps;
3149    /** lowest unresolved dependency */
3150    int lowDep = -1;
3151    /** number of handles in table */
3152    int size = 0;
3153
3154    /**
3155     * Creates handle table with the given initial capacity.
3156     */

3157    HandleTable(int initialCapacity) {
3158        status = new byte[initialCapacity];
3159        entries = new Object JavaDoc[initialCapacity];
3160        deps = new HandleList[initialCapacity];
3161    }
3162    
3163    /**
3164     * Assigns next available handle to given object, and returns assigned
3165     * handle. Once object has been completely deserialized (and all
3166     * dependencies on other objects identified), the handle should be
3167     * "closed" by passing it to finish().
3168     */

3169    int assign(Object JavaDoc obj) {
3170        if (size >= entries.length) {
3171        grow();
3172        }
3173        status[size] = STATUS_UNKNOWN;
3174        entries[size] = obj;
3175        return size++;
3176    }
3177
3178    /**
3179     * Registers a dependency (in exception status) of one handle on
3180     * another. The dependent handle must be "open" (i.e., assigned, but
3181     * not finished yet). No action is taken if either dependent or target
3182     * handle is NULL_HANDLE.
3183     */

3184    void markDependency(int dependent, int target) {
3185        if (dependent == NULL_HANDLE || target == NULL_HANDLE) {
3186        return;
3187        }
3188        switch (status[dependent]) {
3189
3190        case STATUS_UNKNOWN:
3191            switch (status[target]) {
3192            case STATUS_OK:
3193                // ignore dependencies on objs with no exception
3194
break;
3195                
3196            case STATUS_EXCEPTION:
3197                // eagerly propagate exception
3198
markException(dependent,
3199                (ClassNotFoundException JavaDoc) entries[target]);
3200                break;
3201                
3202            case STATUS_UNKNOWN:
3203                // add to dependency list of target
3204
if (deps[target] == null) {
3205                deps[target] = new HandleList();
3206                }
3207                deps[target].add(dependent);
3208                
3209                // remember lowest unresolved target seen
3210
if (lowDep < 0 || lowDep > target) {
3211                lowDep = target;
3212                }
3213                break;
3214                
3215            default:
3216                throw new InternalError JavaDoc();
3217            }
3218            break;
3219
3220        case STATUS_EXCEPTION:
3221            break;
3222
3223        default:
3224            throw new InternalError JavaDoc();
3225        }
3226    }
3227    
3228    /**
3229     * Associates a ClassNotFoundException (if one not already associated)
3230     * with the currently active handle and propagates it to other
3231     * referencing objects as appropriate. The specified handle must be
3232     * "open" (i.e., assigned, but not finished yet).
3233     */

3234    void markException(int handle, ClassNotFoundException JavaDoc ex) {
3235        switch (status[handle]) {
3236        case STATUS_UNKNOWN:
3237            status[handle] = STATUS_EXCEPTION;
3238            entries[handle] = ex;
3239            
3240            // propagate exception to dependents
3241
HandleList dlist = deps[handle];
3242            if (dlist != null) {
3243            int ndeps = dlist.size();
3244            for (int i = 0; i < ndeps; i++) {
3245                markException(dlist.get(i), ex);
3246            }
3247            deps[handle] = null;
3248            }
3249            break;
3250            
3251        case STATUS_EXCEPTION:
3252            break;
3253            
3254        default:
3255            throw new InternalError JavaDoc();
3256        }
3257    }
3258
3259    /**
3260     * Marks given handle as finished, meaning that no new dependencies
3261     * will be marked for handle. Calls to the assign and finish methods
3262     * must occur in LIFO order.
3263     */

3264    void finish(int handle) {
3265        int end;
3266        if (lowDep < 0) {
3267        // no pending unknowns, only resolve current handle
3268
end = handle + 1;
3269        } else if (lowDep >= handle) {
3270        // pending unknowns now clearable, resolve all upward handles
3271
end = size;
3272        lowDep = -1;
3273        } else {
3274        // unresolved backrefs present, can't resolve anything yet
3275
return;
3276        }
3277        
3278        // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
3279
for (int i = handle; i < end; i++) {
3280        switch (status[i]) {
3281            case STATUS_UNKNOWN:
3282            status[i] = STATUS_OK;
3283            deps[i] = null;
3284            break;
3285            
3286            case STATUS_OK:
3287            case STATUS_EXCEPTION:
3288            break;
3289            
3290            default:
3291            throw new InternalError JavaDoc();
3292        }
3293        }
3294    }
3295
3296    /**
3297     * Assigns a new object to the given handle. The object previously
3298     * associated with the handle is forgotten. This method has no effect
3299     * if the given handle already has an exception associated with it.
3300     * This method may be called at any time after the handle is assigned.
3301     */

3302    void setObject(int handle, Object JavaDoc obj) {
3303        switch (status[handle]) {
3304        case STATUS_UNKNOWN:
3305        case STATUS_OK:
3306            entries[handle] = obj;
3307            break;
3308            
3309        case STATUS_EXCEPTION:
3310            break;
3311            
3312        default:
3313            throw new InternalError JavaDoc();
3314        }
3315    }
3316    
3317    /**
3318     * Looks up and returns object associated with the given handle.
3319     * Returns null if the given handle is NULL_HANDLE, or if it has an
3320     * associated ClassNotFoundException.
3321     */

3322    Object JavaDoc lookupObject(int handle) {
3323        return (handle != NULL_HANDLE &&
3324            status[handle] != STATUS_EXCEPTION) ?
3325        entries[handle] : null;
3326    }
3327
3328    /**
3329     * Looks up and returns ClassNotFoundException associated with the
3330     * given handle. Returns null if the given handle is NULL_HANDLE, or
3331     * if there is no ClassNotFoundException associated with the handle.
3332     */

3333    ClassNotFoundException JavaDoc lookupException(int handle) {
3334        return (handle != NULL_HANDLE &&
3335            status[handle] == STATUS_EXCEPTION) ?
3336        (ClassNotFoundException JavaDoc) entries[handle] : null;
3337    }
3338    
3339    /**
3340     * Resets table to its initial state.
3341     */

3342    void clear() {
3343        Arrays.fill(status, 0, size, (byte) 0);
3344        Arrays.fill(entries, 0, size, null);
3345        Arrays.fill(deps, 0, size, null);
3346        lowDep = -1;
3347        size = 0;
3348    }
3349    
3350    /**
3351     * Returns number of handles registered in table.
3352     */

3353    int size() {
3354        return size;
3355    }
3356    
3357    /**
3358     * Expands capacity of internal arrays.
3359     */

3360    private void grow() {
3361        int newCapacity = (entries.length << 1) + 1;
3362        
3363        byte[] newStatus = new byte[newCapacity];
3364        Object JavaDoc[] newEntries = new Object JavaDoc[newCapacity];
3365        HandleList[] newDeps = new HandleList[newCapacity];
3366        
3367        System.arraycopy(status, 0, newStatus, 0, size);
3368        System.arraycopy(entries, 0, newEntries, 0, size);
3369        System.arraycopy(deps, 0, newDeps, 0, size);
3370        
3371        status = newStatus;
3372        entries = newEntries;
3373        deps = newDeps;
3374    }
3375
3376    /**
3377     * Simple growable list of (integer) handles.
3378     */

3379    private static class HandleList {
3380        private int[] list = new int[4];
3381        private int size = 0;
3382        
3383        public HandleList() {
3384        }
3385        
3386        public void add(int handle) {
3387        if (size >= list.length) {
3388            int[] newList = new int[list.length << 1];
3389            System.arraycopy(list, 0, newList, 0, list.length);
3390            list = newList;
3391        }
3392        list[size++] = handle;
3393        }
3394        
3395        public int get(int index) {
3396        if (index >= size) {
3397            throw new ArrayIndexOutOfBoundsException JavaDoc();
3398        }
3399        return list[index];
3400        }
3401
3402        public int size() {
3403        return size;
3404        }
3405    }
3406    }
3407
3408    /**
3409     * Context during upcalls to class-defined readObject methods; holds
3410     * object currently being deserialized and descriptor for current class.
3411     * This context keeps a boolean state to indicate that defaultReadObject
3412     * or readFields has already been invoked with this context or the class's
3413     * readObject method has returned; if true, the getObj method throws
3414     * NotActiveException.
3415     */

3416    private static class CallbackContext {
3417    private final Object JavaDoc obj;
3418    private final ObjectStreamClass JavaDoc desc;
3419    private final AtomicBoolean JavaDoc used = new AtomicBoolean JavaDoc();
3420
3421    public CallbackContext(Object JavaDoc obj, ObjectStreamClass JavaDoc desc) {
3422        this.obj = obj;
3423        this.desc = desc;
3424    }
3425
3426    public Object JavaDoc getObj() throws NotActiveException JavaDoc {
3427        checkAndSetUsed();
3428        return obj;
3429    }
3430
3431    public ObjectStreamClass JavaDoc getDesc() {
3432        return desc;
3433    }
3434
3435    private void checkAndSetUsed() throws NotActiveException JavaDoc {
3436        if (!used.compareAndSet(false, true)) {
3437             throw new NotActiveException JavaDoc(
3438              "not in readObject invocation or fields already read");
3439        }
3440    }
3441
3442    public void setUsed() {
3443        used.set(true);
3444    }
3445    }
3446}
3447
Popular Tags