0001: /*
0002: * @(#)ObjectInputStream.java 1.123 06/10/10
0003: *
0004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: *
0026: */
0027:
0028: package java.io;
0029:
0030: import java.lang.reflect.Array;
0031: import java.lang.reflect.Modifier;
0032: import java.lang.reflect.Proxy;
0033: import java.security.AccessController;
0034: import java.security.PrivilegedAction;
0035: import java.util.Arrays;
0036: import java.util.HashMap;
0037: import sun.misc.SoftCache;
0038: import sun.misc.CVM;
0039:
0040: /* Back-ported JDK 1.4 implementation */
0041:
0042: /**
0043: * An ObjectInputStream deserializes primitive data and objects previously
0044: * written using an ObjectOutputStream.
0045: *
0046: * <p>ObjectOutputStream and ObjectInputStream can provide an application
0047: * with persistent storage for graphs of objects when used with a
0048: * FileOutputStream and FileInputStream respectively.
0049: * ObjectInputStream is used to recover those objects previously
0050: * serialized. Other uses include passing objects between hosts using
0051: * a socket stream or for marshaling and unmarshaling arguments and
0052: * parameters in a remote communication system.<p>
0053: *
0054: * ObjectInputStream ensures that the types of all objects in the
0055: * graph created from the stream match the classes present in the
0056: * Java Virtual Machine. Classes are loaded as required using the
0057: * standard mechanisms. <p>
0058: *
0059: * Only objects that support the java.io.Serializable or
0060: * java.io.Externalizable interface can be read from streams.
0061: *
0062: * <p>The method <STRONG>readObject</STRONG> is used to read an object
0063: * from the stream. Java's safe casting should be used to get the
0064: * desired type. In Java, strings and arrays are objects and are
0065: * treated as objects during serialization. When read they need to be
0066: * cast to the expected type.<p>
0067: *
0068: * Primitive data types can be read from the stream using the appropriate
0069: * method on DataInput. <p>
0070: *
0071: * The default deserialization mechanism for objects restores the
0072: * contents of each field to the value and type it had when it was written.
0073: * Fields declared as transient or static are ignored by the
0074: * deserialization process. References to other objects cause those
0075: * objects to be read from the stream as necessary. Graphs of objects
0076: * are restored correctly using a reference sharing mechanism. New
0077: * objects are always allocated when deserializing, which prevents
0078: * existing objects from being overwritten.
0079: *
0080: * <p>Reading an object is analogous to running the constructors of a new
0081: * object. Memory is allocated for the object and initialized to zero (NULL).
0082: * No-arg constructors are invoked for the non-serializable classes and then
0083: * the fields of the serializable classes are restored from the stream starting
0084: * with the serializable class closest to java.lang.object and finishing with
0085: * the object's most specific class.
0086: *
0087: * <p>For example to read from a stream as written by the example in
0088: * ObjectOutputStream:
0089: * <br>
0090: * <pre>
0091: * FileInputStream fis = new FileInputStream("t.tmp");
0092: * ObjectInputStream ois = new ObjectInputStream(fis);
0093: *
0094: * int i = ois.readInt();
0095: * String today = (String) ois.readObject();
0096: * Date date = (Date) ois.readObject();
0097: *
0098: * ois.close();
0099: * </pre>
0100: *
0101: * <p>Classes control how they are serialized by implementing either the
0102: * java.io.Serializable or java.io.Externalizable interfaces.<P>
0103: *
0104: * Implementing the Serializable interface allows object serialization
0105: * to save and restore the entire state of the object and it allows
0106: * classes to evolve between the time the stream is written and the time it is
0107: * read. It automatically traverses references between objects,
0108: * saving and restoring entire graphs.
0109: *
0110: * <p>Serializable classes that require special handling during the
0111: * serialization and deserialization process should implement the following
0112: * methods:<p>
0113: *
0114: * <PRE>
0115: * private void writeObject(java.io.ObjectOutputStream stream)
0116: * throws IOException;
0117: * private void readObject(java.io.ObjectInputStream stream)
0118: * throws IOException, ClassNotFoundException;
0119: * private void readObjectNoData()
0120: * throws ObjectStreamException;
0121: * </PRE><p>
0122: *
0123: * The readObject method is responsible for reading and restoring the
0124: * state of the object for its particular class using data written to
0125: * the stream by the corresponding writeObject method. The method
0126: * does not need to concern itself with the state belonging to its
0127: * superclasses or subclasses. State is restored by reading data from
0128: * the ObjectInputStream for the individual fields and making
0129: * assignments to the appropriate fields of the object. Reading
0130: * primitive data types is supported by DataInput.
0131: *
0132: * <p>Any attempt to read object data which exceeds the boundaries of the
0133: * custom data written by the corresponding writeObject method will cause an
0134: * OptionalDataException to be thrown with an eof field value of true.
0135: * Non-object reads which exceed the end of the allotted data will reflect the
0136: * end of data in the same way that they would indicate the end of the stream:
0137: * bytewise reads will return -1 as the byte read or number of bytes read, and
0138: * primitive reads will throw EOFExceptions. If there is no corresponding
0139: * writeObject method, then the end of default serialized data marks the end of
0140: * the allotted data.
0141: *
0142: * <p>Primitive and object read calls issued from within a readExternal method
0143: * behave in the same manner--if the stream is already positioned at the end of
0144: * data written by the corresponding writeExternal method, object reads will
0145: * throw OptionalDataExceptions with eof set to true, bytewise reads will
0146: * return -1, and primitive reads will throw EOFExceptions. Note that this
0147: * behavior does not hold for streams written with the old
0148: * <code>ObjectStreamConstants.PROTOCOL_VERSION_1</code> protocol, in which the
0149: * end of data written by writeExternal methods is not demarcated, and hence
0150: * cannot be detected.
0151: *
0152: * <p>The readObjectNoData method is responsible for initializing the state of
0153: * the object for its particular class in the event that the serialization
0154: * stream does not list the given class as a superclass of the object being
0155: * deserialized. This may occur in cases where the receiving party uses a
0156: * different version of the deserialized instance's class than the sending
0157: * party, and the receiver's version extends classes that are not extended by
0158: * the sender's version. This may also occur if the serialization stream has
0159: * been tampered; hence, readObjectNoData is useful for initializing
0160: * deserialized objects properly despite a "hostile" or incomplete source
0161: * stream.
0162: *
0163: * <p>Serialization does not read or assign values to the fields of any
0164: * object that does not implement the java.io.Serializable interface.
0165: * Subclasses of Objects that are not serializable can be
0166: * serializable. In this case the non-serializable class must have a
0167: * no-arg constructor to allow its fields to be initialized. In this
0168: * case it is the responsibility of the subclass to save and restore
0169: * the state of the non-serializable class. It is frequently the case that
0170: * the fields of that class are accessible (public, package, or
0171: * protected) or that there are get and set methods that can be used
0172: * to restore the state.
0173: *
0174: * <p>Any exception that occurs while deserializing an object will be
0175: * caught by the ObjectInputStream and abort the reading process.
0176: *
0177: * <p>Implementing the Externalizable interface allows the object to
0178: * assume complete control over the contents and format of the object's
0179: * serialized form. The methods of the Externalizable interface,
0180: * writeExternal and readExternal, are called to save and restore the
0181: * objects state. When implemented by a class they can write and read
0182: * their own state using all of the methods of ObjectOutput and
0183: * ObjectInput. It is the responsibility of the objects to handle any
0184: * versioning that occurs.
0185: *
0186: * @version 1.135, 01/09/15
0187: * @see java.io.DataInput
0188: * @see java.io.ObjectOutputStream
0189: * @see java.io.Serializable
0190: * @see <a href="../../../guide/serialization/spec/input.doc.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
0191: * @since JDK1.1
0192: */
0193: public class ObjectInputStream extends InputStream implements
0194: ObjectInput, ObjectStreamConstants {
0195: /** handle value representing null */
0196: private static final int NULL_HANDLE = -1;
0197:
0198: /** marker for unshared objects in internal handle table */
0199: private static final Object unsharedMarker = new Object();
0200:
0201: /** table mapping primitive type names to corresponding class objects */
0202: private static final HashMap primClasses = new HashMap(8, 1.0F);
0203: static {
0204: primClasses.put("boolean", boolean.class);
0205: primClasses.put("byte", byte.class);
0206: primClasses.put("char", char.class);
0207: primClasses.put("short", short.class);
0208: primClasses.put("int", int.class);
0209: primClasses.put("long", long.class);
0210: primClasses.put("float", float.class);
0211: primClasses.put("double", double.class);
0212: }
0213:
0214: /** cache of subclass security audit results */
0215: // - Back-ported from JDK 1.4
0216: private static final SoftCache subclassAudits = new SoftCache(5);
0217:
0218: /** filter stream for handling block data conversion */
0219: private final BlockDataInputStream bin;
0220: /** validation callback list */
0221: private final ValidationList vlist;
0222: /** recursion depth */
0223: private int depth;
0224: /** whether stream is closed */
0225: private boolean closed;
0226:
0227: /** wire handle -> obj/exception map */
0228: private final HandleTable handles;
0229: /** scratch field for passing handle values up/down call stack */
0230: private int passHandle = NULL_HANDLE;
0231: /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
0232: private boolean defaultDataEnd = false;
0233:
0234: /** buffer for reading primitive field values */
0235: private byte[] primVals;
0236:
0237: /** if true, invoke readObjectOverride() instead of readObject() */
0238: private final boolean enableOverride;
0239: /** if true, invoke resolveObject() */
0240: private boolean enableResolve;
0241:
0242: // values below valid only during upcalls to readObject()/readExternal()
0243: /** object currently being deserialized */
0244: private Object curObj;
0245: /** descriptor for current class (null if in readExternal()) */
0246: private ObjectStreamClass curDesc;
0247: /** current GetField object */
0248: private GetFieldImpl curGet;
0249:
0250: /**
0251: * Creates an ObjectInputStream that reads from the specified InputStream.
0252: * A serialization stream header is read from the stream and verified.
0253: * This constructor will block until the corresponding ObjectOutputStream
0254: * has written and flushed the header.
0255: *
0256: * <p>If a security manager is installed, this constructor will check for
0257: * the "enableSubclassImplementation" SerializablePermission when invoked
0258: * directly or indirectly by the constructor of a subclass which overrides
0259: * the ObjectInputStream.readFields or ObjectInputStream.readUnshared
0260: * methods.
0261: *
0262: * @param in input stream to read from
0263: * @throws StreamCorruptedException if the stream header is incorrect
0264: * @throws IOException if an I/O error occurs while reading stream header
0265: * @throws SecurityException if untrusted subclass illegally overrides
0266: * security-sensitive methods
0267: * @throws NullPointerException if <code>in</code> is <code>null</code>
0268: * @see ObjectInputStream#ObjectInputStream()
0269: * @see ObjectInputStream#readFields()
0270: * @see ObjectOutputStream#ObjectOutputStream(OutputStream).
0271: */
0272: public ObjectInputStream(InputStream in) throws IOException {
0273: verifySubclass();
0274: bin = new BlockDataInputStream(in);
0275: handles = new HandleTable(10);
0276: vlist = new ValidationList();
0277: enableOverride = false;
0278: readStreamHeader();
0279: bin.setBlockDataMode(true);
0280: }
0281:
0282: /**
0283: * Provide a way for subclasses that are completely reimplementing
0284: * ObjectInputStream to not have to allocate private data just used by
0285: * this implementation of ObjectInputStream.
0286: *
0287: * <p>If there is a security manager installed, this method first calls the
0288: * security manager's <code>checkPermission</code> method with the
0289: * <code>SerializablePermission("enableSubclassImplementation")</code>
0290: * permission to ensure it's ok to enable subclassing.
0291: *
0292: * @exception IOException Thrown if not called by a subclass.
0293: * @throws SecurityException
0294: * if a security manager exists and its
0295: * <code>checkPermission</code> method denies
0296: * enabling subclassing.
0297: *
0298: * @see SecurityManager#checkPermission
0299: * @see java.io.SerializablePermission
0300: */
0301: protected ObjectInputStream() throws IOException, SecurityException {
0302: SecurityManager sm = System.getSecurityManager();
0303: if (sm != null) {
0304: sm
0305: .checkPermission(ObjectStreamConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
0306: }
0307: bin = null;
0308: handles = null;
0309: vlist = null;
0310: enableOverride = true;
0311: }
0312:
0313: /**
0314: * Read an object from the ObjectInputStream.
0315: * The class of the object, the signature of the class, and the values
0316: * of the non-transient and non-static fields of the class and all
0317: * of its supertypes are read. Default deserializing for a class can be
0318: * overriden using the writeObject and readObject methods.
0319: * Objects referenced by this object are read transitively so
0320: * that a complete equivalent graph of objects is reconstructed by
0321: * readObject. <p>
0322: *
0323: * The root object is completly restored when all of its fields
0324: * and the objects it references are completely restored. At this
0325: * point the object validation callbacks are executed in order
0326: * based on their registered priorities. The callbacks are
0327: * registered by objects (in the readObject special methods)
0328: * as they are individually restored.
0329: *
0330: * Exceptions are thrown for problems with the InputStream and for classes
0331: * that should not be deserialized. All exceptions are fatal to the
0332: * InputStream and leave it in an indeterminate state; it is up to the
0333: * caller to ignore or recover the stream state.
0334: *
0335: * @exception java.lang.ClassNotFoundException Class of a serialized object
0336: * cannot be found.
0337: * @exception InvalidClassException Something is wrong with a class used by
0338: * serialization.
0339: * @exception StreamCorruptedException Control information in the
0340: * stream is inconsistent.
0341: * @exception OptionalDataException Primitive data was found in the
0342: * stream instead of objects.
0343: * @exception IOException Any of the usual Input/Output related exceptions.
0344: */
0345: public final Object readObject() throws OptionalDataException,
0346: ClassNotFoundException, IOException {
0347: if (enableOverride) {
0348: return readObjectOverride();
0349: }
0350:
0351: // if nested read, passHandle contains handle of enclosing object
0352: int outerHandle = passHandle;
0353: try {
0354: Object obj = readObject0(false);
0355: handles.markDependency(outerHandle, passHandle);
0356: ClassNotFoundException ex = handles
0357: .lookupException(passHandle);
0358: if (ex != null) {
0359: throw ex;
0360: }
0361: if (depth == 0) {
0362: vlist.doCallbacks();
0363: }
0364: return obj;
0365: } finally {
0366: passHandle = outerHandle;
0367: if (closed && depth == 0) {
0368: clear();
0369: }
0370: }
0371: }
0372:
0373: /**
0374: * This method is called by trusted subclasses of ObjectOutputStream
0375: * that constructed ObjectOutputStream using the
0376: * protected no-arg constructor. The subclass is expected to provide
0377: * an override method with the modifier "final".
0378: *
0379: * @return the Object read from the stream.
0380: * @exception java.lang.ClassNotFoundException Class definition of a
0381: * serialized object cannot be found.
0382: * @exception OptionalDataException Primitive data was found in the
0383: * stream instead of objects.
0384: * @exception IOException if I/O errors occurred while reading from the
0385: * underlying stream
0386: *
0387: * @see #ObjectInputStream()
0388: * @see #readObject()
0389: * @since 1.2
0390: */
0391: protected Object readObjectOverride() throws OptionalDataException,
0392: ClassNotFoundException, IOException {
0393: return null;
0394: }
0395:
0396: /**
0397: * Reads an "unshared" object from the ObjectInputStream. This method is
0398: * identical to readObject, except that it prevents subsequent calls to
0399: * readObject and readUnshared from returning additional references to the
0400: * deserialized instance obtained via this call. Specifically:
0401: * <ul>
0402: * <li>If readUnshared is called to deserialize a back-reference (the
0403: * stream representation of an object which has been written
0404: * previously to the stream), an ObjectStreamException will be
0405: * thrown.
0406: *
0407: * <li>If readUnshared returns successfully, then any subsequent attempts
0408: * to deserialize back-references to the stream handle deserialized
0409: * by readUnshared will cause an ObjectStreamException to be thrown.
0410: * </ul>
0411: * Deserializing an object via readUnshared invalidates the stream handle
0412: * associated with the returned object. Note that this in itself does not
0413: * always guarantee that the reference returned by readUnshared is unique;
0414: * the deserialized object may define a readResolve method which returns an
0415: * object visible to other parties, or readUnshared may return a Class
0416: * object obtainable elsewhere in the stream or through external means.
0417: *
0418: * <p>However, for objects which are not instances of java.lang.Class and
0419: * do not define readResolve methods, readUnshared guarantees that the
0420: * returned object reference is unique and cannot be obtained a second time
0421: * from the ObjectInputStream that created it, even if the underlying data
0422: * stream has been manipulated. This guarantee applies only to the
0423: * base-level object returned by readUnshared, and not to any transitively
0424: * referenced sub-objects in the returned object graph.
0425: *
0426: * <p>ObjectInputStream subclasses which override this method can only be
0427: * constructed in security contexts possessing the
0428: * "enableSubclassImplementation" SerializablePermission; any attempt to
0429: * instantiate such a subclass without this permission will cause a
0430: * SecurityException to be thrown.
0431: *
0432: * @return reference to deserialized object
0433: * @throws ClassNotFoundException if class of an object to deserialize
0434: * cannot be found
0435: * @throws StreamCorruptedException if control information in the stream
0436: * is inconsistent
0437: * @throws ObjectStreamException if object to deserialize has already
0438: * appeared in stream
0439: * @throws OptionalDataException if primitive data is next in stream
0440: * @throws IOException if an I/O error occurs during deserialization
0441: *
0442: */
0443: public Object readUnshared() throws IOException,
0444: ClassNotFoundException {
0445: // if nested read, passHandle contains handle of enclosing object
0446: int outerHandle = passHandle;
0447: try {
0448: Object obj = readObject0(true);
0449: handles.markDependency(outerHandle, passHandle);
0450: ClassNotFoundException ex = handles
0451: .lookupException(passHandle);
0452: if (ex != null) {
0453: throw ex;
0454: }
0455: if (depth == 0) {
0456: vlist.doCallbacks();
0457: }
0458: return obj;
0459: } finally {
0460: passHandle = outerHandle;
0461: if (closed && depth == 0) {
0462: clear();
0463: }
0464: }
0465: }
0466:
0467: /**
0468: * Read the non-static and non-transient fields of the current class from
0469: * this stream. This may only be called from the readObject method of the
0470: * class being deserialized. It will throw the NotActiveException if it is
0471: * called otherwise.
0472: *
0473: * @throws ClassNotFoundException if the class of a serialized object
0474: * could not be found.
0475: * @throws IOException if an I/O error occurs.
0476: * @throws NotActiveException if the stream is not currently reading
0477: * objects.
0478: */
0479: public void defaultReadObject() throws IOException,
0480: ClassNotFoundException {
0481: if (curObj == null || curDesc == null) {
0482: throw new NotActiveException("not in call to readObject");
0483: }
0484: bin.setBlockDataMode(false);
0485: defaultReadFields(curObj, curDesc);
0486: bin.setBlockDataMode(true);
0487: if (!curDesc.hasWriteObjectData()) {
0488: /*
0489: * Fix for 4360508: since stream does not contain terminating
0490: * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
0491: * knows to simulate end-of-custom-data behavior.
0492: */
0493: defaultDataEnd = true;
0494: }
0495: ClassNotFoundException ex = handles.lookupException(passHandle);
0496: if (ex != null) {
0497: throw ex;
0498: }
0499: }
0500:
0501: /**
0502: * Reads the persistent fields from the stream and makes them
0503: * available by name.
0504: *
0505: * @return the <code>GetField</code> object representing the persistent
0506: * fields of the object being deserialized
0507: * @exception java.lang.ClassNotFoundException if the class of a serialized
0508: * object could not be found.
0509: * @exception IOException if an I/O error occurs.
0510: * @exception NotActiveException if the stream is not currently reading
0511: * objects.
0512: * @since 1.2
0513: */
0514: public ObjectInputStream.GetField readFields() throws IOException,
0515: ClassNotFoundException, NotActiveException {
0516: if (curGet == null) {
0517: if (curObj == null || curDesc == null) {
0518: throw new NotActiveException(
0519: "not in call to readObject");
0520: }
0521: curGet = new GetFieldImpl(curDesc);
0522: }
0523: bin.setBlockDataMode(false);
0524: curGet.readFields();
0525: bin.setBlockDataMode(true);
0526: if (!curDesc.hasWriteObjectData()) {
0527: /*
0528: * Fix for 4360508: since stream does not contain terminating
0529: * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
0530: * knows to simulate end-of-custom-data behavior.
0531: */
0532: defaultDataEnd = true;
0533: }
0534:
0535: return curGet;
0536: }
0537:
0538: /**
0539: * Register an object to be validated before the graph is returned. While
0540: * similar to resolveObject these validations are called after the entire
0541: * graph has been reconstituted. Typically, a readObject method will
0542: * register the object with the stream so that when all of the objects are
0543: * restored a final set of validations can be performed.
0544: *
0545: * @param obj the object to receive the validation callback.
0546: * @param prio controls the order of callbacks;zero is a good default.
0547: * Use higher numbers to be called back earlier, lower numbers for
0548: * later callbacks. Within a priority, callbacks are processed in
0549: * no particular order.
0550: * @throws NotActiveException The stream is not currently reading objects
0551: * so it is invalid to register a callback.
0552: * @throws InvalidObjectException The validation object is null.
0553: */
0554: public void registerValidation(ObjectInputValidation obj, int prio)
0555: throws NotActiveException, InvalidObjectException {
0556: if (depth == 0) {
0557: throw new NotActiveException("stream inactive");
0558: }
0559: vlist.register(obj, prio);
0560: }
0561:
0562: /**
0563: * Load the local class equivalent of the specified stream class
0564: * description. Subclasses may implement this method to allow classes to
0565: * be fetched from an alternate source.
0566: *
0567: * <p>The corresponding method in <code>ObjectOutputStream</code> is
0568: * <code>annotateClass</code>. This method will be invoked only once for
0569: * each unique class in the stream. This method can be implemented by
0570: * subclasses to use an alternate loading mechanism but must return a
0571: * <code>Class</code> object. Once returned, the serialVersionUID of the
0572: * class is compared to the serialVersionUID of the serialized class. If
0573: * there is a mismatch, the deserialization fails and an exception is
0574: * raised.
0575: *
0576: * <p>By default the class name is resolved relative to the class that
0577: * called <code>readObject</code>.
0578: *
0579: * @param desc an instance of class <code>ObjectStreamClass</code>
0580: * @return a <code>Class</code> object corresponding to <code>desc</code>
0581: * @throws IOException any of the usual input/output exceptions
0582: * @throws ClassNotFoundException if class of a serialized object cannot
0583: * be found
0584: */
0585: protected Class resolveClass(ObjectStreamClass desc)
0586: throws IOException, ClassNotFoundException {
0587: String name = desc.getName();
0588: try {
0589: return Class
0590: .forName(name, false, latestUserDefinedLoader());
0591: } catch (ClassNotFoundException ex) {
0592: Class cl = (Class) primClasses.get(name);
0593: if (cl != null) {
0594: return cl;
0595: } else {
0596: throw ex;
0597: }
0598: }
0599: }
0600:
0601: /**
0602: * Returns a proxy class that implements the interfaces named in a
0603: * proxy class descriptor; subclasses may implement this method to
0604: * read custom data from the stream along with the descriptors for
0605: * dynamic proxy classes, allowing them to use an alternate loading
0606: * mechanism for the interfaces and the proxy class.
0607: *
0608: * <p>This method is called exactly once for each unique proxy class
0609: * descriptor in the stream.
0610: *
0611: * <p>The corresponding method in <code>ObjectOutputStream</code> is
0612: * <code>annotateProxyClass</code>. For a given subclass of
0613: * <code>ObjectInputStream</code> that overrides this method, the
0614: * <code>annotateProxyClass</code> method in the corresponding
0615: * subclass of <code>ObjectOutputStream</code> must write any data or
0616: * objects read by this method.
0617: *
0618: * <p>The default implementation of this method in
0619: * <code>ObjectInputStream</code> returns the result of calling
0620: * <code>Proxy.getProxyClass</code> with the list of
0621: * <code>Class</code> objects for the interfaces that are named in
0622: * the <code>interfaces</code> parameter. The <code>Class</code>
0623: * object for each interface name <code>i</code> is the value
0624: * returned by calling
0625: * <pre>
0626: * Class.forName(i, false, loader)
0627: * </pre>
0628: * where <code>loader</code> is that of the first non-null class
0629: * loader up the execution stack, or <code>null</code> if no non-null
0630: * class loaders are on the stack (the same class loader choice used
0631: * by the <code>resolveClass</code> method). This same value of
0632: * <code>loader</code> is also the class loader passed to
0633: * <code>Proxy.getProxyClass</code>. If <code>Proxy.getProxyClass</code>
0634: * throws an <code>IllegalArgumentException</code>,
0635: * <code>resolveProxyClass</code> will throw a
0636: * <code>ClassNotFoundException</code> containing the
0637: * <code>IllegalArgumentException</code>.
0638: *
0639: * @param interfaces the list of interface names that were
0640: * deserialized in the proxy class descriptor
0641: * @return a proxy class for the specified interfaces
0642: * @throws IOException any exception thrown by the underlying
0643: * <code>InputStream</code>
0644: * @throws ClassNotFoundException if the proxy class or any of the
0645: * named interfaces could not be found
0646: * @see ObjectOutputStream#annotateProxyClass(Class)
0647: * @since 1.3
0648: */
0649: protected Class resolveProxyClass(String[] interfaces)
0650: throws IOException, ClassNotFoundException {
0651: ClassLoader latestLoader = latestUserDefinedLoader();
0652: ClassLoader nonPublicLoader = null;
0653: boolean hasNonPublicInterface = false;
0654:
0655: // define proxy in class loader of non-public interface(s), if any
0656: Class[] classObjs = new Class[interfaces.length];
0657: for (int i = 0; i < interfaces.length; i++) {
0658: Class cl = Class
0659: .forName(interfaces[i], false, latestLoader);
0660: if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
0661: if (hasNonPublicInterface) {
0662: if (nonPublicLoader != cl.getClassLoader()) {
0663: throw new IllegalAccessError(
0664: "conflicting non-public interface class loaders");
0665: }
0666: } else {
0667: nonPublicLoader = cl.getClassLoader();
0668: hasNonPublicInterface = true;
0669: }
0670: }
0671: classObjs[i] = cl;
0672: }
0673: try {
0674: return Proxy.getProxyClass(
0675: hasNonPublicInterface ? nonPublicLoader
0676: : latestLoader, classObjs);
0677: } catch (IllegalArgumentException e) {
0678: throw new ClassNotFoundException(null, e);
0679: }
0680: }
0681:
0682: /**
0683: * This method will allow trusted subclasses of ObjectInputStream to
0684: * substitute one object for another during deserialization. Replacing
0685: * objects is disabled until enableResolveObject is called. The
0686: * enableResolveObject method checks that the stream requesting to resolve
0687: * object can be trusted. Every reference to serializable objects is passed
0688: * to resolveObject. To insure that the private state of objects is not
0689: * unintentionally exposed only trusted streams may use resolveObject.
0690: *
0691: * <p>This method is called after an object has been read but before it is
0692: * returned from readObject. The default resolveObject method just returns
0693: * the same object.
0694: *
0695: * <p>When a subclass is replacing objects it must insure that the
0696: * substituted object is compatible with every field where the reference
0697: * will be stored. Objects whose type is not a subclass of the type of the
0698: * field or array element abort the serialization by raising an exception
0699: * and the object is not be stored.
0700: *
0701: * <p>This method is called only once when each object is first
0702: * encountered. All subsequent references to the object will be redirected
0703: * to the new object.
0704: *
0705: * @param obj object to be substituted
0706: * @return the substituted object
0707: * @throws IOException Any of the usual Input/Output exceptions.
0708: */
0709: protected Object resolveObject(Object obj) throws IOException {
0710: return obj;
0711: }
0712:
0713: /**
0714: * Enable the stream to allow objects read from the stream to be replaced.
0715: *
0716: * When enabled, the resolveObject method is called for every object
0717: * being deserialized.
0718: *
0719: * If <i>enable</i> is true, and there is a security manager installed,
0720: * this method first calls the
0721: * security manager's <code>checkPermission</code> method with the
0722: * <code>SerializablePermission("enableSubstitution")</code>
0723: * permission to ensure it's ok to
0724: * enable the stream to allow objects read from the stream to be replaced.
0725: *
0726: * @param enable true for enabling use of <code>resolveObject</code> for
0727: * every object being deserialized
0728: * @return the previous setting before this method was invoked
0729: * @throws SecurityException
0730: * if a security manager exists and its
0731: * <code>checkPermission</code> method denies
0732: * enabling the stream to allow objects read from the stream to be
0733: * replaced.
0734: *
0735: * @see SecurityManager#checkPermission
0736: * @see java.io.SerializablePermission
0737: */
0738: protected boolean enableResolveObject(boolean enable)
0739: throws SecurityException {
0740: if (enable == enableResolve) {
0741: return enable;
0742: }
0743: if (enable) {
0744: SecurityManager sm = System.getSecurityManager();
0745: if (sm != null) {
0746: sm
0747: .checkPermission(ObjectStreamConstants.SUBSTITUTION_PERMISSION);
0748: }
0749: }
0750: enableResolve = enable;
0751: return !enableResolve;
0752: }
0753:
0754: /**
0755: * The readStreamHeader method is provided to allow subclasses to
0756: * read and verify their own stream headers. It reads and
0757: * verifies the magic number and version number.
0758: *
0759: * @throws IOException if there are I/O errors while reading from the
0760: * underlying <code>InputStream</code>
0761: * @throws StreamCorruptedException if control information in the
0762: * stream is inconsistent
0763: */
0764: protected void readStreamHeader() throws IOException,
0765: StreamCorruptedException {
0766: if (bin.readShort() != STREAM_MAGIC
0767: || bin.readShort() != STREAM_VERSION) {
0768: throw new StreamCorruptedException("invalid stream header");
0769: }
0770: }
0771:
0772: /**
0773: * Read a class descriptor from the serialization stream. This method is
0774: * called when the ObjectInputStream expects a class descriptor as the next
0775: * item in the serialization stream. Subclasses of ObjectInputStream may
0776: * override this method to read in class descriptors that have been written
0777: * in non-standard formats (by subclasses of ObjectOutputStream which have
0778: * overridden the <code>writeClassDescriptor</code> method). By default,
0779: * this method reads class descriptors according to the format defined in
0780: * the Object Serialization specification.
0781: * <p>
0782: *
0783: * @return the class descriptor read
0784: * @exception IOException If an I/O error has occurred.
0785: * @exception ClassNotFoundException If the Class of a serialized object
0786: * used in the class descriptor representation cannot be found
0787: * @see
0788: * java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass)
0789: * @since 1.3
0790: */
0791: protected ObjectStreamClass readClassDescriptor()
0792: throws IOException, ClassNotFoundException {
0793: ObjectStreamClass desc = new ObjectStreamClass();
0794: desc.readNonProxy(this );
0795: return desc;
0796: }
0797:
0798: /**
0799: * Reads a byte of data. This method will block if no input is
0800: * available.
0801: *
0802: * @return the byte read, or -1 if the end of the
0803: * stream is reached.
0804: * @exception IOException If an I/O error has occurred.
0805: */
0806: public int read() throws IOException {
0807: return bin.read();
0808: }
0809:
0810: /**
0811: * Reads into an array of bytes. This method will
0812: * block until some input is available. Consider
0813: * using java.io.DataInputStream.readFully to read exactly
0814: * 'length' bytes.
0815: *
0816: * @param b the buffer into which the data is read
0817: * @param off the start offset of the data
0818: * @param len the maximum number of bytes read
0819: * @return the actual number of bytes read, -1 is
0820: * returned when the end of the stream is reached.
0821: * @exception IOException If an I/O error has occurred.
0822: * @see java.io.DataInputStream#readFully(byte[],int,int)
0823: */
0824: public int read(byte[] buf, int off, int len) throws IOException {
0825: int endoff = off + len;
0826: if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
0827: throw new IndexOutOfBoundsException();
0828: }
0829: return bin.read(buf, off, len, false);
0830: }
0831:
0832: /**
0833: * Returns the number of bytes that can be read without blocking.
0834: *
0835: * @return the number of available bytes.
0836: * @throws IOException if there are I/O errors while reading from the
0837: * underlying <code>InputStream</code>
0838: */
0839: public int available() throws IOException {
0840: return bin.available();
0841: }
0842:
0843: /**
0844: * Closes the input stream. Must be called to release any resources
0845: * associated with the stream.
0846: *
0847: * @throws IOException If an I/O error has occurred.
0848: */
0849: public void close() throws IOException {
0850: /*
0851: * Even if stream already closed, propagate redundant close to
0852: * underlying stream to stay consistent with previous implementations.
0853: */
0854: closed = true;
0855: if (depth == 0) {
0856: clear();
0857: }
0858: bin.close();
0859: }
0860:
0861: /**
0862: * Reads in a boolean.
0863: *
0864: * @return the boolean read.
0865: * @throws EOFException If end of file is reached.
0866: * @throws IOException If other I/O error has occurred.
0867: */
0868: public boolean readBoolean() throws IOException {
0869: return bin.readBoolean();
0870: }
0871:
0872: /**
0873: * Reads an 8 bit byte.
0874: *
0875: * @return the 8 bit byte read.
0876: * @throws EOFException If end of file is reached.
0877: * @throws IOException If other I/O error has occurred.
0878: */
0879: public byte readByte() throws IOException {
0880: return bin.readByte();
0881: }
0882:
0883: /**
0884: * Reads an unsigned 8 bit byte.
0885: *
0886: * @return the 8 bit byte read.
0887: * @throws EOFException If end of file is reached.
0888: * @throws IOException If other I/O error has occurred.
0889: */
0890: public int readUnsignedByte() throws IOException {
0891: return bin.readUnsignedByte();
0892: }
0893:
0894: /**
0895: * Reads a 16 bit char.
0896: *
0897: * @return the 16 bit char read.
0898: * @throws EOFException If end of file is reached.
0899: * @throws IOException If other I/O error has occurred.
0900: */
0901: public char readChar() throws IOException {
0902: return bin.readChar();
0903: }
0904:
0905: /**
0906: * Reads a 16 bit short.
0907: *
0908: * @return the 16 bit short read.
0909: * @throws EOFException If end of file is reached.
0910: * @throws IOException If other I/O error has occurred.
0911: */
0912: public short readShort() throws IOException {
0913: return bin.readShort();
0914: }
0915:
0916: /**
0917: * Reads an unsigned 16 bit short.
0918: *
0919: * @return the 16 bit short read.
0920: * @throws EOFException If end of file is reached.
0921: * @throws IOException If other I/O error has occurred.
0922: */
0923: public int readUnsignedShort() throws IOException {
0924: return bin.readUnsignedShort();
0925: }
0926:
0927: /**
0928: * Reads a 32 bit int.
0929: *
0930: * @return the 32 bit integer read.
0931: * @throws EOFException If end of file is reached.
0932: * @throws IOException If other I/O error has occurred.
0933: */
0934: public int readInt() throws IOException {
0935: return bin.readInt();
0936: }
0937:
0938: /**
0939: * Reads a 64 bit long.
0940: *
0941: * @return the read 64 bit long.
0942: * @throws EOFException If end of file is reached.
0943: * @throws IOException If other I/O error has occurred.
0944: */
0945: public long readLong() throws IOException {
0946: return bin.readLong();
0947: }
0948:
0949: /**
0950: * Reads a 32 bit float.
0951: *
0952: * @return the 32 bit float read.
0953: * @throws EOFException If end of file is reached.
0954: * @throws IOException If other I/O error has occurred.
0955: */
0956: public float readFloat() throws IOException {
0957: return bin.readFloat();
0958: }
0959:
0960: /**
0961: * Reads a 64 bit double.
0962: *
0963: * @return the 64 bit double read.
0964: * @throws EOFException If end of file is reached.
0965: * @throws IOException If other I/O error has occurred.
0966: */
0967: public double readDouble() throws IOException {
0968: return bin.readDouble();
0969: }
0970:
0971: /**
0972: * Reads bytes, blocking until all bytes are read.
0973: *
0974: * @param buf the buffer into which the data is read
0975: * @throws EOFException If end of file is reached.
0976: * @throws IOException If other I/O error has occurred.
0977: */
0978: public void readFully(byte[] buf) throws IOException {
0979: bin.readFully(buf, 0, buf.length, false);
0980: }
0981:
0982: /**
0983: * Reads bytes, blocking until all bytes are read.
0984: *
0985: * @param buf the buffer into which the data is read
0986: * @param off the start offset of the data
0987: * @param len the maximum number of bytes to read
0988: * @throws EOFException If end of file is reached.
0989: * @throws IOException If other I/O error has occurred.
0990: */
0991: public void readFully(byte[] buf, int off, int len)
0992: throws IOException {
0993: int endoff = off + len;
0994: if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
0995: throw new IndexOutOfBoundsException();
0996: }
0997: bin.readFully(buf, off, len, false);
0998: }
0999:
1000: /**
1001: * Skips bytes, block until all bytes are skipped.
1002: *
1003: * @param len the number of bytes to be skipped
1004: * @return the actual number of bytes skipped.
1005: * @throws EOFException If end of file is reached.
1006: * @throws IOException If other I/O error has occurred.
1007: */
1008: public int skipBytes(int len) throws IOException {
1009: return bin.skipBytes(len);
1010: }
1011:
1012: /**
1013: * Reads in a line that has been terminated by a \n, \r, \r\n or EOF.
1014: *
1015: * @return a String copy of the line.
1016: * @throws IOException if there are I/O errors while reading from the
1017: * underlying <code>InputStream</code>
1018: * @deprecated This method does not properly convert bytes to characters.
1019: * see DataInputStream for the details and alternatives.
1020: */
1021: public String readLine() throws IOException {
1022: return bin.readLine();
1023: }
1024:
1025: /**
1026: * Reads a UTF format String.
1027: *
1028: * @return the String.
1029: * @throws IOException if there are I/O errors while reading from the
1030: * underlying <code>InputStream</code>
1031: * @throws UTFDataFormatException if read bytes do not represent a valid
1032: * UTF-8 encoding of a string
1033: */
1034: public String readUTF() throws IOException {
1035: return bin.readUTF();
1036: }
1037:
1038: /*
1039: * Sets the values of the primitive fields of object obj. fieldIDs is an
1040: * array of field IDs (the primFieldsID field of the appropriate
1041: * ObjectStreamClass) identifying which fields to set. typecodes is an
1042: * array of characters designating the primitive type of each field (e.g.,
1043: * 'C' for char, 'Z' for boolean, etc.) data is the byte buffer from which
1044: * the primitive field values are read, in the order of their field IDs.
1045: *
1046: * For efficiency, this method does not check all of its arguments for
1047: * safety. Specifically, it assumes that obj's type is compatible with the
1048: * given field IDs, and that the data array is long enough to contain all of
1049: * the byte values that will be read out of it.
1050: */
1051: static native void setPrimitiveFieldValues(Object obj,
1052: long[] fieldIDs, char[] typecodes, byte[] data);
1053:
1054: /*
1055: * Sets the value of an object field of object obj. fieldID is the field ID
1056: * identifying which field to set (obtained from the objFieldsID array field
1057: * of the appropriate ObjectStreamClass). type is the field type; it is
1058: * provided so that the native method can ensure that the passed value val
1059: * is assignable to the field.
1060: *
1061: * For efficiency, this method does not check all of its arguments for
1062: * safety. Specifically, it assumes that obj's type is compatible with the
1063: * given field IDs, and that type is indeed the class type of the field
1064: * designated by fieldID.
1065: */
1066: static native void setObjectFieldValue(Object obj, long fieldID,
1067: Class type, Object val);
1068:
1069: /* Allocate a new object for the specified class
1070: * Native since newInstance may not be able to find a zero arg constructor.
1071: */
1072: static native Object allocateNewObject(Class aclass, Class initclass)
1073: throws InstantiationException, IllegalAccessException;
1074:
1075: /*************************************************************/
1076:
1077: /**
1078: * Provide access to the persistent fields read from the input stream.
1079: */
1080: public static abstract class GetField {
1081:
1082: /**
1083: * Get the ObjectStreamClass that describes the fields in the stream.
1084: *
1085: * @return the descriptor class that describes the serializable fields
1086: */
1087: public abstract ObjectStreamClass getObjectStreamClass();
1088:
1089: /**
1090: * Return true if the named field is defaulted and has no value in this
1091: * stream.
1092: *
1093: * @param name the name of the field
1094: * @return true, if and only if the named field is defaulted
1095: * @throws IOException if there are I/O errors while reading from
1096: * the underlying <code>InputStream</code>
1097: * @throws IllegalArgumentException if <code>name</code> does not
1098: * correspond to a serializable field
1099: */
1100: public abstract boolean defaulted(String name)
1101: throws IOException, IllegalArgumentException;
1102:
1103: /**
1104: * Get the value of the named boolean 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>boolean</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 boolean get(String name, boolean val)
1116: throws IOException, IllegalArgumentException;
1117:
1118: /**
1119: * Get the value of the named byte field from the persistent field.
1120: *
1121: * @param name the name of the field
1122: * @param val the default value to use if <code>name</code> does not
1123: * have a value
1124: * @return the value of the named <code>byte</code> field
1125: * @throws IOException if there are I/O errors while reading from the
1126: * underlying <code>InputStream</code>
1127: * @throws IllegalArgumentException if type of <code>name</code> is
1128: * not serializable or if the field type is incorrect
1129: */
1130: public abstract byte get(String name, byte val)
1131: throws IOException, IllegalArgumentException;
1132:
1133: /**
1134: * Get the value of the named char field from the persistent field.
1135: *
1136: * @param name the name of the field
1137: * @param val the default value to use if <code>name</code> does not
1138: * have a value
1139: * @return the value of the named <code>char</code> field
1140: * @throws IOException if there are I/O errors while reading from the
1141: * underlying <code>InputStream</code>
1142: * @throws IllegalArgumentException if type of <code>name</code> is
1143: * not serializable or if the field type is incorrect
1144: */
1145: public abstract char get(String name, char val)
1146: throws IOException, IllegalArgumentException;
1147:
1148: /**
1149: * Get the value of the named short field from the persistent field.
1150: *
1151: * @param name the name of the field
1152: * @param val the default value to use if <code>name</code> does not
1153: * have a value
1154: * @return the value of the named <code>short</code> field
1155: * @throws IOException if there are I/O errors while reading from the
1156: * underlying <code>InputStream</code>
1157: * @throws IllegalArgumentException if type of <code>name</code> is
1158: * not serializable or if the field type is incorrect
1159: */
1160: public abstract short get(String name, short val)
1161: throws IOException, IllegalArgumentException;
1162:
1163: /**
1164: * Get the value of the named int field from the persistent field.
1165: *
1166: * @param name the name of the field
1167: * @param val the default value to use if <code>name</code> does not
1168: * have a value
1169: * @return the value of the named <code>int</code> field
1170: * @throws IOException if there are I/O errors while reading from the
1171: * underlying <code>InputStream</code>
1172: * @throws IllegalArgumentException if type of <code>name</code> is
1173: * not serializable or if the field type is incorrect
1174: */
1175: public abstract int get(String name, int val)
1176: throws IOException, IllegalArgumentException;
1177:
1178: /**
1179: * Get the value of the named long field from the persistent field.
1180: *
1181: * @param name the name of the field
1182: * @param val the default value to use if <code>name</code> does not
1183: * have a value
1184: * @return the value of the named <code>long</code> field
1185: * @throws IOException if there are I/O errors while reading from the
1186: * underlying <code>InputStream</code>
1187: * @throws IllegalArgumentException if type of <code>name</code> is
1188: * not serializable or if the field type is incorrect
1189: */
1190: public abstract long get(String name, long val)
1191: throws IOException, IllegalArgumentException;
1192:
1193: /**
1194: * Get the value of the named float field from the persistent field.
1195: *
1196: * @param name the name of the field
1197: * @param val the default value to use if <code>name</code> does not
1198: * have a value
1199: * @return the value of the named <code>float</code> field
1200: * @throws IOException if there are I/O errors while reading from the
1201: * underlying <code>InputStream</code>
1202: * @throws IllegalArgumentException if type of <code>name</code> is
1203: * not serializable or if the field type is incorrect
1204: */
1205: public abstract float get(String name, float val)
1206: throws IOException, IllegalArgumentException;
1207:
1208: /**
1209: * Get the value of the named double field from the persistent field.
1210: *
1211: * @param name the name of the field
1212: * @param val the default value to use if <code>name</code> does not
1213: * have a value
1214: * @return the value of the named <code>double</code> field
1215: * @throws IOException if there are I/O errors while reading from the
1216: * underlying <code>InputStream</code>
1217: * @throws IllegalArgumentException if type of <code>name</code> is
1218: * not serializable or if the field type is incorrect
1219: */
1220: public abstract double get(String name, double val)
1221: throws IOException, IllegalArgumentException;
1222:
1223: /**
1224: * Get the value of the named Object field from the persistent field.
1225: *
1226: * @param name the name of the field
1227: * @param val the default value to use if <code>name</code> does not
1228: * have a value
1229: * @return the value of the named <code>Object</code> field
1230: * @throws IOException if there are I/O errors while reading from the
1231: * underlying <code>InputStream</code>
1232: * @throws IllegalArgumentException if type of <code>name</code> is
1233: * not serializable or if the field type is incorrect
1234: */
1235: public abstract Object get(String name, Object val)
1236: throws IOException, IllegalArgumentException;
1237: }
1238:
1239: /**
1240: * Verifies that this (possibly subclass) instance can be constructed
1241: * without violating security constraints: the subclass must not override
1242: * security-sensitive non-final methods, or else the
1243: * "enableSubclassImplementation" SerializablePermission is checked.
1244: */
1245: private void verifySubclass() {
1246: Class cl = getClass();
1247: synchronized (subclassAudits) {
1248: Boolean result = (Boolean) subclassAudits.get(cl);
1249: if (result == null) {
1250: //
1251: // Note: only new Boolean instances (i.e., not Boolean.TRUE or
1252: // Boolean.FALSE) must be used as cache values, otherwise cache
1253: // entry will pin associated class.
1254: //
1255: result = new Boolean(auditSubclass(cl));
1256: subclassAudits.put(cl, result);
1257: }
1258: if (result.booleanValue()) {
1259: return;
1260: }
1261: }
1262: SecurityManager sm = System.getSecurityManager();
1263: if (sm != null) {
1264: sm
1265: .checkPermission(ObjectStreamConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
1266: }
1267: }
1268:
1269: /**
1270: * Performs reflective checks on given subclass to verify that it doesn't
1271: * override security-sensitive non-final methods. Returns true if subclass
1272: * is "safe", false otherwise.
1273: */
1274: private static boolean auditSubclass(final Class subcl) {
1275: Boolean result = (Boolean) AccessController
1276: .doPrivileged(new PrivilegedAction() {
1277: public Object run() {
1278: for (Class cl = subcl; cl != ObjectInputStream.class; cl = cl
1279: .getSuperclass()) {
1280: try {
1281: cl.getDeclaredMethod("readUnshared",
1282: new Class[0]);
1283: return Boolean.FALSE;
1284: } catch (NoSuchMethodException ex) {
1285: }
1286: try {
1287: cl.getDeclaredMethod("readFields",
1288: new Class[0]);
1289: return Boolean.FALSE;
1290: } catch (NoSuchMethodException ex) {
1291: }
1292: }
1293: return Boolean.TRUE;
1294: }
1295: });
1296: return result.booleanValue();
1297: }
1298:
1299: /**
1300: * Clears internal data structures.
1301: */
1302: private void clear() {
1303: handles.clear();
1304: vlist.clear();
1305: }
1306:
1307: /**
1308: * Underlying readObject implementation.
1309: */
1310: private Object readObject0(boolean unshared) throws IOException {
1311: boolean oldMode = bin.getBlockDataMode();
1312: if (oldMode) {
1313: int remain = bin.currentBlockRemaining();
1314: if (remain > 0) {
1315: throw new OptionalDataException(remain);
1316: } else if (defaultDataEnd) {
1317: /*
1318: * Fix for 4360508: stream is currently at the end of a field
1319: * value block written via default serialization; since there
1320: * is no terminating TC_ENDBLOCKDATA tag, simulate
1321: * end-of-custom-data behavior explicitly.
1322: */
1323: throw new OptionalDataException(true);
1324: }
1325: bin.setBlockDataMode(false);
1326: }
1327:
1328: byte tc;
1329: while ((tc = bin.peekByte()) == TC_RESET) {
1330: bin.readByte();
1331: handleReset();
1332: }
1333:
1334: depth++;
1335: try {
1336: switch (tc) {
1337: case TC_NULL:
1338: return readNull();
1339:
1340: case TC_REFERENCE:
1341: return readHandle(unshared);
1342:
1343: case TC_CLASS:
1344: return readClass(unshared);
1345:
1346: case TC_CLASSDESC:
1347: case TC_PROXYCLASSDESC:
1348: return readClassDesc(unshared);
1349:
1350: case TC_STRING:
1351: case TC_LONGSTRING:
1352: return checkResolve(readString(unshared));
1353:
1354: case TC_ARRAY:
1355: return checkResolve(readArray(unshared));
1356:
1357: case TC_OBJECT:
1358: return checkResolve(readOrdinaryObject(unshared));
1359:
1360: case TC_EXCEPTION:
1361: IOException ex = readFatalException();
1362: throw new WriteAbortedException("writing aborted", ex);
1363:
1364: case TC_BLOCKDATA:
1365: case TC_BLOCKDATALONG:
1366: if (oldMode) {
1367: bin.setBlockDataMode(true);
1368: bin.peek(); // force header read
1369: throw new OptionalDataException(bin
1370: .currentBlockRemaining());
1371: } else {
1372: throw new StreamCorruptedException(
1373: "unexpected block data");
1374: }
1375:
1376: case TC_ENDBLOCKDATA:
1377: if (oldMode) {
1378: throw new OptionalDataException(true);
1379: } else {
1380: throw new StreamCorruptedException(
1381: "unexpected end of block data");
1382: }
1383:
1384: default:
1385: throw new StreamCorruptedException();
1386: }
1387: } finally {
1388: depth--;
1389: bin.setBlockDataMode(oldMode);
1390: }
1391: }
1392:
1393: /**
1394: * If resolveObject has been enabled and given object does not have an
1395: * exception associated with it, calls resolveObject to determine
1396: * replacement for object, and updates handle table accordingly. Returns
1397: * replacement object, or echoes provided object if no replacement
1398: * occurred. Expects that passHandle is set to given object's handle prior
1399: * to calling this method.
1400: */
1401: private Object checkResolve(Object obj) throws IOException {
1402: if (!enableResolve
1403: || handles.lookupException(passHandle) != null) {
1404: return obj;
1405: }
1406: Object rep = resolveObject(obj);
1407: if (rep != obj) {
1408: handles.setObject(passHandle, rep);
1409: }
1410: return rep;
1411: }
1412:
1413: /**
1414: * Reads string without allowing it to be replaced in stream. Called from
1415: * within ObjectStreamClass.read().
1416: */
1417: String readTypeString() throws IOException {
1418: int oldHandle = passHandle;
1419: try {
1420: switch (bin.peekByte()) {
1421: case TC_NULL:
1422: return (String) readNull();
1423:
1424: case TC_REFERENCE:
1425: return (String) readHandle(false);
1426:
1427: case TC_STRING:
1428: case TC_LONGSTRING:
1429: return readString(false);
1430:
1431: default:
1432: throw new StreamCorruptedException();
1433: }
1434: } finally {
1435: passHandle = oldHandle;
1436: }
1437: }
1438:
1439: /**
1440: * Reads in null code, sets passHandle to NULL_HANDLE and returns null.
1441: */
1442: private Object readNull() throws IOException {
1443: if (bin.readByte() != TC_NULL) {
1444: throw new StreamCorruptedException();
1445: }
1446: passHandle = NULL_HANDLE;
1447: return null;
1448: }
1449:
1450: /**
1451: * Reads in object handle, sets passHandle to the read handle, and returns
1452: * object associated with the handle.
1453: */
1454: private Object readHandle(boolean unshared) throws IOException {
1455: if (bin.readByte() != TC_REFERENCE) {
1456: throw new StreamCorruptedException();
1457: }
1458: passHandle = bin.readInt() - baseWireHandle;
1459: if (passHandle < 0 || passHandle >= handles.size()) {
1460: throw new StreamCorruptedException("illegal handle value");
1461: }
1462: if (unshared) {
1463: // what type of exception to throw here?
1464: throw new InvalidObjectException(
1465: "cannot read back reference as unshared");
1466: }
1467:
1468: Object obj = handles.lookupObject(passHandle);
1469: if (obj == unsharedMarker) {
1470: // what type of exception to throw here?
1471: throw new InvalidObjectException(
1472: "cannot read back reference to unshared object");
1473: }
1474: return obj;
1475: }
1476:
1477: /**
1478: * Reads in and returns class object. Sets passHandle to class object's
1479: * assigned handle. Returns null if class is unresolvable (in which case a
1480: * ClassNotFoundException will be associated with the class' handle in the
1481: * handle table).
1482: */
1483: private Class readClass(boolean unshared) throws IOException {
1484: if (bin.readByte() != TC_CLASS) {
1485: throw new StreamCorruptedException();
1486: }
1487: ObjectStreamClass desc = readClassDesc(false);
1488: Class cl = desc.forClass();
1489: passHandle = handles.assign(unshared ? unsharedMarker : cl);
1490:
1491: ClassNotFoundException resolveEx = desc.getResolveException();
1492: if (resolveEx != null) {
1493: handles.markException(passHandle, resolveEx);
1494: }
1495:
1496: handles.finish(passHandle);
1497: return cl;
1498: }
1499:
1500: /**
1501: * Reads in and returns (possibly null) class descriptor. Sets passHandle
1502: * to class descriptor's assigned handle. If class descriptor cannot be
1503: * resolved to a class in the local VM, a ClassNotFoundException is
1504: * associated with the class descriptor's handle.
1505: */
1506: private ObjectStreamClass readClassDesc(boolean unshared)
1507: throws IOException {
1508: switch (bin.peekByte()) {
1509: case TC_NULL:
1510: return (ObjectStreamClass) readNull();
1511:
1512: case TC_REFERENCE:
1513: return (ObjectStreamClass) readHandle(unshared);
1514:
1515: case TC_PROXYCLASSDESC:
1516: return readProxyDesc(unshared);
1517:
1518: case TC_CLASSDESC:
1519: return readNonProxyDesc(unshared);
1520:
1521: default:
1522: throw new StreamCorruptedException();
1523: }
1524: }
1525:
1526: /**
1527: * Reads in and returns class descriptor for a dynamic proxy class. Sets
1528: * passHandle to proxy class descriptor's assigned handle. If proxy class
1529: * descriptor cannot be resolved to a class in the local VM, a
1530: * ClassNotFoundException is associated with the descriptor's handle.
1531: */
1532: private ObjectStreamClass readProxyDesc(boolean unshared)
1533: throws IOException {
1534: if (bin.readByte() != TC_PROXYCLASSDESC) {
1535: throw new StreamCorruptedException();
1536: }
1537:
1538: ObjectStreamClass desc = new ObjectStreamClass();
1539: int descHandle = handles.assign(unshared ? unsharedMarker
1540: : desc);
1541: passHandle = NULL_HANDLE;
1542:
1543: int numIfaces = bin.readInt();
1544: String[] ifaces = new String[numIfaces];
1545: for (int i = 0; i < numIfaces; i++) {
1546: ifaces[i] = bin.readUTF();
1547: }
1548:
1549: Class cl = null;
1550: ClassNotFoundException resolveEx = null;
1551: bin.setBlockDataMode(true);
1552: try {
1553: if ((cl = resolveProxyClass(ifaces)) == null) {
1554: throw new ClassNotFoundException("null class");
1555: }
1556: } catch (ClassNotFoundException ex) {
1557: resolveEx = ex;
1558: }
1559: skipCustomData();
1560:
1561: desc.initProxy(cl, resolveEx, readClassDesc(false));
1562:
1563: handles.finish(descHandle);
1564: passHandle = descHandle;
1565: return desc;
1566: }
1567:
1568: /**
1569: * Reads in and returns class descriptor for a class that is not a dynamic
1570: * proxy class. Sets passHandle to class descriptor's assigned handle. If
1571: * class descriptor cannot be resolved to a class in the local VM, a
1572: * ClassNotFoundException is associated with the descriptor's handle.
1573: */
1574: private ObjectStreamClass readNonProxyDesc(boolean unshared)
1575: throws IOException {
1576: if (bin.readByte() != TC_CLASSDESC) {
1577: throw new StreamCorruptedException();
1578: }
1579:
1580: ObjectStreamClass desc = new ObjectStreamClass();
1581: int descHandle = handles.assign(unshared ? unsharedMarker
1582: : desc);
1583: passHandle = NULL_HANDLE;
1584:
1585: ObjectStreamClass readDesc = null;
1586: try {
1587: readDesc = readClassDescriptor();
1588: } catch (ClassNotFoundException ex) {
1589: // do something less drastic here?
1590: throw new StreamCorruptedException();
1591: }
1592:
1593: Class cl = null;
1594: ClassNotFoundException resolveEx = null;
1595: bin.setBlockDataMode(true);
1596: try {
1597: if ((cl = resolveClass(readDesc)) == null) {
1598: throw new ClassNotFoundException("null class");
1599: }
1600: } catch (ClassNotFoundException ex) {
1601: resolveEx = ex;
1602: }
1603: skipCustomData();
1604:
1605: desc
1606: .initNonProxy(readDesc, cl, resolveEx,
1607: readClassDesc(false));
1608:
1609: handles.finish(descHandle);
1610: passHandle = descHandle;
1611: return desc;
1612: }
1613:
1614: /**
1615: * Reads in and returns new string. Sets passHandle to new string's
1616: * assigned handle.
1617: */
1618: private String readString(boolean unshared) throws IOException {
1619: String str;
1620: switch (bin.readByte()) {
1621: case TC_STRING:
1622: str = bin.readUTF();
1623: break;
1624:
1625: case TC_LONGSTRING:
1626: str = bin.readLongUTF();
1627: break;
1628:
1629: default:
1630: throw new StreamCorruptedException();
1631: }
1632: passHandle = handles.assign(unshared ? unsharedMarker : str);
1633: handles.finish(passHandle);
1634: return str;
1635: }
1636:
1637: /**
1638: * Reads in and returns array object, or null if array class is
1639: * unresolvable. Sets passHandle to array's assigned handle.
1640: */
1641: private Object readArray(boolean unshared) throws IOException {
1642: if (bin.readByte() != TC_ARRAY) {
1643: throw new StreamCorruptedException();
1644: }
1645:
1646: ObjectStreamClass desc = readClassDesc(false);
1647: int len = bin.readInt();
1648:
1649: Object array = null;
1650: Class cl, ccl = null;
1651: if ((cl = desc.forClass()) != null) {
1652: ccl = cl.getComponentType();
1653: array = Array.newInstance(ccl, len);
1654: }
1655:
1656: int arrayHandle = handles.assign(unshared ? unsharedMarker
1657: : array);
1658: ClassNotFoundException resolveEx = desc.getResolveException();
1659: if (resolveEx != null) {
1660: handles.markException(arrayHandle, resolveEx);
1661: }
1662:
1663: if (ccl == null) {
1664: for (int i = 0; i < len; i++) {
1665: readObject0(false);
1666: }
1667: } else if (ccl.isPrimitive()) {
1668: if (ccl == Integer.TYPE) {
1669: bin.readInts((int[]) array, 0, len);
1670: } else if (ccl == Byte.TYPE) {
1671: bin.readFully((byte[]) array, 0, len, true);
1672: } else if (ccl == Long.TYPE) {
1673: bin.readLongs((long[]) array, 0, len);
1674: } else if (ccl == Float.TYPE) {
1675: bin.readFloats((float[]) array, 0, len);
1676: } else if (ccl == Double.TYPE) {
1677: bin.readDoubles((double[]) array, 0, len);
1678: } else if (ccl == Short.TYPE) {
1679: bin.readShorts((short[]) array, 0, len);
1680: } else if (ccl == Character.TYPE) {
1681: bin.readChars((char[]) array, 0, len);
1682: } else if (ccl == Boolean.TYPE) {
1683: bin.readBooleans((boolean[]) array, 0, len);
1684: } else {
1685: throw new InternalError();
1686: }
1687: } else {
1688: Object[] oa = (Object[]) array;
1689: for (int i = 0; i < len; i++) {
1690: oa[i] = readObject0(false);
1691: handles.markDependency(arrayHandle, passHandle);
1692: }
1693: }
1694:
1695: handles.finish(arrayHandle);
1696: passHandle = arrayHandle;
1697: return array;
1698: }
1699:
1700: /**
1701: * Reads and returns "ordinary" (i.e., not a String, Class,
1702: * ObjectStreamClass or array) object, or null if object's class is
1703: * unresolvable (in which case a ClassNotFoundException will be associated
1704: * with object's handle). Sets passHandle to object's assigned handle.
1705: */
1706: private Object readOrdinaryObject(boolean unshared)
1707: throws IOException {
1708: if (bin.readByte() != TC_OBJECT) {
1709: throw new StreamCorruptedException();
1710: }
1711:
1712: ObjectStreamClass desc = readClassDesc(false);
1713: desc.checkDeserialize();
1714:
1715: Object obj;
1716: try {
1717: obj = desc.isInstantiable() ? desc.newInstance() : null;
1718: } catch (IllegalAccessException e) {
1719: throw new InvalidClassException(desc.forClass().getName(),
1720: "IllegalAccessException");
1721: } catch (InstantiationException e) {
1722: throw new InvalidClassException(desc.forClass().getName(),
1723: "InstantiationException");
1724: } catch (Exception ex) {
1725: throw new InvalidClassException(desc.forClass().getName(),
1726: "unable to create instance");
1727: }
1728:
1729: passHandle = handles.assign(unshared ? unsharedMarker : obj);
1730: ClassNotFoundException resolveEx = desc.getResolveException();
1731: if (resolveEx != null) {
1732: handles.markException(passHandle, resolveEx);
1733: }
1734:
1735: if (desc.isExternalizable()) {
1736: readExternalData((Externalizable) obj, desc);
1737: } else {
1738: readSerialData(obj, desc);
1739: }
1740:
1741: handles.finish(passHandle);
1742:
1743: if (obj != null && handles.lookupException(passHandle) == null
1744: && desc.hasReadResolveMethod()) {
1745: Object rep = desc.invokeReadResolve(obj);
1746: if (rep != obj) {
1747: handles.setObject(passHandle, obj = rep);
1748: }
1749: }
1750:
1751: return obj;
1752: }
1753:
1754: /**
1755: * If obj is non-null, reads externalizable data by invoking readExternal()
1756: * method of obj; otherwise, attempts to skip over externalizable data.
1757: * Expects that passHandle is set to obj's handle before this method is
1758: * called.
1759: */
1760: private void readExternalData(Externalizable obj,
1761: ObjectStreamClass desc) throws IOException {
1762: Object oldObj = curObj;
1763: ObjectStreamClass oldDesc = curDesc;
1764: GetFieldImpl oldGet = curGet;
1765: curObj = obj;
1766: curDesc = null;
1767: curGet = null;
1768:
1769: boolean blocked = desc.hasBlockExternalData();
1770: if (blocked) {
1771: bin.setBlockDataMode(true);
1772: }
1773: if (obj != null) {
1774: try {
1775: obj.readExternal(this );
1776: } catch (ClassNotFoundException ex) {
1777: /*
1778: * In most cases, the handle table has already propagated a
1779: * CNFException to passHandle at this point; this mark call is
1780: * included to address cases where the readExternal method has
1781: * cons'ed and thrown a new CNFException of its own.
1782: */
1783: handles.markException(passHandle, ex);
1784: }
1785: }
1786: if (blocked) {
1787: skipCustomData();
1788: }
1789:
1790: /*
1791: * At this point, if the externalizable data was not written in
1792: * block-data form and either the externalizable class doesn't exist
1793: * locally (i.e., obj == null) or readExternal() just threw a
1794: * CNFException, then the stream is probably in an inconsistent state,
1795: * since some (or all) of the externalizable data may not have been
1796: * consumed. Since there's no "correct" action to take in this case,
1797: * we mimic the behavior of past serialization implementations and
1798: * blindly hope that the stream is in sync; if it isn't and additional
1799: * externalizable data remains in the stream, a subsequent read will
1800: * most likely throw a StreamCorruptedException.
1801: */
1802:
1803: curObj = oldObj;
1804: curDesc = oldDesc;
1805: curGet = oldGet;
1806: }
1807:
1808: /**
1809: * Reads (or attempts to skip, if obj is null) instance data for each
1810: * serializable class of object in stream, from superclass to subclass.
1811: * Expects that passHandle is set to obj's handle before this method is
1812: * called.
1813: */
1814: private void readSerialData(Object obj, ObjectStreamClass desc)
1815: throws IOException {
1816: ObjectStreamClass.ClassDataSlot[] slots = desc
1817: .getClassDataLayout();
1818: for (int i = 0; i < slots.length; i++) {
1819: ObjectStreamClass slotDesc = slots[i].desc;
1820:
1821: if (slots[i].hasData) {
1822: if ((obj != null) && slotDesc.hasReadObjectMethod()) {
1823: Object oldObj = curObj;
1824: ObjectStreamClass oldDesc = curDesc;
1825: GetFieldImpl oldGet = curGet;
1826: curObj = obj;
1827: curDesc = slotDesc;
1828: curGet = null;
1829:
1830: bin.setBlockDataMode(true);
1831: try {
1832: slotDesc.invokeReadObject(obj, this );
1833: } catch (ClassNotFoundException ex) {
1834: /*
1835: * In most cases, the handle table has already
1836: * propagated a CNFException to passHandle at this
1837: * point; this mark call is included to address cases
1838: * where the custom readObject method has cons'ed and
1839: * thrown a new CNFException of its own.
1840: */
1841: handles.markException(passHandle, ex);
1842: }
1843:
1844: curObj = oldObj;
1845: curDesc = oldDesc;
1846: curGet = oldGet;
1847:
1848: /*
1849: * defaultDataEnd may have been set indirectly by custom
1850: * readObject() method when calling defaultReadObject() or
1851: * readFields(); clear it to restore normal read behavior.
1852: */
1853: defaultDataEnd = false;
1854: } else {
1855: defaultReadFields(obj, slotDesc);
1856: }
1857: if (slotDesc.hasWriteObjectData()) {
1858: skipCustomData();
1859: } else {
1860: bin.setBlockDataMode(false);
1861: }
1862: } else {
1863: if (obj != null && slotDesc.hasReadObjectNoDataMethod()) {
1864: slotDesc.invokeReadObjectNoData(obj);
1865: }
1866: }
1867: }
1868: }
1869:
1870: /**
1871: * Skips over all block data and objects until TC_ENDBLOCKDATA is
1872: * encountered.
1873: */
1874: private void skipCustomData() throws IOException {
1875: int oldHandle = passHandle;
1876: for (;;) {
1877: if (bin.getBlockDataMode()) {
1878: bin.skipBlockData();
1879: bin.setBlockDataMode(false);
1880: }
1881: switch (bin.peekByte()) {
1882: case TC_BLOCKDATA:
1883: case TC_BLOCKDATALONG:
1884: bin.setBlockDataMode(true);
1885: break;
1886:
1887: case TC_ENDBLOCKDATA:
1888: bin.readByte();
1889: passHandle = oldHandle;
1890: return;
1891:
1892: default:
1893: readObject0(false);
1894: break;
1895: }
1896: }
1897: }
1898:
1899: /**
1900: * Reads in values of serializable fields declared by given class
1901: * descriptor. If obj is non-null, sets field values in obj. Expects that
1902: * passHandle is set to obj's handle before this method is called.
1903: */
1904: private void defaultReadFields(Object obj, ObjectStreamClass desc)
1905: throws IOException {
1906: // is isInstance check necessary?
1907: Class cl = desc.forClass();
1908: if (cl != null && obj != null && !cl.isInstance(obj)) {
1909: throw new ClassCastException();
1910: }
1911:
1912: int primDataSize = desc.getPrimDataSize();
1913: if (primVals == null || primVals.length < primDataSize) {
1914: primVals = new byte[primDataSize];
1915: }
1916: bin.readFully(primVals, 0, primDataSize, false);
1917: if (obj != null) {
1918: desc.setPrimFieldValues(obj, primVals);
1919: }
1920:
1921: int objHandle = passHandle;
1922: ObjectStreamField[] fields = desc.getFields(false);
1923: Object[] objVals = new Object[desc.getNumObjFields()];
1924: int numPrimFields = fields.length - objVals.length;
1925: for (int i = 0; i < objVals.length; i++) {
1926: ObjectStreamField f = fields[numPrimFields + i];
1927: objVals[i] = readObject0(f.isUnshared());
1928: if (f.getField() != null) {
1929: handles.markDependency(objHandle, passHandle);
1930: }
1931: }
1932: if (obj != null) {
1933: desc.setObjFieldValues(obj, objVals);
1934: }
1935: passHandle = objHandle;
1936: }
1937:
1938: /**
1939: * Reads in and returns IOException that caused serialization to abort.
1940: * All stream state is discarded prior to reading in fatal exception. Sets
1941: * passHandle to fatal exception's handle.
1942: */
1943: private IOException readFatalException() throws IOException {
1944: if (bin.readByte() != TC_EXCEPTION) {
1945: throw new StreamCorruptedException();
1946: }
1947: clear();
1948: return (IOException) readObject0(false);
1949: }
1950:
1951: /**
1952: * If recursion depth is 0, clears internal data structures; otherwise,
1953: * throws a StreamCorruptedException. This method is called when a
1954: * TC_RESET typecode is encountered.
1955: */
1956: private void handleReset() throws StreamCorruptedException {
1957: if (depth > 0) {
1958: throw new StreamCorruptedException("unexpected reset");
1959: }
1960: clear();
1961: }
1962:
1963: /**
1964: * Converts specified span of bytes into float values.
1965: */
1966: // TODO: remove once hotspot inlines Float.intBitsToFloat
1967: private static native void bytesToFloats(byte[] src, int srcpos,
1968: float[] dst, int dstpos, int nfloats);
1969:
1970: /**
1971: * Converts specified span of bytes into double values.
1972: */
1973: // TODO: remove once hotspot inlines Double.longBitsToDouble
1974: private static native void bytesToDoubles(byte[] src, int srcpos,
1975: double[] dst, int dstpos, int ndoubles);
1976:
1977: /**
1978: * Returns the first non-null class loader (not counting class loaders of
1979: * generated reflection implementation classes) up the execution stack, or
1980: * null if only code from the null class loader is on the stack. This
1981: * method is also called via reflection by the following RMI-IIOP class:
1982: *
1983: * com.sun.corba.se.internal.util.JDKClassLoader
1984: *
1985: * This method should not be removed or its signature changed without
1986: * corresponding modifications to the above class.
1987: */
1988: // TODO: change name to something more accurate?
1989: private static native ClassLoader latestUserDefinedLoader();
1990:
1991: /**
1992: * Default GetField implementation.
1993: */
1994: private class GetFieldImpl extends GetField {
1995:
1996: /** class descriptor describing serializable fields */
1997: private final ObjectStreamClass desc;
1998: /** primitive field values */
1999: private final byte[] primVals;
2000: /** object field values */
2001: private final Object[] objVals;
2002: /** object field value handles */
2003: private final int[] objHandles;
2004:
2005: /**
2006: * Creates GetFieldImpl object for reading fields defined in given
2007: * class descriptor.
2008: */
2009: GetFieldImpl(ObjectStreamClass desc) {
2010: this .desc = desc;
2011: primVals = new byte[desc.getPrimDataSize()];
2012: objVals = new Object[desc.getNumObjFields()];
2013: objHandles = new int[objVals.length];
2014: }
2015:
2016: public ObjectStreamClass getObjectStreamClass() {
2017: return desc;
2018: }
2019:
2020: public boolean defaulted(String name) throws IOException,
2021: IllegalArgumentException {
2022: return (getFieldOffset(name, null) < 0);
2023: }
2024:
2025: public boolean get(String name, boolean val)
2026: throws IOException, IllegalArgumentException {
2027: int off = getFieldOffset(name, Boolean.TYPE);
2028: return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
2029: }
2030:
2031: public byte get(String name, byte val) throws IOException,
2032: IllegalArgumentException {
2033: int off = getFieldOffset(name, Byte.TYPE);
2034: return (off >= 0) ? primVals[off] : val;
2035: }
2036:
2037: public char get(String name, char val) throws IOException,
2038: IllegalArgumentException {
2039: int off = getFieldOffset(name, Character.TYPE);
2040: return (off >= 0) ? Bits.getChar(primVals, off) : val;
2041: }
2042:
2043: public short get(String name, short val) throws IOException,
2044: IllegalArgumentException {
2045: int off = getFieldOffset(name, Short.TYPE);
2046: return (off >= 0) ? Bits.getShort(primVals, off) : val;
2047: }
2048:
2049: public int get(String name, int val) throws IOException,
2050: IllegalArgumentException {
2051: int off = getFieldOffset(name, Integer.TYPE);
2052: return (off >= 0) ? Bits.getInt(primVals, off) : val;
2053: }
2054:
2055: public float get(String name, float val) throws IOException,
2056: IllegalArgumentException {
2057: int off = getFieldOffset(name, Float.TYPE);
2058: return (off >= 0) ? Bits.getFloat(primVals, off) : val;
2059: }
2060:
2061: public long get(String name, long val) throws IOException,
2062: IllegalArgumentException {
2063: int off = getFieldOffset(name, Long.TYPE);
2064: return (off >= 0) ? Bits.getLong(primVals, off) : val;
2065: }
2066:
2067: public double get(String name, double val) throws IOException,
2068: IllegalArgumentException {
2069: int off = getFieldOffset(name, Double.TYPE);
2070: return (off >= 0) ? Bits.getDouble(primVals, off) : val;
2071: }
2072:
2073: public Object get(String name, Object val) throws IOException,
2074: IllegalArgumentException {
2075: int off = getFieldOffset(name, Object.class);
2076: if (off >= 0) {
2077: int objHandle = objHandles[off];
2078: handles.markDependency(passHandle, objHandle);
2079: return (handles.lookupException(objHandle) == null) ? objVals[off]
2080: : null;
2081: } else {
2082: return val;
2083: }
2084: }
2085:
2086: /**
2087: * Reads primitive and object field values from stream.
2088: */
2089: void readFields() throws IOException {
2090: bin.readFully(primVals, 0, primVals.length, false);
2091:
2092: int oldHandle = passHandle;
2093: ObjectStreamField[] fields = desc.getFields(false);
2094: int numPrimFields = fields.length - objVals.length;
2095: for (int i = 0; i < objVals.length; i++) {
2096: objVals[i] = readObject0(fields[numPrimFields + i]
2097: .isUnshared());
2098: objHandles[i] = passHandle;
2099: }
2100: passHandle = oldHandle;
2101: }
2102:
2103: /**
2104: * Returns offset of field with given name and type. A specified type
2105: * of null matches all types, Object.class matches all non-primitive
2106: * types, and any other non-null type matches assignable types only.
2107: * If no matching field is found in the (incoming) class
2108: * descriptor but a matching field is present in the associated local
2109: * class descriptor, returns -1. Throws IllegalArgumentException if
2110: * neither incoming nor local class descriptor contains a match.
2111: */
2112: private int getFieldOffset(String name, Class type) {
2113: ObjectStreamField field = desc.getField(name, type);
2114: if (field != null) {
2115: return field.getOffset();
2116: } else if (desc.getLocalDesc().getField(name, type) != null) {
2117: return -1;
2118: } else {
2119: throw new IllegalArgumentException("no such field");
2120: }
2121: }
2122: }
2123:
2124: /**
2125: * Prioritized list of callbacks to be performed once object graph has been
2126: * completely deserialized.
2127: */
2128: private static class ValidationList {
2129:
2130: private static class Callback {
2131: final ObjectInputValidation obj;
2132: final int priority;
2133: Callback next;
2134:
2135: Callback(ObjectInputValidation obj, int priority,
2136: Callback next) {
2137: this .obj = obj;
2138: this .priority = priority;
2139: this .next = next;
2140: }
2141: }
2142:
2143: /** linked list of callbacks */
2144: private Callback list;
2145:
2146: /**
2147: * Creates new (empty) ValidationList.
2148: */
2149: ValidationList() {
2150: }
2151:
2152: /**
2153: * Registers callback. Throws InvalidObjectException if callback
2154: * object is null.
2155: */
2156: void register(ObjectInputValidation obj, int priority)
2157: throws InvalidObjectException {
2158: if (obj == null) {
2159: throw new InvalidObjectException("null callback");
2160: }
2161:
2162: Callback prev = null, cur = list;
2163: while (cur != null && priority < cur.priority) {
2164: prev = cur;
2165: cur = cur.next;
2166: }
2167: if (prev != null) {
2168: prev.next = new Callback(obj, priority, cur);
2169: } else {
2170: list = new Callback(obj, priority, list);
2171: }
2172: }
2173:
2174: /**
2175: * Invokes all registered callbacks and clears the callback list.
2176: * Callbacks with higher priorities are called first; those with equal
2177: * priorities may be called in any order. If any of the callbacks
2178: * throws an InvalidObjectException, the callback process is terminated
2179: * and the exception propagated upwards.
2180: */
2181: void doCallbacks() throws InvalidObjectException {
2182: try {
2183: while (list != null) {
2184: list.obj.validateObject();
2185: list = list.next;
2186: }
2187: } catch (InvalidObjectException ex) {
2188: list = null;
2189: throw ex;
2190: }
2191: }
2192:
2193: /**
2194: * Resets the callback list to its initial (empty) state.
2195: */
2196: public void clear() {
2197: list = null;
2198: }
2199: }
2200:
2201: /**
2202: * Input stream supporting single-byte peek operations.
2203: */
2204: private static class PeekInputStream extends InputStream {
2205:
2206: /** underlying stream */
2207: private final InputStream in;
2208: /** peeked byte */
2209: private int peekb = -1;
2210:
2211: /**
2212: * Creates new PeekInputStream on top of given underlying stream.
2213: */
2214: PeekInputStream(InputStream in) {
2215: this .in = in;
2216: }
2217:
2218: /**
2219: * Peeks at next byte value in stream. Similar to read(), except
2220: * that it does not consume the read value.
2221: */
2222: int peek() throws IOException {
2223: return (peekb >= 0) ? peekb : (peekb = in.read());
2224: }
2225:
2226: public int read() throws IOException {
2227: if (peekb >= 0) {
2228: int v = peekb;
2229: peekb = -1;
2230: return v;
2231: } else {
2232: return in.read();
2233: }
2234: }
2235:
2236: public int read(byte[] b, int off, int len) throws IOException {
2237: if (len == 0) {
2238: return 0;
2239: } else if (peekb < 0) {
2240: return in.read(b, off, len);
2241: } else {
2242: b[off++] = (byte) peekb;
2243: len--;
2244: peekb = -1;
2245: int n = in.read(b, off, len);
2246: return (n >= 0) ? (n + 1) : 1;
2247: }
2248: }
2249:
2250: void readFully(byte[] b, int off, int len) throws IOException {
2251: int n = 0;
2252: while (n < len) {
2253: int count = read(b, off + n, len - n);
2254: if (count < 0) {
2255: throw new EOFException();
2256: }
2257: n += count;
2258: }
2259: }
2260:
2261: public long skip(long n) throws IOException {
2262: if (n <= 0) {
2263: return 0;
2264: }
2265: int skipped = 0;
2266: if (peekb >= 0) {
2267: peekb = -1;
2268: skipped++;
2269: n--;
2270: }
2271: return skipped + skip(n);
2272: }
2273:
2274: public int available() throws IOException {
2275: return in.available() + ((peekb >= 0) ? 1 : 0);
2276: }
2277:
2278: public void close() throws IOException {
2279: in.close();
2280: }
2281: }
2282:
2283: /**
2284: * Input stream with two modes: in default mode, inputs data written in the
2285: * same format as DataOutputStream; in "block data" mode, inputs data
2286: * bracketed by block data markers (see object serialization specification
2287: * for details). Buffering depends on block data mode: when in default
2288: * mode, no data is buffered in advance; when in block data mode, all data
2289: * for the current data block is read in at once (and buffered).
2290: */
2291: private class BlockDataInputStream extends InputStream implements
2292: DataInput {
2293: /** maximum data block length */
2294: private static final int MAX_BLOCK_SIZE = 1024;
2295: /** maximum data block header length */
2296: private static final int MAX_HEADER_SIZE = 5;
2297: /** (tunable) length of char buffer (for reading strings) */
2298: private static final int CHAR_BUF_SIZE = 256;
2299: /** readBlockHeader() return value indicating header read may block */
2300: private static final int HEADER_BLOCKED = -2;
2301:
2302: /** buffer for reading general/block data */
2303: private final byte[] buf = new byte[MAX_BLOCK_SIZE];
2304: /** buffer for reading block data headers */
2305: private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
2306: /** char buffer for fast string reads */
2307: private final char[] cbuf = new char[CHAR_BUF_SIZE];
2308:
2309: /** block data mode */
2310: private boolean blkmode = false;
2311:
2312: // block data state fields; values meaningful only when blkmode true
2313: /** current offset into buf */
2314: private int pos = 0;
2315: /** end offset of valid data in buf, or -1 if no more block data */
2316: private int end = -1;
2317: /** number of bytes in current block yet to be read from stream */
2318: private int unread = 0;
2319:
2320: /** buffer for constructing deserialized strings */
2321: private final StringBuffer sbuf = new StringBuffer();
2322:
2323: /** underlying stream (wrapped in peekable filter stream) */
2324: private final PeekInputStream in;
2325: /** loopback stream (for data reads that span data blocks) */
2326: private final DataInputStream din;
2327:
2328: /**
2329: * Creates new BlockDataInputStream on top of given underlying stream.
2330: * Block data mode is turned off by default.
2331: */
2332: BlockDataInputStream(InputStream in) {
2333: this .in = new PeekInputStream(in);
2334: din = new DataInputStream(this );
2335: }
2336:
2337: /**
2338: * Sets block data mode to the given mode (true == on, false == off)
2339: * and returns the previous mode value. If the new mode is the same as
2340: * the old mode, no action is taken. Throws IllegalStateException if
2341: * block data mode is being switched from on to off while unconsumed
2342: * block data is still present in the stream.
2343: */
2344: boolean setBlockDataMode(boolean newmode) throws IOException {
2345: if (blkmode == newmode) {
2346: return blkmode;
2347: }
2348: if (newmode) {
2349: pos = 0;
2350: end = 0;
2351: unread = 0;
2352: } else if (pos < end) {
2353: throw new IllegalStateException("unread block data");
2354: }
2355: blkmode = newmode;
2356: return !blkmode;
2357: }
2358:
2359: /**
2360: * Returns true if the stream is currently in block data mode, false
2361: * otherwise.
2362: */
2363: boolean getBlockDataMode() {
2364: return blkmode;
2365: }
2366:
2367: /**
2368: * If in block data mode, skips to the end of the current group of data
2369: * blocks (but does not unset block data mode). If not in block data
2370: * mode, throws an IllegalStateException.
2371: */
2372: void skipBlockData() throws IOException {
2373: if (!blkmode) {
2374: throw new IllegalStateException(
2375: "not in block data mode");
2376: }
2377: while (end >= 0) {
2378: refill();
2379: }
2380: }
2381:
2382: /**
2383: * Attempts to read in the next block data header (if any). If
2384: * canBlock is false and a full header cannot be read without possibly
2385: * blocking, returns HEADER_BLOCKED, else if the next element in the
2386: * stream is a block data header, returns the block data length
2387: * specified by the header, else returns -1.
2388: */
2389: private int readBlockHeader(boolean canBlock)
2390: throws IOException {
2391: if (defaultDataEnd) {
2392: /*
2393: * Fix for 4360508: stream is currently at the end of a field
2394: * value block written via default serialization; since there
2395: * is no terminating TC_ENDBLOCKDATA tag, simulate
2396: * end-of-custom-data behavior explicitly.
2397: */
2398: return -1;
2399: }
2400: try {
2401: for (;;) {
2402: int avail = canBlock ? Integer.MAX_VALUE : in
2403: .available();
2404: if (avail == 0) {
2405: return HEADER_BLOCKED;
2406: }
2407:
2408: int tc = in.peek();
2409: switch (tc) {
2410: case TC_BLOCKDATA:
2411: if (avail < 2) {
2412: return HEADER_BLOCKED;
2413: }
2414: in.readFully(hbuf, 0, 2);
2415: return hbuf[1] & 0xFF;
2416:
2417: case TC_BLOCKDATALONG:
2418: if (avail < 5) {
2419: return HEADER_BLOCKED;
2420: }
2421: in.readFully(hbuf, 0, 5);
2422: int len = Bits.getInt(hbuf, 1);
2423: if (len < 0) {
2424: throw new StreamCorruptedException(
2425: "illegal block data header length");
2426: }
2427: return len;
2428:
2429: /*
2430: * TC_RESETs may occur in between data blocks.
2431: * Unfortunately, this case must be parsed at a lower
2432: * level than other typecodes, since primitive data
2433: * reads may span data blocks separated by a TC_RESET.
2434: */
2435: case TC_RESET:
2436: in.read();
2437: handleReset();
2438: break;
2439:
2440: default:
2441: if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
2442: throw new StreamCorruptedException();
2443: }
2444: return -1;
2445: }
2446: }
2447: } catch (EOFException ex) {
2448: throw new StreamCorruptedException(
2449: "unexpected EOF while reading block data header");
2450: }
2451: }
2452:
2453: /**
2454: * Refills internal buffer buf with block data. Any data in buf at the
2455: * time of the call is considered consumed. Sets the pos, end, and
2456: * unread fields to reflect the new amount of available block data; if
2457: * the next element in the stream is not a data block, sets pos and
2458: * unread to 0 and end to -1.
2459: */
2460: private void refill() throws IOException {
2461: try {
2462: do {
2463: pos = 0;
2464: if (unread > 0) {
2465: int n = in.read(buf, 0, Math.min(unread,
2466: MAX_BLOCK_SIZE));
2467: if (n >= 0) {
2468: end = n;
2469: unread -= n;
2470: } else {
2471: throw new StreamCorruptedException(
2472: "unexpected EOF in middle of data block");
2473: }
2474: } else {
2475: int n = readBlockHeader(true);
2476: if (n >= 0) {
2477: end = 0;
2478: unread = n;
2479: } else {
2480: end = -1;
2481: unread = 0;
2482: }
2483: }
2484: } while (pos == end);
2485: } catch (IOException ex) {
2486: pos = 0;
2487: end = -1;
2488: unread = 0;
2489: throw ex;
2490: }
2491: }
2492:
2493: /**
2494: * If in block data mode, returns the number of unconsumed bytes
2495: * remaining in the current data block. If not in block data mode,
2496: * throws an IllegalStateException.
2497: */
2498: int currentBlockRemaining() {
2499: if (blkmode) {
2500: return (end >= 0) ? (end - pos) + unread : 0;
2501: } else {
2502: throw new IllegalStateException();
2503: }
2504: }
2505:
2506: /**
2507: * Peeks at (but does not consume) and returns the next byte value in
2508: * the stream, or -1 if the end of the stream/block data (if in block
2509: * data mode) has been reached.
2510: */
2511: int peek() throws IOException {
2512: if (blkmode) {
2513: if (pos == end) {
2514: refill();
2515: }
2516: return (end >= 0) ? (buf[pos] & 0xFF) : -1;
2517: } else {
2518: return in.peek();
2519: }
2520: }
2521:
2522: /**
2523: * Peeks at (but does not consume) and returns the next byte value in
2524: * the stream, or throws EOFException if end of stream/block data has
2525: * been reached.
2526: */
2527: byte peekByte() throws IOException {
2528: int val = peek();
2529: if (val < 0) {
2530: throw new EOFException();
2531: }
2532: return (byte) val;
2533: }
2534:
2535: /* ----------------- generic input stream methods ------------------ */
2536: /*
2537: * The following methods are equivalent to their counterparts in
2538: * InputStream, except that they interpret data block boundaries and
2539: * read the requested data from within data blocks when in block data
2540: * mode.
2541: */
2542:
2543: public int read() throws IOException {
2544: if (blkmode) {
2545: if (pos == end) {
2546: refill();
2547: }
2548: return (end >= 0) ? (buf[pos++] & 0xFF) : -1;
2549: } else {
2550: return in.read();
2551: }
2552: }
2553:
2554: public int read(byte[] b, int off, int len) throws IOException {
2555: return read(b, off, len, false);
2556: }
2557:
2558: public long skip(long len) throws IOException {
2559: long remain = len;
2560: while (remain > 0) {
2561: if (blkmode) {
2562: if (pos == end) {
2563: refill();
2564: }
2565: if (end < 0) {
2566: break;
2567: }
2568: int nread = (int) Math.min(remain, end - pos);
2569: remain -= nread;
2570: pos += nread;
2571: } else {
2572: int nread = (int) Math.min(remain, MAX_BLOCK_SIZE);
2573: if ((nread = in.read(buf, 0, nread)) < 0) {
2574: break;
2575: }
2576: remain -= nread;
2577: }
2578: }
2579: return len - remain;
2580: }
2581:
2582: public int available() throws IOException {
2583: if (blkmode) {
2584: if ((pos == end) && (unread == 0)) {
2585: int n;
2586: while ((n = readBlockHeader(false)) == 0)
2587: ;
2588: switch (n) {
2589: case HEADER_BLOCKED:
2590: break;
2591:
2592: case -1:
2593: pos = 0;
2594: end = -1;
2595: break;
2596:
2597: default:
2598: pos = 0;
2599: end = 0;
2600: unread = n;
2601: break;
2602: }
2603: }
2604: // avoid unnecessary call to in.available() if possible
2605: int unreadAvail = (unread > 0) ? Math.min(in
2606: .available(), unread) : 0;
2607: return (end >= 0) ? (end - pos) + unreadAvail : 0;
2608: } else {
2609: return in.available();
2610: }
2611: }
2612:
2613: public void close() throws IOException {
2614: if (blkmode) {
2615: pos = 0;
2616: end = -1;
2617: unread = 0;
2618: }
2619: in.close();
2620: }
2621:
2622: /**
2623: * Attempts to read len bytes into byte array b at offset off. Returns
2624: * the number of bytes read, or -1 if the end of stream/block data has
2625: * been reached. If copy is true, reads values into an intermediate
2626: * buffer before copying them to b (to avoid exposing a reference to
2627: * b).
2628: */
2629: int read(byte[] b, int off, int len, boolean copy)
2630: throws IOException {
2631: if (len == 0) {
2632: return 0;
2633: } else if (blkmode) {
2634: if (pos == end) {
2635: refill();
2636: }
2637: if (end < 0) {
2638: return -1;
2639: }
2640: int nread = Math.min(len, end - pos);
2641: System.arraycopy(buf, pos, b, off, nread);
2642: pos += nread;
2643: return nread;
2644: } else if (copy) {
2645: int nread = in.read(buf, 0, Math.min(len,
2646: MAX_BLOCK_SIZE));
2647: if (nread > 0) {
2648: System.arraycopy(buf, 0, b, off, nread);
2649: }
2650: return nread;
2651: } else {
2652: return in.read(b, off, len);
2653: }
2654: }
2655:
2656: /* ----------------- primitive data input methods ------------------ */
2657: /*
2658: * The following methods are equivalent to their counterparts in
2659: * DataInputStream, except that they interpret data block boundaries
2660: * and read the requested data from within data blocks when in block
2661: * data mode.
2662: */
2663:
2664: public void readFully(byte[] b) throws IOException {
2665: readFully(b, 0, b.length, false);
2666: }
2667:
2668: public void readFully(byte[] b, int off, int len)
2669: throws IOException {
2670: readFully(b, off, len, false);
2671: }
2672:
2673: public void readFully(byte[] b, int off, int len, boolean copy)
2674: throws IOException {
2675: while (len > 0) {
2676: int n = read(b, off, len, copy);
2677: if (n < 0) {
2678: throw new EOFException();
2679: }
2680: off += n;
2681: len -= n;
2682: }
2683: }
2684:
2685: public int skipBytes(int n) throws IOException {
2686: return din.skipBytes(n);
2687: }
2688:
2689: public boolean readBoolean() throws IOException {
2690: int v = read();
2691: if (v < 0) {
2692: throw new EOFException();
2693: }
2694: return (v != 0);
2695: }
2696:
2697: public byte readByte() throws IOException {
2698: int v = read();
2699: if (v < 0) {
2700: throw new EOFException();
2701: }
2702: return (byte) v;
2703: }
2704:
2705: public int readUnsignedByte() throws IOException {
2706: int v = read();
2707: if (v < 0) {
2708: throw new EOFException();
2709: }
2710: return v;
2711: }
2712:
2713: public char readChar() throws IOException {
2714: if (!blkmode) {
2715: pos = 0;
2716: in.readFully(buf, 0, 2);
2717: } else if (end - pos < 2) {
2718: return din.readChar();
2719: }
2720: char v = Bits.getChar(buf, pos);
2721: pos += 2;
2722: return v;
2723: }
2724:
2725: public short readShort() throws IOException {
2726: if (!blkmode) {
2727: pos = 0;
2728: in.readFully(buf, 0, 2);
2729: } else if (end - pos < 2) {
2730: return din.readShort();
2731: }
2732: short v = Bits.getShort(buf, pos);
2733: pos += 2;
2734: return v;
2735: }
2736:
2737: public int readUnsignedShort() throws IOException {
2738: if (!blkmode) {
2739: pos = 0;
2740: in.readFully(buf, 0, 2);
2741: } else if (end - pos < 2) {
2742: return din.readUnsignedShort();
2743: }
2744: int v = Bits.getShort(buf, pos) & 0xFFFF;
2745: pos += 2;
2746: return v;
2747: }
2748:
2749: public int readInt() throws IOException {
2750: if (!blkmode) {
2751: pos = 0;
2752: in.readFully(buf, 0, 4);
2753: } else if (end - pos < 4) {
2754: return din.readInt();
2755: }
2756: int v = Bits.getInt(buf, pos);
2757: pos += 4;
2758: return v;
2759: }
2760:
2761: public float readFloat() throws IOException {
2762: if (!blkmode) {
2763: pos = 0;
2764: in.readFully(buf, 0, 4);
2765: } else if (end - pos < 4) {
2766: return din.readFloat();
2767: }
2768: float v = Bits.getFloat(buf, pos);
2769: pos += 4;
2770: return v;
2771: }
2772:
2773: public long readLong() throws IOException {
2774: if (!blkmode) {
2775: pos = 0;
2776: in.readFully(buf, 0, 8);
2777: } else if (end - pos < 8) {
2778: return din.readLong();
2779: }
2780: long v = Bits.getLong(buf, pos);
2781: pos += 8;
2782: return v;
2783: }
2784:
2785: public double readDouble() throws IOException {
2786: if (!blkmode) {
2787: pos = 0;
2788: in.readFully(buf, 0, 8);
2789: } else if (end - pos < 8) {
2790: return din.readDouble();
2791: }
2792: double v = Bits.getDouble(buf, pos);
2793: pos += 8;
2794: return v;
2795: }
2796:
2797: public String readUTF() throws IOException {
2798: return readUTFBody(readUnsignedShort());
2799: }
2800:
2801: public String readLine() throws IOException {
2802: return din.readLine(); // deprecated, not worth optimizing
2803: }
2804:
2805: /* -------------- primitive data array input methods --------------- */
2806: /*
2807: * The following methods read in spans of primitive data values.
2808: * Though equivalent to calling the corresponding primitive read
2809: * methods repeatedly, these methods are optimized for reading groups
2810: * of primitive data values more efficiently.
2811: */
2812:
2813: void readBooleans(boolean[] v, int off, int len)
2814: throws IOException {
2815: int stop, endoff = off + len;
2816: while (off < endoff) {
2817: if (!blkmode) {
2818: int span = Math.min(endoff - off, MAX_BLOCK_SIZE);
2819: in.readFully(buf, 0, span);
2820: stop = off + span;
2821: pos = 0;
2822: } else if (end - pos < 1) {
2823: v[off++] = din.readBoolean();
2824: continue;
2825: } else {
2826: stop = Math.min(endoff, off + end - pos);
2827: }
2828:
2829: while (off < stop) {
2830: v[off++] = Bits.getBoolean(buf, pos++);
2831: }
2832: }
2833: }
2834:
2835: void readChars(char[] v, int off, int len) throws IOException {
2836: int stop, endoff = off + len;
2837: while (off < endoff) {
2838: if (!blkmode) {
2839: int span = Math.min(endoff - off,
2840: MAX_BLOCK_SIZE >> 1);
2841: in.readFully(buf, 0, span << 1);
2842: stop = off + span;
2843: pos = 0;
2844: } else if (end - pos < 2) {
2845: v[off++] = din.readChar();
2846: continue;
2847: } else {
2848: stop = Math.min(endoff, off + ((end - pos) >> 1));
2849: }
2850:
2851: while (off < stop) {
2852: v[off++] = Bits.getChar(buf, pos);
2853: pos += 2;
2854: }
2855: }
2856: }
2857:
2858: void readShorts(short[] v, int off, int len) throws IOException {
2859: int stop, endoff = off + len;
2860: while (off < endoff) {
2861: if (!blkmode) {
2862: int span = Math.min(endoff - off,
2863: MAX_BLOCK_SIZE >> 1);
2864: in.readFully(buf, 0, span << 1);
2865: stop = off + span;
2866: pos = 0;
2867: } else if (end - pos < 2) {
2868: v[off++] = din.readShort();
2869: continue;
2870: } else {
2871: stop = Math.min(endoff, off + ((end - pos) >> 1));
2872: }
2873:
2874: while (off < stop) {
2875: v[off++] = Bits.getShort(buf, pos);
2876: pos += 2;
2877: }
2878: }
2879: }
2880:
2881: void readInts(int[] v, int off, int len) throws IOException {
2882: int stop, endoff = off + len;
2883: while (off < endoff) {
2884: if (!blkmode) {
2885: int span = Math.min(endoff - off,
2886: MAX_BLOCK_SIZE >> 2);
2887: in.readFully(buf, 0, span << 2);
2888: stop = off + span;
2889: pos = 0;
2890: } else if (end - pos < 4) {
2891: v[off++] = din.readInt();
2892: continue;
2893: } else {
2894: stop = Math.min(endoff, off + ((end - pos) >> 2));
2895: }
2896:
2897: while (off < stop) {
2898: v[off++] = Bits.getInt(buf, pos);
2899: pos += 4;
2900: }
2901: }
2902: }
2903:
2904: void readFloats(float[] v, int off, int len) throws IOException {
2905: int span, endoff = off + len;
2906: while (off < endoff) {
2907: if (!blkmode) {
2908: span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
2909: in.readFully(buf, 0, span << 2);
2910: pos = 0;
2911: } else if (end - pos < 4) {
2912: v[off++] = din.readFloat();
2913: continue;
2914: } else {
2915: span = Math.min(endoff - off, ((end - pos) >> 2));
2916: }
2917:
2918: bytesToFloats(buf, pos, v, off, span);
2919: off += span;
2920: pos += span << 2;
2921: }
2922: }
2923:
2924: void readLongs(long[] v, int off, int len) throws IOException {
2925: int stop, endoff = off + len;
2926: while (off < endoff) {
2927: if (!blkmode) {
2928: int span = Math.min(endoff - off,
2929: MAX_BLOCK_SIZE >> 3);
2930: in.readFully(buf, 0, span << 3);
2931: stop = off + span;
2932: pos = 0;
2933: } else if (end - pos < 8) {
2934: v[off++] = din.readLong();
2935: continue;
2936: } else {
2937: stop = Math.min(endoff, off + ((end - pos) >> 3));
2938: }
2939:
2940: while (off < stop) {
2941: v[off++] = Bits.getLong(buf, pos);
2942: pos += 8;
2943: }
2944: }
2945: }
2946:
2947: void readDoubles(double[] v, int off, int len)
2948: throws IOException {
2949: int span, endoff = off + len;
2950: while (off < endoff) {
2951: if (!blkmode) {
2952: span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
2953: in.readFully(buf, 0, span << 3);
2954: pos = 0;
2955: } else if (end - pos < 8) {
2956: v[off++] = din.readDouble();
2957: continue;
2958: } else {
2959: span = Math.min(endoff - off, ((end - pos) >> 3));
2960: }
2961:
2962: bytesToDoubles(buf, pos, v, off, span);
2963: off += span;
2964: pos += span << 3;
2965: }
2966: }
2967:
2968: /**
2969: * Reads in string written in "long" UTF format. "Long" UTF format is
2970: * identical to standard UTF, except that it uses an 8 byte header
2971: * (instead of the standard 2 bytes) to convey the UTF encoding length.
2972: */
2973: String readLongUTF() throws IOException {
2974: return readUTFBody(readLong());
2975: }
2976:
2977: /**
2978: * Reads in the "body" (i.e., the UTF representation minus the 2-byte
2979: * or 8-byte length header) of a UTF encoding, which occupies the next
2980: * utflen bytes.
2981: */
2982: private String readUTFBody(long utflen) throws IOException {
2983: sbuf.setLength(0);
2984: if (!blkmode) {
2985: end = pos = 0;
2986: }
2987:
2988: while (utflen > 0) {
2989: int avail = end - pos;
2990: if (avail >= 3 || (long) avail == utflen) {
2991: utflen -= readUTFSpan(utflen);
2992: } else {
2993: if (blkmode) {
2994: // near block boundary, read one byte at a time
2995: utflen -= readUTFChar(utflen);
2996: } else {
2997: // shift and refill buffer manually
2998: if (avail > 0) {
2999: System.arraycopy(buf, pos, buf, 0, avail);
3000: }
3001: pos = 0;
3002: end = (int) Math.min(MAX_BLOCK_SIZE, utflen);
3003: in.readFully(buf, avail, end - avail);
3004: }
3005: }
3006: }
3007:
3008: return sbuf.toString();
3009: }
3010:
3011: /**
3012: * Reads span of UTF-encoded characters out of internal buffer
3013: * (starting at offset pos and ending at or before offset end),
3014: * consuming no more than utflen bytes. Appends read characters to
3015: * sbuf. Returns the number of bytes consumed.
3016: */
3017: private long readUTFSpan(long utflen) throws IOException {
3018: int cpos = 0;
3019: int start = pos;
3020: int avail = Math.min(end - pos, CHAR_BUF_SIZE);
3021: // stop short of last char unless all of utf bytes in buffer
3022: int stop = pos
3023: + ((utflen > avail) ? avail - 2 : (int) utflen);
3024: boolean outOfBounds = false;
3025:
3026: try {
3027: while (pos < stop) {
3028: int b1, b2, b3;
3029: b1 = buf[pos++] & 0xFF;
3030: switch (b1 >> 4) {
3031: case 0:
3032: case 1:
3033: case 2:
3034: case 3:
3035: case 4:
3036: case 5:
3037: case 6:
3038: case 7: // 1 byte format: 0xxxxxxx
3039: cbuf[cpos++] = (char) b1;
3040: break;
3041:
3042: case 12:
3043: case 13: // 2 byte format: 110xxxxx 10xxxxxx
3044: b2 = buf[pos++];
3045: if ((b2 & 0xC0) != 0x80) {
3046: throw new UTFDataFormatException();
3047: }
3048: cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) | ((b2 & 0x3F) << 0));
3049: break;
3050:
3051: case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3052: b3 = buf[pos + 1];
3053: b2 = buf[pos + 0];
3054: pos += 2;
3055: if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3056: throw new UTFDataFormatException();
3057: }
3058: cbuf[cpos++] = (char) (((b1 & 0x0F) << 12)
3059: | ((b2 & 0x3F) << 6) | ((b3 & 0x3F) << 0));
3060: break;
3061:
3062: default: // 10xx xxxx, 1111 xxxx
3063: throw new UTFDataFormatException();
3064: }
3065: }
3066: } catch (ArrayIndexOutOfBoundsException ex) {
3067: outOfBounds = true;
3068: } finally {
3069: if (outOfBounds || (pos - start) > utflen) {
3070: /*
3071: * Fix for 4450867: if a malformed utf char causes the
3072: * conversion loop to scan past the expected end of the utf
3073: * string, only consume the expected number of utf bytes.
3074: */
3075: pos = start + (int) utflen;
3076: throw new UTFDataFormatException();
3077: }
3078: }
3079:
3080: sbuf.append(cbuf, 0, cpos);
3081: return pos - start;
3082: }
3083:
3084: /**
3085: * Reads in single UTF-encoded character one byte at a time, appends
3086: * the character to sbuf, and returns the number of bytes consumed.
3087: * This method is used when reading in UTF strings written in block
3088: * data mode to handle UTF-encoded characters which (potentially)
3089: * straddle block-data boundaries.
3090: */
3091: private int readUTFChar(long utflen) throws IOException {
3092: int b1, b2, b3;
3093: b1 = readByte() & 0xFF;
3094: switch (b1 >> 4) {
3095: case 0:
3096: case 1:
3097: case 2:
3098: case 3:
3099: case 4:
3100: case 5:
3101: case 6:
3102: case 7: // 1 byte format: 0xxxxxxx
3103: sbuf.append((char) b1);
3104: return 1;
3105:
3106: case 12:
3107: case 13: // 2 byte format: 110xxxxx 10xxxxxx
3108: if (utflen < 2) {
3109: throw new UTFDataFormatException();
3110: }
3111: b2 = readByte();
3112: if ((b2 & 0xC0) != 0x80) {
3113: throw new UTFDataFormatException();
3114: }
3115: sbuf
3116: .append((char) (((b1 & 0x1F) << 6) | ((b2 & 0x3F) << 0)));
3117: return 2;
3118:
3119: case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
3120: if (utflen < 3) {
3121: if (utflen == 2) {
3122: readByte(); // consume remaining byte
3123: }
3124: throw new UTFDataFormatException();
3125: }
3126: b2 = readByte();
3127: b3 = readByte();
3128: if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
3129: throw new UTFDataFormatException();
3130: }
3131: sbuf.append((char) (((b1 & 0x0F) << 12)
3132: | ((b2 & 0x3F) << 6) | ((b3 & 0x3F) << 0)));
3133: return 3;
3134:
3135: default: // 10xx xxxx, 1111 xxxx
3136: throw new UTFDataFormatException();
3137: }
3138: }
3139: }
3140:
3141: /**
3142: * Unsynchronized table which tracks wire handle to object mappings, as
3143: * well as ClassNotFoundExceptions associated with deserialized objects.
3144: * This class implements an exception-propagation algorithm for
3145: * determining which objects should have ClassNotFoundExceptions associated
3146: * with them, taking into account cycles and discontinuities (e.g., skipped
3147: * fields) in the object graph.
3148: *
3149: * <p>General use of the table is as follows: during deserialization, a
3150: * given object is first assigned a handle by calling the assign method.
3151: * This method leaves the assigned handle in an "open" state, wherein
3152: * dependencies on the exception status of other handles can be registered
3153: * by calling the markDependency method, or an exception can be directly
3154: * associated with the handle by calling markException. When a handle is
3155: * tagged with an exception, the HandleTable assumes responsibility for
3156: * propagating the exception to any other objects which depend
3157: * (transitively) on the exception-tagged object.
3158: *
3159: * <p>Once all exception information/dependencies for the handle have been
3160: * registered, the handle should be "closed" by calling the finish method
3161: * on it. The act of finishing a handle allows the exception propagation
3162: * algorithm to aggressively prune dependency links, lessening the
3163: * performance/memory impact of exception tracking.
3164: *
3165: * <p>Note that the exception propagation algorithm used depends on handles
3166: * being assigned/finished in LIFO order; however, for simplicity as well
3167: * as memory conservation, it does not enforce this constraint.
3168: */
3169: // TODO: add full description of exception propagation algorithm?
3170: private static class HandleTable {
3171:
3172: /* status codes indicating whether object has associated exception */
3173: private static final byte STATUS_OK = 1;
3174: private static final byte STATUS_UNKNOWN = 2;
3175: private static final byte STATUS_EXCEPTION = 3;
3176:
3177: /** array mapping handle -> object status */
3178: byte[] status;
3179: /** array mapping handle -> object/exception (depending on status) */
3180: Object[] entries;
3181: /** array mapping handle -> list of dependent handles (if any) */
3182: HandleList[] deps;
3183: /** lowest unresolved dependency */
3184: int lowDep = -1;
3185: /** number of handles in table */
3186: int size = 0;
3187:
3188: /**
3189: * Creates handle table with the given initial capacity.
3190: */
3191: HandleTable(int initialCapacity) {
3192: status = new byte[initialCapacity];
3193: entries = new Object[initialCapacity];
3194: deps = new HandleList[initialCapacity];
3195: }
3196:
3197: /**
3198: * Assigns next available handle to given object, and returns assigned
3199: * handle. Once object has been completely deserialized (and all
3200: * dependencies on other objects identified), the handle should be
3201: * "closed" by passing it to finish().
3202: */
3203: int assign(Object obj) {
3204: if (size >= entries.length) {
3205: grow();
3206: }
3207: status[size] = STATUS_UNKNOWN;
3208: entries[size] = obj;
3209: return size++;
3210: }
3211:
3212: /**
3213: * Registers a dependency (in exception status) of one handle on
3214: * another. The dependent handle must be "open" (i.e., assigned, but
3215: * not finished yet). No action is taken if either dependent or target
3216: * handle is NULL_HANDLE.
3217: */
3218: void markDependency(int dependent, int target) {
3219: if (dependent == NULL_HANDLE || target == NULL_HANDLE) {
3220: return;
3221: }
3222: switch (status[dependent]) {
3223:
3224: case STATUS_UNKNOWN:
3225: switch (status[target]) {
3226: case STATUS_OK:
3227: // ignore dependencies on objs with no exception
3228: break;
3229:
3230: case STATUS_EXCEPTION:
3231: // eagerly propagate exception
3232: markException(dependent,
3233: (ClassNotFoundException) entries[target]);
3234: break;
3235:
3236: case STATUS_UNKNOWN:
3237: // add to dependency list of target
3238: if (deps[target] == null) {
3239: deps[target] = new HandleList();
3240: }
3241: deps[target].add(dependent);
3242:
3243: // remember lowest unresolved target seen
3244: if (lowDep < 0 || lowDep > target) {
3245: lowDep = target;
3246: }
3247: break;
3248:
3249: default:
3250: throw new InternalError();
3251: }
3252: break;
3253:
3254: case STATUS_EXCEPTION:
3255: break;
3256:
3257: default:
3258: throw new InternalError();
3259: }
3260: }
3261:
3262: /**
3263: * Associates a ClassNotFoundException (if one not already associated)
3264: * with the currently active handle and propagates it to other
3265: * referencing objects as appropriate. The specified handle must be
3266: * "open" (i.e., assigned, but not finished yet).
3267: */
3268: void markException(int handle, ClassNotFoundException ex) {
3269: switch (status[handle]) {
3270: case STATUS_UNKNOWN:
3271: status[handle] = STATUS_EXCEPTION;
3272: entries[handle] = ex;
3273:
3274: // propagate exception to dependents
3275: HandleList dlist = deps[handle];
3276: if (dlist != null) {
3277: int ndeps = dlist.size();
3278: for (int i = 0; i < ndeps; i++) {
3279: markException(dlist.get(i), ex);
3280: }
3281: deps[handle] = null;
3282: }
3283: break;
3284:
3285: case STATUS_EXCEPTION:
3286: break;
3287:
3288: default:
3289: throw new InternalError();
3290: }
3291: }
3292:
3293: /**
3294: * Marks given handle as finished, meaning that no new dependencies
3295: * will be marked for handle. Calls to the assign and finish methods
3296: * must occur in LIFO order.
3297: */
3298: void finish(int handle) {
3299: int end;
3300: if (lowDep < 0) {
3301: // no pending unknowns, only resolve current handle
3302: end = handle + 1;
3303: } else if (lowDep >= handle) {
3304: // pending unknowns now clearable, resolve all upward handles
3305: end = size;
3306: lowDep = -1;
3307: } else {
3308: // unresolved backrefs present, can't resolve anything yet
3309: return;
3310: }
3311:
3312: // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
3313: for (int i = handle; i < end; i++) {
3314: switch (status[i]) {
3315: case STATUS_UNKNOWN:
3316: status[i] = STATUS_OK;
3317: deps[i] = null;
3318: break;
3319:
3320: case STATUS_OK:
3321: case STATUS_EXCEPTION:
3322: break;
3323:
3324: default:
3325: throw new InternalError();
3326: }
3327: }
3328: }
3329:
3330: /**
3331: * Assigns a new object to the given handle. The object previously
3332: * associated with the handle is forgotten. This method has no effect
3333: * if the given handle already has an exception associated with it.
3334: * This method may be called at any time after the handle is assigned.
3335: */
3336: void setObject(int handle, Object obj) {
3337: switch (status[handle]) {
3338: case STATUS_UNKNOWN:
3339: case STATUS_OK:
3340: entries[handle] = obj;
3341: break;
3342:
3343: case STATUS_EXCEPTION:
3344: break;
3345:
3346: default:
3347: throw new InternalError();
3348: }
3349: }
3350:
3351: /**
3352: * Looks up and returns object associated with the given handle.
3353: * Returns null if the given handle is NULL_HANDLE, or if it has an
3354: * associated ClassNotFoundException.
3355: */
3356: Object lookupObject(int handle) {
3357: return (handle != NULL_HANDLE && status[handle] != STATUS_EXCEPTION) ? entries[handle]
3358: : null;
3359: }
3360:
3361: /**
3362: * Looks up and returns ClassNotFoundException associated with the
3363: * given handle. Returns null if the given handle is NULL_HANDLE, or
3364: * if there is no ClassNotFoundException associated with the handle.
3365: */
3366: ClassNotFoundException lookupException(int handle) {
3367: return (handle != NULL_HANDLE && status[handle] == STATUS_EXCEPTION) ? (ClassNotFoundException) entries[handle]
3368: : null;
3369: }
3370:
3371: /**
3372: * Resets table to its initial state.
3373: */
3374: void clear() {
3375: Arrays.fill(status, 0, size, (byte) 0);
3376: Arrays.fill(entries, 0, size, null);
3377: Arrays.fill(deps, 0, size, null);
3378: lowDep = -1;
3379: size = 0;
3380: }
3381:
3382: /**
3383: * Returns number of handles registered in table.
3384: */
3385: int size() {
3386: return size;
3387: }
3388:
3389: /**
3390: * Expands capacity of internal arrays.
3391: */
3392: private void grow() {
3393: int newCapacity = (entries.length << 1) + 1;
3394:
3395: byte[] newStatus = new byte[newCapacity];
3396: Object[] newEntries = new Object[newCapacity];
3397: HandleList[] newDeps = new HandleList[newCapacity];
3398: /* IAI - 15 */
3399: CVM.copyByteArray(status, 0, newStatus, 0, size);
3400: CVM.copyObjectArray(entries, 0, newEntries, 0, size);
3401: CVM.copyObjectArray(deps, 0, newDeps, 0, size);
3402: /* IAI - 15 */
3403:
3404: status = newStatus;
3405: entries = newEntries;
3406: deps = newDeps;
3407: }
3408:
3409: /**
3410: * Simple growable list of (integer) handles.
3411: */
3412: private static class HandleList {
3413: private int[] list = new int[4];
3414: private int size = 0;
3415:
3416: public HandleList() {
3417: }
3418:
3419: public void add(int handle) {
3420: if (size >= list.length) {
3421: int[] newList = new int[list.length << 1];
3422: /* IAI - 15 */
3423: CVM.copyIntArray(list, 0, newList, 0, list.length);
3424: /* IAI - 15 */
3425: list = newList;
3426: }
3427: list[size++] = handle;
3428: }
3429:
3430: public int get(int index) {
3431: if (index >= size) {
3432: throw new ArrayIndexOutOfBoundsException();
3433: }
3434: return list[index];
3435: }
3436:
3437: public int size() {
3438: return size;
3439: }
3440: }
3441: }
3442: }
|