1 /*
   2  * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 /*
  26  * Licensed Materials - Property of IBM
  27  * RMI-IIOP v1.0
  28  * Copyright IBM Corp. 1998 1999  All Rights Reserved
  29  *
  30  */
  31 
  32 package com.sun.corba.se.impl.io;
  33 
  34 import java.io.InputStream;
  35 import java.io.IOException;
  36 import java.io.StreamCorruptedException;
  37 import java.io.ObjectInputValidation;
  38 import java.io.NotActiveException;
  39 import java.io.InvalidObjectException;
  40 import java.io.InvalidClassException;
  41 import java.io.DataInputStream;
  42 import java.io.OptionalDataException;
  43 import java.io.WriteAbortedException;
  44 import java.io.Externalizable;
  45 import java.io.EOFException;
  46 import java.lang.reflect.*;
  47 import java.util.Vector;
  48 import java.util.Stack;
  49 import java.util.Hashtable;
  50 import java.util.Enumeration;
  51 
  52 import sun.corba.Bridge ;
  53 
  54 import java.security.AccessController ;
  55 import java.security.PrivilegedAction ;
  56 
  57 import com.sun.corba.se.impl.io.ObjectStreamClass;
  58 import com.sun.corba.se.impl.util.Utility;
  59 
  60 import org.omg.CORBA.portable.ValueInputStream;
  61 
  62 import org.omg.CORBA.ValueMember;
  63 import org.omg.CORBA.SystemException;
  64 import org.omg.CORBA.TCKind;
  65 import org.omg.CORBA.ORB;
  66 import org.omg.CORBA.CompletionStatus;
  67 import org.omg.CORBA.portable.IndirectionException;
  68 import org.omg.CORBA.MARSHAL;
  69 import org.omg.CORBA.TypeCode;
  70 
  71 import com.sun.org.omg.CORBA.ValueDefPackage.FullValueDescription;
  72 import com.sun.org.omg.SendingContext.CodeBase;
  73 
  74 import javax.rmi.PortableRemoteObject;
  75 import javax.rmi.CORBA.Util;
  76 import javax.rmi.CORBA.ValueHandler;
  77 
  78 import java.security.*;
  79 import java.util.*;
  80 
  81 import com.sun.corba.se.impl.orbutil.ObjectUtility ;
  82 import com.sun.corba.se.impl.logging.OMGSystemException ;
  83 import com.sun.corba.se.impl.logging.UtilSystemException ;
  84 
  85 import com.sun.corba.se.spi.logging.CORBALogDomains ;
  86 
  87 /**
  88  * IIOPInputStream is used by the ValueHandlerImpl to handle Java serialization
  89  * input semantics.
  90  *
  91  * @author  Stephen Lewallen
  92  * @since   JDK1.1.6
  93  */
  94 
  95 public class IIOPInputStream
  96     extends com.sun.corba.se.impl.io.InputStreamHook
  97 {
  98     private static Bridge bridge =
  99         (Bridge)AccessController.doPrivileged(
 100             new PrivilegedAction() {
 101                 public Object run() {
 102                     return Bridge.get() ;
 103                 }
 104             }
 105         ) ;
 106 
 107     private static OMGSystemException omgWrapper = OMGSystemException.get(
 108         CORBALogDomains.RPC_ENCODING ) ;
 109     private static UtilSystemException utilWrapper = UtilSystemException.get(
 110         CORBALogDomains.RPC_ENCODING ) ;
 111 
 112     // Necessary to pass the appropriate fields into the
 113     // defaultReadObjectDelegate method (which takes no
 114     // parameters since it's called from
 115     // java.io.ObjectInpuStream defaultReadObject()
 116     // which we can't change).
 117     //
 118     // This is only used in the case where the fields had
 119     // to be obtained remotely because of a serializable
 120     // version difference.  Set in inputObjectUsingFVD.
 121     // Part of serialization evolution fixes for Ladybird,
 122     // bug 4365188.
 123     private ValueMember defaultReadObjectFVDMembers[] = null;
 124 
 125     private org.omg.CORBA_2_3.portable.InputStream orbStream;
 126 
 127     private CodeBase cbSender;
 128 
 129     private ValueHandlerImpl vhandler;  //d4365188
 130 
 131     private Object currentObject = null;
 132 
 133     private ObjectStreamClass currentClassDesc = null;
 134 
 135     private Class currentClass = null;
 136 
 137     private int recursionDepth = 0;
 138 
 139     private int simpleReadDepth = 0;
 140 
 141     // The ActiveRecursionManager replaces the old RecursionManager which
 142     // used to record how many recursions were made, and resolve them after
 143     // an object was completely deserialized.
 144     //
 145     // That created problems (as in bug 4414154) because when custom
 146     // unmarshaling in readObject, there can be recursive references
 147     // to one of the objects currently being unmarshaled, and the
 148     // passive recursion system failed.
 149     ActiveRecursionManager activeRecursionMgr = new ActiveRecursionManager();
 150 
 151     private IOException abortIOException = null;
 152 
 153     /* Remember the first exception that stopped this stream. */
 154     private ClassNotFoundException abortClassNotFoundException = null;
 155 
 156     /* Vector of validation callback objects
 157      * The vector is created as needed. The vector is maintained in
 158      * order of highest (first) priority to lowest
 159      */
 160     private Vector callbacks;
 161 
 162     // Serialization machinery fields
 163     /* Arrays used to keep track of classes and ObjectStreamClasses
 164      * as they are being merged; used in inputObject.
 165      * spClass is the stack pointer for both.  */
 166     ObjectStreamClass[] classdesc;
 167     Class[] classes;
 168     int spClass;
 169 
 170     private static final String kEmptyStr = "";
 171 
 172     // TCKind TypeCodes used in FVD inputClassFields
 173     //public static final TypeCode kRemoteTypeCode = new TypeCodeImpl(TCKind._tk_objref);
 174     //public static final TypeCode kValueTypeCode =  new TypeCodeImpl(TCKind._tk_value);
 175     // removed TypeCodeImpl dependency
 176     public static final TypeCode kRemoteTypeCode = ORB.init().get_primitive_tc(TCKind.tk_objref);
 177     public static final TypeCode kValueTypeCode =  ORB.init().get_primitive_tc(TCKind.tk_value);
 178 
 179     // TESTING CODE - useFVDOnly should be made final before FCS in order to
 180     // optimize out the check.
 181     private static final boolean useFVDOnly = false;
 182 
 183     private byte streamFormatVersion;
 184 
 185     // Since java.io.OptionalDataException's constructors are
 186     // package private, but we need to throw it in some special
 187     // cases, we try to do it by reflection.
 188     private static final Constructor OPT_DATA_EXCEPTION_CTOR;
 189 
 190     private Object[] readObjectArgList = { this } ;
 191 
 192     static {
 193         OPT_DATA_EXCEPTION_CTOR = getOptDataExceptionCtor();
 194     }
 195 
 196     // Grab the OptionalDataException boolean ctor and make
 197     // it accessible.  Note that any exceptions
 198     // will be wrapped in ExceptionInInitializerErrors.
 199     private static Constructor getOptDataExceptionCtor() {
 200 
 201         try {
 202 
 203             Constructor result =
 204 
 205                 (Constructor) AccessController.doPrivileged(
 206                                     new PrivilegedExceptionAction() {
 207                     public java.lang.Object run()
 208                         throws NoSuchMethodException,
 209                         SecurityException {
 210 
 211                         Constructor boolCtor
 212                             = OptionalDataException.class.getDeclaredConstructor(
 213                                                                new Class[] {
 214                                 Boolean.TYPE });
 215 
 216                         boolCtor.setAccessible(true);
 217 
 218                         return boolCtor;
 219                     }});
 220 
 221             if (result == null)
 222                 // XXX I18N, logging needed.
 223                 throw new Error("Unable to find OptionalDataException constructor");
 224 
 225             return result;
 226 
 227         } catch (Exception ex) {
 228             // XXX I18N, logging needed.
 229             throw new ExceptionInInitializerError(ex);
 230         }
 231     }
 232 
 233     // Create a new OptionalDataException with the EOF marker
 234     // set to true.  See handleOptionalDataMarshalException.
 235     private OptionalDataException createOptionalDataException() {
 236         try {
 237             OptionalDataException result
 238                 = (OptionalDataException)
 239                    OPT_DATA_EXCEPTION_CTOR.newInstance(new Object[] {
 240                        Boolean.TRUE });
 241 
 242             if (result == null)
 243                 // XXX I18N, logging needed.
 244                 throw new Error("Created null OptionalDataException");
 245 
 246             return result;
 247 
 248         } catch (Exception ex) {
 249             // XXX I18N, logging needed.
 250             throw new Error("Couldn't create OptionalDataException", ex);
 251         }
 252     }
 253 
 254     // Return the stream format version currently being used
 255     // to deserialize an object
 256     protected byte getStreamFormatVersion() {
 257         return streamFormatVersion;
 258     }
 259 
 260     // At the beginning of data sent by a writeObject or
 261     // writeExternal method there is a byte telling the
 262     // reader the stream format version.
 263     private void readFormatVersion() throws IOException {
 264 
 265         streamFormatVersion = orbStream.read_octet();
 266 
 267         if (streamFormatVersion < 1 ||
 268             streamFormatVersion > vhandler.getMaximumStreamFormatVersion()) {
 269             SystemException sysex = omgWrapper.unsupportedFormatVersion(
 270                     CompletionStatus.COMPLETED_MAYBE);
 271             // XXX I18N?  Logging for IOException?
 272             IOException result = new IOException("Unsupported format version: "
 273                                                  + streamFormatVersion);
 274             result.initCause( sysex ) ;
 275             throw result ;
 276         }
 277 
 278         if (streamFormatVersion == 2) {
 279             if (!(orbStream instanceof ValueInputStream)) {
 280                 SystemException sysex = omgWrapper.notAValueinputstream(
 281                     CompletionStatus.COMPLETED_MAYBE);
 282                 // XXX I18N?  Logging for IOException?
 283                 IOException result = new IOException("Not a ValueInputStream");
 284                 result.initCause( sysex ) ;
 285                 throw result;
 286             }
 287         }
 288     }
 289 
 290     public static void setTestFVDFlag(boolean val){
 291         //  useFVDOnly = val;
 292     }
 293 
 294     /**
 295      * Dummy constructor; passes upper stream a dummy stream;
 296      **/
 297     public IIOPInputStream()
 298         throws java.io.IOException {
 299         super();
 300         resetStream();
 301     }
 302 
 303     final void setOrbStream(org.omg.CORBA_2_3.portable.InputStream os) {
 304         orbStream = os;
 305     }
 306 
 307     final org.omg.CORBA_2_3.portable.InputStream getOrbStream() {
 308         return orbStream;
 309     }
 310 
 311     //added setSender and getSender
 312     public final void setSender(CodeBase cb) {
 313         cbSender = cb;
 314     }
 315 
 316     public final CodeBase getSender() {
 317         return cbSender;
 318     }
 319 
 320     // 4365188 this is added to enable backward compatability w/ wrong
 321     // rep-ids
 322     public final void setValueHandler(ValueHandler vh) {
 323         vhandler = (com.sun.corba.se.impl.io.ValueHandlerImpl) vh;
 324     }
 325 
 326     public final ValueHandler getValueHandler() {
 327         return (javax.rmi.CORBA.ValueHandler) vhandler;
 328     }
 329 
 330     final void increaseRecursionDepth(){
 331         recursionDepth++;
 332     }
 333 
 334     final int decreaseRecursionDepth(){
 335         return --recursionDepth;
 336     }
 337 
 338     /**
 339      * Override the actions of the final method "readObject()"
 340      * in ObjectInputStream.
 341      * @since     JDK1.1.6
 342      *
 343      * Read an object from the ObjectInputStream.
 344      * The class of the object, the signature of the class, and the values
 345      * of the non-transient and non-static fields of the class and all
 346      * of its supertypes are read.  Default deserializing for a class can be
 347      * overriden using the writeObject and readObject methods.
 348      * Objects referenced by this object are read transitively so
 349      * that a complete equivalent graph of objects is reconstructed by readObject. <p>
 350      *
 351      * The root object is completly restored when all of its fields
 352      * and the objects it references are completely restored.  At this
 353      * point the object validation callbacks are executed in order
 354      * based on their registered priorities. The callbacks are
 355      * registered by objects (in the readObject special methods)
 356      * as they are individually restored.
 357      *
 358      * Exceptions are thrown for problems with the InputStream and for classes
 359      * that should not be deserialized.  All exceptions are fatal to the
 360      * InputStream and leave it in an indeterminate state; it is up to the caller
 361      * to ignore or recover the stream state.
 362      * @exception java.lang.ClassNotFoundException Class of a serialized object
 363      *      cannot be found.
 364      * @exception InvalidClassException Something is wrong with a class used by
 365      *     serialization.
 366      * @exception StreamCorruptedException Control information in the
 367      *     stream is inconsistent.
 368      * @exception OptionalDataException Primitive data was found in the
 369      * stream instead of objects.
 370      * @exception IOException Any of the usual Input/Output related exceptions.
 371      * @since     JDK1.1
 372      */
 373     public final synchronized Object readObjectDelegate() throws IOException
 374     {
 375         try {
 376 
 377             readObjectState.readData(this);
 378 
 379             return orbStream.read_abstract_interface();
 380         } catch (MARSHAL marshalException) {
 381             handleOptionalDataMarshalException(marshalException, true);
 382             throw marshalException;
 383         } catch(IndirectionException cdrie)
 384             {
 385                 // The CDR stream had never seen the given offset before,
 386                 // so check the recursion manager (it will throw an
 387                 // IOException if it doesn't have a reference, either).
 388                 return activeRecursionMgr.getObject(cdrie.offset);
 389             }
 390     }
 391 
 392     final synchronized Object simpleReadObject(Class clz,
 393                                   String repositoryID,
 394                                   com.sun.org.omg.SendingContext.CodeBase sender,
 395                                   int offset)
 396                                          /* throws OptionalDataException, ClassNotFoundException, IOException */
 397     {
 398 
 399         /* Save the current state and get ready to read an object. */
 400         Object prevObject = currentObject;
 401         ObjectStreamClass prevClassDesc = currentClassDesc;
 402         Class prevClass = currentClass;
 403         byte oldStreamFormatVersion = streamFormatVersion;
 404 
 405         simpleReadDepth++;      // Entering
 406         Object obj = null;
 407 
 408         /*
 409          * Check for reset, handle it before reading an object.
 410          */
 411         try {
 412             // d4365188: backward compatability
 413             if (vhandler.useFullValueDescription(clz, repositoryID)) {
 414                 obj = inputObjectUsingFVD(clz, repositoryID, sender, offset);
 415             } else {
 416                 obj = inputObject(clz, repositoryID, sender, offset);
 417             }
 418 
 419             obj = currentClassDesc.readResolve(obj);
 420         }
 421         catch(ClassNotFoundException cnfe)
 422             {
 423                 bridge.throwException( cnfe ) ;
 424                 return null;
 425             }
 426         catch(IOException ioe)
 427             {
 428                 // System.out.println("CLZ = " + clz + "; " + ioe.toString());
 429                 bridge.throwException(ioe) ;
 430                 return null;
 431             }
 432         finally {
 433             simpleReadDepth --;
 434             currentObject = prevObject;
 435             currentClassDesc = prevClassDesc;
 436             currentClass = prevClass;
 437             streamFormatVersion = oldStreamFormatVersion;
 438         }
 439 
 440 
 441         /* Check for thrown exceptions and re-throw them, clearing them if
 442          * this is the last recursive call .
 443          */
 444         IOException exIOE = abortIOException;
 445         if (simpleReadDepth == 0)
 446             abortIOException = null;
 447         if (exIOE != null){
 448             bridge.throwException( exIOE ) ;
 449             return null;
 450         }
 451 
 452 
 453         ClassNotFoundException exCNF = abortClassNotFoundException;
 454         if (simpleReadDepth == 0)
 455             abortClassNotFoundException = null;
 456         if (exCNF != null) {
 457             bridge.throwException( exCNF ) ;
 458             return null;
 459         }
 460 
 461         return obj;
 462     }
 463 
 464     public final synchronized  void simpleSkipObject(String repositoryID,
 465                                        com.sun.org.omg.SendingContext.CodeBase sender)
 466                                        /* throws OptionalDataException, ClassNotFoundException, IOException */
 467     {
 468 
 469         /* Save the current state and get ready to read an object. */
 470         Object prevObject = currentObject;
 471         ObjectStreamClass prevClassDesc = currentClassDesc;
 472         Class prevClass = currentClass;
 473         byte oldStreamFormatVersion = streamFormatVersion;
 474 
 475         simpleReadDepth++;      // Entering
 476         Object obj = null;
 477 
 478         /*
 479          * Check for reset, handle it before reading an object.
 480          */
 481         try {
 482             skipObjectUsingFVD(repositoryID, sender);
 483         }
 484         catch(ClassNotFoundException cnfe)
 485             {
 486                 bridge.throwException( cnfe ) ;
 487                 return;
 488             }
 489         catch(IOException ioe)
 490             {
 491                 bridge.throwException( ioe ) ;
 492                 return;
 493             }
 494         finally {
 495             simpleReadDepth --;
 496             streamFormatVersion = oldStreamFormatVersion;
 497             currentObject = prevObject;
 498             currentClassDesc = prevClassDesc;
 499             currentClass = prevClass;
 500         }
 501 
 502 
 503         /* Check for thrown exceptions and re-throw them, clearing them if
 504          * this is the last recursive call .
 505          */
 506         IOException exIOE = abortIOException;
 507         if (simpleReadDepth == 0)
 508             abortIOException = null;
 509         if (exIOE != null){
 510             bridge.throwException( exIOE ) ;
 511             return;
 512         }
 513 
 514 
 515         ClassNotFoundException exCNF = abortClassNotFoundException;
 516         if (simpleReadDepth == 0)
 517             abortClassNotFoundException = null;
 518         if (exCNF != null) {
 519             bridge.throwException( exCNF ) ;
 520             return;
 521         }
 522 
 523         return;
 524     }
 525     /////////////////
 526 
 527     /**
 528      * This method is called by trusted subclasses of ObjectOutputStream
 529      * that constructed ObjectOutputStream using the
 530      * protected no-arg constructor. The subclass is expected to provide
 531      * an override method with the modifier "final".
 532      *
 533      * @return the Object read from the stream.
 534      *
 535      * @see #ObjectInputStream()
 536      * @see #readObject
 537      * @since JDK 1.2
 538      */
 539     protected final Object readObjectOverride()
 540         throws OptionalDataException, ClassNotFoundException, IOException
 541     {
 542         return readObjectDelegate();
 543     }
 544 
 545     /**
 546      * Override the actions of the final method "defaultReadObject()"
 547      * in ObjectInputStream.
 548      * @since     JDK1.1.6
 549      *
 550      * Read the non-static and non-transient fields of the current class
 551      * from this stream.  This may only be called from the readObject method
 552      * of the class being deserialized. It will throw the NotActiveException
 553      * if it is called otherwise.
 554      *
 555      * @exception java.lang.ClassNotFoundException if the class of a serialized
 556      *              object could not be found.
 557      * @exception IOException        if an I/O error occurs.
 558      * @exception NotActiveException if the stream is not currently reading
 559      *              objects.
 560      * @since     JDK1.1
 561      */
 562     final synchronized void defaultReadObjectDelegate()
 563     /* throws IOException, ClassNotFoundException, NotActiveException */
 564     {
 565         try {
 566             if (currentObject == null || currentClassDesc == null)
 567                 // XXX I18N, logging needed.
 568                 throw new NotActiveException("defaultReadObjectDelegate");
 569 
 570             // The array will be null unless fields were retrieved
 571             // remotely because of a serializable version difference.
 572             // Bug fix for 4365188.  See the definition of
 573             // defaultReadObjectFVDMembers for more information.
 574             if (defaultReadObjectFVDMembers != null &&
 575                 defaultReadObjectFVDMembers.length > 0) {
 576 
 577                 // WARNING:  Be very careful!  What if some of
 578                 // these fields actually have to do this, too?
 579                 // This works because the defaultReadObjectFVDMembers
 580                 // reference is passed to inputClassFields, but
 581                 // there is no guarantee that
 582                 // defaultReadObjectFVDMembers will point to the
 583                 // same array after calling inputClassFields.
 584 
 585                 // Use the remote fields to unmarshal.
 586                 inputClassFields(currentObject,
 587                                  currentClass,
 588                                  currentClassDesc,
 589                                  defaultReadObjectFVDMembers,
 590                                  cbSender);
 591 
 592             } else {
 593 
 594                 // Use the local fields to unmarshal.
 595                 ObjectStreamField[] fields =
 596                     currentClassDesc.getFieldsNoCopy();
 597                 if (fields.length > 0) {
 598                     inputClassFields(currentObject, currentClass, fields, cbSender);
 599                 }
 600             }
 601         }
 602         catch(NotActiveException nae)
 603             {
 604                 bridge.throwException( nae ) ;
 605             }
 606         catch(IOException ioe)
 607             {
 608                 bridge.throwException( ioe ) ;
 609             }
 610         catch(ClassNotFoundException cnfe)
 611             {
 612                 bridge.throwException( cnfe ) ;
 613             }
 614 
 615     }
 616 
 617     /**
 618      * Override the actions of the final method "enableResolveObject()"
 619      * in ObjectInputStream.
 620      * @since     JDK1.1.6
 621      *
 622      * Enable the stream to allow objects read from the stream to be replaced.
 623      * If the stream is a trusted class it is allowed to enable replacment.
 624      * Trusted classes are those classes with a classLoader equals null. <p>
 625      *
 626      * When enabled the resolveObject method is called for every object
 627      * being deserialized.
 628      *
 629      * @exception SecurityException The classloader of this stream object is non-null.
 630      * @since     JDK1.1
 631      */
 632     public final boolean enableResolveObjectDelegate(boolean enable)
 633     /* throws SecurityException */
 634     {
 635         return false;
 636     }
 637 
 638     // The following three methods allow the implementing orbStream
 639     // to provide mark/reset behavior as defined in java.io.InputStream.
 640 
 641     public final void mark(int readAheadLimit) {
 642         orbStream.mark(readAheadLimit);
 643     }
 644 
 645     public final boolean markSupported() {
 646         return orbStream.markSupported();
 647     }
 648 
 649     public final void reset() throws IOException {
 650         try {
 651             orbStream.reset();
 652         } catch (Error e) {
 653             IOException err = new IOException(e.getMessage());
 654             err.initCause(e) ;
 655             throw err ;
 656         }
 657     }
 658 
 659     public final int available() throws IOException{
 660         return 0; // unreliable
 661     }
 662 
 663     public final void close() throws IOException{
 664         // no op
 665     }
 666 
 667     public final int read() throws IOException{
 668         try{
 669             readObjectState.readData(this);
 670 
 671             return (orbStream.read_octet() << 0) & 0x000000FF;
 672         } catch (MARSHAL marshalException) {
 673             if (marshalException.minor
 674                 == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) {
 675                 setState(IN_READ_OBJECT_NO_MORE_OPT_DATA);
 676                 return -1;
 677             }
 678 
 679             throw marshalException;
 680         } catch(Error e) {
 681             IOException exc = new IOException(e.getMessage());
 682             exc.initCause(e) ;
 683             throw exc ;
 684         }
 685     }
 686 
 687     public final int read(byte data[], int offset, int length) throws IOException{
 688         try{
 689             readObjectState.readData(this);
 690 
 691             orbStream.read_octet_array(data, offset, length);
 692             return length;
 693         } catch (MARSHAL marshalException) {
 694             if (marshalException.minor
 695                 == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) {
 696                 setState(IN_READ_OBJECT_NO_MORE_OPT_DATA);
 697                 return -1;
 698             }
 699 
 700             throw marshalException;
 701         } catch(Error e) {
 702             IOException exc = new IOException(e.getMessage());
 703             exc.initCause(e) ;
 704             throw exc ;
 705         }
 706 
 707     }
 708 
 709     public final boolean readBoolean() throws IOException{
 710         try{
 711             readObjectState.readData(this);
 712 
 713             return orbStream.read_boolean();
 714         } catch (MARSHAL marshalException) {
 715             handleOptionalDataMarshalException(marshalException, false);
 716             throw marshalException;
 717 
 718         } catch(Error e) {
 719             IOException exc = new IOException(e.getMessage());
 720             exc.initCause(e);
 721             throw exc ;
 722         }
 723     }
 724 
 725     public final byte readByte() throws IOException{
 726         try{
 727             readObjectState.readData(this);
 728 
 729             return orbStream.read_octet();
 730         } catch (MARSHAL marshalException) {
 731             handleOptionalDataMarshalException(marshalException, false);
 732             throw marshalException;
 733 
 734         } catch(Error e) {
 735             IOException exc = new IOException(e.getMessage());
 736             exc.initCause(e);
 737             throw exc ;
 738         }
 739     }
 740 
 741     public final char readChar() throws IOException{
 742         try{
 743             readObjectState.readData(this);
 744 
 745             return orbStream.read_wchar();
 746         } catch (MARSHAL marshalException) {
 747             handleOptionalDataMarshalException(marshalException, false);
 748             throw marshalException;
 749 
 750         } catch(Error e) {
 751             IOException exc = new IOException(e.getMessage());
 752             exc.initCause(e);
 753             throw exc ;
 754         }
 755     }
 756 
 757     public final double readDouble() throws IOException{
 758         try{
 759             readObjectState.readData(this);
 760 
 761             return orbStream.read_double();
 762         } catch (MARSHAL marshalException) {
 763             handleOptionalDataMarshalException(marshalException, false);
 764             throw marshalException;
 765         } catch(Error e) {
 766             IOException exc = new IOException(e.getMessage());
 767             exc.initCause(e);
 768             throw exc ;
 769         }
 770     }
 771 
 772     public final float readFloat() throws IOException{
 773         try{
 774             readObjectState.readData(this);
 775 
 776             return orbStream.read_float();
 777         } catch (MARSHAL marshalException) {
 778             handleOptionalDataMarshalException(marshalException, false);
 779             throw marshalException;
 780         } catch(Error e) {
 781             IOException exc = new IOException(e.getMessage());
 782             exc.initCause(e);
 783             throw exc ;
 784         }
 785     }
 786 
 787     public final void readFully(byte data[]) throws IOException{
 788 // d11623 : implement readFully, required for serializing some core classes
 789 
 790         readFully(data, 0, data.length);
 791     }
 792 
 793     public final void readFully(byte data[],  int offset,  int size) throws IOException{
 794 // d11623 : implement readFully, required for serializing some core classes
 795         try{
 796             readObjectState.readData(this);
 797 
 798             orbStream.read_octet_array(data, offset, size);
 799         } catch (MARSHAL marshalException) {
 800             handleOptionalDataMarshalException(marshalException, false);
 801 
 802             throw marshalException;
 803         } catch(Error e) {
 804             IOException exc = new IOException(e.getMessage());
 805             exc.initCause(e);
 806             throw exc ;
 807         }
 808     }
 809 
 810     public final int readInt() throws IOException{
 811         try{
 812             readObjectState.readData(this);
 813 
 814             return orbStream.read_long();
 815         } catch (MARSHAL marshalException) {
 816             handleOptionalDataMarshalException(marshalException, false);
 817             throw marshalException;
 818         } catch(Error e) {
 819             IOException exc = new IOException(e.getMessage());
 820             exc.initCause(e);
 821             throw exc ;
 822         }
 823     }
 824 
 825     public final String readLine() throws IOException{
 826         // XXX I18N, logging needed.
 827         throw new IOException("Method readLine not supported");
 828     }
 829 
 830     public final long readLong() throws IOException{
 831         try{
 832             readObjectState.readData(this);
 833 
 834             return orbStream.read_longlong();
 835         } catch (MARSHAL marshalException) {
 836             handleOptionalDataMarshalException(marshalException, false);
 837             throw marshalException;
 838         } catch(Error e) {
 839             IOException exc = new IOException(e.getMessage());
 840             exc.initCause(e);
 841             throw exc ;
 842         }
 843     }
 844 
 845     public final short readShort() throws IOException{
 846         try{
 847             readObjectState.readData(this);
 848 
 849             return orbStream.read_short();
 850         } catch (MARSHAL marshalException) {
 851             handleOptionalDataMarshalException(marshalException, false);
 852             throw marshalException;
 853         } catch(Error e) {
 854             IOException exc = new IOException(e.getMessage());
 855             exc.initCause(e);
 856             throw exc ;
 857         }
 858     }
 859 
 860     protected final void readStreamHeader() throws IOException, StreamCorruptedException{
 861         // no op
 862     }
 863 
 864     public final int readUnsignedByte() throws IOException{
 865         try{
 866             readObjectState.readData(this);
 867 
 868             return (orbStream.read_octet() << 0) & 0x000000FF;
 869         } catch (MARSHAL marshalException) {
 870             handleOptionalDataMarshalException(marshalException, false);
 871             throw marshalException;
 872         } catch(Error e) {
 873             IOException exc = new IOException(e.getMessage());
 874             exc.initCause(e);
 875             throw exc ;
 876         }
 877     }
 878 
 879     public final int readUnsignedShort() throws IOException{
 880         try{
 881             readObjectState.readData(this);
 882 
 883             return (orbStream.read_ushort() << 0) & 0x0000FFFF;
 884         } catch (MARSHAL marshalException) {
 885             handleOptionalDataMarshalException(marshalException, false);
 886             throw marshalException;
 887         } catch(Error e) {
 888             IOException exc = new IOException(e.getMessage());
 889             exc.initCause(e);
 890             throw exc ;
 891         }
 892     }
 893 
 894     /**
 895      * Helper method for correcting the Kestrel bug 4367783 (dealing
 896      * with larger than 8-bit chars).  The old behavior is preserved
 897      * in orbutil.IIOPInputStream_1_3 in order to interoperate with
 898      * our legacy ORBs.
 899      */
 900     protected String internalReadUTF(org.omg.CORBA.portable.InputStream stream)
 901     {
 902         return stream.read_wstring();
 903     }
 904 
 905     public final String readUTF() throws IOException{
 906         try{
 907             readObjectState.readData(this);
 908 
 909             return internalReadUTF(orbStream);
 910         } catch (MARSHAL marshalException) {
 911             handleOptionalDataMarshalException(marshalException, false);
 912             throw marshalException;
 913         } catch(Error e) {
 914             IOException exc = new IOException(e.getMessage());
 915             exc.initCause(e);
 916             throw exc ;
 917         }
 918     }
 919 
 920     // If the ORB stream detects an incompatibility between what's
 921     // on the wire and what our Serializable's readObject wants,
 922     // it throws a MARSHAL exception with a specific minor code.
 923     // This is rethrown to the readObject as an OptionalDataException.
 924     // So far in RMI-IIOP, this process isn't specific enough to
 925     // tell the readObject how much data is available, so we always
 926     // set the OptionalDataException's EOF marker to true.
 927     private void handleOptionalDataMarshalException(MARSHAL marshalException,
 928                                                     boolean objectRead)
 929         throws IOException {
 930 
 931         // Java Object Serialization spec 3.4: "If the readObject method
 932         // of the class attempts to read more data than is present in the
 933         // optional part of the stream for this class, the stream will
 934         // return -1 for bytewise reads, throw an EOFException for
 935         // primitive data reads, or throw an OptionalDataException
 936         // with the eof field set to true for object reads."
 937         if (marshalException.minor
 938             == OMGSystemException.RMIIIOP_OPTIONAL_DATA_INCOMPATIBLE1) {
 939 
 940             IOException result;
 941 
 942             if (!objectRead)
 943                 result = new EOFException("No more optional data");
 944             else
 945                 result = createOptionalDataException();
 946 
 947             result.initCause(marshalException);
 948 
 949             setState(IN_READ_OBJECT_NO_MORE_OPT_DATA);
 950 
 951             throw result;
 952         }
 953     }
 954 
 955     public final synchronized void registerValidation(ObjectInputValidation obj,
 956                                                       int prio)
 957         throws NotActiveException, InvalidObjectException{
 958         // XXX I18N, logging needed.
 959         throw new Error("Method registerValidation not supported");
 960     }
 961 
 962     protected final Class resolveClass(ObjectStreamClass v)
 963         throws IOException, ClassNotFoundException{
 964         // XXX I18N, logging needed.
 965         throw new IOException("Method resolveClass not supported");
 966     }
 967 
 968     protected final Object resolveObject(Object obj) throws IOException{
 969         // XXX I18N, logging needed.
 970         throw new IOException("Method resolveObject not supported");
 971     }
 972 
 973     public final int skipBytes(int len) throws IOException{
 974         try{
 975             readObjectState.readData(this);
 976 
 977             byte buf[] = new byte[len];
 978             orbStream.read_octet_array(buf, 0, len);
 979             return len;
 980         } catch (MARSHAL marshalException) {
 981             handleOptionalDataMarshalException(marshalException, false);
 982 
 983             throw marshalException;
 984         } catch(Error e) {
 985             IOException exc = new IOException(e.getMessage());
 986             exc.initCause(e) ;
 987             throw exc ;
 988         }
 989     }
 990 
 991     private synchronized Object inputObject(Class clz,
 992                                String repositoryID,
 993                                com.sun.org.omg.SendingContext.CodeBase sender,
 994                                int offset)
 995         throws IOException, ClassNotFoundException
 996     {
 997 
 998         /*
 999          * Get the descriptor and then class of the incoming object.
1000          */
1001 
1002         currentClassDesc = ObjectStreamClass.lookup(clz);
1003         currentClass = currentClassDesc.forClass();
1004         //currentClassDesc.setClass(currentClass);
1005         if (currentClass == null)
1006             // XXX I18N, logging needed.
1007             throw new ClassNotFoundException(currentClassDesc.getName());
1008 
1009         try {
1010             /* If Externalizable,
1011              *  Create an instance and tell it to read its data.
1012              * else,
1013              *  Handle it as a serializable class.
1014              */
1015             if (Enum.class.isAssignableFrom( clz )) {
1016                 int ordinal = orbStream.read_long() ;
1017                 String value = (String)orbStream.read_value( String.class ) ;
1018                 return Enum.valueOf( clz, value ) ;
1019             } else if (currentClassDesc.isExternalizable()) {
1020                 try {
1021                     currentObject = (currentClass == null) ?
1022                         null : currentClassDesc.newInstance();
1023                     if (currentObject != null) {
1024 
1025                         // Store this object and its beginning position
1026                         // since there might be indirections to it while
1027                         // it's been unmarshalled.
1028                         activeRecursionMgr.addObject(offset, currentObject);
1029 
1030                         // Read format version
1031                         readFormatVersion();
1032 
1033                         Externalizable ext = (Externalizable)currentObject;
1034                         ext.readExternal(this);
1035                 }
1036             } catch (InvocationTargetException e) {
1037                 InvalidClassException exc = new InvalidClassException(
1038                     currentClass.getName(),
1039                     "InvocationTargetException accessing no-arg constructor");
1040                 exc.initCause( e ) ;
1041                 throw exc ;
1042             } catch (UnsupportedOperationException e) {
1043                 InvalidClassException exc = new InvalidClassException(
1044                     currentClass.getName(),
1045                     "UnsupportedOperationException accessing no-arg constructor");
1046                 exc.initCause( e ) ;
1047                 throw exc ;
1048             } catch (InstantiationException e) {
1049                 InvalidClassException exc = new InvalidClassException(
1050                     currentClass.getName(),
1051                     "InstantiationException accessing no-arg constructor");
1052                 exc.initCause( e ) ;
1053                 throw exc ;
1054             }
1055         } // end : if (currentClassDesc.isExternalizable())
1056         else {
1057             /* Count number of classes and descriptors we might have
1058              * to work on.
1059              */
1060 
1061             ObjectStreamClass currdesc = currentClassDesc;
1062             Class currclass = currentClass;
1063 
1064             int spBase = spClass;       // current top of stack
1065 
1066             /* The object's classes should be processed from supertype to subtype
1067              * Push all the clases of the current object onto a stack.
1068              * Note that only the serializable classes are represented
1069              * in the descriptor list.
1070              *
1071              * Handle versioning where one or more supertypes of
1072              * have been inserted or removed.  The stack will
1073              * contain pairs of descriptors and the corresponding
1074              * class.  If the object has a class that did not occur in
1075              * the original the descriptor will be null.  If the
1076              * original object had a descriptor for a class not
1077              * present in the local hierarchy of the object the class will be
1078              * null.
1079              *
1080              */
1081 
1082             /*
1083              * This is your basic diff pattern, made simpler
1084              * because reordering is not allowed.
1085              */
1086             // sun.4296963 ibm.11861
1087             // d11861 we should stop when we find the highest serializable class
1088             // We need this so that when we allocate the new object below, we
1089             // can call the constructor of the non-serializable superclass.
1090             // Note that in the JRMP variant of this code the
1091             // ObjectStreamClass.lookup() method handles this, but we've put
1092             // this fix here rather than change lookup because the new behaviour
1093             // is needed in other cases.
1094 
1095             for (currdesc = currentClassDesc, currclass = currentClass;
1096                  currdesc != null && currdesc.isSerializable();   /*sun.4296963 ibm.11861*/
1097                  currdesc = currdesc.getSuperclass()) {
1098 
1099                 /*
1100                  * Search the classes to see if the class of this
1101                  * descriptor appears further up the hierarchy. Until
1102                  * it's found assume its an inserted class.  If it's
1103                  * not found, its the descriptor's class that has been
1104                  * removed.
1105                  */
1106                 Class cc = currdesc.forClass();
1107                 Class cl;
1108                 for (cl = currclass; cl != null; cl = cl.getSuperclass()) {
1109                     if (cc == cl) {
1110                         // found a superclass that matches this descriptor
1111                         break;
1112                     } else {
1113                         /* Ignore a class that doesn't match.  No
1114                          * action is needed since it is already
1115                          * initialized.
1116                          */
1117                     }
1118                 } // end : for (cl = currclass; cl != null; cl = cl.getSuperclass())
1119                 /* Test if there is room for this new entry.
1120                  * If not, double the size of the arrays and copy the contents.
1121                  */
1122                 spClass++;
1123                 if (spClass >= classes.length) {
1124                     int newlen = classes.length * 2;
1125                     Class[] newclasses = new Class[newlen];
1126                     ObjectStreamClass[] newclassdesc = new ObjectStreamClass[newlen];
1127 
1128                     System.arraycopy(classes, 0,
1129                                      newclasses, 0,
1130                                      classes.length);
1131                     System.arraycopy(classdesc, 0,
1132                                      newclassdesc, 0,
1133                                      classes.length);
1134 
1135                     classes = newclasses;
1136                     classdesc = newclassdesc;
1137                 }
1138 
1139                 if (cl == null) {
1140                     /* Class not found corresponding to this descriptor.
1141                      * Pop off all the extra classes pushed.
1142                      * Push the descriptor and a null class.
1143                      */
1144                     classdesc[spClass] = currdesc;
1145                     classes[spClass] = null;
1146                 } else {
1147                     /* Current class descriptor matches current class.
1148                      * Some classes may have been inserted.
1149                      * Record the match and advance the class, continue
1150                      * with the next descriptor.
1151                      */
1152                     classdesc[spClass] = currdesc;
1153                     classes[spClass] = cl;
1154                     currclass = cl.getSuperclass();
1155                 }
1156             } // end : for (currdesc = currentClassDesc, currclass = currentClass;
1157 
1158             /* Allocate a new object.  The object is only constructed
1159              * above the highest serializable class and is set to
1160              * default values for all more specialized classes.
1161              */
1162             try {
1163                 currentObject = (currentClass == null) ?
1164                     null : currentClassDesc.newInstance() ;
1165 
1166                 // Store this object and its beginning position
1167                 // since there might be indirections to it while
1168                 // it's been unmarshalled.
1169                 activeRecursionMgr.addObject(offset, currentObject);
1170             } catch (InvocationTargetException e) {
1171                 InvalidClassException exc = new InvalidClassException(
1172                     currentClass.getName(),
1173                     "InvocationTargetException accessing no-arg constructor");
1174                 exc.initCause( e ) ;
1175                 throw exc ;
1176             } catch (UnsupportedOperationException e) {
1177                 InvalidClassException exc = new InvalidClassException(
1178                     currentClass.getName(),
1179                     "UnsupportedOperationException accessing no-arg constructor");
1180                 exc.initCause( e ) ;
1181                 throw exc ;
1182             } catch (InstantiationException e) {
1183                 InvalidClassException exc = new InvalidClassException(
1184                     currentClass.getName(),
1185                     "InstantiationException accessing no-arg constructor");
1186                 exc.initCause( e ) ;
1187                 throw exc ;
1188             }
1189 
1190             /*
1191              * For all the pushed descriptors and classes.
1192              *  if the class has its own writeObject and readObject methods
1193              *      call the readObject method
1194              *  else
1195              *      invoke the defaultReadObject method
1196              */
1197             try {
1198                 for (spClass = spClass; spClass > spBase; spClass--) {
1199                     /*
1200                      * Set current descriptor and corresponding class
1201                      */
1202                     currentClassDesc = classdesc[spClass];
1203                     currentClass = classes[spClass];
1204                     if (classes[spClass] != null) {
1205                         /* Read the data from the stream described by the
1206                          * descriptor and store into the matching class.
1207                          */
1208 
1209                         ReadObjectState oldState = readObjectState;
1210                         setState(DEFAULT_STATE);
1211 
1212                         try {
1213 
1214                             // Changed since invokeObjectReader no longer does this.
1215                             if (currentClassDesc.hasWriteObject()) {
1216 
1217                                 // Read format version
1218                                 readFormatVersion();
1219 
1220                                 // Read defaultWriteObject indicator
1221                                 boolean calledDefaultWriteObject = readBoolean();
1222 
1223                                 readObjectState.beginUnmarshalCustomValue(this,
1224                                                                           calledDefaultWriteObject,
1225                                                                           (currentClassDesc.readObjectMethod
1226                                                                            != null));
1227                             } else {
1228                                 if (currentClassDesc.hasReadObject())
1229                                     setState(IN_READ_OBJECT_REMOTE_NOT_CUSTOM_MARSHALED);
1230                             }
1231 
1232                             if (!invokeObjectReader(currentClassDesc, currentObject, currentClass) ||
1233                                 readObjectState == IN_READ_OBJECT_DEFAULTS_SENT) {
1234 
1235                                 // Error case of no readObject and didn't call
1236                                 // defaultWriteObject handled in default state
1237 
1238                                 ObjectStreamField[] fields =
1239                                     currentClassDesc.getFieldsNoCopy();
1240                                 if (fields.length > 0) {
1241                                     inputClassFields(currentObject, currentClass, fields, sender);
1242                                 }
1243                             }
1244 
1245                             if (currentClassDesc.hasWriteObject())
1246                                 readObjectState.endUnmarshalCustomValue(this);
1247 
1248                         } finally {
1249                             setState(oldState);
1250                         }
1251 
1252                     } else {
1253 
1254                         // _REVISIT_ : Can we ever get here?
1255                         /* No local class for this descriptor,
1256                          * Skip over the data for this class.
1257                          * like defaultReadObject with a null currentObject.
1258                          * The code will read the values but discard them.
1259                          */
1260                             ObjectStreamField[] fields =
1261                                 currentClassDesc.getFieldsNoCopy();
1262                             if (fields.length > 0) {
1263                                 inputClassFields(null, currentClass, fields, sender);
1264                             }
1265 
1266                         }
1267 
1268                 }
1269             } finally {
1270                                 // Make sure we exit at the same stack level as when we started.
1271                 spClass = spBase;
1272             }
1273         }
1274         } finally {
1275             // We've completed deserializing this object.  Any
1276             // future indirections will be handled correctly at the
1277             // CDR level.  The ActiveRecursionManager only deals with
1278             // objects currently being deserialized.
1279             activeRecursionMgr.removeObject(offset);
1280         }
1281 
1282         return currentObject;
1283     }
1284 
1285     // This retrieves a vector of FVD's for the hierarchy of serializable classes stemming from
1286     // repositoryID.  It is assumed that the sender will not provide base_value id's for non-serializable
1287     // classes!
1288     private Vector getOrderedDescriptions(String repositoryID,
1289                                           com.sun.org.omg.SendingContext.CodeBase sender) {
1290         Vector descs = new Vector();
1291 
1292         if (sender == null) {
1293             return descs;
1294         }
1295 
1296         FullValueDescription aFVD = sender.meta(repositoryID);
1297         while (aFVD != null) {
1298             descs.insertElementAt(aFVD, 0);
1299             if ((aFVD.base_value != null) && !kEmptyStr.equals(aFVD.base_value)) {
1300                 aFVD = sender.meta(aFVD.base_value);
1301             }
1302             else return descs;
1303         }
1304 
1305         return descs;
1306     }
1307 
1308     /**
1309      * This input method uses FullValueDescriptions retrieved from the sender's runtime to
1310      * read in the data.  This method is capable of throwing out data not applicable to client's fields.
1311      * This method handles instances where the reader has a class not sent by the sender, the sender sent
1312      * a class not present on the reader, and/or the reader's class does not match the sender's class.
1313      *
1314      * NOTE : If the local description indicates custom marshaling and the remote type's FVD also
1315      * indicates custom marsahling than the local type is used to read the data off the wire.  However,
1316      * if either says custom while the other does not, a MARSHAL error is thrown.  Externalizable is
1317      * a form of custom marshaling.
1318      *
1319      */
1320     private synchronized Object inputObjectUsingFVD(Class clz,
1321                                        String repositoryID,
1322                                        com.sun.org.omg.SendingContext.CodeBase sender,
1323                                        int offset)
1324         throws IOException, ClassNotFoundException
1325     {
1326         int spBase = spClass;   // current top of stack
1327         try{
1328 
1329             /*
1330              * Get the descriptor and then class of the incoming object.
1331              */
1332 
1333             ObjectStreamClass currdesc = currentClassDesc = ObjectStreamClass.lookup(clz);
1334             Class currclass = currentClass = clz;
1335 
1336             /* If Externalizable,
1337              *  Create an instance and tell it to read its data.
1338              * else,
1339              *  Handle it as a serializable class.
1340              */
1341             if (currentClassDesc.isExternalizable()) {
1342                 try {
1343                     currentObject = (currentClass == null) ?
1344                         null : currentClassDesc.newInstance();
1345                     if (currentObject != null) {
1346                         // Store this object and its beginning position
1347                         // since there might be indirections to it while
1348                         // it's been unmarshalled.
1349                         activeRecursionMgr.addObject(offset, currentObject);
1350 
1351                         // Read format version
1352                         readFormatVersion();
1353 
1354                         Externalizable ext = (Externalizable)currentObject;
1355                         ext.readExternal(this);
1356                     }
1357                 } catch (InvocationTargetException e) {
1358                     InvalidClassException exc = new InvalidClassException(
1359                         currentClass.getName(),
1360                         "InvocationTargetException accessing no-arg constructor");
1361                     exc.initCause( e ) ;
1362                     throw exc ;
1363                 } catch (UnsupportedOperationException e) {
1364                     InvalidClassException exc = new InvalidClassException(
1365                         currentClass.getName(),
1366                         "UnsupportedOperationException accessing no-arg constructor");
1367                     exc.initCause( e ) ;
1368                     throw exc ;
1369                 } catch (InstantiationException e) {
1370                     InvalidClassException exc = new InvalidClassException(
1371                         currentClass.getName(),
1372                         "InstantiationException accessing no-arg constructor");
1373                     exc.initCause( e ) ;
1374                     throw exc ;
1375                 }
1376             } else {
1377                 /*
1378                  * This is your basic diff pattern, made simpler
1379                  * because reordering is not allowed.
1380                  */
1381                 for (currdesc = currentClassDesc, currclass = currentClass;
1382                      currdesc != null && currdesc.isSerializable();   /*sun.4296963 ibm.11861*/
1383 
1384                      currdesc = currdesc.getSuperclass()) {
1385 
1386                     /*
1387                      * Search the classes to see if the class of this
1388                      * descriptor appears further up the hierarchy. Until
1389                      * it's found assume its an inserted class.  If it's
1390                      * not found, its the descriptor's class that has been
1391                      * removed.
1392                      */
1393                     Class cc = currdesc.forClass();
1394                     Class cl;
1395                     for (cl = currclass; cl != null; cl = cl.getSuperclass()) {
1396                         if (cc == cl) {
1397                             // found a superclass that matches this descriptor
1398                             break;
1399                         } else {
1400                             /* Ignore a class that doesn't match.  No
1401                              * action is needed since it is already
1402                              * initialized.
1403                              */
1404                         }
1405                     } // end : for (cl = currclass; cl != null; cl = cl.getSuperclass())
1406                     /* Test if there is room for this new entry.
1407                      * If not, double the size of the arrays and copy the contents.
1408                      */
1409                     spClass++;
1410                     if (spClass >= classes.length) {
1411                         int newlen = classes.length * 2;
1412                         Class[] newclasses = new Class[newlen];
1413                         ObjectStreamClass[] newclassdesc = new ObjectStreamClass[newlen];
1414 
1415                         System.arraycopy(classes, 0,
1416                                          newclasses, 0,
1417                                          classes.length);
1418                         System.arraycopy(classdesc, 0,
1419                                          newclassdesc, 0,
1420                                          classes.length);
1421 
1422                         classes = newclasses;
1423                         classdesc = newclassdesc;
1424                     }
1425 
1426                     if (cl == null) {
1427                         /* Class not found corresponding to this descriptor.
1428                          * Pop off all the extra classes pushed.
1429                          * Push the descriptor and a null class.
1430                          */
1431                         classdesc[spClass] = currdesc;
1432                         classes[spClass] = null;
1433                     } else {
1434                         /* Current class descriptor matches current class.
1435                          * Some classes may have been inserted.
1436                          * Record the match and advance the class, continue
1437                          * with the next descriptor.
1438                          */
1439                         classdesc[spClass] = currdesc;
1440                         classes[spClass] = cl;
1441                         currclass = cl.getSuperclass();
1442                     }
1443                 } // end : for (currdesc = currentClassDesc, currclass = currentClass;
1444 
1445                 /* Allocate a new object.
1446                  */
1447                 try {
1448                     currentObject = (currentClass == null) ?
1449                         null : currentClassDesc.newInstance();
1450 
1451                     // Store this object and its beginning position
1452                     // since there might be indirections to it while
1453                     // it's been unmarshalled.
1454                     activeRecursionMgr.addObject(offset, currentObject);
1455                 } catch (InvocationTargetException e) {
1456                     InvalidClassException exc = new InvalidClassException(
1457                         currentClass.getName(),
1458                         "InvocationTargetException accessing no-arg constructor");
1459                     exc.initCause( e ) ;
1460                     throw exc ;
1461                 } catch (UnsupportedOperationException e) {
1462                     InvalidClassException exc = new InvalidClassException(
1463                         currentClass.getName(),
1464                         "UnsupportedOperationException accessing no-arg constructor");
1465                     exc.initCause( e ) ;
1466                     throw exc ;
1467                 } catch (InstantiationException e) {
1468                     InvalidClassException exc = new InvalidClassException(
1469                         currentClass.getName(),
1470                         "InstantiationException accessing no-arg constructor");
1471                     exc.initCause( e ) ;
1472                     throw exc ;
1473                 }
1474 
1475                 Enumeration fvdsList = getOrderedDescriptions(repositoryID, sender).elements();
1476 
1477                 while((fvdsList.hasMoreElements()) && (spClass > spBase)) {
1478                     FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement();
1479                     // d4365188: backward compatability
1480                     String repIDForFVD = vhandler.getClassName(fvd.id);
1481                     String repIDForClass = vhandler.getClassName(vhandler.getRMIRepositoryID(currentClass));
1482 
1483                     while ((spClass > spBase) &&
1484                            (!repIDForFVD.equals(repIDForClass))) {
1485                         int pos = findNextClass(repIDForFVD, classes, spClass, spBase);
1486                         if (pos != -1) {
1487                             spClass = pos;
1488                             currclass = currentClass = classes[spClass];
1489                             repIDForClass = vhandler.getClassName(vhandler.getRMIRepositoryID(currentClass));
1490                         }
1491                         else { // Read and throw away one level of the fvdslist
1492 
1493                             // This seems to mean that the sender had a superclass that
1494                             // we don't have
1495 
1496                             if (fvd.is_custom) {
1497 
1498                                 readFormatVersion();
1499                                 boolean calledDefaultWriteObject = readBoolean();
1500 
1501                                 if (calledDefaultWriteObject)
1502                                     inputClassFields(null, null, null, fvd.members, sender);
1503 
1504                                 if (getStreamFormatVersion() == 2) {
1505 
1506                                     ((ValueInputStream)getOrbStream()).start_value();
1507                                     ((ValueInputStream)getOrbStream()).end_value();
1508                                 }
1509 
1510                                 // WARNING: If stream format version is 1 and there's
1511                                 // optional data, we'll get some form of exception down
1512                                 // the line or data corruption.
1513 
1514                             } else {
1515 
1516                                 inputClassFields(null, currentClass, null, fvd.members, sender);
1517                             }
1518 
1519                             if (fvdsList.hasMoreElements()){
1520                                 fvd = (FullValueDescription)fvdsList.nextElement();
1521                                 repIDForFVD = vhandler.getClassName(fvd.id);
1522                             }
1523                             else return currentObject;
1524                         }
1525                     }
1526 
1527                     currdesc = currentClassDesc = ObjectStreamClass.lookup(currentClass);
1528 
1529                     if (!repIDForClass.equals("java.lang.Object")) {
1530 
1531                         // If the sender used custom marshaling, then it should have put
1532                         // the two bytes on the wire indicating stream format version
1533                         // and whether or not the writeObject method called
1534                         // defaultWriteObject/writeFields.
1535 
1536                         ReadObjectState oldState = readObjectState;
1537                         setState(DEFAULT_STATE);
1538 
1539                         try {
1540 
1541                             if (fvd.is_custom) {
1542 
1543                                 // Read format version
1544                                 readFormatVersion();
1545 
1546                                 // Read defaultWriteObject indicator
1547                                 boolean calledDefaultWriteObject = readBoolean();
1548 
1549                                 readObjectState.beginUnmarshalCustomValue(this,
1550                                                                           calledDefaultWriteObject,
1551                                                                           (currentClassDesc.readObjectMethod
1552                                                                            != null));
1553                             }
1554 
1555                             boolean usedReadObject = false;
1556 
1557                             // Always use readObject if it exists, and fall back to default
1558                             // unmarshaling if it doesn't.
1559                             try {
1560 
1561                                 if (!fvd.is_custom && currentClassDesc.hasReadObject())
1562                                     setState(IN_READ_OBJECT_REMOTE_NOT_CUSTOM_MARSHALED);
1563 
1564                                 // See the definition of defaultReadObjectFVDMembers
1565                                 // for more information.  This concerns making sure
1566                                 // we use the remote FVD's members in defaultReadObject.
1567                                 defaultReadObjectFVDMembers = fvd.members;
1568                                 usedReadObject = invokeObjectReader(currentClassDesc,
1569                                                                     currentObject,
1570                                                                     currentClass);
1571 
1572                             } finally {
1573                                 defaultReadObjectFVDMembers = null;
1574                             }
1575 
1576                             // Note that the !usedReadObject !calledDefaultWriteObject
1577                             // case is handled by the beginUnmarshalCustomValue method
1578                             // of the default state
1579                             if (!usedReadObject || readObjectState == IN_READ_OBJECT_DEFAULTS_SENT)
1580                                 inputClassFields(currentObject, currentClass, currdesc, fvd.members, sender);
1581 
1582                             if (fvd.is_custom)
1583                                 readObjectState.endUnmarshalCustomValue(this);
1584 
1585                         } finally {
1586                             setState(oldState);
1587                         }
1588 
1589                         currclass = currentClass = classes[--spClass];
1590 
1591                     } else {
1592 
1593                         // The remaining hierarchy of the local class does not match the sender's FVD.
1594                         // So, use remaining FVDs to read data off wire.  If any remaining FVDs indicate
1595                         // custom marshaling, throw MARSHAL error.
1596                         inputClassFields(null, currentClass, null, fvd.members, sender);
1597 
1598                         while (fvdsList.hasMoreElements()){
1599                             fvd = (FullValueDescription)fvdsList.nextElement();
1600 
1601                             if (fvd.is_custom)
1602                                 skipCustomUsingFVD(fvd.members, sender);
1603                             else
1604                                 inputClassFields(null, currentClass, null, fvd.members, sender);
1605                         }
1606 
1607                     }
1608 
1609                 } // end : while(fvdsList.hasMoreElements())
1610                 while (fvdsList.hasMoreElements()){
1611 
1612                     FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement();
1613                     if (fvd.is_custom)
1614                         skipCustomUsingFVD(fvd.members, sender);
1615                     else
1616                         throwAwayData(fvd.members, sender);
1617                 }
1618             }
1619 
1620             return currentObject;
1621         }
1622         finally {
1623                 // Make sure we exit at the same stack level as when we started.
1624                 spClass = spBase;
1625 
1626                 // We've completed deserializing this object.  Any
1627                 // future indirections will be handled correctly at the
1628                 // CDR level.  The ActiveRecursionManager only deals with
1629                 // objects currently being deserialized.
1630                 activeRecursionMgr.removeObject(offset);
1631             }
1632 
1633         }
1634 
1635     /**
1636      * This input method uses FullValueDescriptions retrieved from the sender's runtime to
1637      * read in the data.  This method is capable of throwing out data not applicable to client's fields.
1638      *
1639      * NOTE : If the local description indicates custom marshaling and the remote type's FVD also
1640      * indicates custom marsahling than the local type is used to read the data off the wire.  However,
1641      * if either says custom while the other does not, a MARSHAL error is thrown.  Externalizable is
1642      * a form of custom marshaling.
1643      *
1644      */
1645     private Object skipObjectUsingFVD(String repositoryID,
1646                                       com.sun.org.omg.SendingContext.CodeBase sender)
1647         throws IOException, ClassNotFoundException
1648     {
1649 
1650         Enumeration fvdsList = getOrderedDescriptions(repositoryID, sender).elements();
1651 
1652         while(fvdsList.hasMoreElements()) {
1653             FullValueDescription fvd = (FullValueDescription)fvdsList.nextElement();
1654             String repIDForFVD = vhandler.getClassName(fvd.id);
1655 
1656             if (!repIDForFVD.equals("java.lang.Object")) {
1657                 if (fvd.is_custom) {
1658 
1659                     readFormatVersion();
1660 
1661                     boolean calledDefaultWriteObject = readBoolean();
1662 
1663                     if (calledDefaultWriteObject)
1664                         inputClassFields(null, null, null, fvd.members, sender);
1665 
1666                     if (getStreamFormatVersion() == 2) {
1667 
1668                         ((ValueInputStream)getOrbStream()).start_value();
1669                         ((ValueInputStream)getOrbStream()).end_value();
1670                     }
1671 
1672                     // WARNING: If stream format version is 1 and there's
1673                     // optional data, we'll get some form of exception down
1674                     // the line.
1675 
1676                 } else {
1677                     // Use default marshaling
1678                     inputClassFields(null, null, null, fvd.members, sender);
1679                 }
1680             }
1681 
1682         } // end : while(fvdsList.hasMoreElements())
1683         return null;
1684 
1685     }
1686 
1687     ///////////////////
1688 
1689     private int findNextClass(String classname, Class classes[], int _spClass, int _spBase){
1690 
1691         for (int i = _spClass; i > _spBase; i--){
1692             if (classname.equals(classes[i].getName())) {
1693                 return i;
1694             }
1695         }
1696 
1697         return -1;
1698     }
1699 
1700     /*
1701      * Invoke the readObject method if present.  Assumes that in the case of custom
1702      * marshaling, the format version and defaultWriteObject indicator were already
1703      * removed.
1704      */
1705     private boolean invokeObjectReader(ObjectStreamClass osc, Object obj, Class aclass)
1706         throws InvalidClassException, StreamCorruptedException,
1707                ClassNotFoundException, IOException
1708     {
1709         if (osc.readObjectMethod == null) {
1710             return false;
1711         }
1712 
1713         try {
1714             osc.readObjectMethod.invoke( obj, readObjectArgList ) ;
1715             return true;
1716         } catch (InvocationTargetException e) {
1717             Throwable t = e.getTargetException();
1718             if (t instanceof ClassNotFoundException)
1719                 throw (ClassNotFoundException)t;
1720             else if (t instanceof IOException)
1721                 throw (IOException)t;
1722             else if (t instanceof RuntimeException)
1723                 throw (RuntimeException) t;
1724             else if (t instanceof Error)
1725                 throw (Error) t;
1726             else
1727                 // XXX I18N, logging needed.
1728                 throw new Error("internal error");
1729         } catch (IllegalAccessException e) {
1730             return false;
1731         }
1732     }
1733 
1734     /*
1735      * Reset the stream to be just like it was after the constructor.
1736      */
1737     private void resetStream() throws IOException {
1738 
1739         if (classes == null)
1740             classes = new Class[20];
1741         else {
1742             for (int i = 0; i < classes.length; i++)
1743                 classes[i] = null;
1744         }
1745         if (classdesc == null)
1746             classdesc = new ObjectStreamClass[20];
1747         else {
1748             for (int i = 0; i < classdesc.length; i++)
1749                 classdesc[i] = null;
1750         }
1751         spClass = 0;
1752 
1753         if (callbacks != null)
1754             callbacks.setSize(0);       // discard any pending callbacks
1755     }
1756 
1757     /**
1758      * Factored out of inputClassFields  This reads a primitive value and sets it
1759      * in the field of o described by the ObjectStreamField field.
1760      *
1761      * Note that reflection cannot be used here, because reflection cannot be used
1762      * to set final fields.
1763      */
1764     private void inputPrimitiveField(Object o, Class cl, ObjectStreamField field)
1765         throws InvalidClassException, IOException {
1766 
1767         try {
1768             switch (field.getTypeCode()) {
1769                 case 'B':
1770                     byte byteValue = orbStream.read_octet();
1771                     if (field.getField() != null) {
1772                         bridge.putByte( o, field.getFieldID(), byteValue ) ;
1773                         //reflective code: field.getField().setByte( o, byteValue ) ;
1774                     }
1775                     break;
1776                 case 'Z':
1777                     boolean booleanValue = orbStream.read_boolean();
1778                     if (field.getField() != null) {
1779                         bridge.putBoolean( o, field.getFieldID(), booleanValue ) ;
1780                         //reflective code: field.getField().setBoolean( o, booleanValue ) ;
1781                     }
1782                     break;
1783                 case 'C':
1784                     char charValue = orbStream.read_wchar();
1785                     if (field.getField() != null) {
1786                         bridge.putChar( o, field.getFieldID(), charValue ) ;
1787                         //reflective code: field.getField().setChar( o, charValue ) ;
1788                     }
1789                     break;
1790                 case 'S':
1791                     short shortValue = orbStream.read_short();
1792                     if (field.getField() != null) {
1793                         bridge.putShort( o, field.getFieldID(), shortValue ) ;
1794                         //reflective code: field.getField().setShort( o, shortValue ) ;
1795                     }
1796                     break;
1797                 case 'I':
1798                     int intValue = orbStream.read_long();
1799                     if (field.getField() != null) {
1800                         bridge.putInt( o, field.getFieldID(), intValue ) ;
1801                         //reflective code: field.getField().setInt( o, intValue ) ;
1802                     }
1803                     break;
1804                 case 'J':
1805                     long longValue = orbStream.read_longlong();
1806                     if (field.getField() != null) {
1807                         bridge.putLong( o, field.getFieldID(), longValue ) ;
1808                         //reflective code: field.getField().setLong( o, longValue ) ;
1809                     }
1810                     break;
1811                 case 'F' :
1812                     float floatValue = orbStream.read_float();
1813                     if (field.getField() != null) {
1814                         bridge.putFloat( o, field.getFieldID(), floatValue ) ;
1815                         //reflective code: field.getField().setFloat( o, floatValue ) ;
1816                     }
1817                     break;
1818                 case 'D' :
1819                     double doubleValue = orbStream.read_double();
1820                     if (field.getField() != null) {
1821                         bridge.putDouble( o, field.getFieldID(), doubleValue ) ;
1822                         //reflective code: field.getField().setDouble( o, doubleValue ) ;
1823                     }
1824                     break;
1825                 default:
1826                     // XXX I18N, logging needed.
1827                     throw new InvalidClassException(cl.getName());
1828             }
1829         } catch (IllegalArgumentException e) {
1830             /* This case should never happen. If the field types
1831                are not the same, InvalidClassException is raised when
1832                matching the local class to the serialized ObjectStreamClass. */
1833             ClassCastException cce = new ClassCastException("Assigning instance of class " +
1834                                          field.getType().getName() +
1835                                          " to field " +
1836                                          currentClassDesc.getName() + '#' +
1837                                          field.getField().getName());
1838             cce.initCause( e ) ;
1839             throw cce ;
1840         }
1841      }
1842 
1843     private Object inputObjectField(org.omg.CORBA.ValueMember field,
1844                                     com.sun.org.omg.SendingContext.CodeBase sender)
1845         throws IndirectionException, ClassNotFoundException, IOException,
1846                StreamCorruptedException {
1847 
1848         Object objectValue = null;
1849         Class type = null;
1850         String id = field.id;
1851 
1852         try {
1853             type = vhandler.getClassFromType(id);
1854         } catch(ClassNotFoundException cnfe) {
1855             // Make sure type = null
1856             type = null;
1857         }
1858 
1859         String signature = null;
1860         if (type != null)
1861             signature = ValueUtility.getSignature(field);
1862 
1863         if (signature != null && (signature.equals("Ljava/lang/Object;") ||
1864                                   signature.equals("Ljava/io/Serializable;") ||
1865                                   signature.equals("Ljava/io/Externalizable;"))) {
1866             objectValue = javax.rmi.CORBA.Util.readAny(orbStream);
1867         } else {
1868             // Decide what method call to make based on the type. If
1869             // it is a type for which we need to load a stub, convert
1870             // the type to the correct stub type.
1871             //
1872             // NOTE : Since FullValueDescription does not allow us
1873             // to ask whether something is an interface we do not
1874             // have the ability to optimize this check.
1875 
1876             int callType = ValueHandlerImpl.kValueType;
1877 
1878             if (!vhandler.isSequence(id)) {
1879 
1880                 if (field.type.kind().value() == kRemoteTypeCode.kind().value()) {
1881 
1882                     // RMI Object reference...
1883                     callType = ValueHandlerImpl.kRemoteType;
1884 
1885                 } else {
1886 
1887                     // REVISIT.  If we don't have the local class,
1888                     // we should probably verify that it's an RMI type,
1889                     // query the remote FVD, and use is_abstract.
1890                     // Our FVD seems to get NullPointerExceptions for any
1891                     // non-RMI types.
1892 
1893                     // This uses the local class in the same way as
1894                     // inputObjectField(ObjectStreamField) does.  REVISIT
1895                     // inputObjectField(ObjectStreamField)'s loadStubClass
1896                     // logic.  Assumption is that the given type cannot
1897                     // evolve to become a CORBA abstract interface or
1898                     // a RMI abstract interface.
1899 
1900                     if (type != null && type.isInterface() &&
1901                         (vhandler.isAbstractBase(type) ||
1902                          ObjectStreamClassCorbaExt.isAbstractInterface(type))) {
1903 
1904                         callType = ValueHandlerImpl.kAbstractType;
1905                     }
1906                 }
1907             }
1908 
1909             // Now that we have used the FVD of the field to determine the proper course
1910             // of action, it is ok to use the type (Class) from this point forward since
1911             // the rep. id for this read will also follow on the wire.
1912 
1913             switch (callType) {
1914                 case ValueHandlerImpl.kRemoteType:
1915                     if (type != null)
1916                         objectValue = Utility.readObjectAndNarrow(orbStream, type);
1917                     else
1918                         objectValue = orbStream.read_Object();
1919                     break;
1920                 case ValueHandlerImpl.kAbstractType:
1921                     if (type != null)
1922                         objectValue = Utility.readAbstractAndNarrow(orbStream, type);
1923                     else
1924                         objectValue = orbStream.read_abstract_interface();
1925                     break;
1926                 case ValueHandlerImpl.kValueType:
1927                     if (type != null)
1928                         objectValue = orbStream.read_value(type);
1929                     else
1930                                             objectValue = orbStream.read_value();
1931                     break;
1932                 default:
1933                     // XXX I18N, logging needed.
1934                     throw new StreamCorruptedException("Unknown callType: " + callType);
1935             }
1936         }
1937 
1938         return objectValue;
1939     }
1940 
1941     /**
1942      * Factored out of inputClassFields and reused in
1943      * inputCurrentClassFieldsForReadFields.
1944      *
1945      * Reads the field (which of an Object type as opposed to a primitive)
1946      * described by ObjectStreamField field and returns it.
1947      */
1948     private Object inputObjectField(ObjectStreamField field)
1949         throws InvalidClassException, StreamCorruptedException,
1950                ClassNotFoundException, IndirectionException, IOException {
1951 
1952         if (ObjectStreamClassCorbaExt.isAny(field.getTypeString())) {
1953             return javax.rmi.CORBA.Util.readAny(orbStream);
1954         }
1955 
1956         Object objectValue = null;
1957 
1958         // fields have an API to provide the actual class
1959         // corresponding to the data type
1960         // Class type = osc.forClass();
1961         Class fieldType = field.getType();
1962         Class actualType = fieldType; // This may change if stub loaded.
1963 
1964         // Decide what method call to make based on the fieldType. If
1965         // it is a type for which we need to load a stub, convert
1966         // the type to the correct stub type.
1967 
1968         int callType = ValueHandlerImpl.kValueType;
1969         boolean narrow = false;
1970 
1971         if (fieldType.isInterface()) {
1972             boolean loadStubClass = false;
1973 
1974             if (java.rmi.Remote.class.isAssignableFrom(fieldType)) {
1975 
1976                 // RMI Object reference...
1977                 callType = ValueHandlerImpl.kRemoteType;
1978 
1979             } else if (org.omg.CORBA.Object.class.isAssignableFrom(fieldType)){
1980 
1981                 // IDL Object reference...
1982                 callType = ValueHandlerImpl.kRemoteType;
1983                 loadStubClass = true;
1984 
1985             } else if (vhandler.isAbstractBase(fieldType)) {
1986                 // IDL Abstract Object reference...
1987 
1988                 callType = ValueHandlerImpl.kAbstractType;
1989                 loadStubClass = true;
1990             } else if (ObjectStreamClassCorbaExt.isAbstractInterface(fieldType)) {
1991                 // RMI Abstract Object reference...
1992 
1993                 callType = ValueHandlerImpl.kAbstractType;
1994             }
1995 
1996             if (loadStubClass) {
1997                 try {
1998                     String codebase = Util.getCodebase(fieldType);
1999                     String repID = vhandler.createForAnyType(fieldType);
2000                     Class stubType =
2001                         Utility.loadStubClass(repID, codebase, fieldType);
2002                     actualType = stubType;
2003                 } catch (ClassNotFoundException e) {
2004                     narrow = true;
2005                 }
2006             } else {
2007                 narrow = true;
2008             }
2009         }
2010 
2011         switch (callType) {
2012             case ValueHandlerImpl.kRemoteType:
2013                 if (!narrow)
2014                     objectValue = (Object)orbStream.read_Object(actualType);
2015                 else
2016                     objectValue = Utility.readObjectAndNarrow(orbStream, actualType);
2017                 break;
2018             case ValueHandlerImpl.kAbstractType:
2019                 if (!narrow)
2020                     objectValue = (Object)orbStream.read_abstract_interface(actualType);
2021                 else
2022                     objectValue = Utility.readAbstractAndNarrow(orbStream, actualType);
2023                 break;
2024             case ValueHandlerImpl.kValueType:
2025                 objectValue = (Object)orbStream.read_value(actualType);
2026                 break;
2027             default:
2028                 // XXX I18N, logging needed.
2029                 throw new StreamCorruptedException("Unknown callType: " + callType);
2030         }
2031 
2032         return objectValue;
2033     }
2034 
2035     private final boolean mustUseRemoteValueMembers() {
2036         return defaultReadObjectFVDMembers != null;
2037     }
2038 
2039     void readFields(java.util.Map fieldToValueMap)
2040         throws InvalidClassException, StreamCorruptedException,
2041                ClassNotFoundException, IOException {
2042 
2043         if (mustUseRemoteValueMembers()) {
2044             inputRemoteMembersForReadFields(fieldToValueMap);
2045         } else
2046             inputCurrentClassFieldsForReadFields(fieldToValueMap);
2047     }
2048 
2049     private final void inputRemoteMembersForReadFields(java.util.Map fieldToValueMap)
2050         throws InvalidClassException, StreamCorruptedException,
2051                ClassNotFoundException, IOException {
2052 
2053         // Must have this local variable since defaultReadObjectFVDMembers
2054         // may get mangled by recursion.
2055         ValueMember fields[] = defaultReadObjectFVDMembers;
2056 
2057         try {
2058 
2059             for (int i = 0; i < fields.length; i++) {
2060 
2061                 switch (fields[i].type.kind().value()) {
2062 
2063                 case TCKind._tk_octet:
2064                     byte byteValue = orbStream.read_octet();
2065                     fieldToValueMap.put(fields[i].name, new Byte(byteValue));
2066                     break;
2067                 case TCKind._tk_boolean:
2068                     boolean booleanValue = orbStream.read_boolean();
2069                     fieldToValueMap.put(fields[i].name, booleanValue);
2070                     break;
2071                 case TCKind._tk_char:
2072                     // Backwards compatibility.  Older Sun ORBs sent
2073                     // _tk_char even though they read and wrote wchars
2074                     // correctly.
2075                     //
2076                     // Fall through to the _tk_wchar case.
2077                 case TCKind._tk_wchar:
2078                     char charValue = orbStream.read_wchar();
2079                     fieldToValueMap.put(fields[i].name, new Character(charValue));
2080                     break;
2081                 case TCKind._tk_short:
2082                     short shortValue = orbStream.read_short();
2083                     fieldToValueMap.put(fields[i].name, new Short(shortValue));
2084                     break;
2085                 case TCKind._tk_long:
2086                     int intValue = orbStream.read_long();
2087                     fieldToValueMap.put(fields[i].name, new Integer(intValue));
2088                     break;
2089                 case TCKind._tk_longlong:
2090                     long longValue = orbStream.read_longlong();
2091                     fieldToValueMap.put(fields[i].name, new Long(longValue));
2092                     break;
2093                 case TCKind._tk_float:
2094                     float floatValue = orbStream.read_float();
2095                     fieldToValueMap.put(fields[i].name, new Float(floatValue));
2096                     break;
2097                 case TCKind._tk_double:
2098                     double doubleValue = orbStream.read_double();
2099                     fieldToValueMap.put(fields[i].name, new Double(doubleValue));
2100                     break;
2101                 case TCKind._tk_value:
2102                 case TCKind._tk_objref:
2103                 case TCKind._tk_value_box:
2104                     Object objectValue = null;
2105                     try {
2106                         objectValue = inputObjectField(fields[i],
2107                                                        cbSender);
2108 
2109                     } catch (IndirectionException cdrie) {
2110                         // The CDR stream had never seen the given offset before,
2111                         // so check the recursion manager (it will throw an
2112                         // IOException if it doesn't have a reference, either).
2113                         objectValue = activeRecursionMgr.getObject(cdrie.offset);
2114                     }
2115 
2116                     fieldToValueMap.put(fields[i].name, objectValue);
2117                     break;
2118                 default:
2119                     // XXX I18N, logging needed.
2120                     throw new StreamCorruptedException("Unknown kind: "
2121                                                        + fields[i].type.kind().value());
2122                 }
2123             }
2124         } catch (Throwable t) {
2125             StreamCorruptedException result = new StreamCorruptedException(t.getMessage());
2126             result.initCause(t);
2127             throw result;
2128         }
2129     }
2130 
2131     /**
2132      * Called from InputStreamHook.
2133      *
2134      * Reads the fields of the current class (could be the ones
2135      * queried from the remote FVD) and puts them in
2136      * the given Map, name to value.  Wraps primitives in the
2137      * corresponding java.lang Objects.
2138      */
2139     private final void inputCurrentClassFieldsForReadFields(java.util.Map fieldToValueMap)
2140         throws InvalidClassException, StreamCorruptedException,
2141                ClassNotFoundException, IOException {
2142 
2143         ObjectStreamField[] fields = currentClassDesc.getFieldsNoCopy();
2144 
2145         int primFields = fields.length - currentClassDesc.objFields;
2146 
2147         // Handle the primitives first
2148         for (int i = 0; i < primFields; ++i) {
2149 
2150             switch (fields[i].getTypeCode()) {
2151                 case 'B':
2152                     byte byteValue = orbStream.read_octet();
2153                     fieldToValueMap.put(fields[i].getName(),
2154                                         new Byte(byteValue));
2155                     break;
2156                 case 'Z':
2157                    boolean booleanValue = orbStream.read_boolean();
2158                    fieldToValueMap.put(fields[i].getName(), booleanValue);
2159                    break;
2160                 case 'C':
2161                     char charValue = orbStream.read_wchar();
2162                     fieldToValueMap.put(fields[i].getName(),
2163                                         new Character(charValue));
2164                     break;
2165                 case 'S':
2166                     short shortValue = orbStream.read_short();
2167                     fieldToValueMap.put(fields[i].getName(),
2168                                         new Short(shortValue));
2169                     break;
2170                 case 'I':
2171                     int intValue = orbStream.read_long();
2172                     fieldToValueMap.put(fields[i].getName(),
2173                                         new Integer(intValue));
2174                     break;
2175                 case 'J':
2176                     long longValue = orbStream.read_longlong();
2177                     fieldToValueMap.put(fields[i].getName(),
2178                                         new Long(longValue));
2179                     break;
2180                 case 'F' :
2181                     float floatValue = orbStream.read_float();
2182                     fieldToValueMap.put(fields[i].getName(),
2183                                         new Float(floatValue));
2184                     break;
2185                 case 'D' :
2186                     double doubleValue = orbStream.read_double();
2187                     fieldToValueMap.put(fields[i].getName(),
2188                                         new Double(doubleValue));
2189                     break;
2190                 default:
2191                     // XXX I18N, logging needed.
2192                     throw new InvalidClassException(currentClassDesc.getName());
2193             }
2194         }
2195 
2196         /* Read and set object fields from the input stream. */
2197         if (currentClassDesc.objFields > 0) {
2198             for (int i = primFields; i < fields.length; i++) {
2199                 Object objectValue = null;
2200                 try {
2201                     objectValue = inputObjectField(fields[i]);
2202                 } catch(IndirectionException cdrie) {
2203                     // The CDR stream had never seen the given offset before,
2204                     // so check the recursion manager (it will throw an
2205                     // IOException if it doesn't have a reference, either).
2206                     objectValue = activeRecursionMgr.getObject(cdrie.offset);
2207                 }
2208 
2209                 fieldToValueMap.put(fields[i].getName(), objectValue);
2210             }
2211         }
2212     }
2213 
2214     /*
2215      * Read the fields of the specified class from the input stream and set
2216      * the values of the fields in the specified object. If the specified
2217      * object is null, just consume the fields without setting any values. If
2218      * any ObjectStreamField does not have a reflected Field, don't try to set
2219      * that field in the object.
2220      *
2221      * REVISIT -- This code doesn't do what the comment says to when
2222      * getField() is null!
2223      */
2224     private void inputClassFields(Object o, Class cl,
2225                                   ObjectStreamField[] fields,
2226                                   com.sun.org.omg.SendingContext.CodeBase sender)
2227         throws InvalidClassException, StreamCorruptedException,
2228                ClassNotFoundException, IOException
2229     {
2230 
2231         int primFields = fields.length - currentClassDesc.objFields;
2232 
2233         if (o != null) {
2234             for (int i = 0; i < primFields; ++i) {
2235                 inputPrimitiveField(o, cl, fields[i]);
2236             }
2237         }
2238 
2239         /* Read and set object fields from the input stream. */
2240         if (currentClassDesc.objFields > 0) {
2241             for (int i = primFields; i < fields.length; i++) {
2242                 Object objectValue = null;
2243 
2244                 try {
2245                     objectValue = inputObjectField(fields[i]);
2246                 } catch(IndirectionException cdrie) {
2247                     // The CDR stream had never seen the given offset before,
2248                     // so check the recursion manager (it will throw an
2249                     // IOException if it doesn't have a reference, either).
2250                     objectValue = activeRecursionMgr.getObject(cdrie.offset);
2251                 }
2252 
2253                 if ((o == null) || (fields[i].getField() == null)) {
2254                     continue;
2255                 }
2256 
2257                 try {
2258                     Class fieldCl = fields[i].getClazz();
2259                     if (objectValue != null && !fieldCl.isInstance(objectValue)) {
2260                         throw new IllegalArgumentException();
2261                     }
2262                     bridge.putObject( o, fields[i].getFieldID(), objectValue ) ;
2263                     // reflective code: fields[i].getField().set( o, objectValue ) ;
2264                 } catch (IllegalArgumentException e) {
2265                     ClassCastException exc = new ClassCastException("Assigning instance of class " +
2266                                                  objectValue.getClass().getName() +
2267                                                  " to field " +
2268                                                  currentClassDesc.getName() +
2269                                                  '#' +
2270                                                  fields[i].getField().getName());
2271                     exc.initCause( e ) ;
2272                     throw exc ;
2273                 }
2274             } // end : for loop
2275             }
2276         }
2277 
2278     /*
2279      * Read the fields of the specified class from the input stream and set
2280      * the values of the fields in the specified object. If the specified
2281      * object is null, just consume the fields without setting any values. If
2282      * any ObjectStreamField does not have a reflected Field, don't try to set
2283      * that field in the object.
2284      */
2285     private void inputClassFields(Object o, Class cl,
2286                                   ObjectStreamClass osc,
2287                                   ValueMember[] fields,
2288                                   com.sun.org.omg.SendingContext.CodeBase sender)
2289         throws InvalidClassException, StreamCorruptedException,
2290                ClassNotFoundException, IOException
2291     {
2292         try{
2293             for (int i = 0; i < fields.length; ++i) {
2294                 try {
2295                     switch (fields[i].type.kind().value()) {
2296                     case TCKind._tk_octet:
2297                         byte byteValue = orbStream.read_octet();
2298                         if ((o != null) && osc.hasField(fields[i]))
2299                         setByteField(o, cl, fields[i].name, byteValue);
2300                         break;
2301                     case TCKind._tk_boolean:
2302                         boolean booleanValue = orbStream.read_boolean();
2303                         if ((o != null) && osc.hasField(fields[i]))
2304                         setBooleanField(o, cl, fields[i].name, booleanValue);
2305                         break;
2306                     case TCKind._tk_char:
2307                         // Backwards compatibility.  Older Sun ORBs sent
2308                         // _tk_char even though they read and wrote wchars
2309                         // correctly.
2310                         //
2311                         // Fall through to the _tk_wchar case.
2312                     case TCKind._tk_wchar:
2313                         char charValue = orbStream.read_wchar();
2314                         if ((o != null) && osc.hasField(fields[i]))
2315                         setCharField(o, cl, fields[i].name, charValue);
2316                         break;
2317                     case TCKind._tk_short:
2318                         short shortValue = orbStream.read_short();
2319                         if ((o != null) && osc.hasField(fields[i]))
2320                         setShortField(o, cl, fields[i].name, shortValue);
2321                         break;
2322                     case TCKind._tk_long:
2323                         int intValue = orbStream.read_long();
2324                         if ((o != null) && osc.hasField(fields[i]))
2325                         setIntField(o, cl, fields[i].name, intValue);
2326                         break;
2327                     case TCKind._tk_longlong:
2328                         long longValue = orbStream.read_longlong();
2329                         if ((o != null) && osc.hasField(fields[i]))
2330                         setLongField(o, cl, fields[i].name, longValue);
2331                         break;
2332                     case TCKind._tk_float:
2333                         float floatValue = orbStream.read_float();
2334                         if ((o != null) && osc.hasField(fields[i]))
2335                         setFloatField(o, cl, fields[i].name, floatValue);
2336                         break;
2337                     case TCKind._tk_double:
2338                         double doubleValue = orbStream.read_double();
2339                         if ((o != null) && osc.hasField(fields[i]))
2340                         setDoubleField(o, cl, fields[i].name, doubleValue);
2341                         break;
2342                     case TCKind._tk_value:
2343                     case TCKind._tk_objref:
2344                     case TCKind._tk_value_box:
2345                         Object objectValue = null;
2346                         try {
2347                             objectValue = inputObjectField(fields[i], sender);
2348                         } catch (IndirectionException cdrie) {
2349                             // The CDR stream had never seen the given offset before,
2350                             // so check the recursion manager (it will throw an
2351                             // IOException if it doesn't have a reference, either).
2352                             objectValue = activeRecursionMgr.getObject(cdrie.offset);
2353                         }
2354 
2355                         if (o == null)
2356                             continue;
2357                         try {
2358                             if (osc.hasField(fields[i])){
2359                                 setObjectField(o,
2360                                                cl,
2361                                                fields[i].name,
2362                                                objectValue);
2363                             } else {
2364                                 // REVISIT.  Convert to a log message.
2365                                 // This is a normal case when fields have
2366                                 // been added as part of evolution, but
2367                                 // silently skipping can make it hard to
2368                                 // debug if there's an error
2369 //                                 System.out.println("**** warning, not setting field: "
2370 //                                                    + fields[i].name
2371 //                                                    + " since not on class "
2372 //                                                    + osc.getName());
2373 
2374                             }
2375                         } catch (IllegalArgumentException e) {
2376                             // XXX I18N, logging needed.
2377                             ClassCastException cce = new ClassCastException("Assigning instance of class " +
2378                                 objectValue.getClass().getName() + " to field " + fields[i].name);
2379                             cce.initCause(e) ;
2380                             throw cce ;
2381                         }
2382                         break;
2383                     default:
2384                         // XXX I18N, logging needed.
2385                         throw new StreamCorruptedException("Unknown kind: "
2386                                                            + fields[i].type.kind().value());
2387                     }
2388                 } catch (IllegalArgumentException e) {
2389                     /* This case should never happen. If the field types
2390                        are not the same, InvalidClassException is raised when
2391                        matching the local class to the serialized ObjectStreamClass. */
2392                     // XXX I18N, logging needed.
2393                     ClassCastException cce = new ClassCastException("Assigning instance of class " + fields[i].id +
2394                         " to field " + currentClassDesc.getName() + '#' + fields[i].name);
2395                     cce.initCause( e ) ;
2396                     throw cce ;
2397                 }
2398             }
2399         } catch(Throwable t){
2400             // XXX I18N, logging needed.
2401             StreamCorruptedException sce = new StreamCorruptedException(t.getMessage());
2402             sce.initCause(t) ;
2403             throw sce ;
2404         }
2405     }
2406 
2407     private void skipCustomUsingFVD(ValueMember[] fields,
2408                                     com.sun.org.omg.SendingContext.CodeBase sender)
2409                                     throws InvalidClassException, StreamCorruptedException,
2410                                            ClassNotFoundException, IOException
2411     {
2412         readFormatVersion();
2413         boolean calledDefaultWriteObject = readBoolean();
2414 
2415         if (calledDefaultWriteObject)
2416             throwAwayData(fields, sender);
2417 
2418         if (getStreamFormatVersion() == 2) {
2419 
2420             ((ValueInputStream)getOrbStream()).start_value();
2421             ((ValueInputStream)getOrbStream()).end_value();
2422         }
2423     }
2424 
2425     /*
2426      * Read the fields of the specified class from the input stream throw data away.
2427      * This must handle same switch logic as above.
2428      */
2429     private void throwAwayData(ValueMember[] fields,
2430                                com.sun.org.omg.SendingContext.CodeBase sender)
2431         throws InvalidClassException, StreamCorruptedException,
2432                ClassNotFoundException, IOException {
2433 
2434         for (int i = 0; i < fields.length; ++i) {
2435 
2436             try {
2437 
2438                 switch (fields[i].type.kind().value()) {
2439                 case TCKind._tk_octet:
2440                     orbStream.read_octet();
2441                     break;
2442                 case TCKind._tk_boolean:
2443                     orbStream.read_boolean();
2444                     break;
2445                 case TCKind._tk_char:
2446                     // Backwards compatibility.  Older Sun ORBs sent
2447                     // _tk_char even though they read and wrote wchars
2448                     // correctly.
2449                     //
2450                     // Fall through to the _tk_wchar case.
2451                 case TCKind._tk_wchar:
2452                     orbStream.read_wchar();
2453                     break;
2454                 case TCKind._tk_short:
2455                     orbStream.read_short();
2456                     break;
2457                 case TCKind._tk_long:
2458                     orbStream.read_long();
2459                     break;
2460                 case TCKind._tk_longlong:
2461                     orbStream.read_longlong();
2462                     break;
2463                 case TCKind._tk_float:
2464                     orbStream.read_float();
2465                     break;
2466                 case TCKind._tk_double:
2467                     orbStream.read_double();
2468                     break;
2469                 case TCKind._tk_value:
2470                 case TCKind._tk_objref:
2471                 case TCKind._tk_value_box:
2472                     Class type = null;
2473                     String id = fields[i].id;
2474 
2475                     try {
2476                         type = vhandler.getClassFromType(id);
2477                     }
2478                     catch(ClassNotFoundException cnfe){
2479                         // Make sure type = null
2480                         type = null;
2481                     }
2482                     String signature = null;
2483                     if (type != null)
2484                         signature = ValueUtility.getSignature(fields[i]);
2485 
2486                     // Read value
2487                     try {
2488                         if ((signature != null) && ( signature.equals("Ljava/lang/Object;") ||
2489                                                      signature.equals("Ljava/io/Serializable;") ||
2490                                                      signature.equals("Ljava/io/Externalizable;")) ) {
2491                             javax.rmi.CORBA.Util.readAny(orbStream);
2492                         }
2493                         else {
2494                             // Decide what method call to make based on the type.
2495                             //
2496                             // NOTE : Since FullValueDescription does not allow us
2497                             // to ask whether something is an interface we do not
2498                             // have the ability to optimize this check.
2499 
2500                             int callType = ValueHandlerImpl.kValueType;
2501 
2502                             if (!vhandler.isSequence(id)) {
2503                                 FullValueDescription fieldFVD = sender.meta(fields[i].id);
2504                                 if (kRemoteTypeCode == fields[i].type) {
2505 
2506                                     // RMI Object reference...
2507                                     callType = ValueHandlerImpl.kRemoteType;
2508                                 } else if (fieldFVD.is_abstract) {
2509                                     // RMI Abstract Object reference...
2510 
2511                                     callType = ValueHandlerImpl.kAbstractType;
2512                                 }
2513                             }
2514 
2515                             // Now that we have used the FVD of the field to determine the proper course
2516                             // of action, it is ok to use the type (Class) from this point forward since
2517                             // the rep. id for this read will also follow on the wire.
2518 
2519                             switch (callType) {
2520                             case ValueHandlerImpl.kRemoteType:
2521                                 orbStream.read_Object();
2522                                 break;
2523                             case ValueHandlerImpl.kAbstractType:
2524                                 orbStream.read_abstract_interface();
2525                                 break;
2526                             case ValueHandlerImpl.kValueType:
2527                                 if (type != null) {
2528                                     orbStream.read_value(type);
2529                                 } else {
2530                                     orbStream.read_value();
2531                                 }
2532                                 break;
2533                             default:
2534                                 // XXX I18N, logging needed.
2535                                 throw new StreamCorruptedException("Unknown callType: "
2536                                                                    + callType);
2537                             }
2538                         }
2539 
2540                     }
2541                     catch(IndirectionException cdrie) {
2542                         // Since we are throwing this away, don't bother handling recursion.
2543                         continue;
2544                     }
2545 
2546                     break;
2547                 default:
2548                     // XXX I18N, logging needed.
2549                     throw new StreamCorruptedException("Unknown kind: "
2550                                                        + fields[i].type.kind().value());
2551 
2552                 }
2553             } catch (IllegalArgumentException e) {
2554                 /* This case should never happen. If the field types
2555                    are not the same, InvalidClassException is raised when
2556                    matching the local class to the serialized ObjectStreamClass. */
2557                 // XXX I18N, logging needed.
2558                 ClassCastException cce = new ClassCastException("Assigning instance of class " +
2559                     fields[i].id + " to field " + currentClassDesc.getName() +
2560                     '#' + fields[i].name);
2561                 cce.initCause(e) ;
2562                 throw cce ;
2563             }
2564         }
2565 
2566     }
2567 
2568     private static void setObjectField(Object o, Class c, String fieldName, Object v) {
2569         try {
2570             Field fld = c.getDeclaredField( fieldName ) ;
2571             Class fieldCl = fld.getType();
2572             if(v != null && !fieldCl.isInstance(v)) {
2573                 throw new Exception();
2574             }
2575             long key = bridge.objectFieldOffset( fld ) ;
2576             bridge.putObject( o, key, v ) ;
2577         } catch (Exception e) {
2578             if (o != null) {
2579                 throw utilWrapper.errorSetObjectField( e, fieldName,
2580                     o.toString(),
2581                     v.toString() ) ;
2582             } else {
2583                 throw utilWrapper.errorSetObjectField( e, fieldName,
2584                     "null " + c.getName() + " object",
2585                     v.toString() ) ;
2586             }
2587         }
2588     }
2589 
2590     private static void setBooleanField(Object o, Class c, String fieldName, boolean v)
2591     {
2592         try {
2593             Field fld = c.getDeclaredField( fieldName ) ;
2594             if ((fld != null) && (fld.getType() == Boolean.TYPE)) {
2595                 long key = bridge.objectFieldOffset( fld ) ;
2596                 bridge.putBoolean( o, key, v ) ;
2597             } else {
2598                 throw new InvalidObjectException("Field Type mismatch");
2599             }
2600         } catch (Exception e) {
2601             if (o != null) {
2602             throw utilWrapper.errorSetBooleanField( e, fieldName,
2603                 o.toString(), v);
2604             } else {
2605                 throw utilWrapper.errorSetBooleanField( e, fieldName,
2606                     "null " + c.getName() + " object", v );
2607             }
2608         }
2609     }
2610 
2611     private static void setByteField(Object o, Class c, String fieldName, byte v)
2612     {
2613         try {
2614             Field fld = c.getDeclaredField( fieldName ) ;
2615             if ((fld != null) && (fld.getType() == Byte.TYPE)) {
2616                 long key = bridge.objectFieldOffset( fld ) ;
2617                 bridge.putByte( o, key, v ) ;
2618             } else {
2619                 throw new InvalidObjectException("Field Type mismatch");
2620             }
2621         } catch (Exception e) {
2622             if (o != null) {
2623                 throw utilWrapper.errorSetByteField( e, fieldName,
2624                     o.toString(),
2625                     new Byte(v) ) ;
2626             } else {
2627                 throw utilWrapper.errorSetByteField( e, fieldName,
2628                     "null " + c.getName() + " object",
2629                     new Byte(v) ) ;
2630             }
2631         }
2632     }
2633 
2634     private static void setCharField(Object o, Class c, String fieldName, char v)
2635     {
2636         try {
2637             Field fld = c.getDeclaredField( fieldName ) ;
2638             if ((fld != null) && (fld.getType() == Character.TYPE)) {
2639                 long key = bridge.objectFieldOffset( fld ) ;
2640                 bridge.putChar( o, key, v ) ;
2641             } else {
2642                 throw new InvalidObjectException("Field Type mismatch");
2643             }
2644         } catch (Exception e) {
2645             if (o != null) {
2646                 throw utilWrapper.errorSetCharField( e, fieldName,
2647                     o.toString(),
2648                     new Character(v) ) ;
2649             } else {
2650                 throw utilWrapper.errorSetCharField( e, fieldName,
2651                     "null " + c.getName() + " object",
2652                     new Character(v) ) ;
2653             }
2654         }
2655     }
2656 
2657     private static void setShortField(Object o, Class c, String fieldName, short v)
2658     {
2659         try {
2660             Field fld = c.getDeclaredField( fieldName ) ;
2661             if ((fld != null) && (fld.getType() == Short.TYPE)) {
2662                 long key = bridge.objectFieldOffset( fld ) ;
2663                 bridge.putShort( o, key, v ) ;
2664             } else {
2665                 throw new InvalidObjectException("Field Type mismatch");
2666             }
2667         } catch (Exception e) {
2668             if (o != null) {
2669             throw utilWrapper.errorSetShortField( e, fieldName,
2670                 o.toString(),
2671                 new Short(v) ) ;
2672             } else {
2673                 throw utilWrapper.errorSetShortField( e, fieldName,
2674                     "null " + c.getName() + " object",
2675                     new Short(v) ) ;
2676             }
2677         }
2678     }
2679 
2680     private static void setIntField(Object o, Class c, String fieldName, int v)
2681     {
2682         try {
2683             Field fld = c.getDeclaredField( fieldName ) ;
2684             if ((fld != null) && (fld.getType() == Integer.TYPE)) {
2685                 long key = bridge.objectFieldOffset( fld ) ;
2686                 bridge.putInt( o, key, v ) ;
2687             } else {
2688                 throw new InvalidObjectException("Field Type mismatch");
2689             }
2690         } catch (Exception e) {
2691             if (o != null) {
2692                 throw utilWrapper.errorSetIntField( e, fieldName,
2693                     o.toString(),
2694                     new Integer(v) ) ;
2695             } else {
2696                 throw utilWrapper.errorSetIntField( e, fieldName,
2697                     "null " + c.getName() + " object",
2698                     new Integer(v) ) ;
2699             }
2700         }
2701     }
2702 
2703     private static void setLongField(Object o, Class c, String fieldName, long v)
2704     {
2705         try {
2706             Field fld = c.getDeclaredField( fieldName ) ;
2707             if ((fld != null) && (fld.getType() == Long.TYPE)) {
2708                 long key = bridge.objectFieldOffset( fld ) ;
2709                 bridge.putLong( o, key, v ) ;
2710             } else {
2711                 throw new InvalidObjectException("Field Type mismatch");
2712             }
2713         } catch (Exception e) {
2714             if (o != null) {
2715                 throw utilWrapper.errorSetLongField( e, fieldName,
2716                     o.toString(),
2717                     new Long(v) ) ;
2718             } else {
2719                 throw utilWrapper.errorSetLongField( e, fieldName,
2720                     "null " + c.getName() + " object",
2721                     new Long(v) ) ;
2722             }
2723         }
2724     }
2725 
2726     private static void setFloatField(Object o, Class c, String fieldName, float v)
2727     {
2728         try {
2729             Field fld = c.getDeclaredField( fieldName ) ;
2730             if ((fld != null) && (fld.getType() == Float.TYPE)) {
2731                 long key = bridge.objectFieldOffset( fld ) ;
2732                 bridge.putFloat( o, key, v ) ;
2733             } else {
2734                 throw new InvalidObjectException("Field Type mismatch");
2735             }
2736         } catch (Exception e) {
2737             if (o != null) {
2738                 throw utilWrapper.errorSetFloatField( e, fieldName,
2739                     o.toString(),
2740                     new Float(v) ) ;
2741             } else {
2742                 throw utilWrapper.errorSetFloatField( e, fieldName,
2743                     "null " + c.getName() + " object",
2744                     new Float(v) ) ;
2745             }
2746         }
2747     }
2748 
2749     private static void setDoubleField(Object o, Class c, String fieldName, double v)
2750     {
2751         try {
2752             Field fld = c.getDeclaredField( fieldName ) ;
2753             if ((fld != null) && (fld.getType() == Double.TYPE)) {
2754                 long key = bridge.objectFieldOffset( fld ) ;
2755                 bridge.putDouble( o, key, v ) ;
2756             } else {
2757                 throw new InvalidObjectException("Field Type mismatch");
2758             }
2759         } catch (Exception e) {
2760             if (o != null) {
2761                 throw utilWrapper.errorSetDoubleField( e, fieldName,
2762                     o.toString(),
2763                     new Double(v) ) ;
2764             } else {
2765                 throw utilWrapper.errorSetDoubleField( e, fieldName,
2766                     "null " + c.getName() + " object",
2767                     new Double(v) ) ;
2768             }
2769         }
2770     }
2771 
2772     /**
2773      * This class maintains a map of stream position to
2774      * an Object currently being deserialized.  It is used
2775      * to handle the cases where the are indirections to
2776      * an object on the recursion stack.  The CDR level
2777      * handles indirections to objects previously seen
2778      * (and completely deserialized) in the stream.
2779      */
2780     static class ActiveRecursionManager
2781     {
2782         private Map offsetToObjectMap;
2783 
2784         public ActiveRecursionManager() {
2785             // A hash map is unsynchronized and allows
2786             // null values
2787             offsetToObjectMap = new HashMap();
2788         }
2789 
2790         // Called right after allocating a new object.
2791         // Offset is the starting position in the stream
2792         // of the object.
2793         public void addObject(int offset, Object value) {
2794             offsetToObjectMap.put(new Integer(offset), value);
2795         }
2796 
2797         // If the given starting position doesn't refer
2798         // to the beginning of an object currently being
2799         // deserialized, this throws an IOException.
2800         // Otherwise, it returns a reference to the
2801         // object.
2802         public Object getObject(int offset) throws IOException {
2803             Integer position = new Integer(offset);
2804 
2805             if (!offsetToObjectMap.containsKey(position))
2806                 // XXX I18N, logging needed.
2807                 throw new IOException("Invalid indirection to offset "
2808                                       + offset);
2809 
2810             return offsetToObjectMap.get(position);
2811         }
2812 
2813         // Called when an object has been completely
2814         // deserialized, so it should no longer be in
2815         // this mapping.  The CDR level can handle
2816         // further indirections.
2817         public void removeObject(int offset) {
2818             offsetToObjectMap.remove(new Integer(offset));
2819         }
2820 
2821         // If the given offset doesn't map to an Object,
2822         // then it isn't an indirection to an object
2823         // currently being deserialized.
2824         public boolean containsObject(int offset) {
2825             return offsetToObjectMap.containsKey(new Integer(offset));
2826         }
2827     }
2828 }