changeset 238:76aeef3afc04

6996740: Yet more breakage caused by 6891766 Summary: Restore com.sun.corba.se.simpl.io.IIOPInputStream that 6891766 nuked in error Reviewed-by: asaha
author alanb
date Tue, 02 Nov 2010 18:27:04 +0000
parents 046be5aaff1c
children e5819cb9b15e 8260ec509a10
files make/com/sun/corba/minclude/com_sun_corba_se_impl_io.jmk src/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java
diffstat 2 files changed, 2722 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/make/com/sun/corba/minclude/com_sun_corba_se_impl_io.jmk	Sun Oct 31 22:10:24 2010 -0700
+++ b/make/com/sun/corba/minclude/com_sun_corba_se_impl_io.jmk	Tue Nov 02 18:27:04 2010 +0000
@@ -34,6 +34,7 @@
 	com/sun/corba/se/impl/io/ObjectStreamField.java \
 	com/sun/corba/se/impl/io/OptionalDataException.java \
 	com/sun/corba/se/impl/io/ValueHandlerImpl.java \
+        com/sun/corba/se/impl/io/IIOPInputStream.java \
 	com/sun/corba/se/impl/io/IIOPOutputStream.java \
 	com/sun/corba/se/impl/io/TypeMismatchException.java \
 	com/sun/corba/se/impl/io/InputStreamHook.java \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java	Tue Nov 02 18:27:04 2010 +0000
@@ -0,0 +1,2721 @@
+/*
+ * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * Licensed Materials - Property of IBM
+ * RMI-IIOP v1.0
+ * Copyright IBM Corp. 1998 1999  All Rights Reserved
+ *
+ */
+
+package com.sun.corba.se.impl.io;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.StreamCorruptedException;
+import java.io.ObjectInputValidation;
+import java.io.NotActiveException;
+import java.io.InvalidObjectException;
+import java.io.InvalidClassException;
+import java.io.DataInputStream;
+import java.io.OptionalDataException;
+import java.io.WriteAbortedException;
+import java.io.Externalizable;
+import java.io.EOFException;
+import java.lang.reflect.*;
+import java.util.Vector;
+import java.util.Stack;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+import sun.corba.Bridge ;
+
+import java.security.AccessController ;
+import java.security.PrivilegedAction ;
+
+import com.sun.corba.se.impl.io.ObjectStreamClass;
+import com.sun.corba.se.impl.util.Utility;
+
+import org.omg.CORBA.portable.ValueInputStream;
+
+import org.omg.CORBA.ValueMember;
+import org.omg.CORBA.SystemException;
+import org.omg.CORBA.TCKind;
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.CompletionStatus;
+import org.omg.CORBA.portable.IndirectionException;
+import org.omg.CORBA.MARSHAL;
+import org.omg.CORBA.TypeCode;
+
+import com.sun.org.omg.CORBA.ValueDefPackage.FullValueDescription;
+import com.sun.org.omg.SendingContext.CodeBase;
+
+import javax.rmi.PortableRemoteObject;
+import javax.rmi.CORBA.Util;
+import javax.rmi.CORBA.ValueHandler;
+
+import java.security.*;
+import java.util.*;
+
+import com.sun.corba.se.impl.orbutil.ObjectUtility ;
+import com.sun.corba.se.impl.logging.OMGSystemException ;
+import com.sun.corba.se.impl.logging.UtilSystemException ;
+
+import com.sun.corba.se.spi.logging.CORBALogDomains ;
+
+/**
+ * IIOPInputStream is used by the ValueHandlerImpl to handle Java serialization
+ * input semantics.
+ *
+ * @author  Stephen Lewallen
+ * @since   JDK1.1.6
+ */
+
+public class IIOPInputStream
+    extends com.sun.corba.se.impl.io.InputStreamHook
+{
+    private static Bridge bridge =
+        (Bridge)AccessController.doPrivileged(
+            new PrivilegedAction() {
+                public Object run() {
+                    return Bridge.get() ;
+                }
+            }
+        ) ;
+
+    private static OMGSystemException omgWrapper = OMGSystemException.get(
+        CORBALogDomains.RPC_ENCODING ) ;
+    private static UtilSystemException utilWrapper = UtilSystemException.get(
+        CORBALogDomains.RPC_ENCODING ) ;
+
+    // Necessary to pass the appropriate fields into the
+    // defaultReadObjectDelegate method (which takes no
+    // parameters since it's called from
+    // java.io.ObjectInpuStream defaultReadObject()
+    // which we can't change).
+    //
+    // This is only used in the case where the fields had
+    // to be obtained remotely because of a serializable
+    // version difference.  Set in inputObjectUsingFVD.
+    // Part of serialization evolution fixes for Ladybird,
+    // bug 4365188.
+    private ValueMember defaultReadObjectFVDMembers[] = null;
+
+    private org.omg.CORBA_2_3.portable.InputStream orbStream;
+
+    private CodeBase cbSender;
+
+    private ValueHandlerImpl vhandler;  //d4365188
+
+    private Object currentObject = null;
+
+    private ObjectStreamClass currentClassDesc = null;
+
+    private Class currentClass = null;
+
+    private int recursionDepth = 0;
+
+    private int simpleReadDepth = 0;
+
+    // The ActiveRecursionManager replaces the old RecursionManager which
+    // used to record how many recursions were made, and resolve them after
+    // an object was completely deserialized.
+    //
+    // That created problems (as in bug 4414154) because when custom
+    // unmarshaling in readObject, there can be recursive references
+    // to one of the objects currently being unmarshaled, and the
+    // passive recursion system failed.
+    ActiveRecursionManager activeRecursionMgr = new ActiveRecursionManager();
+
+    private IOException abortIOException = null;
+
+    /* Remember the first exception that stopped this stream. */
+    private ClassNotFoundException abortClassNotFoundException = null;
+
+    /* Vector of validation callback objects
+     * The vector is created as needed. The vector is maintained in
+     * order of highest (first) priority to lowest
+     */
+    private Vector callbacks;
+
+    // Serialization machinery fields
+    /* Arrays used to keep track of classes and ObjectStreamClasses
+     * as they are being merged; used in inputObject.
+     * spClass is the stack pointer for both.  */
+    ObjectStreamClass[] classdesc;
+    Class[] classes;
+    int spClass;
+
+    private static final String kEmptyStr = "";
+
+    // TCKind TypeCodes used in FVD inputClassFields
+    //public static final TypeCode kRemoteTypeCode = new TypeCodeImpl(TCKind._tk_objref);
+    //public static final TypeCode kValueTypeCode =  new TypeCodeImpl(TCKind._tk_value);
+    // removed TypeCodeImpl dependency
+    public static final TypeCode kRemoteTypeCode = ORB.init().get_primitive_tc(TCKind.tk_objref);
+    public static final TypeCode kValueTypeCode =  ORB.init().get_primitive_tc(TCKind.tk_value);
+
+    // TESTING CODE - useFVDOnly should be made final before FCS in order to
+    // optimize out the check.
+    private static final boolean useFVDOnly = false;
+
+    private byte streamFormatVersion;
+
+    // Since java.io.OptionalDataException's constructors are
+    // package private, but we need to throw it in some special
+    // cases, we try to do it by reflection.
+    private static final Constructor OPT_DATA_EXCEPTION_CTOR;
+
+    private Object[] readObjectArgList = { this } ;
+
+    static {
+        OPT_DATA_EXCEPTION_CTOR = getOptDataExceptionCtor();
+    }
+
+    // Grab the OptionalDataException boolean ctor and make
+    // it accessible.  Note that any exceptions
+    // will be wrapped in ExceptionInInitializerErrors.
+    private static Constructor getOptDataExceptionCtor() {
+
+        try {
+
+            Constructor result =
+
+                (Constructor) AccessController.doPrivileged(
+                                    new PrivilegedExceptionAction() {
+                    public java.lang.Object run()
+                        throws NoSuchMethodException,
+                        SecurityException {
+
+                        Constructor boolCtor
+                            = OptionalDataException.class.getDeclaredConstructor(
+                                                               new Class[] {
+                                Boolean.TYPE });
+
+                        boolCtor.setAccessible(true);
+
+                        return boolCtor;
+                    }});
+
+            if (result == null)
+                // XXX I18N, logging needed.
+                throw new Error("Unable to find OptionalDataException constructor");
+
+            return result;
+
+        } catch (Exception ex) {
+            // XXX I18N, logging needed.
+            throw new ExceptionInInitializerError(ex);
+        }
+    }
+
+    // Create a new OptionalDataException with the EOF marker
+    // set to true.  See handleOptionalDataMarshalException.
+    private OptionalDataException createOptionalDataException() {
+        try {
+            OptionalDataException result
+                = (OptionalDataException)
+                   OPT_DATA_EXCEPTION_CTOR.newInstance(new Object[] {
+                       Boolean.TRUE });
+
+            if (result == null)
+                // XXX I18N, logging needed.
+                throw new Error("Created null OptionalDataException");
+
+            return result;
+
+        } catch (Exception ex) {
+            // XXX I18N, logging needed.
+            throw new Error("Couldn't create OptionalDataException", ex);
+        }
+    }
+
+    // Return the stream format version currently being used
+    // to deserialize an object
+    protected byte getStreamFormatVersion() {
+        return streamFormatVersion;
+    }
+
+    // At the beginning of data sent by a writeObject or
+    // writeExternal method there is a byte telling the
+    // reader the stream format version.
+    private void readFormatVersion() throws IOException {
+
+        streamFormatVersion = orbStream.read_octet();
+
+        if (streamFormatVersion < 1 ||
+            streamFormatVersion > vhandler.getMaximumStreamFormatVersion()) {
+            SystemException sysex = omgWrapper.unsupportedFormatVersion(
+                    CompletionStatus.COMPLETED_MAYBE);
+            // XXX I18N?  Logging for IOException?
+            IOException result = new IOException("Unsupported format version: "
+                                                 + streamFormatVersion);
+            result.initCause( sysex ) ;
+            throw result ;
+        }
+
+        if (streamFormatVersion == 2) {
+            if (!(orbStream instanceof ValueInputStream)) {
+                SystemException sysex = omgWrapper.notAValueinputstream(
+                    CompletionStatus.COMPLETED_MAYBE);
+                // XXX I18N?  Logging for IOException?
+                IOException result = new IOException("Not a ValueInputStream");
+                result.initCause( sysex ) ;
+                throw result;
+            }
+        }
+    }
+
+    public static void setTestFVDFlag(boolean val){
+        //  useFVDOnly = val;
+    }
+
+    /**
+     * Dummy constructor; passes upper stream a dummy stream;
+     **/
+    public IIOPInputStream()
+        throws java.io.IOException {
+        super();
+        resetStream();
+    }
+
+    public final void setOrbStream(org.omg.CORBA_2_3.portable.InputStream os) {
+        orbStream = os;
+    }
+
+    public final org.omg.CORBA_2_3.portable.InputStream getOrbStream() {
+        return orbStream;
+    }
+
+    //added setSender and getSender
+    public final void setSender(CodeBase cb) {
+        cbSender = cb;
+    }
+
+    public final CodeBase getSender() {
+        return cbSender;
+    }
+
+    // 4365188 this is added to enable backward compatability w/ wrong
+    // rep-ids
+    public final void setValueHandler(ValueHandler vh) {
+        vhandler = (com.sun.corba.se.impl.io.ValueHandlerImpl) vh;
+    }
+
+    public final ValueHandler getValueHandler() {
+        return (javax.rmi.CORBA.ValueHandler) vhandler;
+    }
+
+    public final void increaseRecursionDepth(){
+        recursionDepth++;
+    }
+
+    public final int decreaseRecursionDepth(){
+        return --recursionDepth;
+    }
+
+    /**
+     * Override the actions of the final method "readObject()"
+     * in ObjectInputStream.
+     * @since     JDK1.1.6
+     *
+     * Read an object from the ObjectInputStream.
+     * The class of the object, the signature of the class, and the values
+     * of the non-transient and non-static fields of the class and all
+     * of its supertypes are read.  Default deserializing for a class can be
+     * overriden using the writeObject and readObject methods.
+     * Objects referenced by this object are read transitively so
+     * that a complete equivalent graph of objects is reconstructed by readObject. <p>
+     *
+     * The root object is completly restored when all of its fields
+     * and the objects it references are completely restored.  At this
+     * point the object validation callbacks are executed in order
+     * based on their registered priorities. The callbacks are
+     * registered by objects (in the readObject special methods)
+     * as they are individually restored.
+     *
+     * Exceptions are thrown for problems with the InputStream and for classes
+     * that should not be deserialized.  All exceptions are fatal to the
+     * InputStream and leave it in an indeterminate state; it is up to the caller
+     * to ignore or recover the stream state.
+     * @exception java.lang.ClassNotFoundException Class of a serialized object
+     *      cannot be found.
+     * @exception InvalidClassException Something is wrong with a class used by
+     *     serialization.
+     * @exception StreamCorruptedException Control information in the
+     *     stream is inconsistent.
+     * @exception OptionalDataException Primitive data was found in the
+     * stream instead of objects.
+     * @exception IOException Any of the usual Input/Output related exceptions.
+     * @since     JDK1.1
+     */
+    public final Object readObjectDelegate() throws IOException
+    {
+        try {
+
+            readObjectState.readData(this);
+
+            return orbStream.read_abstract_interface();
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, true);
+            throw marshalException;
+        } catch(IndirectionException cdrie)
+            {
+                // The CDR stream had never seen the given offset before,
+                // so check the recursion manager (it will throw an
+                // IOException if it doesn't have a reference, either).
+                return activeRecursionMgr.getObject(cdrie.offset);
+            }
+    }
+
+    final Object simpleReadObject(Class clz,
+                                  String repositoryID,
+                                  com.sun.org.omg.SendingContext.CodeBase sender,
+                                  int offset)
+                                         /* throws OptionalDataException, ClassNotFoundException, IOException */
+    {
+
+        /* Save the current state and get ready to read an object. */
+        Object prevObject = currentObject;
+        ObjectStreamClass prevClassDesc = currentClassDesc;
+        Class prevClass = currentClass;
+        byte oldStreamFormatVersion = streamFormatVersion;
+
+        simpleReadDepth++;      // Entering
+        Object obj = null;
+
+        /*
+         * Check for reset, handle it before reading an object.
+         */
+        try {
+            // d4365188: backward compatability
+            if (vhandler.useFullValueDescription(clz, repositoryID)) {
+                obj = inputObjectUsingFVD(clz, repositoryID, sender, offset);
+            } else {
+                obj = inputObject(clz, repositoryID, sender, offset);
+            }
+
+            obj = currentClassDesc.readResolve(obj);
+        }
+        catch(ClassNotFoundException cnfe)
+            {
+                bridge.throwException( cnfe ) ;
+                return null;
+            }
+        catch(IOException ioe)
+            {
+                // System.out.println("CLZ = " + clz + "; " + ioe.toString());
+                bridge.throwException(ioe) ;
+                return null;
+            }
+        finally {
+            simpleReadDepth --;
+            currentObject = prevObject;
+            currentClassDesc = prevClassDesc;
+            currentClass = prevClass;
+            streamFormatVersion = oldStreamFormatVersion;
+        }
+
+
+        /* Check for thrown exceptions and re-throw them, clearing them if
+         * this is the last recursive call .
+         */
+        IOException exIOE = abortIOException;
+        if (simpleReadDepth == 0)
+            abortIOException = null;
+        if (exIOE != null){
+            bridge.throwException( exIOE ) ;
+            return null;
+        }
+
+
+        ClassNotFoundException exCNF = abortClassNotFoundException;
+        if (simpleReadDepth == 0)
+            abortClassNotFoundException = null;
+        if (exCNF != null) {
+            bridge.throwException( exCNF ) ;
+            return null;
+        }
+
+        return obj;
+    }
+
+    public final void simpleSkipObject(String repositoryID,
+                                       com.sun.org.omg.SendingContext.CodeBase sender)
+                                       /* throws OptionalDataException, ClassNotFoundException, IOException */
+    {
+
+        /* Save the current state and get ready to read an object. */
+        Object prevObject = currentObject;
+        ObjectStreamClass prevClassDesc = currentClassDesc;
+        Class prevClass = currentClass;
+        byte oldStreamFormatVersion = streamFormatVersion;
+
+        simpleReadDepth++;      // Entering
+        Object obj = null;
+
+        /*
+         * Check for reset, handle it before reading an object.
+         */
+        try {
+            skipObjectUsingFVD(repositoryID, sender);
+        }
+        catch(ClassNotFoundException cnfe)
+            {
+                bridge.throwException( cnfe ) ;
+                return;
+            }
+        catch(IOException ioe)
+            {
+                bridge.throwException( ioe ) ;
+                return;
+            }
+        finally {
+            simpleReadDepth --;
+            streamFormatVersion = oldStreamFormatVersion;
+            currentObject = prevObject;
+            currentClassDesc = prevClassDesc;
+            currentClass = prevClass;
+        }
+
+
+        /* Check for thrown exceptions and re-throw them, clearing them if
+         * this is the last recursive call .
+         */
+        IOException exIOE = abortIOException;
+        if (simpleReadDepth == 0)
+            abortIOException = null;
+        if (exIOE != null){
+            bridge.throwException( exIOE ) ;
+            return;
+        }
+
+
+        ClassNotFoundException exCNF = abortClassNotFoundException;
+        if (simpleReadDepth == 0)
+            abortClassNotFoundException = null;
+        if (exCNF != null) {
+            bridge.throwException( exCNF ) ;
+            return;
+        }
+
+        return;
+    }
+    /////////////////
+
+    /**
+     * This method is called by trusted subclasses of ObjectOutputStream
+     * that constructed ObjectOutputStream using the
+     * protected no-arg constructor. The subclass is expected to provide
+     * an override method with the modifier "final".
+     *
+     * @return the Object read from the stream.
+     *
+     * @see #ObjectInputStream()
+     * @see #readObject
+     * @since JDK 1.2
+     */
+    protected final Object readObjectOverride()
+        throws OptionalDataException, ClassNotFoundException, IOException
+    {
+        return readObjectDelegate();
+    }
+
+    /**
+     * Override the actions of the final method "defaultReadObject()"
+     * in ObjectInputStream.
+     * @since     JDK1.1.6
+     *
+     * Read the non-static and non-transient fields of the current class
+     * from this stream.  This may only be called from the readObject method
+     * of the class being deserialized. It will throw the NotActiveException
+     * if it is called otherwise.
+     *
+     * @exception java.lang.ClassNotFoundException if the class of a serialized
+     *              object could not be found.
+     * @exception IOException        if an I/O error occurs.
+     * @exception NotActiveException if the stream is not currently reading
+     *              objects.
+     * @since     JDK1.1
+     */
+    public final void defaultReadObjectDelegate()
+    /* throws IOException, ClassNotFoundException, NotActiveException */
+    {
+        try {
+            if (currentObject == null || currentClassDesc == null)
+                // XXX I18N, logging needed.
+                throw new NotActiveException("defaultReadObjectDelegate");
+
+            // The array will be null unless fields were retrieved
+            // remotely because of a serializable version difference.
+            // Bug fix for 4365188.  See the definition of
+            // defaultReadObjectFVDMembers for more information.
+            if (defaultReadObjectFVDMembers != null &&
+                defaultReadObjectFVDMembers.length > 0) {
+
+                // WARNING:  Be very careful!  What if some of
+                // these fields actually have to do this, too?
+                // This works because the defaultReadObjectFVDMembers
+                // reference is passed to inputClassFields, but
+                // there is no guarantee that
+                // defaultReadObjectFVDMembers will point to the
+                // same array after calling inputClassFields.
+
+                // Use the remote fields to unmarshal.
+                inputClassFields(currentObject,
+                                 currentClass,
+                                 currentClassDesc,
+                                 defaultReadObjectFVDMembers,
+                                 cbSender);
+
+            } else {
+
+                // Use the local fields to unmarshal.
+                ObjectStreamField[] fields =
+                    currentClassDesc.getFieldsNoCopy();
+                if (fields.length > 0) {
+                    inputClassFields(currentObject, currentClass, fields, cbSender);
+                }
+            }
+        }
+        catch(NotActiveException nae)
+            {
+                bridge.throwException( nae ) ;
+            }
+        catch(IOException ioe)
+            {
+                bridge.throwException( ioe ) ;
+            }
+        catch(ClassNotFoundException cnfe)
+            {
+                bridge.throwException( cnfe ) ;
+            }
+
+    }
+
+    /**
+     * Override the actions of the final method "enableResolveObject()"
+     * in ObjectInputStream.
+     * @since     JDK1.1.6
+     *
+     * Enable the stream to allow objects read from the stream to be replaced.
+     * If the stream is a trusted class it is allowed to enable replacment.
+     * Trusted classes are those classes with a classLoader equals null. <p>
+     *
+     * When enabled the resolveObject method is called for every object
+     * being deserialized.
+     *
+     * @exception SecurityException The classloader of this stream object is non-null.
+     * @since     JDK1.1
+     */
+    public final boolean enableResolveObjectDelegate(boolean enable)
+    /* throws SecurityException */
+    {
+        return false;
+    }
+
+    // The following three methods allow the implementing orbStream
+    // to provide mark/reset behavior as defined in java.io.InputStream.
+
+    public final void mark(int readAheadLimit) {
+        orbStream.mark(readAheadLimit);
+    }
+
+    public final boolean markSupported() {
+        return orbStream.markSupported();
+    }
+
+    public final void reset() throws IOException {
+        try {
+            orbStream.reset();
+        } catch (Error e) {
+            IOException err = new IOException(e.getMessage());
+            err.initCause(e) ;
+            throw err ;
+        }
+    }
+
+    public final int available() throws IOException{
+        return 0; // unreliable
+    }
+
+    public final void close() throws IOException{
+        // no op
+    }
+
+    public final int read() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return (orbStream.read_octet() << 0) & 0x000000FF;
+        } catch (MARSHAL marshalException) {
+            if (marshalException.minor
+                == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) {
+                setState(IN_READ_OBJECT_NO_MORE_OPT_DATA);
+                return -1;
+            }
+
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e) ;
+            throw exc ;
+        }
+    }
+
+    public final int read(byte data[], int offset, int length) throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            orbStream.read_octet_array(data, offset, length);
+            return length;
+        } catch (MARSHAL marshalException) {
+            if (marshalException.minor
+                == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) {
+                setState(IN_READ_OBJECT_NO_MORE_OPT_DATA);
+                return -1;
+            }
+
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e) ;
+            throw exc ;
+        }
+
+    }
+
+    public final boolean readBoolean() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return orbStream.read_boolean();
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+            throw marshalException;
+
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    public final byte readByte() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return orbStream.read_octet();
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+            throw marshalException;
+
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    public final char readChar() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return orbStream.read_wchar();
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+            throw marshalException;
+
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    public final double readDouble() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return orbStream.read_double();
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    public final float readFloat() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return orbStream.read_float();
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    public final void readFully(byte data[]) throws IOException{
+// d11623 : implement readFully, required for serializing some core classes
+
+        readFully(data, 0, data.length);
+    }
+
+    public final void readFully(byte data[],  int offset,  int size) throws IOException{
+// d11623 : implement readFully, required for serializing some core classes
+        try{
+            readObjectState.readData(this);
+
+            orbStream.read_octet_array(data, offset, size);
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    public final int readInt() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return orbStream.read_long();
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    public final String readLine() throws IOException{
+        // XXX I18N, logging needed.
+        throw new IOException("Method readLine not supported");
+    }
+
+    public final long readLong() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return orbStream.read_longlong();
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    public final short readShort() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return orbStream.read_short();
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    protected final void readStreamHeader() throws IOException, StreamCorruptedException{
+        // no op
+    }
+
+    public final int readUnsignedByte() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return (orbStream.read_octet() << 0) & 0x000000FF;
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    public final int readUnsignedShort() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return (orbStream.read_ushort() << 0) & 0x0000FFFF;
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    /**
+     * Helper method for correcting the Kestrel bug 4367783 (dealing
+     * with larger than 8-bit chars).  The old behavior is preserved
+     * in orbutil.IIOPInputStream_1_3 in order to interoperate with
+     * our legacy ORBs.
+     */
+    protected String internalReadUTF(org.omg.CORBA.portable.InputStream stream)
+    {
+        return stream.read_wstring();
+    }
+
+    public final String readUTF() throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            return internalReadUTF(orbStream);
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e);
+            throw exc ;
+        }
+    }
+
+    // If the ORB stream detects an incompatibility between what's
+    // on the wire and what our Serializable's readObject wants,
+    // it throws a MARSHAL exception with a specific minor code.
+    // This is rethrown to the readObject as an OptionalDataException.
+    // So far in RMI-IIOP, this process isn't specific enough to
+    // tell the readObject how much data is available, so we always
+    // set the OptionalDataException's EOF marker to true.
+    private void handleOptionalDataMarshalException(MARSHAL marshalException,
+                                                    boolean objectRead)
+        throws IOException {
+
+        // Java Object Serialization spec 3.4: "If the readObject method
+        // of the class attempts to read more data than is present in the
+        // optional part of the stream for this class, the stream will
+        // return -1 for bytewise reads, throw an EOFException for
+        // primitive data reads, or throw an OptionalDataException
+        // with the eof field set to true for object reads."
+        if (marshalException.minor
+            == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) {
+
+            IOException result;
+
+            if (!objectRead)
+                result = new EOFException("No more optional data");
+            else
+                result = createOptionalDataException();
+
+            result.initCause(marshalException);
+
+            setState(IN_READ_OBJECT_NO_MORE_OPT_DATA);
+
+            throw result;
+        }
+    }
+
+    public final synchronized void registerValidation(ObjectInputValidation obj,
+                                                      int prio)
+        throws NotActiveException, InvalidObjectException{
+        // XXX I18N, logging needed.
+        throw new Error("Method registerValidation not supported");
+    }
+
+    protected final Class resolveClass(ObjectStreamClass v)
+        throws IOException, ClassNotFoundException{
+        // XXX I18N, logging needed.
+        throw new IOException("Method resolveClass not supported");
+    }
+
+    protected final Object resolveObject(Object obj) throws IOException{
+        // XXX I18N, logging needed.
+        throw new IOException("Method resolveObject not supported");
+    }
+
+    public final int skipBytes(int len) throws IOException{
+        try{
+            readObjectState.readData(this);
+
+            byte buf[] = new byte[len];
+            orbStream.read_octet_array(buf, 0, len);
+            return len;
+        } catch (MARSHAL marshalException) {
+            handleOptionalDataMarshalException(marshalException, false);
+
+            throw marshalException;
+        } catch(Error e) {
+            IOException exc = new IOException(e.getMessage());
+            exc.initCause(e) ;
+            throw exc ;
+        }
+    }
+
+    private Object inputObject(Class clz,
+                               String repositoryID,
+                               com.sun.org.omg.SendingContext.CodeBase sender,
+                               int offset)
+        throws IOException, ClassNotFoundException
+    {
+
+        /*
+         * Get the descriptor and then class of the incoming object.
+         */
+
+        currentClassDesc = ObjectStreamClass.lookup(clz);
+        currentClass = currentClassDesc.forClass();
+        //currentClassDesc.setClass(currentClass);
+        if (currentClass == null)
+            // XXX I18N, logging needed.
+            throw new ClassNotFoundException(currentClassDesc.getName());
+
+        try {
+            /* If Externalizable,
+             *  Create an instance and tell it to read its data.
+             * else,
+             *  Handle it as a serializable class.
+             */
+            if (currentClassDesc.isExternalizable()) {
+                try {
+                    currentObject = (currentClass == null) ?
+                        null : currentClassDesc.newInstance();
+                    if (currentObject != null) {
+
+                        // Store this object and its beginning position
+                        // since there might be indirections to it while
+                        // it's been unmarshalled.
+                        activeRecursionMgr.addObject(offset, currentObject);
+
+                        // Read format version
+                        readFormatVersion();
+
+                        Externalizable ext = (Externalizable)currentObject;
+                        ext.readExternal(this);
+                }
+            } catch (InvocationTargetException e) {
+                InvalidClassException exc = new InvalidClassException(
+                    currentClass.getName(),
+                    "InvocationTargetException accessing no-arg constructor");
+                exc.initCause( e ) ;
+                throw exc ;
+            } catch (UnsupportedOperationException e) {
+                InvalidClassException exc = new InvalidClassException(
+                    currentClass.getName(),
+                    "UnsupportedOperationException accessing no-arg constructor");
+                exc.initCause( e ) ;
+                throw exc ;
+            } catch (InstantiationException e) {
+                InvalidClassException exc = new InvalidClassException(
+                    currentClass.getName(),
+                    "InstantiationException accessing no-arg constructor");
+                exc.initCause( e ) ;
+                throw exc ;
+            }
+        } // end : if (currentClassDesc.isExternalizable())
+        else {
+            /* Count number of classes and descriptors we might have
+             * to work on.
+             */
+
+            ObjectStreamClass currdesc = currentClassDesc;
+            Class currclass = currentClass;
+
+            int spBase = spClass;       // current top of stack
+
+            /* The object's classes should be processed from supertype to subtype
+             * Push all the clases of the current object onto a stack.
+             * Note that only the serializable classes are represented
+             * in the descriptor list.
+             *
+             * Handle versioning where one or more supertypes of
+             * have been inserted or removed.  The stack will
+             * contain pairs of descriptors and the corresponding
+             * class.  If the object has a class that did not occur in
+             * the original the descriptor will be null.  If the
+             * original object had a descriptor for a class not
+             * present in the local hierarchy of the object the class will be
+             * null.
+             *
+             */
+
+            /*
+             * This is your basic diff pattern, made simpler
+             * because reordering is not allowed.
+             */
+            // sun.4296963 ibm.11861
+            // d11861 we should stop when we find the highest serializable class
+            // We need this so that when we allocate the new object below, we
+            // can call the constructor of the non-serializable superclass.
+            // Note that in the JRMP variant of this code the
+            // ObjectStreamClass.lookup() method handles this, but we've put
+            // this fix here rather than change lookup because the new behaviour
+            // is needed in other cases.
+
+            for (currdesc = currentClassDesc, currclass = currentClass;
+                 currdesc != null && currdesc.isSerializable();   /*sun.4296963 ibm.11861*/
+                 currdesc = currdesc.getSuperclass()) {
+
+                /*
+                 * Search the classes to see if the class of this
+                 * descriptor appears further up the hierarchy. Until
+                 * it's found assume its an inserted class.  If it's
+                 * not found, its the descriptor's class that has been
+                 * removed.
+                 */
+                Class cc = currdesc.forClass();
+                Class cl;
+                for (cl = currclass; cl != null; cl = cl.getSuperclass()) {
+                    if (cc == cl) {
+                        // found a superclass that matches this descriptor
+                        break;
+                    } else {
+                        /* Ignore a class that doesn't match.  No
+                         * action is needed since it is already
+                         * initialized.
+                         */
+                    }
+                } // end : for (cl = currclass; cl != null; cl = cl.getSuperclass())
+                /* Test if there is room for this new entry.
+                 * If not, double the size of the arrays and copy the contents.
+                 */
+                spClass++;
+                if (spClass >= classes.length) {
+                    int newlen = classes.length * 2;
+                    Class[] newclasses = new Class[newlen];
+                    ObjectStreamClass[] newclassdesc = new ObjectStreamClass[newlen];
+
+                    System.arraycopy(classes, 0,
+                                     newclasses, 0,
+                                     classes.length);
+                    System.arraycopy(classdesc, 0,
+                                     newclassdesc, 0,
+                                     classes.length);
+
+                    classes = newclasses;
+                    classdesc = newclassdesc;
+                }
+
+                if (cl == null) {
+                    /* Class not found corresponding to this descriptor.
+                     * Pop off all the extra classes pushed.
+                     * Push the descriptor and a null class.
+                     */
+                    classdesc[spClass] = currdesc;
+                    classes[spClass] = null;
+                } else {
+                    /* Current class descriptor matches current class.
+                     * Some classes may have been inserted.
+                     * Record the match and advance the class, continue
+                     * with the next descriptor.
+                     */
+                    classdesc[spClass] = currdesc;
+                    classes[spClass] = cl;
+                    currclass = cl.getSuperclass();
+                }
+            } // end : for (currdesc = currentClassDesc, currclass = currentClass;
+
+            /* Allocate a new object.  The object is only constructed
+             * above the highest serializable class and is set to
+             * default values for all more specialized classes.
+             */
+            try {
+                currentObject = (currentClass == null) ?
+                    null : currentClassDesc.newInstance() ;
+
+                // Store this object and its beginning position
+                // since there might be indirections to it while
+                // it's been unmarshalled.
+                activeRecursionMgr.addObject(offset, currentObject);
+            } catch (InvocationTargetException e) {
+                InvalidClassException exc = new InvalidClassException(
+                    currentClass.getName(),
+                    "InvocationTargetException accessing no-arg constructor");
+                exc.initCause( e ) ;
+                throw exc ;
+            } catch (UnsupportedOperationException e) {
+                InvalidClassException exc = new InvalidClassException(
+                    currentClass.getName(),
+                    "UnsupportedOperationException accessing no-arg constructor");
+                exc.initCause( e ) ;
+                throw exc ;
+            } catch (InstantiationException e) {
+                InvalidClassException exc = new InvalidClassException(
+                    currentClass.getName(),
+                    "InstantiationException accessing no-arg constructor");
+                exc.initCause( e ) ;
+                throw exc ;
+            }
+
+            /*
+             * For all the pushed descriptors and classes.
+             *  if the class has its own writeObject and readObject methods
+             *      call the readObject method
+             *  else
+             *      invoke the defaultReadObject method
+             */
+            try {
+                for (spClass = spClass; spClass > spBase; spClass--) {
+                    /*
+                     * Set current descriptor and corresponding class
+                     */
+                    currentClassDesc = classdesc[spClass];
+                    currentClass = classes[spClass];
+                    if (classes[spClass] != null) {
+                        /* Read the data from the stream described by the
+                         * descriptor and store into the matching class.
+                         */
+
+                        ReadObjectState oldState = readObjectState;
+                        setState(DEFAULT_STATE);
+
+                        try {
+
+                            // Changed since invokeObjectReader no longer does this.
+                            if (currentClassDesc.hasWriteObject()) {
+
+                                // Read format version
+                                readFormatVersion();
+
+                                // Read defaultWriteObject indicator
+                                boolean calledDefaultWriteObject = readBoolean();
+
+                                readObjectState.beginUnmarshalCustomValue(this,
+                                                                          calledDefaultWriteObject,
+                                                                          (currentClassDesc.readObjectMethod
+                                                                           != null));
+                            } else {
+                                if (currentClassDesc.hasReadObject())
+                                    setState(IN_READ_OBJECT_REMOTE_NOT_CUSTOM_MARSHALED);
+                            }
+
+                            if (!invokeObjectReader(currentClassDesc, currentObject, currentClass) ||
+                                readObjectState == IN_READ_OBJECT_DEFAULTS_SENT) {
+
+                                // Error case of no readObject and didn't call
+                                // defaultWriteObject handled in default state
+
+                                ObjectStreamField[] fields =
+                                    currentClassDesc.getFieldsNoCopy();
+                                if (fields.length > 0) {
+                                    inputClassFields(currentObject, currentClass, fields, sender);
+                                }
+                            }
+
+                            if (currentClassDesc.hasWriteObject())
+                                readObjectState.endUnmarshalCustomValue(this);
+
+                        } finally {
+                            setState(oldState);
+                        }
+
+                    } else {
+
+                        // _REVISIT_ : Can we ever get here?
+                        /* No local class for this descriptor,
+                         * Skip over the data for this class.
+                         * like defaultReadObject with a null currentObject.
+                         * The code will read the values but discard them.
+                         */
+                            ObjectStreamField[] fields =
+                                currentClassDesc.getFieldsNoCopy();
+                            if (fields.length > 0) {
+                                inputClassFields(null, currentClass, fields, sender);
+                            }
+
+                        }
+
+                }
+            } finally {
+                                // Make sure we exit at the same stack level as when we started.
+                spClass = spBase;
+            }
+        }
+        } finally {
+            // We've completed deserializing this object.  Any
+            // future indirections will be handled correctly at the
+            // CDR level.  The ActiveRecursionManager only deals with
+            // objects currently being deserialized.
+            activeRecursionMgr.removeObject(offset);
+        }
+
+        return currentObject;
+    }
+
+    // This retrieves a vector of FVD's for the hierarchy of serializable classes stemming from
+    // repositoryID.  It is assumed that the sender will not provide base_value id's for non-serializable
+    // classes!
+    private Vector getOrderedDescriptions(String repositoryID,
+                                          com.sun.org.omg.SendingContext.CodeBase sender) {
+        Vector descs = new Vector();
+
+        if (sender == null) {
+            return descs;
+        }
+
+        FullValueDescription aFVD = sender.meta(repositoryID);
+        while (aFVD != null) {
+            descs.insertElementAt(aFVD, 0);
+            if ((aFVD.base_value != null) && !kEmptyStr.equals(aFVD.base_value)) {
+                aFVD = sender.meta(aFVD.base_value);
+            }
+            else return descs;
+        }
+
+        return descs;
+    }
+
+    /**
+     * This input method uses FullValueDescriptions retrieved from the sender's runtime to
+     * read in the data.  This method is capable of throwing out data not applicable to client's fields.
+     * This method handles instances where the reader has a class not sent by the sender, the sender sent
+     * a class not present on the reader, and/or the reader's class does not match the sender's class.
+     *
+     * NOTE : If the local description indicates custom marshaling and the remote type's FVD also
+     * indicates custom marsahling than the local type is used to read the data off the wire.  However,
+     * if either says custom while the other does not, a MARSHAL error is thrown.  Externalizable is
+     * a form of custom marshaling.
+     *
+     */
+    private Object inputObjectUsingFVD(Class clz,
+                                       String repositoryID,
+                                       com.sun.org.omg.SendingContext.CodeBase sender,
+                                       int offset)
+        throws IOException, ClassNotFoundException
+    {
+        int spBase = spClass;   // current top of stack
+        try{
+
+            /*
+             * Get the descriptor and then class of the incoming object.
+             */
+
+            ObjectStreamClass currdesc = currentClassDesc = ObjectStreamClass.lookup(clz);
+            Class currclass = currentClass = clz;
+
+            /* If Externalizable,
+             *  Create an instance and tell it to read its data.
+             * else,
+             *  Handle it as a serializable class.
+             */
+            if (currentClassDesc.isExternalizable()) {
+                try {
+                    currentObject = (currentClass == null) ?
+                        null : currentClassDesc.newInstance();
+                    if (currentObject != null) {
+                        // Store this object and its beginning position
+                        // since there might be indirections to it while
+                        // it's been unmarshalled.
+                        activeRecursionMgr.addObject(offset, currentObject);
+
+                        // Read format version
+                        readFormatVersion();
+
+                        Externalizable ext = (Externalizable)currentObject;
+                        ext.readExternal(this);
+                    }
+                } catch (InvocationTargetException e) {
+                    InvalidClassException exc = new InvalidClassException(
+                        currentClass.getName(),
+                        "InvocationTargetException accessing no-arg constructor");
+                    exc.initCause( e ) ;
+                    throw exc ;
+                } catch (UnsupportedOperationException e) {
+                    InvalidClassException exc = new InvalidClassException(
+                        currentClass.getName(),
+                        "UnsupportedOperationException accessing no-arg constructor");
+                    exc.initCause( e ) ;
+                    throw exc ;
+                } catch (InstantiationException e) {
+                    InvalidClassException exc = new InvalidClassException(
+                        currentClass.getName(),
+                        "InstantiationException accessing no-arg constructor");
+                    exc.initCause( e ) ;
+                    throw exc ;
+                }
+            } else {
+                /*
+                 * This is your basic diff pattern, made simpler
+                 * because reordering is not allowed.
+                 */
+                for (currdesc = currentClassDesc, currclass = currentClass;
+                     currdesc != null && currdesc.isSerializable();   /*sun.4296963 ibm.11861*/
+
+                     currdesc = currdesc.getSuperclass()) {
+
+                    /*
+                     * Search the classes to see if the class of this
+                     * descriptor appears further up the hierarchy. Until
+                     * it's found assume its an inserted class.  If it's
+                     * not found, its the descriptor's class that has been
+                     * removed.
+                     */
+                    Class cc = currdesc.forClass();
+                    Class cl;
+                    for (cl = currclass; cl != null; cl = cl.getSuperclass()) {
+                        if (cc == cl) {
+                            // found a superclass that matches this descriptor
+                            break;
+                        } else {
+                            /* Ignore a class that doesn't match.  No
+                             * action is needed since it is already
+                             * initialized.
+                             */
+                        }
+                    } // end : for (cl = currclass; cl != null; cl = cl.getSuperclass())
+                    /* Test if there is room for this new entry.
+                     * If not, double the size of the arrays and copy the contents.
+                     */
+                    spClass++;
+                    if (spClass >= classes.length) {
+                        int newlen = classes.length * 2;
+                        Class[] newclasses = new Class[newlen];
+                        ObjectStreamClass[] newclassdesc = new ObjectStreamClass[newlen];
+
+                        System.arraycopy(classes, 0,
+                                         newclasses, 0,
+                                         classes.length);
+                        System.arraycopy(classdesc, 0,
+                                         newclassdesc, 0,
+                                         classes.length);
+
+                        classes = newclasses;
+                        classdesc = newclassdesc;
+                    }
+
+                    if (cl == null) {
+                        /* Class not found corresponding to this descriptor.
+                         * Pop off all the extra classes pushed.
+                         * Push the descriptor and a null class.
+                         */
+                        classdesc[spClass] = currdesc;
+                        classes[spClass] = null;
+                    } else {
+                        /* Current class descriptor matches current class.
+                         * Some classes may have been inserted.
+                         * Record the match and advance the class, continue
+                         * with the next descriptor.
+                         */
+                        classdesc[spClass] = currdesc;
+                        classes[spClass] = cl;
+                        currclass = cl.getSuperclass();
+                    }
+                } // end : for (currdesc = currentClassDesc, currclass = currentClass;
+
+                /* Allocate a new object.
+                 */
+                try {
+                    currentObject = (currentClass == null) ?
+                        null : currentClassDesc.newInstance();
+
+                    // Store this object and its beginning position
+                    // since there might be indirections to it while
+                    // it's been unmarshalled.
+                    activeRecursionMgr.addObject(offset, currentObject);
+                } catch (InvocationTargetException e) {
+                    InvalidClassException exc = new InvalidClassException(
+                        currentClass.getName(),
+                        "InvocationTargetException accessing no-arg constructor");
+                    exc.initCause( e ) ;
+                    throw exc ;
+                } catch (UnsupportedOperationException e) {
+                    InvalidClassException exc = new InvalidClassException(
+                        currentClass.getName(),
+                        "UnsupportedOperationException accessing no-arg constructor");
+                    exc.initCause( e ) ;
+                    throw exc ;
+                } catch (InstantiationException e) {
+                    InvalidClassException exc = new InvalidClassException(
+                        currentClass.getName(),
+                        "InstantiationException accessing no-arg constructor");
+                    exc.initCause( e ) ;
+                    throw exc ;
+                }
+
+                Enumeration fvdsList = getOrderedDescriptions(repositoryID, sender).elements();
+
+                while((fvdsList.hasMoreElements()) && (spClass > spBase)) {
+                    FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement();
+                    // d4365188: backward compatability
+                    String repIDForFVD = vhandler.getClassName(fvd.id);
+                    String repIDForClass = vhandler.getClassName(vhandler.getRMIRepositoryID(currentClass));
+
+                    while ((spClass > spBase) &&
+                           (!repIDForFVD.equals(repIDForClass))) {
+                        int pos = findNextClass(repIDForFVD, classes, spClass, spBase);
+                        if (pos != -1) {
+                            spClass = pos;
+                            currclass = currentClass = classes[spClass];
+                            repIDForClass = vhandler.getClassName(vhandler.getRMIRepositoryID(currentClass));
+                        }
+                        else { // Read and throw away one level of the fvdslist
+
+                            // This seems to mean that the sender had a superclass that
+                            // we don't have
+
+                            if (fvd.is_custom) {
+
+                                readFormatVersion();
+                                boolean calledDefaultWriteObject = readBoolean();
+
+                                if (calledDefaultWriteObject)
+                                    inputClassFields(null, null, null, fvd.members, sender);
+
+                                if (getStreamFormatVersion() == 2) {
+
+                                    ((ValueInputStream)getOrbStream()).start_value();
+                                    ((ValueInputStream)getOrbStream()).end_value();
+                                }
+
+                                // WARNING: If stream format version is 1 and there's
+                                // optional data, we'll get some form of exception down
+                                // the line or data corruption.
+
+                            } else {
+
+                                inputClassFields(null, currentClass, null, fvd.members, sender);
+                            }
+
+                            if (fvdsList.hasMoreElements()){
+                                fvd = (FullValueDescription)fvdsList.nextElement();
+                                repIDForFVD = vhandler.getClassName(fvd.id);
+                            }
+                            else return currentObject;
+                        }
+                    }
+
+                    currdesc = currentClassDesc = ObjectStreamClass.lookup(currentClass);
+
+                    if (!repIDForClass.equals("java.lang.Object")) {
+
+                        // If the sender used custom marshaling, then it should have put
+                        // the two bytes on the wire indicating stream format version
+                        // and whether or not the writeObject method called
+                        // defaultWriteObject/writeFields.
+
+                        ReadObjectState oldState = readObjectState;
+                        setState(DEFAULT_STATE);
+
+                        try {
+
+                            if (fvd.is_custom) {
+
+                                // Read format version
+                                readFormatVersion();
+
+                                // Read defaultWriteObject indicator
+                                boolean calledDefaultWriteObject = readBoolean();
+
+                                readObjectState.beginUnmarshalCustomValue(this,
+                                                                          calledDefaultWriteObject,
+                                                                          (currentClassDesc.readObjectMethod
+                                                                           != null));
+                            }
+
+                            boolean usedReadObject = false;
+
+                            // Always use readObject if it exists, and fall back to default
+                            // unmarshaling if it doesn't.
+                            try {
+
+                                if (!fvd.is_custom && currentClassDesc.hasReadObject())
+                                    setState(IN_READ_OBJECT_REMOTE_NOT_CUSTOM_MARSHALED);
+
+                                // See the definition of defaultReadObjectFVDMembers
+                                // for more information.  This concerns making sure
+                                // we use the remote FVD's members in defaultReadObject.
+                                defaultReadObjectFVDMembers = fvd.members;
+                                usedReadObject = invokeObjectReader(currentClassDesc,
+                                                                    currentObject,
+                                                                    currentClass);
+
+                            } finally {
+                                defaultReadObjectFVDMembers = null;
+                            }
+
+                            // Note that the !usedReadObject !calledDefaultWriteObject
+                            // case is handled by the beginUnmarshalCustomValue method
+                            // of the default state
+                            if (!usedReadObject || readObjectState == IN_READ_OBJECT_DEFAULTS_SENT)
+                                inputClassFields(currentObject, currentClass, currdesc, fvd.members, sender);
+
+                            if (fvd.is_custom)
+                                readObjectState.endUnmarshalCustomValue(this);
+
+                        } finally {
+                            setState(oldState);
+                        }
+
+                        currclass = currentClass = classes[--spClass];
+
+                    } else {
+
+                        // The remaining hierarchy of the local class does not match the sender's FVD.
+                        // So, use remaining FVDs to read data off wire.  If any remaining FVDs indicate
+                        // custom marshaling, throw MARSHAL error.
+                        inputClassFields(null, currentClass, null, fvd.members, sender);
+
+                        while (fvdsList.hasMoreElements()){
+                            fvd = (FullValueDescription)fvdsList.nextElement();
+
+                            if (fvd.is_custom)
+                                skipCustomUsingFVD(fvd.members, sender);
+                            else
+                                inputClassFields(null, currentClass, null, fvd.members, sender);
+                        }
+
+                    }
+
+                } // end : while(fvdsList.hasMoreElements())
+                while (fvdsList.hasMoreElements()){
+
+                    FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement();
+                    if (fvd.is_custom)
+                        skipCustomUsingFVD(fvd.members, sender);
+                    else
+                        throwAwayData(fvd.members, sender);
+                }
+            }
+
+            return currentObject;
+        }
+        finally {
+                // Make sure we exit at the same stack level as when we started.
+                spClass = spBase;
+
+                // We've completed deserializing this object.  Any
+                // future indirections will be handled correctly at the
+                // CDR level.  The ActiveRecursionManager only deals with
+                // objects currently being deserialized.
+                activeRecursionMgr.removeObject(offset);
+            }
+
+        }
+
+    /**
+     * This input method uses FullValueDescriptions retrieved from the sender's runtime to
+     * read in the data.  This method is capable of throwing out data not applicable to client's fields.
+     *
+     * NOTE : If the local description indicates custom marshaling and the remote type's FVD also
+     * indicates custom marsahling than the local type is used to read the data off the wire.  However,
+     * if either says custom while the other does not, a MARSHAL error is thrown.  Externalizable is
+     * a form of custom marshaling.
+     *
+     */
+    private Object skipObjectUsingFVD(String repositoryID,
+                                      com.sun.org.omg.SendingContext.CodeBase sender)
+        throws IOException, ClassNotFoundException
+    {
+
+        Enumeration fvdsList = getOrderedDescriptions(repositoryID, sender).elements();
+
+        while(fvdsList.hasMoreElements()) {
+            FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement();
+            String repIDForFVD = vhandler.getClassName(fvd.id);
+
+            if (!repIDForFVD.equals("java.lang.Object")) {
+                if (fvd.is_custom) {
+
+                    readFormatVersion();
+
+                    boolean calledDefaultWriteObject = readBoolean();
+
+                    if (calledDefaultWriteObject)
+                        inputClassFields(null, null, null, fvd.members, sender);
+
+                    if (getStreamFormatVersion() == 2) {
+
+                        ((ValueInputStream)getOrbStream()).start_value();
+                        ((ValueInputStream)getOrbStream()).end_value();
+                    }
+
+                    // WARNING: If stream format version is 1 and there's
+                    // optional data, we'll get some form of exception down
+                    // the line.
+
+                } else {
+                    // Use default marshaling
+                    inputClassFields(null, null, null, fvd.members, sender);
+                }
+            }
+
+        } // end : while(fvdsList.hasMoreElements())
+        return null;
+
+    }
+
+    ///////////////////
+
+    private int findNextClass(String classname, Class classes[], int _spClass, int _spBase){
+
+        for (int i = _spClass; i > _spBase; i--){
+            if (classname.equals(classes[i].getName())) {
+                return i;
+            }
+        }
+
+        return -1;
+    }
+
+    /*
+     * Invoke the readObject method if present.  Assumes that in the case of custom
+     * marshaling, the format version and defaultWriteObject indicator were already
+     * removed.
+     */
+    private boolean invokeObjectReader(ObjectStreamClass osc, Object obj, Class aclass)
+        throws InvalidClassException, StreamCorruptedException,
+               ClassNotFoundException, IOException
+    {
+        if (osc.readObjectMethod == null) {
+            return false;
+        }
+
+        try {
+            osc.readObjectMethod.invoke( obj, readObjectArgList ) ;
+            return true;
+        } catch (InvocationTargetException e) {
+            Throwable t = e.getTargetException();
+            if (t instanceof ClassNotFoundException)
+                throw (ClassNotFoundException)t;
+            else if (t instanceof IOException)
+                throw (IOException)t;
+            else if (t instanceof RuntimeException)
+                throw (RuntimeException) t;
+            else if (t instanceof Error)
+                throw (Error) t;
+            else
+                // XXX I18N, logging needed.
+                throw new Error("internal error");
+        } catch (IllegalAccessException e) {
+            return false;
+        }
+    }
+
+    /*
+     * Reset the stream to be just like it was after the constructor.
+     */
+    private void resetStream() throws IOException {
+
+        if (classes == null)
+            classes = new Class[20];
+        else {
+            for (int i = 0; i < classes.length; i++)
+                classes[i] = null;
+        }
+        if (classdesc == null)
+            classdesc = new ObjectStreamClass[20];
+        else {
+            for (int i = 0; i < classdesc.length; i++)
+                classdesc[i] = null;
+        }
+        spClass = 0;
+
+        if (callbacks != null)
+            callbacks.setSize(0);       // discard any pending callbacks
+    }
+
+    /**
+     * Factored out of inputClassFields  This reads a primitive value and sets it
+     * in the field of o described by the ObjectStreamField field.
+     *
+     * Note that reflection cannot be used here, because reflection cannot be used
+     * to set final fields.
+     */
+    private void inputPrimitiveField(Object o, Class cl, ObjectStreamField field)
+        throws InvalidClassException, IOException {
+
+        try {
+            switch (field.getTypeCode()) {
+                case 'B':
+                    byte byteValue = orbStream.read_octet();
+                    bridge.putByte( o, field.getFieldID(), byteValue ) ;
+                    //reflective code: field.getField().setByte( o, byteValue ) ;
+                    break;
+                case 'Z':
+                    boolean booleanValue = orbStream.read_boolean();
+                    bridge.putBoolean( o, field.getFieldID(), booleanValue ) ;
+                    //reflective code: field.getField().setBoolean( o, booleanValue ) ;
+                    break;
+                case 'C':
+                    char charValue = orbStream.read_wchar();
+                    bridge.putChar( o, field.getFieldID(), charValue ) ;
+                    //reflective code: field.getField().setChar( o, charValue ) ;
+                    break;
+                case 'S':
+                    short shortValue = orbStream.read_short();
+                    bridge.putShort( o, field.getFieldID(), shortValue ) ;
+                    //reflective code: field.getField().setShort( o, shortValue ) ;
+                    break;
+                case 'I':
+                    int intValue = orbStream.read_long();
+                    bridge.putInt( o, field.getFieldID(), intValue ) ;
+                    //reflective code: field.getField().setInt( o, intValue ) ;
+                    break;
+                case 'J':
+                    long longValue = orbStream.read_longlong();
+                    bridge.putLong( o, field.getFieldID(), longValue ) ;
+                    //reflective code: field.getField().setLong( o, longValue ) ;
+                    break;
+                case 'F' :
+                    float floatValue = orbStream.read_float();
+                    bridge.putFloat( o, field.getFieldID(), floatValue ) ;
+                    //reflective code: field.getField().setFloat( o, floatValue ) ;
+                    break;
+                case 'D' :
+                    double doubleValue = orbStream.read_double();
+                    bridge.putDouble( o, field.getFieldID(), doubleValue ) ;
+                    //reflective code: field.getField().setDouble( o, doubleValue ) ;
+                    break;
+                default:
+                    // XXX I18N, logging needed.
+                    throw new InvalidClassException(cl.getName());
+            }
+        } catch (IllegalArgumentException e) {
+            /* This case should never happen. If the field types
+               are not the same, InvalidClassException is raised when
+               matching the local class to the serialized ObjectStreamClass. */
+            ClassCastException cce = new ClassCastException("Assigning instance of class " +
+                                         field.getType().getName() +
+                                         " to field " +
+                                         currentClassDesc.getName() + '#' +
+                                         field.getField().getName());
+            cce.initCause( e ) ;
+            throw cce ;
+        }
+     }
+
+    private Object inputObjectField(org.omg.CORBA.ValueMember field,
+                                    com.sun.org.omg.SendingContext.CodeBase sender)
+        throws IndirectionException, ClassNotFoundException, IOException,
+               StreamCorruptedException {
+
+        Object objectValue = null;
+        Class type = null;
+        String id = field.id;
+
+        try {
+            type = vhandler.getClassFromType(id);
+        } catch(ClassNotFoundException cnfe) {
+            // Make sure type = null
+            type = null;
+        }
+
+        String signature = null;
+        if (type != null)
+            signature = ValueUtility.getSignature(field);
+
+        if (signature != null && (signature.equals("Ljava/lang/Object;") ||
+                                  signature.equals("Ljava/io/Serializable;") ||
+                                  signature.equals("Ljava/io/Externalizable;"))) {
+            objectValue = javax.rmi.CORBA.Util.readAny(orbStream);
+        } else {
+            // Decide what method call to make based on the type. If
+            // it is a type for which we need to load a stub, convert
+            // the type to the correct stub type.
+            //
+            // NOTE : Since FullValueDescription does not allow us
+            // to ask whether something is an interface we do not
+            // have the ability to optimize this check.
+
+            int callType = ValueHandlerImpl.kValueType;
+
+            if (!vhandler.isSequence(id)) {
+
+                if (field.type.kind().value() == kRemoteTypeCode.kind().value()) {
+
+                    // RMI Object reference...
+                    callType = ValueHandlerImpl.kRemoteType;
+
+                } else {
+
+                    // REVISIT.  If we don't have the local class,
+                    // we should probably verify that it's an RMI type,
+                    // query the remote FVD, and use is_abstract.
+                    // Our FVD seems to get NullPointerExceptions for any
+                    // non-RMI types.
+
+                    // This uses the local class in the same way as
+                    // inputObjectField(ObjectStreamField) does.  REVISIT
+                    // inputObjectField(ObjectStreamField)'s loadStubClass
+                    // logic.  Assumption is that the given type cannot
+                    // evolve to become a CORBA abstract interface or
+                    // a RMI abstract interface.
+
+                    if (type != null && type.isInterface() &&
+                        (vhandler.isAbstractBase(type) ||
+                         ObjectStreamClassCorbaExt.isAbstractInterface(type))) {
+
+                        callType = ValueHandlerImpl.kAbstractType;
+                    }
+                }
+            }
+
+            // Now that we have used the FVD of the field to determine the proper course
+            // of action, it is ok to use the type (Class) from this point forward since
+            // the rep. id for this read will also follow on the wire.
+
+            switch (callType) {
+                case ValueHandlerImpl.kRemoteType:
+                    if (type != null)
+                        objectValue = Utility.readObjectAndNarrow(orbStream, type);
+                    else
+                        objectValue = orbStream.read_Object();
+                    break;
+                case ValueHandlerImpl.kAbstractType:
+                    if (type != null)
+                        objectValue = Utility.readAbstractAndNarrow(orbStream, type);
+                    else
+                        objectValue = orbStream.read_abstract_interface();
+                    break;
+                case ValueHandlerImpl.kValueType:
+                    if (type != null)
+                        objectValue = orbStream.read_value(type);
+                    else
+                                            objectValue = orbStream.read_value();
+                    break;
+                default:
+                    // XXX I18N, logging needed.
+                    throw new StreamCorruptedException("Unknown callType: " + callType);
+            }
+        }
+
+        return objectValue;
+    }
+
+    /**
+     * Factored out of inputClassFields and reused in
+     * inputCurrentClassFieldsForReadFields.
+     *
+     * Reads the field (which of an Object type as opposed to a primitive)
+     * described by ObjectStreamField field and returns it.
+     */
+    private Object inputObjectField(ObjectStreamField field)
+        throws InvalidClassException, StreamCorruptedException,
+               ClassNotFoundException, IndirectionException, IOException {
+
+        if (ObjectStreamClassCorbaExt.isAny(field.getTypeString())) {
+            return javax.rmi.CORBA.Util.readAny(orbStream);
+        }
+
+        Object objectValue = null;
+
+        // fields have an API to provide the actual class
+        // corresponding to the data type
+        // Class type = osc.forClass();
+        Class fieldType = field.getType();
+        Class actualType = fieldType; // This may change if stub loaded.
+
+        // Decide what method call to make based on the fieldType. If
+        // it is a type for which we need to load a stub, convert
+        // the type to the correct stub type.
+
+        int callType = ValueHandlerImpl.kValueType;
+        boolean narrow = false;
+
+        if (fieldType.isInterface()) {
+            boolean loadStubClass = false;
+
+            if (java.rmi.Remote.class.isAssignableFrom(fieldType)) {
+
+                // RMI Object reference...
+                callType = ValueHandlerImpl.kRemoteType;
+
+            } else if (org.omg.CORBA.Object.class.isAssignableFrom(fieldType)){
+
+                // IDL Object reference...
+                callType = ValueHandlerImpl.kRemoteType;
+                loadStubClass = true;
+
+            } else if (vhandler.isAbstractBase(fieldType)) {
+                // IDL Abstract Object reference...
+
+                callType = ValueHandlerImpl.kAbstractType;
+                loadStubClass = true;
+            } else if (ObjectStreamClassCorbaExt.isAbstractInterface(fieldType)) {
+                // RMI Abstract Object reference...
+
+                callType = ValueHandlerImpl.kAbstractType;
+            }
+
+            if (loadStubClass) {
+                try {
+                    String codebase = Util.getCodebase(fieldType);
+                    String repID = vhandler.createForAnyType(fieldType);
+                    Class stubType =
+                        Utility.loadStubClass(repID, codebase, fieldType);
+                    actualType = stubType;
+                } catch (ClassNotFoundException e) {
+                    narrow = true;
+                }
+            } else {
+                narrow = true;
+            }
+        }
+
+        switch (callType) {
+            case ValueHandlerImpl.kRemoteType:
+                if (!narrow)
+                    objectValue = (Object)orbStream.read_Object(actualType);
+                else
+                    objectValue = Utility.readObjectAndNarrow(orbStream, actualType);
+                break;
+            case ValueHandlerImpl.kAbstractType:
+                if (!narrow)
+                    objectValue = (Object)orbStream.read_abstract_interface(actualType);
+                else
+                    objectValue = Utility.readAbstractAndNarrow(orbStream, actualType);
+                break;
+            case ValueHandlerImpl.kValueType:
+                objectValue = (Object)orbStream.read_value(actualType);
+                break;
+            default:
+                // XXX I18N, logging needed.
+                throw new StreamCorruptedException("Unknown callType: " + callType);
+        }
+
+        return objectValue;
+    }
+
+    private final boolean mustUseRemoteValueMembers() {
+        return defaultReadObjectFVDMembers != null;
+    }
+
+    void readFields(java.util.Map fieldToValueMap)
+        throws InvalidClassException, StreamCorruptedException,
+               ClassNotFoundException, IOException {
+
+        if (mustUseRemoteValueMembers()) {
+            inputRemoteMembersForReadFields(fieldToValueMap);
+        } else
+            inputCurrentClassFieldsForReadFields(fieldToValueMap);
+    }
+
+    private final void inputRemoteMembersForReadFields(java.util.Map fieldToValueMap)
+        throws InvalidClassException, StreamCorruptedException,
+               ClassNotFoundException, IOException {
+
+        // Must have this local variable since defaultReadObjectFVDMembers
+        // may get mangled by recursion.
+        ValueMember fields[] = defaultReadObjectFVDMembers;
+
+        try {
+
+            for (int i = 0; i < fields.length; i++) {
+
+                switch (fields[i].type.kind().value()) {
+
+                case TCKind._tk_octet:
+                    byte byteValue = orbStream.read_octet();
+                    fieldToValueMap.put(fields[i].name, new Byte(byteValue));
+                    break;
+                case TCKind._tk_boolean:
+                    boolean booleanValue = orbStream.read_boolean();
+                    fieldToValueMap.put(fields[i].name, new Boolean(booleanValue));
+                    break;
+                case TCKind._tk_char:
+                    // Backwards compatibility.  Older Sun ORBs sent
+                    // _tk_char even though they read and wrote wchars
+                    // correctly.
+                    //
+                    // Fall through to the _tk_wchar case.
+                case TCKind._tk_wchar:
+                    char charValue = orbStream.read_wchar();
+                    fieldToValueMap.put(fields[i].name, new Character(charValue));
+                    break;
+                case TCKind._tk_short:
+                    short shortValue = orbStream.read_short();
+                    fieldToValueMap.put(fields[i].name, new Short(shortValue));
+                    break;
+                case TCKind._tk_long:
+                    int intValue = orbStream.read_long();
+                    fieldToValueMap.put(fields[i].name, new Integer(intValue));
+                    break;
+                case TCKind._tk_longlong:
+                    long longValue = orbStream.read_longlong();
+                    fieldToValueMap.put(fields[i].name, new Long(longValue));
+                    break;
+                case TCKind._tk_float:
+                    float floatValue = orbStream.read_float();
+                    fieldToValueMap.put(fields[i].name, new Float(floatValue));
+                    break;
+                case TCKind._tk_double:
+                    double doubleValue = orbStream.read_double();
+                    fieldToValueMap.put(fields[i].name, new Double(doubleValue));
+                    break;
+                case TCKind._tk_value:
+                case TCKind._tk_objref:
+                case TCKind._tk_value_box:
+                    Object objectValue = null;
+                    try {
+                        objectValue = inputObjectField(fields[i],
+                                                       cbSender);
+
+                    } catch (IndirectionException cdrie) {
+                        // The CDR stream had never seen the given offset before,
+                        // so check the recursion manager (it will throw an
+                        // IOException if it doesn't have a reference, either).
+                        objectValue = activeRecursionMgr.getObject(cdrie.offset);
+                    }
+
+                    fieldToValueMap.put(fields[i].name, objectValue);
+                    break;
+                default:
+                    // XXX I18N, logging needed.
+                    throw new StreamCorruptedException("Unknown kind: "
+                                                       + fields[i].type.kind().value());
+                }
+            }
+        } catch (Throwable t) {
+            StreamCorruptedException result = new StreamCorruptedException(t.getMessage());
+            result.initCause(t);
+            throw result;
+        }
+    }
+
+    /**
+     * Called from InputStreamHook.
+     *
+     * Reads the fields of the current class (could be the ones
+     * queried from the remote FVD) and puts them in
+     * the given Map, name to value.  Wraps primitives in the
+     * corresponding java.lang Objects.
+     */
+    private final void inputCurrentClassFieldsForReadFields(java.util.Map fieldToValueMap)
+        throws InvalidClassException, StreamCorruptedException,
+               ClassNotFoundException, IOException {
+
+        ObjectStreamField[] fields = currentClassDesc.getFieldsNoCopy();
+
+        int primFields = fields.length - currentClassDesc.objFields;
+
+        // Handle the primitives first
+        for (int i = 0; i < primFields; ++i) {
+
+            switch (fields[i].getTypeCode()) {
+                case 'B':
+                    byte byteValue = orbStream.read_octet();
+                    fieldToValueMap.put(fields[i].getName(),
+                                        new Byte(byteValue));
+                    break;
+                case 'Z':
+                   boolean booleanValue = orbStream.read_boolean();
+                   fieldToValueMap.put(fields[i].getName(),
+                                       new Boolean(booleanValue));
+                   break;
+                case 'C':
+                    char charValue = orbStream.read_wchar();
+                    fieldToValueMap.put(fields[i].getName(),
+                                        new Character(charValue));
+                    break;
+                case 'S':
+                    short shortValue = orbStream.read_short();
+                    fieldToValueMap.put(fields[i].getName(),
+                                        new Short(shortValue));
+                    break;
+                case 'I':
+                    int intValue = orbStream.read_long();
+                    fieldToValueMap.put(fields[i].getName(),
+                                        new Integer(intValue));
+                    break;
+                case 'J':
+                    long longValue = orbStream.read_longlong();
+                    fieldToValueMap.put(fields[i].getName(),
+                                        new Long(longValue));
+                    break;
+                case 'F' :
+                    float floatValue = orbStream.read_float();
+                    fieldToValueMap.put(fields[i].getName(),
+                                        new Float(floatValue));
+                    break;
+                case 'D' :
+                    double doubleValue = orbStream.read_double();
+                    fieldToValueMap.put(fields[i].getName(),
+                                        new Double(doubleValue));
+                    break;
+                default:
+                    // XXX I18N, logging needed.
+                    throw new InvalidClassException(currentClassDesc.getName());
+            }
+        }
+
+        /* Read and set object fields from the input stream. */
+        if (currentClassDesc.objFields > 0) {
+            for (int i = primFields; i < fields.length; i++) {
+                Object objectValue = null;
+                try {
+                    objectValue = inputObjectField(fields[i]);
+                } catch(IndirectionException cdrie) {
+                    // The CDR stream had never seen the given offset before,
+                    // so check the recursion manager (it will throw an
+                    // IOException if it doesn't have a reference, either).
+                    objectValue = activeRecursionMgr.getObject(cdrie.offset);
+                }
+
+                fieldToValueMap.put(fields[i].getName(), objectValue);
+            }
+        }
+    }
+
+    /*
+     * Read the fields of the specified class from the input stream and set
+     * the values of the fields in the specified object. If the specified
+     * object is null, just consume the fields without setting any values. If
+     * any ObjectStreamField does not have a reflected Field, don't try to set
+     * that field in the object.
+     *
+     * REVISIT -- This code doesn't do what the comment says to when
+     * getField() is null!
+     */
+    private void inputClassFields(Object o, Class cl,
+                                  ObjectStreamField[] fields,
+                                  com.sun.org.omg.SendingContext.CodeBase sender)
+        throws InvalidClassException, StreamCorruptedException,
+               ClassNotFoundException, IOException
+    {
+
+        int primFields = fields.length - currentClassDesc.objFields;
+
+        if (o != null) {
+            for (int i = 0; i < primFields; ++i) {
+                if (fields[i].getField() == null)
+                    continue;
+
+                inputPrimitiveField(o, cl, fields[i]);
+            }
+        }
+
+        /* Read and set object fields from the input stream. */
+        if (currentClassDesc.objFields > 0) {
+            for (int i = primFields; i < fields.length; i++) {
+                Object objectValue = null;
+
+                try {
+                    objectValue = inputObjectField(fields[i]);
+                } catch(IndirectionException cdrie) {
+                    // The CDR stream had never seen the given offset before,
+                    // so check the recursion manager (it will throw an
+                    // IOException if it doesn't have a reference, either).
+                    objectValue = activeRecursionMgr.getObject(cdrie.offset);
+                }
+
+                if ((o == null) || (fields[i].getField() == null)) {
+                    continue;
+                }
+
+                try {
+                    bridge.putObject( o, fields[i].getFieldID(), objectValue ) ;
+                    // reflective code: fields[i].getField().set( o, objectValue ) ;
+                } catch (IllegalArgumentException e) {
+                    ClassCastException exc = new ClassCastException("Assigning instance of class " +
+                                                 objectValue.getClass().getName() +
+                                                 " to field " +
+                                                 currentClassDesc.getName() +
+                                                 '#' +
+                                                 fields[i].getField().getName());
+                    exc.initCause( e ) ;
+                    throw exc ;
+                }
+            } // end : for loop
+            }
+        }
+
+    /*
+     * Read the fields of the specified class from the input stream and set
+     * the values of the fields in the specified object. If the specified
+     * object is null, just consume the fields without setting any values. If
+     * any ObjectStreamField does not have a reflected Field, don't try to set
+     * that field in the object.
+     */
+    private void inputClassFields(Object o, Class cl,
+                                  ObjectStreamClass osc,
+                                  ValueMember[] fields,
+                                  com.sun.org.omg.SendingContext.CodeBase sender)
+        throws InvalidClassException, StreamCorruptedException,
+               ClassNotFoundException, IOException
+    {
+        try{
+            for (int i = 0; i < fields.length; ++i) {
+                try {
+                    switch (fields[i].type.kind().value()) {
+                    case TCKind._tk_octet:
+                        byte byteValue = orbStream.read_octet();
+                        if ((o != null) && osc.hasField(fields[i]))
+                        setByteField(o, cl, fields[i].name, byteValue);
+                        break;
+                    case TCKind._tk_boolean:
+                        boolean booleanValue = orbStream.read_boolean();
+                        if ((o != null) && osc.hasField(fields[i]))
+                        setBooleanField(o, cl, fields[i].name, booleanValue);
+                        break;
+                    case TCKind._tk_char:
+                        // Backwards compatibility.  Older Sun ORBs sent
+                        // _tk_char even though they read and wrote wchars
+                        // correctly.
+                        //
+                        // Fall through to the _tk_wchar case.
+                    case TCKind._tk_wchar:
+                        char charValue = orbStream.read_wchar();
+                        if ((o != null) && osc.hasField(fields[i]))
+                        setCharField(o, cl, fields[i].name, charValue);
+                        break;
+                    case TCKind._tk_short:
+                        short shortValue = orbStream.read_short();
+                        if ((o != null) && osc.hasField(fields[i]))
+                        setShortField(o, cl, fields[i].name, shortValue);
+                        break;
+                    case TCKind._tk_long:
+                        int intValue = orbStream.read_long();
+                        if ((o != null) && osc.hasField(fields[i]))
+                        setIntField(o, cl, fields[i].name, intValue);
+                        break;
+                    case TCKind._tk_longlong:
+                        long longValue = orbStream.read_longlong();
+                        if ((o != null) && osc.hasField(fields[i]))
+                        setLongField(o, cl, fields[i].name, longValue);
+                        break;
+                    case TCKind._tk_float:
+                        float floatValue = orbStream.read_float();
+                        if ((o != null) && osc.hasField(fields[i]))
+                        setFloatField(o, cl, fields[i].name, floatValue);
+                        break;
+                    case TCKind._tk_double:
+                        double doubleValue = orbStream.read_double();
+                        if ((o != null) && osc.hasField(fields[i]))
+                        setDoubleField(o, cl, fields[i].name, doubleValue);
+                        break;
+                    case TCKind._tk_value:
+                    case TCKind._tk_objref:
+                    case TCKind._tk_value_box:
+                        Object objectValue = null;
+                        try {
+                            objectValue = inputObjectField(fields[i], sender);
+                        } catch (IndirectionException cdrie) {
+                            // The CDR stream had never seen the given offset before,
+                            // so check the recursion manager (it will throw an
+                            // IOException if it doesn't have a reference, either).
+                            objectValue = activeRecursionMgr.getObject(cdrie.offset);
+                        }
+
+                        if (o == null)
+                            continue;
+                        try {
+                            if (osc.hasField(fields[i])){
+                                setObjectField(o,
+                                               cl,
+                                               fields[i].name,
+                                               objectValue);
+                            } else {
+                                // REVISIT.  Convert to a log message.
+                                // This is a normal case when fields have
+                                // been added as part of evolution, but
+                                // silently skipping can make it hard to
+                                // debug if there's an error
+//                                 System.out.println("**** warning, not setting field: "
+//                                                    + fields[i].name
+//                                                    + " since not on class "
+//                                                    + osc.getName());
+
+                            }
+                        } catch (IllegalArgumentException e) {
+                            // XXX I18N, logging needed.
+                            ClassCastException cce = new ClassCastException("Assigning instance of class " +
+                                objectValue.getClass().getName() + " to field " + fields[i].name);
+                            cce.initCause(e) ;
+                            throw cce ;
+                        }
+                        break;
+                    default:
+                        // XXX I18N, logging needed.
+                        throw new StreamCorruptedException("Unknown kind: "
+                                                           + fields[i].type.kind().value());
+                    }
+                } catch (IllegalArgumentException e) {
+                    /* This case should never happen. If the field types
+                       are not the same, InvalidClassException is raised when
+                       matching the local class to the serialized ObjectStreamClass. */
+                    // XXX I18N, logging needed.
+                    ClassCastException cce = new ClassCastException("Assigning instance of class " + fields[i].id +
+                        " to field " + currentClassDesc.getName() + '#' + fields[i].name);
+                    cce.initCause( e ) ;
+                    throw cce ;
+                }
+            }
+        } catch(Throwable t){
+            // XXX I18N, logging needed.
+            StreamCorruptedException sce = new StreamCorruptedException(t.getMessage());
+            sce.initCause(t) ;
+            throw sce ;
+        }
+    }
+
+    private void skipCustomUsingFVD(ValueMember[] fields,
+                                    com.sun.org.omg.SendingContext.CodeBase sender)
+                                    throws InvalidClassException, StreamCorruptedException,
+                                           ClassNotFoundException, IOException
+    {
+        readFormatVersion();
+        boolean calledDefaultWriteObject = readBoolean();
+
+        if (calledDefaultWriteObject)
+            throwAwayData(fields, sender);
+
+        if (getStreamFormatVersion() == 2) {
+
+            ((ValueInputStream)getOrbStream()).start_value();
+            ((ValueInputStream)getOrbStream()).end_value();
+        }
+    }
+
+    /*
+     * Read the fields of the specified class from the input stream throw data away.
+     * This must handle same switch logic as above.
+     */
+    private void throwAwayData(ValueMember[] fields,
+                               com.sun.org.omg.SendingContext.CodeBase sender)
+        throws InvalidClassException, StreamCorruptedException,
+               ClassNotFoundException, IOException
+    {
+        for (int i = 0; i < fields.length; ++i) {
+
+            try {
+
+                switch (fields[i].type.kind().value()) {
+                case TCKind._tk_octet:
+                    orbStream.read_octet();
+                    break;
+                case TCKind._tk_boolean:
+                    orbStream.read_boolean();
+                    break;
+                case TCKind._tk_char:
+                    // Backwards compatibility.  Older Sun ORBs sent
+                    // _tk_char even though they read and wrote wchars
+                    // correctly.
+                    //
+                    // Fall through to the _tk_wchar case.
+                case TCKind._tk_wchar:
+                    orbStream.read_wchar();
+                    break;
+                case TCKind._tk_short:
+                    orbStream.read_short();
+                    break;
+                case TCKind._tk_long:
+                    orbStream.read_long();
+                    break;
+                case TCKind._tk_longlong:
+                    orbStream.read_longlong();
+                    break;
+                case TCKind._tk_float:
+                    orbStream.read_float();
+                    break;
+                case TCKind._tk_double:
+                    orbStream.read_double();
+                    break;
+                case TCKind._tk_value:
+                case TCKind._tk_objref:
+                case TCKind._tk_value_box:
+                    Class type = null;
+                    String id = fields[i].id;
+
+                    try {
+                        type = vhandler.getClassFromType(id);
+                    }
+                    catch(ClassNotFoundException cnfe){
+                        // Make sure type = null
+                        type = null;
+                    }
+                    String signature = null;
+                    if (type != null)
+                        signature = ValueUtility.getSignature(fields[i]);
+
+                    // Read value
+                    try {
+                        if ((signature != null) && ( signature.equals("Ljava/lang/Object;") ||
+                                                     signature.equals("Ljava/io/Serializable;") ||
+                                                     signature.equals("Ljava/io/Externalizable;")) ) {
+                            javax.rmi.CORBA.Util.readAny(orbStream);
+                        }
+                        else {
+                            // Decide what method call to make based on the type.
+                            //
+                            // NOTE : Since FullValueDescription does not allow us
+                            // to ask whether something is an interface we do not
+                            // have the ability to optimize this check.
+
+                            int callType = ValueHandlerImpl.kValueType;
+
+                            if (!vhandler.isSequence(id)) {
+                                FullValueDescription fieldFVD = sender.meta(fields[i].id);
+                                if (kRemoteTypeCode == fields[i].type) {
+
+                                    // RMI Object reference...
+                                    callType = ValueHandlerImpl.kRemoteType;
+                                } else if (fieldFVD.is_abstract) {
+                                    // RMI Abstract Object reference...
+
+                                    callType = ValueHandlerImpl.kAbstractType;
+                                }
+                            }
+
+                            // Now that we have used the FVD of the field to determine the proper course
+                            // of action, it is ok to use the type (Class) from this point forward since
+                            // the rep. id for this read will also follow on the wire.
+
+                            switch (callType) {
+                            case ValueHandlerImpl.kRemoteType:
+                                orbStream.read_Object();
+                                break;
+                            case ValueHandlerImpl.kAbstractType:
+                                orbStream.read_abstract_interface();
+                                break;
+                            case ValueHandlerImpl.kValueType:
+                                if (type != null) {
+                                    orbStream.read_value(type);
+                                } else {
+                                    orbStream.read_value();
+                                }
+                                break;
+                            default:
+                                // XXX I18N, logging needed.
+                                throw new StreamCorruptedException("Unknown callType: "
+                                                                   + callType);
+                            }
+                        }
+
+                    }
+                    catch(IndirectionException cdrie) {
+                        // Since we are throwing this away, don't bother handling recursion.
+                        continue;
+                    }
+
+                    break;
+                default:
+                    // XXX I18N, logging needed.
+                    throw new StreamCorruptedException("Unknown kind: "
+                                                       + fields[i].type.kind().value());
+
+                }
+            } catch (IllegalArgumentException e) {
+                /* This case should never happen. If the field types
+                   are not the same, InvalidClassException is raised when
+                   matching the local class to the serialized ObjectStreamClass. */
+                // XXX I18N, logging needed.
+                ClassCastException cce = new ClassCastException("Assigning instance of class " +
+                    fields[i].id + " to field " + currentClassDesc.getName() +
+                    '#' + fields[i].name);
+                cce.initCause(e) ;
+                throw cce ;
+            }
+        }
+
+    }
+
+    private static void setObjectField(Object o, Class c, String fieldName, Object v)
+    {
+        try {
+            Field fld = c.getDeclaredField( fieldName ) ;
+            long key = bridge.objectFieldOffset( fld ) ;
+            bridge.putObject( o, key, v ) ;
+        } catch (Exception e) {
+            throw utilWrapper.errorSetObjectField( e, fieldName,
+                o.toString(),
+                v.toString() ) ;
+        }
+    }
+
+    private static void setBooleanField(Object o, Class c, String fieldName, boolean v)
+    {
+        try {
+            Field fld = c.getDeclaredField( fieldName ) ;
+            long key = bridge.objectFieldOffset( fld ) ;
+            bridge.putBoolean( o, key, v ) ;
+        } catch (Exception e) {
+            throw utilWrapper.errorSetBooleanField( e, fieldName,
+                o.toString(),
+                new Boolean(v) ) ;
+        }
+    }
+
+    private static void setByteField(Object o, Class c, String fieldName, byte v)
+    {
+        try {
+            Field fld = c.getDeclaredField( fieldName ) ;
+            long key = bridge.objectFieldOffset( fld ) ;
+            bridge.putByte( o, key, v ) ;
+        } catch (Exception e) {
+            throw utilWrapper.errorSetByteField( e, fieldName,
+                o.toString(),
+                new Byte(v) ) ;
+        }
+    }
+
+    private static void setCharField(Object o, Class c, String fieldName, char v)
+    {
+        try {
+            Field fld = c.getDeclaredField( fieldName ) ;
+            long key = bridge.objectFieldOffset( fld ) ;
+            bridge.putChar( o, key, v ) ;
+        } catch (Exception e) {
+            throw utilWrapper.errorSetCharField( e, fieldName,
+                o.toString(),
+                new Character(v) ) ;
+        }
+    }
+
+    private static void setShortField(Object o, Class c, String fieldName, short v)
+    {
+        try {
+            Field fld = c.getDeclaredField( fieldName ) ;
+            long key = bridge.objectFieldOffset( fld ) ;
+            bridge.putShort( o, key, v ) ;
+        } catch (Exception e) {
+            throw utilWrapper.errorSetShortField( e, fieldName,
+                o.toString(),
+                new Short(v) ) ;
+        }
+    }
+
+    private static void setIntField(Object o, Class c, String fieldName, int v)
+    {
+        try {
+            Field fld = c.getDeclaredField( fieldName ) ;
+            long key = bridge.objectFieldOffset( fld ) ;
+            bridge.putInt( o, key, v ) ;
+        } catch (Exception e) {
+            throw utilWrapper.errorSetIntField( e, fieldName,
+                o.toString(),
+                new Integer(v) ) ;
+        }
+    }
+
+    private static void setLongField(Object o, Class c, String fieldName, long v)
+    {
+        try {
+            Field fld = c.getDeclaredField( fieldName ) ;
+            long key = bridge.objectFieldOffset( fld ) ;
+            bridge.putLong( o, key, v ) ;
+        } catch (Exception e) {
+            throw utilWrapper.errorSetLongField( e, fieldName,
+                o.toString(),
+                new Long(v) ) ;
+        }
+    }
+
+    private static void setFloatField(Object o, Class c, String fieldName, float v)
+    {
+        try {
+            Field fld = c.getDeclaredField( fieldName ) ;
+            long key = bridge.objectFieldOffset( fld ) ;
+            bridge.putFloat( o, key, v ) ;
+        } catch (Exception e) {
+            throw utilWrapper.errorSetFloatField( e, fieldName,
+                o.toString(),
+                new Float(v) ) ;
+        }
+    }
+
+    private static void setDoubleField(Object o, Class c, String fieldName, double v)
+    {
+        try {
+            Field fld = c.getDeclaredField( fieldName ) ;
+            long key = bridge.objectFieldOffset( fld ) ;
+            bridge.putDouble( o, key, v ) ;
+        } catch (Exception e) {
+            throw utilWrapper.errorSetDoubleField( e, fieldName,
+                o.toString(),
+                new Double(v) ) ;
+        }
+    }
+
+    /**
+     * This class maintains a map of stream position to
+     * an Object currently being deserialized.  It is used
+     * to handle the cases where the are indirections to
+     * an object on the recursion stack.  The CDR level
+     * handles indirections to objects previously seen
+     * (and completely deserialized) in the stream.
+     */
+    static class ActiveRecursionManager
+    {
+        private Map offsetToObjectMap;
+
+        public ActiveRecursionManager() {
+            // A hash map is unsynchronized and allows
+            // null values
+            offsetToObjectMap = new HashMap();
+        }
+
+        // Called right after allocating a new object.
+        // Offset is the starting position in the stream
+        // of the object.
+        public void addObject(int offset, Object value) {
+            offsetToObjectMap.put(new Integer(offset), value);
+        }
+
+        // If the given starting position doesn't refer
+        // to the beginning of an object currently being
+        // deserialized, this throws an IOException.
+        // Otherwise, it returns a reference to the
+        // object.
+        public Object getObject(int offset) throws IOException {
+            Integer position = new Integer(offset);
+
+            if (!offsetToObjectMap.containsKey(position))
+                // XXX I18N, logging needed.
+                throw new IOException("Invalid indirection to offset "
+                                      + offset);
+
+            return offsetToObjectMap.get(position);
+        }
+
+        // Called when an object has been completely
+        // deserialized, so it should no longer be in
+        // this mapping.  The CDR level can handle
+        // further indirections.
+        public void removeObject(int offset) {
+            offsetToObjectMap.remove(new Integer(offset));
+        }
+
+        // If the given offset doesn't map to an Object,
+        // then it isn't an indirection to an object
+        // currently being deserialized.
+        public boolean containsObject(int offset) {
+            return offsetToObjectMap.containsKey(new Integer(offset));
+        }
+    }
+}