IIOPInputStream.java revision 608:7e06bf1dcb09
1/*
2 * Copyright (c) 1998, 2013, 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
32package com.sun.corba.se.impl.io;
33
34import java.io.InputStream;
35import java.io.IOException;
36import java.io.StreamCorruptedException;
37import java.io.ObjectInputValidation;
38import java.io.NotActiveException;
39import java.io.InvalidObjectException;
40import java.io.InvalidClassException;
41import java.io.DataInputStream;
42import java.io.OptionalDataException;
43import java.io.WriteAbortedException;
44import java.io.Externalizable;
45import java.io.EOFException;
46import java.lang.reflect.*;
47import java.util.Vector;
48import java.util.Stack;
49import java.util.Hashtable;
50import java.util.Enumeration;
51
52import sun.corba.Bridge ;
53
54import java.security.AccessController ;
55import java.security.PrivilegedAction ;
56
57import com.sun.corba.se.impl.io.ObjectStreamClass;
58import com.sun.corba.se.impl.util.Utility;
59
60import org.omg.CORBA.portable.ValueInputStream;
61
62import org.omg.CORBA.ValueMember;
63import org.omg.CORBA.SystemException;
64import org.omg.CORBA.TCKind;
65import org.omg.CORBA.ORB;
66import org.omg.CORBA.CompletionStatus;
67import org.omg.CORBA.portable.IndirectionException;
68import org.omg.CORBA.MARSHAL;
69import org.omg.CORBA.TypeCode;
70
71import com.sun.org.omg.CORBA.ValueDefPackage.FullValueDescription;
72import com.sun.org.omg.SendingContext.CodeBase;
73
74import javax.rmi.PortableRemoteObject;
75import javax.rmi.CORBA.Util;
76import javax.rmi.CORBA.ValueHandler;
77
78import java.security.*;
79import java.util.*;
80
81import com.sun.corba.se.impl.orbutil.ObjectUtility ;
82import com.sun.corba.se.impl.logging.OMGSystemException ;
83import com.sun.corba.se.impl.logging.UtilSystemException ;
84
85import 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
95public 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                    bridge.putByte( o, field.getFieldID(), byteValue ) ;
1772                    //reflective code: field.getField().setByte( o, byteValue ) ;
1773                    break;
1774                case 'Z':
1775                    boolean booleanValue = orbStream.read_boolean();
1776                    bridge.putBoolean( o, field.getFieldID(), booleanValue ) ;
1777                    //reflective code: field.getField().setBoolean( o, booleanValue ) ;
1778                    break;
1779                case 'C':
1780                    char charValue = orbStream.read_wchar();
1781                    bridge.putChar( o, field.getFieldID(), charValue ) ;
1782                    //reflective code: field.getField().setChar( o, charValue ) ;
1783                    break;
1784                case 'S':
1785                    short shortValue = orbStream.read_short();
1786                    bridge.putShort( o, field.getFieldID(), shortValue ) ;
1787                    //reflective code: field.getField().setShort( o, shortValue ) ;
1788                    break;
1789                case 'I':
1790                    int intValue = orbStream.read_long();
1791                    bridge.putInt( o, field.getFieldID(), intValue ) ;
1792                    //reflective code: field.getField().setInt( o, intValue ) ;
1793                    break;
1794                case 'J':
1795                    long longValue = orbStream.read_longlong();
1796                    bridge.putLong( o, field.getFieldID(), longValue ) ;
1797                    //reflective code: field.getField().setLong( o, longValue ) ;
1798                    break;
1799                case 'F' :
1800                    float floatValue = orbStream.read_float();
1801                    bridge.putFloat( o, field.getFieldID(), floatValue ) ;
1802                    //reflective code: field.getField().setFloat( o, floatValue ) ;
1803                    break;
1804                case 'D' :
1805                    double doubleValue = orbStream.read_double();
1806                    bridge.putDouble( o, field.getFieldID(), doubleValue ) ;
1807                    //reflective code: field.getField().setDouble( o, doubleValue ) ;
1808                    break;
1809                default:
1810                    // XXX I18N, logging needed.
1811                    throw new InvalidClassException(cl.getName());
1812            }
1813        } catch (IllegalArgumentException e) {
1814            /* This case should never happen. If the field types
1815               are not the same, InvalidClassException is raised when
1816               matching the local class to the serialized ObjectStreamClass. */
1817            ClassCastException cce = new ClassCastException("Assigning instance of class " +
1818                                         field.getType().getName() +
1819                                         " to field " +
1820                                         currentClassDesc.getName() + '#' +
1821                                         field.getField().getName());
1822            cce.initCause( e ) ;
1823            throw cce ;
1824        }
1825     }
1826
1827    private Object inputObjectField(org.omg.CORBA.ValueMember field,
1828                                    com.sun.org.omg.SendingContext.CodeBase sender)
1829        throws IndirectionException, ClassNotFoundException, IOException,
1830               StreamCorruptedException {
1831
1832        Object objectValue = null;
1833        Class type = null;
1834        String id = field.id;
1835
1836        try {
1837            type = vhandler.getClassFromType(id);
1838        } catch(ClassNotFoundException cnfe) {
1839            // Make sure type = null
1840            type = null;
1841        }
1842
1843        String signature = null;
1844        if (type != null)
1845            signature = ValueUtility.getSignature(field);
1846
1847        if (signature != null && (signature.equals("Ljava/lang/Object;") ||
1848                                  signature.equals("Ljava/io/Serializable;") ||
1849                                  signature.equals("Ljava/io/Externalizable;"))) {
1850            objectValue = javax.rmi.CORBA.Util.readAny(orbStream);
1851        } else {
1852            // Decide what method call to make based on the type. If
1853            // it is a type for which we need to load a stub, convert
1854            // the type to the correct stub type.
1855            //
1856            // NOTE : Since FullValueDescription does not allow us
1857            // to ask whether something is an interface we do not
1858            // have the ability to optimize this check.
1859
1860            int callType = ValueHandlerImpl.kValueType;
1861
1862            if (!vhandler.isSequence(id)) {
1863
1864                if (field.type.kind().value() == kRemoteTypeCode.kind().value()) {
1865
1866                    // RMI Object reference...
1867                    callType = ValueHandlerImpl.kRemoteType;
1868
1869                } else {
1870
1871                    // REVISIT.  If we don't have the local class,
1872                    // we should probably verify that it's an RMI type,
1873                    // query the remote FVD, and use is_abstract.
1874                    // Our FVD seems to get NullPointerExceptions for any
1875                    // non-RMI types.
1876
1877                    // This uses the local class in the same way as
1878                    // inputObjectField(ObjectStreamField) does.  REVISIT
1879                    // inputObjectField(ObjectStreamField)'s loadStubClass
1880                    // logic.  Assumption is that the given type cannot
1881                    // evolve to become a CORBA abstract interface or
1882                    // a RMI abstract interface.
1883
1884                    if (type != null && type.isInterface() &&
1885                        (vhandler.isAbstractBase(type) ||
1886                         ObjectStreamClassCorbaExt.isAbstractInterface(type))) {
1887
1888                        callType = ValueHandlerImpl.kAbstractType;
1889                    }
1890                }
1891            }
1892
1893            // Now that we have used the FVD of the field to determine the proper course
1894            // of action, it is ok to use the type (Class) from this point forward since
1895            // the rep. id for this read will also follow on the wire.
1896
1897            switch (callType) {
1898                case ValueHandlerImpl.kRemoteType:
1899                    if (type != null)
1900                        objectValue = Utility.readObjectAndNarrow(orbStream, type);
1901                    else
1902                        objectValue = orbStream.read_Object();
1903                    break;
1904                case ValueHandlerImpl.kAbstractType:
1905                    if (type != null)
1906                        objectValue = Utility.readAbstractAndNarrow(orbStream, type);
1907                    else
1908                        objectValue = orbStream.read_abstract_interface();
1909                    break;
1910                case ValueHandlerImpl.kValueType:
1911                    if (type != null)
1912                        objectValue = orbStream.read_value(type);
1913                    else
1914                                            objectValue = orbStream.read_value();
1915                    break;
1916                default:
1917                    // XXX I18N, logging needed.
1918                    throw new StreamCorruptedException("Unknown callType: " + callType);
1919            }
1920        }
1921
1922        return objectValue;
1923    }
1924
1925    /**
1926     * Factored out of inputClassFields and reused in
1927     * inputCurrentClassFieldsForReadFields.
1928     *
1929     * Reads the field (which of an Object type as opposed to a primitive)
1930     * described by ObjectStreamField field and returns it.
1931     */
1932    private Object inputObjectField(ObjectStreamField field)
1933        throws InvalidClassException, StreamCorruptedException,
1934               ClassNotFoundException, IndirectionException, IOException {
1935
1936        if (ObjectStreamClassCorbaExt.isAny(field.getTypeString())) {
1937            return javax.rmi.CORBA.Util.readAny(orbStream);
1938        }
1939
1940        Object objectValue = null;
1941
1942        // fields have an API to provide the actual class
1943        // corresponding to the data type
1944        // Class type = osc.forClass();
1945        Class fieldType = field.getType();
1946        Class actualType = fieldType; // This may change if stub loaded.
1947
1948        // Decide what method call to make based on the fieldType. If
1949        // it is a type for which we need to load a stub, convert
1950        // the type to the correct stub type.
1951
1952        int callType = ValueHandlerImpl.kValueType;
1953        boolean narrow = false;
1954
1955        if (fieldType.isInterface()) {
1956            boolean loadStubClass = false;
1957
1958            if (java.rmi.Remote.class.isAssignableFrom(fieldType)) {
1959
1960                // RMI Object reference...
1961                callType = ValueHandlerImpl.kRemoteType;
1962
1963            } else if (org.omg.CORBA.Object.class.isAssignableFrom(fieldType)){
1964
1965                // IDL Object reference...
1966                callType = ValueHandlerImpl.kRemoteType;
1967                loadStubClass = true;
1968
1969            } else if (vhandler.isAbstractBase(fieldType)) {
1970                // IDL Abstract Object reference...
1971
1972                callType = ValueHandlerImpl.kAbstractType;
1973                loadStubClass = true;
1974            } else if (ObjectStreamClassCorbaExt.isAbstractInterface(fieldType)) {
1975                // RMI Abstract Object reference...
1976
1977                callType = ValueHandlerImpl.kAbstractType;
1978            }
1979
1980            if (loadStubClass) {
1981                try {
1982                    String codebase = Util.getCodebase(fieldType);
1983                    String repID = vhandler.createForAnyType(fieldType);
1984                    Class stubType =
1985                        Utility.loadStubClass(repID, codebase, fieldType);
1986                    actualType = stubType;
1987                } catch (ClassNotFoundException e) {
1988                    narrow = true;
1989                }
1990            } else {
1991                narrow = true;
1992            }
1993        }
1994
1995        switch (callType) {
1996            case ValueHandlerImpl.kRemoteType:
1997                if (!narrow)
1998                    objectValue = (Object)orbStream.read_Object(actualType);
1999                else
2000                    objectValue = Utility.readObjectAndNarrow(orbStream, actualType);
2001                break;
2002            case ValueHandlerImpl.kAbstractType:
2003                if (!narrow)
2004                    objectValue = (Object)orbStream.read_abstract_interface(actualType);
2005                else
2006                    objectValue = Utility.readAbstractAndNarrow(orbStream, actualType);
2007                break;
2008            case ValueHandlerImpl.kValueType:
2009                objectValue = (Object)orbStream.read_value(actualType);
2010                break;
2011            default:
2012                // XXX I18N, logging needed.
2013                throw new StreamCorruptedException("Unknown callType: " + callType);
2014        }
2015
2016        return objectValue;
2017    }
2018
2019    private final boolean mustUseRemoteValueMembers() {
2020        return defaultReadObjectFVDMembers != null;
2021    }
2022
2023    void readFields(java.util.Map fieldToValueMap)
2024        throws InvalidClassException, StreamCorruptedException,
2025               ClassNotFoundException, IOException {
2026
2027        if (mustUseRemoteValueMembers()) {
2028            inputRemoteMembersForReadFields(fieldToValueMap);
2029        } else
2030            inputCurrentClassFieldsForReadFields(fieldToValueMap);
2031    }
2032
2033    private final void inputRemoteMembersForReadFields(java.util.Map fieldToValueMap)
2034        throws InvalidClassException, StreamCorruptedException,
2035               ClassNotFoundException, IOException {
2036
2037        // Must have this local variable since defaultReadObjectFVDMembers
2038        // may get mangled by recursion.
2039        ValueMember fields[] = defaultReadObjectFVDMembers;
2040
2041        try {
2042
2043            for (int i = 0; i < fields.length; i++) {
2044
2045                switch (fields[i].type.kind().value()) {
2046
2047                case TCKind._tk_octet:
2048                    byte byteValue = orbStream.read_octet();
2049                    fieldToValueMap.put(fields[i].name, new Byte(byteValue));
2050                    break;
2051                case TCKind._tk_boolean:
2052                    boolean booleanValue = orbStream.read_boolean();
2053                    fieldToValueMap.put(fields[i].name, new Boolean(booleanValue));
2054                    break;
2055                case TCKind._tk_char:
2056                    // Backwards compatibility.  Older Sun ORBs sent
2057                    // _tk_char even though they read and wrote wchars
2058                    // correctly.
2059                    //
2060                    // Fall through to the _tk_wchar case.
2061                case TCKind._tk_wchar:
2062                    char charValue = orbStream.read_wchar();
2063                    fieldToValueMap.put(fields[i].name, new Character(charValue));
2064                    break;
2065                case TCKind._tk_short:
2066                    short shortValue = orbStream.read_short();
2067                    fieldToValueMap.put(fields[i].name, new Short(shortValue));
2068                    break;
2069                case TCKind._tk_long:
2070                    int intValue = orbStream.read_long();
2071                    fieldToValueMap.put(fields[i].name, new Integer(intValue));
2072                    break;
2073                case TCKind._tk_longlong:
2074                    long longValue = orbStream.read_longlong();
2075                    fieldToValueMap.put(fields[i].name, new Long(longValue));
2076                    break;
2077                case TCKind._tk_float:
2078                    float floatValue = orbStream.read_float();
2079                    fieldToValueMap.put(fields[i].name, new Float(floatValue));
2080                    break;
2081                case TCKind._tk_double:
2082                    double doubleValue = orbStream.read_double();
2083                    fieldToValueMap.put(fields[i].name, new Double(doubleValue));
2084                    break;
2085                case TCKind._tk_value:
2086                case TCKind._tk_objref:
2087                case TCKind._tk_value_box:
2088                    Object objectValue = null;
2089                    try {
2090                        objectValue = inputObjectField(fields[i],
2091                                                       cbSender);
2092
2093                    } catch (IndirectionException cdrie) {
2094                        // The CDR stream had never seen the given offset before,
2095                        // so check the recursion manager (it will throw an
2096                        // IOException if it doesn't have a reference, either).
2097                        objectValue = activeRecursionMgr.getObject(cdrie.offset);
2098                    }
2099
2100                    fieldToValueMap.put(fields[i].name, objectValue);
2101                    break;
2102                default:
2103                    // XXX I18N, logging needed.
2104                    throw new StreamCorruptedException("Unknown kind: "
2105                                                       + fields[i].type.kind().value());
2106                }
2107            }
2108        } catch (Throwable t) {
2109            StreamCorruptedException result = new StreamCorruptedException(t.getMessage());
2110            result.initCause(t);
2111            throw result;
2112        }
2113    }
2114
2115    /**
2116     * Called from InputStreamHook.
2117     *
2118     * Reads the fields of the current class (could be the ones
2119     * queried from the remote FVD) and puts them in
2120     * the given Map, name to value.  Wraps primitives in the
2121     * corresponding java.lang Objects.
2122     */
2123    private final void inputCurrentClassFieldsForReadFields(java.util.Map fieldToValueMap)
2124        throws InvalidClassException, StreamCorruptedException,
2125               ClassNotFoundException, IOException {
2126
2127        ObjectStreamField[] fields = currentClassDesc.getFieldsNoCopy();
2128
2129        int primFields = fields.length - currentClassDesc.objFields;
2130
2131        // Handle the primitives first
2132        for (int i = 0; i < primFields; ++i) {
2133
2134            switch (fields[i].getTypeCode()) {
2135                case 'B':
2136                    byte byteValue = orbStream.read_octet();
2137                    fieldToValueMap.put(fields[i].getName(),
2138                                        new Byte(byteValue));
2139                    break;
2140                case 'Z':
2141                   boolean booleanValue = orbStream.read_boolean();
2142                   fieldToValueMap.put(fields[i].getName(),
2143                                       new Boolean(booleanValue));
2144                   break;
2145                case 'C':
2146                    char charValue = orbStream.read_wchar();
2147                    fieldToValueMap.put(fields[i].getName(),
2148                                        new Character(charValue));
2149                    break;
2150                case 'S':
2151                    short shortValue = orbStream.read_short();
2152                    fieldToValueMap.put(fields[i].getName(),
2153                                        new Short(shortValue));
2154                    break;
2155                case 'I':
2156                    int intValue = orbStream.read_long();
2157                    fieldToValueMap.put(fields[i].getName(),
2158                                        new Integer(intValue));
2159                    break;
2160                case 'J':
2161                    long longValue = orbStream.read_longlong();
2162                    fieldToValueMap.put(fields[i].getName(),
2163                                        new Long(longValue));
2164                    break;
2165                case 'F' :
2166                    float floatValue = orbStream.read_float();
2167                    fieldToValueMap.put(fields[i].getName(),
2168                                        new Float(floatValue));
2169                    break;
2170                case 'D' :
2171                    double doubleValue = orbStream.read_double();
2172                    fieldToValueMap.put(fields[i].getName(),
2173                                        new Double(doubleValue));
2174                    break;
2175                default:
2176                    // XXX I18N, logging needed.
2177                    throw new InvalidClassException(currentClassDesc.getName());
2178            }
2179        }
2180
2181        /* Read and set object fields from the input stream. */
2182        if (currentClassDesc.objFields > 0) {
2183            for (int i = primFields; i < fields.length; i++) {
2184                Object objectValue = null;
2185                try {
2186                    objectValue = inputObjectField(fields[i]);
2187                } catch(IndirectionException cdrie) {
2188                    // The CDR stream had never seen the given offset before,
2189                    // so check the recursion manager (it will throw an
2190                    // IOException if it doesn't have a reference, either).
2191                    objectValue = activeRecursionMgr.getObject(cdrie.offset);
2192                }
2193
2194                fieldToValueMap.put(fields[i].getName(), objectValue);
2195            }
2196        }
2197    }
2198
2199    /*
2200     * Read the fields of the specified class from the input stream and set
2201     * the values of the fields in the specified object. If the specified
2202     * object is null, just consume the fields without setting any values. If
2203     * any ObjectStreamField does not have a reflected Field, don't try to set
2204     * that field in the object.
2205     *
2206     * REVISIT -- This code doesn't do what the comment says to when
2207     * getField() is null!
2208     */
2209    private void inputClassFields(Object o, Class cl,
2210                                  ObjectStreamField[] fields,
2211                                  com.sun.org.omg.SendingContext.CodeBase sender)
2212        throws InvalidClassException, StreamCorruptedException,
2213               ClassNotFoundException, IOException
2214    {
2215
2216        int primFields = fields.length - currentClassDesc.objFields;
2217
2218        if (o != null) {
2219            for (int i = 0; i < primFields; ++i) {
2220                if (fields[i].getField() == null)
2221                    continue;
2222
2223                inputPrimitiveField(o, cl, fields[i]);
2224            }
2225        }
2226
2227        /* Read and set object fields from the input stream. */
2228        if (currentClassDesc.objFields > 0) {
2229            for (int i = primFields; i < fields.length; i++) {
2230                Object objectValue = null;
2231
2232                try {
2233                    objectValue = inputObjectField(fields[i]);
2234                } catch(IndirectionException cdrie) {
2235                    // The CDR stream had never seen the given offset before,
2236                    // so check the recursion manager (it will throw an
2237                    // IOException if it doesn't have a reference, either).
2238                    objectValue = activeRecursionMgr.getObject(cdrie.offset);
2239                }
2240
2241                if ((o == null) || (fields[i].getField() == null)) {
2242                    continue;
2243                }
2244
2245                try {
2246                    Class fieldCl = fields[i].getClazz();
2247                    if (objectValue != null && !fieldCl.isInstance(objectValue)) {
2248                        throw new IllegalArgumentException();
2249                    }
2250                    bridge.putObject( o, fields[i].getFieldID(), objectValue ) ;
2251                    // reflective code: fields[i].getField().set( o, objectValue ) ;
2252                } catch (IllegalArgumentException e) {
2253                    ClassCastException exc = new ClassCastException("Assigning instance of class " +
2254                                                 objectValue.getClass().getName() +
2255                                                 " to field " +
2256                                                 currentClassDesc.getName() +
2257                                                 '#' +
2258                                                 fields[i].getField().getName());
2259                    exc.initCause( e ) ;
2260                    throw exc ;
2261                }
2262            } // end : for loop
2263            }
2264        }
2265
2266    /*
2267     * Read the fields of the specified class from the input stream and set
2268     * the values of the fields in the specified object. If the specified
2269     * object is null, just consume the fields without setting any values. If
2270     * any ObjectStreamField does not have a reflected Field, don't try to set
2271     * that field in the object.
2272     */
2273    private void inputClassFields(Object o, Class cl,
2274                                  ObjectStreamClass osc,
2275                                  ValueMember[] fields,
2276                                  com.sun.org.omg.SendingContext.CodeBase sender)
2277        throws InvalidClassException, StreamCorruptedException,
2278               ClassNotFoundException, IOException
2279    {
2280        try{
2281            for (int i = 0; i < fields.length; ++i) {
2282                try {
2283                    switch (fields[i].type.kind().value()) {
2284                    case TCKind._tk_octet:
2285                        byte byteValue = orbStream.read_octet();
2286                        if ((o != null) && osc.hasField(fields[i]))
2287                        setByteField(o, cl, fields[i].name, byteValue);
2288                        break;
2289                    case TCKind._tk_boolean:
2290                        boolean booleanValue = orbStream.read_boolean();
2291                        if ((o != null) && osc.hasField(fields[i]))
2292                        setBooleanField(o, cl, fields[i].name, booleanValue);
2293                        break;
2294                    case TCKind._tk_char:
2295                        // Backwards compatibility.  Older Sun ORBs sent
2296                        // _tk_char even though they read and wrote wchars
2297                        // correctly.
2298                        //
2299                        // Fall through to the _tk_wchar case.
2300                    case TCKind._tk_wchar:
2301                        char charValue = orbStream.read_wchar();
2302                        if ((o != null) && osc.hasField(fields[i]))
2303                        setCharField(o, cl, fields[i].name, charValue);
2304                        break;
2305                    case TCKind._tk_short:
2306                        short shortValue = orbStream.read_short();
2307                        if ((o != null) && osc.hasField(fields[i]))
2308                        setShortField(o, cl, fields[i].name, shortValue);
2309                        break;
2310                    case TCKind._tk_long:
2311                        int intValue = orbStream.read_long();
2312                        if ((o != null) && osc.hasField(fields[i]))
2313                        setIntField(o, cl, fields[i].name, intValue);
2314                        break;
2315                    case TCKind._tk_longlong:
2316                        long longValue = orbStream.read_longlong();
2317                        if ((o != null) && osc.hasField(fields[i]))
2318                        setLongField(o, cl, fields[i].name, longValue);
2319                        break;
2320                    case TCKind._tk_float:
2321                        float floatValue = orbStream.read_float();
2322                        if ((o != null) && osc.hasField(fields[i]))
2323                        setFloatField(o, cl, fields[i].name, floatValue);
2324                        break;
2325                    case TCKind._tk_double:
2326                        double doubleValue = orbStream.read_double();
2327                        if ((o != null) && osc.hasField(fields[i]))
2328                        setDoubleField(o, cl, fields[i].name, doubleValue);
2329                        break;
2330                    case TCKind._tk_value:
2331                    case TCKind._tk_objref:
2332                    case TCKind._tk_value_box:
2333                        Object objectValue = null;
2334                        try {
2335                            objectValue = inputObjectField(fields[i], sender);
2336                        } catch (IndirectionException cdrie) {
2337                            // The CDR stream had never seen the given offset before,
2338                            // so check the recursion manager (it will throw an
2339                            // IOException if it doesn't have a reference, either).
2340                            objectValue = activeRecursionMgr.getObject(cdrie.offset);
2341                        }
2342
2343                        if (o == null)
2344                            continue;
2345                        try {
2346                            if (osc.hasField(fields[i])){
2347                                setObjectField(o,
2348                                               cl,
2349                                               fields[i].name,
2350                                               objectValue);
2351                            } else {
2352                                // REVISIT.  Convert to a log message.
2353                                // This is a normal case when fields have
2354                                // been added as part of evolution, but
2355                                // silently skipping can make it hard to
2356                                // debug if there's an error
2357//                                 System.out.println("**** warning, not setting field: "
2358//                                                    + fields[i].name
2359//                                                    + " since not on class "
2360//                                                    + osc.getName());
2361
2362                            }
2363                        } catch (IllegalArgumentException e) {
2364                            // XXX I18N, logging needed.
2365                            ClassCastException cce = new ClassCastException("Assigning instance of class " +
2366                                objectValue.getClass().getName() + " to field " + fields[i].name);
2367                            cce.initCause(e) ;
2368                            throw cce ;
2369                        }
2370                        break;
2371                    default:
2372                        // XXX I18N, logging needed.
2373                        throw new StreamCorruptedException("Unknown kind: "
2374                                                           + fields[i].type.kind().value());
2375                    }
2376                } catch (IllegalArgumentException e) {
2377                    /* This case should never happen. If the field types
2378                       are not the same, InvalidClassException is raised when
2379                       matching the local class to the serialized ObjectStreamClass. */
2380                    // XXX I18N, logging needed.
2381                    ClassCastException cce = new ClassCastException("Assigning instance of class " + fields[i].id +
2382                        " to field " + currentClassDesc.getName() + '#' + fields[i].name);
2383                    cce.initCause( e ) ;
2384                    throw cce ;
2385                }
2386            }
2387        } catch(Throwable t){
2388            // XXX I18N, logging needed.
2389            StreamCorruptedException sce = new StreamCorruptedException(t.getMessage());
2390            sce.initCause(t) ;
2391            throw sce ;
2392        }
2393    }
2394
2395    private void skipCustomUsingFVD(ValueMember[] fields,
2396                                    com.sun.org.omg.SendingContext.CodeBase sender)
2397                                    throws InvalidClassException, StreamCorruptedException,
2398                                           ClassNotFoundException, IOException
2399    {
2400        readFormatVersion();
2401        boolean calledDefaultWriteObject = readBoolean();
2402
2403        if (calledDefaultWriteObject)
2404            throwAwayData(fields, sender);
2405
2406        if (getStreamFormatVersion() == 2) {
2407
2408            ((ValueInputStream)getOrbStream()).start_value();
2409            ((ValueInputStream)getOrbStream()).end_value();
2410        }
2411    }
2412
2413    /*
2414     * Read the fields of the specified class from the input stream throw data away.
2415     * This must handle same switch logic as above.
2416     */
2417    private void throwAwayData(ValueMember[] fields,
2418                               com.sun.org.omg.SendingContext.CodeBase sender)
2419        throws InvalidClassException, StreamCorruptedException,
2420               ClassNotFoundException, IOException
2421    {
2422        for (int i = 0; i < fields.length; ++i) {
2423
2424            try {
2425
2426                switch (fields[i].type.kind().value()) {
2427                case TCKind._tk_octet:
2428                    orbStream.read_octet();
2429                    break;
2430                case TCKind._tk_boolean:
2431                    orbStream.read_boolean();
2432                    break;
2433                case TCKind._tk_char:
2434                    // Backwards compatibility.  Older Sun ORBs sent
2435                    // _tk_char even though they read and wrote wchars
2436                    // correctly.
2437                    //
2438                    // Fall through to the _tk_wchar case.
2439                case TCKind._tk_wchar:
2440                    orbStream.read_wchar();
2441                    break;
2442                case TCKind._tk_short:
2443                    orbStream.read_short();
2444                    break;
2445                case TCKind._tk_long:
2446                    orbStream.read_long();
2447                    break;
2448                case TCKind._tk_longlong:
2449                    orbStream.read_longlong();
2450                    break;
2451                case TCKind._tk_float:
2452                    orbStream.read_float();
2453                    break;
2454                case TCKind._tk_double:
2455                    orbStream.read_double();
2456                    break;
2457                case TCKind._tk_value:
2458                case TCKind._tk_objref:
2459                case TCKind._tk_value_box:
2460                    Class type = null;
2461                    String id = fields[i].id;
2462
2463                    try {
2464                        type = vhandler.getClassFromType(id);
2465                    }
2466                    catch(ClassNotFoundException cnfe){
2467                        // Make sure type = null
2468                        type = null;
2469                    }
2470                    String signature = null;
2471                    if (type != null)
2472                        signature = ValueUtility.getSignature(fields[i]);
2473
2474                    // Read value
2475                    try {
2476                        if ((signature != null) && ( signature.equals("Ljava/lang/Object;") ||
2477                                                     signature.equals("Ljava/io/Serializable;") ||
2478                                                     signature.equals("Ljava/io/Externalizable;")) ) {
2479                            javax.rmi.CORBA.Util.readAny(orbStream);
2480                        }
2481                        else {
2482                            // Decide what method call to make based on the type.
2483                            //
2484                            // NOTE : Since FullValueDescription does not allow us
2485                            // to ask whether something is an interface we do not
2486                            // have the ability to optimize this check.
2487
2488                            int callType = ValueHandlerImpl.kValueType;
2489
2490                            if (!vhandler.isSequence(id)) {
2491                                FullValueDescription fieldFVD = sender.meta(fields[i].id);
2492                                if (kRemoteTypeCode == fields[i].type) {
2493
2494                                    // RMI Object reference...
2495                                    callType = ValueHandlerImpl.kRemoteType;
2496                                } else if (fieldFVD.is_abstract) {
2497                                    // RMI Abstract Object reference...
2498
2499                                    callType = ValueHandlerImpl.kAbstractType;
2500                                }
2501                            }
2502
2503                            // Now that we have used the FVD of the field to determine the proper course
2504                            // of action, it is ok to use the type (Class) from this point forward since
2505                            // the rep. id for this read will also follow on the wire.
2506
2507                            switch (callType) {
2508                            case ValueHandlerImpl.kRemoteType:
2509                                orbStream.read_Object();
2510                                break;
2511                            case ValueHandlerImpl.kAbstractType:
2512                                orbStream.read_abstract_interface();
2513                                break;
2514                            case ValueHandlerImpl.kValueType:
2515                                if (type != null) {
2516                                    orbStream.read_value(type);
2517                                } else {
2518                                    orbStream.read_value();
2519                                }
2520                                break;
2521                            default:
2522                                // XXX I18N, logging needed.
2523                                throw new StreamCorruptedException("Unknown callType: "
2524                                                                   + callType);
2525                            }
2526                        }
2527
2528                    }
2529                    catch(IndirectionException cdrie) {
2530                        // Since we are throwing this away, don't bother handling recursion.
2531                        continue;
2532                    }
2533
2534                    break;
2535                default:
2536                    // XXX I18N, logging needed.
2537                    throw new StreamCorruptedException("Unknown kind: "
2538                                                       + fields[i].type.kind().value());
2539
2540                }
2541            } catch (IllegalArgumentException e) {
2542                /* This case should never happen. If the field types
2543                   are not the same, InvalidClassException is raised when
2544                   matching the local class to the serialized ObjectStreamClass. */
2545                // XXX I18N, logging needed.
2546                ClassCastException cce = new ClassCastException("Assigning instance of class " +
2547                    fields[i].id + " to field " + currentClassDesc.getName() +
2548                    '#' + fields[i].name);
2549                cce.initCause(e) ;
2550                throw cce ;
2551            }
2552        }
2553
2554    }
2555
2556    private static void setObjectField(Object o, Class c, String fieldName, Object v)
2557    {
2558        try {
2559            Field fld = c.getDeclaredField( fieldName ) ;
2560            Class fieldCl = fld.getType();
2561            if(v != null && !fieldCl.isInstance(v)) {
2562                throw new Exception();
2563            }
2564            long key = bridge.objectFieldOffset( fld ) ;
2565            bridge.putObject( o, key, v ) ;
2566        } catch (Exception e) {
2567            throw utilWrapper.errorSetObjectField( e, fieldName,
2568                o.toString(),
2569                v.toString() ) ;
2570        }
2571    }
2572
2573    private static void setBooleanField(Object o, Class c, String fieldName, boolean v)
2574    {
2575        try {
2576            Field fld = c.getDeclaredField( fieldName ) ;
2577            long key = bridge.objectFieldOffset( fld ) ;
2578            bridge.putBoolean( o, key, v ) ;
2579        } catch (Exception e) {
2580            throw utilWrapper.errorSetBooleanField( e, fieldName,
2581                o.toString(),
2582                new Boolean(v) ) ;
2583        }
2584    }
2585
2586    private static void setByteField(Object o, Class c, String fieldName, byte v)
2587    {
2588        try {
2589            Field fld = c.getDeclaredField( fieldName ) ;
2590            long key = bridge.objectFieldOffset( fld ) ;
2591            bridge.putByte( o, key, v ) ;
2592        } catch (Exception e) {
2593            throw utilWrapper.errorSetByteField( e, fieldName,
2594                o.toString(),
2595                new Byte(v) ) ;
2596        }
2597    }
2598
2599    private static void setCharField(Object o, Class c, String fieldName, char v)
2600    {
2601        try {
2602            Field fld = c.getDeclaredField( fieldName ) ;
2603            long key = bridge.objectFieldOffset( fld ) ;
2604            bridge.putChar( o, key, v ) ;
2605        } catch (Exception e) {
2606            throw utilWrapper.errorSetCharField( e, fieldName,
2607                o.toString(),
2608                new Character(v) ) ;
2609        }
2610    }
2611
2612    private static void setShortField(Object o, Class c, String fieldName, short v)
2613    {
2614        try {
2615            Field fld = c.getDeclaredField( fieldName ) ;
2616            long key = bridge.objectFieldOffset( fld ) ;
2617            bridge.putShort( o, key, v ) ;
2618        } catch (Exception e) {
2619            throw utilWrapper.errorSetShortField( e, fieldName,
2620                o.toString(),
2621                new Short(v) ) ;
2622        }
2623    }
2624
2625    private static void setIntField(Object o, Class c, String fieldName, int v)
2626    {
2627        try {
2628            Field fld = c.getDeclaredField( fieldName ) ;
2629            long key = bridge.objectFieldOffset( fld ) ;
2630            bridge.putInt( o, key, v ) ;
2631        } catch (Exception e) {
2632            throw utilWrapper.errorSetIntField( e, fieldName,
2633                o.toString(),
2634                new Integer(v) ) ;
2635        }
2636    }
2637
2638    private static void setLongField(Object o, Class c, String fieldName, long v)
2639    {
2640        try {
2641            Field fld = c.getDeclaredField( fieldName ) ;
2642            long key = bridge.objectFieldOffset( fld ) ;
2643            bridge.putLong( o, key, v ) ;
2644        } catch (Exception e) {
2645            throw utilWrapper.errorSetLongField( e, fieldName,
2646                o.toString(),
2647                new Long(v) ) ;
2648        }
2649    }
2650
2651    private static void setFloatField(Object o, Class c, String fieldName, float v)
2652    {
2653        try {
2654            Field fld = c.getDeclaredField( fieldName ) ;
2655            long key = bridge.objectFieldOffset( fld ) ;
2656            bridge.putFloat( o, key, v ) ;
2657        } catch (Exception e) {
2658            throw utilWrapper.errorSetFloatField( e, fieldName,
2659                o.toString(),
2660                new Float(v) ) ;
2661        }
2662    }
2663
2664    private static void setDoubleField(Object o, Class c, String fieldName, double v)
2665    {
2666        try {
2667            Field fld = c.getDeclaredField( fieldName ) ;
2668            long key = bridge.objectFieldOffset( fld ) ;
2669            bridge.putDouble( o, key, v ) ;
2670        } catch (Exception e) {
2671            throw utilWrapper.errorSetDoubleField( e, fieldName,
2672                o.toString(),
2673                new Double(v) ) ;
2674        }
2675    }
2676
2677    /**
2678     * This class maintains a map of stream position to
2679     * an Object currently being deserialized.  It is used
2680     * to handle the cases where the are indirections to
2681     * an object on the recursion stack.  The CDR level
2682     * handles indirections to objects previously seen
2683     * (and completely deserialized) in the stream.
2684     */
2685    static class ActiveRecursionManager
2686    {
2687        private Map offsetToObjectMap;
2688
2689        public ActiveRecursionManager() {
2690            // A hash map is unsynchronized and allows
2691            // null values
2692            offsetToObjectMap = new HashMap();
2693        }
2694
2695        // Called right after allocating a new object.
2696        // Offset is the starting position in the stream
2697        // of the object.
2698        public void addObject(int offset, Object value) {
2699            offsetToObjectMap.put(new Integer(offset), value);
2700        }
2701
2702        // If the given starting position doesn't refer
2703        // to the beginning of an object currently being
2704        // deserialized, this throws an IOException.
2705        // Otherwise, it returns a reference to the
2706        // object.
2707        public Object getObject(int offset) throws IOException {
2708            Integer position = new Integer(offset);
2709
2710            if (!offsetToObjectMap.containsKey(position))
2711                // XXX I18N, logging needed.
2712                throw new IOException("Invalid indirection to offset "
2713                                      + offset);
2714
2715            return offsetToObjectMap.get(position);
2716        }
2717
2718        // Called when an object has been completely
2719        // deserialized, so it should no longer be in
2720        // this mapping.  The CDR level can handle
2721        // further indirections.
2722        public void removeObject(int offset) {
2723            offsetToObjectMap.remove(new Integer(offset));
2724        }
2725
2726        // If the given offset doesn't map to an Object,
2727        // then it isn't an indirection to an object
2728        // currently being deserialized.
2729        public boolean containsObject(int offset) {
2730            return offsetToObjectMap.containsKey(new Integer(offset));
2731        }
2732    }
2733}
2734